llvm-project/clang/lib/Parse/ParseAST.cpp

190 lines
6.7 KiB
C++
Raw Normal View History

//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the clang::ParseAST method.
//
//===----------------------------------------------------------------------===//
#include "clang/Parse/ParseAST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaConsumer.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/TimeProfiler.h"
#include <cstdio>
#include <memory>
using namespace clang;
namespace {
/// Resets LLVM's pretty stack state so that stack traces are printed correctly
/// when there are nested CrashRecoveryContexts and the inner one recovers from
/// a crash.
class ResetStackCleanup
: public llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup,
const void> {
public:
ResetStackCleanup(llvm::CrashRecoveryContext *Context, const void *Top)
: llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, const void>(
Context, Top) {}
void recoverResources() override {
llvm::RestorePrettyStackState(resource);
}
};
/// If a crash happens while the parser is active, an entry is printed for it.
class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
const Parser &P;
public:
PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
void print(raw_ostream &OS) const override;
};
/// If a crash happens while the parser is active, print out a line indicating
/// what the current token is.
void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
const Token &Tok = P.getCurToken();
if (Tok.is(tok::eof)) {
OS << "<eof> parser at end of file\n";
return;
}
if (Tok.getLocation().isInvalid()) {
OS << "<unknown> parser at unknown location\n";
return;
}
const Preprocessor &PP = P.getPreprocessor();
Tok.getLocation().print(OS, PP.getSourceManager());
if (Tok.isAnnotation()) {
OS << ": at annotation token\n";
} else {
// Do the equivalent of PP.getSpelling(Tok) except for the parts that would
// allocate memory.
bool Invalid = false;
const SourceManager &SM = P.getPreprocessor().getSourceManager();
unsigned Length = Tok.getLength();
const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid);
if (Invalid) {
OS << ": unknown current parser token\n";
return;
}
OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n";
}
}
} // namespace
//===----------------------------------------------------------------------===//
// Public interface to the file
//===----------------------------------------------------------------------===//
/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as
/// the file is parsed. This inserts the parsed decls into the translation unit
/// held by Ctx.
///
void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
ASTContext &Ctx, bool PrintStats,
TranslationUnitKind TUKind,
CodeCompleteConsumer *CompletionConsumer,
bool SkipFunctionBodies) {
std::unique_ptr<Sema> S(
new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
}
void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
// Collect global stats on Decls/Stmts (until we have a module streamer).
if (PrintStats) {
Decl::EnableStatistics();
Stmt::EnableStatistics();
}
Build up statistics about the work done for analysis based warnings. Special detail is added for uninitialized variable analysis as this has serious performance problems than need to be tracked. Computing some of this data is expensive, for example walking the CFG to determine its size. To avoid doing that unless the stats data is going to be used, we thread a bit into the Sema object to track whether detailed stats should be collected or not. This bit is used to avoid computations whereever the computations are likely to be more expensive than checking the state of the flag. Thus, counters are in some cases unconditionally updated, but the more expensive (and less frequent) aggregation steps are skipped. With this patch, we're able to see that for 'gcc.c': *** Analysis Based Warnings Stats: 232 functions analyzed (0 w/o CFGs). 7151 CFG blocks built. 30 average CFG blocks per function. 1167 max CFG blocks per function. 163 functions analyzed for uninitialiazed variables 640 variables analyzed. 3 average variables per function. 94 max variables per function. 96409 block visits. 591 average block visits per function. 61546 max block visits per function. And for the reduced testcase in PR10183: *** Analysis Based Warnings Stats: 98 functions analyzed (0 w/o CFGs). 8526 CFG blocks built. 87 average CFG blocks per function. 7277 max CFG blocks per function. 68 functions analyzed for uninitialiazed variables 1359 variables analyzed. 19 average variables per function. 1196 max variables per function. 2540494 block visits. 37360 average block visits per function. 2536495 max block visits per function. That last number is the somewhat scary one that indicates the problem in PR10183. llvm-svn: 134494
2011-07-07 00:21:37 +08:00
// Also turn on collection of stats inside of the Sema object.
bool OldCollectStats = PrintStats;
std::swap(OldCollectStats, S.CollectStats);
// Initialize the template instantiation observer chain.
// FIXME: See note on "finalize" below.
initialize(S.TemplateInstCallbacks, S);
ASTConsumer *Consumer = &S.getASTConsumer();
std::unique_ptr<Parser> ParseOP(
new Parser(S.getPreprocessor(), S, SkipFunctionBodies));
Parser &P = *ParseOP.get();
llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup>
CleanupPrettyStack(llvm::SavePrettyStackState());
PrettyStackTraceParserEntry CrashInfo(P);
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<Parser>
CleanupParser(ParseOP.get());
S.getPreprocessor().EnterMainSourceFile();
ExternalASTSource *External = S.getASTContext().getExternalSource();
if (External)
External->StartTranslationUnit(Consumer);
// If a PCH through header is specified that does not have an include in
// the source, or a PCH is being created with #pragma hdrstop with nothing
// after the pragma, there won't be any tokens or a Lexer.
bool HaveLexer = S.getPreprocessor().getCurrentLexer();
if (HaveLexer) {
llvm::TimeTraceScope TimeScope("Frontend", StringRef(""));
P.Initialize();
Parser::DeclGroupPtrTy ADecl;
for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
AtEOF = P.ParseTopLevelDecl(ADecl)) {
// If we got a null return and something *was* parsed, ignore it. This
// is due to a top-level semicolon, an action override, or a parse error
// skipping something.
if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
return;
}
}
// Process any TopLevelDecls generated by #pragma weak.
for (Decl *D : S.WeakTopLevelDecls())
Consumer->HandleTopLevelDecl(DeclGroupRef(D));
Consumer->HandleTranslationUnit(S.getASTContext());
Build up statistics about the work done for analysis based warnings. Special detail is added for uninitialized variable analysis as this has serious performance problems than need to be tracked. Computing some of this data is expensive, for example walking the CFG to determine its size. To avoid doing that unless the stats data is going to be used, we thread a bit into the Sema object to track whether detailed stats should be collected or not. This bit is used to avoid computations whereever the computations are likely to be more expensive than checking the state of the flag. Thus, counters are in some cases unconditionally updated, but the more expensive (and less frequent) aggregation steps are skipped. With this patch, we're able to see that for 'gcc.c': *** Analysis Based Warnings Stats: 232 functions analyzed (0 w/o CFGs). 7151 CFG blocks built. 30 average CFG blocks per function. 1167 max CFG blocks per function. 163 functions analyzed for uninitialiazed variables 640 variables analyzed. 3 average variables per function. 94 max variables per function. 96409 block visits. 591 average block visits per function. 61546 max block visits per function. And for the reduced testcase in PR10183: *** Analysis Based Warnings Stats: 98 functions analyzed (0 w/o CFGs). 8526 CFG blocks built. 87 average CFG blocks per function. 7277 max CFG blocks per function. 68 functions analyzed for uninitialiazed variables 1359 variables analyzed. 19 average variables per function. 1196 max variables per function. 2540494 block visits. 37360 average block visits per function. 2536495 max block visits per function. That last number is the somewhat scary one that indicates the problem in PR10183. llvm-svn: 134494
2011-07-07 00:21:37 +08:00
// Finalize the template instantiation observer chain.
// FIXME: This (and init.) should be done in the Sema class, but because
// Sema does not have a reliable "Finalize" function (it has a
// destructor, but it is not guaranteed to be called ("-disable-free")).
// So, do the initialization above and do the finalization here:
finalize(S.TemplateInstCallbacks, S);
Build up statistics about the work done for analysis based warnings. Special detail is added for uninitialized variable analysis as this has serious performance problems than need to be tracked. Computing some of this data is expensive, for example walking the CFG to determine its size. To avoid doing that unless the stats data is going to be used, we thread a bit into the Sema object to track whether detailed stats should be collected or not. This bit is used to avoid computations whereever the computations are likely to be more expensive than checking the state of the flag. Thus, counters are in some cases unconditionally updated, but the more expensive (and less frequent) aggregation steps are skipped. With this patch, we're able to see that for 'gcc.c': *** Analysis Based Warnings Stats: 232 functions analyzed (0 w/o CFGs). 7151 CFG blocks built. 30 average CFG blocks per function. 1167 max CFG blocks per function. 163 functions analyzed for uninitialiazed variables 640 variables analyzed. 3 average variables per function. 94 max variables per function. 96409 block visits. 591 average block visits per function. 61546 max block visits per function. And for the reduced testcase in PR10183: *** Analysis Based Warnings Stats: 98 functions analyzed (0 w/o CFGs). 8526 CFG blocks built. 87 average CFG blocks per function. 7277 max CFG blocks per function. 68 functions analyzed for uninitialiazed variables 1359 variables analyzed. 19 average variables per function. 1196 max variables per function. 2540494 block visits. 37360 average block visits per function. 2536495 max block visits per function. That last number is the somewhat scary one that indicates the problem in PR10183. llvm-svn: 134494
2011-07-07 00:21:37 +08:00
std::swap(OldCollectStats, S.CollectStats);
if (PrintStats) {
llvm::errs() << "\nSTATISTICS:\n";
if (HaveLexer) P.getActions().PrintStats();
S.getASTContext().PrintStats();
Decl::PrintStats();
Stmt::PrintStats();
Consumer->PrintStats();
}
}