//===- DebugSupport.cpp -----------------------------------------*- 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 // //===----------------------------------------------------------------------===// // // This file defines functions which generate more readable forms of data // structures used in the dataflow analyses, for debugging purposes. // //===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/DebugSupport.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" namespace clang { namespace dataflow { using llvm::fmt_pad; using llvm::formatv; namespace { class DebugStringGenerator { public: explicit DebugStringGenerator( llvm::DenseMap AtomNamesArg) : Counter(0), AtomNames(std::move(AtomNamesArg)) { #ifndef NDEBUG llvm::StringSet<> Names; for (auto &N : AtomNames) { assert(Names.insert(N.second).second && "The same name must not assigned to different atoms"); } #endif } /// Returns a string representation of a boolean value `B`. std::string debugString(const BoolValue &B, size_t Depth = 0) { std::string S; switch (B.getKind()) { case Value::Kind::AtomicBool: { S = getAtomName(&cast(B)); break; } case Value::Kind::Conjunction: { auto &C = cast(B); auto L = debugString(C.getLeftSubValue(), Depth + 1); auto R = debugString(C.getRightSubValue(), Depth + 1); S = formatv("(and\n{0}\n{1})", L, R); break; } case Value::Kind::Disjunction: { auto &D = cast(B); auto L = debugString(D.getLeftSubValue(), Depth + 1); auto R = debugString(D.getRightSubValue(), Depth + 1); S = formatv("(or\n{0}\n{1})", L, R); break; } case Value::Kind::Negation: { auto &N = cast(B); S = formatv("(not\n{0})", debugString(N.getSubVal(), Depth + 1)); break; } default: llvm_unreachable("Unhandled value kind"); } auto Indent = Depth * 4; return formatv("{0}", fmt_pad(S, Indent, 0)); } private: /// Returns the name assigned to `Atom`, either user-specified or created by /// default rules (B0, B1, ...). std::string getAtomName(const AtomicBoolValue *Atom) { auto Entry = AtomNames.try_emplace(Atom, formatv("B{0}", Counter)); if (Entry.second) { Counter++; } return Entry.first->second; } // Keep track of number of atoms without a user-specified name, used to assign // non-repeating default names to such atoms. size_t Counter; // Keep track of names assigned to atoms. llvm::DenseMap AtomNames; }; } // namespace std::string debugString(const BoolValue &B, llvm::DenseMap AtomNames) { return DebugStringGenerator(std::move(AtomNames)).debugString(B); } } // namespace dataflow } // namespace clang