--- /dev/null
+//===- JsonSupport.h - JSON Output Utilities --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_JSONSUPPORT_H
+#define LLVM_CLANG_BASIC_JSONSUPPORT_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/raw_ostream.h"
+
+
+namespace clang {
+
+inline raw_ostream &Indent(raw_ostream &Out, const unsigned int Space,
+ bool IsDot) {
+ for (unsigned int I = 0; I < Space * 2; ++I)
+ Out << (IsDot ? " " : " ");
+ return Out;
+}
+
+} // namespace clang
+
+#endif // LLVM_CLANG_BASIC_JSONSUPPORT_H
}
// Pretty-printing.
- void print(raw_ostream &Out, const char *nl = "\n", const char *sep = "",
- const LocationContext *CurrentLC = nullptr) const;
- void printDOT(raw_ostream &Out,
- const LocationContext *CurrentLC = nullptr) const;
+ void printJson(raw_ostream &Out, const LocationContext *LCtx = nullptr,
+ const char *NL = "\n", const char *Sep = "",
+ unsigned int Space = 0, bool IsDot = false) const;
+
+ void printDOT(raw_ostream &Out, const LocationContext *LCtx = nullptr,
+ unsigned int Space = 0) const;
void dump() const;
virtual bool scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Visitor) = 0;
- virtual void print(Store store, raw_ostream &Out, const char* nl) = 0;
+ virtual void printJson(raw_ostream &Out, Store S, const char *NL,
+ unsigned int Space, bool IsDot) const = 0;
class BindingsHandler {
public:
// State pretty-printing.
//===----------------------------------------------------------------------===//
-void ProgramState::print(raw_ostream &Out,
- const char *NL, const char *Sep,
- const LocationContext *LC) const {
+void ProgramState::printJson(raw_ostream &Out, const LocationContext *LCtx,
+ const char *NL, const char *Sep,
+ unsigned int Space, bool IsDot) const {
// Print the store.
ProgramStateManager &Mgr = getStateManager();
const ASTContext &Context = getStateManager().getContext();
- Mgr.getStoreManager().print(getStore(), Out, NL);
+ Mgr.getStoreManager().printJson(Out, getStore(), NL, Space, IsDot);
// Print out the environment.
- Env.print(Out, NL, Sep, Context, LC);
+ Env.print(Out, NL, Sep, Context, LCtx);
// Print out the constraints.
Mgr.getConstraintManager().print(this, Out, NL, Sep);
printDynamicTypeInfo(this, Out, NL, Sep);
// Print checker-specific data.
- Mgr.getOwningEngine().printState(Out, this, NL, Sep, LC);
+ Mgr.getOwningEngine().printState(Out, this, NL, Sep, LCtx);
}
-void ProgramState::printDOT(raw_ostream &Out,
- const LocationContext *LC) const {
- print(Out, "\\l", "\\|", LC);
+void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LCtx,
+ unsigned int Space) const {
+ printJson(Out, LCtx, "\\l", "\\|", Space, /*IsDot=*/true);
}
LLVM_DUMP_METHOD void ProgramState::dump() const {
- print(llvm::errs());
+ printJson(llvm::errs());
}
AnalysisManager& ProgramState::getAnalysisManager() const {
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
}
namespace llvm {
- static inline
- raw_ostream &operator<<(raw_ostream &os, BindingKey K) {
- os << '(' << K.getRegion();
- if (!K.hasSymbolicOffset())
- os << ',' << K.getOffset();
- os << ',' << (K.isDirect() ? "direct" : "default")
- << ')';
- return os;
- }
+static inline raw_ostream &operator<<(raw_ostream &Out, BindingKey K) {
+ Out << "\"kind\": \"" << (K.isDirect() ? "Direct" : "Default")
+ << "\", \"offset\": ";
+
+ if (!K.hasSymbolicOffset())
+ Out << K.getOffset();
+ else
+ Out << "null";
-} // end llvm namespace
+ return Out;
+}
+
+} // namespace llvm
-#ifndef NDEBUG
LLVM_DUMP_METHOD void BindingKey::dump() const { llvm::errs() << *this; }
-#endif
//===----------------------------------------------------------------------===//
// Actual Store type.
return asImmutableMap().getRootWithoutRetain();
}
- void dump(raw_ostream &OS, const char *nl) const {
- for (iterator I = begin(), E = end(); I != E; ++I) {
- const ClusterBindings &Cluster = I.getData();
- for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
- CI != CE; ++CI) {
- OS << ' ' << CI.getKey() << " : " << CI.getData() << nl;
- }
- OS << nl;
- }
+ void printJson(raw_ostream &Out, const char *NL = "\n",
+ unsigned int Space = 0, bool IsDot = false) const {
+ for (iterator I = begin(); I != end(); ++I) {
+ Indent(Out, Space, IsDot)
+ << "{ \"cluster\": \"" << I.getKey() << "\", \"items\": [" << NL;
+
+ ++Space;
+ const ClusterBindings &CB = I.getData();
+ for (ClusterBindings::iterator CI = CB.begin(); CI != CB.end(); ++CI) {
+ Indent(Out, Space, IsDot) << "{ " << CI.getKey() << ", \"value\": \""
+ << CI.getData() << "\" }";
+ if (std::next(CI) != CB.end())
+ Out << ',';
+ Out << NL;
+ }
+
+ --Space;
+ Indent(Out, Space, IsDot) << "]}";
+ if (std::next(I) != end())
+ Out << ',';
+ Out << NL;
+ }
}
- LLVM_DUMP_METHOD void dump() const { dump(llvm::errs(), "\n"); }
+ LLVM_DUMP_METHOD void dump() const { printJson(llvm::errs()); }
};
} // end anonymous namespace
RBFactory.getTreeFactory());
}
- void print(Store store, raw_ostream &Out, const char* nl) override;
+ void printJson(raw_ostream &Out, Store S, const char *NL = "\n",
+ unsigned int Space = 0, bool IsDot = false) const override;
void iterBindings(Store store, BindingsHandler& f) override {
RegionBindingsRef B = getRegionBindings(store);
// Utility methods.
//===----------------------------------------------------------------------===//
-void RegionStoreManager::print(Store store, raw_ostream &OS,
- const char* nl) {
- RegionBindingsRef B = getRegionBindings(store);
- OS << "Store (direct and default bindings), "
- << B.asStore()
- << " :" << nl;
- B.dump(OS, nl);
+void RegionStoreManager::printJson(raw_ostream &Out, Store S, const char *NL,
+ unsigned int Space, bool IsDot) const {
+ RegionBindingsRef Bindings = getRegionBindings(S);
+
+ Indent(Out, Space, IsDot) << "\"store\": ";
+
+ if (Bindings.isEmpty()) {
+ Out << "null," << NL;
+ return;
+ }
+
+ Out << '[' << NL;
+ Bindings.printJson(Out, NL, ++Space, IsDot);
+ Indent(Out, --Space, IsDot) << "]," << NL;
}
-// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s 2>&1 | FileCheck %s
+// RUN: %clang_analyze_cc1 \
+// RUN: -analyzer-checker=debug.ExprInspection \
+// RUN: -verify %s 2>&1 | FileCheck %s
// Self-tests for the debug.ExprInspection checker.
clang_analyzer_dump(x); // expected-warning{{reg_$0<int x>}}
clang_analyzer_dump(x + (-1)); // expected-warning{{(reg_$0<int x>) + -1}}
int y = 1;
- clang_analyzer_printState();
- for (; y < 3; ++y)
+ for (; y < 3; ++y) {
clang_analyzer_numTimesReached(); // expected-warning{{2}}
+
+ if (y == 2) {
+ int z = x > 13;
+ if (!z)
+ clang_analyzer_printState();
+ }
+ }
}
-// CHECK: Store (direct and default bindings)
-// CHECK-NEXT: (y,0,direct) : 1 S32b
+// CHECK: "store": [
+// CHECK-NEXT: { "cluster": "y", "items": [
+// CHECK-NEXT: { "kind": "Direct", "offset": 0, "value": "2 S32b" }
+// CHECK-NEXT: ]}
+// CHECK-NEXT: ]
-// CHECK: Expressions by stack frame:
+// CHECK: Expressions by stack frame:
// CHECK-NEXT: #0 Calling foo
-// CHECK-NEXT: clang_analyzer_printState : &code{clang_analyzer_printState}
+// CHECK-NEXT: (LC1, S847) clang_analyzer_printState : &code{clang_analyzer_printState}
-// CHECK: {{(Ranges are empty.)|(Constraints:[[:space:]]*$)}}
+// CHECK: Ranges of symbol values:
+// CHECK-NEXT: reg_$0<int x> : { [-2147483648, 13] }