зеркало из https://github.com/microsoft/clang.git
Added AnalysisConsumer, a meta-level ASTConsumer class to drive various
analyses. This potentially is the primordial origins of a Clang-equivalent "PassManager". The new AnalysisConsumer interface allows multiple analyses to be run from a single invocation of Clang. Migrated the logic of "-warn-dead-stores" and "-warn-uninit-values" to use the new AnalysisConsumer interface. The new interface results in a significant code reduction to incorporate an analysis into the Driver. Updated a test case to (correctly) acknowledge that it contains a dead store (this check wasn't being performed because it was previously masked by -warn-uninit-values). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52996 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
91d1a14be8
Коммит
f4381fddf1
|
@ -634,58 +634,6 @@ ASTConsumer *clang::CreateLiveVarAnalyzer(const std::string& fname) {
|
|||
return new LivenessVisitor(fname);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DeadStores - run checker to locate dead stores in a function
|
||||
|
||||
namespace {
|
||||
class DeadStoreVisitor : public CFGVisitor {
|
||||
Diagnostic &Diags;
|
||||
ASTContext *Ctx;
|
||||
public:
|
||||
DeadStoreVisitor(Diagnostic &diags) : Diags(diags) {}
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
virtual void VisitCFG(CFG& C, Decl& CD) {
|
||||
llvm::OwningPtr<ParentMap> PM(new ParentMap(CD.getCodeBody()));
|
||||
CheckDeadStores(C, *Ctx, *PM, Diags);
|
||||
}
|
||||
|
||||
virtual bool printFuncDeclStart() { return false; }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateDeadStoreChecker(Diagnostic &Diags) {
|
||||
return new DeadStoreVisitor(Diags);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Unitialized Values - run checker to flag potential uses of uninitalized
|
||||
// variables.
|
||||
|
||||
namespace {
|
||||
class UninitValsVisitor : public CFGVisitor {
|
||||
Diagnostic &Diags;
|
||||
ASTContext *Ctx;
|
||||
public:
|
||||
UninitValsVisitor(Diagnostic &diags) : Diags(diags) {}
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
virtual void VisitCFG(CFG& C, Decl&) {
|
||||
CheckUninitializedValues(C, *Ctx, Diags);
|
||||
}
|
||||
|
||||
virtual bool printFuncDeclStart() { return false; }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateUnitValsChecker(Diagnostic &Diags) {
|
||||
return new UninitValsVisitor(Diags);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CheckerConsumer - Generic Driver for running intra-procedural path-sensitive
|
||||
// analyses.
|
||||
|
|
|
@ -30,7 +30,6 @@ struct LangOptions;
|
|||
class Preprocessor;
|
||||
class PreprocessorFactory;
|
||||
|
||||
|
||||
ASTConsumer *CreateASTPrinter(std::ostream* OS = NULL);
|
||||
|
||||
ASTConsumer *CreateASTDumper();
|
||||
|
@ -41,10 +40,6 @@ ASTConsumer *CreateCFGDumper(bool ViewGraphs, const std::string& FName);
|
|||
|
||||
ASTConsumer *CreateLiveVarAnalyzer(const std::string& fname);
|
||||
|
||||
ASTConsumer *CreateDeadStoreChecker(Diagnostic &Diags);
|
||||
|
||||
ASTConsumer *CreateUnitValsChecker(Diagnostic &Diags);
|
||||
|
||||
ASTConsumer *CreateGRSimpleVals(Diagnostic &Diags,
|
||||
Preprocessor* PP, PreprocessorFactory* PPF,
|
||||
const std::string& Function,
|
||||
|
@ -75,4 +70,6 @@ ASTConsumer *CreateASTSerializer(const std::string& InFile,
|
|||
|
||||
} // end clang namespace
|
||||
|
||||
#include "AnalysisConsumer.h"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// "Meta" ASTConsumer for running different source analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ASTConsumers.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/ADT/ImmutableList.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Basic type definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
class AnalysisManager;
|
||||
typedef void (*CodeAction)(AnalysisManager& Mgr);
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AnalysisConsumer declaration.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
|
||||
typedef llvm::ImmutableList<CodeAction> Actions;
|
||||
Actions FunctionActions;
|
||||
Actions ObjCMethodActions;
|
||||
|
||||
Actions::Factory F;
|
||||
|
||||
public:
|
||||
const bool Visualize;
|
||||
const bool TrimGraph;
|
||||
const LangOptions& LOpts;
|
||||
Diagnostic &Diags;
|
||||
ASTContext* Ctx;
|
||||
Preprocessor* PP;
|
||||
PreprocessorFactory* PPF;
|
||||
const std::string HTMLDir;
|
||||
const std::string FName;
|
||||
llvm::OwningPtr<PathDiagnosticClient> PD;
|
||||
bool AnalyzeAll;
|
||||
|
||||
AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf,
|
||||
const LangOptions& lopts,
|
||||
const std::string& fname,
|
||||
const std::string& htmldir,
|
||||
bool visualize, bool trim, bool analyzeAll)
|
||||
: FunctionActions(F.GetEmptyList()), ObjCMethodActions(F.GetEmptyList()),
|
||||
Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
|
||||
Ctx(0), PP(pp), PPF(ppf),
|
||||
HTMLDir(htmldir),
|
||||
FName(fname),
|
||||
AnalyzeAll(analyzeAll) {}
|
||||
|
||||
void addCodeAction(CodeAction action) {
|
||||
FunctionActions = F.Concat(action, FunctionActions);
|
||||
ObjCMethodActions = F.Concat(action, ObjCMethodActions);
|
||||
}
|
||||
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D);
|
||||
void HandleCode(Decl* D, Stmt* Body, Actions actions);
|
||||
};
|
||||
|
||||
|
||||
class VISIBILITY_HIDDEN AnalysisManager {
|
||||
Decl* D;
|
||||
Stmt* Body;
|
||||
AnalysisConsumer& C;
|
||||
|
||||
llvm::OwningPtr<CFG> cfg;
|
||||
llvm::OwningPtr<LiveVariables> liveness;
|
||||
llvm::OwningPtr<ParentMap> PM;
|
||||
|
||||
public:
|
||||
AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b)
|
||||
: D(d), Body(b), C(c) {}
|
||||
|
||||
|
||||
Decl* getCodeDecl() const { return D; }
|
||||
Stmt* getBody() const { return Body; }
|
||||
|
||||
CFG* getCFG() {
|
||||
if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
|
||||
return cfg.get();
|
||||
}
|
||||
|
||||
ParentMap* getParentMap() {
|
||||
if (!PM) PM.reset(new ParentMap(getBody()));
|
||||
return PM.get();
|
||||
}
|
||||
|
||||
ASTContext& getContext() {
|
||||
return *C.Ctx;
|
||||
}
|
||||
|
||||
Diagnostic& getDiagnostic() {
|
||||
return C.Diags;
|
||||
}
|
||||
|
||||
LiveVariables* getLiveVariables() {
|
||||
if (!liveness) liveness.reset(new LiveVariables(*getCFG()));
|
||||
return liveness.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
template <> struct FoldingSetTrait<CodeAction> {
|
||||
static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
|
||||
ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AnalysisConsumer implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void AnalysisConsumer::HandleTopLevelDecl(Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
case Decl::Function: {
|
||||
FunctionDecl* FD = cast<FunctionDecl>(D);
|
||||
Stmt* Body = FD->getBody();
|
||||
if (Body) HandleCode(FD, Body, FunctionActions);
|
||||
break;
|
||||
}
|
||||
|
||||
case Decl::ObjCMethod: {
|
||||
ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
|
||||
Stmt* Body = MD->getBody();
|
||||
if (Body) HandleCode(MD, Body, ObjCMethodActions);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions actions) {
|
||||
|
||||
// Don't run the actions if an error has occured with parsing the file.
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
SourceLocation Loc = D->getLocation();
|
||||
|
||||
// Only run actions on declarations defined in actual source.
|
||||
if (!Loc.isFileID())
|
||||
return;
|
||||
|
||||
// Don't run the actions on declarations in header files unless
|
||||
// otherwise specified.
|
||||
if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(Loc))
|
||||
return;
|
||||
|
||||
// Create an AnalysisManager that will manage the state for analyzing
|
||||
// this method/function.
|
||||
AnalysisManager mgr(*this, D, Body);
|
||||
|
||||
// Dispatch on the actions.
|
||||
for (Actions::iterator I = actions.begin(),
|
||||
E = actions.end(); I != E; ++I)
|
||||
((*I).getHead())(mgr);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Analyses
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void ActionDeadStores(AnalysisManager& mgr) {
|
||||
CheckDeadStores(*mgr.getCFG(), mgr.getContext(), *mgr.getParentMap(),
|
||||
mgr.getDiagnostic());
|
||||
}
|
||||
|
||||
static void ActionUninitVals(AnalysisManager& mgr) {
|
||||
CheckUninitializedValues(*mgr.getCFG(), mgr.getContext(),
|
||||
mgr.getDiagnostic());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AnalysisConsumer creation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
|
||||
Diagnostic &diags, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf,
|
||||
const LangOptions& lopts,
|
||||
const std::string& fname,
|
||||
const std::string& htmldir,
|
||||
bool visualize, bool trim,
|
||||
bool analyzeAll) {
|
||||
|
||||
llvm::OwningPtr<AnalysisConsumer>
|
||||
C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir,
|
||||
visualize, trim, analyzeAll));
|
||||
|
||||
for ( ; Beg != End ; ++Beg)
|
||||
switch (*Beg) {
|
||||
case WarnDeadStores:
|
||||
C->addCodeAction(&ActionDeadStores);
|
||||
break;
|
||||
|
||||
case WarnUninitVals:
|
||||
C->addCodeAction(&ActionUninitVals);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return C.take();
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// "Meta" ASTConsumer for running different source analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DRIVER_ANALYSISCONSUMER_H
|
||||
#define DRIVER_ANALYSISCONSUMER_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
enum Analyses {
|
||||
WarnDeadStores,
|
||||
WarnUninitVals
|
||||
};
|
||||
|
||||
ASTConsumer* CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
|
||||
Diagnostic &diags, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf,
|
||||
const LangOptions& lopts,
|
||||
const std::string& fname,
|
||||
const std::string& htmldir,
|
||||
bool visualize, bool trim,
|
||||
bool analyzeAll);
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
|
@ -78,16 +78,14 @@ enum ProgActions {
|
|||
AnalysisGRSimpleVals, // Perform graph-reachability constant prop.
|
||||
AnalysisGRSimpleValsView, // Visualize results of path-sens. analysis.
|
||||
CheckerCFRef, // Run the Core Foundation Ref. Count Checker.
|
||||
WarnDeadStores, // Run DeadStores checker on parsed ASTs.
|
||||
WarnDeadStoresCheck, // Check diagnostics for "DeadStores".
|
||||
WarnUninitVals, // Run UnitializedVariables checker.
|
||||
TestSerialization, // Run experimental serialization code.
|
||||
ParsePrintCallbacks, // Parse and print each callback.
|
||||
ParseSyntaxOnly, // Parse and perform semantic analysis.
|
||||
ParseNoop, // Parse with noop callbacks.
|
||||
RunPreprocessorOnly, // Just lex, no output.
|
||||
PrintPreprocessedInput, // -E mode.
|
||||
DumpTokens // Token dump mode.
|
||||
DumpTokens, // Token dump mode.
|
||||
RunAnalysis // Run one or more source code analyses.
|
||||
};
|
||||
|
||||
static llvm::cl::opt<ProgActions>
|
||||
|
@ -120,10 +118,6 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
|
|||
"Run parser, then build and view CFGs with Graphviz"),
|
||||
clEnumValN(AnalysisLiveVariables, "dump-live-variables",
|
||||
"Print results of live variable analysis"),
|
||||
clEnumValN(WarnDeadStores, "warn-dead-stores",
|
||||
"Flag warnings of stores to dead variables"),
|
||||
clEnumValN(WarnUninitVals, "warn-uninit-values",
|
||||
"Flag warnings of uses of unitialized variables"),
|
||||
clEnumValN(AnalysisGRSimpleVals, "checker-simple",
|
||||
"Perform path-sensitive constant propagation"),
|
||||
clEnumValN(CheckerCFRef, "checker-cfref",
|
||||
|
@ -181,6 +175,15 @@ AnalyzeAll("checker-opt-analyze-headers",
|
|||
llvm::cl::desc("Force the static analyzer to analyze "
|
||||
"functions defined in header files"));
|
||||
|
||||
static llvm::cl::list<Analyses>
|
||||
AnalysisList(llvm::cl::desc("Available Source Code Analyses:"),
|
||||
llvm::cl::values(
|
||||
clEnumValN(WarnDeadStores, "warn-dead-stores",
|
||||
"Flag warnings of stores to dead variables"),
|
||||
clEnumValN(WarnUninitVals, "warn-uninit-values",
|
||||
"Flag warnings of uses of unitialized variables"),
|
||||
clEnumValEnd));
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Language Options
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1199,12 +1202,6 @@ static ASTConsumer* CreateASTConsumer(const std::string& InFile,
|
|||
case AnalysisLiveVariables:
|
||||
return CreateLiveVarAnalyzer(AnalyzeSpecificFunction);
|
||||
|
||||
case WarnDeadStores:
|
||||
return CreateDeadStoreChecker(Diag);
|
||||
|
||||
case WarnUninitVals:
|
||||
return CreateUnitValsChecker(Diag);
|
||||
|
||||
case AnalysisGRSimpleVals:
|
||||
return CreateGRSimpleVals(Diag, PP, PPF, AnalyzeSpecificFunction,
|
||||
OutputFile, VisualizeEG, TrimGraph, AnalyzeAll);
|
||||
|
@ -1228,6 +1225,15 @@ static ASTConsumer* CreateASTConsumer(const std::string& InFile,
|
|||
|
||||
case RewriteObjC:
|
||||
return CreateCodeRewriterTest(InFile, OutputFile, Diag, LangOpts);
|
||||
|
||||
case RunAnalysis:
|
||||
assert (!AnalysisList.empty());
|
||||
return CreateAnalysisConsumer(&AnalysisList[0],
|
||||
&AnalysisList[0]+AnalysisList.size(),
|
||||
Diag, PP, PPF, LangOpts,
|
||||
AnalyzeSpecificFunction,
|
||||
OutputFile, VisualizeEG, TrimGraph,
|
||||
AnalyzeAll);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1485,6 +1491,11 @@ int main(int argc, char **argv) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
// Are we invoking one or more source analyses?
|
||||
if (!AnalysisList.empty() && ProgAction == ParseSyntaxOnly)
|
||||
ProgAction = RunAnalysis;
|
||||
|
||||
|
||||
llvm::OwningPtr<SourceManager> SourceMgr;
|
||||
|
||||
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
||||
|
|
|
@ -4,7 +4,7 @@ void f1()
|
|||
{
|
||||
int i;
|
||||
|
||||
int j = i ? : 1; // expected-warning{{use of uninitialized variable}}
|
||||
int j = i ? : 1; // expected-warning{{use of uninitialized variable}} //expected-warning{{Value stored to 'j' is never read}}
|
||||
}
|
||||
|
||||
void *f2(int *i)
|
||||
|
|
Загрузка…
Ссылка в новой задаче