forked from OSchip/llvm-project
[clang][dataflow] Add support for (built-in) (in)equality operators
Adds logical interpretation of built-in equality operators, `==` and `!=`.s Differential Revision: https://reviews.llvm.org/D122830
This commit is contained in:
parent
c45975cbf9
commit
ef1e1b3106
|
@ -21,6 +21,7 @@
|
|||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
@ -37,6 +38,26 @@ static const Expr *skipExprWithCleanups(const Expr *E) {
|
|||
return E;
|
||||
}
|
||||
|
||||
static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
|
||||
Environment &Env) {
|
||||
// Equality of booleans involves implicit integral casts. Ignore these casts
|
||||
// for now and focus on the values associated with the wrapped expressions.
|
||||
// FIXME: Consider changing this once the framework offers better support for
|
||||
// integral casts.
|
||||
const Expr *LHSNorm = LHS.IgnoreCasts();
|
||||
const Expr *RHSNorm = RHS.IgnoreCasts();
|
||||
assert(LHSNorm != nullptr);
|
||||
assert(RHSNorm != nullptr);
|
||||
|
||||
if (auto *LHSValue = dyn_cast_or_null<BoolValue>(
|
||||
Env.getValue(*LHSNorm, SkipPast::Reference)))
|
||||
if (auto *RHSValue = dyn_cast_or_null<BoolValue>(
|
||||
Env.getValue(*RHSNorm, SkipPast::Reference)))
|
||||
return Env.makeIff(*LHSValue, *RHSValue);
|
||||
|
||||
return Env.makeAtomicBoolValue();
|
||||
}
|
||||
|
||||
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
|
||||
public:
|
||||
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
|
||||
|
@ -83,8 +104,16 @@ public:
|
|||
Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
|
||||
break;
|
||||
}
|
||||
case BO_NE:
|
||||
case BO_EQ: {
|
||||
auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
|
||||
auto &Loc = Env.createStorageLocation(*S);
|
||||
Env.setStorageLocation(*S, Loc);
|
||||
Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue
|
||||
: Env.makeNot(LHSEqRHSValue));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// FIXME: Add support for BO_EQ, BO_NE.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2578,4 +2578,74 @@ TEST_F(TransferTest, AssignMemberBeforeCopy) {
|
|||
});
|
||||
}
|
||||
|
||||
TEST_F(TransferTest, BooleanEquality) {
|
||||
std::string Code = R"(
|
||||
void target(bool Bar) {
|
||||
bool Foo = true;
|
||||
if (Bar == Foo) {
|
||||
(void)0;
|
||||
/*[[p-then]]*/
|
||||
} else {
|
||||
(void)0;
|
||||
/*[[p-else]]*/
|
||||
}
|
||||
}
|
||||
)";
|
||||
runDataflow(
|
||||
Code, [](llvm::ArrayRef<
|
||||
std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
|
||||
Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results, ElementsAre(Pair("p-else", _), Pair("p-then", _)));
|
||||
const Environment &EnvElse = Results[0].second.Env;
|
||||
const Environment &EnvThen = Results[1].second.Env;
|
||||
|
||||
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
|
||||
ASSERT_THAT(BarDecl, NotNull());
|
||||
|
||||
auto &BarValThen =
|
||||
*cast<BoolValue>(EnvThen.getValue(*BarDecl, SkipPast::None));
|
||||
EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen));
|
||||
|
||||
auto &BarValElse =
|
||||
*cast<BoolValue>(EnvElse.getValue(*BarDecl, SkipPast::None));
|
||||
EXPECT_FALSE(EnvElse.flowConditionImplies(BarValElse));
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(TransferTest, BooleanInequality) {
|
||||
std::string Code = R"(
|
||||
void target(bool Bar) {
|
||||
bool Foo = true;
|
||||
if (Bar != Foo) {
|
||||
(void)0;
|
||||
/*[[p-then]]*/
|
||||
} else {
|
||||
(void)0;
|
||||
/*[[p-else]]*/
|
||||
}
|
||||
}
|
||||
)";
|
||||
runDataflow(
|
||||
Code, [](llvm::ArrayRef<
|
||||
std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
|
||||
Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results, ElementsAre(Pair("p-else", _), Pair("p-then", _)));
|
||||
const Environment &EnvElse = Results[0].second.Env;
|
||||
const Environment &EnvThen = Results[1].second.Env;
|
||||
|
||||
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
|
||||
ASSERT_THAT(BarDecl, NotNull());
|
||||
|
||||
auto &BarValThen =
|
||||
*cast<BoolValue>(EnvThen.getValue(*BarDecl, SkipPast::None));
|
||||
EXPECT_FALSE(EnvThen.flowConditionImplies(BarValThen));
|
||||
|
||||
auto &BarValElse =
|
||||
*cast<BoolValue>(EnvElse.getValue(*BarDecl, SkipPast::None));
|
||||
EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
Loading…
Reference in New Issue