1//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the clang::ParseAST method. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Parse/ParseAST.h" 15#include "clang/AST/ASTConsumer.h" 16#include "clang/AST/ASTContext.h" 17#include "clang/AST/ExternalASTSource.h" 18#include "clang/AST/Stmt.h" 19#include "clang/Parse/ParseDiagnostic.h" 20#include "clang/Parse/Parser.h" 21#include "clang/Sema/CodeCompleteConsumer.h" 22#include "clang/Sema/Sema.h" 23#include "clang/Sema/SemaConsumer.h" 24#include "llvm/Support/CrashRecoveryContext.h" 25#include <cstdio> 26#include <memory> 27 28using namespace clang; 29 30namespace { 31 32/// Resets LLVM's pretty stack state so that stack traces are printed correctly 33/// when there are nested CrashRecoveryContexts and the inner one recovers from 34/// a crash. 35class ResetStackCleanup 36 : public llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, 37 const void> { 38public: 39 ResetStackCleanup(llvm::CrashRecoveryContext *Context, const void *Top) 40 : llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, const void>( 41 Context, Top) {} 42 void recoverResources() override { 43 llvm::RestorePrettyStackState(resource); 44 } 45}; 46 47/// If a crash happens while the parser is active, an entry is printed for it. 48class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { 49 const Parser &P; 50public: 51 PrettyStackTraceParserEntry(const Parser &p) : P(p) {} 52 void print(raw_ostream &OS) const override; 53}; 54 55/// If a crash happens while the parser is active, print out a line indicating 56/// what the current token is. 57void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { 58 const Token &Tok = P.getCurToken(); 59 if (Tok.is(tok::eof)) { 60 OS << "<eof> parser at end of file\n"; 61 return; 62 } 63 64 if (Tok.getLocation().isInvalid()) { 65 OS << "<unknown> parser at unknown location\n"; 66 return; 67 } 68 69 const Preprocessor &PP = P.getPreprocessor(); 70 Tok.getLocation().print(OS, PP.getSourceManager()); 71 if (Tok.isAnnotation()) { 72 OS << ": at annotation token\n"; 73 } else { 74 // Do the equivalent of PP.getSpelling(Tok) except for the parts that would 75 // allocate memory. 76 bool Invalid = false; 77 const SourceManager &SM = P.getPreprocessor().getSourceManager(); 78 unsigned Length = Tok.getLength(); 79 const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid); 80 if (Invalid) { 81 OS << ": unknown current parser token\n"; 82 return; 83 } 84 OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n"; 85 } 86} 87 88} // namespace 89 90//===----------------------------------------------------------------------===// 91// Public interface to the file 92//===----------------------------------------------------------------------===// 93 94/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as 95/// the file is parsed. This inserts the parsed decls into the translation unit 96/// held by Ctx. 97/// 98void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, 99 ASTContext &Ctx, bool PrintStats, 100 TranslationUnitKind TUKind, 101 CodeCompleteConsumer *CompletionConsumer, 102 bool SkipFunctionBodies) { 103 104 std::unique_ptr<Sema> S( 105 new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer)); 106 107 // Recover resources if we crash before exiting this method. 108 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get()); 109 110 ParseAST(*S.get(), PrintStats, SkipFunctionBodies); 111} 112 113void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { 114 // Collect global stats on Decls/Stmts (until we have a module streamer). 115 if (PrintStats) { 116 Decl::EnableStatistics(); 117 Stmt::EnableStatistics(); 118 } 119 120 // Also turn on collection of stats inside of the Sema object. 121 bool OldCollectStats = PrintStats; 122 std::swap(OldCollectStats, S.CollectStats); 123 124 ASTConsumer *Consumer = &S.getASTConsumer(); 125 126 std::unique_ptr<Parser> ParseOP( 127 new Parser(S.getPreprocessor(), S, SkipFunctionBodies)); 128 Parser &P = *ParseOP.get(); 129 130 llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup> 131 CleanupPrettyStack(llvm::SavePrettyStackState()); 132 PrettyStackTraceParserEntry CrashInfo(P); 133 134 // Recover resources if we crash before exiting this method. 135 llvm::CrashRecoveryContextCleanupRegistrar<Parser> 136 CleanupParser(ParseOP.get()); 137 138 S.getPreprocessor().EnterMainSourceFile(); 139 P.Initialize(); 140 141 // C11 6.9p1 says translation units must have at least one top-level 142 // declaration. C++ doesn't have this restriction. We also don't want to 143 // complain if we have a precompiled header, although technically if the PCH 144 // is empty we should still emit the (pedantic) diagnostic. 145 Parser::DeclGroupPtrTy ADecl; 146 ExternalASTSource *External = S.getASTContext().getExternalSource(); 147 if (External) 148 External->StartTranslationUnit(Consumer); 149 150 if (P.ParseTopLevelDecl(ADecl)) { 151 if (!External && !S.getLangOpts().CPlusPlus) 152 P.Diag(diag::ext_empty_translation_unit); 153 } else { 154 do { 155 // If we got a null return and something *was* parsed, ignore it. This 156 // is due to a top-level semicolon, an action override, or a parse error 157 // skipping something. 158 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) 159 return; 160 } while (!P.ParseTopLevelDecl(ADecl)); 161 } 162 163 // Process any TopLevelDecls generated by #pragma weak. 164 for (Decl *D : S.WeakTopLevelDecls()) 165 Consumer->HandleTopLevelDecl(DeclGroupRef(D)); 166 167 Consumer->HandleTranslationUnit(S.getASTContext()); 168 169 std::swap(OldCollectStats, S.CollectStats); 170 if (PrintStats) { 171 llvm::errs() << "\nSTATISTICS:\n"; 172 P.getActions().PrintStats(); 173 S.getASTContext().PrintStats(); 174 Decl::PrintStats(); 175 Stmt::PrintStats(); 176 Consumer->PrintStats(); 177 } 178} 179