xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===-- ModelInjector.cpp ---------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "ModelInjector.h"
100b57cec5SDimitry Andric #include "clang/AST/Decl.h"
110b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
12a7dea167SDimitry Andric #include "clang/Basic/LangStandard.h"
130b57cec5SDimitry Andric #include "clang/Basic/Stack.h"
14480093f4SDimitry Andric #include "clang/AST/DeclObjC.h"
150b57cec5SDimitry Andric #include "clang/Frontend/ASTUnit.h"
160b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
170b57cec5SDimitry Andric #include "clang/Frontend/FrontendAction.h"
180b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
190b57cec5SDimitry Andric #include "clang/Serialization/ASTReader.h"
200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
210b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
220b57cec5SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h"
230b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
240b57cec5SDimitry Andric #include <utility>
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace clang;
270b57cec5SDimitry Andric using namespace ento;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {}
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric Stmt *ModelInjector::getBody(const FunctionDecl *D) {
320b57cec5SDimitry Andric   onBodySynthesis(D);
330b57cec5SDimitry Andric   return Bodies[D->getName()];
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric Stmt *ModelInjector::getBody(const ObjCMethodDecl *D) {
370b57cec5SDimitry Andric   onBodySynthesis(D);
380b57cec5SDimitry Andric   return Bodies[D->getName()];
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric void ModelInjector::onBodySynthesis(const NamedDecl *D) {
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   // FIXME: what about overloads? Declarations can be used as keys but what
440b57cec5SDimitry Andric   // about file name index? Mangled names may not be suitable for that either.
450b57cec5SDimitry Andric   if (Bodies.count(D->getName()) != 0)
460b57cec5SDimitry Andric     return;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   SourceManager &SM = CI.getSourceManager();
490b57cec5SDimitry Andric   FileID mainFileID = SM.getMainFileID();
500b57cec5SDimitry Andric 
51*5f757f3fSDimitry Andric   llvm::StringRef modelPath = CI.getAnalyzerOpts().ModelPath;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   llvm::SmallString<128> fileName;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   if (!modelPath.empty())
560b57cec5SDimitry Andric     fileName =
570b57cec5SDimitry Andric         llvm::StringRef(modelPath.str() + "/" + D->getName().str() + ".model");
580b57cec5SDimitry Andric   else
590b57cec5SDimitry Andric     fileName = llvm::StringRef(D->getName().str() + ".model");
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   if (!llvm::sys::fs::exists(fileName.str())) {
620b57cec5SDimitry Andric     Bodies[D->getName()] = nullptr;
630b57cec5SDimitry Andric     return;
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   auto Invocation = std::make_shared<CompilerInvocation>(CI.getInvocation());
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
69a7dea167SDimitry Andric   InputKind IK = Language::CXX; // FIXME
700b57cec5SDimitry Andric   FrontendOpts.Inputs.clear();
710b57cec5SDimitry Andric   FrontendOpts.Inputs.emplace_back(fileName, IK);
720b57cec5SDimitry Andric   FrontendOpts.DisableFree = true;
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   // Modules are parsed by a separate CompilerInstance, so this code mimics that
770b57cec5SDimitry Andric   // behavior for models
780b57cec5SDimitry Andric   CompilerInstance Instance(CI.getPCHContainerOperations());
790b57cec5SDimitry Andric   Instance.setInvocation(std::move(Invocation));
800b57cec5SDimitry Andric   Instance.createDiagnostics(
810b57cec5SDimitry Andric       new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
820b57cec5SDimitry Andric       /*ShouldOwnClient=*/true);
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   Instance.getDiagnostics().setSourceManager(&SM);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   // The instance wants to take ownership, however DisableFree frontend option
870b57cec5SDimitry Andric   // is set to true to avoid double free issues
880b57cec5SDimitry Andric   Instance.setFileManager(&CI.getFileManager());
890b57cec5SDimitry Andric   Instance.setSourceManager(&SM);
900b57cec5SDimitry Andric   Instance.setPreprocessor(CI.getPreprocessorPtr());
910b57cec5SDimitry Andric   Instance.setASTContext(&CI.getASTContext());
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   Instance.getPreprocessor().InitializeForModelFile();
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   ParseModelFileAction parseModelFile(Bodies);
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   llvm::CrashRecoveryContext CRC;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); },
1000b57cec5SDimitry Andric                         DesiredStackSize);
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   Instance.getPreprocessor().FinalizeForModelFile();
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   Instance.resetAndLeakSourceManager();
1050b57cec5SDimitry Andric   Instance.resetAndLeakFileManager();
1060b57cec5SDimitry Andric   Instance.resetAndLeakPreprocessor();
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   // The preprocessor enters to the main file id when parsing is started, so
1090b57cec5SDimitry Andric   // the main file id is changed to the model file during parsing and it needs
1100b57cec5SDimitry Andric   // to be reset to the former main file id after parsing of the model file
1110b57cec5SDimitry Andric   // is done.
1120b57cec5SDimitry Andric   SM.setMainFileID(mainFileID);
1130b57cec5SDimitry Andric }
114