[clang-tidy] Move misc-use-override and readability-shrink-to-fit to "modernize/"

These checks are focusing on migrating the code from C++98/03 to C++11, so they
belong to the modernize module.

llvm-svn: 246437
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 1d575af5..1858924 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -6,8 +6,10 @@
   ModernizeTidyModule.cpp
   PassByValueCheck.cpp
   ReplaceAutoPtrCheck.cpp
+  ShrinkToFitCheck.cpp
   UseAutoCheck.cpp
   UseNullptrCheck.cpp
+  UseOverrideCheck.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 71c6221..ff0666f 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -13,8 +13,10 @@
 #include "LoopConvertCheck.h"
 #include "PassByValueCheck.h"
 #include "ReplaceAutoPtrCheck.h"
+#include "ShrinkToFitCheck.h"
 #include "UseAutoCheck.h"
 #include "UseNullptrCheck.h"
+#include "UseOverrideCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -29,8 +31,10 @@
     CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
     CheckFactories.registerCheck<ReplaceAutoPtrCheck>(
         "modernize-replace-auto-ptr");
+    CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
     CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");
     CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
+    CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
   }
 
   ClangTidyOptions getModuleOptions() override {
diff --git a/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp
new file mode 100644
index 0000000..c5e9e5e
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp
@@ -0,0 +1,104 @@
+//===--- ShrinkToFitCheck.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 "ShrinkToFitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace {
+bool isShrinkableContainer(llvm::StringRef ClassName) {
+  static const char *Shrinkables[] = {
+    "std::basic_string",
+    "std::deque",
+    "std::vector"
+  };
+  return std::binary_search(std::begin(Shrinkables), std::end(Shrinkables),
+                            ClassName);
+}
+
+AST_MATCHER(NamedDecl, stlShrinkableContainer) {
+  return isShrinkableContainer(Node.getQualifiedNameAsString());
+}
+} // namespace
+
+namespace tidy {
+namespace modernize {
+
+void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) {
+  // Swap as a function need not to be considered, because rvalue can not
+  // be bound to a non-const reference.
+  const auto ShrinkableAsMember =
+      memberExpr(member(valueDecl().bind("ContainerDecl")));
+  const auto ShrinkableAsDecl =
+      declRefExpr(hasDeclaration(valueDecl().bind("ContainerDecl")));
+  const auto CopyCtorCall = constructExpr(
+      hasArgument(0, anyOf(ShrinkableAsMember, ShrinkableAsDecl,
+                           unaryOperator(has(ShrinkableAsMember)),
+                           unaryOperator(has(ShrinkableAsDecl)))));
+  const auto SwapParam = expr(anyOf(
+      memberExpr(member(equalsBoundNode("ContainerDecl"))),
+      declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))),
+      unaryOperator(has(memberExpr(member(equalsBoundNode("ContainerDecl"))))),
+      unaryOperator(
+          has(declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl")))))));
+
+  Finder->addMatcher(
+      memberCallExpr(on(hasType(namedDecl(stlShrinkableContainer()))),
+                     callee(methodDecl(hasName("swap"))),
+                     has(memberExpr(hasDescendant(CopyCtorCall))),
+                     hasArgument(0, SwapParam.bind("ContainerToShrink")),
+                     unless(isInTemplateInstantiation()))
+          .bind("CopyAndSwapTrick"),
+      this);
+}
+
+void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) {
+  const LangOptions &Opts = Result.Context->getLangOpts();
+
+  if (!Opts.CPlusPlus11)
+    return;
+
+  const auto *MemberCall =
+      Result.Nodes.getNodeAs<CXXMemberCallExpr>("CopyAndSwapTrick");
+  const auto *Container = Result.Nodes.getNodeAs<Expr>("ContainerToShrink");
+  FixItHint Hint;
+
+  if (!MemberCall->getLocStart().isMacroID()) {
+    std::string ReplacementText;
+    if (const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
+      ReplacementText =
+          Lexer::getSourceText(CharSourceRange::getTokenRange(
+                                   UnaryOp->getSubExpr()->getSourceRange()),
+                               *Result.SourceManager, Opts);
+      ReplacementText += "->shrink_to_fit()";
+    } else {
+      ReplacementText = Lexer::getSourceText(
+          CharSourceRange::getTokenRange(Container->getSourceRange()),
+          *Result.SourceManager, Opts);
+      ReplacementText += ".shrink_to_fit()";
+    }
+
+    Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
+                                        ReplacementText);
+  }
+
+  diag(MemberCall->getLocStart(), "the shrink_to_fit method should be used "
+                                  "to reduce the capacity of a shrinkable "
+                                  "container")
+      << Hint;
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.h b/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.h
new file mode 100644
index 0000000..1e3745c
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.h
@@ -0,0 +1,37 @@
+//===--- ShrinkToFitCheck.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_MODERNIZE_SHRINKTOFITCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_SHRINKTOFITCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Replace copy and swap tricks on shrinkable containers with the
+/// `shrink_to_fit()` method call.
+///
+/// The `shrink_to_fit()` method is more readable and more effective than
+/// the copy and swap trick to reduce the capacity of a shrinkable container.
+/// Note that, the `shrink_to_fit()` method is only available in C++11 and up.
+class ShrinkToFitCheck : public ClangTidyCheck {
+public:
+  ShrinkToFitCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_SHRINKTOFITCHECK_H
diff --git a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
new file mode 100644
index 0000000..e506e83
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
@@ -0,0 +1,197 @@
+//===--- UseOverrideCheck.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 "UseOverrideCheck.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 {
+namespace modernize {
+
+void UseOverrideCheck::registerMatchers(MatchFinder *Finder) {
+  // Only register the matcher for C++11.
+  if (getLangOpts().CPlusPlus11)
+    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 MatchFinder::MatchResult &Result) {
+  const SourceManager &Sources = *Result.SourceManager;
+  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),
+                 Result.Context->getLangOpts(), 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;
+    if (Tok.is(tok::raw_identifier)) {
+      IdentifierInfo &Info = Result.Context->Idents.get(StringRef(
+          Sources.getCharacterData(Tok.getLocation()), Tok.getLength()));
+      Tok.setIdentifierInfo(&Info);
+      Tok.setKind(Info.getTokenID());
+    }
+    Tokens.push_back(Tok);
+  }
+  return Tokens;
+}
+
+static StringRef GetText(const Token &Tok, const SourceManager &Sources) {
+  return StringRef(Sources.getCharacterData(Tok.getLocation()),
+                   Tok.getLength());
+}
+
+void UseOverrideCheck::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;
+
+  bool HasVirtual = Method->isVirtualAsWritten();
+  bool HasOverride = Method->getAttr<OverrideAttr>();
+  bool HasFinal = Method->getAttr<FinalAttr>();
+
+  bool OnlyVirtualSpecified = HasVirtual && !HasOverride && !HasFinal;
+  unsigned KeywordCount = HasVirtual + HasOverride + HasFinal;
+
+  if (!OnlyVirtualSpecified && KeywordCount == 1)
+    return; // Nothing to do.
+
+  std::string Message;
+
+  if (OnlyVirtualSpecified) {
+    Message =
+        "prefer using 'override' or (rarely) 'final' instead of 'virtual'";
+  } else if (KeywordCount == 0) {
+    Message = "annotate this function with 'override' or (rarely) 'final'";
+  } else {
+    StringRef Redundant =
+        HasVirtual ? (HasOverride && HasFinal ? "'virtual' and 'override' are"
+                                              : "'virtual' is")
+                   : "'override' is";
+    StringRef Correct = HasFinal ? "'final'" : "'override'";
+
+    Message =
+        (llvm::Twine(Redundant) +
+         " redundant since the function is already declared " + Correct).str();
+  }
+
+  DiagnosticBuilder Diag = diag(Method->getLocation(), Message);
+
+  CharSourceRange FileRange = Lexer::makeFileCharRange(
+      CharSourceRange::getTokenRange(Method->getSourceRange()), 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, Result);
+
+  // Add 'override' on inline declarations that don't already have it.
+  if (!HasFinal && !HasOverride) {
+    SourceLocation InsertLoc;
+    StringRef ReplacementText = "override ";
+
+    for (Token T : Tokens) {
+      if (T.is(tok::kw___attribute)) {
+        InsertLoc = T.getLocation();
+        break;
+      }
+    }
+
+    if (Method->hasAttrs()) {
+      for (const clang::Attr *A : Method->getAttrs()) {
+        if (!A->isImplicit()) {
+          SourceLocation Loc =
+              Sources.getExpansionLoc(A->getRange().getBegin());
+          if (!InsertLoc.isValid() ||
+              Sources.isBeforeInTranslationUnit(Loc, InsertLoc))
+            InsertLoc = Loc;
+        }
+      }
+    }
+
+    if (InsertLoc.isInvalid() && Method->doesThisDeclarationHaveABody() &&
+        Method->getBody() && !Method->isDefaulted()) {
+      // For methods with inline definition, add the override keyword at the
+      // end of the declaration of the function, but prefer to put it on the
+      // same line as the declaration if the beginning brace for the start of
+      // the body falls on the next line.
+      Token LastNonCommentToken;
+      for (Token T : Tokens) {
+        if (!T.is(tok::comment)) {
+          LastNonCommentToken = T;
+        }
+      }
+      InsertLoc = LastNonCommentToken.getEndLoc();
+      ReplacementText = " override";
+    }
+
+    if (!InsertLoc.isValid()) {
+      // For declarations marked with "= 0" or "= [default|delete]", the end
+      // location will point until after those markings. Therefore, the override
+      // keyword shouldn't be inserted at the end, but before the '='.
+      if (Tokens.size() > 2 && (GetText(Tokens.back(), Sources) == "0" ||
+                                Tokens.back().is(tok::kw_default) ||
+                                Tokens.back().is(tok::kw_delete)) &&
+          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 (HasFinal && HasOverride) {
+    SourceLocation OverrideLoc = Method->getAttr<OverrideAttr>()->getLocation();
+    Diag << FixItHint::CreateRemoval(
+        CharSourceRange::getTokenRange(OverrideLoc, OverrideLoc));
+  }
+
+  if (HasVirtual) {
+    for (Token Tok : Tokens) {
+      if (Tok.is(tok::kw_virtual)) {
+        Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+            Tok.getLocation(), Tok.getLocation()));
+        break;
+      }
+    }
+  }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
new file mode 100644
index 0000000..83ce7da
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
@@ -0,0 +1,32 @@
+//===--- UseOverrideCheck.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_MODERNIZE_USEOVERRIDECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEOVERRIDECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Use C++11's `override` and remove `virtual` where applicable.
+class UseOverrideCheck : public ClangTidyCheck {
+public:
+  UseOverrideCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEOVERRIDECHECK_H