[clang-tools-extra] r208954 - Initial version of clang-tidy check to use override instead of virual.

Daniel Jasper djasper at google.com
Fri May 16 02:30:10 PDT 2014


Author: djasper
Date: Fri May 16 04:30:09 2014
New Revision: 208954

URL: http://llvm.org/viewvc/llvm-project?rev=208954&view=rev
Log:
Initial version of clang-tidy check to use override instead of virual.

Review: http://reviews.llvm.org/D3688

Added:
    clang-tools-extra/trunk/clang-tidy/misc/UseOverride.cpp
    clang-tools-extra/trunk/clang-tidy/misc/UseOverride.h
    clang-tools-extra/trunk/test/clang-tidy/use-override.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
    clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy_fix.sh

Modified: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt?rev=208954&r1=208953&r2=208954&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt Fri May 16 04:30:09 2014
@@ -4,6 +4,7 @@ add_clang_library(clangTidyMiscModule
   ArgumentCommentCheck.cpp
   MiscTidyModule.cpp
   RedundantSmartptrGet.cpp
+  UseOverride.cpp
 
   LINK_LIBS
   clangAST

Modified: clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp?rev=208954&r1=208953&r2=208954&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp Fri May 16 04:30:09 2014
@@ -12,6 +12,7 @@
 #include "../ClangTidyModuleRegistry.h"
 #include "ArgumentCommentCheck.h"
 #include "RedundantSmartptrGet.h"
+#include "UseOverride.h"
 
 namespace clang {
 namespace tidy {
@@ -25,6 +26,9 @@ public:
     CheckFactories.addCheckFactory(
         "misc-redundant-smartptr-get",
         new ClangTidyCheckFactory<RedundantSmartptrGet>());
+    CheckFactories.addCheckFactory(
+        "misc-use-override",
+        new ClangTidyCheckFactory<UseOverride>());
   }
 };
 

Added: clang-tools-extra/trunk/clang-tidy/misc/UseOverride.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/UseOverride.cpp?rev=208954&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/UseOverride.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/UseOverride.cpp Fri May 16 04:30:09 2014
@@ -0,0 +1,131 @@
+//===--- UseOverride.cpp - clang-tidy -------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseOverride.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+void UseOverride::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(methodDecl(isOverride()).bind("method"), this);
+}
+
+// Re-lex the tokens to get precise locations to insert 'override' and remove
+// 'virtual'.
+static SmallVector<Token, 16> ParseTokens(CharSourceRange Range,
+                                          const SourceManager &Sources,
+                                          LangOptions LangOpts) {
+  std::pair<FileID, unsigned> LocInfo =
+      Sources.getDecomposedLoc(Range.getBegin());
+  StringRef File = Sources.getBufferData(LocInfo.first);
+  const char *TokenBegin = File.data() + LocInfo.second;
+  Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first), LangOpts,
+                 File.begin(), TokenBegin, File.end());
+  SmallVector<Token, 16> Tokens;
+  Token Tok;
+  while (!RawLexer.LexFromRawLexer(Tok)) {
+    if (Tok.is(tok::semi) || Tok.is(tok::l_brace))
+      break;
+    if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation()))
+      break;
+    Tokens.push_back(Tok);
+  }
+  return Tokens;
+}
+
+static StringRef GetText(const Token& Tok, const SourceManager &Sources) {
+  return {Sources.getCharacterData(Tok.getLocation()), Tok.getLength()};
+}
+
+void UseOverride::check(const MatchFinder::MatchResult &Result) {
+  const FunctionDecl *Method = Result.Nodes.getStmtAs<FunctionDecl>("method");
+  const SourceManager &Sources = *Result.SourceManager;
+
+  assert(Method != nullptr);
+  if (Method->getInstantiatedFromMemberFunction() != nullptr)
+    Method = Method->getInstantiatedFromMemberFunction();
+
+  if (Method->isImplicit() || Method->getLocation().isMacroID() ||
+      Method->isOutOfLine())
+    return;
+
+  if (Method->getAttr<clang::OverrideAttr>() != nullptr &&
+      !Method->isVirtualAsWritten())
+    return; // Nothing to do.
+
+  DiagnosticBuilder Diag = diag(Method->getLocation(),
+                                "Prefer using 'override' instead of 'virtual'");
+
+  CharSourceRange FileRange =
+      Lexer::makeFileCharRange(CharSourceRange::getTokenRange(
+                                   Method->getLocStart(), Method->getLocEnd()),
+                               Sources, Result.Context->getLangOpts());
+
+  if (!FileRange.isValid())
+    return;
+
+  // FIXME: Instead of re-lexing and looking for specific macros such as
+  // 'ABSTRACT', properly store the location of 'virtual' and '= 0' in each
+  // FunctionDecl.
+  SmallVector<Token, 16> Tokens = ParseTokens(FileRange, Sources,
+                                              Result.Context->getLangOpts());
+
+  // Add 'override' on inline declarations that don't already have it.
+  if (Method->getAttr<clang::OverrideAttr>() == nullptr) {
+    SourceLocation InsertLoc;
+    StringRef ReplacementText = "override ";
+
+    if (Method->hasAttrs()) {
+      for (const clang::Attr *attr : Method->getAttrs()) {
+        if (!attr->isImplicit()) {
+          InsertLoc = Sources.getExpansionLoc(attr->getLocation());
+          break;
+        }
+      }
+    }
+
+    if (InsertLoc.isInvalid() && Method->doesThisDeclarationHaveABody()) {
+      InsertLoc = Method->getBody()->getLocStart();
+    }
+
+    if (!InsertLoc.isValid()) {
+      if (Tokens.size() > 2 && GetText(Tokens.back(), Sources) == "0" &&
+          GetText(Tokens[Tokens.size() - 2], Sources) == "=") {
+        InsertLoc = Tokens[Tokens.size() - 2].getLocation();
+      } else if (GetText(Tokens.back(), Sources) == "ABSTRACT") {
+        InsertLoc = Tokens.back().getLocation();
+      }
+    }
+
+    if (!InsertLoc.isValid()) {
+      InsertLoc = FileRange.getEnd();
+      ReplacementText = " override";
+    }
+    Diag << FixItHint::CreateInsertion(InsertLoc, ReplacementText);
+  }
+
+  if (Method->isVirtualAsWritten()) {
+    for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
+      if (Tokens[i].is(tok::raw_identifier) &&
+          GetText(Tokens[i], Sources) == "virtual") {
+        Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+            Tokens[i].getLocation(), Tokens[i].getLocation()));
+        break;
+      }
+    }
+  }
+}
+
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/misc/UseOverride.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/UseOverride.h?rev=208954&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/UseOverride.h (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/UseOverride.h Fri May 16 04:30:09 2014
@@ -0,0 +1,29 @@
+//===--- UseOverride.h - clang-tidy -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USE_OVERRIDE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USE_OVERRIDE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// \brief Use C++11's 'override' and remove 'virtual' where applicable.
+class UseOverride : public ClangTidyCheck {
+public:
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USE_OVERRIDE_H
+

Modified: clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy_fix.sh
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy_fix.sh?rev=208954&r1=208953&r2=208954&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy_fix.sh (original)
+++ clang-tools-extra/trunk/test/clang-tidy/check_clang_tidy_fix.sh Fri May 16 04:30:09 2014
@@ -8,4 +8,4 @@ TEMPORARY_FILE=$3.cpp
 
 grep -Ev "// *[A-Z-]+:" ${INPUT_FILE} > ${TEMPORARY_FILE}
 clang-tidy ${TEMPORARY_FILE} -fix --checks="-*,${CHECK_TO_RUN}" -- --std=c++11
-FileCheck -input-file=${TEMPORARY_FILE} ${INPUT_FILE}
+FileCheck -input-file=${TEMPORARY_FILE} ${INPUT_FILE} -strict-whitespace

Added: clang-tools-extra/trunk/test/clang-tidy/use-override.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/use-override.cpp?rev=208954&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/use-override.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/use-override.cpp Fri May 16 04:30:09 2014
@@ -0,0 +1,134 @@
+// RUN: $(dirname %s)/check_clang_tidy_fix.sh %s misc-use-override %t
+// REQUIRES: shell
+
+#define ABSTRACT = 0
+
+#define OVERRIDE override
+#define VIRTUAL virtual
+#define NOT_VIRTUAL
+#define NOT_OVERRIDE
+
+#define MUST_USE_RESULT __attribute__((warn_unused_result))
+
+struct MUST_USE_RESULT MustUseResultObject {};
+
+struct Base {
+  virtual ~Base() {}
+  virtual void a();
+  virtual void b();
+  virtual void c();
+  virtual void d();
+  virtual void e() = 0;
+  virtual void f() = 0;
+  virtual void g() = 0;
+
+  virtual void j() const;
+  virtual MustUseResultObject k();
+  virtual bool l() MUST_USE_RESULT;
+};
+
+struct SimpleCases : public Base {
+public:
+  virtual ~SimpleCases();
+  // CHECK: {{^  ~SimpleCases\(\) override;}}
+
+  void a();
+  // CHECK: {{^  void a\(\) override;}}
+  void b() override;
+  // CHECK: {{^  void b\(\) override;}}
+  virtual void c();
+  // CHECK: {{^  void c\(\) override;}}
+  virtual void d() override;
+  // CHECK: {{^  void d\(\) override;}}
+
+  virtual void e() = 0;
+  // CHECK: {{^  void e\(\) override = 0;}}
+  virtual void f()=0;
+  // CHECK: {{^  void f\(\)override =0;}}
+  virtual void g() ABSTRACT;
+  // CHECK: {{^  void g\(\) override ABSTRACT;}}
+
+  virtual void j() const;
+  // CHECK: {{^  void j\(\) const override;}}
+  virtual MustUseResultObject k();  // Has an implicit attribute.
+  // CHECK: {{^  MustUseResultObject k\(\) override;}}
+  virtual bool l() MUST_USE_RESULT; // Has an explicit attribute
+  // CHECK: {{^  bool l\(\) override MUST_USE_RESULT;}}
+};
+
+void SimpleCases::i() {}
+// CHECK: {{^void SimpleCases::i\(\) {}}}
+
+struct InlineDefinitions : public Base {
+public:
+  virtual ~InlineDefinitions() {}
+  // CHECK: {{^  ~InlineDefinitions\(\) override {}}}
+
+  void a() {}
+  // CHECK: {{^  void a\(\) override {}}}
+  void b() override {}
+  // CHECK: {{^  void b\(\) override {}}}
+  virtual void c() {}
+  // CHECK: {{^  void c\(\) override {}}}
+  virtual void d() override {}
+  // CHECK: {{^  void d\(\) override {}}}
+
+  virtual void j() const {}
+  // CHECK: {{^  void j\(\) const override {}}}
+  virtual MustUseResultObject k() {}  // Has an implicit attribute.
+  // CHECK: {{^  MustUseResultObject k\(\) override {}}}
+  virtual bool l() MUST_USE_RESULT {} // Has an explicit attribute
+  // CHECK: {{^  bool l\(\) override MUST_USE_RESULT {}}}
+};
+
+struct Macros : public Base {
+  // Tests for 'virtual' and 'override' being defined through macros. Basically
+  // give up for now.
+  NOT_VIRTUAL void a() NOT_OVERRIDE;
+  // CHECK: {{^  NOT_VIRTUAL void a\(\) override NOT_OVERRIDE;}}
+
+  VIRTUAL void b() NOT_OVERRIDE;
+  // CHECK: {{^  VIRTUAL void b\(\) override NOT_OVERRIDE;}}
+
+  NOT_VIRTUAL void c() OVERRIDE;
+  // CHECK: {{^  NOT_VIRTUAL void c\(\) OVERRIDE;}}
+
+  VIRTUAL void d() OVERRIDE;
+  // CHECK: {{^  VIRTUAL void d\(\) OVERRIDE;}}
+
+#define FUNC(name, return_type) return_type name()
+  FUNC(void, e);
+  // CHECK: {{^  FUNC\(void, e\);}}
+
+#define F virtual void f();
+  F
+  // CHECK: {{^  F}}
+};
+
+// Tests for templates.
+template <typename T> struct TemplateBase {
+  virtual void f(T t);
+};
+
+template <typename T> struct DerivedFromTemplate : public TemplateBase<T> {
+  virtual void f(T t);
+  // CHECK: {{^  void f\(T t\) override;}}
+};
+void f() { DerivedFromTemplate<int>().f(2); }
+
+template <class C>
+struct UnusedMemberInstantiation : public C {
+  virtual ~UnusedMemberInstantiation() {}
+  // CHECK: {{^  ~UnusedMemberInstantiation\(\) override {}}}
+};
+struct IntantiateWithoutUse : public UnusedMemberInstantiation<Base> {};
+
+// The OverrideAttr isn't propagated to specializations in all cases. Make sure
+// we don't add "override" a second time.
+template <int I>
+struct MembersOfSpecializations : public Base {
+  void a() override;
+  // CHECK: {{^  void a\(\) override;}}
+};
+template <> void MembersOfSpecializations<3>::a() {}
+void f() { D<3>().a(); };





More information about the cfe-commits mailing list