192f9852fSVassil Vassilev //===--------- IncrementalParser.cpp - Incremental Compilation -----------===// 292f9852fSVassil Vassilev // 392f9852fSVassil Vassilev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 492f9852fSVassil Vassilev // See https://llvm.org/LICENSE.txt for license information. 592f9852fSVassil Vassilev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 692f9852fSVassil Vassilev // 792f9852fSVassil Vassilev //===----------------------------------------------------------------------===// 892f9852fSVassil Vassilev // 992f9852fSVassil Vassilev // This file implements the class which performs incremental code compilation. 1092f9852fSVassil Vassilev // 1192f9852fSVassil Vassilev //===----------------------------------------------------------------------===// 1292f9852fSVassil Vassilev 1392f9852fSVassil Vassilev #include "IncrementalParser.h" 1479af92bbSFred Fu 1511b47c10SVassil Vassilev #include "clang/AST/DeclContextInternals.h" 1692f9852fSVassil Vassilev #include "clang/Frontend/CompilerInstance.h" 17*a72d7eeaSVassil Vassilev #include "clang/Interpreter/PartialTranslationUnit.h" 1892f9852fSVassil Vassilev #include "clang/Parse/Parser.h" 1992f9852fSVassil Vassilev #include "clang/Sema/Sema.h" 2092f9852fSVassil Vassilev #include "llvm/Support/CrashRecoveryContext.h" 2192f9852fSVassil Vassilev #include "llvm/Support/Error.h" 2292f9852fSVassil Vassilev 2392f9852fSVassil Vassilev #include <sstream> 2492f9852fSVassil Vassilev 2592f9852fSVassil Vassilev namespace clang { 2692f9852fSVassil Vassilev 27*a72d7eeaSVassil Vassilev // IncrementalParser::IncrementalParser() {} 285111286fSJun Zhang 29*a72d7eeaSVassil Vassilev IncrementalParser::IncrementalParser(CompilerInstance &Instance, 3092f9852fSVassil Vassilev llvm::Error &Err) 31*a72d7eeaSVassil Vassilev : S(Instance.getSema()) { 3292f9852fSVassil Vassilev llvm::ErrorAsOutParameter EAO(&Err); 33*a72d7eeaSVassil Vassilev Consumer = &S.getASTConsumer(); 34*a72d7eeaSVassil Vassilev P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false)); 3592f9852fSVassil Vassilev P->Initialize(); 36ddeab07cSAnubhab Ghosh } 37ddeab07cSAnubhab Ghosh 38*a72d7eeaSVassil Vassilev IncrementalParser::~IncrementalParser() { P.reset(); } 3992f9852fSVassil Vassilev 40*a72d7eeaSVassil Vassilev llvm::Expected<TranslationUnitDecl *> 4111b47c10SVassil Vassilev IncrementalParser::ParseOrWrapTopLevelDecl() { 4292f9852fSVassil Vassilev // Recover resources if we crash before exiting this method. 4392f9852fSVassil Vassilev llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S); 4492f9852fSVassil Vassilev Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); 4592f9852fSVassil Vassilev Sema::LocalEagerInstantiationScope LocalInstantiations(S); 4692f9852fSVassil Vassilev 4711b47c10SVassil Vassilev // Add a new PTU. 4811b47c10SVassil Vassilev ASTContext &C = S.getASTContext(); 4911b47c10SVassil Vassilev C.addTranslationUnitDecl(); 505922f234SVassil Vassilev 5111b47c10SVassil Vassilev // Skip previous eof due to last incremental input. 52247fa041SJun Zhang if (P->getCurToken().is(tok::annot_repl_input_end)) { 53247fa041SJun Zhang P->ConsumeAnyToken(); 5411b47c10SVassil Vassilev // FIXME: Clang does not call ExitScope on finalizing the regular TU, we 5511b47c10SVassil Vassilev // might want to do that around HandleEndOfTranslationUnit. 5611b47c10SVassil Vassilev P->ExitScope(); 5711b47c10SVassil Vassilev S.CurContext = nullptr; 5811b47c10SVassil Vassilev // Start a new PTU. 5911b47c10SVassil Vassilev P->EnterScope(Scope::DeclScope); 6011b47c10SVassil Vassilev S.ActOnTranslationUnitScope(P->getCurScope()); 6111b47c10SVassil Vassilev } 6292f9852fSVassil Vassilev 6392f9852fSVassil Vassilev Parser::DeclGroupPtrTy ADecl; 64ab28488eSIain Sandoe Sema::ModuleImportState ImportState; 65ab28488eSIain Sandoe for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; 66ab28488eSIain Sandoe AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) { 6792f9852fSVassil Vassilev if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) 6892f9852fSVassil Vassilev return llvm::make_error<llvm::StringError>("Parsing failed. " 6992f9852fSVassil Vassilev "The consumer rejected a decl", 7092f9852fSVassil Vassilev std::error_code()); 7111b47c10SVassil Vassilev } 7211b47c10SVassil Vassilev 73*a72d7eeaSVassil Vassilev DiagnosticsEngine &Diags = S.getDiagnostics(); 7411b47c10SVassil Vassilev if (Diags.hasErrorOccurred()) { 75*a72d7eeaSVassil Vassilev CleanUpPTU(C.getTranslationUnitDecl()); 7611b47c10SVassil Vassilev 77946c45a4STapasweni Pathak Diags.Reset(/*soft=*/true); 78946c45a4STapasweni Pathak Diags.getClient()->clear(); 7911b47c10SVassil Vassilev return llvm::make_error<llvm::StringError>("Parsing failed.", 8011b47c10SVassil Vassilev std::error_code()); 8192f9852fSVassil Vassilev } 8292f9852fSVassil Vassilev 8392f9852fSVassil Vassilev // Process any TopLevelDecls generated by #pragma weak. 8492f9852fSVassil Vassilev for (Decl *D : S.WeakTopLevelDecls()) { 8592f9852fSVassil Vassilev DeclGroupRef DGR(D); 8692f9852fSVassil Vassilev Consumer->HandleTopLevelDecl(DGR); 8792f9852fSVassil Vassilev } 8892f9852fSVassil Vassilev 8992f9852fSVassil Vassilev LocalInstantiations.perform(); 9092f9852fSVassil Vassilev GlobalInstantiations.perform(); 9192f9852fSVassil Vassilev 9211b47c10SVassil Vassilev Consumer->HandleTranslationUnit(C); 9392f9852fSVassil Vassilev 94*a72d7eeaSVassil Vassilev return C.getTranslationUnitDecl(); 9592f9852fSVassil Vassilev } 9692f9852fSVassil Vassilev 97*a72d7eeaSVassil Vassilev llvm::Expected<TranslationUnitDecl *> 9811b47c10SVassil Vassilev IncrementalParser::Parse(llvm::StringRef input) { 99*a72d7eeaSVassil Vassilev Preprocessor &PP = S.getPreprocessor(); 10092f9852fSVassil Vassilev assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?"); 10192f9852fSVassil Vassilev 10292f9852fSVassil Vassilev std::ostringstream SourceName; 10392f9852fSVassil Vassilev SourceName << "input_line_" << InputCount++; 10492f9852fSVassil Vassilev 10592f9852fSVassil Vassilev // Create an uninitialized memory buffer, copy code in and append "\n" 10692f9852fSVassil Vassilev size_t InputSize = input.size(); // don't include trailing 0 10792f9852fSVassil Vassilev // MemBuffer size should *not* include terminating zero 10892f9852fSVassil Vassilev std::unique_ptr<llvm::MemoryBuffer> MB( 10992f9852fSVassil Vassilev llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1, 11092f9852fSVassil Vassilev SourceName.str())); 11192f9852fSVassil Vassilev char *MBStart = const_cast<char *>(MB->getBufferStart()); 11292f9852fSVassil Vassilev memcpy(MBStart, input.data(), InputSize); 11392f9852fSVassil Vassilev MBStart[InputSize] = '\n'; 11492f9852fSVassil Vassilev 115*a72d7eeaSVassil Vassilev SourceManager &SM = S.getSourceManager(); 11692f9852fSVassil Vassilev 11792f9852fSVassil Vassilev // FIXME: Create SourceLocation, which will allow clang to order the overload 11892f9852fSVassil Vassilev // candidates for example 11992f9852fSVassil Vassilev SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID()); 12092f9852fSVassil Vassilev 12192f9852fSVassil Vassilev // Create FileID for the current buffer. 12292f9852fSVassil Vassilev FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, 12392f9852fSVassil Vassilev /*LoadedOffset=*/0, NewLoc); 12492f9852fSVassil Vassilev 12592f9852fSVassil Vassilev // NewLoc only used for diags. 126298367eeSKazu Hirata if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc)) 12792f9852fSVassil Vassilev return llvm::make_error<llvm::StringError>("Parsing failed. " 12892f9852fSVassil Vassilev "Cannot enter source file.", 12992f9852fSVassil Vassilev std::error_code()); 13092f9852fSVassil Vassilev 13111b47c10SVassil Vassilev auto PTU = ParseOrWrapTopLevelDecl(); 13211b47c10SVassil Vassilev if (!PTU) 13311b47c10SVassil Vassilev return PTU.takeError(); 13492f9852fSVassil Vassilev 13592f9852fSVassil Vassilev if (PP.getLangOpts().DelayedTemplateParsing) { 13692f9852fSVassil Vassilev // Microsoft-specific: 13792f9852fSVassil Vassilev // Late parsed templates can leave unswallowed "macro"-like tokens. 13892f9852fSVassil Vassilev // They will seriously confuse the Parser when entering the next 13992f9852fSVassil Vassilev // source file. So lex until we are EOF. 14092f9852fSVassil Vassilev Token Tok; 14192f9852fSVassil Vassilev do { 14292f9852fSVassil Vassilev PP.Lex(Tok); 143247fa041SJun Zhang } while (Tok.isNot(tok::annot_repl_input_end)); 144247fa041SJun Zhang } else { 14592f9852fSVassil Vassilev Token AssertTok; 14692f9852fSVassil Vassilev PP.Lex(AssertTok); 147247fa041SJun Zhang assert(AssertTok.is(tok::annot_repl_input_end) && 14892f9852fSVassil Vassilev "Lexer must be EOF when starting incremental parse!"); 149247fa041SJun Zhang } 15092f9852fSVassil Vassilev 151094ab478SJun Zhang return PTU; 152d71a4e02SJun Zhang } 153d71a4e02SJun Zhang 154*a72d7eeaSVassil Vassilev void IncrementalParser::CleanUpPTU(TranslationUnitDecl *MostRecentTU) { 155d999ce03SVassil Vassilev if (StoredDeclsMap *Map = MostRecentTU->getPrimaryContext()->getLookupPtr()) { 1562e38c50eSStefan Gränitz for (auto &&[Key, List] : *Map) { 157dea5a9ccSJun Zhang DeclContextLookupResult R = List.getLookupResult(); 1582e38c50eSStefan Gränitz std::vector<NamedDecl *> NamedDeclsToRemove; 1592e38c50eSStefan Gränitz bool RemoveAll = true; 160dea5a9ccSJun Zhang for (NamedDecl *D : R) { 1612e38c50eSStefan Gränitz if (D->getTranslationUnitDecl() == MostRecentTU) 1622e38c50eSStefan Gränitz NamedDeclsToRemove.push_back(D); 1632e38c50eSStefan Gränitz else 1642e38c50eSStefan Gränitz RemoveAll = false; 1652e38c50eSStefan Gränitz } 1662e38c50eSStefan Gränitz if (LLVM_LIKELY(RemoveAll)) { 1672e38c50eSStefan Gränitz Map->erase(Key); 1682e38c50eSStefan Gränitz } else { 1692e38c50eSStefan Gränitz for (NamedDecl *D : NamedDeclsToRemove) 170dea5a9ccSJun Zhang List.remove(D); 171dea5a9ccSJun Zhang } 172dea5a9ccSJun Zhang } 173dea5a9ccSJun Zhang } 174d999ce03SVassil Vassilev 175d999ce03SVassil Vassilev // FIXME: We should de-allocate MostRecentTU 176d999ce03SVassil Vassilev for (Decl *D : MostRecentTU->decls()) { 177d999ce03SVassil Vassilev auto *ND = dyn_cast<NamedDecl>(D); 178d999ce03SVassil Vassilev if (!ND) 179d999ce03SVassil Vassilev continue; 180d999ce03SVassil Vassilev // Check if we need to clean up the IdResolver chain. 1813beb232fSHaojian Wu if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC && 1823beb232fSHaojian Wu !D->getLangOpts().CPlusPlus) 183*a72d7eeaSVassil Vassilev S.IdResolver.RemoveDecl(ND); 184d999ce03SVassil Vassilev } 185dea5a9ccSJun Zhang } 186dea5a9ccSJun Zhang 18792f9852fSVassil Vassilev } // end namespace clang 188