20

It seems that refcheck does not recognize references made by cleveref:

\documentclass{article}
\usepackage{amsmath}
\usepackage{cleveref}
\usepackage{refcheck}

\begin{document}
\begin{align}
  a & = b \label{eq:a} \\
  c & = d \label{eq:b}
\end{align}

See~\eqref{eq:a}, \cref{eq:b}.

\begin{figure}
  \caption{Figure 1}
  \label{fig:a}
\end{figure}
\begin{figure}
  \caption{Figure 2}
  \label{fig:b}
\end{figure}

See Figure~\ref{fig:a}, \cref{fig:b}.

\end{document}

Here, refcheck marks eq:b and fig:b as unreferenced.

  1. Is there a way to make the two packages work together?
  2. Alternatively, are there replacement packages that do work better?
  3. If the answer to 1) is yes, can this even be achieved for \crefrange?
David Carlisle
  • 757,742
mafp
  • 19,096
  • Have you tried "Poor man's cleveref" (chapter 10 in cleveref's docs)? This should be an easy workaround on a Linux or Mac OS X system. – krlmlr Dec 19 '12 at 23:19
  • 3
    @user946850 I know that option, but I'm not convinced. As a purist, I don't want to run sed scripts in between. And you still have the false positives when using compressed references (\crefrange, and \cref with several labels). – mafp Dec 19 '12 at 23:40

6 Answers6

31

refcheck doesn't know about \cref and \Cref. We can add a macro that makes the package aware of other reference commands:

\documentclass{article}
\usepackage{amsmath}
\usepackage{cleveref}
\usepackage{refcheck}

%%% Infrastructure    
\makeatletter
\newcommand{\refcheckize}[1]{%
  \expandafter\let\csname @@\string#1\endcsname#1%
  \expandafter\DeclareRobustCommand\csname relax\string#1\endcsname[1]{%
    \csname @@\string#1\endcsname{##1}\wrtusdrf{##1}}%
  \expandafter\let\expandafter#1\csname relax\string#1\endcsname
}
\makeatother
%%%

%%% Now we add the reference commands we want refcheck to be aware of
\refcheckize{\cref}
\refcheckize{\Cref}

\begin{document}
\begin{align}
  a & = b \label{eq:a} \\
  c & = d \label{eq:b}
\end{align}

See~\eqref{eq:a}, \cref{eq:b}.

\begin{figure}
  \caption{Figure 1}
  \label{fig:a}
\end{figure}
\begin{figure}
  \caption{Figure 2}
  \label{fig:b}
\end{figure}

See Figure~\ref{fig:a}, \Cref{fig:b}.

\end{document}

enter image description here

David Carlisle
  • 757,742
egreg
  • 1,121,712
  • 1
    This is great! But does it work when \creffing multiple labels? And what about \crefrange and friends? -- It seems that at least one of the packages should be enhanced to support the other, perhaps both: I imagine a command like \noref (provided by refcheck) that would simply mark a reference as "used" and could be called by cleveref, autoref, nameref, ... – krlmlr Dec 19 '12 at 23:06
  • 1
    Nice. Unfortunately, I use \cref almost exclusively for multiple references to employ the compression feature, and in this case your solution obviously won't work. I guess one needs to hook deeper into the packages. Should I ask the cleveref author for active support of refcheck, or the refcheck author (I'm not sure if he is still an active Texie.)? – mafp Dec 19 '12 at 23:09
  • @user946850 refcheck simply modifies \ref and \pageref to write \usedref in the .aux file; the "refcheckized" macros do just the same. – egreg Dec 19 '12 at 23:09
  • @mafp I'm afraid that this requires much more work. – egreg Dec 19 '12 at 23:10
  • 1
    @mafp: According to egreg's comment, it seems that there's no need to modify refcheck, but cleveref (or its author...) should be made aware of that package. The cleveref docs suggest that (a) the package is well maintained and (b) the author is not aware of refcheck (quick search for "refcheck"). It would definitely be a great improvement for cleveref... – krlmlr Dec 19 '12 at 23:12
  • 2
    This also works with \autoref of hyperref. – Reinstate Monica Jul 21 '14 at 20:37
  • 1
    @egreg Any updates/thoughts on this after three years? Could not find any tool (like chklref) or package (like refcheck) that supports commands such as \Cref{fig:a,fig:b}. Already wrote the cleveref author. – Alex Jan 04 '16 at 20:29
  • @Alex Sorry, nothing I know about. – egreg Jan 04 '16 at 22:41
  • Is there a similar incantation that will make refcheck work with \autopageref? – Mark Mar 17 '16 at 01:21
  • 1
    @Mark Have you tried \refcheckize{\autopageref}? – egreg Mar 17 '16 at 06:56
  • Yep, no effect as far as I can tell. – Mark Mar 17 '16 at 11:11
  • @Mark The problem is that hyperref redefines \ref and \pageref to have a possible * after them; you can try out \ref*{label} and see it doesn't work. If you don't plan to use *-variants of the commands, I think it's possible to make them work. Supporting *-variants is not done by refcheck anyway. – egreg Mar 17 '16 at 11:57
  • @Mark Isn't it easier using \cpageref? – egreg Mar 17 '16 at 12:04
  • You're right, the star variants don't work. I don't need the star variants though. And cpageref is from cleveref, right? I'm not using cleveref. Should I be? – Mark Mar 18 '16 at 02:23
  • \cpageref solves nothing actually; I just tried it. Only the page number gets a hyperlink, and not the word "page". If that's what I wanted, there's already good old \pageref :) – Mark Mar 18 '16 at 02:50
  • Is there similar magic I can use to get \nameref to work? – Mark Mar 28 '16 at 18:10
  • It is indeed possible to get the starred version of \ref to work with refcheck, e.g. using my quick fix from this answer: http://tex.stackexchange.com/a/274822/73383 :) – Erlend Graff Aug 12 '16 at 23:21
  • 1
    This was working for me in the past but recently found that I needed an extra pair of curly braces for the reference to be detected properly. This was easy to fix by using \wrtusdrf on both: \wrtusdrf{##1}\wrtusdrf{{##1}}. I see no harm in putting both, maybe will help someone else with the same issue. – codebeard Nov 28 '16 at 12:31
  • Des it work with \autoref? – KcFnMi May 19 '19 at 03:04
  • @KcFnMi Did you try with \refcheckize{\autoref}? – egreg May 19 '19 at 08:48
  • Got Undefined control sequence. Whre should I put that command? Is there any documentation for this command? Can't find it on https://mirror-hk.koddos.net/CTAN/macros/latex/contrib/refcheck/refdemo.pdf. – KcFnMi May 19 '19 at 16:38
  • @KcFnMi You did \usepackage{hyperref}, didn't you? – egreg May 19 '19 at 16:43
  • Ok, got it! I would like to have showrefs only for unreferenced labels, is it possible? – KcFnMi May 19 '19 at 16:59
11

I ran into the same issue, and found it was relatively straightforward to extend egreg's answer to handle extra cases like \crefrange{eq1}{eq2} and \cref{eq1,eq2,eq4}:

\makeatletter
\newcommand{\refcheckize}[1]{%
  \expandafter\let\csname @@\string#1\endcsname#1%
  \expandafter\DeclareRobustCommand\csname relax\string#1\endcsname[1]{%
    \csname @@\string#1\endcsname{##1}\@for\@temp:=##1\do{\wrtusdrf{\@temp}\wrtusdrf{{\@temp}}}}%
  \expandafter\let\expandafter#1\csname relax\string#1\endcsname
}
\newcommand{\refcheckizetwo}[1]{%
  \expandafter\let\csname @@\string#1\endcsname#1%
  \expandafter\DeclareRobustCommand\csname relax\string#1\endcsname[2]{%
    \csname @@\string#1\endcsname{##1}{##2}\wrtusdrf{##1}\wrtusdrf{{##1}}\wrtusdrf{##2}\wrtusdrf{{##2}}}%
  \expandafter\let\expandafter#1\csname relax\string#1\endcsname
}
\makeatother

\refcheckize{\cref}
\refcheckize{\Cref}
\refcheckizetwo{\crefrange}
\refcheckizetwo{\Crefrange}

Credit goes to egreg for the original solution.

2016 Edit:

I'm not sure why, but this had stopped working for me at some point. I started getting a lot of errors like this again:

Package refcheck Warning: Unused label `{eq:objective}' on input line 30.

For whatever reason (maybe a strange interaction of packages) refcheck was expecting an extra pair of curly braces. That is, it expected \label{eq:objective} to be paired with \wrtusdrf{{eq:objective}}, but the \refcheckize commands were only producing \wrtusdrf{eq:objective}.

To fix this I have now put a matching \wrtusdrf{{...}} along with every \wrtusdrf{...} in the macros. This shouldn't have any negative effect provided that you don't differentiate labels solely with curly braces (please don't do that.)

codebeard
  • 1,285
  • Works very well. However, the solution doesn't seem to like subfigures (using the subcaption package). – Alex Dec 25 '15 at 19:01
1

I ended up with using a little shell script to find unreferenced labels. This has some drawbacks of course, but works very well in my case (document with hundreds of pages):

# Helper function to find unreferenced labels, since the chkltex tool and the refcheck package do not support cleveref
# Note: this could show false positives sometimes
echo "Checking for unreferenced labels...";
labels=$(grep -Eo '^[\s]*[^%]+.*label{[^}]+}' $_dir_sources/*.tex|sed -Ee "s/^.*{(.*)}/\1/g")
for label in $labels; do
  found=$(grep -E "ref{[^}]*$label" $_dir_sources/*.tex)
  if [[ -z "$found" ]]; then
    echo "Label '$label' not referenced?";
  fi
done
Alex
  • 197
  • 1
  • 9
1

My choice is to write my own \cref command.

\iffalse
    \usepackage{refcheck}
    \def\crefname#1#2#3{}
    \def\cref#1{\{\getrefs#1,\relax\}}
    \def\getrefs#1,#2\relax{%
        \ref{#1}%
        \ifx\relax#2\relax\else
            , \getrefs#2\relax
        \fi
    }
\else
    \usepackage[capitalise,poorman]{cleveref}
\fi

Truning \iffalse to \iftrue drops the cleveref package, and defines \crefname and \cref. Then \refcheck should work well. (Of course it changes the style of the reference, but it won't change the reference relation.)

CY Qian
  • 107
0

Alex's answer did not work for me at first (sed issues the error "char 14: Invalid content of {} "). I am not a regex expert, so I ended up rewriting the line that finds the labels. So far this works for any type of reference:

echo "Checking for unreferenced labels...";
# find all label names
labels=$(grep -oP 'label{[^}]+}' *.tex | sed -e "s/^.*label{//" -e "s/}//")
#echo $labels
# for each label, see if it appears in a ref command (\ref, \cref and others)
for label in $labels; do
   found=$(grep -E "ref{[^}]*$label" *.tex)
if [[ -z "$found" ]]; then
    echo "Label '$label' not referenced";
fi
done
Laurent90
  • 161
  • Welcome to TeX.SE! Can you please explain your "did not work" better, for example showing the resulting error message etc. What did you changed in your given code and why? – Mensch Jun 25 '20 at 10:41
  • Thanks for your remark, I have updated my answer accordingly. – Laurent90 Jun 25 '20 at 11:01
0

I have updated Laurent90's answer to

  • include .tex files in subfolders
  • only consider \label as labels so as not to include things like \fmflabel
  • not include labels that have been commented out (though it will fail to include a label if the label is preceded by \% for instance)
  • not consider labels referenced if the ref is commented out (though it will give false positives if preceded by \% for instance)
  • there must be a , or } right after the label when it is referenced so the label abc is not falsely considered referenced if a label abcd is referenced
# remove "-not -iname '*appendix*.tex'" to include appendix files
files=$(find . -iname '*.tex' -not -iname '*appendix*.tex')
labels=$(sed -E "s/^[ \t]*[^%]*\\\label\{([^}]+)\}.*/\1/g;t;d" $files)
for label in $labels; do
grep -Eq "^[ \t]*[^%]*ref{[^}]*$label[},]" $files || echo "Label '$label' not referenced"
done