forked from OSchip/llvm-project
Initial architecture for clang-tidy.
This is the first version of a possible clang-tidy architecture. The purpose of clang-tidy is to detect errors in adhering to common coding patterns, e.g. described in the LLVM Coding Standards. This is still heavily in flux. Review: http://llvm-reviews.chandlerc.com/D884 llvm-svn: 187345
This commit is contained in:
parent
baca389e28
commit
d07c840e6a
|
@ -2,6 +2,7 @@ add_subdirectory(remove-cstr-calls)
|
|||
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)
|
||||
|
|
|
@ -12,7 +12,7 @@ CLANG_LEVEL := ../..
|
|||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
|
||||
PARALLEL_DIRS := remove-cstr-calls tool-template modularize
|
||||
DIRS := cpp11-migrate unittests
|
||||
DIRS := cpp11-migrate clang-tidy unittests
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
asmparser
|
||||
bitreader
|
||||
support
|
||||
mc
|
||||
)
|
||||
|
||||
add_clang_library(clangTidy
|
||||
ClangTidy.cpp
|
||||
ClangTidyModule.cpp
|
||||
)
|
||||
target_link_libraries(clangTidy
|
||||
clangTooling
|
||||
clangBasic
|
||||
clangRewriteFrontend
|
||||
clangTidyLLVMModule
|
||||
clangTidyGoogleModule
|
||||
)
|
||||
|
||||
add_subdirectory(tool)
|
||||
add_subdirectory(llvm)
|
||||
add_subdirectory(google)
|
|
@ -0,0 +1,184 @@
|
|||
//===--- 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/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/Path.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
using namespace clang::driver;
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace {
|
||||
|
||||
class ClangTidyPPAction : public PreprocessOnlyAction {
|
||||
public:
|
||||
ClangTidyPPAction(SmallVectorImpl<ClangTidyCheck *> &Checks,
|
||||
ClangTidyContext &Context)
|
||||
: Checks(Checks), Context(Context) {}
|
||||
|
||||
private:
|
||||
virtual bool BeginSourceFileAction(CompilerInstance &Compiler,
|
||||
llvm::StringRef file_name) {
|
||||
Context.setSourceManager(&Compiler.getSourceManager());
|
||||
for (SmallVectorImpl<ClangTidyCheck *>::iterator I = Checks.begin(),
|
||||
E = Checks.end();
|
||||
I != E; ++I)
|
||||
(*I)->registerPPCallbacks(Compiler);
|
||||
return true;
|
||||
}
|
||||
|
||||
SmallVectorImpl<ClangTidyCheck *> &Checks;
|
||||
ClangTidyContext &Context;
|
||||
};
|
||||
|
||||
class ClangTidyPPActionFactory : public FrontendActionFactory {
|
||||
public:
|
||||
ClangTidyPPActionFactory(SmallVectorImpl<ClangTidyCheck *> &Checks,
|
||||
ClangTidyContext &Context)
|
||||
: Checks(Checks), Context(Context) {}
|
||||
|
||||
virtual FrontendAction *create() {
|
||||
return new ClangTidyPPAction(Checks, Context);
|
||||
}
|
||||
|
||||
private:
|
||||
SmallVectorImpl<ClangTidyCheck *> &Checks;
|
||||
ClangTidyContext &Context;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
DiagnosticBuilder ClangTidyContext::Diag(SourceLocation Loc,
|
||||
StringRef Message) {
|
||||
return DiagEngine->Report(
|
||||
Loc, DiagEngine->getCustomDiagID(DiagnosticsEngine::Warning, Message));
|
||||
}
|
||||
|
||||
void ClangTidyContext::setDiagnosticsEngine(DiagnosticsEngine *Engine) {
|
||||
DiagEngine = Engine;
|
||||
}
|
||||
|
||||
void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
|
||||
DiagEngine->setSourceManager(SourceMgr);
|
||||
}
|
||||
|
||||
/// \brief Store a \c ClangTidyError.
|
||||
void ClangTidyContext::storeError(const ClangTidyError &Error) {
|
||||
Errors->push_back(Error);
|
||||
}
|
||||
|
||||
void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
|
||||
Context->setSourceManager(Result.SourceManager);
|
||||
check(Result);
|
||||
}
|
||||
|
||||
void runClangTidy(StringRef CheckRegexString,
|
||||
const tooling::CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> Ranges,
|
||||
SmallVectorImpl<ClangTidyError> *Errors) {
|
||||
// FIXME: Ranges are currently full files. Support selecting specific
|
||||
// (line-)ranges.
|
||||
ClangTool Tool(Compilations, Ranges);
|
||||
clang::tidy::ClangTidyContext Context(Errors);
|
||||
ClangTidyDiagnosticConsumer DiagConsumer(Context);
|
||||
ClangTidyCheckFactories CheckFactories;
|
||||
for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
|
||||
E = ClangTidyModuleRegistry::end();
|
||||
I != E; ++I) {
|
||||
OwningPtr<ClangTidyModule> Module(I->instantiate());
|
||||
Module->addCheckFactories(CheckFactories);
|
||||
}
|
||||
|
||||
SmallVector<ClangTidyCheck *, 16> Checks;
|
||||
CheckFactories.createChecks(CheckRegexString, Checks);
|
||||
|
||||
MatchFinder Finder;
|
||||
for (SmallVectorImpl<ClangTidyCheck *>::iterator I = Checks.begin(),
|
||||
E = Checks.end();
|
||||
I != E; ++I) {
|
||||
(*I)->setContext(&Context);
|
||||
(*I)->registerMatchers(&Finder);
|
||||
}
|
||||
|
||||
Tool.run(new ClangTidyPPActionFactory(Checks, Context));
|
||||
Tool.run(newFrontendActionFactory(&Finder));
|
||||
}
|
||||
|
||||
void handleErrors(SmallVectorImpl<ClangTidyError> &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 (SmallVectorImpl<ClangTidyError>::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
|
|
@ -0,0 +1,161 @@
|
|||
//===--- 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.
|
||||
///
|
||||
/// FIXME: Make Diagnostics flexible enough to support this directly.
|
||||
struct ClangTidyError {
|
||||
ClangTidyError(const SourceManager &Sources, SourceLocation Loc,
|
||||
StringRef Message, const tooling::Replacements &Fix);
|
||||
|
||||
std::string Message;
|
||||
unsigned FileOffset;
|
||||
std::string FilePath;
|
||||
tooling::Replacements Fix;
|
||||
};
|
||||
|
||||
/// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticEngine
|
||||
/// provided by this context.
|
||||
///
|
||||
/// A \c ClangTidyCheck always has access to the active context to report
|
||||
/// warnings like:
|
||||
/// \code
|
||||
/// Context->Diag(Loc, "Single-argument constructors must be explicit")
|
||||
/// << FixItHint::CreateInsertion(Loc, "explicit ");
|
||||
/// \endcode
|
||||
class ClangTidyContext {
|
||||
public:
|
||||
ClangTidyContext(SmallVectorImpl<ClangTidyError> *Errors) : Errors(Errors) {}
|
||||
|
||||
/// \brief Report any errors detected using this method.
|
||||
///
|
||||
/// This is still under heavy development and will likely change towards using
|
||||
/// tablegen'd diagnostic IDs.
|
||||
/// FIXME: Figure out a way to manage ID spaces.
|
||||
DiagnosticBuilder Diag(SourceLocation Loc, StringRef Message);
|
||||
|
||||
/// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
|
||||
/// correctly.
|
||||
///
|
||||
/// This is called from the \c ClangTidyCheck base class.
|
||||
void setDiagnosticsEngine(DiagnosticsEngine *Engine);
|
||||
|
||||
/// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine.
|
||||
///
|
||||
/// This is called from the \c ClangTidyCheck base class.
|
||||
void setSourceManager(SourceManager *SourceMgr);
|
||||
|
||||
private:
|
||||
friend class ClangTidyDiagnosticConsumer; // Calls storeError().
|
||||
|
||||
/// \brief Store a \c ClangTidyError.
|
||||
void storeError(const ClangTidyError &Error);
|
||||
|
||||
SmallVectorImpl<ClangTidyError> *Errors;
|
||||
DiagnosticsEngine *DiagEngine;
|
||||
};
|
||||
|
||||
/// \brief Base class for all clang-tidy checks.
|
||||
///
|
||||
/// To implement a \c ClangTidyCheck, write a subclass and overwrite some of the
|
||||
/// base class's methods. E.g. to implement a check that validates namespace
|
||||
/// declarations, overwrite \c registerMatchers:
|
||||
///
|
||||
/// \code
|
||||
/// registerMatchers(ast_matchers::MatchFinder *Finder) {
|
||||
/// Finder->addMatcher(namespaceDecl().bind("namespace"), this);
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// and then overwrite \c check(const MatchResult &Result) to do the actual
|
||||
/// check for each match.
|
||||
///
|
||||
/// A new \c ClangTidyCheck instance is created per translation unit.
|
||||
///
|
||||
/// FIXME: Figure out whether carrying information from one TU to another is
|
||||
/// useful/necessary.
|
||||
class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback {
|
||||
public:
|
||||
virtual ~ClangTidyCheck() {}
|
||||
|
||||
/// \brief Overwrite this to register \c PPCallbacks with \c Compiler.
|
||||
///
|
||||
/// This should be used for clang-tidy checks that analyze preprocessor-
|
||||
/// dependent properties, e.g. the order of include directives.
|
||||
virtual void registerPPCallbacks(CompilerInstance &Compiler) {}
|
||||
|
||||
/// \brief Overwrite this to register ASTMatchers with \p Finder.
|
||||
///
|
||||
/// This should be used by clang-tidy checks that analyze code properties that
|
||||
/// dependent on AST knowledge.
|
||||
///
|
||||
/// You can register as many matchers as necessary with \p Finder. Usually,
|
||||
/// "this" will be used as callback, but you can also specify other callback
|
||||
/// classes. Thereby, different matchers can trigger different callbacks.
|
||||
///
|
||||
/// If you need to merge information between the different matchers, you can
|
||||
/// store these as members of the derived class. However, note that all
|
||||
/// matches occur in the order of the AST traversal.
|
||||
virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {}
|
||||
|
||||
/// \brief \c ClangTidyChecks that register ASTMatchers should do the actual
|
||||
/// work in here.
|
||||
virtual void check(const ast_matchers::MatchFinder::MatchResult &Result) {}
|
||||
|
||||
/// \brief The infrastructure sets the context to \p Ctx with this function.
|
||||
void setContext(ClangTidyContext *Ctx) { Context = Ctx; }
|
||||
|
||||
protected:
|
||||
ClangTidyContext *Context;
|
||||
|
||||
private:
|
||||
virtual void run(const ast_matchers::MatchFinder::MatchResult &Result);
|
||||
};
|
||||
|
||||
/// \brief Run a set of clang-tidy checks on a set of files.
|
||||
void runClangTidy(StringRef CheckRegexString,
|
||||
const tooling::CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> Ranges,
|
||||
SmallVectorImpl<ClangTidyError> *Errors);
|
||||
|
||||
// FIXME: This interface will need to be significantly extended to be useful.
|
||||
// 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(SmallVectorImpl<ClangTidyError> &Errors, bool Fix);
|
||||
|
||||
} // end namespace tidy
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_H
|
|
@ -0,0 +1,71 @@
|
|||
//===--- 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 {
|
||||
|
||||
/// \brief A diagnostic consumer that turns each \c Diagnostic into a
|
||||
/// \c SourceManager-independent \c ClangTidyError.
|
||||
//
|
||||
// FIXME: If we move away from unit-tests, this can be moved to a private
|
||||
// implementation file.
|
||||
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());
|
||||
}
|
||||
|
||||
// FIXME: The concept of converting between FixItHints and Replacements is
|
||||
// more generic and should be pulled out into a more useful Diagnostics
|
||||
// library.
|
||||
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
|
|
@ -0,0 +1,49 @@
|
|||
//===--- tools/extra/clang-tidy/ClangTidyModule.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 Implements classes required to build clang-tidy modules.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangTidyModule.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
|
||||
CheckFactoryBase::~CheckFactoryBase() {}
|
||||
|
||||
ClangTidyCheckFactories::~ClangTidyCheckFactories() {
|
||||
for (std::map<std::string, CheckFactoryBase *>::iterator
|
||||
I = Factories.begin(),
|
||||
E = Factories.end();
|
||||
I != E; ++I) {
|
||||
delete I->second;
|
||||
}
|
||||
}
|
||||
void ClangTidyCheckFactories::addCheckFactory(StringRef Name,
|
||||
CheckFactoryBase *Factory) {
|
||||
|
||||
Factories[Name] = Factory;
|
||||
}
|
||||
|
||||
void ClangTidyCheckFactories::createChecks(
|
||||
StringRef CheckRegexString, SmallVectorImpl<ClangTidyCheck *> &Checks) {
|
||||
llvm::Regex CheckRegex(CheckRegexString);
|
||||
for (std::map<std::string, CheckFactoryBase *>::iterator
|
||||
I = Factories.begin(),
|
||||
E = Factories.end();
|
||||
I != E; ++I) {
|
||||
if (CheckRegex.match(I->first))
|
||||
Checks.push_back(I->second->createCheck());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
|
@ -0,0 +1,98 @@
|
|||
//===--- 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 {
|
||||
|
||||
/// \brief A factory, that can instantiate a specific clang-tidy check for
|
||||
/// processing a translation unit.
|
||||
///
|
||||
/// In order to register your check with the \c ClangTidyModule, create a
|
||||
/// subclass of \c CheckFactoryBase and implement \c createCheck(). Then, use
|
||||
/// this subclass in \c ClangTidyModule::addCheckFactories().
|
||||
class CheckFactoryBase {
|
||||
public:
|
||||
virtual ~CheckFactoryBase();
|
||||
virtual ClangTidyCheck *createCheck() = 0;
|
||||
};
|
||||
|
||||
/// \brief A subclass of \c CheckFactoryBase that should be used for all
|
||||
/// \c ClangTidyChecks that don't require constructor parameters.
|
||||
///
|
||||
/// For example, if have a clang-tidy check like:
|
||||
/// \code
|
||||
/// class MyTidyCheck : public ClangTidyCheck {
|
||||
/// virtual void registerMatchers(ast_matchers::MatchFinder *Finder) { .. }
|
||||
/// };
|
||||
/// \endcode
|
||||
/// you can register it with:
|
||||
/// \code
|
||||
/// class MyModule : public ClangTidyModule {
|
||||
/// virtual void addCheckFactories(ClangTidyCheckFactories &CheckFactories) {
|
||||
/// CheckFactories.addCheckFactory(
|
||||
/// "myproject-my-check", new ClangTidyCheckFactory<MyTidyCheck>());
|
||||
/// }
|
||||
/// };
|
||||
/// \endcode
|
||||
template <typename T> class ClangTidyCheckFactory : public CheckFactoryBase {
|
||||
public:
|
||||
virtual ClangTidyCheck *createCheck() { return new T; }
|
||||
};
|
||||
|
||||
class ClangTidyCheckFactories;
|
||||
|
||||
/// \brief A clang-tidy module groups a number of \c ClangTidyChecks and gives
|
||||
/// them a prefixed name.
|
||||
class ClangTidyModule {
|
||||
public:
|
||||
virtual ~ClangTidyModule() {}
|
||||
|
||||
/// \brief Implement this function in order to register all \c CheckFactories
|
||||
/// belonging to this module.
|
||||
virtual void addCheckFactories(ClangTidyCheckFactories &CheckFactories) = 0;
|
||||
};
|
||||
|
||||
/// \brief A collection of \c ClangTidyCheckFactory instances.
|
||||
///
|
||||
/// All clang-tidy modules register their check factories with an instance of
|
||||
/// this object.
|
||||
class ClangTidyCheckFactories {
|
||||
public:
|
||||
ClangTidyCheckFactories() {}
|
||||
~ClangTidyCheckFactories();
|
||||
|
||||
/// \brief Register \p Factory with the name \p Name.
|
||||
///
|
||||
/// The \c ClangTidyCheckFactories object takes ownership of the \p Factory.
|
||||
void addCheckFactory(StringRef Name, CheckFactoryBase *Factory);
|
||||
|
||||
/// \brief Create instances of all checks matching \p CheckRegexString and
|
||||
/// store them in \p Checks.
|
||||
///
|
||||
/// The caller takes ownership of the return \c ClangTidyChecks.
|
||||
void createChecks(StringRef CheckRegexString,
|
||||
SmallVectorImpl<ClangTidyCheck *> &Checks);
|
||||
|
||||
private:
|
||||
StringRef FilterRegex;
|
||||
std::map<std::string, CheckFactoryBase *> Factories;
|
||||
};
|
||||
|
||||
} // end namespace tidy
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_MODULE_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
|
|
@ -0,0 +1,16 @@
|
|||
##===- tools/extra/clang-tidy/Makefile ----sssss------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../../..
|
||||
LIBRARYNAME := clangTidy
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
|
||||
DIRS = llvm google tool
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
|
@ -0,0 +1,10 @@
|
|||
set(LLVM_LINK_COMPONENTS support)
|
||||
|
||||
add_clang_library(clangTidyGoogleModule
|
||||
GoogleTidyModule.cpp
|
||||
)
|
||||
target_link_libraries(clangTidyGoogleModule
|
||||
clangTooling
|
||||
clangBasic
|
||||
clangASTMatchers
|
||||
)
|
|
@ -0,0 +1,61 @@
|
|||
//===--- 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 void addCheckFactories(ClangTidyCheckFactories &CheckFactories) {
|
||||
CheckFactories.addCheckFactory(
|
||||
"google-explicit-constructor",
|
||||
new ClangTidyCheckFactory<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
|
|
@ -0,0 +1,31 @@
|
|||
//===--- 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
|
|
@ -0,0 +1,12 @@
|
|||
##===- clang-tidy/google/Makefile --------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
CLANG_LEVEL := ../../../..
|
||||
LIBRARYNAME := clangTidyGoogleModule
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
|
@ -0,0 +1,10 @@
|
|||
set(LLVM_LINK_COMPONENTS support)
|
||||
|
||||
add_clang_library(clangTidyLLVMModule
|
||||
LLVMTidyModule.cpp
|
||||
)
|
||||
target_link_libraries(clangTidyLLVMModule
|
||||
clangTooling
|
||||
clangBasic
|
||||
clangASTMatchers
|
||||
)
|
|
@ -0,0 +1,104 @@
|
|||
//===--- 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 addCheckFactories(ClangTidyCheckFactories &CheckFactories) {
|
||||
CheckFactories.addCheckFactory(
|
||||
"llvm-include-order", new ClangTidyCheckFactory<IncludeOrderCheck>());
|
||||
CheckFactories.addCheckFactory(
|
||||
"llvm-namespace-comment",
|
||||
new ClangTidyCheckFactory<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
|
|
@ -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
|
|
@ -0,0 +1,12 @@
|
|||
##===- clang-tidy/llvm/Makefile ----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
CLANG_LEVEL := ../../../..
|
||||
LIBRARYNAME := clangTidyLLVMModule
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
|
@ -0,0 +1,18 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
asmparser
|
||||
bitreader
|
||||
support
|
||||
mc
|
||||
)
|
||||
|
||||
add_clang_executable(clang-tidy
|
||||
ClangTidyMain.cpp
|
||||
)
|
||||
target_link_libraries(clang-tidy
|
||||
clangTidy
|
||||
)
|
||||
|
||||
install(TARGETS clang-tidy
|
||||
RUNTIME DESTINATION bin)
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
//===--- tools/extra/clang-tidy/ClangTidyMain.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 "clang/Driver/OptTable.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "llvm/Support/CommandLine.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.
|
||||
|
||||
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.
|
||||
|
||||
SmallVector<clang::tidy::ClangTidyError, 16> Errors;
|
||||
clang::tidy::runClangTidy(Checks, *Compilations, Ranges, &Errors);
|
||||
clang::tidy::handleErrors(Errors, Fix);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
##===- clang-tidy/tool/Makefile ----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../../../..
|
||||
|
||||
TOOLNAME = clang-tidy
|
||||
|
||||
# No plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
|
||||
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
|
||||
clangFormat.a clangASTMatchers.a clangTooling.a clangFrontend.a \
|
||||
clangSerialization.a clangDriver.a clangParse.a clangSema.a \
|
||||
clangAnalysis.a clangRewriteFrontend.a clangRewriteCore.a \
|
||||
clangEdit.a clangAST.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
|
@ -27,7 +27,7 @@ set(CLANG_TOOLS_TEST_DEPS
|
|||
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
|
||||
|
|
|
@ -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
|
|
@ -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); };
|
|
@ -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); };
|
|
@ -6,3 +6,4 @@ function(add_extra_unittest test_dirname)
|
|||
endfunction()
|
||||
|
||||
add_subdirectory(cpp11-migrate)
|
||||
add_subdirectory(clang-tidy)
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
CLANG_LEVEL := ../../..
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
|
||||
PARALLEL_DIRS := cpp11-migrate
|
||||
PARALLEL_DIRS := cpp11-migrate clang-tidy
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
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
|
||||
LLVMModuleTest.cpp
|
||||
GoogleModuleTest.cpp)
|
||||
|
||||
target_link_libraries(ClangTidyTests
|
||||
gtest
|
||||
gtest_main
|
||||
clangTidy
|
||||
clangTooling
|
||||
clangBasic
|
||||
clangASTMatchers
|
||||
)
|
|
@ -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), Context(&Errors) {}
|
||||
|
||||
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));
|
||||
tooling::Replacements Fixes;
|
||||
for (SmallVector<ClangTidyError, 16>::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;
|
||||
};
|
||||
|
||||
OwningPtr<ClangTidyCheck> Check;
|
||||
SmallVector<ClangTidyError, 16> Errors;
|
||||
ClangTidyContext Context;
|
||||
};
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANG_TIDY_TEST_H
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,24 @@
|
|||
##===- unittests/clang-tidy/Makefile -----------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL = ../../../..
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
|
||||
TESTNAME = ClangTidy
|
||||
LINK_COMPONENTS := asmparser bitreader support MC MCParser option
|
||||
USEDLIBS = clangTidy.a clangTidyLLVMModule.a clangTidyGoogleModule.a \
|
||||
clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
|
||||
clangDriver.a clangRewriteFrontend.a clangRewriteCore.a \
|
||||
clangParse.a clangSema.a clangAnalysis.a clangAST.a \
|
||||
clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
MAKEFILE_UNITTEST_NO_INCLUDE_COMMON := 1
|
||||
CPP.Flags += -I$(PROJ_SRC_DIR)/../../clang-tidy
|
||||
include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
|
Loading…
Reference in New Issue