1176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines//===-- ModelInjector.cpp ---------------------------------------*- C++ -*-===//
2176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines//
3176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines//                     The LLVM Compiler Infrastructure
4176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines//
5176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines// This file is distributed under the University of Illinois Open Source
6176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines// License. See LICENSE.TXT for details.
7176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines//
8176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines//===----------------------------------------------------------------------===//
9176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
10176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#include "ModelInjector.h"
110e2c34f92f00628d48968dfea096d36381f494cbStephen Hines#include "clang/AST/Decl.h"
120e2c34f92f00628d48968dfea096d36381f494cbStephen Hines#include "clang/Basic/IdentifierTable.h"
13176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#include "clang/Frontend/ASTUnit.h"
14176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#include "clang/Frontend/CompilerInstance.h"
15176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#include "clang/Frontend/FrontendAction.h"
16176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#include "clang/Lex/Preprocessor.h"
170e2c34f92f00628d48968dfea096d36381f494cbStephen Hines#include "clang/Serialization/ASTReader.h"
180e2c34f92f00628d48968dfea096d36381f494cbStephen Hines#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
190e2c34f92f00628d48968dfea096d36381f494cbStephen Hines#include "llvm/ADT/STLExtras.h"
20176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#include "llvm/Support/CrashRecoveryContext.h"
21176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#include "llvm/Support/FileSystem.h"
220e2c34f92f00628d48968dfea096d36381f494cbStephen Hines#include <string>
230e2c34f92f00628d48968dfea096d36381f494cbStephen Hines#include <utility>
24176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
25176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hinesusing namespace clang;
26176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hinesusing namespace ento;
27176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
28176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {}
29176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
30176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesStmt *ModelInjector::getBody(const FunctionDecl *D) {
31176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  onBodySynthesis(D);
32176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  return Bodies[D->getName()];
33176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines}
34176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
35176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesStmt *ModelInjector::getBody(const ObjCMethodDecl *D) {
36176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  onBodySynthesis(D);
37176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  return Bodies[D->getName()];
38176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines}
39176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
40176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hinesvoid ModelInjector::onBodySynthesis(const NamedDecl *D) {
41176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
42176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // FIXME: what about overloads? Declarations can be used as keys but what
43176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // about file name index? Mangled names may not be suitable for that either.
44176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  if (Bodies.count(D->getName()) != 0)
45176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    return;
46176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
47176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  SourceManager &SM = CI.getSourceManager();
48176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  FileID mainFileID = SM.getMainFileID();
49176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
50176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
51176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  llvm::StringRef modelPath = analyzerOpts->Config["model-path"];
52176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
53176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  llvm::SmallString<128> fileName;
54176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
55176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  if (!modelPath.empty())
56176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    fileName =
57176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        llvm::StringRef(modelPath.str() + "/" + D->getName().str() + ".model");
58176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  else
59176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    fileName = llvm::StringRef(D->getName().str() + ".model");
60176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
61176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  if (!llvm::sys::fs::exists(fileName.str())) {
62176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    Bodies[D->getName()] = nullptr;
63176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    return;
64176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  }
65176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
66176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  IntrusiveRefCntPtr<CompilerInvocation> Invocation(
67176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      new CompilerInvocation(CI.getInvocation()));
68176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
69176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
70176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  InputKind IK = IK_CXX; // FIXME
71176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  FrontendOpts.Inputs.clear();
72176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  FrontendOpts.Inputs.push_back(FrontendInputFile(fileName, IK));
73176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  FrontendOpts.DisableFree = true;
74176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
75176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
76176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
77176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // Modules are parsed by a separate CompilerInstance, so this code mimics that
78176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // behavior for models
79176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  CompilerInstance Instance;
80176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.setInvocation(&*Invocation);
81176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.createDiagnostics(
82176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
83176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      /*ShouldOwnClient=*/true);
84176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
85176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.getDiagnostics().setSourceManager(&SM);
86176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
87176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.setVirtualFileSystem(&CI.getVirtualFileSystem());
88176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
89176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // The instance wants to take ownership, however DisableFree frontend option
90176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // is set to true to avoid double free issues
91176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.setFileManager(&CI.getFileManager());
92176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.setSourceManager(&SM);
93176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.setPreprocessor(&CI.getPreprocessor());
94176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.setASTContext(&CI.getASTContext());
95176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
96176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.getPreprocessor().InitializeForModelFile();
97176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
98176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  ParseModelFileAction parseModelFile(Bodies);
99176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
100176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  const unsigned ThreadStackSize = 8 << 20;
101176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  llvm::CrashRecoveryContext CRC;
102176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
103176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); },
104176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                        ThreadStackSize);
105176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
106176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.getPreprocessor().FinalizeForModelFile();
107176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
108176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.resetAndLeakSourceManager();
109176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.resetAndLeakFileManager();
110176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  Instance.resetAndLeakPreprocessor();
111176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
112176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // The preprocessor enters to the main file id when parsing is started, so
113176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // the main file id is changed to the model file during parsing and it needs
114176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // to be reseted to the former main file id after parsing of the model file
115176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  // is done.
116176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  SM.setMainFileID(mainFileID);
117176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines}
118