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(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(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, 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(Tok.getLocation(), &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.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(OldCollectStats, S.CollectStats); 125 126 // Initialize the template instantiation observer chain. 127 // FIXME: See note on "finalize" below. 128 initialize(S.TemplateInstCallbacks, 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(ADecl, ImportState); !AtEOF; 163 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 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) 168 return; 169 } 170 } 171 172 // Process any TopLevelDecls generated by #pragma weak. 173 for (Decl *D : S.WeakTopLevelDecls()) 174 Consumer->HandleTopLevelDecl(DeclGroupRef(D)); 175 176 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 finalize(S.TemplateInstCallbacks, S); 184 185 std::swap(OldCollectStats, 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