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