1 //===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements a clang-check tool that runs clang based on the info 10 // stored in a compilation database. 11 // 12 // This tool uses the Clang Tooling infrastructure, see 13 // http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html 14 // for details on setting it up with LLVM source tree. 15 // 16 //===----------------------------------------------------------------------===// 17 18 #include "clang/AST/ASTConsumer.h" 19 #include "clang/CodeGen/ObjectFilePCHContainerOperations.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 #include "llvm/Support/TargetSelect.h" 33 34 using namespace clang::driver; 35 using namespace clang::tooling; 36 using namespace llvm; 37 38 static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); 39 static cl::extrahelp MoreHelp( 40 "\tFor example, to run clang-check on all files in a subtree of the\n" 41 "\tsource tree, use:\n" 42 "\n" 43 "\t find path/in/subtree -name '*.cpp'|xargs clang-check\n" 44 "\n" 45 "\tor using a specific build path:\n" 46 "\n" 47 "\t find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n" 48 "\n" 49 "\tNote, that path/in/subtree and current directory should follow the\n" 50 "\trules described above.\n" 51 "\n" 52 ); 53 54 static cl::OptionCategory ClangCheckCategory("clang-check options"); 55 static const opt::OptTable &Options = getDriverOptTable(); 56 static cl::opt<bool> 57 ASTDump("ast-dump", 58 cl::desc(Options.getOptionHelpText(options::OPT_ast_dump)), 59 cl::cat(ClangCheckCategory)); 60 static cl::opt<bool> 61 ASTList("ast-list", 62 cl::desc(Options.getOptionHelpText(options::OPT_ast_list)), 63 cl::cat(ClangCheckCategory)); 64 static cl::opt<bool> 65 ASTPrint("ast-print", 66 cl::desc(Options.getOptionHelpText(options::OPT_ast_print)), 67 cl::cat(ClangCheckCategory)); 68 static cl::opt<std::string> ASTDumpFilter( 69 "ast-dump-filter", 70 cl::desc(Options.getOptionHelpText(options::OPT_ast_dump_filter)), 71 cl::cat(ClangCheckCategory)); 72 static cl::opt<bool> 73 Analyze("analyze", 74 cl::desc(Options.getOptionHelpText(options::OPT_analyze)), 75 cl::cat(ClangCheckCategory)); 76 77 static cl::opt<bool> 78 Fixit("fixit", cl::desc(Options.getOptionHelpText(options::OPT_fixit)), 79 cl::cat(ClangCheckCategory)); 80 static cl::opt<bool> FixWhatYouCan( 81 "fix-what-you-can", 82 cl::desc(Options.getOptionHelpText(options::OPT_fix_what_you_can)), 83 cl::cat(ClangCheckCategory)); 84 85 namespace { 86 87 // FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp 88 // into a header file and reuse that. 89 class FixItOptions : public clang::FixItOptions { 90 public: 91 FixItOptions() { 92 FixWhatYouCan = ::FixWhatYouCan; 93 } 94 95 std::string RewriteFilename(const std::string& filename, int &fd) override { 96 // We don't need to do permission checking here since clang will diagnose 97 // any I/O errors itself. 98 99 fd = -1; // No file descriptor for file. 100 101 return filename; 102 } 103 }; 104 105 /// Subclasses \c clang::FixItRewriter to not count fixed errors/warnings 106 /// in the final error counts. 107 /// 108 /// This has the side-effect that clang-check -fixit exits with code 0 on 109 /// successfully fixing all errors. 110 class FixItRewriter : public clang::FixItRewriter { 111 public: 112 FixItRewriter(clang::DiagnosticsEngine& Diags, 113 clang::SourceManager& SourceMgr, 114 const clang::LangOptions& LangOpts, 115 clang::FixItOptions* FixItOpts) 116 : clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) { 117 } 118 119 bool IncludeInDiagnosticCounts() const override { return false; } 120 }; 121 122 /// Subclasses \c clang::FixItAction so that we can install the custom 123 /// \c FixItRewriter. 124 class ClangCheckFixItAction : public clang::FixItAction { 125 public: 126 bool BeginSourceFileAction(clang::CompilerInstance& CI) 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(nullptr /*Dump to stdout.*/, ASTDumpFilter, 141 /*DumpDecls=*/true, 142 /*Deserialize=*/false, 143 /*DumpLookups=*/false, 144 clang::ADOF_Default); 145 if (ASTPrint) 146 return clang::CreateASTPrinter(nullptr, ASTDumpFilter); 147 return std::make_unique<clang::ASTConsumer>(); 148 } 149 }; 150 151 } // namespace 152 153 int main(int argc, const char **argv) { 154 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); 155 156 // Initialize targets for clang module support. 157 llvm::InitializeAllTargets(); 158 llvm::InitializeAllTargetMCs(); 159 llvm::InitializeAllAsmPrinters(); 160 llvm::InitializeAllAsmParsers(); 161 162 CommonOptionsParser OptionsParser(argc, argv, ClangCheckCategory); 163 ClangTool Tool(OptionsParser.getCompilations(), 164 OptionsParser.getSourcePathList()); 165 166 // Clear adjusters because -fsyntax-only is inserted by the default chain. 167 Tool.clearArgumentsAdjusters(); 168 Tool.appendArgumentsAdjuster(getClangStripOutputAdjuster()); 169 Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); 170 171 // Running the analyzer requires --analyze. Other modes can work with the 172 // -fsyntax-only option. 173 Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster( 174 Analyze ? "--analyze" : "-fsyntax-only", ArgumentInsertPosition::BEGIN)); 175 176 ClangCheckActionFactory CheckFactory; 177 std::unique_ptr<FrontendActionFactory> FrontendFactory; 178 179 // Choose the correct factory based on the selected mode. 180 if (Analyze) 181 FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>(); 182 else if (Fixit) 183 FrontendFactory = newFrontendActionFactory<ClangCheckFixItAction>(); 184 else 185 FrontendFactory = newFrontendActionFactory(&CheckFactory); 186 187 return Tool.run(FrontendFactory.get()); 188 } 189