1 //===-- FormatClasses.h -----------------------------------------*- 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 #ifndef LLDB_DATAFORMATTERS_FORMATCLASSES_H
10 #define LLDB_DATAFORMATTERS_FORMATCLASSES_H
11 
12 #include <functional>
13 #include <memory>
14 #include <string>
15 #include <vector>
16 
17 #include "lldb/DataFormatters/TypeFormat.h"
18 #include "lldb/DataFormatters/TypeSummary.h"
19 #include "lldb/DataFormatters/TypeSynthetic.h"
20 #include "lldb/Interpreter/ScriptInterpreter.h"
21 #include "lldb/Symbol/CompilerType.h"
22 #include "lldb/Symbol/Type.h"
23 #include "lldb/lldb-enumerations.h"
24 #include "lldb/lldb-public.h"
25 
26 namespace lldb_private {
27 
28 class HardcodedFormatters {
29 public:
30   template <typename FormatterType>
31   using HardcodedFormatterFinder =
32       std::function<typename FormatterType::SharedPointer(
33           lldb_private::ValueObject &, lldb::DynamicValueType,
34           FormatManager &)>;
35 
36   template <typename FormatterType>
37   using HardcodedFormatterFinders =
38       std::vector<HardcodedFormatterFinder<FormatterType>>;
39 
40   typedef HardcodedFormatterFinders<TypeFormatImpl> HardcodedFormatFinder;
41   typedef HardcodedFormatterFinders<TypeSummaryImpl> HardcodedSummaryFinder;
42   typedef HardcodedFormatterFinders<SyntheticChildren> HardcodedSyntheticFinder;
43 };
44 
45 class FormattersMatchCandidate {
46 public:
47   // Contains flags to indicate how this candidate was generated (e.g. if
48   // typedefs were stripped, or pointers were skipped). These are later compared
49   // to flags in formatters to confirm a string match.
50   struct Flags {
51     bool stripped_pointer = false;
52     bool stripped_reference = false;
53     bool stripped_typedef = false;
54 
55     // Returns a copy of this with the "stripped pointer" flag set.
WithStrippedPointerFlags56     Flags WithStrippedPointer() {
57       Flags result(*this);
58       result.stripped_pointer = true;
59       return result;
60     }
61 
62     // Returns a copy of this with the "stripped reference" flag set.
WithStrippedReferenceFlags63     Flags WithStrippedReference() {
64       Flags result(*this);
65       result.stripped_reference = true;
66       return result;
67     }
68 
69     // Returns a copy of this with the "stripped typedef" flag set.
WithStrippedTypedefFlags70     Flags WithStrippedTypedef() {
71       Flags result(*this);
72       result.stripped_typedef = true;
73       return result;
74     }
75   };
76 
FormattersMatchCandidate(ConstString name,ScriptInterpreter * script_interpreter,TypeImpl type,Flags flags)77   FormattersMatchCandidate(ConstString name,
78                            ScriptInterpreter *script_interpreter, TypeImpl type,
79                            Flags flags)
80       : m_type_name(name), m_script_interpreter(script_interpreter),
81         m_type(type), m_flags(flags) {}
82 
83   ~FormattersMatchCandidate() = default;
84 
GetTypeName()85   ConstString GetTypeName() const { return m_type_name; }
86 
GetType()87   TypeImpl GetType() const { return m_type; }
88 
GetScriptInterpreter()89   ScriptInterpreter *GetScriptInterpreter() const {
90     return m_script_interpreter;
91   }
92 
DidStripPointer()93   bool DidStripPointer() const { return m_flags.stripped_pointer; }
94 
DidStripReference()95   bool DidStripReference() const { return m_flags.stripped_reference; }
96 
DidStripTypedef()97   bool DidStripTypedef() const { return m_flags.stripped_typedef; }
98 
99   template <class Formatter>
IsMatch(const std::shared_ptr<Formatter> & formatter_sp)100   bool IsMatch(const std::shared_ptr<Formatter> &formatter_sp) const {
101     if (!formatter_sp)
102       return false;
103     if (formatter_sp->Cascades() == false && DidStripTypedef())
104       return false;
105     if (formatter_sp->SkipsPointers() && DidStripPointer())
106       return false;
107     if (formatter_sp->SkipsReferences() && DidStripReference())
108       return false;
109     return true;
110   }
111 
112 private:
113   ConstString m_type_name;
114   // If a formatter provides a matching callback function, we need the script
115   // interpreter and the type object (as an argument to the callback).
116   ScriptInterpreter *m_script_interpreter;
117   TypeImpl m_type;
118   Flags m_flags;
119 };
120 
121 typedef std::vector<FormattersMatchCandidate> FormattersMatchVector;
122 typedef std::vector<lldb::LanguageType> CandidateLanguagesVector;
123 
124 class FormattersMatchData {
125 public:
126   FormattersMatchData(ValueObject &, lldb::DynamicValueType);
127 
128   FormattersMatchVector GetMatchesVector();
129 
130   ConstString GetTypeForCache();
131 
132   CandidateLanguagesVector GetCandidateLanguages();
133 
134   ValueObject &GetValueObject();
135 
136   lldb::DynamicValueType GetDynamicValueType();
137 
138 private:
139   ValueObject &m_valobj;
140   lldb::DynamicValueType m_dynamic_value_type;
141   std::pair<FormattersMatchVector, bool> m_formatters_match_vector;
142   ConstString m_type_for_cache;
143   CandidateLanguagesVector m_candidate_languages;
144 };
145 
146 class TypeNameSpecifierImpl {
147 public:
148   TypeNameSpecifierImpl() = default;
149 
TypeNameSpecifierImpl(llvm::StringRef name,lldb::FormatterMatchType match_type)150   TypeNameSpecifierImpl(llvm::StringRef name,
151                         lldb::FormatterMatchType match_type)
152       : m_match_type(match_type) {
153     m_type.m_type_name = std::string(name);
154   }
155 
156   // if constructing with a given type, we consider that a case of exact match.
TypeNameSpecifierImpl(lldb::TypeSP type)157   TypeNameSpecifierImpl(lldb::TypeSP type)
158       : m_match_type(lldb::eFormatterMatchExact) {
159     if (type) {
160       m_type.m_type_name = std::string(type->GetName().GetStringRef());
161       m_type.m_compiler_type = type->GetForwardCompilerType();
162     }
163   }
164 
TypeNameSpecifierImpl(CompilerType type)165   TypeNameSpecifierImpl(CompilerType type)
166       : m_match_type(lldb::eFormatterMatchExact) {
167     if (type.IsValid()) {
168       m_type.m_type_name.assign(type.GetTypeName().GetCString());
169       m_type.m_compiler_type = type;
170     }
171   }
172 
GetName()173   const char *GetName() {
174     if (m_type.m_type_name.size())
175       return m_type.m_type_name.c_str();
176     return nullptr;
177   }
178 
GetCompilerType()179   CompilerType GetCompilerType() {
180     if (m_type.m_compiler_type.IsValid())
181       return m_type.m_compiler_type;
182     return CompilerType();
183   }
184 
GetMatchType()185   lldb::FormatterMatchType GetMatchType() { return m_match_type; }
186 
IsRegex()187   bool IsRegex() { return m_match_type == lldb::eFormatterMatchRegex; }
188 
189 private:
190   lldb::FormatterMatchType m_match_type = lldb::eFormatterMatchExact;
191   // TODO: Replace this with TypeAndOrName.
192   struct TypeOrName {
193     std::string m_type_name;
194     CompilerType m_compiler_type;
195   };
196   TypeOrName m_type;
197 
198   TypeNameSpecifierImpl(const TypeNameSpecifierImpl &) = delete;
199   const TypeNameSpecifierImpl &
200   operator=(const TypeNameSpecifierImpl &) = delete;
201 };
202 
203 } // namespace lldb_private
204 
205 #endif // LLDB_DATAFORMATTERS_FORMATCLASSES_H
206