Some more updates mostly simplifying the interface for implementing
ClangTidyChecks.
Hi klimek, chandlerc, doug.gregor,
http://llvm-reviews.chandlerc.com/D884
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D884?vs=2270&id=2272#toc
Files:
CMakeLists.txt
clang-tidy/CMakeLists.txt
clang-tidy/ClangTidy.cpp
clang-tidy/ClangTidy.h
clang-tidy/ClangTidyDiagnosticConsumer.h
clang-tidy/ClangTidyModule.h
clang-tidy/ClangTidyModuleRegistry.h
clang-tidy/google/CMakeLists.txt
clang-tidy/google/GoogleTidyModule.cpp
clang-tidy/google/GoogleTidyModule.h
clang-tidy/llvm/CMakeLists.txt
clang-tidy/llvm/LLVMTidyModule.cpp
clang-tidy/llvm/LLVMTidyModule.h
test/CMakeLists.txt
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,191 @@
+//===--- 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 "ClangTidyDiagnosticConsumer.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:
+ ClangTidyPPAction(SmallVectorImpl<NamedCheck> &Checks,
+ ClangTidyContext &Context)
+ : Checks(Checks), Context(Context) {}
+
+private:
+ virtual bool BeginSourceFileAction(CompilerInstance &Compiler,
+ llvm::StringRef file_name) {
+ Context.setSourceManager(&Compiler.getSourceManager());
+ for (SmallVectorImpl<NamedCheck>::iterator I = Checks.begin(),
+ E = Checks.end();
+ I != E; ++I)
+ I->Check->registerPPCallbacks(Compiler);
+ return true;
+ }
+
+ SmallVectorImpl<NamedCheck> &Checks;
+ ClangTidyContext &Context;
+};
+
+class ClangTidyPPActionFactory : public FrontendActionFactory {
+public:
+ ClangTidyPPActionFactory(SmallVectorImpl<NamedCheck> &Checks,
+ ClangTidyContext &Context)
+ : Checks(Checks), Context(Context) {}
+
+ virtual FrontendAction *create() {
+ return new ClangTidyPPAction(Checks, Context);
+ }
+
+private:
+ SmallVectorImpl<NamedCheck> &Checks;
+ ClangTidyContext &Context;
+};
+
+} // 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;
+ ClangTidyDiagnosticConsumer DiagConsumer(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 (SmallVectorImpl<NamedCheck>::iterator I = ModuleChecks.begin(),
+ E = ModuleChecks.end();
+ I != E; ++I) {
+ if (CheckRegex.match(I->Name))
+ Checks.push_back(*I);
+ }
+ }
+
+ MatchFinder Finder;
+ for (SmallVectorImpl<NamedCheck>::iterator I = Checks.begin(),
+ E = Checks.end();
+ I != E; ++I) {
+ I->Check->SetContext(&Context);
+ I->Check->registerMatchers(&Finder);
+ }
+
+ Tool.run(new clang::tidy::ClangTidyPPActionFactory(Checks, Context));
+ 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,112 @@
+//===--- 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/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/Diagnostic.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.
+///
+/// This is used as an intermediate format to transport Diagnostics without a
+/// dependency on a SourceManager. The goal is to make Diagnostics flexible
+/// enough to support this directly.
+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 \c DiagnosticEngine
+/// provided by this context.
+class ClangTidyContext {
+public:
+ /// \brief Report any errors detected using this method.
+ ///
+ /// This is still under heavy development and will likely change towards using
+ /// tablegen'd diagnostic IDs.
+ DiagnosticBuilder Diag(SourceLocation Loc, StringRef Message) {
+ return DiagEngine->Report(
+ Loc, DiagEngine->getCustomDiagID(DiagnosticsEngine::Warning, Message));
+ }
+
+ /// \brief Store a \c ClangTidyError.
+ ///
+ /// This should not be used directly.
+ void storeError(const ClangTidyError &Error) { Errors.push_back(Error); }
+
+ const ClangTidyErrors &errors() const { return Errors; }
+ void setDiagnosticsEngine(DiagnosticsEngine *Engine) { DiagEngine = Engine; }
+ void setSourceManager(SourceManager *SourceMgr) {
+ DiagEngine->setSourceManager(SourceMgr);
+ }
+
+private:
+ ClangTidyErrors Errors;
+ DiagnosticsEngine *DiagEngine;
+};
+
+/// \brief Base class for all clang-tidy checks.
+class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ virtual ~ClangTidyCheck() {}
+
+ void SetContext(ClangTidyContext *Ctx) { Context = Ctx; }
+ virtual void registerPPCallbacks(CompilerInstance &Compiler) {}
+ virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {}
+
+ virtual void check(const ast_matchers::MatchFinder::MatchResult &Result) {}
+
+protected:
+ ClangTidyContext *Context;
+
+private:
+ virtual void run(const ast_matchers::MatchFinder::MatchResult &Result) {
+ Context->setSourceManager(Result.SourceManager);
+ check(Result);
+ }
+};
+
+/// \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/ClangTidyDiagnosticConsumer.h
===================================================================
--- /dev/null
+++ clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -0,0 +1,59 @@
+//===--- ClangTidyDiagnosticConsumer.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_DIAGNOSTIC_CONSUMER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_DIAGNOSTIC_CONSUMER_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Refactoring.h"
+#include "llvm/ADT/SmallString.h"
+
+namespace clang {
+
+class CompilerInstance;
+namespace ast_matchers { class MatchFinder; }
+namespace tooling { class CompilationDatabase; }
+
+namespace tidy {
+
+class ClangTidyDiagnosticConsumer : public DiagnosticConsumer {
+public:
+ ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx) : Context(Ctx) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ Diags.reset(new DiagnosticsEngine(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+ this, /*ShouldOwnClient=*/ false));
+ Context.setDiagnosticsEngine(Diags.get());
+ }
+
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
+ tooling::Replacements Replacements;
+ SourceManager &SourceMgr = Info.getSourceManager();
+ for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) {
+ Replacements.insert(tooling::Replacement(
+ SourceMgr, Info.getFixItHint(i).RemoveRange.getBegin(), 0,
+ Info.getFixItHint(i).CodeToInsert));
+ }
+ SmallString<100> Buf;
+ Info.FormatDiagnostic(Buf);
+ Context.storeError(
+ ClangTidyError(SourceMgr, Info.getLocation(), Buf.str(), Replacements));
+ }
+
+private:
+ ClangTidyContext &Context;
+ OwningPtr<DiagnosticsEngine> Diags;
+};
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_DIAGNOSTIC_CONSUMER_H
Index: clang-tidy/ClangTidyModule.h
===================================================================
--- /dev/null
+++ clang-tidy/ClangTidyModule.h
@@ -0,0 +1,39 @@
+//===--- 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 {
+
+struct NamedCheck {
+ NamedCheck(StringRef Name, ClangTidyCheck *Check)
+ : Name(Name), Check(Check) {}
+ std::string Name;
+ ClangTidyCheck *Check;
+};
+
+/// \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(SmallVectorImpl<NamedCheck> &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
+ GoogleTidyModule.cpp
+ )
+target_link_libraries(clangTidyGoogleModule
+ clangTooling
+ clangBasic
+ clangASTMatchers
+ )
Index: clang-tidy/google/GoogleTidyModule.cpp
===================================================================
--- /dev/null
+++ clang-tidy/google/GoogleTidyModule.cpp
@@ -0,0 +1,62 @@
+//===--- GoogleTidyModule.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 "GoogleTidyModule.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 {
+
+void
+ExplicitConstructorCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
+ Finder->addMatcher(constructorDecl().bind("construct"), this);
+}
+
+void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
+ const CXXConstructorDecl *Ctor =
+ Result.Nodes.getNodeAs<CXXConstructorDecl>("construct");
+ if (!Ctor->isExplicit() && !Ctor->isImplicit() && Ctor->getNumParams() >= 1 &&
+ Ctor->getMinRequiredArguments() <= 1) {
+ SourceLocation Loc = Ctor->getLocation();
+ Context->Diag(Loc, "Single-argument constructors must be explicit")
+ << FixItHint::CreateInsertion(Loc, "explicit ");
+ }
+}
+
+class GoogleModule : public ClangTidyModule {
+public:
+ virtual ~GoogleModule() {}
+
+ virtual void addChecks(SmallVectorImpl<NamedCheck> &Checks) {
+ Checks.push_back(NamedCheck("google-explicit-constructor",
+ new ExplicitConstructorCheck()));
+ }
+};
+
+// Register the GoogleTidyModule 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/GoogleTidyModule.h
===================================================================
--- /dev/null
+++ clang-tidy/google/GoogleTidyModule.h
@@ -0,0 +1,30 @@
+//===--- GoogleTidyModule.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_TIDY_MODULE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GOOGLE_TIDY_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);
+ virtual void check(const ast_matchers::MatchFinder::MatchResult &Result);
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GOOGLE_TIDY_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
+ LLVMTidyModule.cpp
+ )
+target_link_libraries(clangTidyLLVMModule
+ clangTooling
+ clangBasic
+ clangASTMatchers
+ )
Index: clang-tidy/llvm/LLVMTidyModule.cpp
===================================================================
--- /dev/null
+++ clang-tidy/llvm/LLVMTidyModule.cpp
@@ -0,0 +1,103 @@
+//===--- LLVMTidyModule.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 "LLVMTidyModule.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 {
+
+void
+NamespaceCommentCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
+ Finder->addMatcher(namespaceDecl().bind("namespace"), this);
+}
+
+void NamespaceCommentCheck::check(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".
+ if (Tok.is(tok::comment)) {
+ // FIXME: Check comment content.
+ return;
+ }
+ std::string Fix = " // namespace";
+ if (!ND->isAnonymousNamespace())
+ Fix = Fix.append(" ").append(ND->getNameAsString());
+
+ Context->Diag(ND->getLocation(),
+ "namespace not terminated with a closing comment")
+ << FixItHint::CreateInsertion(ND->getRBraceLoc().getLocWithOffset(1),
+ Fix);
+}
+
+namespace {
+class IncludeOrderPPCallbacks : public PPCallbacks {
+public:
+ explicit IncludeOrderPPCallbacks(ClangTidyContext &Context)
+ : Context(Context) {}
+
+ 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.
+ Context.Diag(HashLoc, "This is an include");
+ }
+
+private:
+ ClangTidyContext &Context;
+};
+} // namespace
+
+void IncludeOrderCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Compiler.getPreprocessor()
+ .addPPCallbacks(new IncludeOrderPPCallbacks(*Context));
+}
+
+class LLVMModule : public ClangTidyModule {
+public:
+ virtual ~LLVMModule() {}
+
+ virtual void addChecks(SmallVectorImpl<NamedCheck> &Checks) {
+ Checks.push_back(
+ NamedCheck("llvm-include-order", new IncludeOrderCheck()));
+ Checks.push_back(
+ NamedCheck("llvm-namespace-comment", new NamespaceCommentCheck()));
+ }
+};
+
+// Register the LLVMTidyModule 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/LLVMTidyModule.h
===================================================================
--- /dev/null
+++ clang-tidy/llvm/LLVMTidyModule.h
@@ -0,0 +1,38 @@
+//===--- LLVMTidyModule.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_TIDY_MODULE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_LLVM_TIDY_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);
+ virtual void check(const ast_matchers::MatchFinder::MatchResult &Result);
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_TIDY_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: 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,20 @@
+//===--- ClangTidyTest.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 "ClangTidy.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+
+TEST(ClangTidyTest, Basic) {
+}
+
+} // namespace tidy
+} // namespace clang
Index: unittests/clang-tidy/ClangTidyTest.h
===================================================================
--- /dev/null
+++ unittests/clang-tidy/ClangTidyTest.h
@@ -0,0 +1,75 @@
+//===--- 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 "ClangTidyDiagnosticConsumer.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.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(StringRef Code) {
+ ClangTidyDiagnosticConsumer DiagConsumer(Context);
+ Check->SetContext(&Context);
+ EXPECT_TRUE(
+ tooling::runToolOnCode(new TestPPAction(*Check, &Context), 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);
+ }
+
+ void expectNoChanges(StringRef Code) { EXPECT_EQ(Code, runCheckOn(Code)); }
+
+private:
+ class TestPPAction : public PreprocessOnlyAction {
+ public:
+ TestPPAction(ClangTidyCheck &Check, ClangTidyContext *Context)
+ : Check(Check), Context(Context) {}
+
+ private:
+ virtual bool BeginSourceFileAction(CompilerInstance &Compiler,
+ llvm::StringRef file_name) {
+ Context->setSourceManager(&Compiler.getSourceManager());
+ Check.registerPPCallbacks(Compiler);
+ return true;
+ }
+
+ ClangTidyCheck &Check;
+ ClangTidyContext *Context;
+ };
+
+ 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,26 @@
+#include "ClangTidyTest.h"
+
+#include "google/GoogleTidyModule.h"
+
+namespace clang {
+namespace tidy {
+
+typedef ClangTidyTest<ExplicitConstructorCheck> ExplicitConstructorCheckTest;
+
+TEST_F(ExplicitConstructorCheckTest, SingleArgumentConstructorsOnly) {
+ expectNoChanges("class C { C(); };");
+ expectNoChanges("class C { C(int i, int j); };");
+}
+
+TEST_F(ExplicitConstructorCheckTest, Basic) {
+ EXPECT_EQ("class C { explicit C(int i); };",
+ runCheckOn("class C { C(int i); };"));
+}
+
+TEST_F(ExplicitConstructorCheckTest, DefaultParameters) {
+ EXPECT_EQ("class C { explicit C(int i, int j = 0); };",
+ runCheckOn("class C { C(int i, int j = 0); };"));
+}
+
+} // 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/LLVMTidyModule.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