1 //===- DebugSupport.cpp -----------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines functions which generate more readable forms of data 10 // structures used in the dataflow analyses, for debugging purposes. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Analysis/FlowSensitive/DebugSupport.h" 15 #include "clang/Analysis/FlowSensitive/Value.h" 16 #include "llvm/ADT/DenseMap.h" 17 #include "llvm/ADT/StringSet.h" 18 #include "llvm/Support/ErrorHandling.h" 19 #include "llvm/Support/FormatAdapters.h" 20 #include "llvm/Support/FormatVariadic.h" 21 22 namespace clang { 23 namespace dataflow { 24 25 using llvm::fmt_pad; 26 using llvm::formatv; 27 28 namespace { 29 30 class DebugStringGenerator { 31 public: 32 explicit DebugStringGenerator( 33 llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNamesArg) 34 : Counter(0), AtomNames(std::move(AtomNamesArg)) { 35 #ifndef NDEBUG 36 llvm::StringSet<> Names; 37 for (auto &N : AtomNames) { 38 assert(Names.insert(N.second).second && 39 "The same name must not assigned to different atoms"); 40 } 41 #endif 42 } 43 44 /// Returns a string representation of a boolean value `B`. 45 std::string debugString(const BoolValue &B, size_t Depth = 0) { 46 std::string S; 47 switch (B.getKind()) { 48 case Value::Kind::AtomicBool: { 49 S = getAtomName(&cast<AtomicBoolValue>(B)); 50 break; 51 } 52 case Value::Kind::Conjunction: { 53 auto &C = cast<ConjunctionValue>(B); 54 auto L = debugString(C.getLeftSubValue(), Depth + 1); 55 auto R = debugString(C.getRightSubValue(), Depth + 1); 56 S = formatv("(and\n{0}\n{1})", L, R); 57 break; 58 } 59 case Value::Kind::Disjunction: { 60 auto &D = cast<DisjunctionValue>(B); 61 auto L = debugString(D.getLeftSubValue(), Depth + 1); 62 auto R = debugString(D.getRightSubValue(), Depth + 1); 63 S = formatv("(or\n{0}\n{1})", L, R); 64 break; 65 } 66 case Value::Kind::Negation: { 67 auto &N = cast<NegationValue>(B); 68 S = formatv("(not\n{0})", debugString(N.getSubVal(), Depth + 1)); 69 break; 70 } 71 default: 72 llvm_unreachable("Unhandled value kind"); 73 } 74 auto Indent = Depth * 4; 75 return formatv("{0}", fmt_pad(S, Indent, 0)); 76 } 77 78 private: 79 /// Returns the name assigned to `Atom`, either user-specified or created by 80 /// default rules (B0, B1, ...). 81 std::string getAtomName(const AtomicBoolValue *Atom) { 82 auto Entry = AtomNames.try_emplace(Atom, formatv("B{0}", Counter)); 83 if (Entry.second) { 84 Counter++; 85 } 86 return Entry.first->second; 87 } 88 89 // Keep track of number of atoms without a user-specified name, used to assign 90 // non-repeating default names to such atoms. 91 size_t Counter; 92 93 // Keep track of names assigned to atoms. 94 llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames; 95 }; 96 97 } // namespace 98 99 std::string 100 debugString(const BoolValue &B, 101 llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) { 102 return DebugStringGenerator(std::move(AtomNames)).debugString(B); 103 } 104 105 } // namespace dataflow 106 } // namespace clang 107