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