/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- ModelInjector.cpp ---------------------------------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "ModelInjector.h" |
10 | | #include "clang/AST/Decl.h" |
11 | | #include "clang/Basic/IdentifierTable.h" |
12 | | #include "clang/Basic/LangStandard.h" |
13 | | #include "clang/Basic/Stack.h" |
14 | | #include "clang/AST/DeclObjC.h" |
15 | | #include "clang/Frontend/ASTUnit.h" |
16 | | #include "clang/Frontend/CompilerInstance.h" |
17 | | #include "clang/Frontend/FrontendAction.h" |
18 | | #include "clang/Lex/Preprocessor.h" |
19 | | #include "clang/Serialization/ASTReader.h" |
20 | | #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" |
21 | | #include "llvm/ADT/STLExtras.h" |
22 | | #include "llvm/Support/CrashRecoveryContext.h" |
23 | | #include "llvm/Support/FileSystem.h" |
24 | | #include <utility> |
25 | | |
26 | | using namespace clang; |
27 | | using namespace ento; |
28 | | |
29 | 1.79k | ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {} |
30 | | |
31 | 20.8k | Stmt *ModelInjector::getBody(const FunctionDecl *D) { |
32 | 20.8k | onBodySynthesis(D); |
33 | 20.8k | return Bodies[D->getName()]; |
34 | 20.8k | } |
35 | | |
36 | 0 | Stmt *ModelInjector::getBody(const ObjCMethodDecl *D) { |
37 | 0 | onBodySynthesis(D); |
38 | 0 | return Bodies[D->getName()]; |
39 | 0 | } |
40 | | |
41 | 20.8k | void ModelInjector::onBodySynthesis(const NamedDecl *D) { |
42 | | |
43 | | // FIXME: what about overloads? Declarations can be used as keys but what |
44 | | // about file name index? Mangled names may not be suitable for that either. |
45 | 20.8k | if (Bodies.count(D->getName()) != 0) |
46 | 1.70k | return; |
47 | | |
48 | 19.1k | SourceManager &SM = CI.getSourceManager(); |
49 | 19.1k | FileID mainFileID = SM.getMainFileID(); |
50 | | |
51 | 19.1k | llvm::StringRef modelPath = CI.getAnalyzerOpts().ModelPath; |
52 | | |
53 | 19.1k | llvm::SmallString<128> fileName; |
54 | | |
55 | 19.1k | if (!modelPath.empty()) |
56 | 4 | fileName = |
57 | 4 | llvm::StringRef(modelPath.str() + "/" + D->getName().str() + ".model"); |
58 | 19.1k | else |
59 | 19.1k | fileName = llvm::StringRef(D->getName().str() + ".model"); |
60 | | |
61 | 19.1k | if (!llvm::sys::fs::exists(fileName.str())) { |
62 | 19.1k | Bodies[D->getName()] = nullptr; |
63 | 19.1k | return; |
64 | 19.1k | } |
65 | | |
66 | 2 | auto Invocation = std::make_shared<CompilerInvocation>(CI.getInvocation()); |
67 | | |
68 | 2 | FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); |
69 | 2 | InputKind IK = Language::CXX; // FIXME |
70 | 2 | FrontendOpts.Inputs.clear(); |
71 | 2 | FrontendOpts.Inputs.emplace_back(fileName, IK); |
72 | 2 | FrontendOpts.DisableFree = true; |
73 | | |
74 | 2 | Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; |
75 | | |
76 | | // Modules are parsed by a separate CompilerInstance, so this code mimics that |
77 | | // behavior for models |
78 | 2 | CompilerInstance Instance(CI.getPCHContainerOperations()); |
79 | 2 | Instance.setInvocation(std::move(Invocation)); |
80 | 2 | Instance.createDiagnostics( |
81 | 2 | new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), |
82 | 2 | /*ShouldOwnClient=*/true); |
83 | | |
84 | 2 | Instance.getDiagnostics().setSourceManager(&SM); |
85 | | |
86 | | // The instance wants to take ownership, however DisableFree frontend option |
87 | | // is set to true to avoid double free issues |
88 | 2 | Instance.setFileManager(&CI.getFileManager()); |
89 | 2 | Instance.setSourceManager(&SM); |
90 | 2 | Instance.setPreprocessor(CI.getPreprocessorPtr()); |
91 | 2 | Instance.setASTContext(&CI.getASTContext()); |
92 | | |
93 | 2 | Instance.getPreprocessor().InitializeForModelFile(); |
94 | | |
95 | 2 | ParseModelFileAction parseModelFile(Bodies); |
96 | | |
97 | 2 | llvm::CrashRecoveryContext CRC; |
98 | | |
99 | 2 | CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); }, |
100 | 2 | DesiredStackSize); |
101 | | |
102 | 2 | Instance.getPreprocessor().FinalizeForModelFile(); |
103 | | |
104 | 2 | Instance.resetAndLeakSourceManager(); |
105 | 2 | Instance.resetAndLeakFileManager(); |
106 | 2 | Instance.resetAndLeakPreprocessor(); |
107 | | |
108 | | // The preprocessor enters to the main file id when parsing is started, so |
109 | | // the main file id is changed to the model file during parsing and it needs |
110 | | // to be reset to the former main file id after parsing of the model file |
111 | | // is done. |
112 | 2 | SM.setMainFileID(mainFileID); |
113 | 2 | } |