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