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