This revision was automatically updated to reflect the committed changes.
Closed by commit rGbdf31471c76b: [Analyzer][solver] Add dump methods for
(dis)equality classes. (authored by martong).
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D103967/new/
https://reviews.llvm.org/D103967
Files:
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/test/Analysis/expr-inspection-printState-diseq-info.c
clang/test/Analysis/expr-inspection-printState-eq-classes.c
clang/test/Analysis/expr-inspection.c
Index: clang/test/Analysis/expr-inspection.c
===================================================================
--- clang/test/Analysis/expr-inspection.c
+++ clang/test/Analysis/expr-inspection.c
@@ -38,6 +38,8 @@
// CHECK-NEXT: "constraints": [
// CHECK-NEXT: { "symbol": "reg_$0<int x>", "range": "{ [-2147483648, 13] }" }
// CHECK-NEXT: ],
+// CHECK-NEXT: "equivalence_classes": null,
+// CHECK-NEXT: "disequality_info": null,
// CHECK-NEXT: "dynamic_types": null,
// CHECK-NEXT: "dynamic_casts": null,
// CHECK-NEXT: "constructing_objects": null,
Index: clang/test/Analysis/expr-inspection-printState-eq-classes.c
===================================================================
--- /dev/null
+++ clang/test/Analysis/expr-inspection-printState-eq-classes.c
@@ -0,0 +1,21 @@
+// RUN: %clang_analyze_cc1 \
+// RUN: -analyzer-checker=debug.ExprInspection %s 2>&1 | FileCheck %s
+
+void clang_analyzer_printState();
+
+void test_equivalence_classes(int a, int b, int c, int d) {
+ if (a + b != c)
+ return;
+ if (a != d)
+ return;
+ if (b != 0)
+ return;
+ clang_analyzer_printState();
+ (void)(a * b * c * d);
+ return;
+}
+
+ // CHECK: "equivalence_classes": [
+ // CHECK-NEXT: [ "((reg_$0<int a>) + (reg_$1<int b>)) != (reg_$2<int c>)", "(reg_$0<int a>) != (reg_$2<int c>)" ],
+ // CHECK-NEXT: [ "(reg_$0<int a>) + (reg_$1<int b>)", "reg_$0<int a>", "reg_$2<int c>", "reg_$3<int d>" ]
+ // CHECK-NEXT: ],
Index: clang/test/Analysis/expr-inspection-printState-diseq-info.c
===================================================================
--- /dev/null
+++ clang/test/Analysis/expr-inspection-printState-diseq-info.c
@@ -0,0 +1,34 @@
+// RUN: %clang_analyze_cc1 \
+// RUN: -analyzer-checker=debug.ExprInspection %s 2>&1 | FileCheck %s
+
+void clang_analyzer_printState();
+
+void test_disequality_info(int e0, int b0, int b1, int c0) {
+ int e1 = e0 - b0;
+ if (b0 == 2) {
+ int e2 = e1 - b1;
+ if (e2 > 0) {
+ if (b1 != c0)
+ clang_analyzer_printState();
+ }
+ }
+}
+
+ // CHECK: "disequality_info": [
+ // CHECK-NEXT: {
+ // CHECK-NEXT: "class": [ "(reg_$0<int e0>) - 2" ],
+ // CHECK-NEXT: "disequal_to": [
+ // CHECK-NEXT: [ "reg_$2<int b1>" ]]
+ // CHECK-NEXT: },
+ // CHECK-NEXT: {
+ // CHECK-NEXT: "class": [ "reg_$2<int b1>" ],
+ // CHECK-NEXT: "disequal_to": [
+ // CHECK-NEXT: [ "(reg_$0<int e0>) - 2" ],
+ // CHECK-NEXT: [ "reg_$3<int c0>" ]]
+ // CHECK-NEXT: },
+ // CHECK-NEXT: {
+ // CHECK-NEXT: "class": [ "reg_$3<int c0>" ],
+ // CHECK-NEXT: "disequal_to": [
+ // CHECK-NEXT: [ "reg_$2<int b1>" ]]
+ // CHECK-NEXT: }
+ // CHECK-NEXT: ],
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -592,6 +592,11 @@
RangeSet::Factory &F,
ProgramStateRef State);
+ void dumpToStream(ProgramStateRef State, raw_ostream &os) const;
+ LLVM_DUMP_METHOD void dump(ProgramStateRef State) const {
+ dumpToStream(State, llvm::errs());
+ }
+
/// Check equivalence data for consistency.
LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool
isClassDataConsistent(ProgramStateRef State);
@@ -1599,6 +1604,15 @@
void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n",
unsigned int Space = 0, bool IsDot = false) const override;
+ void printConstraints(raw_ostream &Out, ProgramStateRef State,
+ const char *NL = "\n", unsigned int Space = 0,
+ bool IsDot = false) const;
+ void printEquivalenceClasses(raw_ostream &Out, ProgramStateRef State,
+ const char *NL = "\n", unsigned int Space = 0,
+ bool IsDot = false) const;
+ void printDisequalities(raw_ostream &Out, ProgramStateRef State,
+ const char *NL = "\n", unsigned int Space = 0,
+ bool IsDot = false) const;
//===------------------------------------------------------------------===//
// Implementation for interface from RangedConstraintManager.
@@ -1749,6 +1763,15 @@
// EqualityClass implementation details
//===----------------------------------------------------------------------===//
+LLVM_DUMP_METHOD void EquivalenceClass::dumpToStream(ProgramStateRef State,
+ raw_ostream &os) const {
+ SymbolSet ClassMembers = getClassMembers(State);
+ for (const SymbolRef &MemberSym : ClassMembers) {
+ MemberSym->dump();
+ os << "\n";
+ }
+}
+
inline EquivalenceClass EquivalenceClass::find(ProgramStateRef State,
SymbolRef Sym) {
assert(State && "State should not be null");
@@ -2601,6 +2624,16 @@
void RangeConstraintManager::printJson(raw_ostream &Out, ProgramStateRef State,
const char *NL, unsigned int Space,
bool IsDot) const {
+ printConstraints(Out, State, NL, Space, IsDot);
+ printEquivalenceClasses(Out, State, NL, Space, IsDot);
+ printDisequalities(Out, State, NL, Space, IsDot);
+}
+
+void RangeConstraintManager::printConstraints(raw_ostream &Out,
+ ProgramStateRef State,
+ const char *NL,
+ unsigned int Space,
+ bool IsDot) const {
ConstraintRangeTy Constraints = State->get<ConstraintRange>();
Indent(Out, Space, IsDot) << "\"constraints\": ";
@@ -2634,3 +2667,140 @@
--Space;
Indent(Out, Space, IsDot) << "]," << NL;
}
+
+static std::string toString(const SymbolRef &Sym) {
+ std::string S;
+ llvm::raw_string_ostream O(S);
+ Sym->dumpToStream(O);
+ return O.str();
+}
+
+static std::string toString(ProgramStateRef State, EquivalenceClass Class) {
+ SymbolSet ClassMembers = Class.getClassMembers(State);
+ llvm::SmallVector<SymbolRef, 8> ClassMembersSorted(ClassMembers.begin(),
+ ClassMembers.end());
+ llvm::sort(ClassMembersSorted,
+ [](const SymbolRef &LHS, const SymbolRef &RHS) {
+ return toString(LHS) < toString(RHS);
+ });
+
+ bool FirstMember = true;
+
+ std::string Str;
+ llvm::raw_string_ostream Out(Str);
+ Out << "[ ";
+ for (SymbolRef ClassMember : ClassMembersSorted) {
+ if (FirstMember)
+ FirstMember = false;
+ else
+ Out << ", ";
+ Out << "\"" << ClassMember << "\"";
+ }
+ Out << " ]";
+ return Out.str();
+}
+
+void RangeConstraintManager::printEquivalenceClasses(raw_ostream &Out,
+ ProgramStateRef State,
+ const char *NL,
+ unsigned int Space,
+ bool IsDot) const {
+ ClassMembersTy Members = State->get<ClassMembers>();
+
+ Indent(Out, Space, IsDot) << "\"equivalence_classes\": ";
+ if (Members.isEmpty()) {
+ Out << "null," << NL;
+ return;
+ }
+
+ std::set<std::string> MembersStr;
+ for (std::pair<EquivalenceClass, SymbolSet> ClassToSymbolSet : Members)
+ MembersStr.insert(toString(State, ClassToSymbolSet.first));
+
+ ++Space;
+ Out << '[' << NL;
+ bool FirstClass = true;
+ for (const std::string &Str : MembersStr) {
+ if (FirstClass) {
+ FirstClass = false;
+ } else {
+ Out << ',';
+ Out << NL;
+ }
+ Indent(Out, Space, IsDot);
+ Out << Str;
+ }
+ Out << NL;
+
+ --Space;
+ Indent(Out, Space, IsDot) << "]," << NL;
+}
+
+void RangeConstraintManager::printDisequalities(raw_ostream &Out,
+ ProgramStateRef State,
+ const char *NL,
+ unsigned int Space,
+ bool IsDot) const {
+ DisequalityMapTy Disequalities = State->get<DisequalityMap>();
+
+ Indent(Out, Space, IsDot) << "\"disequality_info\": ";
+ if (Disequalities.isEmpty()) {
+ Out << "null," << NL;
+ return;
+ }
+
+ // Transform the disequality info to an ordered map of
+ // [string -> (ordered set of strings)]
+ using EqClassesStrTy = std::set<std::string>;
+ using DisequalityInfoStrTy = std::map<std::string, EqClassesStrTy>;
+ DisequalityInfoStrTy DisequalityInfoStr;
+ for (std::pair<EquivalenceClass, ClassSet> ClassToDisEqSet : Disequalities) {
+ EquivalenceClass Class = ClassToDisEqSet.first;
+ ClassSet DisequalClasses = ClassToDisEqSet.second;
+ EqClassesStrTy MembersStr;
+ for (EquivalenceClass DisEqClass : DisequalClasses)
+ MembersStr.insert(toString(State, DisEqClass));
+ DisequalityInfoStr.insert({toString(State, Class), MembersStr});
+ }
+
+ ++Space;
+ Out << '[' << NL;
+ bool FirstClass = true;
+ for (std::pair<std::string, EqClassesStrTy> ClassToDisEqSet :
+ DisequalityInfoStr) {
+ const std::string &Class = ClassToDisEqSet.first;
+ if (FirstClass) {
+ FirstClass = false;
+ } else {
+ Out << ',';
+ Out << NL;
+ }
+ Indent(Out, Space, IsDot) << "{" << NL;
+ unsigned int DisEqSpace = Space + 1;
+ Indent(Out, DisEqSpace, IsDot) << "\"class\": ";
+ Out << Class;
+ const EqClassesStrTy &DisequalClasses = ClassToDisEqSet.second;
+ if (!DisequalClasses.empty()) {
+ Out << "," << NL;
+ Indent(Out, DisEqSpace, IsDot) << "\"disequal_to\": [" << NL;
+ unsigned int DisEqClassSpace = DisEqSpace + 1;
+ Indent(Out, DisEqClassSpace, IsDot);
+ bool FirstDisEqClass = true;
+ for (const std::string &DisEqClass : DisequalClasses) {
+ if (FirstDisEqClass) {
+ FirstDisEqClass = false;
+ } else {
+ Out << ',' << NL;
+ Indent(Out, DisEqClassSpace, IsDot);
+ }
+ Out << DisEqClass;
+ }
+ Out << "]" << NL;
+ }
+ Indent(Out, Space, IsDot) << "}";
+ }
+ Out << NL;
+
+ --Space;
+ Indent(Out, Space, IsDot) << "]," << NL;
+}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits