1*f4a2713aSLionel Sambuc //===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===// 2*f4a2713aSLionel Sambuc // 3*f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure 4*f4a2713aSLionel Sambuc // 5*f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source 6*f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details. 7*f4a2713aSLionel Sambuc // 8*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 9*f4a2713aSLionel Sambuc // 10*f4a2713aSLionel Sambuc // This file implements a clang-check tool that runs clang based on the info 11*f4a2713aSLionel Sambuc // stored in a compilation database. 12*f4a2713aSLionel Sambuc // 13*f4a2713aSLionel Sambuc // This tool uses the Clang Tooling infrastructure, see 14*f4a2713aSLionel Sambuc // http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html 15*f4a2713aSLionel Sambuc // for details on setting it up with LLVM source tree. 16*f4a2713aSLionel Sambuc // 17*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 18*f4a2713aSLionel Sambuc 19*f4a2713aSLionel Sambuc #include "clang/AST/ASTConsumer.h" 20*f4a2713aSLionel Sambuc #include "clang/Driver/Options.h" 21*f4a2713aSLionel Sambuc #include "clang/Frontend/ASTConsumers.h" 22*f4a2713aSLionel Sambuc #include "clang/Frontend/CompilerInstance.h" 23*f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" 24*f4a2713aSLionel Sambuc #include "clang/Rewrite/Frontend/FixItRewriter.h" 25*f4a2713aSLionel Sambuc #include "clang/Rewrite/Frontend/FrontendActions.h" 26*f4a2713aSLionel Sambuc #include "clang/Tooling/CommonOptionsParser.h" 27*f4a2713aSLionel Sambuc #include "clang/Tooling/Tooling.h" 28*f4a2713aSLionel Sambuc #include "llvm/Support/CommandLine.h" 29*f4a2713aSLionel Sambuc #include "llvm/Support/Path.h" 30*f4a2713aSLionel Sambuc #include "llvm/Support/Signals.h" 31*f4a2713aSLionel Sambuc #include "llvm/Option/OptTable.h" 32*f4a2713aSLionel Sambuc 33*f4a2713aSLionel Sambuc using namespace clang::driver; 34*f4a2713aSLionel Sambuc using namespace clang::tooling; 35*f4a2713aSLionel Sambuc using namespace llvm; 36*f4a2713aSLionel Sambuc using namespace llvm::opt; 37*f4a2713aSLionel Sambuc 38*f4a2713aSLionel Sambuc static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); 39*f4a2713aSLionel Sambuc static cl::extrahelp MoreHelp( 40*f4a2713aSLionel Sambuc "\tFor example, to run clang-check on all files in a subtree of the\n" 41*f4a2713aSLionel Sambuc "\tsource tree, use:\n" 42*f4a2713aSLionel Sambuc "\n" 43*f4a2713aSLionel Sambuc "\t find path/in/subtree -name '*.cpp'|xargs clang-check\n" 44*f4a2713aSLionel Sambuc "\n" 45*f4a2713aSLionel Sambuc "\tor using a specific build path:\n" 46*f4a2713aSLionel Sambuc "\n" 47*f4a2713aSLionel Sambuc "\t find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n" 48*f4a2713aSLionel Sambuc "\n" 49*f4a2713aSLionel Sambuc "\tNote, that path/in/subtree and current directory should follow the\n" 50*f4a2713aSLionel Sambuc "\trules described above.\n" 51*f4a2713aSLionel Sambuc "\n" 52*f4a2713aSLionel Sambuc ); 53*f4a2713aSLionel Sambuc 54*f4a2713aSLionel Sambuc static OwningPtr<OptTable> Options(createDriverOptTable()); 55*f4a2713aSLionel Sambuc static cl::opt<bool> ASTDump( 56*f4a2713aSLionel Sambuc "ast-dump", 57*f4a2713aSLionel Sambuc cl::desc(Options->getOptionHelpText(options::OPT_ast_dump))); 58*f4a2713aSLionel Sambuc static cl::opt<bool> ASTList( 59*f4a2713aSLionel Sambuc "ast-list", 60*f4a2713aSLionel Sambuc cl::desc(Options->getOptionHelpText(options::OPT_ast_list))); 61*f4a2713aSLionel Sambuc static cl::opt<bool> ASTPrint( 62*f4a2713aSLionel Sambuc "ast-print", 63*f4a2713aSLionel Sambuc cl::desc(Options->getOptionHelpText(options::OPT_ast_print))); 64*f4a2713aSLionel Sambuc static cl::opt<std::string> ASTDumpFilter( 65*f4a2713aSLionel Sambuc "ast-dump-filter", 66*f4a2713aSLionel Sambuc cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter))); 67*f4a2713aSLionel Sambuc static cl::opt<bool> Analyze( 68*f4a2713aSLionel Sambuc "analyze", 69*f4a2713aSLionel Sambuc cl::desc(Options->getOptionHelpText(options::OPT_analyze))); 70*f4a2713aSLionel Sambuc 71*f4a2713aSLionel Sambuc static cl::opt<bool> Fixit( 72*f4a2713aSLionel Sambuc "fixit", 73*f4a2713aSLionel Sambuc cl::desc(Options->getOptionHelpText(options::OPT_fixit))); 74*f4a2713aSLionel Sambuc static cl::opt<bool> FixWhatYouCan( 75*f4a2713aSLionel Sambuc "fix-what-you-can", 76*f4a2713aSLionel Sambuc cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can))); 77*f4a2713aSLionel Sambuc 78*f4a2713aSLionel Sambuc static cl::list<std::string> ArgsAfter("extra-arg", 79*f4a2713aSLionel Sambuc cl::desc("Additional argument to append to the compiler command line")); 80*f4a2713aSLionel Sambuc static cl::list<std::string> ArgsBefore("extra-arg-before", 81*f4a2713aSLionel Sambuc cl::desc("Additional argument to prepend to the compiler command line")); 82*f4a2713aSLionel Sambuc 83*f4a2713aSLionel Sambuc namespace { 84*f4a2713aSLionel Sambuc 85*f4a2713aSLionel Sambuc // FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp 86*f4a2713aSLionel Sambuc // into a header file and reuse that. 87*f4a2713aSLionel Sambuc class FixItOptions : public clang::FixItOptions { 88*f4a2713aSLionel Sambuc public: 89*f4a2713aSLionel Sambuc FixItOptions() { 90*f4a2713aSLionel Sambuc FixWhatYouCan = ::FixWhatYouCan; 91*f4a2713aSLionel Sambuc } 92*f4a2713aSLionel Sambuc 93*f4a2713aSLionel Sambuc std::string RewriteFilename(const std::string& filename, int &fd) { 94*f4a2713aSLionel Sambuc assert(llvm::sys::path::is_absolute(filename) && 95*f4a2713aSLionel Sambuc "clang-fixit expects absolute paths only."); 96*f4a2713aSLionel Sambuc 97*f4a2713aSLionel Sambuc // We don't need to do permission checking here since clang will diagnose 98*f4a2713aSLionel Sambuc // any I/O errors itself. 99*f4a2713aSLionel Sambuc 100*f4a2713aSLionel Sambuc fd = -1; // No file descriptor for file. 101*f4a2713aSLionel Sambuc 102*f4a2713aSLionel Sambuc return filename; 103*f4a2713aSLionel Sambuc } 104*f4a2713aSLionel Sambuc }; 105*f4a2713aSLionel Sambuc 106*f4a2713aSLionel Sambuc /// \brief Subclasses \c clang::FixItRewriter to not count fixed errors/warnings 107*f4a2713aSLionel Sambuc /// in the final error counts. 108*f4a2713aSLionel Sambuc /// 109*f4a2713aSLionel Sambuc /// This has the side-effect that clang-check -fixit exits with code 0 on 110*f4a2713aSLionel Sambuc /// successfully fixing all errors. 111*f4a2713aSLionel Sambuc class FixItRewriter : public clang::FixItRewriter { 112*f4a2713aSLionel Sambuc public: 113*f4a2713aSLionel Sambuc FixItRewriter(clang::DiagnosticsEngine& Diags, 114*f4a2713aSLionel Sambuc clang::SourceManager& SourceMgr, 115*f4a2713aSLionel Sambuc const clang::LangOptions& LangOpts, 116*f4a2713aSLionel Sambuc clang::FixItOptions* FixItOpts) 117*f4a2713aSLionel Sambuc : clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) { 118*f4a2713aSLionel Sambuc } 119*f4a2713aSLionel Sambuc 120*f4a2713aSLionel Sambuc virtual bool IncludeInDiagnosticCounts() const { return false; } 121*f4a2713aSLionel Sambuc }; 122*f4a2713aSLionel Sambuc 123*f4a2713aSLionel Sambuc /// \brief Subclasses \c clang::FixItAction so that we can install the custom 124*f4a2713aSLionel Sambuc /// \c FixItRewriter. 125*f4a2713aSLionel Sambuc class FixItAction : public clang::FixItAction { 126*f4a2713aSLionel Sambuc public: 127*f4a2713aSLionel Sambuc virtual bool BeginSourceFileAction(clang::CompilerInstance& CI, 128*f4a2713aSLionel Sambuc StringRef Filename) { 129*f4a2713aSLionel Sambuc FixItOpts.reset(new FixItOptions); 130*f4a2713aSLionel Sambuc Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), 131*f4a2713aSLionel Sambuc CI.getLangOpts(), FixItOpts.get())); 132*f4a2713aSLionel Sambuc return true; 133*f4a2713aSLionel Sambuc } 134*f4a2713aSLionel Sambuc }; 135*f4a2713aSLionel Sambuc 136*f4a2713aSLionel Sambuc class InsertAdjuster: public clang::tooling::ArgumentsAdjuster { 137*f4a2713aSLionel Sambuc public: 138*f4a2713aSLionel Sambuc enum Position { BEGIN, END }; 139*f4a2713aSLionel Sambuc 140*f4a2713aSLionel Sambuc InsertAdjuster(const CommandLineArguments &Extra, Position Pos) 141*f4a2713aSLionel Sambuc : Extra(Extra), Pos(Pos) { 142*f4a2713aSLionel Sambuc } 143*f4a2713aSLionel Sambuc 144*f4a2713aSLionel Sambuc InsertAdjuster(const char *Extra, Position Pos) 145*f4a2713aSLionel Sambuc : Extra(1, std::string(Extra)), Pos(Pos) { 146*f4a2713aSLionel Sambuc } 147*f4a2713aSLionel Sambuc 148*f4a2713aSLionel Sambuc virtual CommandLineArguments 149*f4a2713aSLionel Sambuc Adjust(const CommandLineArguments &Args) LLVM_OVERRIDE { 150*f4a2713aSLionel Sambuc CommandLineArguments Return(Args); 151*f4a2713aSLionel Sambuc 152*f4a2713aSLionel Sambuc CommandLineArguments::iterator I; 153*f4a2713aSLionel Sambuc if (Pos == END) { 154*f4a2713aSLionel Sambuc I = Return.end(); 155*f4a2713aSLionel Sambuc } else { 156*f4a2713aSLionel Sambuc I = Return.begin(); 157*f4a2713aSLionel Sambuc ++I; // To leave the program name in place 158*f4a2713aSLionel Sambuc } 159*f4a2713aSLionel Sambuc 160*f4a2713aSLionel Sambuc Return.insert(I, Extra.begin(), Extra.end()); 161*f4a2713aSLionel Sambuc return Return; 162*f4a2713aSLionel Sambuc } 163*f4a2713aSLionel Sambuc 164*f4a2713aSLionel Sambuc private: 165*f4a2713aSLionel Sambuc const CommandLineArguments Extra; 166*f4a2713aSLionel Sambuc const Position Pos; 167*f4a2713aSLionel Sambuc }; 168*f4a2713aSLionel Sambuc 169*f4a2713aSLionel Sambuc } // namespace 170*f4a2713aSLionel Sambuc 171*f4a2713aSLionel Sambuc // Anonymous namespace here causes problems with gcc <= 4.4 on MacOS 10.6. 172*f4a2713aSLionel Sambuc // "Non-global symbol: ... can't be a weak_definition" 173*f4a2713aSLionel Sambuc namespace clang_check { 174*f4a2713aSLionel Sambuc class ClangCheckActionFactory { 175*f4a2713aSLionel Sambuc public: 176*f4a2713aSLionel Sambuc clang::ASTConsumer *newASTConsumer() { 177*f4a2713aSLionel Sambuc if (ASTList) 178*f4a2713aSLionel Sambuc return clang::CreateASTDeclNodeLister(); 179*f4a2713aSLionel Sambuc if (ASTDump) 180*f4a2713aSLionel Sambuc return clang::CreateASTDumper(ASTDumpFilter); 181*f4a2713aSLionel Sambuc if (ASTPrint) 182*f4a2713aSLionel Sambuc return clang::CreateASTPrinter(&llvm::outs(), ASTDumpFilter); 183*f4a2713aSLionel Sambuc return new clang::ASTConsumer(); 184*f4a2713aSLionel Sambuc } 185*f4a2713aSLionel Sambuc }; 186*f4a2713aSLionel Sambuc } 187*f4a2713aSLionel Sambuc 188*f4a2713aSLionel Sambuc int main(int argc, const char **argv) { 189*f4a2713aSLionel Sambuc llvm::sys::PrintStackTraceOnErrorSignal(); 190*f4a2713aSLionel Sambuc CommonOptionsParser OptionsParser(argc, argv); 191*f4a2713aSLionel Sambuc ClangTool Tool(OptionsParser.getCompilations(), 192*f4a2713aSLionel Sambuc OptionsParser.getSourcePathList()); 193*f4a2713aSLionel Sambuc 194*f4a2713aSLionel Sambuc // Clear adjusters because -fsyntax-only is inserted by the default chain. 195*f4a2713aSLionel Sambuc Tool.clearArgumentsAdjusters(); 196*f4a2713aSLionel Sambuc Tool.appendArgumentsAdjuster(new ClangStripOutputAdjuster()); 197*f4a2713aSLionel Sambuc if (ArgsAfter.size() > 0) { 198*f4a2713aSLionel Sambuc Tool.appendArgumentsAdjuster(new InsertAdjuster(ArgsAfter, 199*f4a2713aSLionel Sambuc InsertAdjuster::END)); 200*f4a2713aSLionel Sambuc } 201*f4a2713aSLionel Sambuc if (ArgsBefore.size() > 0) { 202*f4a2713aSLionel Sambuc Tool.appendArgumentsAdjuster(new InsertAdjuster(ArgsBefore, 203*f4a2713aSLionel Sambuc InsertAdjuster::BEGIN)); 204*f4a2713aSLionel Sambuc } 205*f4a2713aSLionel Sambuc 206*f4a2713aSLionel Sambuc // Running the analyzer requires --analyze. Other modes can work with the 207*f4a2713aSLionel Sambuc // -fsyntax-only option. 208*f4a2713aSLionel Sambuc Tool.appendArgumentsAdjuster(new InsertAdjuster( 209*f4a2713aSLionel Sambuc Analyze ? "--analyze" : "-fsyntax-only", InsertAdjuster::BEGIN)); 210*f4a2713aSLionel Sambuc 211*f4a2713aSLionel Sambuc clang_check::ClangCheckActionFactory CheckFactory; 212*f4a2713aSLionel Sambuc FrontendActionFactory *FrontendFactory; 213*f4a2713aSLionel Sambuc 214*f4a2713aSLionel Sambuc // Choose the correct factory based on the selected mode. 215*f4a2713aSLionel Sambuc if (Analyze) 216*f4a2713aSLionel Sambuc FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>(); 217*f4a2713aSLionel Sambuc else if (Fixit) 218*f4a2713aSLionel Sambuc FrontendFactory = newFrontendActionFactory<FixItAction>(); 219*f4a2713aSLionel Sambuc else 220*f4a2713aSLionel Sambuc FrontendFactory = newFrontendActionFactory(&CheckFactory); 221*f4a2713aSLionel Sambuc 222*f4a2713aSLionel Sambuc return Tool.run(FrontendFactory); 223*f4a2713aSLionel Sambuc } 224