sammccall updated this revision to Diff 516392. sammccall marked an inline comment as done. sammccall added a comment.
fix bad cast Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D148949/new/ https://reviews.llvm.org/D148949 Files: clang/include/clang/Analysis/FlowSensitive/Value.h clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp clang/lib/Analysis/FlowSensitive/HTMLLogger.css clang/lib/Analysis/FlowSensitive/HTMLLogger.html clang/lib/Analysis/FlowSensitive/HTMLLogger.js clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp
Index: clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp +++ clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp @@ -176,6 +176,7 @@ << "has analysis point state"; EXPECT_THAT(Logs[0], HasSubstr("transferBranch(0)")) << "has analysis logs"; EXPECT_THAT(Logs[0], HasSubstr("LocToVal")) << "has built-in lattice dump"; + EXPECT_THAT(Logs[0], HasSubstr("\"type\": \"int\"")) << "has value dump"; } } // namespace Index: clang/lib/Analysis/FlowSensitive/HTMLLogger.js =================================================================== --- clang/lib/Analysis/FlowSensitive/HTMLLogger.js +++ clang/lib/Analysis/FlowSensitive/HTMLLogger.js @@ -73,6 +73,9 @@ } return parent.insertBefore(clone, next); } + // data-use="xyz": use <template id="xyz"> instead. (Allows recursion.) + if ('use' in tmpl.dataset) + return inflate(document.getElementById(tmpl.dataset.use), data, parent, next); // <template> tag handling. Base case: recursively inflate. function handle(data) { for (c of tmpl.content.childNodes) Index: clang/lib/Analysis/FlowSensitive/HTMLLogger.html =================================================================== --- clang/lib/Analysis/FlowSensitive/HTMLLogger.html +++ clang/lib/Analysis/FlowSensitive/HTMLLogger.html @@ -10,6 +10,30 @@ <head> <?INJECT?> + +<template id="value-template"> + <details class="value" open> + <summary> + <span>{{v.kind}} + <template data-if="v.value_id"><span class="address">#{{v.value_id}}</span></template> + </span> + <template data-if="v.location"> + <span>{{v.type}} <span class="address">@{{v.location}}</span></span> + </template> + </summary> + <template + data-for="kv in Object.entries(v)" + data-if="['kind', 'value_id', 'type', 'location'].indexOf(kv[0]) < 0"> + <div class="property"><span class="key">{{kv[0]}}</span> + <template data-if="typeof(kv[1]) != 'object'">{{kv[1]}}</template> + <template data-if="typeof(kv[1]) == 'object'" data-let="v = kv[1]"> + <template data-use="value-template"></template> + </template> + </div> + </template> + </details> +</template> + </head> <body> @@ -50,6 +74,10 @@ <template data-if="state.element == 0">{{state.block}} (iteration {{state.iter}}) initial state</template> <template data-if="state.element != 0">Element {{selection.elt}} (iteration {{state.iter}})</template> </header> +<template data-if="state.value" data-let="v = state.value"> + <h2>Value</h2> + <template data-use="value-template"></template> +</template> <template data-if="state.logs"> <h2>Logs</h2> <pre>{{state.logs}}</pre> Index: clang/lib/Analysis/FlowSensitive/HTMLLogger.css =================================================================== --- clang/lib/Analysis/FlowSensitive/HTMLLogger.css +++ clang/lib/Analysis/FlowSensitive/HTMLLogger.css @@ -116,3 +116,27 @@ position: relative; margin-left: 0.5em; } + +.value { + border: 1px solid #888; + font-size: x-small; + flex-grow: 1; +} +.value summary { + background-color: #ace; + display: flex; + justify-content: space-between; +} +.value .address { + font-size: xx-small; + font-family: monospace; + color: #888; +} +.value .property { + display: flex; + margin-top: 0.5em; +} +.value .property .key { + font-weight: bold; + min-width: 5em; +} Index: clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -67,6 +67,7 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/JSON.h" #include "llvm/Support/Program.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" // Defines assets: HTMLLogger_{html_js,css} #include "HTMLLogger.inc" @@ -79,6 +80,94 @@ using StreamFactory = std::function<std::unique_ptr<llvm::raw_ostream>()>; +// Recursively dumps Values/StorageLocations as JSON +class ModelDumper { +public: + ModelDumper(llvm::json::OStream &JOS, const Environment &Env) + : JOS(JOS), Env(Env) {} + + void dump(Value &V) { + JOS.attribute("value_id", llvm::to_string(&V)); + if (!Visited.insert(&V).second) + return; + + JOS.attribute("kind", debugString(V.getKind())); + for (const auto& Prop : V.properties()) + JOS.attributeObject(Prop.first(), [&] { dump(*Prop.second); }); + + // Running the SAT solver is expensive, but knowing which booleans are + // guaranteed true/false here is valuable and hard to determine by hand. + if (auto *B = llvm::dyn_cast<BoolValue>(&V)) { + JOS.attribute("truth", Env.flowConditionImplies(*B) ? "true" + : Env.flowConditionImplies(Env.makeNot(*B)) + ? "false" + : "unknown"); + } + + switch (V.getKind()) { + case Value::Kind::Integer: + case Value::Kind::TopBool: + case Value::Kind::AtomicBool: + break; + case Value::Kind::Reference: + JOS.attributeObject( + "referent", [&] { dump(cast<ReferenceValue>(V).getReferentLoc()); }); + break; + case Value::Kind::Pointer: + JOS.attributeObject( + "pointee", [&] { dump(cast<PointerValue>(V).getPointeeLoc()); }); + break; + case Value::Kind::Struct: + for (const auto &Child : cast<StructValue>(V).children()) + JOS.attributeObject(Child.first->getNameAsString(), + [&] { dump(*Child.second); }); + break; + case Value::Kind::Disjunction: { + auto &VV = cast<DisjunctionValue>(V); + JOS.attributeObject("lhs", [&] { dump(VV.getLeftSubValue()); }); + JOS.attributeObject("rhs", [&] { dump(VV.getRightSubValue()); }); + break; + } + case Value::Kind::Conjunction: { + auto &VV = cast<ConjunctionValue>(V); + JOS.attributeObject("lhs", [&] { dump(VV.getLeftSubValue()); }); + JOS.attributeObject("rhs", [&] { dump(VV.getRightSubValue()); }); + break; + } + case Value::Kind::Negation: { + auto &VV = cast<NegationValue>(V); + JOS.attributeObject("not", [&] { dump(VV.getSubVal()); }); + break; + } + case Value::Kind::Implication: { + auto &VV = cast<ImplicationValue>(V); + JOS.attributeObject("if", [&] { dump(VV.getLeftSubValue()); }); + JOS.attributeObject("then", [&] { dump(VV.getRightSubValue()); }); + break; + } + case Value::Kind::Biconditional: { + auto &VV = cast<BiconditionalValue>(V); + JOS.attributeObject("lhs", [&] { dump(VV.getLeftSubValue()); }); + JOS.attributeObject("rhs", [&] { dump(VV.getRightSubValue()); }); + break; + } + } + } + void dump(const StorageLocation &L) { + JOS.attribute("location", llvm::to_string(&L)); + if (!Visited.insert(&L).second) + return; + + JOS.attribute("type", L.getType().getAsString()); + if (auto *V = Env.getValue(L)) + dump(*V); + } + + llvm::DenseSet<const void*> Visited; + llvm::json::OStream &JOS; + const Environment &Env; +}; + class HTMLLogger : public Logger { StreamFactory Streams; std::unique_ptr<llvm::raw_ostream> OS; @@ -184,6 +273,16 @@ JOS->attribute("block", blockID(Block)); JOS->attribute("iter", Iter); JOS->attribute("element", ElementIndex); + + // If this state immediately follows an Expr, show its built-in model. + if (ElementIndex > 0) { + auto S = + Iters.back().first->Elements[ElementIndex - 1].getAs<CFGStmt>(); + if (const Expr *E = S ? llvm::dyn_cast<Expr>(S->getStmt()) : nullptr) + if (auto *Loc = State.Env.getStorageLocation(*E, SkipPast::None)) + JOS->attributeObject( + "value", [&] { ModelDumper(*JOS, State.Env).dump(*Loc); }); + } if (!ContextLogs.empty()) { JOS->attribute("logs", ContextLogs); ContextLogs.clear(); Index: clang/include/clang/Analysis/FlowSensitive/Value.h =================================================================== --- clang/include/clang/Analysis/FlowSensitive/Value.h +++ clang/include/clang/Analysis/FlowSensitive/Value.h @@ -73,6 +73,11 @@ Properties.insert_or_assign(Name, &Val); } + llvm::iterator_range<llvm::StringMap<Value *>::const_iterator> + properties() const { + return {Properties.begin(), Properties.end()}; + } + private: Kind ValKind; llvm::StringMap<Value *> Properties; @@ -307,6 +312,12 @@ /// Assigns `Val` as the child value for `D`. void setChild(const ValueDecl &D, Value &Val) { Children[&D] = &Val; } + llvm::iterator_range< + llvm::DenseMap<const ValueDecl *, Value *>::const_iterator> + children() const { + return {Children.begin(), Children.end()}; + } + private: llvm::DenseMap<const ValueDecl *, Value *> Children; };
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits