Home | History | Annotate | Download | only in Parse
      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 
     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             Context, Top) {}
     43   void recoverResources() override {
     44     llvm::RestorePrettyStackState(resource);
     45   }
     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   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 void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
     59   const Token &Tok = P.getCurToken();
     60   if (Tok.is(tok::eof)) {
     61     OS << "<eof> parser at end of file\n";
     62     return;
     63   }
     64 
     65   if (Tok.getLocation().isInvalid()) {
     66     OS << "<unknown> parser at unknown location\n";
     67     return;
     68   }
     69 
     70   const Preprocessor &PP = P.getPreprocessor();
     71   Tok.getLocation().print(OS, PP.getSourceManager());
     72   if (Tok.isAnnotation()) {
     73     OS << ": at annotation token\n";
     74   } else {
     75     // Do the equivalent of PP.getSpelling(Tok) except for the parts that would
     76     // allocate memory.
     77     bool Invalid = false;
     78     const SourceManager &SM = P.getPreprocessor().getSourceManager();
     79     unsigned Length = Tok.getLength();
     80     const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid);
     81     if (Invalid) {
     82       OS << ": unknown current parser token\n";
     83       return;
     84     }
     85     OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n";
     86   }
     87 }
     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                      bool SkipFunctionBodies) {
    104 
    105   std::unique_ptr<Sema> S(
    106       new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
    107 
    108   // Recover resources if we crash before exiting this method.
    109   llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
    110 
    111   ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
    112 }
    113 
    114 void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
    115   // Collect global stats on Decls/Stmts (until we have a module streamer).
    116   if (PrintStats) {
    117     Decl::EnableStatistics();
    118     Stmt::EnableStatistics();
    119   }
    120 
    121   // Also turn on collection of stats inside of the Sema object.
    122   bool OldCollectStats = PrintStats;
    123   std::swap(OldCollectStats, S.CollectStats);
    124 
    125   ASTConsumer *Consumer = &S.getASTConsumer();
    126 
    127   std::unique_ptr<Parser> ParseOP(
    128       new Parser(S.getPreprocessor(), S, SkipFunctionBodies));
    129   Parser &P = *ParseOP.get();
    130 
    131   llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup>
    132       CleanupPrettyStack(llvm::SavePrettyStackState());
    133   PrettyStackTraceParserEntry CrashInfo(P);
    134 
    135   // Recover resources if we crash before exiting this method.
    136   llvm::CrashRecoveryContextCleanupRegistrar<Parser>
    137     CleanupParser(ParseOP.get());
    138 
    139   S.getPreprocessor().EnterMainSourceFile();
    140   P.Initialize();
    141 
    142   // C11 6.9p1 says translation units must have at least one top-level
    143   // declaration. C++ doesn't have this restriction. We also don't want to
    144   // complain if we have a precompiled header, although technically if the PCH
    145   // is empty we should still emit the (pedantic) diagnostic.
    146   Parser::DeclGroupPtrTy ADecl;
    147   ExternalASTSource *External = S.getASTContext().getExternalSource();
    148   if (External)
    149     External->StartTranslationUnit(Consumer);
    150 
    151   if (P.ParseTopLevelDecl(ADecl)) {
    152     if (!External && !S.getLangOpts().CPlusPlus)
    153       P.Diag(diag::ext_empty_translation_unit);
    154   } else {
    155     do {
    156       // If we got a null return and something *was* parsed, ignore it.  This
    157       // is due to a top-level semicolon, an action override, or a parse error
    158       // skipping something.
    159       if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
    160         return;
    161     } while (!P.ParseTopLevelDecl(ADecl));
    162   }
    163 
    164   // Process any TopLevelDecls generated by #pragma weak.
    165   for (Decl *D : S.WeakTopLevelDecls())
    166     Consumer->HandleTopLevelDecl(DeclGroupRef(D));
    167 
    168   Consumer->HandleTranslationUnit(S.getASTContext());
    169 
    170   std::swap(OldCollectStats, S.CollectStats);
    171   if (PrintStats) {
    172     llvm::errs() << "\nSTATISTICS:\n";
    173     P.getActions().PrintStats();
    174     S.getASTContext().PrintStats();
    175     Decl::PrintStats();
    176     Stmt::PrintStats();
    177     Consumer->PrintStats();
    178   }
    179 }
    180