xref: /llvm-project/clang/lib/Interpreter/IncrementalParser.cpp (revision a72d7eea5413444249670579fecea6823fb3c564)
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