[Lldb-commits] [lldb] Make only one function that needs to be implemented when searching for types (PR #74786)

Will Hawkins via lldb-commits lldb-commits at lists.llvm.org
Fri Dec 8 23:20:04 PST 2023


================
@@ -45,6 +66,286 @@ struct CompilerContext {
 bool contextMatches(llvm::ArrayRef<CompilerContext> context_chain,
                     llvm::ArrayRef<CompilerContext> pattern);
 
+FLAGS_ENUM(TypeQueryOptions){
+    e_none = 0u,
+    /// If set TypeQuery::m_context contains an exact context that must match
+    /// the full context. If not set TypeQuery::m_context can contain a partial
+    /// type match where the full context isn't fully specified.
+    e_exact_match = (1u << 0),
+    /// If set, TypeQuery::m_context is a clang module compiler context. If not
+    /// set TypeQuery::m_context is normal type lookup context.
+    e_module_search = (1u << 1),
+    /// When true, the find types call should stop the query as soon as a single
+    /// matching type is found. When false, the type query should find all
+    /// matching types.
+    e_find_one = (1u << 2),
+};
+LLDB_MARK_AS_BITMASK_ENUM(TypeQueryOptions)
+
+/// A class that contains all state required for type lookups.
+///
+/// Using a TypeQuery class for matching types simplifies the internal APIs we
+/// need to implement type lookups in LLDB. Type lookups can fully specify the
+/// exact typename by filling out a complete or partial CompilerContext array.
+/// This allows for powerful searches and also allows the SymbolFile classes to
+/// use the m_context array to lookup types by basename, then eliminate
+/// potential matches without having to resolve types into each TypeSystem. This
+/// makes type lookups vastly more efficient and allows the SymbolFile objects
+/// to stop looking up types when the type matching is complete, like if we are
+/// looking for only a single type in our search.
+class TypeQuery {
+public:
+  TypeQuery() = delete;
+
+  /// Construct a type match object using a fully or partially qualified name.
+  ///
+  /// The specified \a type_name will be chopped up and the m_context will be
+  /// populated by separating the string by looking for "::". We do this because
+  /// symbol files have indexes that contain only the type's basename. This also
+  /// allows symbol files to efficiently not realize types that don't match the
+  /// specified context. Example of \a type_name values that can be specified
+  /// include:
+  ///   "foo": Look for any type whose basename matches "foo".
+  ///     If \a exact_match is true, then the type can't be contained in any
+  ///     declaration context like a namespace, class, or other containing
+  ///     scope.
+  ///     If \a exact match is false, then we will find all matches including
+  ///     ones that are contained in other declaration contexts, including top
+  ///     level types.
+  ///   "foo::bar": Look for any type whose basename matches "bar" but make sure
+  ///     its parent declaration context is any named declaration context
+  ///     (namespace, class, struct, etc) whose name matches "foo".
+  ///     If \a exact_match is true, then the "foo" declaration context must
+  ///     appear at the source file level or inside of a function.
+  ///     If \a exact match is false, then the "foo" declaration context can
+  ///     be contained in any other declaration contexts.
+  ///   "class foo": Only match types that are classes whose basename matches
+  ///     "foo".
+  ///   "struct foo": Only match types that are structures whose basename
+  ///     matches "foo".
+  ///   "class foo::bar": Only match types that are classes whose basename
+  ///     matches "bar" and that are contained in any named declaration context
+  ///     named "foo".
+  ///
+  /// \param[in] type_name
+  ///   A fully or partially qualified type name. This name will be parsed and
+  ///   broken up and the m_context will be populated with the various parts of
+  ///   the name. This typename can be prefixed with "struct ", "class ",
+  ///   "union", "enum " or "typedef " before the actual type name to limit the
+  ///   results of the types that match. The declaration context can be
+  ///   specified with the "::" string. like "a::b::my_type".
+  ///
+  /// \param[in] options A set of boolean enumeration flags from the
+  ///   TypeQueryOptions enumerations. \see TypeQueryOptions.
+  TypeQuery(llvm::StringRef name, TypeQueryOptions options = e_none);
+
+  /// Construct a type match object that matches a type basename that exists
+  /// in the specified declaration context.
+  ///
+  /// This allows the m_context to be first populated using a declaration
+  /// context to exactly identify the containing declaration context of a type.
+  /// This can be used when you have a forward declaration to a type and you
+  /// need to search for its complete type.
+  ///
+  /// \param[in] decl_ctx
+  ///   A declaration context object that comes from a TypeSystem plug-in. This
+  ///   object will be asked to full the array of CompilerContext objects
+  ///   by adding the top most declaration context first into the array and then
+  ///   adding any containing declaration contexts.
+  ///
+  /// \param[in] type_basename
+  ///   The basename of the type to lookup in the specified declaration context.
+  ///
+  /// \param[in] options A set of boolean enumeration flags from the
+  ///   TypeQueryOptions enumerations. \see TypeQueryOptions.
+  TypeQuery(const CompilerDeclContext &decl_ctx, ConstString type_basename,
+            TypeQueryOptions options = e_none);
+  /// Construct a type match object using a compiler declaration that specifies
+  /// a typename and a declaration context to use when doing exact type lookups.
+  ///
+  /// This allows the m_context to be first populated using a type declaration.
+  /// The type declaration might have a declaration context and each TypeSystem
+  /// plug-in can populate the declaration context needed to perform an exact
+  /// lookup for a type.
+  /// This can be used when you have a forward declaration to a type and you
+  /// need to search for its complete type.
+  ///
+  /// \param[in] decl
+  ///   A type declaration context object that comes from a TypeSystem plug-in.
+  ///   This object will be asked to full the array of CompilerContext objects
+  ///   by adding the top most declaration context first into the array and then
+  ///   adding any containing declaration contexts, and ending with the exact
+  ///   typename and the kind of type it is (class, struct, union, enum, etc).
+  ///
+  /// \param[in] options A set of boolean enumeration flags from the
+  ///   TypeQueryOptions enumerations. \see TypeQueryOptions.
+  TypeQuery(const CompilerDecl &decl, TypeQueryOptions options = e_none);
+
+  /// Construct a type match object using a CompilerContext array.
+  ///
+  /// Clients can manually create compiler contexts and use these to find
+  /// matches when searching for types. There are two types of contexts that
+  /// are supported when doing type searchs: type contexts and clang module
+  /// contexts. Type contexts have contexts that specify the type and its
+  /// containing declaration context like namespaces and classes. Clang module
+  /// contexts specify contexts more completely to find exact matches within
+  /// clang module debug information. They will include the modules that the
+  /// type is included in and any functions that the type might be defined in.
+  /// This allows very fine grained type resolution.
----------------
hawkinsw wrote:

```suggestion
  /// This allows very fine-grained type resolution.
```

https://github.com/llvm/llvm-project/pull/74786


More information about the lldb-commits mailing list