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