/src/llvm-project/clang/lib/Parse/ParseAST.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | Context, Top) {} |
44 | 0 | void recoverResources() override { |
45 | 0 | llvm::RestorePrettyStackState(resource); |
46 | 0 | } |
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 | 46 | 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 | 0 | void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { |
60 | 0 | const Token &Tok = P.getCurToken(); |
61 | 0 | if (Tok.is(tok::eof)) { |
62 | 0 | OS << "<eof> parser at end of file\n"; |
63 | 0 | return; |
64 | 0 | } |
65 | | |
66 | 0 | if (Tok.getLocation().isInvalid()) { |
67 | 0 | OS << "<unknown> parser at unknown location\n"; |
68 | 0 | return; |
69 | 0 | } |
70 | | |
71 | 0 | const Preprocessor &PP = P.getPreprocessor(); |
72 | 0 | Tok.getLocation().print(OS, PP.getSourceManager()); |
73 | 0 | if (Tok.isAnnotation()) { |
74 | 0 | OS << ": at annotation token\n"; |
75 | 0 | } else { |
76 | | // Do the equivalent of PP.getSpelling(Tok) except for the parts that would |
77 | | // allocate memory. |
78 | 0 | bool Invalid = false; |
79 | 0 | const SourceManager &SM = P.getPreprocessor().getSourceManager(); |
80 | 0 | unsigned Length = Tok.getLength(); |
81 | 0 | const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid); |
82 | 0 | if (Invalid) { |
83 | 0 | OS << ": unknown current parser token\n"; |
84 | 0 | return; |
85 | 0 | } |
86 | 0 | OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n"; |
87 | 0 | } |
88 | 0 | } |
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 | 0 | bool SkipFunctionBodies) { |
105 | |
|
106 | 0 | std::unique_ptr<Sema> S( |
107 | 0 | new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer)); |
108 | | |
109 | | // Recover resources if we crash before exiting this method. |
110 | 0 | llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get()); |
111 | |
|
112 | 0 | ParseAST(*S.get(), PrintStats, SkipFunctionBodies); |
113 | 0 | } |
114 | | |
115 | 46 | void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { |
116 | | // Collect global stats on Decls/Stmts (until we have a module streamer). |
117 | 46 | if (PrintStats) { |
118 | 0 | Decl::EnableStatistics(); |
119 | 0 | Stmt::EnableStatistics(); |
120 | 0 | } |
121 | | |
122 | | // Also turn on collection of stats inside of the Sema object. |
123 | 46 | bool OldCollectStats = PrintStats; |
124 | 46 | std::swap(OldCollectStats, S.CollectStats); |
125 | | |
126 | | // Initialize the template instantiation observer chain. |
127 | | // FIXME: See note on "finalize" below. |
128 | 46 | initialize(S.TemplateInstCallbacks, S); |
129 | | |
130 | 46 | ASTConsumer *Consumer = &S.getASTConsumer(); |
131 | | |
132 | 46 | std::unique_ptr<Parser> ParseOP( |
133 | 46 | new Parser(S.getPreprocessor(), S, SkipFunctionBodies)); |
134 | 46 | Parser &P = *ParseOP.get(); |
135 | | |
136 | 46 | llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup> |
137 | 46 | CleanupPrettyStack(llvm::SavePrettyStackState()); |
138 | 46 | PrettyStackTraceParserEntry CrashInfo(P); |
139 | | |
140 | | // Recover resources if we crash before exiting this method. |
141 | 46 | llvm::CrashRecoveryContextCleanupRegistrar<Parser> |
142 | 46 | CleanupParser(ParseOP.get()); |
143 | | |
144 | 46 | S.getPreprocessor().EnterMainSourceFile(); |
145 | 46 | ExternalASTSource *External = S.getASTContext().getExternalSource(); |
146 | 46 | if (External) |
147 | 0 | 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 | 46 | bool HaveLexer = S.getPreprocessor().getCurrentLexer(); |
153 | | |
154 | 46 | if (HaveLexer) { |
155 | 46 | llvm::TimeTraceScope TimeScope("Frontend"); |
156 | 46 | P.Initialize(); |
157 | 46 | Parser::DeclGroupPtrTy ADecl; |
158 | 46 | Sema::ModuleImportState ImportState; |
159 | 46 | EnterExpressionEvaluationContext PotentiallyEvaluated( |
160 | 46 | S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); |
161 | | |
162 | 34.7k | for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; |
163 | 34.6k | AtEOF = P.ParseTopLevelDecl(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 | 34.6k | if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) |
168 | 0 | return; |
169 | 34.6k | } |
170 | 46 | } |
171 | | |
172 | | // Process any TopLevelDecls generated by #pragma weak. |
173 | 46 | for (Decl *D : S.WeakTopLevelDecls()) |
174 | 0 | Consumer->HandleTopLevelDecl(DeclGroupRef(D)); |
175 | | |
176 | 46 | Consumer->HandleTranslationUnit(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 | 46 | finalize(S.TemplateInstCallbacks, S); |
184 | | |
185 | 46 | std::swap(OldCollectStats, S.CollectStats); |
186 | 46 | if (PrintStats) { |
187 | 0 | llvm::errs() << "\nSTATISTICS:\n"; |
188 | 0 | if (HaveLexer) P.getActions().PrintStats(); |
189 | 0 | S.getASTContext().PrintStats(); |
190 | 0 | Decl::PrintStats(); |
191 | 0 | Stmt::PrintStats(); |
192 | 0 | Consumer->PrintStats(); |
193 | 0 | } |
194 | 46 | } |