36 #include "llvm/ADT/PostOrderIterator.h" 37 #include "llvm/ADT/Statistic.h" 38 #include "llvm/Support/FileSystem.h" 39 #include "llvm/Support/Path.h" 40 #include "llvm/Support/Program.h" 41 #include "llvm/Support/Timer.h" 42 #include "llvm/Support/raw_ostream.h" 47 using namespace clang;
50 #define DEBUG_TYPE "AnalysisConsumer" 52 STATISTIC(NumFunctionTopLevel,
"The # of functions at top level.");
54 "The # of functions and blocks analyzed (as top level " 55 "with inlining turned on).");
57 "The # of basic blocks in the analyzed functions.");
58 STATISTIC(NumVisitedBlocksInAnalyzedFunctions,
59 "The # of visited basic blocks in the analyzed functions.");
60 STATISTIC(PercentReachableBlocks,
"The % of reachable basic blocks.");
61 STATISTIC(MaxCFGSize,
"The maximum number of basic blocks in a function.");
67 void ento::createPlistHTMLDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
69 const std::string &prefix,
71 createHTMLDiagnosticConsumer(AnalyzerOpts, C,
72 llvm::sys::path::parent_path(prefix), PP);
73 createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
76 void ento::createTextPathDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
78 const std::string &Prefix,
80 llvm_unreachable(
"'text' consumer should be enabled on ClangDiags");
84 class ClangDiagPathDiagConsumer :
public PathDiagnosticConsumer {
86 bool IncludePath, ShouldEmitAsError;
90 : Diag(Diag), IncludePath(
false), ShouldEmitAsError(
false) {}
91 ~ClangDiagPathDiagConsumer()
override {}
92 StringRef
getName()
const override {
return "ClangDiags"; }
94 bool supportsLogicalOpControlFlow()
const override {
return true; }
95 bool supportsCrossFileDiagnostics()
const override {
return true; }
97 PathGenerationScheme getGenerationScheme()
const override {
98 return IncludePath ?
Minimal : None;
105 void enableWerror() { ShouldEmitAsError =
true; }
107 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
108 FilesMade *filesMade)
override {
115 for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
116 E = Diags.end(); I != E; ++I) {
117 const PathDiagnostic *PD = *I;
119 Diag.
Report(WarnLoc, WarnID) << PD->getShortDescription()
120 << PD->path.back()->getRanges();
123 for (
const auto &Piece : PD->path) {
124 if (!isa<PathDiagnosticNotePiece>(Piece.get()))
128 Diag.
Report(NoteLoc, NoteID) << Piece->getString()
129 << Piece->getRanges();
136 PathPieces FlatPath = PD->path.flatten(
true);
137 for (
const auto &Piece : FlatPath) {
138 if (isa<PathDiagnosticNotePiece>(Piece.get()))
142 Diag.
Report(NoteLoc, NoteID) << Piece->getString()
143 << Piece->getRanges();
156 class AnalysisConsumer :
public AnalysisASTConsumer,
163 typedef unsigned AnalysisMode;
166 AnalysisMode RecVisitorMode;
168 BugReporter *RecVisitorBR;
170 std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns;
175 const std::string OutDir;
194 std::unique_ptr<CheckerManager> checkerMgr;
195 std::unique_ptr<AnalysisManager> Mgr;
198 std::unique_ptr<llvm::TimerGroup> AnalyzerTimers;
199 std::unique_ptr<llvm::Timer> SyntaxCheckTimer;
200 std::unique_ptr<llvm::Timer> ExprEngineTimer;
201 std::unique_ptr<llvm::Timer> BugReporterTimer;
205 FunctionSummariesTy FunctionSummaries;
210 : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),
211 PP(CI.getPreprocessor()), OutDir(outdir), Opts(
std::move(opts)),
212 Plugins(plugins), Injector(injector), CTU(CI) {
213 DigestAnalyzerOptions();
214 if (Opts->PrintStats || Opts->ShouldSerializeStats) {
215 AnalyzerTimers = llvm::make_unique<llvm::TimerGroup>(
216 "analyzer",
"Analyzer timers");
217 SyntaxCheckTimer = llvm::make_unique<llvm::Timer>(
218 "syntaxchecks",
"Syntax-based analysis time", *AnalyzerTimers);
219 ExprEngineTimer = llvm::make_unique<llvm::Timer>(
220 "exprengine",
"Path exploration time", *AnalyzerTimers);
221 BugReporterTimer = llvm::make_unique<llvm::Timer>(
222 "bugreporter",
"Path-sensitive report post-processing time",
224 llvm::EnableStatistics(
false);
228 ~AnalysisConsumer()
override {
229 if (Opts->PrintStats) {
230 llvm::PrintStatistics();
234 void DigestAnalyzerOptions() {
235 if (Opts->AnalysisDiagOpt !=
PD_NONE) {
237 ClangDiagPathDiagConsumer *clangDiags =
239 PathConsumers.push_back(clangDiags);
241 if (Opts->AnalyzerWerror)
242 clangDiags->enableWerror();
244 if (Opts->AnalysisDiagOpt == PD_TEXT) {
245 clangDiags->enablePaths();
247 }
else if (!OutDir.empty()) {
248 switch (Opts->AnalysisDiagOpt) {
250 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ 252 CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \ 254 #include "clang/StaticAnalyzer/Core/Analyses.def" 260 switch (Opts->AnalysisStoreOpt) {
262 llvm_unreachable(
"Unknown store manager.");
263 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ 264 case NAME##Model: CreateStoreMgr = CREATEFN; break; 265 #include "clang/StaticAnalyzer/Core/Analyses.def" 268 switch (Opts->AnalysisConstraintsOpt) {
270 llvm_unreachable(
"Unknown constraint manager.");
271 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ 272 case NAME##Model: CreateConstraintMgr = CREATEFN; break; 273 #include "clang/StaticAnalyzer/Core/Analyses.def" 277 void DisplayFunction(
const Decl *D, AnalysisMode Mode,
279 if (!Opts->AnalyzerDisplayProgress)
285 llvm::errs() <<
"ANALYZE";
287 if (Mode == AM_Syntax)
288 llvm::errs() <<
" (Syntax)";
289 else if (Mode == AM_Path) {
290 llvm::errs() <<
" (Path, ";
293 llvm::errs() <<
" Inline_Minimal";
296 llvm::errs() <<
" Inline_Regular";
302 assert(Mode == (AM_Syntax | AM_Path) &&
"Unexpected mode!");
305 << getFunctionName(D) <<
'\n';
309 void Initialize(
ASTContext &Context)
override {
312 *Ctx, *Opts, Plugins, CheckerRegistrationFns, PP.
getDiagnostics());
314 Mgr = llvm::make_unique<AnalysisManager>(
316 CreateConstraintMgr, checkerMgr.get(), *Opts, Injector);
322 void HandleTopLevelDeclInObjCContainer(
DeclGroupRef D)
override;
324 void HandleTranslationUnit(
ASTContext &C)
override;
334 void HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize);
342 void HandleCode(
Decl *D, AnalysisMode Mode,
346 void RunPathSensitiveChecks(
Decl *D,
351 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
354 bool VisitDecl(
Decl *D) {
355 AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
356 if (Mode & AM_Syntax) {
357 if (SyntaxCheckTimer)
358 SyntaxCheckTimer->startTimer();
359 checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
360 if (SyntaxCheckTimer)
361 SyntaxCheckTimer->stopTimer();
366 bool VisitVarDecl(
VarDecl *VD) {
367 if (!Opts->IsNaiveCTUEnabled)
383 Opts->DisplayCTUProgress);
385 if (!CTUDeclOrError) {
386 handleAllErrors(CTUDeclOrError.takeError(),
397 if (II && II->
getName().startswith(
"__inline"))
404 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
405 HandleCode(FD, RecVisitorMode);
412 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
413 HandleCode(MD, RecVisitorMode);
420 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
424 HandleCode(BD, RecVisitorMode);
430 void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer)
override {
431 PathConsumers.push_back(Consumer);
434 void AddCheckerRegistrationFn(std::function<
void(CheckerRegistry&)> Fn)
override {
435 CheckerRegistrationFns.push_back(std::move(Fn));
440 std::string getFunctionName(
const Decl *D);
443 AnalysisMode getModeForDecl(
Decl *D, AnalysisMode Mode);
444 void runAnalysisOnTranslationUnit(
ASTContext &C);
447 void reportAnalyzerProgress(StringRef S);
455 bool AnalysisConsumer::HandleTopLevelDecl(
DeclGroupRef DG) {
456 storeTopLevelDecls(DG);
460 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(
DeclGroupRef DG) {
461 storeTopLevelDecls(DG);
464 void AnalysisConsumer::storeTopLevelDecls(
DeclGroupRef DG) {
469 if (isa<ObjCMethodDecl>(*I))
472 LocalTUDecls.push_back(*I);
479 if (VisitedAsTopLevel.count(D))
489 if (isa<ObjCMethodDecl>(D))
494 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
495 if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())
500 return Visited.count(D);
504 AnalysisConsumer::getInliningModeForFunction(
const Decl *D,
509 if (Visited.count(D) && isa<ObjCMethodDecl>(D)) {
518 void AnalysisConsumer::HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize) {
524 for (
unsigned i = 0 ;
i < LocalTUDeclsSize ; ++
i) {
536 llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
537 for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator
538 I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
539 NumFunctionTopLevel++;
556 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
557 (Mgr->options.InliningMode == All ?
nullptr : &VisitedCallees));
560 for (
const Decl *Callee : VisitedCallees)
563 Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
564 : Callee->getCanonicalDecl());
565 VisitedAsTopLevel.insert(D);
572 StringRef Buffer = SM.
getBuffer(FID)->getBuffer();
573 if (Buffer.startswith(
"/* A Bison parser, made by"))
578 void AnalysisConsumer::runAnalysisOnTranslationUnit(
ASTContext &C) {
579 BugReporter BR(*Mgr);
581 if (SyntaxCheckTimer)
582 SyntaxCheckTimer->startTimer();
583 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
584 if (SyntaxCheckTimer)
585 SyntaxCheckTimer->stopTimer();
590 RecVisitorMode = AM_Syntax;
591 if (!Mgr->shouldInlineCall())
592 RecVisitorMode |= AM_Path;
601 const unsigned LocalTUDeclsSize = LocalTUDecls.size();
602 for (
unsigned i = 0 ;
i < LocalTUDeclsSize ; ++
i) {
603 TraverseDecl(LocalTUDecls[
i]);
606 if (Mgr->shouldInlineCall())
607 HandleDeclsCallGraph(LocalTUDeclsSize);
610 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
612 RecVisitorBR =
nullptr;
615 void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {
616 if (Opts->AnalyzerDisplayProgress)
620 void AnalysisConsumer::HandleTranslationUnit(
ASTContext &C) {
628 reportAnalyzerProgress(
"Skipping bison-generated file\n");
629 }
else if (Opts->DisableAllChecks) {
633 reportAnalyzerProgress(
"All checks are disabled using a supplied option\n");
636 runAnalysisOnTranslationUnit(C);
640 NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
641 NumVisitedBlocksInAnalyzedFunctions =
642 FunctionSummaries.getTotalNumVisitedBasicBlocks();
643 if (NumBlocksInAnalyzedFunctions > 0)
644 PercentReachableBlocks =
645 (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
646 NumBlocksInAnalyzedFunctions;
655 std::string AnalysisConsumer::getFunctionName(
const Decl *D) {
657 llvm::raw_string_ostream
OS(Str);
659 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
663 if (Ctx->getLangOpts().CPlusPlus) {
668 OS <<
P->getType().getAsString();
673 }
else if (isa<BlockDecl>(D)) {
681 }
else if (
const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
684 OS << (OMD->isInstanceMethod() ?
'-' :
'+') <<
'[';
686 if (
const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) {
687 OS << OID->getName();
688 }
else if (
const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) {
689 OS << OID->getName();
690 }
else if (
const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) {
691 if (OC->IsClassExtension()) {
692 OS << OC->getClassInterface()->getName();
694 OS << OC->getIdentifier()->getNameStart() <<
'(' 695 << OC->getIdentifier()->getNameStart() <<
')';
697 }
else if (
const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
698 OS << OCD->getClassInterface()->getName() <<
'(' 699 << OCD->getName() <<
')';
700 }
else if (isa<ObjCProtocolDecl>(DC)) {
704 cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
708 OS <<
' ' << OMD->getSelector().getAsString() <<
']';
715 AnalysisConsumer::AnalysisMode
716 AnalysisConsumer::getModeForDecl(
Decl *D, AnalysisMode Mode) {
717 if (!Opts->AnalyzeSpecificFunction.empty() &&
718 getFunctionName(D) != Opts->AnalyzeSpecificFunction)
731 if (!Opts->AnalyzeAll && !Mgr->isInCodeFile(SL)) {
734 return Mode & ~AM_Path;
740 void AnalysisConsumer::HandleCode(
Decl *D, AnalysisMode Mode,
745 Mode = getModeForDecl(D, Mode);
750 Mgr->ClearContexts();
752 if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized())
755 DisplayFunction(D, Mode, IMode);
756 CFG *DeclCFG = Mgr->getCFG(D);
758 MaxCFGSize.updateMax(DeclCFG->
size());
760 BugReporter BR(*Mgr);
762 if (Mode & AM_Syntax) {
763 if (SyntaxCheckTimer)
764 SyntaxCheckTimer->startTimer();
765 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
766 if (SyntaxCheckTimer)
767 SyntaxCheckTimer->stopTimer();
769 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
770 RunPathSensitiveChecks(D, IMode, VisitedCallees);
772 NumFunctionsAnalyzed++;
780 void AnalysisConsumer::RunPathSensitiveChecks(
Decl *D,
792 ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
796 ExprEngineTimer->startTimer();
797 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
798 Mgr->options.MaxNodesPerTopLevelFunction);
800 ExprEngineTimer->stopTimer();
802 if (!Mgr->options.DumpExplodedGraphTo.empty())
803 Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);
806 if (Mgr->options.visualizeExplodedGraphWithGraphViz)
807 Eng.ViewGraph(Mgr->options.TrimGraph);
810 if (BugReporterTimer)
811 BugReporterTimer->startTimer();
812 Eng.getBugReporter().FlushReports();
813 if (BugReporterTimer)
814 BugReporterTimer->stopTimer();
821 std::unique_ptr<AnalysisASTConsumer>
827 bool hasModelPath = analyzerOpts->Config.count(
"model-path") > 0;
829 return llvm::make_unique<AnalysisConsumer>(
831 CI.getFrontendOpts().Plugins,
The AST-based call graph.
std::string OutputFile
The output file, if any.
Represents a function declaration or definition.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
bool isThisDeclarationADefinition() const
Returns whether this specific method is a definition.
bool hasErrorOccurred() const
A (possibly-)qualified type.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Stmt - This represents one statement.
unsigned size() const
Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to...
std::unique_ptr< CheckerManager > createCheckerManager(ASTContext &context, AnalyzerOptions &opts, ArrayRef< std::string > plugins, ArrayRef< std::function< void(CheckerRegistry &)>> checkerRegistrationFns, DiagnosticsEngine &diags)
Represents a variable declaration or definition.
ObjCMethodDecl - Represents an instance or class method declaration.
Describes how types, statements, expressions, and declarations should be printed. ...
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
One of these records is kept for each identifier that is lexed.
Follow the default settings for inlining callees.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Defines the clang::CodeInjector interface which is responsible for injecting AST of function definiti...
SourceLocation getBeginLoc() const LLVM_READONLY
std::unique_ptr< StoreManager >(* StoreManagerCreator)(ProgramStateManager &)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
ArrayRef< ParmVarDecl * > parameters() const
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
FrontendOptions & getFrontendOpts()
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
Concrete class used by the front-end to report problems and issues.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
AnalyzerOptionsRef getAnalyzerOpts()
param_iterator param_begin()
llvm::DenseSet< const Decl * > SetOfConstDecls
bool containsConst(const VarDecl *VD, const ASTContext &ACtx)
std::unique_ptr< ConstraintManager >(* ConstraintManagerCreator)(ProgramStateManager &, SubEngine *)
static bool shouldSkipFunction(const Decl *D, const SetOfConstDecls &Visited, const SetOfConstDecls &VisitedAsTopLevel)
InliningModes
The modes of inlining, which override the default analysis-wide settings.
Represents a block literal declaration, which is like an unnamed FunctionDecl.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
unsigned getLine() const
Return the presumed line number of this location.
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
Defines the clang::Preprocessor interface.
This file defines the clang::ento::ModelInjector class which implements the clang::CodeInjector inter...
Represents an unpacked "presumed" location which can be presented to the user.
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
const char * getFilename() const
Return the presumed filename of this location.
unsigned getColumn() const
Return the presumed column number of this location.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Encodes a location in the source.
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.")
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
Do minimal inlining of callees.
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
StringRef getName() const
Return the actual identifier string.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
const llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
Dataflow Directional Tag Classes.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
static std::string getName(const CallEvent &Call)
CodeInjector is an interface which is responsible for injecting AST of function definitions that may ...
FileID getMainFileID() const
Returns the FileID of the main source file.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.
This class is used for tools that requires cross translation unit capability.
std::unique_ptr< AnalysisASTConsumer > CreateAnalysisConsumer(CompilerInstance &CI)
CreateAnalysisConsumer - Creates an ASTConsumer to run various code analysis passes.
void setWarningsAsErrors(bool Val)
When set to true, any warnings reported are issued as errors.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
Stores options for the analyzer from the command line.
SourceManager & getSourceManager()
llvm::Expected< const FunctionDecl * > getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress=false)
This function loads a function or variable definition from an external AST file and merges it into th...
bool hasFatalErrorOccurred() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
static bool isBisonFile(ASTContext &C)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
TranslationUnitDecl * getTranslationUnitDecl() const
DiagnosticsEngine & getDiagnostics() const
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
void emitCrossTUDiagnostics(const IndexError &IE)
Emit diagnostics for the user for potential configuration errors.
void addToCallGraph(Decl *D)
Populate the call graph with the functions in the given declaration.
std::string getQualifiedNameAsString() const
The top declaration context.
bool isStaticDataMember() const
Determines whether this is a static data member.
std::deque< Decl * > SetOfDecls
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Engages in a tight little dance with the lexer to efficiently preprocess tokens.