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 Kremenek ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {}
30eeccb30bSTed Kremenek 
getBody(const FunctionDecl * D)31eeccb30bSTed Kremenek Stmt *ModelInjector::getBody(const FunctionDecl *D) {
32eeccb30bSTed Kremenek   onBodySynthesis(D);
33eeccb30bSTed Kremenek   return Bodies[D->getName()];
34eeccb30bSTed Kremenek }
35eeccb30bSTed Kremenek 
getBody(const ObjCMethodDecl * D)36eeccb30bSTed Kremenek Stmt *ModelInjector::getBody(const ObjCMethodDecl *D) {
37eeccb30bSTed Kremenek   onBodySynthesis(D);
38eeccb30bSTed Kremenek   return Bodies[D->getName()];
39eeccb30bSTed Kremenek }
40eeccb30bSTed Kremenek 
onBodySynthesis(const NamedDecl * D)41eeccb30bSTed Kremenek void 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