xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp (revision e5dd70708596ae51455a0ffa086a00c5b29f8583)
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*e5dd7070Spatrick ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {}
30*e5dd7070Spatrick 
getBody(const FunctionDecl * D)31*e5dd7070Spatrick Stmt *ModelInjector::getBody(const FunctionDecl *D) {
32*e5dd7070Spatrick   onBodySynthesis(D);
33*e5dd7070Spatrick   return Bodies[D->getName()];
34*e5dd7070Spatrick }
35*e5dd7070Spatrick 
getBody(const ObjCMethodDecl * D)36*e5dd7070Spatrick Stmt *ModelInjector::getBody(const ObjCMethodDecl *D) {
37*e5dd7070Spatrick   onBodySynthesis(D);
38*e5dd7070Spatrick   return Bodies[D->getName()];
39*e5dd7070Spatrick }
40*e5dd7070Spatrick 
onBodySynthesis(const NamedDecl * D)41*e5dd7070Spatrick void 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