1212795Sdim//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===//
2212795Sdim//
3212795Sdim//                     The LLVM Compiler Infrastructure
4212795Sdim//
5212795Sdim// This file is distributed under the University of Illinois Open Source
6212795Sdim// License. See LICENSE.TXT for details.
7212795Sdim//
8212795Sdim//===----------------------------------------------------------------------===//
9212795Sdim//
10212795Sdim// This file implements the clang::ParseAST method.
11212795Sdim//
12212795Sdim//===----------------------------------------------------------------------===//
13212795Sdim
14212795Sdim#include "clang/Parse/ParseAST.h"
15212795Sdim#include "clang/AST/ASTConsumer.h"
16245431Sdim#include "clang/AST/ASTContext.h"
17212795Sdim#include "clang/AST/DeclCXX.h"
18212795Sdim#include "clang/AST/ExternalASTSource.h"
19212795Sdim#include "clang/AST/Stmt.h"
20252723Sdim#include "clang/Parse/ParseDiagnostic.h"
21212795Sdim#include "clang/Parse/Parser.h"
22252723Sdim#include "clang/Sema/CodeCompleteConsumer.h"
23252723Sdim#include "clang/Sema/ExternalSemaSource.h"
24252723Sdim#include "clang/Sema/Sema.h"
25252723Sdim#include "clang/Sema/SemaConsumer.h"
26221345Sdim#include "llvm/ADT/OwningPtr.h"
27221345Sdim#include "llvm/Support/CrashRecoveryContext.h"
28212795Sdim#include <cstdio>
29212795Sdim
30212795Sdimusing namespace clang;
31212795Sdim
32252723Sdimnamespace {
33252723Sdim
34252723Sdim/// If a crash happens while the parser is active, an entry is printed for it.
35252723Sdimclass PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
36252723Sdim  const Parser &P;
37252723Sdimpublic:
38252723Sdim  PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
39252723Sdim  virtual void print(raw_ostream &OS) const;
40252723Sdim};
41252723Sdim
42252723Sdim/// If a crash happens while the parser is active, print out a line indicating
43252723Sdim/// what the current token is.
44252723Sdimvoid PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
45252723Sdim  const Token &Tok = P.getCurToken();
46252723Sdim  if (Tok.is(tok::eof)) {
47252723Sdim    OS << "<eof> parser at end of file\n";
48252723Sdim    return;
49252723Sdim  }
50252723Sdim
51252723Sdim  if (Tok.getLocation().isInvalid()) {
52252723Sdim    OS << "<unknown> parser at unknown location\n";
53252723Sdim    return;
54252723Sdim  }
55252723Sdim
56252723Sdim  const Preprocessor &PP = P.getPreprocessor();
57252723Sdim  Tok.getLocation().print(OS, PP.getSourceManager());
58252723Sdim  if (Tok.isAnnotation()) {
59252723Sdim    OS << ": at annotation token\n";
60252723Sdim  } else {
61252723Sdim    // Do the equivalent of PP.getSpelling(Tok) except for the parts that would
62252723Sdim    // allocate memory.
63252723Sdim    bool Invalid = false;
64252723Sdim    const SourceManager &SM = P.getPreprocessor().getSourceManager();
65252723Sdim    unsigned Length = Tok.getLength();
66252723Sdim    const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid);
67252723Sdim    if (Invalid) {
68252723Sdim      OS << ": unknown current parser token\n";
69252723Sdim      return;
70252723Sdim    }
71252723Sdim    OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n";
72252723Sdim  }
73252723Sdim}
74252723Sdim
75252723Sdim}  // namespace
76252723Sdim
77212795Sdim//===----------------------------------------------------------------------===//
78212795Sdim// Public interface to the file
79212795Sdim//===----------------------------------------------------------------------===//
80212795Sdim
81212795Sdim/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as
82212795Sdim/// the file is parsed.  This inserts the parsed decls into the translation unit
83212795Sdim/// held by Ctx.
84212795Sdim///
85212795Sdimvoid clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
86212795Sdim                     ASTContext &Ctx, bool PrintStats,
87226890Sdim                     TranslationUnitKind TUKind,
88235633Sdim                     CodeCompleteConsumer *CompletionConsumer,
89235633Sdim                     bool SkipFunctionBodies) {
90221345Sdim
91252723Sdim  OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
92221345Sdim
93221345Sdim  // Recover resources if we crash before exiting this method.
94235633Sdim  llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
95221345Sdim
96235633Sdim  ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
97212795Sdim}
98212795Sdim
99235633Sdimvoid clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
100212795Sdim  // Collect global stats on Decls/Stmts (until we have a module streamer).
101212795Sdim  if (PrintStats) {
102235633Sdim    Decl::EnableStatistics();
103235633Sdim    Stmt::EnableStatistics();
104212795Sdim  }
105212795Sdim
106224145Sdim  // Also turn on collection of stats inside of the Sema object.
107224145Sdim  bool OldCollectStats = PrintStats;
108224145Sdim  std::swap(OldCollectStats, S.CollectStats);
109224145Sdim
110212795Sdim  ASTConsumer *Consumer = &S.getASTConsumer();
111212795Sdim
112235633Sdim  OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
113235633Sdim                                       SkipFunctionBodies));
114221345Sdim  Parser &P = *ParseOP.get();
115221345Sdim
116221345Sdim  PrettyStackTraceParserEntry CrashInfo(P);
117221345Sdim
118221345Sdim  // Recover resources if we crash before exiting this method.
119221345Sdim  llvm::CrashRecoveryContextCleanupRegistrar<Parser>
120235633Sdim    CleanupParser(ParseOP.get());
121221345Sdim
122212795Sdim  S.getPreprocessor().EnterMainSourceFile();
123212795Sdim  P.Initialize();
124245431Sdim
125245431Sdim  // C11 6.9p1 says translation units must have at least one top-level
126245431Sdim  // declaration. C++ doesn't have this restriction. We also don't want to
127245431Sdim  // complain if we have a precompiled header, although technically if the PCH
128245431Sdim  // is empty we should still emit the (pedantic) diagnostic.
129245431Sdim  Parser::DeclGroupPtrTy ADecl;
130245431Sdim  ExternalASTSource *External = S.getASTContext().getExternalSource();
131245431Sdim  if (External)
132212795Sdim    External->StartTranslationUnit(Consumer);
133235633Sdim
134245431Sdim  if (P.ParseTopLevelDecl(ADecl)) {
135245431Sdim    if (!External && !S.getLangOpts().CPlusPlus)
136245431Sdim      P.Diag(diag::ext_empty_translation_unit);
137245431Sdim  } else {
138245431Sdim    do {
139245431Sdim      // If we got a null return and something *was* parsed, ignore it.  This
140245431Sdim      // is due to a top-level semicolon, an action override, or a parse error
141245431Sdim      // skipping something.
142245431Sdim      if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
143252723Sdim        return;
144245431Sdim    } while (!P.ParseTopLevelDecl(ADecl));
145245431Sdim  }
146245431Sdim
147212795Sdim  // Process any TopLevelDecls generated by #pragma weak.
148263509Sdim  for (SmallVectorImpl<Decl *>::iterator
149212795Sdim       I = S.WeakTopLevelDecls().begin(),
150212795Sdim       E = S.WeakTopLevelDecls().end(); I != E; ++I)
151212795Sdim    Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
152212795Sdim
153212795Sdim  Consumer->HandleTranslationUnit(S.getASTContext());
154224145Sdim
155224145Sdim  std::swap(OldCollectStats, S.CollectStats);
156212795Sdim  if (PrintStats) {
157224145Sdim    llvm::errs() << "\nSTATISTICS:\n";
158212795Sdim    P.getActions().PrintStats();
159212795Sdim    S.getASTContext().PrintStats();
160212795Sdim    Decl::PrintStats();
161212795Sdim    Stmt::PrintStats();
162212795Sdim    Consumer->PrintStats();
163212795Sdim  }
164212795Sdim}
165