Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:42:46

0001 //===-- FormattersContainer.h -----------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLDB_DATAFORMATTERS_FORMATTERSCONTAINER_H
0010 #define LLDB_DATAFORMATTERS_FORMATTERSCONTAINER_H
0011 
0012 #include <functional>
0013 #include <map>
0014 #include <memory>
0015 #include <mutex>
0016 #include <string>
0017 
0018 #include "lldb/lldb-public.h"
0019 
0020 #include "lldb/DataFormatters/FormatClasses.h"
0021 #include "lldb/DataFormatters/TypeFormat.h"
0022 #include "lldb/DataFormatters/TypeSummary.h"
0023 #include "lldb/DataFormatters/TypeSynthetic.h"
0024 #include "lldb/Symbol/CompilerType.h"
0025 #include "lldb/Utility/RegularExpression.h"
0026 #include "lldb/Utility/StringLexer.h"
0027 #include "lldb/ValueObject/ValueObject.h"
0028 
0029 namespace lldb_private {
0030 
0031 class IFormatChangeListener {
0032 public:
0033   virtual ~IFormatChangeListener() = default;
0034 
0035   virtual void Changed() = 0;
0036 
0037   virtual uint32_t GetCurrentRevision() = 0;
0038 };
0039 
0040 /// Class for matching type names.
0041 class TypeMatcher {
0042   /// Type name for exact match, or name of the python callback if m_match_type
0043   /// is `eFormatterMatchCallback`.
0044   ConstString m_name;
0045   RegularExpression m_type_name_regex;
0046   /// Indicates what kind of matching strategy should be used:
0047   /// - eFormatterMatchExact: match the exact type name in m_name.
0048   /// - eFormatterMatchRegex: match using the RegularExpression object
0049   ///   `m_type_name_regex` instead.
0050   /// - eFormatterMatchCallback: run the function in m_name to decide if a type
0051   ///   matches or not.
0052   lldb::FormatterMatchType m_match_type;
0053 
0054   // if the user tries to add formatters for, say, "struct Foo" those will not
0055   // match any type because of the way we strip qualifiers from typenames this
0056   // method looks for the case where the user is adding a
0057   // "class","struct","enum" or "union" Foo and strips the unnecessary qualifier
0058   static ConstString StripTypeName(ConstString type) {
0059     if (type.IsEmpty())
0060       return type;
0061 
0062     std::string type_cstr(type.AsCString());
0063     StringLexer type_lexer(type_cstr);
0064 
0065     type_lexer.AdvanceIf("class ");
0066     type_lexer.AdvanceIf("enum ");
0067     type_lexer.AdvanceIf("struct ");
0068     type_lexer.AdvanceIf("union ");
0069 
0070     while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
0071       ;
0072 
0073     return ConstString(type_lexer.GetUnlexed());
0074   }
0075 
0076 public:
0077   TypeMatcher() = delete;
0078   /// Creates a matcher that accepts any type with exactly the given type name.
0079   TypeMatcher(ConstString type_name)
0080       : m_name(type_name), m_match_type(lldb::eFormatterMatchExact) {}
0081   /// Creates a matcher that accepts any type matching the given regex.
0082   TypeMatcher(RegularExpression regex)
0083       : m_type_name_regex(std::move(regex)),
0084         m_match_type(lldb::eFormatterMatchRegex) {}
0085   /// Creates a matcher using the matching type and string from the given type
0086   /// name specifier.
0087   TypeMatcher(lldb::TypeNameSpecifierImplSP type_specifier)
0088       : m_name(type_specifier->GetName()),
0089         m_match_type(type_specifier->GetMatchType()) {
0090     if (m_match_type == lldb::eFormatterMatchRegex)
0091       m_type_name_regex = RegularExpression(type_specifier->GetName());
0092   }
0093 
0094   /// True iff this matches the given type.
0095   bool Matches(FormattersMatchCandidate candidate_type) const {
0096     ConstString type_name = candidate_type.GetTypeName();
0097     switch (m_match_type) {
0098     case lldb::eFormatterMatchExact:
0099       return m_name == type_name ||
0100              StripTypeName(m_name) == StripTypeName(type_name);
0101     case lldb::eFormatterMatchRegex:
0102       return m_type_name_regex.Execute(type_name.GetStringRef());
0103     case lldb::eFormatterMatchCallback:
0104       // CommandObjectType{Synth,Filter}Add tries to prevent the user from
0105       // creating both a synthetic child provider and a filter for the same type
0106       // in the same category, but we don't have a type object at that point, so
0107       // it creates a dummy candidate without type or script interpreter.
0108       // Skip callback matching in these cases.
0109       if (candidate_type.GetScriptInterpreter())
0110         return candidate_type.GetScriptInterpreter()->FormatterCallbackFunction(
0111             m_name.AsCString(),
0112             std::make_shared<TypeImpl>(candidate_type.GetType()));
0113     }
0114     return false;
0115   }
0116 
0117   lldb::FormatterMatchType GetMatchType() const { return m_match_type; }
0118 
0119   /// Returns the underlying match string for this TypeMatcher.
0120   ConstString GetMatchString() const {
0121     if (m_match_type == lldb::eFormatterMatchExact)
0122         return StripTypeName(m_name);
0123     if (m_match_type == lldb::eFormatterMatchRegex)
0124         return ConstString(m_type_name_regex.GetText());
0125     return m_name;
0126   }
0127 
0128   /// Returns true if this TypeMatcher and the given one were most created by
0129   /// the same match string.
0130   /// The main purpose of this function is to find existing TypeMatcher
0131   /// instances by the user input that created them. This is necessary as LLDB
0132   /// allows referencing existing TypeMatchers in commands by the user input
0133   /// that originally created them:
0134   /// (lldb) type summary add --summary-string \"A\" -x TypeName
0135   /// (lldb) type summary delete TypeName
0136   bool CreatedBySameMatchString(TypeMatcher other) const {
0137     return GetMatchString() == other.GetMatchString();
0138   }
0139 };
0140 
0141 template <typename ValueType> class FormattersContainer {
0142 public:
0143   typedef typename std::shared_ptr<ValueType> ValueSP;
0144   typedef std::vector<std::pair<TypeMatcher, ValueSP>> MapType;
0145   typedef std::function<bool(const TypeMatcher &, const ValueSP &)>
0146       ForEachCallback;
0147   typedef typename std::shared_ptr<FormattersContainer<ValueType>>
0148       SharedPointer;
0149 
0150   friend class TypeCategoryImpl;
0151 
0152   FormattersContainer(IFormatChangeListener *lst) : listener(lst) {}
0153 
0154   void Add(TypeMatcher matcher, const ValueSP &entry) {
0155     if (listener)
0156       entry->GetRevision() = listener->GetCurrentRevision();
0157     else
0158       entry->GetRevision() = 0;
0159 
0160     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0161     Delete(matcher);
0162     m_map.emplace_back(std::move(matcher), std::move(entry));
0163     if (listener)
0164       listener->Changed();
0165   }
0166 
0167   bool Delete(TypeMatcher matcher) {
0168     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0169     for (auto iter = m_map.begin(); iter != m_map.end(); ++iter)
0170       if (iter->first.CreatedBySameMatchString(matcher)) {
0171         m_map.erase(iter);
0172         if (listener)
0173           listener->Changed();
0174         return true;
0175       }
0176     return false;
0177   }
0178 
0179   // Finds the first formatter in the container that matches `candidate`.
0180   bool Get(FormattersMatchCandidate candidate, ValueSP &entry) {
0181     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0182     for (auto &formatter : llvm::reverse(m_map)) {
0183       if (formatter.first.Matches(candidate)) {
0184         entry = formatter.second;
0185         return true;
0186       }
0187     }
0188     return false;
0189   }
0190 
0191   // Finds the first match between candidate types in `candidates` and
0192   // formatters in this container.
0193   bool Get(const FormattersMatchVector &candidates, ValueSP &entry) {
0194     for (const FormattersMatchCandidate &candidate : candidates) {
0195       if (Get(candidate, entry)) {
0196         if (candidate.IsMatch(entry) == false) {
0197           entry.reset();
0198           continue;
0199         } else {
0200           return true;
0201         }
0202       }
0203     }
0204     return false;
0205   }
0206 
0207   bool GetExact(TypeMatcher matcher, ValueSP &entry) {
0208     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0209     for (const auto &pos : m_map)
0210       if (pos.first.CreatedBySameMatchString(matcher)) {
0211         entry = pos.second;
0212         return true;
0213       }
0214     return false;
0215   }
0216 
0217   ValueSP GetAtIndex(size_t index) {
0218     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0219     if (index >= m_map.size())
0220       return ValueSP();
0221     return m_map[index].second;
0222   }
0223 
0224   lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
0225     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0226     if (index >= m_map.size())
0227       return lldb::TypeNameSpecifierImplSP();
0228     TypeMatcher type_matcher = m_map[index].first;
0229     return std::make_shared<TypeNameSpecifierImpl>(
0230         type_matcher.GetMatchString().GetStringRef(),
0231         type_matcher.GetMatchType());
0232   }
0233 
0234   void Clear() {
0235     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0236     m_map.clear();
0237     if (listener)
0238       listener->Changed();
0239   }
0240 
0241   void ForEach(ForEachCallback callback) {
0242     if (callback) {
0243       std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0244       for (const auto &pos : m_map) {
0245         const TypeMatcher &type = pos.first;
0246         if (!callback(type, pos.second))
0247           break;
0248       }
0249     }
0250   }
0251 
0252   uint32_t GetCount() {
0253     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0254     return m_map.size();
0255   }
0256 
0257   void AutoComplete(CompletionRequest &request) {
0258     ForEach([&request](const TypeMatcher &matcher, const ValueSP &value) {
0259       request.TryCompleteCurrentArg(matcher.GetMatchString().GetStringRef());
0260       return true;
0261     });
0262   }
0263 
0264 protected:
0265   FormattersContainer(const FormattersContainer &) = delete;
0266   const FormattersContainer &operator=(const FormattersContainer &) = delete;
0267 
0268   MapType m_map;
0269   std::recursive_mutex m_map_mutex;
0270   IFormatChangeListener *listener;
0271 };
0272 
0273 } // namespace lldb_private
0274 
0275 #endif // LLDB_DATAFORMATTERS_FORMATTERSCONTAINER_H