1//===--------- IncrementalParser.cpp - Incremental Compilation  -----------===//
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// This file implements the class which performs incremental code compilation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "IncrementalParser.h"
14
15#include "clang/AST/DeclContextInternals.h"
16#include "clang/CodeGen/BackendUtil.h"
17#include "clang/CodeGen/CodeGenAction.h"
18#include "clang/CodeGen/ModuleBuilder.h"
19#include "clang/Frontend/CompilerInstance.h"
20#include "clang/Frontend/FrontendAction.h"
21#include "clang/FrontendTool/Utils.h"
22#include "clang/Parse/Parser.h"
23#include "clang/Sema/Sema.h"
24
25#include "llvm/Option/ArgList.h"
26#include "llvm/Support/CrashRecoveryContext.h"
27#include "llvm/Support/Error.h"
28#include "llvm/Support/Timer.h"
29
30#include <sstream>
31
32namespace clang {
33
34/// A custom action enabling the incremental processing functionality.
35///
36/// The usual \p FrontendAction expects one call to ExecuteAction and once it
37/// sees a call to \p EndSourceFile it deletes some of the important objects
38/// such as \p Preprocessor and \p Sema assuming no further input will come.
39///
40/// \p IncrementalAction ensures it keep its underlying action's objects alive
41/// as long as the \p IncrementalParser needs them.
42///
43class IncrementalAction : public WrapperFrontendAction {
44private:
45  bool IsTerminating = false;
46
47public:
48  IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
49                    llvm::Error &Err)
50      : WrapperFrontendAction([&]() {
51          llvm::ErrorAsOutParameter EAO(&Err);
52          std::unique_ptr<FrontendAction> Act;
53          switch (CI.getFrontendOpts().ProgramAction) {
54          default:
55            Err = llvm::createStringError(
56                std::errc::state_not_recoverable,
57                "Driver initialization failed. "
58                "Incremental mode for action %d is not supported",
59                CI.getFrontendOpts().ProgramAction);
60            return Act;
61          case frontend::ASTDump:
62            [[fallthrough]];
63          case frontend::ASTPrint:
64            [[fallthrough]];
65          case frontend::ParseSyntaxOnly:
66            Act = CreateFrontendAction(CI);
67            break;
68          case frontend::PluginAction:
69            [[fallthrough]];
70          case frontend::EmitAssembly:
71            [[fallthrough]];
72          case frontend::EmitBC:
73            [[fallthrough]];
74          case frontend::EmitObj:
75            [[fallthrough]];
76          case frontend::PrintPreprocessedInput:
77            [[fallthrough]];
78          case frontend::EmitLLVMOnly:
79            Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
80            break;
81          }
82          return Act;
83        }()) {}
84  FrontendAction *getWrapped() const { return WrappedAction.get(); }
85  TranslationUnitKind getTranslationUnitKind() override {
86    return TU_Incremental;
87  }
88  void ExecuteAction() override {
89    CompilerInstance &CI = getCompilerInstance();
90    assert(CI.hasPreprocessor() && "No PP!");
91
92    // FIXME: Move the truncation aspect of this into Sema, we delayed this till
93    // here so the source manager would be initialized.
94    if (hasCodeCompletionSupport() &&
95        !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
96      CI.createCodeCompletionConsumer();
97
98    // Use a code completion consumer?
99    CodeCompleteConsumer *CompletionConsumer = nullptr;
100    if (CI.hasCodeCompletionConsumer())
101      CompletionConsumer = &CI.getCodeCompletionConsumer();
102
103    Preprocessor &PP = CI.getPreprocessor();
104    PP.EnterMainSourceFile();
105
106    if (!CI.hasSema())
107      CI.createSema(getTranslationUnitKind(), CompletionConsumer);
108  }
109
110  // Do not terminate after processing the input. This allows us to keep various
111  // clang objects alive and to incrementally grow the current TU.
112  void EndSourceFile() override {
113    // The WrappedAction can be nullptr if we issued an error in the ctor.
114    if (IsTerminating && getWrapped())
115      WrapperFrontendAction::EndSourceFile();
116  }
117
118  void FinalizeAction() {
119    assert(!IsTerminating && "Already finalized!");
120    IsTerminating = true;
121    EndSourceFile();
122  }
123};
124
125IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance,
126                                     llvm::LLVMContext &LLVMCtx,
127                                     llvm::Error &Err)
128    : CI(std::move(Instance)) {
129  llvm::ErrorAsOutParameter EAO(&Err);
130  Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
131  if (Err)
132    return;
133  CI->ExecuteAction(*Act);
134  Consumer = &CI->getASTConsumer();
135  P.reset(
136      new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
137  P->Initialize();
138}
139
140IncrementalParser::~IncrementalParser() {
141  P.reset();
142  Act->FinalizeAction();
143}
144
145llvm::Expected<PartialTranslationUnit &>
146IncrementalParser::ParseOrWrapTopLevelDecl() {
147  // Recover resources if we crash before exiting this method.
148  Sema &S = CI->getSema();
149  llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
150  Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
151  Sema::LocalEagerInstantiationScope LocalInstantiations(S);
152
153  PTUs.emplace_back(PartialTranslationUnit());
154  PartialTranslationUnit &LastPTU = PTUs.back();
155  // Add a new PTU.
156  ASTContext &C = S.getASTContext();
157  C.addTranslationUnitDecl();
158  LastPTU.TUPart = C.getTranslationUnitDecl();
159
160  // Skip previous eof due to last incremental input.
161  if (P->getCurToken().is(tok::eof)) {
162    P->ConsumeToken();
163    // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
164    // might want to do that around HandleEndOfTranslationUnit.
165    P->ExitScope();
166    S.CurContext = nullptr;
167    // Start a new PTU.
168    P->EnterScope(Scope::DeclScope);
169    S.ActOnTranslationUnitScope(P->getCurScope());
170  }
171
172  Parser::DeclGroupPtrTy ADecl;
173  Sema::ModuleImportState ImportState;
174  for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
175       AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
176    if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
177      return llvm::make_error<llvm::StringError>("Parsing failed. "
178                                                 "The consumer rejected a decl",
179                                                 std::error_code());
180  }
181
182  DiagnosticsEngine &Diags = getCI()->getDiagnostics();
183  if (Diags.hasErrorOccurred()) {
184    PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(),
185                                            nullptr};
186    CleanUpPTU(MostRecentPTU);
187
188    Diags.Reset(/*soft=*/true);
189    Diags.getClient()->clear();
190    return llvm::make_error<llvm::StringError>("Parsing failed.",
191                                               std::error_code());
192  }
193
194  // Process any TopLevelDecls generated by #pragma weak.
195  for (Decl *D : S.WeakTopLevelDecls()) {
196    DeclGroupRef DGR(D);
197    Consumer->HandleTopLevelDecl(DGR);
198  }
199
200  LocalInstantiations.perform();
201  GlobalInstantiations.perform();
202
203  Consumer->HandleTranslationUnit(C);
204
205  return LastPTU;
206}
207
208static CodeGenerator *getCodeGen(FrontendAction *Act) {
209  IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act);
210  FrontendAction *WrappedAct = IncrAct->getWrapped();
211  if (!WrappedAct->hasIRSupport())
212    return nullptr;
213  return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
214}
215
216llvm::Expected<PartialTranslationUnit &>
217IncrementalParser::Parse(llvm::StringRef input) {
218  Preprocessor &PP = CI->getPreprocessor();
219  assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
220
221  std::ostringstream SourceName;
222  SourceName << "input_line_" << InputCount++;
223
224  // Create an uninitialized memory buffer, copy code in and append "\n"
225  size_t InputSize = input.size(); // don't include trailing 0
226  // MemBuffer size should *not* include terminating zero
227  std::unique_ptr<llvm::MemoryBuffer> MB(
228      llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
229                                                        SourceName.str()));
230  char *MBStart = const_cast<char *>(MB->getBufferStart());
231  memcpy(MBStart, input.data(), InputSize);
232  MBStart[InputSize] = '\n';
233
234  SourceManager &SM = CI->getSourceManager();
235
236  // FIXME: Create SourceLocation, which will allow clang to order the overload
237  // candidates for example
238  SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
239
240  // Create FileID for the current buffer.
241  FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
242                               /*LoadedOffset=*/0, NewLoc);
243
244  // NewLoc only used for diags.
245  if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
246    return llvm::make_error<llvm::StringError>("Parsing failed. "
247                                               "Cannot enter source file.",
248                                               std::error_code());
249
250  auto PTU = ParseOrWrapTopLevelDecl();
251  if (!PTU)
252    return PTU.takeError();
253
254  if (PP.getLangOpts().DelayedTemplateParsing) {
255    // Microsoft-specific:
256    // Late parsed templates can leave unswallowed "macro"-like tokens.
257    // They will seriously confuse the Parser when entering the next
258    // source file. So lex until we are EOF.
259    Token Tok;
260    do {
261      PP.Lex(Tok);
262    } while (Tok.isNot(tok::eof));
263  }
264
265  Token AssertTok;
266  PP.Lex(AssertTok);
267  assert(AssertTok.is(tok::eof) &&
268         "Lexer must be EOF when starting incremental parse!");
269
270  if (CodeGenerator *CG = getCodeGen(Act.get())) {
271    std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
272    CG->StartModule("incr_module_" + std::to_string(PTUs.size()),
273                    M->getContext());
274
275    PTU->TheModule = std::move(M);
276  }
277
278  return PTU;
279}
280
281void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) {
282  TranslationUnitDecl *MostRecentTU = PTU.TUPart;
283  TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl();
284  if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) {
285    for (auto I = Map->begin(); I != Map->end(); ++I) {
286      StoredDeclsList &List = I->second;
287      DeclContextLookupResult R = List.getLookupResult();
288      for (NamedDecl *D : R) {
289        if (D->getTranslationUnitDecl() == MostRecentTU) {
290          List.remove(D);
291        }
292      }
293      if (List.isNull())
294        Map->erase(I);
295    }
296  }
297}
298
299llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
300  CodeGenerator *CG = getCodeGen(Act.get());
301  assert(CG);
302  return CG->GetMangledName(GD);
303}
304
305} // end namespace clang
306