1 //===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the clang::ParseAST method.
11 //===----------------------------------------------------------------------===//
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/Basic/DiagnosticParse.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"
30 using namespace clang
;
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
37 class ResetStackCleanup
38 : public llvm::CrashRecoveryContextCleanupBase
<ResetStackCleanup
,
41 ResetStackCleanup(llvm::CrashRecoveryContext
*Context
, const void *Top
)
42 : llvm::CrashRecoveryContextCleanupBase
<ResetStackCleanup
, const void>(
44 void recoverResources() override
{
45 llvm::RestorePrettyStackState(resource
);
49 /// If a crash happens while the parser is active, an entry is printed for it.
50 class PrettyStackTraceParserEntry
: public llvm::PrettyStackTraceEntry
{
53 PrettyStackTraceParserEntry(const Parser
&p
) : P(p
) {}
54 void print(raw_ostream
&OS
) const override
;
57 /// If a crash happens while the parser is active, print out a line indicating
58 /// what the current token is.
59 void PrettyStackTraceParserEntry::print(raw_ostream
&OS
) const {
60 const Token
&Tok
= P
.getCurToken();
61 if (Tok
.is(tok::eof
)) {
62 OS
<< "<eof> parser at end of file\n";
66 if (Tok
.getLocation().isInvalid()) {
67 OS
<< "<unknown> parser at unknown location\n";
71 const Preprocessor
&PP
= P
.getPreprocessor();
72 Tok
.getLocation().print(OS
, PP
.getSourceManager());
73 if (Tok
.isAnnotation()) {
74 OS
<< ": at annotation token\n";
76 // Do the equivalent of PP.getSpelling(Tok) except for the parts that would
79 const SourceManager
&SM
= P
.getPreprocessor().getSourceManager();
80 unsigned Length
= Tok
.getLength();
81 const char *Spelling
= SM
.getCharacterData(Tok
.getLocation(), &Invalid
);
83 OS
<< ": unknown current parser token\n";
86 OS
<< ": current parser token '" << StringRef(Spelling
, Length
) << "'\n";
92 //===----------------------------------------------------------------------===//
93 // Public interface to the file
94 //===----------------------------------------------------------------------===//
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
100 void clang::ParseAST(Preprocessor
&PP
, ASTConsumer
*Consumer
,
101 ASTContext
&Ctx
, bool PrintStats
,
102 TranslationUnitKind TUKind
,
103 CodeCompleteConsumer
*CompletionConsumer
,
104 bool SkipFunctionBodies
) {
106 std::unique_ptr
<Sema
> S(
107 new Sema(PP
, Ctx
, *Consumer
, TUKind
, CompletionConsumer
));
109 // Recover resources if we crash before exiting this method.
110 llvm::CrashRecoveryContextCleanupRegistrar
<Sema
> CleanupSema(S
.get());
112 ParseAST(*S
.get(), PrintStats
, SkipFunctionBodies
);
115 void clang::ParseAST(Sema
&S
, bool PrintStats
, bool SkipFunctionBodies
) {
116 // Collect global stats on Decls/Stmts (until we have a module streamer).
118 Decl::EnableStatistics();
119 Stmt::EnableStatistics();
122 // Also turn on collection of stats inside of the Sema object.
123 bool OldCollectStats
= PrintStats
;
124 std::swap(OldCollectStats
, S
.CollectStats
);
126 // Initialize the template instantiation observer chain.
127 // FIXME: See note on "finalize" below.
128 initialize(S
.TemplateInstCallbacks
, S
);
130 ASTConsumer
*Consumer
= &S
.getASTConsumer();
132 std::unique_ptr
<Parser
> ParseOP(
133 new Parser(S
.getPreprocessor(), S
, SkipFunctionBodies
));
134 Parser
&P
= *ParseOP
.get();
136 llvm::CrashRecoveryContextCleanupRegistrar
<const void, ResetStackCleanup
>
137 CleanupPrettyStack(llvm::SavePrettyStackState());
138 PrettyStackTraceParserEntry
CrashInfo(P
);
140 // Recover resources if we crash before exiting this method.
141 llvm::CrashRecoveryContextCleanupRegistrar
<Parser
>
142 CleanupParser(ParseOP
.get());
144 S
.getPreprocessor().EnterMainSourceFile();
145 ExternalASTSource
*External
= S
.getASTContext().getExternalSource();
147 External
->StartTranslationUnit(Consumer
);
149 // If a PCH through header is specified that does not have an include in
150 // the source, or a PCH is being created with #pragma hdrstop with nothing
151 // after the pragma, there won't be any tokens or a Lexer.
152 bool HaveLexer
= S
.getPreprocessor().getCurrentLexer();
155 llvm::TimeTraceScope
TimeScope("Frontend", [&]() {
156 llvm::TimeTraceMetadata M
;
157 if (llvm::isTimeTraceVerbose()) {
158 const SourceManager
&SM
= S
.getSourceManager();
159 if (const auto *FE
= SM
.getFileEntryForID(SM
.getMainFileID()))
160 M
.File
= FE
->tryGetRealPathName();
165 Parser::DeclGroupPtrTy ADecl
;
166 Sema::ModuleImportState ImportState
;
167 EnterExpressionEvaluationContext
PotentiallyEvaluated(
168 S
, Sema::ExpressionEvaluationContext::PotentiallyEvaluated
);
170 for (bool AtEOF
= P
.ParseFirstTopLevelDecl(ADecl
, ImportState
); !AtEOF
;
171 AtEOF
= P
.ParseTopLevelDecl(ADecl
, ImportState
)) {
172 // If we got a null return and something *was* parsed, ignore it. This
173 // is due to a top-level semicolon, an action override, or a parse error
174 // skipping something.
175 if (ADecl
&& !Consumer
->HandleTopLevelDecl(ADecl
.get()))
180 // Process any TopLevelDecls generated by #pragma weak.
181 for (Decl
*D
: S
.WeakTopLevelDecls())
182 Consumer
->HandleTopLevelDecl(DeclGroupRef(D
));
184 Consumer
->HandleTranslationUnit(S
.getASTContext());
186 // Finalize the template instantiation observer chain.
187 // FIXME: This (and init.) should be done in the Sema class, but because
188 // Sema does not have a reliable "Finalize" function (it has a
189 // destructor, but it is not guaranteed to be called ("-disable-free")).
190 // So, do the initialization above and do the finalization here:
191 finalize(S
.TemplateInstCallbacks
, S
);
193 std::swap(OldCollectStats
, S
.CollectStats
);
195 llvm::errs() << "\nSTATISTICS:\n";
196 if (HaveLexer
) P
.getActions().PrintStats();
197 S
.getASTContext().PrintStats();
200 Consumer
->PrintStats();