Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -121,6 +121,9 @@ void handleEraseAfter(CheckerContext &C, const SVal &Iter) const; void handleEraseAfter(CheckerContext &C, const SVal &Iter1, const SVal &Iter2) const; + void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, + const char *Sep) const override; + public: IteratorModeling() {} @@ -1080,6 +1083,58 @@ C.addTransition(State); } +void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { + + auto ContMap = State->get(); + + if (!ContMap.isEmpty()) { + Out << Sep << "Container Data :" << NL; + for (const auto Cont : ContMap) { + Cont.first->dumpToStream(Out); + Out << " : [ "; + const auto CData = Cont.second; + if (CData.getBegin()) + CData.getBegin()->dumpToStream(Out); + else + Out << ""; + Out << " .. "; + if (CData.getEnd()) + CData.getEnd()->dumpToStream(Out); + else + Out << ""; + Out << " ]" << NL; + } + } + + auto SymbolMap = State->get(); + auto RegionMap = State->get(); + + if (!SymbolMap.isEmpty() || !RegionMap.isEmpty()) { + Out << Sep << "Iterator Positions :" << NL; + for (const auto Sym : SymbolMap) { + Sym.first->dumpToStream(Out); + Out << " : "; + const auto Pos = Sym.second; + Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == "; + Pos.getContainer()->dumpToStream(Out); + Out<<" ; Offset == "; + Pos.getOffset()->dumpToStream(Out); + } + + for (const auto Reg : RegionMap) { + Reg.first->dumpToStream(Out); + Out << " : "; + const auto Pos = Reg.second; + Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == "; + Pos.getContainer()->dumpToStream(Out); + Out<<" ; Offset == "; + Pos.getOffset()->dumpToStream(Out); + } + } +} + + namespace { const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, Index: clang/test/Analysis/iterator-modelling.cpp =================================================================== --- clang/test/Analysis/iterator-modelling.cpp +++ clang/test/Analysis/iterator-modelling.cpp @@ -1,6 +1,9 @@ // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify + // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true %s 2>&1 | FileCheck %s + #include "Inputs/system-header-simulator-cxx.h" template @@ -1970,3 +1973,29 @@ clang_analyzer_iterator_position(first)); // expected-warning@-1{{FALSE}} expected-warning@-1 0-1{{TRUE}} FIXME: should only expect FALSE in every case } } + +void clang_analyzer_printState(); + +void print_state(std::vector &V) { + const auto i0 = V.cbegin(); + clang_analyzer_printState(); + +// CHECK: "checker_messages": [ +// CHECK-NEXT: { "checker": "alpha.cplusplus.IteratorModeling", "messages": [ +// CHECK-NEXT: "Container Data :", +// CHECK-NEXT: "SymRegion{reg_$[[#]] & V>} : [ conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} .. ]", +// CHECK-NEXT: "Iterator Positions :", +// CHECK-NEXT: "i0 : Valid ; Container == SymRegion{reg_$[[#]] & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}" +// CHECK-NEXT: ]} + + const auto i1 = V.cend(); + clang_analyzer_printState(); + +// CHECK: "checker_messages": [ +// CHECK-NEXT: { "checker": "alpha.cplusplus.IteratorModeling", "messages": [ +// CHECK-NEXT: "Container Data :", +// CHECK-NEXT: "SymRegion{reg_$[[#]] & V>} : [ conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} .. conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} ]", +// CHECK-NEXT: "Iterator Positions :", +// CHECK-NEXT: "i1 : Valid ; Container == SymRegion{reg_$[[#]] & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}" +// CHECK-NEXT: ]} +}