brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.6 KiB · bf08911 Raw
219 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the class which performs incremental code compilation.10//11//===----------------------------------------------------------------------===//12 13#include "IncrementalParser.h"14#include "IncrementalAction.h"15 16#include "clang/AST/DeclContextInternals.h"17#include "clang/Frontend/CompilerInstance.h"18#include "clang/Interpreter/PartialTranslationUnit.h"19#include "clang/Parse/Parser.h"20#include "clang/Sema/Sema.h"21#include "llvm/IR/Module.h"22#include "llvm/Support/CrashRecoveryContext.h"23#include "llvm/Support/Error.h"24 25#include <sstream>26 27#define DEBUG_TYPE "clang-repl"28 29namespace clang {30 31// IncrementalParser::IncrementalParser() {}32 33IncrementalParser::IncrementalParser(CompilerInstance &Instance,34                                     IncrementalAction *Act, llvm::Error &Err,35                                     std::list<PartialTranslationUnit> &PTUs)36    : S(Instance.getSema()), Act(Act), PTUs(PTUs) {37  llvm::ErrorAsOutParameter EAO(&Err);38  Consumer = &S.getASTConsumer();39  P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));40 41  if (ExternalASTSource *External = S.getASTContext().getExternalSource())42    External->StartTranslationUnit(Consumer);43 44  P->Initialize();45}46 47IncrementalParser::~IncrementalParser() { P.reset(); }48 49llvm::Expected<TranslationUnitDecl *>50IncrementalParser::ParseOrWrapTopLevelDecl() {51  // Recover resources if we crash before exiting this method.52  llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);53  Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true,54                                                           /*AtEndOfTU=*/true);55  Sema::LocalEagerInstantiationScope LocalInstantiations(S, /*AtEndOfTU=*/true);56 57  // Add a new PTU.58  ASTContext &C = S.getASTContext();59  C.addTranslationUnitDecl();60 61  // Skip previous eof due to last incremental input.62  if (P->getCurToken().is(tok::annot_repl_input_end)) {63    P->ConsumeAnyToken();64    // FIXME: Clang does not call ExitScope on finalizing the regular TU, we65    // might want to do that around HandleEndOfTranslationUnit.66    P->ExitScope();67    S.CurContext = nullptr;68    // Start a new PTU.69    P->EnterScope(Scope::DeclScope);70    S.ActOnTranslationUnitScope(P->getCurScope());71  }72 73  Parser::DeclGroupPtrTy ADecl;74  Sema::ModuleImportState ImportState;75  for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;76       AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {77    if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))78      return llvm::make_error<llvm::StringError>("Parsing failed. "79                                                 "The consumer rejected a decl",80                                                 std::error_code());81  }82 83  DiagnosticsEngine &Diags = S.getDiagnostics();84  if (Diags.hasErrorOccurred()) {85    CleanUpPTU(C.getTranslationUnitDecl());86 87    Diags.Reset(/*soft=*/true);88    Diags.getClient()->clear();89    return llvm::make_error<llvm::StringError>("Parsing failed.",90                                               std::error_code());91  }92 93  // Process any TopLevelDecls generated by #pragma weak.94  for (Decl *D : S.WeakTopLevelDecls()) {95    DeclGroupRef DGR(D);96    Consumer->HandleTopLevelDecl(DGR);97  }98 99  LocalInstantiations.perform();100  GlobalInstantiations.perform();101 102  Consumer->HandleTranslationUnit(C);103 104  return C.getTranslationUnitDecl();105}106 107llvm::Expected<TranslationUnitDecl *>108IncrementalParser::Parse(llvm::StringRef input) {109  Preprocessor &PP = S.getPreprocessor();110  assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");111 112  std::ostringstream SourceName;113  SourceName << "input_line_" << InputCount++;114 115  // Create an uninitialized memory buffer, copy code in and append "\n"116  size_t InputSize = input.size(); // don't include trailing 0117  // MemBuffer size should *not* include terminating zero118  std::unique_ptr<llvm::MemoryBuffer> MB(119      llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,120                                                        SourceName.str()));121  char *MBStart = const_cast<char *>(MB->getBufferStart());122  memcpy(MBStart, input.data(), InputSize);123  MBStart[InputSize] = '\n';124 125  SourceManager &SM = S.getSourceManager();126 127  // FIXME: Create SourceLocation, which will allow clang to order the overload128  // candidates for example129  SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());130 131  // Create FileID for the current buffer.132  FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,133                               /*LoadedOffset=*/0, NewLoc);134 135  // NewLoc only used for diags.136  if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))137    return llvm::make_error<llvm::StringError>("Parsing failed. "138                                               "Cannot enter source file.",139                                               std::error_code());140 141  auto PTU = ParseOrWrapTopLevelDecl();142  if (!PTU)143    return PTU.takeError();144 145  if (PP.getLangOpts().DelayedTemplateParsing) {146    // Microsoft-specific:147    // Late parsed templates can leave unswallowed "macro"-like tokens.148    // They will seriously confuse the Parser when entering the next149    // source file. So lex until we are EOF.150    Token Tok;151    do {152      PP.Lex(Tok);153    } while (Tok.isNot(tok::annot_repl_input_end));154  } else {155    Token AssertTok;156    PP.Lex(AssertTok);157    assert(AssertTok.is(tok::annot_repl_input_end) &&158           "Lexer must be EOF when starting incremental parse!");159  }160 161  return PTU;162}163 164void IncrementalParser::CleanUpPTU(TranslationUnitDecl *MostRecentTU) {165  if (StoredDeclsMap *Map = MostRecentTU->getPrimaryContext()->getLookupPtr()) {166    for (auto &&[Key, List] : *Map) {167      DeclContextLookupResult R = List.getLookupResult();168      std::vector<NamedDecl *> NamedDeclsToRemove;169      bool RemoveAll = true;170      for (NamedDecl *D : R) {171        if (D->getTranslationUnitDecl() == MostRecentTU)172          NamedDeclsToRemove.push_back(D);173        else174          RemoveAll = false;175      }176      if (LLVM_LIKELY(RemoveAll)) {177        Map->erase(Key);178      } else {179        for (NamedDecl *D : NamedDeclsToRemove)180          List.remove(D);181      }182    }183  }184 185  // FIXME: We should de-allocate MostRecentTU186  for (Decl *D : MostRecentTU->decls()) {187    auto *ND = dyn_cast<NamedDecl>(D);188    if (!ND || ND->getDeclName().isEmpty())189      continue;190    // Check if we need to clean up the IdResolver chain.191    if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC &&192        !D->getLangOpts().CPlusPlus)193      S.IdResolver.RemoveDecl(ND);194  }195}196 197PartialTranslationUnit &198IncrementalParser::RegisterPTU(TranslationUnitDecl *TU,199                               std::unique_ptr<llvm::Module> M /*={}*/) {200  PTUs.emplace_back(PartialTranslationUnit());201  PartialTranslationUnit &LastPTU = PTUs.back();202  LastPTU.TUPart = TU;203 204  if (!M)205    M = Act->GenModule();206 207  assert((!Act->getCodeGen() || M) && "Must have a llvm::Module at this point");208 209  LastPTU.TheModule = std::move(M);210  LLVM_DEBUG(llvm::dbgs() << "compile-ptu " << PTUs.size() - 1211                          << ": [TU=" << LastPTU.TUPart);212  if (LastPTU.TheModule)213    LLVM_DEBUG(llvm::dbgs() << ", M=" << LastPTU.TheModule.get() << " ("214                            << LastPTU.TheModule->getName() << ")");215  LLVM_DEBUG(llvm::dbgs() << "]\n");216  return LastPTU;217}218} // end namespace clang219