mirror of https://github.com/microsoft/clang.git
[analyzer] Use Clang's evaluation for global constants and default arguments.
Previously, we were handling only simple integer constants for globals and the smattering of implicitly-valued expressions handled by Environment for default arguments. Now, we can use any integer constant expression that Clang can evaluate, in addition to everything we handled before. PR15094 / <rdar://problem/12830437> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175026 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
04870edbea
commit
38f68ef19c
|
@ -37,9 +37,6 @@ static const Expr *ignoreTransparentExprs(const Expr *E) {
|
|||
case Stmt::SubstNonTypeTemplateParmExprClass:
|
||||
E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
|
||||
break;
|
||||
case Stmt::CXXDefaultArgExprClass:
|
||||
E = cast<CXXDefaultArgExpr>(E)->getExpr();
|
||||
break;
|
||||
default:
|
||||
// This is the base case: we can't look through more than we already have.
|
||||
return E;
|
||||
|
@ -75,7 +72,6 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
|
|||
|
||||
switch (S->getStmtClass()) {
|
||||
case Stmt::CXXBindTemporaryExprClass:
|
||||
case Stmt::CXXDefaultArgExprClass:
|
||||
case Stmt::ExprWithCleanupsClass:
|
||||
case Stmt::GenericSelectionExprClass:
|
||||
case Stmt::OpaqueValueExprClass:
|
||||
|
|
|
@ -639,7 +639,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
case Stmt::StringLiteralClass:
|
||||
case Stmt::ObjCStringLiteralClass:
|
||||
case Stmt::CXXBindTemporaryExprClass:
|
||||
case Stmt::CXXDefaultArgExprClass:
|
||||
case Stmt::SubstNonTypeTemplateParmExprClass:
|
||||
case Stmt::CXXNullPtrLiteralExprClass: {
|
||||
Bldr.takeNodes(Pred);
|
||||
|
@ -650,6 +649,39 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
break;
|
||||
}
|
||||
|
||||
case Stmt::CXXDefaultArgExprClass: {
|
||||
Bldr.takeNodes(Pred);
|
||||
ExplodedNodeSet PreVisit;
|
||||
getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
|
||||
|
||||
ExplodedNodeSet Tmp;
|
||||
StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
|
||||
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
const Expr *ArgE = cast<CXXDefaultArgExpr>(S)->getExpr();
|
||||
|
||||
// Avoid creating and destroying a lot of APSInts.
|
||||
SVal V;
|
||||
llvm::APSInt Result;
|
||||
|
||||
for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end();
|
||||
I != E; ++I) {
|
||||
ProgramStateRef State = (*I)->getState();
|
||||
|
||||
if (ArgE->EvaluateAsInt(Result, getContext()))
|
||||
V = svalBuilder.makeIntVal(Result);
|
||||
else
|
||||
V = State->getSVal(ArgE, LCtx);
|
||||
|
||||
State = State->BindExpr(S, LCtx, V);
|
||||
Bldr2.generateNode(S, *I, State);
|
||||
}
|
||||
|
||||
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
|
||||
Bldr.addNodes(Dst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::ObjCArrayLiteralClass:
|
||||
case Expr::ObjCDictionaryLiteralClass:
|
||||
// FIXME: explicitly model with a region and the actual contents
|
||||
|
|
|
@ -1524,11 +1524,14 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
|
|||
QualType CT = Ctx.getCanonicalType(T);
|
||||
if (CT.isConstQualified()) {
|
||||
if (const Expr *Init = VD->getInit()) {
|
||||
if (const IntegerLiteral *IL =
|
||||
dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) {
|
||||
const nonloc::ConcreteInt &V = svalBuilder.makeIntVal(IL);
|
||||
return svalBuilder.evalCast(V, Init->getType(), IL->getType());
|
||||
}
|
||||
llvm::APSInt Result;
|
||||
if (Init->EvaluateAsInt(Result, Ctx))
|
||||
return svalBuilder.makeIntVal(Result);
|
||||
|
||||
if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
|
||||
return svalBuilder.makeNull();
|
||||
|
||||
// FIXME: Handle other possible constant expressions.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,15 +67,29 @@ int constIntGlob() {
|
|||
return 3 / *m; // expected-warning {{Division by zero}}
|
||||
}
|
||||
|
||||
extern const int x;
|
||||
extern const int y;
|
||||
int constIntGlobExtern() {
|
||||
if (x == 0) {
|
||||
if (y == 0) {
|
||||
foo();
|
||||
return 5 / x; // expected-warning {{Division by zero}}
|
||||
return 5 / y; // expected-warning {{Division by zero}}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void * const ptr = 0;
|
||||
void constPtrGlob() {
|
||||
clang_analyzer_eval(ptr == 0); // expected-warning{{TRUE}}
|
||||
foo();
|
||||
clang_analyzer_eval(ptr == 0); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
static const int x2 = x;
|
||||
void constIntGlob2() {
|
||||
clang_analyzer_eval(x2 == 0); // expected-warning{{TRUE}}
|
||||
foo();
|
||||
clang_analyzer_eval(x2 == 0); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
void testAnalyzerEvalIsPure() {
|
||||
extern int someGlobal;
|
||||
if (someGlobal == 0) {
|
||||
|
|
|
@ -216,7 +216,7 @@ namespace DefaultArgs {
|
|||
|
||||
class Secret {
|
||||
public:
|
||||
static const int value = 42;
|
||||
static const int value = 40 + 2;
|
||||
int get(int i = value) {
|
||||
return i;
|
||||
}
|
||||
|
@ -225,16 +225,40 @@ namespace DefaultArgs {
|
|||
void testMethod() {
|
||||
Secret obj;
|
||||
clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}}
|
||||
|
||||
// FIXME: Should be 'TRUE'. See PR13673 or <rdar://problem/11720796>.
|
||||
clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
|
||||
|
||||
// FIXME: Even if we constrain the variable, we still have a problem.
|
||||
// See PR13385 or <rdar://problem/12156507>.
|
||||
if (Secret::value != 42)
|
||||
return;
|
||||
clang_analyzer_eval(obj.get() == 42); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
|
||||
}
|
||||
|
||||
enum ABC {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2
|
||||
};
|
||||
|
||||
int enumUser(ABC input = B) {
|
||||
return static_cast<int>(input);
|
||||
}
|
||||
|
||||
void testEnum() {
|
||||
clang_analyzer_eval(enumUser(C) == 2); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(enumUser() == 1); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
|
||||
int exprUser(int input = 2 * 4) {
|
||||
return input;
|
||||
}
|
||||
|
||||
int complicatedExprUser(int input = 2 * Secret::value) {
|
||||
return input;
|
||||
}
|
||||
|
||||
void testExprs() {
|
||||
clang_analyzer_eval(exprUser(1) == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(exprUser() == 8); // expected-warning{{TRUE}}
|
||||
|
||||
clang_analyzer_eval(complicatedExprUser(1) == 1); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(complicatedExprUser() == 84); // expected-warning{{TRUE}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue