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?
2
  • 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, 2012 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, 2012 at 23:40

6 Answers 6

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

23
  • 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, 2012 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, 2012 at 23:09
  • 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, 2012 at 23:12
  • 2
    This also works with \autoref of hyperref. Jul 21, 2014 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 4, 2016 at 20:29
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.)

1
  • Works very well. However, the solution doesn't seem to like subfigures (using the subcaption package).
    – Alex
    Dec 25, 2015 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
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.)

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
2
  • 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, 2020 at 10:41
  • Thanks for your remark, I have updated my answer accordingly.
    – Laurent90
    Jun 25, 2020 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .