Addressed review comments.

Hi klimek, chandlerc, doug.gregor,

http://llvm-reviews.chandlerc.com/D884

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D884?vs=2172&id=2254#toc

Files:
  CMakeLists.txt
  clang-tidy/CMakeLists.txt
  clang-tidy/ClangTidy.cpp
  clang-tidy/ClangTidy.h
  clang-tidy/ClangTidyModule.h
  clang-tidy/ClangTidyModuleRegistry.h
  clang-tidy/google/CMakeLists.txt
  clang-tidy/google/GoogleModule.cpp
  clang-tidy/google/GoogleModule.h
  clang-tidy/llvm/CMakeLists.txt
  clang-tidy/llvm/LLVMModule.cpp
  clang-tidy/llvm/LLVMModule.h
  test/CMakeLists.txt
  test/clang-tidy/basic.cpp
  test/clang-tidy/fix.cpp
  test/clang-tidy/select-checks.cpp
  unittests/CMakeLists.txt
  unittests/clang-tidy/CMakeLists.txt
  unittests/clang-tidy/ClangTidyTest.cpp
  unittests/clang-tidy/ClangTidyTest.h
  unittests/clang-tidy/GoogleModuleTest.cpp
  unittests/clang-tidy/LLVMModuleTest.cpp
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -2,6 +2,7 @@
 add_subdirectory(tool-template)
 add_subdirectory(cpp11-migrate)
 add_subdirectory(modularize)
+add_subdirectory(clang-tidy)
 
 # Add the common testsuite after all the tools.
 add_subdirectory(test)
Index: clang-tidy/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-tidy/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  asmparser
+  bitreader
+  support
+  mc
+  )
+
+add_clang_executable(clang-tidy
+  ClangTidy.cpp
+  )
+
+target_link_libraries(clang-tidy
+  clangTooling
+  clangBasic
+  clangRewriteFrontend
+  clangTidyLLVMModule
+  clangTidyGoogleModule
+  )
+
+install(TARGETS clang-tidy
+  RUNTIME DESTINATION bin)
+
+add_subdirectory(llvm)
+add_subdirectory(google)
Index: clang-tidy/ClangTidy.cpp
===================================================================
--- /dev/null
+++ clang-tidy/ClangTidy.cpp
@@ -0,0 +1,180 @@
+//===--- tools/extra/clang-tidy/ClangTidy.cpp - Clang tidy tool -----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+///  \file This file implements a clang-tidy tool.
+///
+///  This tool uses the Clang Tooling infrastructure, see
+///    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+///  for details on setting it up with LLVM source tree.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidy.h"
+#include "ClangTidyModuleRegistry.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Options.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Frontend/FixItRewriter.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+#include "clang/Tooling/Refactoring.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/Signals.h"
+#include <vector>
+
+using namespace clang::ast_matchers;
+using namespace clang::driver;
+using namespace clang::tooling;
+using namespace llvm;
+
+cl::OptionCategory ClangTidyCategory("clang-tidy options");
+
+cl::list<std::string> Ranges(
+      cl::Positional, cl::desc("<range0> [... <rangeN>]"), cl::OneOrMore);
+
+static cl::opt<std::string> Checks(
+    "checks",
+    cl::desc("Regular expression matching the names of the checks to be run."),
+    cl::init(".*"), cl::cat(ClangTidyCategory));
+static cl::opt<bool> Fix("fix", cl::desc("Fix detected errors if possible."),
+                         cl::init(false), cl::cat(ClangTidyCategory));
+
+// FIXME: Add option to list name/description of all checks.
+
+namespace clang {
+namespace tidy {
+namespace {
+
+class ClangTidyPPAction : public PreprocessOnlyAction {
+public:
+  explicit ClangTidyPPAction(ClangTidyCheckVector &Checks)
+      : Checks(Checks) {}
+
+private:
+  virtual bool BeginSourceFileAction(CompilerInstance &Compiler,
+                                     llvm::StringRef file_name) {
+    for (ClangTidyCheckVector::iterator I = Checks.begin(), E = Checks.end();
+         I != E; ++I)
+      I->second->registerPPCallbacks(Compiler);
+    return true;
+  }
+
+  ClangTidyCheckVector& Checks;
+};
+
+class ClangTidyPPActionFactory : public FrontendActionFactory {
+public:
+   explicit ClangTidyPPActionFactory(ClangTidyCheckVector &Checks)
+       : Checks(Checks) {}
+  virtual FrontendAction *create() { return new ClangTidyPPAction(Checks); }
+
+private:
+  ClangTidyCheckVector &Checks;
+};
+
+} // namespace
+
+ClangTidyErrors runClangTidy(StringRef CheckRegexString,
+                             const tooling::CompilationDatabase &Compilations,
+                             ArrayRef<std::string> Ranges) {
+  // FIXME: Ranges are currently full files. Support selecting specific
+  // (line-)ranges.
+  ClangTool Tool(Compilations, Ranges);
+  clang::tidy::ClangTidyContext Context;
+  Regex CheckRegex(CheckRegexString);
+  SmallVector<NamedCheck, 16> Checks;
+  for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
+                                         E = ClangTidyModuleRegistry::end();
+       I != E; ++I) {
+    OwningPtr<ClangTidyModule> Module(I->instantiate());
+    SmallVector<NamedCheck, 16> ModuleChecks;
+    Module->addChecks(ModuleChecks);
+    for (ClangTidyCheckVector::iterator I = ModuleChecks.begin(),
+                                        E = ModuleChecks.end();
+         I != E; ++I) {
+      if (CheckRegex.match(I->first))
+        Checks.push_back(*I);
+    }
+  }
+
+  MatchFinder Finder;
+  for (ClangTidyCheckVector::iterator I = Checks.begin(), E = Checks.end();
+       I != E; ++I) {
+    I->second->SetContext(&Context);
+    I->second->registerMatchers(&Finder);
+  }
+
+  Tool.run(new clang::tidy::ClangTidyPPActionFactory(Checks));
+  Tool.run(newFrontendActionFactory(&Finder));
+
+  return Context.errors();
+}
+
+void handleErrors(ClangTidyErrors &Errors, bool Fix) {
+  FileManager Files((FileSystemOptions()));
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticConsumer *DiagPrinter =
+      new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts);
+  DiagnosticsEngine Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+                          &*DiagOpts, DiagPrinter);
+  DiagPrinter->BeginSourceFile(LangOptions());
+  SourceManager SourceMgr(Diags, Files);
+  Rewriter Rewrite(SourceMgr, LangOptions());
+  for (ClangTidyErrors::iterator I = Errors.begin(), E = Errors.end(); I != E;
+       ++I) {
+    const FileEntry *File = Files.getFile(I->FilePath);
+    FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
+    SourceLocation Loc = SourceMgr.getLocForStartOfFile(ID);
+    Diags.Report(Loc.getLocWithOffset(I->FileOffset),
+                 Diags.getCustomDiagID(DiagnosticsEngine::Warning, I->Message));
+    tooling::applyAllReplacements(I->Fix, Rewrite);
+  }
+  // FIXME: Run clang-format on changes.
+  if (Fix)
+    Rewrite.overwriteChangedFiles();
+}
+
+// This anchor is used to force the linker to link the LLVMModule.
+extern volatile int LLVMModuleAnchorSource;
+static int LLVMModuleAnchorDestination = LLVMModuleAnchorSource;
+
+// This anchor is used to force the linker to link the GoogleModule.
+extern volatile int GoogleModuleAnchorSource;
+static int GoogleModuleAnchorDestination = GoogleModuleAnchorSource;
+
+} // namespace tidy
+} // namespace clang
+
+using clang::tidy::ClangTidyErrors;
+
+int main(int argc, const char **argv) {
+  cl::ParseCommandLineOptions(argc, argv, "TBD\n");
+  OwningPtr<clang::tooling::CompilationDatabase> Compilations(
+      FixedCompilationDatabase::loadFromCommandLine(argc, argv));
+  if (!Compilations)
+    return 0;
+  // FIXME: Load other compilation databases.
+
+  ClangTidyErrors Errors =
+      clang::tidy::runClangTidy(Checks, *Compilations, Ranges);
+  clang::tidy::handleErrors(Errors, Fix);
+
+  return 0;
+}
Index: clang-tidy/ClangTidy.h
===================================================================
--- /dev/null
+++ clang-tidy/ClangTidy.h
@@ -0,0 +1,87 @@
+//===--- ClangTidy.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_CLANG_TIDY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_H
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Refactoring.h"
+
+namespace clang {
+
+class CompilerInstance;
+namespace ast_matchers { class MatchFinder; }
+namespace tooling { class CompilationDatabase; }
+
+namespace tidy {
+
+/// \brief A detected error complete with information to display diagnostic and
+/// automatic fix.
+struct ClangTidyError {
+  ClangTidyError(const SourceManager &Sources, SourceLocation Loc,
+                 StringRef Message, const tooling::Replacements &Fix)
+      : Message(Message), Fix(Fix) {
+    FilePath = Sources.getFilename(Loc);
+    FileOffset = Sources.getFileOffset(Loc);
+  }
+
+  std::string Message;
+  unsigned FileOffset;
+  std::string FilePath;
+  tooling::Replacements Fix;
+};
+
+typedef SmallVector<ClangTidyError, 16> ClangTidyErrors;
+
+/// \brief Every \c ClangTidyCheck reports errors through a context.
+class ClangTidyContext {
+public:
+  // FIXME: Provide a much more detailed explanation and examples of how to use
+  // this interface.
+  //
+  /// \brief Report a \c ClangTidyError.
+  ///
+  /// This is the main point of interaction for specific \c ClangTidyCheck
+  /// implementations.
+  void reportError(const ClangTidyError &Error) { Errors.push_back(Error); }
+
+  const ClangTidyErrors &errors() const { return Errors; }
+
+private:
+  ClangTidyErrors Errors;
+};
+
+/// \brief Base class for all clang-tidy checks.
+class ClangTidyCheck {
+public:
+  virtual ~ClangTidyCheck() {}
+
+  void SetContext(ClangTidyContext *Ctx) { Context = Ctx; }
+  virtual void registerPPCallbacks(CompilerInstance &Compiler) {}
+  virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {}
+
+protected:
+  ClangTidyContext *Context;
+};
+
+/// \brief Run a set of clang-tidy checks on a set of files.
+ClangTidyErrors runClangTidy(StringRef CheckRegexString,
+                             const tooling::CompilationDatabase &Compilations,
+                             ArrayRef<std::string> Ranges);
+
+// FIXME: Implement confidence levels for displaying/fixing errors.
+//
+/// \brief Displays the found \p Errors to the users. If \p Fix is true, \p
+/// Errors containing fixes are automatically applied.
+void handleErrors(ClangTidyErrors &Errors, bool Fix);
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_H
Index: clang-tidy/ClangTidyModule.h
===================================================================
--- /dev/null
+++ clang-tidy/ClangTidyModule.h
@@ -0,0 +1,35 @@
+//===--- ClangTidyModule.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_CLANG_TIDY_MODULE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_MODULE_H
+
+#include "ClangTidy.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <utility>
+
+namespace clang {
+namespace tidy {
+
+typedef std::pair<StringRef, ClangTidyCheck *> NamedCheck;
+typedef SmallVectorImpl<NamedCheck> ClangTidyCheckVector;
+
+/// \brief A clang-tidy module groups a number of \c ClangTidyChecks and
+/// gives them a prefixed name.
+class ClangTidyModule {
+public:
+  virtual ~ClangTidyModule() {}
+  virtual void addChecks(ClangTidyCheckVector &Checks) = 0;
+};
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_MODULE_H
Index: clang-tidy/ClangTidyModuleRegistry.h
===================================================================
--- /dev/null
+++ clang-tidy/ClangTidyModuleRegistry.h
@@ -0,0 +1,24 @@
+//===--- ClangTidyModuleRegistry.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_CLANG_TIDY_MODULE_REGISTRY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_MODULE_REGISTRY_H
+
+#include "ClangTidyModule.h"
+#include "llvm/Support/Registry.h"
+
+namespace clang {
+namespace tidy {
+
+typedef llvm::Registry<ClangTidyModule> ClangTidyModuleRegistry;
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_MODULE_REGISTRY_H
Index: clang-tidy/google/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-tidy/google/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyGoogleModule
+  GoogleModule.cpp
+  )
+target_link_libraries(clangTidyGoogleModule
+  clangTooling
+  clangBasic
+  clangASTMatchers
+  )
Index: clang-tidy/google/GoogleModule.cpp
===================================================================
--- /dev/null
+++ clang-tidy/google/GoogleModule.cpp
@@ -0,0 +1,80 @@
+//===--- LLVMModule.cpp - clang-tidy ----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GoogleModule.h"
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+namespace {
+
+class ConstructorCallback : public MatchFinder::MatchCallback {
+public:
+  ConstructorCallback(ClangTidyContext *Context) : Context(Context) {}
+
+  virtual void run(const MatchFinder::MatchResult &Result) {
+    const CXXConstructorDecl *Ctor =
+        Result.Nodes.getNodeAs<CXXConstructorDecl>("construct");
+    if (!Ctor->isExplicit() && !Ctor->isImplicit() &&
+        Ctor->getNumParams() == 1) {
+      SourceLocation Loc = Ctor->getLocation();
+      tooling::Replacements Replacements;
+      Replacements.insert(
+          tooling::Replacement(*Result.SourceManager, Loc, 0, "explicit "));
+      Context->reportError(ClangTidyError(
+          *Result.SourceManager, Loc,
+          "Single-argument constructors must be explicit", Replacements));
+    }
+  }
+
+private:
+  ClangTidyContext *Context;
+};
+
+} // namespace
+
+void
+ExplicitConstructorCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
+  Finder->addMatcher(constructorDecl().bind("construct"),
+                     new ConstructorCallback(Context));
+}
+
+class GoogleModule : public ClangTidyModule {
+public:
+  virtual ~GoogleModule() {}
+
+  virtual void addChecks(ClangTidyCheckVector &Checks) {
+    Checks.push_back(NamedCheck("google-explicit-constructor",
+                                new ExplicitConstructorCheck()));
+  }
+};
+
+// Register the JSONCompilationDatabasePlugin with the
+// CompilationDatabasePluginRegistry using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<GoogleModule> X("google-module",
+                                                    "Adds Google lint checks.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the GoogleModule.
+volatile int GoogleModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/google/GoogleModule.h
===================================================================
--- /dev/null
+++ clang-tidy/google/GoogleModule.h
@@ -0,0 +1,29 @@
+//===--- LLVMModule.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_GOOGLE_GOOGLE_MODULE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GOOGLE_MODULE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// \brief Checks that all single-argument constructors are explicit.
+///
+/// see: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Explicit_Constructors
+class ExplicitConstructorCheck : public ClangTidyCheck {
+public:
+  virtual void registerMatchers(ast_matchers::MatchFinder *Finder);
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GOOGLE_MODULE_H
Index: clang-tidy/llvm/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-tidy/llvm/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyLLVMModule
+  LLVMModule.cpp
+  )
+target_link_libraries(clangTidyLLVMModule
+  clangTooling
+  clangBasic
+  clangASTMatchers
+  )
Index: clang-tidy/llvm/LLVMModule.cpp
===================================================================
--- /dev/null
+++ clang-tidy/llvm/LLVMModule.cpp
@@ -0,0 +1,128 @@
+//===--- LLVMModule.cpp - clang-tidy ----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LLVMModule.h"
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+namespace {
+
+class NamespaceCommentCallback : public MatchFinder::MatchCallback {
+public:
+  NamespaceCommentCallback(ClangTidyContext *Context) : Context(Context) {}
+
+  virtual void run(const MatchFinder::MatchResult &Result) {
+    const NamespaceDecl *ND =
+        Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
+    Token Tok;
+    SourceLocation Loc = ND->getRBraceLoc().getLocWithOffset(1);
+    while (Lexer::getRawToken(Loc, Tok, *Result.SourceManager,
+                              Result.Context->getLangOpts())) {
+      Loc = Loc.getLocWithOffset(1);
+    }
+    // FIXME: Check that this namespace is "long".
+    bool IsProperlyTerminated = false;
+    if (Tok.is(tok::comment)) {
+      // FIXME: Check comment content.
+      IsProperlyTerminated = true;
+    }
+    if (!IsProperlyTerminated) {
+      std::string Fix = " // namespace";
+      if (!ND->isAnonymousNamespace())
+        Fix = Fix.append(" ").append(ND->getNameAsString());
+      tooling::Replacements Replacements;
+      Replacements.insert(
+          tooling::Replacement(*Result.SourceManager,
+                               ND->getRBraceLoc().getLocWithOffset(1), 0, Fix));
+      Context->reportError(ClangTidyError(
+          *Result.SourceManager, ND->getLocation(),
+          "namespace not terminated with a closing comment", Replacements));
+    }
+  }
+
+private:
+  ClangTidyContext *Context;
+};
+
+} // namespace
+
+void
+NamespaceCommentCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
+  Finder->addMatcher(namespaceDecl().bind("namespace"),
+                     new NamespaceCommentCallback(Context));
+}
+
+namespace {
+
+class IncludeOrderPPCallbacks : public PPCallbacks {
+public:
+  explicit IncludeOrderPPCallbacks(const SourceManager &Sources)
+      : Sources(Sources) {}
+
+  virtual void InclusionDirective(SourceLocation HashLoc,
+                                  const Token &IncludeTok, StringRef FileName,
+                                  bool IsAngled, CharSourceRange FilenameRange,
+                                  const FileEntry *File, StringRef SearchPath,
+                                  StringRef RelativePath,
+                                  const Module *Imported) {
+    // FIXME: This is a dummy implementation to show how to get at preprocessor
+    // information. Implement a real include order check.
+    StringRef SourceFile = Sources.getFilename(HashLoc);
+    if (!SourceFile.endswith(".cc"))
+      return;
+    llvm::errs() << FileName << ":" << SearchPath << "\n";
+  }
+
+private:
+  const SourceManager &Sources;
+};
+
+} // namespace
+
+void IncludeOrderCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+  Compiler.getPreprocessor()
+      .addPPCallbacks(new IncludeOrderPPCallbacks(Compiler.getSourceManager()));
+}
+
+class LLVMModule : public ClangTidyModule {
+public:
+  virtual ~LLVMModule() {}
+
+  virtual void addChecks(ClangTidyCheckVector &Checks) {
+    Checks.push_back(
+        NamedCheck("llvm-include-order", new IncludeOrderCheck()));
+    Checks.push_back(
+        NamedCheck("llvm-namespace-comment", new NamespaceCommentCheck()));
+  }
+};
+
+// Register the JSONCompilationDatabasePlugin with the
+// CompilationDatabasePluginRegistry using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<LLVMModule>
+    X("llvm-module", "Adds LLVM lint checks.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the LLVMModule.
+volatile int LLVMModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/llvm/LLVMModule.h
===================================================================
--- /dev/null
+++ clang-tidy/llvm/LLVMModule.h
@@ -0,0 +1,37 @@
+//===--- LLVMModule.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_LLVM_LLVM_MODULE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_LLVM_MODULE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// \brief Checks the correct order of \c #includes.
+///
+/// see: http://llvm.org/docs/CodingStandards.html#include-style
+class IncludeOrderCheck : public ClangTidyCheck {
+public:
+  virtual void registerPPCallbacks(CompilerInstance &Compiler);
+};
+
+/// \brief Checks that long namespaces have a closing comment.
+///
+/// see: http://llvm.org/docs/CodingStandards.html#namespace-indentation
+class NamespaceCommentCheck : public ClangTidyCheck {
+public:
+  virtual void registerMatchers(ast_matchers::MatchFinder *Finder);
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_LLVM_MODULE_H
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -27,7 +27,7 @@
   clang clang-headers FileCheck count not
 
   # Individual tools we test.
-  remove-cstr-calls cpp11-migrate modularize
+  remove-cstr-calls cpp11-migrate modularize clang-tidy
 
   # Unit tests
   ExtraToolsUnitTests
Index: test/clang-tidy/basic.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/basic.cpp
@@ -0,0 +1,7 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -- > %t2.cpp
+// RUN: FileCheck -input-file=%t2.cpp %s
+
+namespace i {
+}
+// CHECK: warning: namespace not terminated with a closing comment
Index: test/clang-tidy/fix.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/fix.cpp
@@ -0,0 +1,10 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -fix --
+// RUN: FileCheck -input-file=%t.cpp %s
+
+namespace i {
+}
+// CHECK: } // namespace i
+
+class A { A(int i); };
+// CHECK: class A { explicit A(int i); };
Index: test/clang-tidy/select-checks.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/select-checks.cpp
@@ -0,0 +1,10 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -fix -checks=llvm.* --
+// RUN: FileCheck -input-file=%t.cpp %s
+
+namespace i {
+}
+// CHECK: } // namespace i
+
+class A { A(int i); }; // Not fixing this, because the check is in google-.
+// CHECK: class A { A(int i); };
Index: unittests/CMakeLists.txt
===================================================================
--- unittests/CMakeLists.txt
+++ unittests/CMakeLists.txt
@@ -6,3 +6,4 @@
 endfunction()
 
 add_subdirectory(cpp11-migrate)
+add_subdirectory(clang-tidy)
Index: unittests/clang-tidy/CMakeLists.txt
===================================================================
--- /dev/null
+++ unittests/clang-tidy/CMakeLists.txt
@@ -0,0 +1,22 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+get_filename_component(CLANG_LINT_SOURCE_DIR
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-tidy REALPATH)
+include_directories(${CLANG_LINT_SOURCE_DIR})
+
+add_extra_unittest(ClangTidyTests
+  ClangTidyTest.cpp
+  LLVMModuleTest.cpp
+  GoogleModuleTest.cpp)
+
+target_link_libraries(ClangTidyTests
+  gtest
+  gtest_main
+  clangTidyLLVMModule
+  clangTidyGoogleModule
+  clangTooling
+  clangBasic
+  clangASTMatchers
+  )
Index: unittests/clang-tidy/ClangTidyTest.cpp
===================================================================
--- /dev/null
+++ unittests/clang-tidy/ClangTidyTest.cpp
@@ -0,0 +1,21 @@
+//===--- ClangTidyTest.cpp - clang-tidy -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidy.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+
+TEST(ClangTidyTest, Basic) {
+  ClangTidyContext Context;
+}
+
+} // namespace tidy
+} // namespace clang
Index: unittests/clang-tidy/ClangTidyTest.h
===================================================================
--- /dev/null
+++ unittests/clang-tidy/ClangTidyTest.h
@@ -0,0 +1,66 @@
+//===--- ClangTidyTest.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_UNITTESTS_CLANG_TIDY_CLANG_TIDY_TEST_H
+#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANG_TIDY_TEST_H
+
+
+#include "ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+
+template <typename T>
+class ClangTidyTest : public ::testing::Test {
+protected:
+  ClangTidyTest() : Check(new T) {}
+
+  std::string runCheckOn(llvm::StringRef Code) {
+    Check->SetContext(&Context);
+    EXPECT_TRUE(tooling::runToolOnCode(new TestPPAction(*Check), Code));
+    ast_matchers::MatchFinder Finder;
+    Check->registerMatchers(&Finder);
+    OwningPtr<tooling::FrontendActionFactory> Factory(
+        tooling::newFrontendActionFactory(&Finder));
+    EXPECT_TRUE(tooling::runToolOnCode(Factory->create(), Code));
+    ClangTidyErrors Errors = Context.errors();
+    tooling::Replacements Fixes;
+    for (ClangTidyErrors::const_iterator I = Errors.begin(), E = Errors.end();
+         I != E; ++I)
+      Fixes.insert(I->Fix.begin(), I->Fix.end());
+    return tooling::applyAllReplacements(Code, Fixes);
+  }
+
+private:
+  class TestPPAction : public PreprocessOnlyAction {
+  public:
+    TestPPAction(ClangTidyCheck &Check) : Check(Check) {}
+
+  private:
+    virtual bool BeginSourceFileAction(CompilerInstance &Compiler,
+                                       llvm::StringRef file_name) {
+      Check.registerPPCallbacks(Compiler);
+      return true;
+    }
+
+    ClangTidyCheck &Check;
+  };
+
+  ClangTidyContext Context;
+  OwningPtr<ClangTidyCheck> Check;
+};
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANG_TIDY_TEST_H
Index: unittests/clang-tidy/GoogleModuleTest.cpp
===================================================================
--- /dev/null
+++ unittests/clang-tidy/GoogleModuleTest.cpp
@@ -0,0 +1,16 @@
+#include "ClangTidyTest.h"
+
+#include "google/GoogleModule.h"
+
+namespace clang {
+namespace tidy {
+
+typedef ClangTidyTest<ExplicitConstructorCheck> ExplicitConstructorCheckTest;
+
+TEST_F(ExplicitConstructorCheckTest, Basic) {
+  EXPECT_EQ("class C { explicit C(int i); };",
+            runCheckOn("class C { C(int i); };"));
+}
+
+} // namespace tidy
+} // namespace clang
Index: unittests/clang-tidy/LLVMModuleTest.cpp
===================================================================
--- /dev/null
+++ unittests/clang-tidy/LLVMModuleTest.cpp
@@ -0,0 +1,15 @@
+#include "ClangTidyTest.h"
+
+#include "llvm/LLVMModule.h"
+
+namespace clang {
+namespace tidy {
+
+typedef ClangTidyTest<NamespaceCommentCheck> NamespaceCommentCheckTest;
+
+TEST_F(NamespaceCommentCheckTest, Basic) {
+  EXPECT_EQ("namespace i {\n} // namespace i", runCheckOn("namespace i {\n}"));
+}
+
+} // namespace tidy
+} // namespace clang
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to