title: Automatically detect identical consecutive std::string::find() calls
body: <p>During a code review, i found source code like this:</p>
  
  <pre><code>void f_odd(std::string &amp;className, std::string &amp;testName)
  {
     if (className.find("::") != std::string::npos)
     {
       testName = className.substr(className.find("::") + 2);
       (void)className.erase(className.find("::"), std::string::npos);
     }
  }
  </code></pre>
  
  <p>Within this function, std::string::find() is called three times with the same pattern( here "::").</p>
  
  <p>This code can of course be refactored to </p>
  
  <pre><code>void f(std::string &amp;className, std::string &amp;testName)
  {
     const size_t endOfClassNamePos = className.find("::");
     if (endOfClassNamePos != std::string::npos)
     {
       testName = className.substr(endOfClassNamePos + 2);
       (void)className.erase(endOfClassNamePos, std::string::npos);
     }
  }
  </code></pre>
  
  <p>where find is called only once.</p>
  
  <p><strong>Question</strong></p>
  
  <p>Does anybody know a strategy to detecting such a pattern like this? I am having a huge code base, where i intend to spot this pattern.
  I plan to use a Windows or a Linux environment. </p>
  
  <p><strong>Potential Strategies</strong></p>
  
  <ol>
  <li>Use/adapt a static code analysis tool, like cppcheck to detect these kind of oddities.</li>
  <li>Search within the code base with regular expression. </li>
  <li>Use/adapt clang-tidy for detection of this pattern.</li>
  <li>Write a custom checker in some language (e.g. Python) that detects these issues. In this case, the checking should be performed on pre-processed code.</li>
  </ol>
  
  <p><strong>No Go's</strong></p>
  
  <ul>
  <li>Manual review</li>
  </ul>
  
  <hr>
  
  <p><strong>Update 1</strong></p>
  
  <p>I decided to start with potential strategy 1). I plan to adapt cppcheck to catch this issue. </p>
  
  <p>Cppcheck offers a possibility to write customized rules, based on PCRE regular expressions. For this, cppcheck has to be compiled with enabled PCRE support. Since the current test environment is Linux-based, the following commands can be used to download the latest version of cppcheck:</p>
  
  <p><code>git clone https://github.com/danmar/cppcheck.git &amp;&amp; cd cppcheck</code></p>
  
  <p>After that, compile and install the tool as follows:</p>
  
  <p><code>sudo make install HAVE_RULES=yes</code></p>
  
  <p>Now the basic tool setup is done. In order to develop a cppcheck-rule, i prepared a simple test case (file: test.cpp), similar to the sample code in the first section of this article. This file contains three functions and the cppcheck-rule shall emit a warning on <code>f_odd</code> and <code>f_odd1</code> about consecutive identical <code>std::string::find</code> calls.</p>
  
  <p>test.cpp:</p>
  
  <pre><code>#include &lt;string&gt;
  void f(std::string &amp;className, std::string &amp;testName)
  {
     const size_t endOfClassNamePos = className.find("::");
     if (endOfClassNamePos != std::string::npos)
     {
       testName = className.substr(endOfClassNamePos + 2);
       (void)className.erase(endOfClassNamePos, std::string::npos);
     }
   }
  
   void f_odd(std::string &amp;className, std::string &amp;testName)
   {
      if (className.find("::") != std::string::npos)
      {
         testName = className.substr(className.find("::") + 2);
         (void)className.erase(className.find("::"), std::string::npos);
      }
   }
  
   #define A "::"
   #define B "::"
   #define C "::"
   void f_odd1(std::string &amp;className, std::string &amp;testName)
   {
     if (className.find(A) != std::string::npos)
     {
        testName = className.substr(className.find(B) + 2);
        (void)className.erase(className.find(C), std::string::npos);
     }
   }
  </code></pre>
  
  <p>So far so good. Now cppcheck has to be tweaked to catch consecutive identical <code>std::string::find</code> calls. For this i have created a <a href="https://github.com/orbitcowboy/cppcheck_rules/blob/master/rules/rule.xml" rel="nofollow">cppcheck_rule-file</a> that contains a regular expression that matches consecutive identical <code>std::string::find</code> calls:</p>
  
  <pre><code>&lt;?xml version="1.0"?&gt;
  &lt;rule&gt;
  &lt;tokenlist&gt;normal&lt;/tokenlist&gt;
  &lt;pattern&gt;&lt;![CDATA[([a-zA-Z][a-zA-Z0-9]*)(\s*\.\s*find)(\s*\(\s*\"[ -~]*\"\s*\))[ -\{\n]*(\1\2\3)+[ -z\n]]]&gt;&lt;/pattern&gt;
  &lt;message&gt;
      &lt;severity&gt;style&lt;/severity&gt;
      &lt;summary&gt;Found identical consecutive std::string::find calls.&lt;/summary&gt;
  &lt;/message&gt;
  </code></pre>
  
  <p></p>
  
  <p>This file can be used to extend cppcheck about a new check. 
  Lets try:</p>
  
  <p><code>cppcheck --rule-file=rules/rule.xml test/test.cpp</code></p>
  
  <p>and the output is</p>
  
  <pre><code>Checking test/test.cpp...
  [test/test.cpp:14]: (style) Found identical consecutive std::string::find calls.
  [test/test.cpp:26]: (style) Found identical consecutive std::string::find calls.
  </code></pre>
  
  <p>Now, identical consecutive <code>std::string::find</code> calls can be detected in C/C++ codes. Does anybody know a better/more efficient or more clever solution?</p>
  
  <p>References:</p>
  
  <ul>
  <li><a href="https://github.com/orbitcowboy/cppcheck_rules" rel="nofollow">Checkout the cppcheck_rule file on github</a></li>
  <li><a href="https://www.google.de/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=5&amp;cad=rja&amp;uact=8&amp;ved=0ahUKEwiwjPSrm7LMAhXMWSwKHX66BH8QFgg_MAQ&amp;url=http%3A%2F%2Fwww.cs.kent.edu%2F~rothstei%2Fspring_12%2Fsecprognotes%2Fcppcheck_writing-rules-1.pdf&amp;usg=AFQjCNFLjfvbJ4NlmqatgOg6TeJ7te2knw&amp;sig2=Cn3z2MZMLH4f1jqOTPa-Og" rel="nofollow">How to write custom rules for cppcheck</a></li>
  </ul>
  
  <hr>