Skip to content

Commit 6f3b775

Browse files
author
Gabor Marton
committed
[Analyzer][solver] Add dump methods for (dis)equality classes.
This proved to be very useful during debugging. Differential Revision: https://reviews.llvm.org/D103967
1 parent ad81dea commit 6f3b775

File tree

4 files changed

+195
-0
lines changed

4 files changed

+195
-0
lines changed

clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,11 @@ class EquivalenceClass : public llvm::FoldingSetNode {
594594
RangeSet::Factory &F,
595595
ProgramStateRef State);
596596

597+
void dumpToStream(ProgramStateRef State, raw_ostream &os) const;
598+
LLVM_DUMP_METHOD void dump(ProgramStateRef State) const {
599+
dumpToStream(State, llvm::errs());
600+
}
601+
597602
/// Check equivalence data for consistency.
598603
LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool
599604
isClassDataConsistent(ProgramStateRef State);
@@ -1414,6 +1419,17 @@ class RangeConstraintManager : public RangedConstraintManager {
14141419

14151420
void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n",
14161421
unsigned int Space = 0, bool IsDot = false) const override;
1422+
void printConstraints(raw_ostream &Out, ProgramStateRef State,
1423+
const char *NL = "\n", unsigned int Space = 0,
1424+
bool IsDot = false) const;
1425+
void printEquivalenceClasses(raw_ostream &Out, ProgramStateRef State,
1426+
const char *NL = "\n", unsigned int Space = 0,
1427+
bool IsDot = false) const;
1428+
void printEquivalenceClass(raw_ostream &Out, ProgramStateRef State,
1429+
EquivalenceClass Class) const;
1430+
void printDisequalities(raw_ostream &Out, ProgramStateRef State,
1431+
const char *NL = "\n", unsigned int Space = 0,
1432+
bool IsDot = false) const;
14171433

