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