1 //===--- clang-wpa.cpp - clang whole program analyzer ---------------------===// 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 tool reads a sequence of precompiled AST files, and do various 11 // cross translation unit analyses. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/Basic/FileManager.h" 16 #include "clang/Basic/SourceManager.h" 17 #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" 18 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 20 #include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" 21 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 22 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" 23 #include "clang/Frontend/ASTUnit.h" 24 #include "clang/Frontend/CompilerInstance.h" 25 #include "clang/Index/CallGraph.h" 26 #include "clang/Index/Indexer.h" 27 #include "clang/Index/TranslationUnit.h" 28 #include "clang/Index/DeclReferenceMap.h" 29 #include "clang/Index/SelectorMap.h" 30 #include "clang/Lex/Preprocessor.h" 31 #include "clang/Basic/TargetInfo.h" 32 #include "llvm/ADT/IntrusiveRefCntPtr.h" 33 #include "llvm/Support/CommandLine.h" 34 #include "llvm/Support/raw_ostream.h" 35 using namespace clang; 36 using namespace idx; 37 38 static llvm::cl::list<std::string> 39 InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>")); 40 41 static llvm::cl::opt<bool> 42 ViewCallGraph("view-call-graph", llvm::cl::desc("Display the call graph.")); 43 44 static llvm::cl::opt<std::string> 45 AnalyzeFunction("analyze-function", 46 llvm::cl::desc("Specify the entry function.")); 47 48 namespace { 49 // A thin wrapper over ASTUnit implementing the TranslationUnit interface. 50 class ASTUnitTU : public TranslationUnit { 51 ASTUnit *AST; 52 DeclReferenceMap DeclRefMap; 53 SelectorMap SelMap; 54 55 public: 56 ASTUnitTU(ASTUnit *ast) 57 : AST(ast), DeclRefMap(AST->getASTContext()), SelMap(AST->getASTContext()) { 58 } 59 60 virtual ASTContext &getASTContext() { 61 return AST->getASTContext(); 62 } 63 64 virtual Preprocessor &getPreprocessor() { 65 return AST->getPreprocessor(); 66 } 67 68 virtual Diagnostic &getDiagnostic() { 69 return AST->getDiagnostics(); 70 } 71 72 virtual DeclReferenceMap &getDeclReferenceMap() { 73 return DeclRefMap; 74 } 75 76 virtual SelectorMap &getSelectorMap() { 77 return SelMap; 78 } 79 }; 80 } 81 82 int main(int argc, char **argv) { 83 llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa"); 84 std::vector<ASTUnit*> ASTUnits; 85 86 Program Prog; 87 Indexer Idxer(Prog); 88 89 if (InputFilenames.empty()) 90 return 0; 91 92 DiagnosticOptions DiagOpts; 93 llvm::IntrusiveRefCntPtr<Diagnostic> Diags 94 = CompilerInstance::createDiagnostics(DiagOpts, argc, argv); 95 for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) { 96 const std::string &InFile = InputFilenames[i]; 97 llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromASTFile(InFile, Diags, 98 FileSystemOptions(), 99 false, 0, 0, true)); 100 if (!AST) 101 return 1; 102 103 ASTUnits.push_back(AST.take()); 104 } 105 106 if (ViewCallGraph) { 107 llvm::OwningPtr<CallGraph> CG; 108 CG.reset(new CallGraph(Prog)); 109 110 for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i) 111 CG->addTU(ASTUnits[i]->getASTContext()); 112 113 CG->ViewCallGraph(); 114 return 0; 115 } 116 117 if (AnalyzeFunction.empty()) 118 return 0; 119 120 // Feed all ASTUnits to the Indexer. 121 for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i) { 122 ASTUnitTU *TU = new ASTUnitTU(ASTUnits[i]); 123 Idxer.IndexAST(TU); 124 } 125 126 Entity Ent = Entity::get(AnalyzeFunction, Prog); 127 FunctionDecl *FD; 128 TranslationUnit *TU; 129 llvm::tie(FD, TU) = Idxer.getDefinitionFor(Ent); 130 131 if (!FD) 132 return 0; 133 134 // Create an analysis engine. 135 Preprocessor &PP = TU->getPreprocessor(); 136 137 AnalyzerOptions Opts; 138 139 // Hard code options and checkers for now. 140 141 Opts.MaxNodes = 300000; 142 Opts.MaxLoop = 3; 143 Opts.InlineCall = true; 144 Opts.CFGAddImplicitDtors = true; 145 Opts.EagerlyTrimEGraph = true; 146 147 Opts.CheckersControlList.push_back(std::make_pair("core", true)); 148 if (PP.getTargetInfo().getTriple().getOS() != llvm::Triple::Win32) 149 Opts.CheckersControlList.push_back(std::make_pair("unix", true)); 150 if (PP.getTargetInfo().getTriple().getVendor() == llvm::Triple::Apple) 151 Opts.CheckersControlList.push_back(std::make_pair("macosx", true)); 152 153 // Checks to perform for Objective-C/Objective-C++. 154 if (PP.getLangOptions().ObjC1) 155 Opts.CheckersControlList.push_back(std::make_pair("cocoa", true)); 156 157 llvm::OwningPtr<ento::CheckerManager> checkerMgr; 158 checkerMgr.reset(ento::registerCheckers(Opts, PP.getLangOptions(), 159 PP.getDiagnostics())); 160 161 using namespace clang::ento; 162 AnalysisManager AMgr(TU->getASTContext(), PP.getDiagnostics(), 163 PP.getLangOptions(), /* PathDiagnostic */ 0, 164 CreateRegionStoreManager, 165 CreateRangeConstraintManager, checkerMgr.get(), &Idxer, 166 Opts.MaxNodes, Opts.MaxLoop, 167 Opts.VisualizeEGDot, Opts.VisualizeEGUbi, 168 Opts.PurgeDead, Opts.EagerlyAssume, 169 Opts.TrimGraph, Opts.InlineCall, 170 Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors, 171 Opts.CFGAddInitializers, 172 Opts.EagerlyTrimEGraph); 173 174 TransferFuncs* TF = MakeCFRefCountTF(AMgr.getASTContext(), /*GC*/false, 175 AMgr.getLangOptions()); 176 ExprEngine Eng(AMgr, TF); 177 178 Eng.ExecuteWorkList(AMgr.getStackFrame(FD, TU), AMgr.getMaxNodes()); 179 180 return 0; 181 } 182