Index: clang-tidy/CMakeLists.txt =================================================================== --- clang-tidy/CMakeLists.txt +++ clang-tidy/CMakeLists.txt @@ -2,6 +2,10 @@ Support ) +if(CLANG_PLUGIN_SUPPORT) + set(LLVM_NO_DEAD_STRIP 1) +endif() + add_clang_library(clangTidy ClangTidy.cpp ClangTidyModule.cpp Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -219,6 +219,7 @@ void exportReplacements(const std::vector &Errors, raw_ostream &OS); +void populateStaticAnalyzerCheckerList(StringRef Plugin, const char **Argv); } // end namespace tidy } // end namespace clang Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -18,6 +18,8 @@ #include "ClangTidy.h" #include "ClangTidyDiagnosticConsumer.h" #include "ClangTidyModuleRegistry.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Compilation.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -33,6 +35,7 @@ #include "clang/Rewrite/Frontend/FixItRewriter.h" #include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "clang/Tooling/Refactoring.h" #include "clang/Tooling/ReplacementsYaml.h" #include "clang/Tooling/Tooling.h" @@ -55,7 +58,7 @@ namespace { static const char *AnalyzerCheckNamePrefix = "clang-analyzer-"; -static StringRef StaticAnalyzerChecks[] = { +static std::vector StaticAnalyzerChecks = { #define GET_CHECKERS #define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \ FULLNAME, @@ -410,6 +413,36 @@ return Context.getStats(); } +void populateStaticAnalyzerCheckerList(StringRef Plugin, const char **Argv) { + IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); + TextDiagnosticPrinter DiagPrinter(llvm::outs(), &*DiagOpts); + DiagnosticsEngine DiagEng( + IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, + &DiagPrinter, /*ShouldOwn=*/false); + std::unique_ptr ClangDriver( + tooling::newDriver(&DiagEng, Argv[0])); + ClangDriver->setCheckInputsExist(false); + std::vector CommandLine{Argv[0], "-c", "dummy.cpp"}; + if (!Plugin.empty()) { + CommandLine.push_back("-Xclang"); + CommandLine.push_back("-load"); + CommandLine.push_back("-Xclang"); + CommandLine.push_back(Plugin.data()); + } + + std::unique_ptr Comp(ClangDriver->BuildCompilation(CommandLine)); + if (!Comp) + return; + + auto ArgList(getCC1Arguments(&DiagEng, &*Comp)); + if (ArgList == nullptr) + return; + + std::unique_ptr CI( + tooling::newInvocation(&DiagEng, *ArgList)); + StaticAnalyzerChecks = ento::getCheckerList(CI->getFrontendOpts().Plugins); +} + void handleErrors(const std::vector &Errors, bool Fix) { ErrorReporter Reporter(Fix); for (const ClangTidyError &Error : Errors) Index: clang-tidy/tool/CMakeLists.txt =================================================================== --- clang-tidy/tool/CMakeLists.txt +++ clang-tidy/tool/CMakeLists.txt @@ -20,3 +20,6 @@ install(TARGETS clang-tidy RUNTIME DESTINATION bin) +if(CLANG_PLUGIN_SUPPORT) + set_target_properties(clang-tidy PROPERTIES ENABLE_EXPORTS 1) +endif() Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -146,6 +146,12 @@ "code with clang-apply-replacements."), cl::value_desc("filename"), cl::cat(ClangTidyCategory)); +static cl::opt PluginPath( + "plugin-path", + cl::desc("Path of the shared object that contains static\n" + "analyzer checkers."), + cl::value_desc("filename"), cl::cat(ClangTidyCategory)); + namespace clang { namespace tidy { @@ -270,6 +276,8 @@ std::string FileName = OptionsParser.getSourcePathList().front(); ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FileName); + if (!PluginPath.empty()) + populateStaticAnalyzerCheckerList(PluginPath, argv); std::vector EnabledChecks = getCheckNames(EffectiveOptions); // FIXME: Allow using --list-checks without positional arguments. @@ -294,7 +302,7 @@ llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true); return 1; } - + ProfileData Profile; std::vector Errors; Index: clang-tidy/tool/Makefile =================================================================== --- clang-tidy/tool/Makefile +++ clang-tidy/tool/Makefile @@ -11,8 +11,11 @@ TOOLNAME = clang-tidy -# No plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 +ifeq ($(CLANG_PLUGIN_SUPPORT), 1) +NO_DEAD_STRIP := 1 +else +TOOL_NO_EXPORTS := 1 +endif include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option Index: test/clang-tidy/clang-static-analyzer-plugin.cpp =================================================================== --- test/clang-tidy/clang-static-analyzer-plugin.cpp +++ test/clang-tidy/clang-static-analyzer-plugin.cpp @@ -0,0 +1,12 @@ +// RUN: clang-tidy %s -checks='-*,clang-analyzer-example.MainCallChecker' -plugin-path %llvmshlibdir/SampleAnalyzerPlugin%pluginext -- | FileCheck %s +// REQUIRES: plugins, examples + +// Test that the MainCallChecker example analyzer plugin loads and runs. + +int main(); + +void caller() { + main(); + // CHECK: warning: call to main +} +