//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // 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 "llvm/Support/CrashRecoveryContext.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); 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(); P.Initialize(); // C11 6.9p1 says translation units must have at least one top-level // declaration. C++ doesn't have this restriction. We also don't want to // complain if we have a precompiled header, although technically if the PCH // is empty we should still emit the (pedantic) diagnostic. Parser::DeclGroupPtrTy ADecl; ExternalASTSource *External = S.getASTContext().getExternalSource(); if (External) External->StartTranslationUnit(Consumer); if (P.ParseTopLevelDecl(ADecl)) { if (!External && !S.getLangOpts().CPlusPlus) P.Diag(diag::ext_empty_translation_unit); } else { do { // 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; } while (!P.ParseTopLevelDecl(ADecl)); } // Process any TopLevelDecls generated by #pragma weak. for (Decl *D : S.WeakTopLevelDecls()) Consumer->HandleTopLevelDecl(DeclGroupRef(D)); Consumer->HandleTranslationUnit(S.getASTContext()); std::swap(OldCollectStats, S.CollectStats); if (PrintStats) { llvm::errs() << "\nSTATISTICS:\n"; P.getActions().PrintStats(); S.getASTContext().PrintStats(); Decl::PrintStats(); Stmt::PrintStats(); Consumer->PrintStats(); } }