1*0a6a1f1dSLionel Sambuc //===-- ModelInjector.cpp ---------------------------------------*- C++ -*-===// 2*0a6a1f1dSLionel Sambuc // 3*0a6a1f1dSLionel Sambuc // The LLVM Compiler Infrastructure 4*0a6a1f1dSLionel Sambuc // 5*0a6a1f1dSLionel Sambuc // This file is distributed under the University of Illinois Open Source 6*0a6a1f1dSLionel Sambuc // License. See LICENSE.TXT for details. 7*0a6a1f1dSLionel Sambuc // 8*0a6a1f1dSLionel Sambuc //===----------------------------------------------------------------------===// 9*0a6a1f1dSLionel Sambuc 10*0a6a1f1dSLionel Sambuc #include "ModelInjector.h" 11*0a6a1f1dSLionel Sambuc #include "clang/AST/Decl.h" 12*0a6a1f1dSLionel Sambuc #include "clang/Basic/IdentifierTable.h" 13*0a6a1f1dSLionel Sambuc #include "clang/Frontend/ASTUnit.h" 14*0a6a1f1dSLionel Sambuc #include "clang/Frontend/CompilerInstance.h" 15*0a6a1f1dSLionel Sambuc #include "clang/Frontend/FrontendAction.h" 16*0a6a1f1dSLionel Sambuc #include "clang/Lex/Preprocessor.h" 17*0a6a1f1dSLionel Sambuc #include "clang/Serialization/ASTReader.h" 18*0a6a1f1dSLionel Sambuc #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" 19*0a6a1f1dSLionel Sambuc #include "llvm/ADT/STLExtras.h" 20*0a6a1f1dSLionel Sambuc #include "llvm/Support/CrashRecoveryContext.h" 21*0a6a1f1dSLionel Sambuc #include "llvm/Support/FileSystem.h" 22*0a6a1f1dSLionel Sambuc #include <string> 23*0a6a1f1dSLionel Sambuc #include <utility> 24*0a6a1f1dSLionel Sambuc 25*0a6a1f1dSLionel Sambuc using namespace clang; 26*0a6a1f1dSLionel Sambuc using namespace ento; 27*0a6a1f1dSLionel Sambuc ModelInjector(CompilerInstance & CI)28*0a6a1f1dSLionel SambucModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {} 29*0a6a1f1dSLionel Sambuc getBody(const FunctionDecl * D)30*0a6a1f1dSLionel SambucStmt *ModelInjector::getBody(const FunctionDecl *D) { 31*0a6a1f1dSLionel Sambuc onBodySynthesis(D); 32*0a6a1f1dSLionel Sambuc return Bodies[D->getName()]; 33*0a6a1f1dSLionel Sambuc } 34*0a6a1f1dSLionel Sambuc getBody(const ObjCMethodDecl * D)35*0a6a1f1dSLionel SambucStmt *ModelInjector::getBody(const ObjCMethodDecl *D) { 36*0a6a1f1dSLionel Sambuc onBodySynthesis(D); 37*0a6a1f1dSLionel Sambuc return Bodies[D->getName()]; 38*0a6a1f1dSLionel Sambuc } 39*0a6a1f1dSLionel Sambuc onBodySynthesis(const NamedDecl * D)40*0a6a1f1dSLionel Sambucvoid ModelInjector::onBodySynthesis(const NamedDecl *D) { 41*0a6a1f1dSLionel Sambuc 42*0a6a1f1dSLionel Sambuc // FIXME: what about overloads? Declarations can be used as keys but what 43*0a6a1f1dSLionel Sambuc // about file name index? Mangled names may not be suitable for that either. 44*0a6a1f1dSLionel Sambuc if (Bodies.count(D->getName()) != 0) 45*0a6a1f1dSLionel Sambuc return; 46*0a6a1f1dSLionel Sambuc 47*0a6a1f1dSLionel Sambuc SourceManager &SM = CI.getSourceManager(); 48*0a6a1f1dSLionel Sambuc FileID mainFileID = SM.getMainFileID(); 49*0a6a1f1dSLionel Sambuc 50*0a6a1f1dSLionel Sambuc AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts(); 51*0a6a1f1dSLionel Sambuc llvm::StringRef modelPath = analyzerOpts->Config["model-path"]; 52*0a6a1f1dSLionel Sambuc 53*0a6a1f1dSLionel Sambuc llvm::SmallString<128> fileName; 54*0a6a1f1dSLionel Sambuc 55*0a6a1f1dSLionel Sambuc if (!modelPath.empty()) 56*0a6a1f1dSLionel Sambuc fileName = 57*0a6a1f1dSLionel Sambuc llvm::StringRef(modelPath.str() + "/" + D->getName().str() + ".model"); 58*0a6a1f1dSLionel Sambuc else 59*0a6a1f1dSLionel Sambuc fileName = llvm::StringRef(D->getName().str() + ".model"); 60*0a6a1f1dSLionel Sambuc 61*0a6a1f1dSLionel Sambuc if (!llvm::sys::fs::exists(fileName.str())) { 62*0a6a1f1dSLionel Sambuc Bodies[D->getName()] = nullptr; 63*0a6a1f1dSLionel Sambuc return; 64*0a6a1f1dSLionel Sambuc } 65*0a6a1f1dSLionel Sambuc 66*0a6a1f1dSLionel Sambuc IntrusiveRefCntPtr<CompilerInvocation> Invocation( 67*0a6a1f1dSLionel Sambuc new CompilerInvocation(CI.getInvocation())); 68*0a6a1f1dSLionel Sambuc 69*0a6a1f1dSLionel Sambuc FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); 70*0a6a1f1dSLionel Sambuc InputKind IK = IK_CXX; // FIXME 71*0a6a1f1dSLionel Sambuc FrontendOpts.Inputs.clear(); 72*0a6a1f1dSLionel Sambuc FrontendOpts.Inputs.push_back(FrontendInputFile(fileName, IK)); 73*0a6a1f1dSLionel Sambuc FrontendOpts.DisableFree = true; 74*0a6a1f1dSLionel Sambuc 75*0a6a1f1dSLionel Sambuc Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; 76*0a6a1f1dSLionel Sambuc 77*0a6a1f1dSLionel Sambuc // Modules are parsed by a separate CompilerInstance, so this code mimics that 78*0a6a1f1dSLionel Sambuc // behavior for models 79*0a6a1f1dSLionel Sambuc CompilerInstance Instance; 80*0a6a1f1dSLionel Sambuc Instance.setInvocation(&*Invocation); 81*0a6a1f1dSLionel Sambuc Instance.createDiagnostics( 82*0a6a1f1dSLionel Sambuc new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), 83*0a6a1f1dSLionel Sambuc /*ShouldOwnClient=*/true); 84*0a6a1f1dSLionel Sambuc 85*0a6a1f1dSLionel Sambuc Instance.getDiagnostics().setSourceManager(&SM); 86*0a6a1f1dSLionel Sambuc 87*0a6a1f1dSLionel Sambuc Instance.setVirtualFileSystem(&CI.getVirtualFileSystem()); 88*0a6a1f1dSLionel Sambuc 89*0a6a1f1dSLionel Sambuc // The instance wants to take ownership, however DisableFree frontend option 90*0a6a1f1dSLionel Sambuc // is set to true to avoid double free issues 91*0a6a1f1dSLionel Sambuc Instance.setFileManager(&CI.getFileManager()); 92*0a6a1f1dSLionel Sambuc Instance.setSourceManager(&SM); 93*0a6a1f1dSLionel Sambuc Instance.setPreprocessor(&CI.getPreprocessor()); 94*0a6a1f1dSLionel Sambuc Instance.setASTContext(&CI.getASTContext()); 95*0a6a1f1dSLionel Sambuc 96*0a6a1f1dSLionel Sambuc Instance.getPreprocessor().InitializeForModelFile(); 97*0a6a1f1dSLionel Sambuc 98*0a6a1f1dSLionel Sambuc ParseModelFileAction parseModelFile(Bodies); 99*0a6a1f1dSLionel Sambuc 100*0a6a1f1dSLionel Sambuc const unsigned ThreadStackSize = 8 << 20; 101*0a6a1f1dSLionel Sambuc llvm::CrashRecoveryContext CRC; 102*0a6a1f1dSLionel Sambuc 103*0a6a1f1dSLionel Sambuc CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); }, 104*0a6a1f1dSLionel Sambuc ThreadStackSize); 105*0a6a1f1dSLionel Sambuc 106*0a6a1f1dSLionel Sambuc Instance.getPreprocessor().FinalizeForModelFile(); 107*0a6a1f1dSLionel Sambuc 108*0a6a1f1dSLionel Sambuc Instance.resetAndLeakSourceManager(); 109*0a6a1f1dSLionel Sambuc Instance.resetAndLeakFileManager(); 110*0a6a1f1dSLionel Sambuc Instance.resetAndLeakPreprocessor(); 111*0a6a1f1dSLionel Sambuc 112*0a6a1f1dSLionel Sambuc // The preprocessor enters to the main file id when parsing is started, so 113*0a6a1f1dSLionel Sambuc // the main file id is changed to the model file during parsing and it needs 114*0a6a1f1dSLionel Sambuc // to be reseted to the former main file id after parsing of the model file 115*0a6a1f1dSLionel Sambuc // is done. 116*0a6a1f1dSLionel Sambuc SM.setMainFileID(mainFileID); 117*0a6a1f1dSLionel Sambuc } 118