[PATCH] Warn on explicit copy constructors.

Alexander Kornienko alexfh at google.com
Tue Apr 29 06:58:21 PDT 2014


Hi djasper,

The Google C++ Style Guide doesn't require copy constructors to be
declared explicit, but some people do this by mistake. Make this check detect
and fix such cases.

http://reviews.llvm.org/D3541

Files:
  clang-tidy/google/GoogleTidyModule.cpp
  unittests/clang-tidy/GoogleModuleTest.cpp

Index: clang-tidy/google/GoogleTidyModule.cpp
===================================================================
--- clang-tidy/google/GoogleTidyModule.cpp
+++ clang-tidy/google/GoogleTidyModule.cpp
@@ -15,6 +15,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/Support/raw_ostream.h"
@@ -28,14 +29,56 @@
   Finder->addMatcher(constructorDecl().bind("ctor"), this);
 }
 
+// Looks for the token matching the predicate and returns the range of the found
+// token including trailing whitespace.
+SourceRange FindToken(const SourceManager &Sources, LangOptions LangOpts,
+                      SourceLocation StartLoc, SourceLocation EndLoc,
+                      bool (*Pred)(const Token &)) {
+  FileID File = Sources.getFileID(Sources.getSpellingLoc(StartLoc));
+  StringRef Buf = Sources.getBufferData(File);
+  const char *StartChar = Sources.getCharacterData(StartLoc);
+  Lexer Lex(StartLoc, LangOpts, StartChar, StartChar, Buf.end());
+  Lex.SetCommentRetentionState(true);
+  Token Tok;
+  do {
+    Lex.LexFromRawLexer(Tok);
+    if (Pred(Tok)) {
+      Token NextTok;
+      Lex.LexFromRawLexer(NextTok);
+      return SourceRange(Tok.getLocation(), NextTok.getLocation());
+    }
+  } while (Tok.isNot(tok::eof) && Tok.getLocation() < EndLoc);
+
+  return SourceRange();
+}
+
 void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
   const CXXConstructorDecl *Ctor =
       Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
   // Do not be confused: isExplicit means 'explicit' keyword is present,
   // isImplicit means that it's a compiler-generated constructor.
-  if (Ctor->isOutOfLine() || Ctor->isExplicit() || Ctor->isImplicit() ||
-      Ctor->isDeleted() || Ctor->isCopyOrMoveConstructor())
+  if (Ctor->isOutOfLine() || Ctor->isImplicit() || Ctor->isDeleted())
     return;
+  if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor()) {
+    if (Ctor->isExplicit() && Ctor->isCopyOrMoveConstructor()) {
+      SourceRange ExplicitTokenRange = FindToken(
+          *Result.SourceManager, Result.Context->getLangOpts(),
+          Ctor->getOuterLocStart(), Ctor->getLocEnd(), [](const Token &Tok) {
+            return Tok.is(tok::raw_identifier) &&
+                   StringRef(Tok.getRawIdentifierData(), Tok.getLength()) ==
+                       "explicit";
+          });
+      if (ExplicitTokenRange.isValid()) {
+        DiagnosticBuilder Diag =
+            diag(ExplicitTokenRange.getBegin(),
+                 "Copy constructor declared explicit.");
+        Diag << FixItHint::CreateRemoval(
+            CharSourceRange::getCharRange(ExplicitTokenRange));
+      }
+    }
+    return;
+  }
+
   if (Ctor->getNumParams() == 0 || Ctor->getMinRequiredArguments() > 1)
     return;
   SourceLocation Loc = Ctor->getLocation();
Index: unittests/clang-tidy/GoogleModuleTest.cpp
===================================================================
--- unittests/clang-tidy/GoogleModuleTest.cpp
+++ unittests/clang-tidy/GoogleModuleTest.cpp
@@ -37,6 +37,16 @@
                 "class C { C(int i); }; C::C(int i) {}"));
 }
 
+TEST(ExplicitConstructorCheckTest, RemoveExplicit) {
+  EXPECT_EQ("class A { A(const A&); };\n"
+            "class B { /*asdf*/  B(const B&); };\n"
+            "class C { /*asdf*/  C(const C&); };",
+            runCheckOnCode<ExplicitConstructorCheck>(
+                "class A { explicit    A(const A&); };\n"
+                "class B { explicit   /*asdf*/  B(const B&); };\n"
+                "class C { explicit/*asdf*/  C(const C&); };"));
+}
+
 } // namespace test
 } // namespace tidy
 } // namespace clang
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D3541.8919.patch
Type: text/x-patch
Size: 3810 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140429/e14fca0b/attachment.bin>


More information about the cfe-commits mailing list