• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ASTUnitTU(ASTUnit * ast)56   ASTUnitTU(ASTUnit *ast)
57     : AST(ast), DeclRefMap(AST->getASTContext()), SelMap(AST->getASTContext()) {
58   }
59 
getASTContext()60   virtual ASTContext &getASTContext() {
61     return AST->getASTContext();
62   }
63 
getPreprocessor()64   virtual Preprocessor &getPreprocessor() {
65     return AST->getPreprocessor();
66   }
67 
getDiagnostic()68   virtual Diagnostic &getDiagnostic() {
69     return AST->getDiagnostics();
70   }
71 
getDeclReferenceMap()72   virtual DeclReferenceMap &getDeclReferenceMap() {
73     return DeclRefMap;
74   }
75 
getSelectorMap()76   virtual SelectorMap &getSelectorMap() {
77     return SelMap;
78   }
79 };
80 }
81 
main(int argc,char ** argv)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