10b57cec5SDimitry Andric //===-- ModelInjector.cpp ---------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "ModelInjector.h" 100b57cec5SDimitry Andric #include "clang/AST/Decl.h" 110b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h" 12a7dea167SDimitry Andric #include "clang/Basic/LangStandard.h" 130b57cec5SDimitry Andric #include "clang/Basic/Stack.h" 14480093f4SDimitry Andric #include "clang/AST/DeclObjC.h" 150b57cec5SDimitry Andric #include "clang/Frontend/ASTUnit.h" 160b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h" 170b57cec5SDimitry Andric #include "clang/Frontend/FrontendAction.h" 180b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h" 190b57cec5SDimitry Andric #include "clang/Serialization/ASTReader.h" 200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" 210b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 220b57cec5SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h" 230b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 240b57cec5SDimitry Andric #include <utility> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace clang; 270b57cec5SDimitry Andric using namespace ento; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {} 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric Stmt *ModelInjector::getBody(const FunctionDecl *D) { 320b57cec5SDimitry Andric onBodySynthesis(D); 330b57cec5SDimitry Andric return Bodies[D->getName()]; 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric Stmt *ModelInjector::getBody(const ObjCMethodDecl *D) { 370b57cec5SDimitry Andric onBodySynthesis(D); 380b57cec5SDimitry Andric return Bodies[D->getName()]; 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric void ModelInjector::onBodySynthesis(const NamedDecl *D) { 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric // FIXME: what about overloads? Declarations can be used as keys but what 440b57cec5SDimitry Andric // about file name index? Mangled names may not be suitable for that either. 450b57cec5SDimitry Andric if (Bodies.count(D->getName()) != 0) 460b57cec5SDimitry Andric return; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric SourceManager &SM = CI.getSourceManager(); 490b57cec5SDimitry Andric FileID mainFileID = SM.getMainFileID(); 500b57cec5SDimitry Andric 51*5f757f3fSDimitry Andric llvm::StringRef modelPath = CI.getAnalyzerOpts().ModelPath; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric llvm::SmallString<128> fileName; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric if (!modelPath.empty()) 560b57cec5SDimitry Andric fileName = 570b57cec5SDimitry Andric llvm::StringRef(modelPath.str() + "/" + D->getName().str() + ".model"); 580b57cec5SDimitry Andric else 590b57cec5SDimitry Andric fileName = llvm::StringRef(D->getName().str() + ".model"); 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric if (!llvm::sys::fs::exists(fileName.str())) { 620b57cec5SDimitry Andric Bodies[D->getName()] = nullptr; 630b57cec5SDimitry Andric return; 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric auto Invocation = std::make_shared<CompilerInvocation>(CI.getInvocation()); 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); 69a7dea167SDimitry Andric InputKind IK = Language::CXX; // FIXME 700b57cec5SDimitry Andric FrontendOpts.Inputs.clear(); 710b57cec5SDimitry Andric FrontendOpts.Inputs.emplace_back(fileName, IK); 720b57cec5SDimitry Andric FrontendOpts.DisableFree = true; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric // Modules are parsed by a separate CompilerInstance, so this code mimics that 770b57cec5SDimitry Andric // behavior for models 780b57cec5SDimitry Andric CompilerInstance Instance(CI.getPCHContainerOperations()); 790b57cec5SDimitry Andric Instance.setInvocation(std::move(Invocation)); 800b57cec5SDimitry Andric Instance.createDiagnostics( 810b57cec5SDimitry Andric new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), 820b57cec5SDimitry Andric /*ShouldOwnClient=*/true); 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric Instance.getDiagnostics().setSourceManager(&SM); 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric // The instance wants to take ownership, however DisableFree frontend option 870b57cec5SDimitry Andric // is set to true to avoid double free issues 880b57cec5SDimitry Andric Instance.setFileManager(&CI.getFileManager()); 890b57cec5SDimitry Andric Instance.setSourceManager(&SM); 900b57cec5SDimitry Andric Instance.setPreprocessor(CI.getPreprocessorPtr()); 910b57cec5SDimitry Andric Instance.setASTContext(&CI.getASTContext()); 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric Instance.getPreprocessor().InitializeForModelFile(); 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric ParseModelFileAction parseModelFile(Bodies); 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric llvm::CrashRecoveryContext CRC; 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); }, 1000b57cec5SDimitry Andric DesiredStackSize); 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric Instance.getPreprocessor().FinalizeForModelFile(); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric Instance.resetAndLeakSourceManager(); 1050b57cec5SDimitry Andric Instance.resetAndLeakFileManager(); 1060b57cec5SDimitry Andric Instance.resetAndLeakPreprocessor(); 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // The preprocessor enters to the main file id when parsing is started, so 1090b57cec5SDimitry Andric // the main file id is changed to the model file during parsing and it needs 1100b57cec5SDimitry Andric // to be reset to the former main file id after parsing of the model file 1110b57cec5SDimitry Andric // is done. 1120b57cec5SDimitry Andric SM.setMainFileID(mainFileID); 1130b57cec5SDimitry Andric } 114