llvm-project
194 строки · 6.9 Кб
1//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the clang::ParseAST method.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Parse/ParseAST.h"14#include "clang/AST/ASTConsumer.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/ExternalASTSource.h"17#include "clang/AST/Stmt.h"18#include "clang/Parse/ParseDiagnostic.h"19#include "clang/Parse/Parser.h"20#include "clang/Sema/CodeCompleteConsumer.h"21#include "clang/Sema/EnterExpressionEvaluationContext.h"22#include "clang/Sema/Sema.h"23#include "clang/Sema/SemaConsumer.h"24#include "clang/Sema/TemplateInstCallback.h"25#include "llvm/Support/CrashRecoveryContext.h"26#include "llvm/Support/TimeProfiler.h"27#include <cstdio>28#include <memory>29
30using namespace clang;31
32namespace {33
34/// Resets LLVM's pretty stack state so that stack traces are printed correctly
35/// when there are nested CrashRecoveryContexts and the inner one recovers from
36/// a crash.
37class ResetStackCleanup38: public llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup,39const void> {40public:41ResetStackCleanup(llvm::CrashRecoveryContext *Context, const void *Top)42: llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, const void>(43Context, Top) {}44void recoverResources() override {45llvm::RestorePrettyStackState(resource);46}47};48
49/// If a crash happens while the parser is active, an entry is printed for it.
50class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {51const Parser &P;52public:53PrettyStackTraceParserEntry(const Parser &p) : P(p) {}54void print(raw_ostream &OS) const override;55};56
57/// If a crash happens while the parser is active, print out a line indicating
58/// what the current token is.
59void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {60const Token &Tok = P.getCurToken();61if (Tok.is(tok::eof)) {62OS << "<eof> parser at end of file\n";63return;64}65
66if (Tok.getLocation().isInvalid()) {67OS << "<unknown> parser at unknown location\n";68return;69}70
71const Preprocessor &PP = P.getPreprocessor();72Tok.getLocation().print(OS, PP.getSourceManager());73if (Tok.isAnnotation()) {74OS << ": at annotation token\n";75} else {76// Do the equivalent of PP.getSpelling(Tok) except for the parts that would77// allocate memory.78bool Invalid = false;79const SourceManager &SM = P.getPreprocessor().getSourceManager();80unsigned Length = Tok.getLength();81const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid);82if (Invalid) {83OS << ": unknown current parser token\n";84return;85}86OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n";87}88}
89
90} // namespace91
92//===----------------------------------------------------------------------===//
93// Public interface to the file
94//===----------------------------------------------------------------------===//
95
96/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as
97/// the file is parsed. This inserts the parsed decls into the translation unit
98/// held by Ctx.
99///
100void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,101ASTContext &Ctx, bool PrintStats,102TranslationUnitKind TUKind,103CodeCompleteConsumer *CompletionConsumer,104bool SkipFunctionBodies) {105
106std::unique_ptr<Sema> S(107new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));108
109// Recover resources if we crash before exiting this method.110llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());111
112ParseAST(*S.get(), PrintStats, SkipFunctionBodies);113}
114
115void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {116// Collect global stats on Decls/Stmts (until we have a module streamer).117if (PrintStats) {118Decl::EnableStatistics();119Stmt::EnableStatistics();120}121
122// Also turn on collection of stats inside of the Sema object.123bool OldCollectStats = PrintStats;124std::swap(OldCollectStats, S.CollectStats);125
126// Initialize the template instantiation observer chain.127// FIXME: See note on "finalize" below.128initialize(S.TemplateInstCallbacks, S);129
130ASTConsumer *Consumer = &S.getASTConsumer();131
132std::unique_ptr<Parser> ParseOP(133new Parser(S.getPreprocessor(), S, SkipFunctionBodies));134Parser &P = *ParseOP.get();135
136llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup>137CleanupPrettyStack(llvm::SavePrettyStackState());138PrettyStackTraceParserEntry CrashInfo(P);139
140// Recover resources if we crash before exiting this method.141llvm::CrashRecoveryContextCleanupRegistrar<Parser>142CleanupParser(ParseOP.get());143
144S.getPreprocessor().EnterMainSourceFile();145ExternalASTSource *External = S.getASTContext().getExternalSource();146if (External)147External->StartTranslationUnit(Consumer);148
149// If a PCH through header is specified that does not have an include in150// the source, or a PCH is being created with #pragma hdrstop with nothing151// after the pragma, there won't be any tokens or a Lexer.152bool HaveLexer = S.getPreprocessor().getCurrentLexer();153
154if (HaveLexer) {155llvm::TimeTraceScope TimeScope("Frontend");156P.Initialize();157Parser::DeclGroupPtrTy ADecl;158Sema::ModuleImportState ImportState;159EnterExpressionEvaluationContext PotentiallyEvaluated(160S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);161
162for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;163AtEOF = P.ParseTopLevelDecl(ADecl, ImportState)) {164// If we got a null return and something *was* parsed, ignore it. This165// is due to a top-level semicolon, an action override, or a parse error166// skipping something.167if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))168return;169}170}171
172// Process any TopLevelDecls generated by #pragma weak.173for (Decl *D : S.WeakTopLevelDecls())174Consumer->HandleTopLevelDecl(DeclGroupRef(D));175
176Consumer->HandleTranslationUnit(S.getASTContext());177
178// Finalize the template instantiation observer chain.179// FIXME: This (and init.) should be done in the Sema class, but because180// Sema does not have a reliable "Finalize" function (it has a181// destructor, but it is not guaranteed to be called ("-disable-free")).182// So, do the initialization above and do the finalization here:183finalize(S.TemplateInstCallbacks, S);184
185std::swap(OldCollectStats, S.CollectStats);186if (PrintStats) {187llvm::errs() << "\nSTATISTICS:\n";188if (HaveLexer) P.getActions().PrintStats();189S.getASTContext().PrintStats();190Decl::PrintStats();191Stmt::PrintStats();192Consumer->PrintStats();193}194}
195