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 | |
30 | using namespace clang; |
31 | |
32 | namespace { |
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. |
37 | class ResetStackCleanup |
38 | : public llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, |
39 | const void> { |
40 | public: |
41 | ResetStackCleanup(llvm::CrashRecoveryContext *Context, const void *Top) |
42 | : llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, const void>( |
43 | Context, Top) {} |
44 | void recoverResources() override { |
45 | llvm::RestorePrettyStackState(State: resource); |
46 | } |
47 | }; |
48 | |
49 | /// If a crash happens while the parser is active, an entry is printed for it. |
50 | class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { |
51 | const Parser &P; |
52 | public: |
53 | PrettyStackTraceParserEntry(const Parser &p) : P(p) {} |
54 | void 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. |
59 | void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { |
60 | const Token &Tok = P.getCurToken(); |
61 | if (Tok.is(K: tok::eof)) { |
62 | OS << "<eof> parser at end of file\n" ; |
63 | return; |
64 | } |
65 | |
66 | if (Tok.getLocation().isInvalid()) { |
67 | OS << "<unknown> parser at unknown location\n" ; |
68 | return; |
69 | } |
70 | |
71 | const Preprocessor &PP = P.getPreprocessor(); |
72 | Tok.getLocation().print(OS, SM: PP.getSourceManager()); |
73 | if (Tok.isAnnotation()) { |
74 | OS << ": at annotation token\n" ; |
75 | } else { |
76 | // Do the equivalent of PP.getSpelling(Tok) except for the parts that would |
77 | // allocate memory. |
78 | bool Invalid = false; |
79 | const SourceManager &SM = P.getPreprocessor().getSourceManager(); |
80 | unsigned Length = Tok.getLength(); |
81 | const char *Spelling = SM.getCharacterData(SL: Tok.getLocation(), Invalid: &Invalid); |
82 | if (Invalid) { |
83 | OS << ": unknown current parser token\n" ; |
84 | return; |
85 | } |
86 | OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n" ; |
87 | } |
88 | } |
89 | |
90 | } // namespace |
91 | |
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 | /// |
100 | void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, |
101 | ASTContext &Ctx, bool PrintStats, |
102 | TranslationUnitKind TUKind, |
103 | CodeCompleteConsumer *CompletionConsumer, |
104 | bool SkipFunctionBodies) { |
105 | |
106 | std::unique_ptr<Sema> S( |
107 | new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer)); |
108 | |
109 | // Recover resources if we crash before exiting this method. |
110 | llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get()); |
111 | |
112 | ParseAST(S&: *S.get(), PrintStats, SkipFunctionBodies); |
113 | } |
114 | |
115 | void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { |
116 | // Collect global stats on Decls/Stmts (until we have a module streamer). |
117 | if (PrintStats) { |
118 | Decl::EnableStatistics(); |
119 | Stmt::EnableStatistics(); |
120 | } |
121 | |
122 | // Also turn on collection of stats inside of the Sema object. |
123 | bool OldCollectStats = PrintStats; |
124 | std::swap(a&: OldCollectStats, b&: S.CollectStats); |
125 | |
126 | // Initialize the template instantiation observer chain. |
127 | // FIXME: See note on "finalize" below. |
128 | initialize(Callbacks&: S.TemplateInstCallbacks, TheSema: S); |
129 | |
130 | ASTConsumer *Consumer = &S.getASTConsumer(); |
131 | |
132 | std::unique_ptr<Parser> ParseOP( |
133 | new Parser(S.getPreprocessor(), S, SkipFunctionBodies)); |
134 | Parser &P = *ParseOP.get(); |
135 | |
136 | llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup> |
137 | CleanupPrettyStack(llvm::SavePrettyStackState()); |
138 | PrettyStackTraceParserEntry CrashInfo(P); |
139 | |
140 | // Recover resources if we crash before exiting this method. |
141 | llvm::CrashRecoveryContextCleanupRegistrar<Parser> |
142 | CleanupParser(ParseOP.get()); |
143 | |
144 | S.getPreprocessor().EnterMainSourceFile(); |
145 | ExternalASTSource *External = S.getASTContext().getExternalSource(); |
146 | if (External) |
147 | External->StartTranslationUnit(Consumer); |
148 | |
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(); |
153 | |
154 | if (HaveLexer) { |
155 | llvm::TimeTraceScope TimeScope("Frontend" ); |
156 | P.Initialize(); |
157 | Parser::DeclGroupPtrTy ADecl; |
158 | Sema::ModuleImportState ImportState; |
159 | EnterExpressionEvaluationContext PotentiallyEvaluated( |
160 | S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); |
161 | |
162 | for (bool AtEOF = P.ParseFirstTopLevelDecl(Result&: ADecl, ImportState); !AtEOF; |
163 | AtEOF = P.ParseTopLevelDecl(Result&: ADecl, ImportState)) { |
164 | // If we got a null return and something *was* parsed, ignore it. This |
165 | // is due to a top-level semicolon, an action override, or a parse error |
166 | // skipping something. |
167 | if (ADecl && !Consumer->HandleTopLevelDecl(D: ADecl.get())) |
168 | return; |
169 | } |
170 | } |
171 | |
172 | // Process any TopLevelDecls generated by #pragma weak. |
173 | for (Decl *D : S.WeakTopLevelDecls()) |
174 | Consumer->HandleTopLevelDecl(D: DeclGroupRef(D)); |
175 | |
176 | Consumer->HandleTranslationUnit(Ctx&: S.getASTContext()); |
177 | |
178 | // Finalize the template instantiation observer chain. |
179 | // FIXME: This (and init.) should be done in the Sema class, but because |
180 | // Sema does not have a reliable "Finalize" function (it has a |
181 | // destructor, but it is not guaranteed to be called ("-disable-free")). |
182 | // So, do the initialization above and do the finalization here: |
183 | finalize(Callbacks&: S.TemplateInstCallbacks, TheSema: S); |
184 | |
185 | std::swap(a&: OldCollectStats, b&: S.CollectStats); |
186 | if (PrintStats) { |
187 | llvm::errs() << "\nSTATISTICS:\n" ; |
188 | if (HaveLexer) P.getActions().PrintStats(); |
189 | S.getASTContext().PrintStats(); |
190 | Decl::PrintStats(); |
191 | Stmt::PrintStats(); |
192 | Consumer->PrintStats(); |
193 | } |
194 | } |
195 | |