14181434
//===------------------------------------------------------------------===//
14191435
// Implementation for interface from RangedConstraintManager.
@@ -1637,6 +1653,15 @@ ConstraintMap ento::getConstraintMap(ProgramStateRef State) {
16371653
// EqualityClass implementation details
16381654
//===----------------------------------------------------------------------===//
16391655

1656+
LLVM_DUMP_METHOD void EquivalenceClass::dumpToStream(ProgramStateRef State,
1657+
raw_ostream &os) const {
1658+
SymbolSet ClassMembers = getClassMembers(State);
1659+
for (const SymbolRef &MemberSym : ClassMembers) {
1660+
MemberSym->dump();
1661+
os << "\n";
1662+
}
1663+
}
1664+
16401665
inline EquivalenceClass EquivalenceClass::find(ProgramStateRef State,
16411666
SymbolRef Sym) {
16421667
assert(State && "State should not be null");
@@ -2483,6 +2508,16 @@ ProgramStateRef RangeConstraintManager::assumeSymOutsideInclusiveRange(
24832508
void RangeConstraintManager::printJson(raw_ostream &Out, ProgramStateRef State,
24842509
const char *NL, unsigned int Space,
24852510
bool IsDot) const {
2511+
printConstraints(Out, State, NL, Space, IsDot);
2512+
printEquivalenceClasses(Out, State, NL, Space, IsDot);
2513+
printDisequalities(Out, State, NL, Space, IsDot);
2514+
}
2515+
2516+
void RangeConstraintManager::printConstraints(raw_ostream &Out,
2517+
ProgramStateRef State,
2518+
const char *NL,
2519+
unsigned int Space,
2520+
bool IsDot) const {
24862521
ConstraintRangeTy Constraints = State->get<ConstraintRange>();
24872522

24882523
Indent(Out, Space, IsDot) << "\"constraints\": ";
@@ -2516,3 +2551,106 @@ void RangeConstraintManager::printJson(raw_ostream &Out, ProgramStateRef State,
25162551
--Space;
25172552
Indent(Out, Space, IsDot) << "]," << NL;
25182553
}
2554+
2555+
void RangeConstraintManager::printEquivalenceClass(
2556+
raw_ostream &Out, ProgramStateRef State, EquivalenceClass Class) const {
2557+
bool FirstMember = true;
2558+
SymbolSet ClassMembers = Class.getClassMembers(State);
2559+
Out << "[ ";
2560+
for (SymbolRef ClassMember : ClassMembers) {
2561+
if (FirstMember)
2562+
FirstMember = false;
2563+
else
2564+
Out << ", ";
2565+
Out << "\"" << ClassMember << "\"";
2566+
}
2567+
Out << " ]";
2568+
}
2569+
2570+
void RangeConstraintManager::printEquivalenceClasses(raw_ostream &Out,
2571+
ProgramStateRef State,
2572+
const char *NL,
2573+
unsigned int Space,
2574+
bool IsDot) const {
2575+
ClassMembersTy Members = State->get<ClassMembers>();
2576+
2577+
Indent(Out, Space, IsDot) << "\"equivalence_classes\": ";
2578+
if (Members.isEmpty()) {
2579+
Out << "null," << NL;
2580+
return;
2581+
}
2582+
2583+
++Space;
2584+
Out << '[' << NL;
2585+
bool FirstClass = true;
2586+
for (std::pair<EquivalenceClass, SymbolSet> ClassToSymbolSet : Members) {
2587+
EquivalenceClass Class = ClassToSymbolSet.first;
2588+
2589+
if (FirstClass) {
2590+
FirstClass = false;
2591+
} else {
2592+
Out << ',';
2593+
Out << NL;
2594+
}
2595+
Indent(Out, Space, IsDot);
2596+
printEquivalenceClass(Out, State, Class);
2597+
}
2598+
Out << NL;
2599+
2600+
--Space;
2601+
Indent(Out, Space, IsDot) << "]," << NL;
2602+
}
2603+
2604+
void RangeConstraintManager::printDisequalities(raw_ostream &Out,
2605+
ProgramStateRef State,
2606+
const char *NL,
2607+
unsigned int Space,
2608+
bool IsDot) const {
2609+
DisequalityMapTy Disequalities = State->get<DisequalityMap>();
2610+
2611+
Indent(Out, Space, IsDot) << "\"disequality_info\": ";
2612+
if (Disequalities.isEmpty()) {
2613+
Out << "null," << NL;
2614+
return;
2615+
}
2616+
2617+
++Space;
2618+
Out << '[' << NL;
2619+
bool FirstClass = true;
2620+
for (std::pair<EquivalenceClass, ClassSet> ClassToDisEqSet : Disequalities) {
2621+
EquivalenceClass Class = ClassToDisEqSet.first;
2622+
if (FirstClass) {
2623+
FirstClass = false;
2624+
} else {
2625+
Out << ',';
2626+
Out << NL;
2627+
}
2628+
Indent(Out, Space, IsDot) << "{" << NL;
2629+
unsigned int DisEqSpace = Space + 1;
2630+
Indent(Out, DisEqSpace, IsDot) << "\"class\": ";
2631+
printEquivalenceClass(Out, State, Class);
2632+
ClassSet DisequalClasses = ClassToDisEqSet.second;
2633+
if (!DisequalClasses.isEmpty()) {
2634+
Out << "," << NL;
2635+
Indent(Out, DisEqSpace, IsDot) << "\"disequal_to\": [" << NL;
2636+
unsigned int DisEqClassSpace = DisEqSpace + 1;
2637+
Indent(Out, DisEqClassSpace, IsDot);
2638+
bool FirstDisEqClass = true;
2639+
for (EquivalenceClass DisEqClass : DisequalClasses) {
2640+
if (FirstDisEqClass) {
2641+
FirstDisEqClass = false;
2642+
} else {
2643+
Out << ',' << NL;
2644+
Indent(Out, DisEqClassSpace, IsDot);
2645+
}
2646+
printEquivalenceClass(Out, State, DisEqClass);
2647+
}
2648+
Out << "]" << NL;
2649+
}
2650+
Indent(Out, Space, IsDot) << "}";
2651+
}
2652+
Out << NL;
2653+
2654+
--Space;
2655+
Indent(Out, Space, IsDot) << "]," << NL;
2656+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_analyze_cc1 \
2+
// RUN: -analyzer-checker=debug.ExprInspection %s 2>&1 | FileCheck %s
3+
4+
void clang_analyzer_printState();
5+
6+
void test_disequality_info(int e0, int b0, int b1, int c0) {
7+
int e1 = e0 - b0;
8+
if (b0 == 2) {
9+
int e2 = e1 - b1;
10+
if (e2 > 0) {
11+
if (b1 != c0)
12+
clang_analyzer_printState();
13+
}
14+
}
15+
}
16+
17+
// CHECK: "disequality_info": [
18+
// CHECK-NEXT: {
19+
// CHECK-NEXT: "class": [ "reg_$2<int b1>" ],
20+
// CHECK-NEXT: "disequal_to": [
21+
// CHECK-NEXT: [ "(reg_$0<int e0>) - 2" ],
22+
// CHECK-NEXT: [ "reg_$3<int c0>" ]]
23+
// CHECK-NEXT: },
24+
// CHECK-NEXT: {
25+
// CHECK-NEXT: "class": [ "(reg_$0<int e0>) - 2" ],
26+
// CHECK-NEXT: "disequal_to": [
27+
// CHECK-NEXT: [ "reg_$2<int b1>" ]]
28+
// CHECK-NEXT: },
29+
// CHECK-NEXT: {
30+
// CHECK-NEXT: "class": [ "reg_$3<int c0>" ],
31+
// CHECK-NEXT: "disequal_to": [
32+
// CHECK-NEXT: [ "reg_$2<int b1>" ]]
33+
// CHECK-NEXT: }
34+
// CHECK-NEXT: ],
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_analyze_cc1 \
2+
// RUN: -analyzer-checker=debug.ExprInspection %s 2>&1 | FileCheck %s
3+
4+
void clang_analyzer_printState();
5+
6+
void test_equivalence_classes(int a, int b, int c, int d) {
7+
if (a + b != c)
8+
return;
9+
if (a != d)
10+
return;
11+
if (b != 0)
12+
return;
13+
clang_analyzer_printState();
14+
(void)(a * b * c * d);
15+
return;
16+
}
17+
18+
// CHECK: "equivalence_classes": [
19+
// CHECK-NEXT: [ "reg_$0<int a>", "(reg_$0<int a>) + (reg_$1<int b>)", "reg_$2<int c>", "reg_$3<int d>" ],
20+
// CHECK-NEXT: [ "((reg_$0<int a>) + (reg_$1<int b>)) != (reg_$2<int c>)", "(reg_$0<int a>) != (reg_$2<int c>)" ]
21+
// CHECK-NEXT: ],

clang/test/Analysis/expr-inspection.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ void foo(int x) {
3838
// CHECK-NEXT: "constraints": [
3939
// CHECK-NEXT: { "symbol": "reg_$0<int x>", "range": "{ [-2147483648, 13] }" }
4040
// CHECK-NEXT: ],
41+
// CHECK-NEXT: "equivalence_classes": null,
42+
// CHECK-NEXT: "disequality_info": null,
4143
// CHECK-NEXT: "dynamic_types": null,
4244
// CHECK-NEXT: "dynamic_casts": null,
4345
// CHECK-NEXT: "constructing_objects": null,

0 commit comments

Comments
 (0)