| //===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the clang::ParseAST method. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/Parse/ParseAST.h" |
| #include "clang/AST/ASTConsumer.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ExternalASTSource.h" |
| #include "clang/AST/Stmt.h" |
| #include "clang/Parse/ParseDiagnostic.h" |
| #include "clang/Parse/Parser.h" |
| #include "clang/Sema/CodeCompleteConsumer.h" |
| #include "clang/Sema/Sema.h" |
| #include "clang/Sema/SemaConsumer.h" |
| #include "clang/Sema/TemplateInstCallback.h" |
| #include "llvm/Support/CrashRecoveryContext.h" |
| #include "llvm/Support/TimeProfiler.h" |
| #include <cstdio> |
| #include <memory> |
| |
| using namespace clang; |
| |
| namespace { |
| |
| /// Resets LLVM's pretty stack state so that stack traces are printed correctly |
| /// when there are nested CrashRecoveryContexts and the inner one recovers from |
| /// a crash. |
| class ResetStackCleanup |
| : public llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, |
| const void> { |
| public: |
| ResetStackCleanup(llvm::CrashRecoveryContext *Context, const void *Top) |
| : llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, const void>( |
| Context, Top) {} |
| void recoverResources() override { |
| llvm::RestorePrettyStackState(resource); |
| } |
| }; |
| |
| /// If a crash happens while the parser is active, an entry is printed for it. |
| class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { |
| const Parser &P; |
| public: |
| PrettyStackTraceParserEntry(const Parser &p) : P(p) {} |
| void print(raw_ostream &OS) const override; |
| }; |
| |
| /// If a crash happens while the parser is active, print out a line indicating |
| /// what the current token is. |
| void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { |
| const Token &Tok = P.getCurToken(); |
| if (Tok.is(tok::eof)) { |
| OS << "<eof> parser at end of file\n"; |
| return; |
| } |
| |
| if (Tok.getLocation().isInvalid()) { |
| OS << "<unknown> parser at unknown location\n"; |
| return; |
| } |
| |
| const Preprocessor &PP = P.getPreprocessor(); |
| Tok.getLocation().print(OS, PP.getSourceManager()); |
| if (Tok.isAnnotation()) { |
| OS << ": at annotation token\n"; |
| } else { |
| // Do the equivalent of PP.getSpelling(Tok) except for the parts that would |
| // allocate memory. |
| bool Invalid = false; |
| const SourceManager &SM = P.getPreprocessor().getSourceManager(); |
| unsigned Length = Tok.getLength(); |
| const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid); |
| if (Invalid) { |
| OS << ": unknown current parser token\n"; |
| return; |
| } |
| OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n"; |
| } |
| } |
| |
| } // namespace |
| |
| //===----------------------------------------------------------------------===// |
| // Public interface to the file |
| //===----------------------------------------------------------------------===// |
| |
| /// ParseAST - Parse the entire file specified, notifying the ASTConsumer as |
| /// the file is parsed. This inserts the parsed decls into the translation unit |
| /// held by Ctx. |
| /// |
| void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, |
| ASTContext &Ctx, bool PrintStats, |
| TranslationUnitKind TUKind, |
| CodeCompleteConsumer *CompletionConsumer, |
| bool SkipFunctionBodies) { |
| |
| std::unique_ptr<Sema> S( |
| new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer)); |
| |
| // Recover resources if we crash before exiting this method. |
| llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get()); |
| |
| ParseAST(*S.get(), PrintStats, SkipFunctionBodies); |
| } |
| |
| void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { |
| // Collect global stats on Decls/Stmts (until we have a module streamer). |
| if (PrintStats) { |
| Decl::EnableStatistics(); |
| Stmt::EnableStatistics(); |
| } |
| |
| // Also turn on collection of stats inside of the Sema object. |
| bool OldCollectStats = PrintStats; |
| std::swap(OldCollectStats, S.CollectStats); |
| |
| // Initialize the template instantiation observer chain. |
| // FIXME: See note on "finalize" below. |
| initialize(S.TemplateInstCallbacks, S); |
| |
| ASTConsumer *Consumer = &S.getASTConsumer(); |
| |
| std::unique_ptr<Parser> ParseOP( |
| new Parser(S.getPreprocessor(), S, SkipFunctionBodies)); |
| Parser &P = *ParseOP.get(); |
| |
| llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup> |
| CleanupPrettyStack(llvm::SavePrettyStackState()); |
| PrettyStackTraceParserEntry CrashInfo(P); |
| |
| // Recover resources if we crash before exiting this method. |
| llvm::CrashRecoveryContextCleanupRegistrar<Parser> |
| CleanupParser(ParseOP.get()); |
| |
| S.getPreprocessor().EnterMainSourceFile(); |
| ExternalASTSource *External = S.getASTContext().getExternalSource(); |
| if (External) |
| External->StartTranslationUnit(Consumer); |
| |
| // If a PCH through header is specified that does not have an include in |
| // the source, or a PCH is being created with #pragma hdrstop with nothing |
| // after the pragma, there won't be any tokens or a Lexer. |
| bool HaveLexer = S.getPreprocessor().getCurrentLexer(); |
| |
| if (HaveLexer) { |
| llvm::TimeTraceScope TimeScope("Frontend", StringRef("")); |
| P.Initialize(); |
| Parser::DeclGroupPtrTy ADecl; |
| for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF; |
| AtEOF = P.ParseTopLevelDecl(ADecl)) { |
| // If we got a null return and something *was* parsed, ignore it. This |
| // is due to a top-level semicolon, an action override, or a parse error |
| // skipping something. |
| if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) |
| return; |
| } |
| } |
| |
| // Process any TopLevelDecls generated by #pragma weak. |
| for (Decl *D : S.WeakTopLevelDecls()) |
| Consumer->HandleTopLevelDecl(DeclGroupRef(D)); |
| |
| Consumer->HandleTranslationUnit(S.getASTContext()); |
| |
| // Finalize the template instantiation observer chain. |
| // FIXME: This (and init.) should be done in the Sema class, but because |
| // Sema does not have a reliable "Finalize" function (it has a |
| // destructor, but it is not guaranteed to be called ("-disable-free")). |
| // So, do the initialization above and do the finalization here: |
| finalize(S.TemplateInstCallbacks, S); |
| |
| std::swap(OldCollectStats, S.CollectStats); |
| if (PrintStats) { |
| llvm::errs() << "\nSTATISTICS:\n"; |
| if (HaveLexer) P.getActions().PrintStats(); |
| S.getASTContext().PrintStats(); |
| Decl::PrintStats(); |
| Stmt::PrintStats(); |
| Consumer->PrintStats(); |
| } |
| } |