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