Skip to content

Commit 212950f

Browse files
authored
[lldb] Refactor TypeQuery::ContextMatches, take 2 (llvm#101333)
This is an alternative, much simpler implementation of llvm#99305. In this version I replace the AnyModule wildcard match with a special TypeQuery flag which achieves (mostly) the same thing. It is a preparatory step for teaching ContextMatches about anonymous namespaces. It started out as a way to remove the assumption that the pattern and target contexts must be of the same length -- that's will not be correct with anonymous namespaces, and probably isn't even correct right now for AnyModule matches.
1 parent 6848b99 commit 212950f

File tree

7 files changed

+121
-97
lines changed

7 files changed

+121
-97
lines changed

lldb/include/lldb/Symbol/Type.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,6 @@ struct CompilerContext {
6565
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
6666
const CompilerContext &rhs);
6767

68-
/// Match \p context_chain against \p pattern, which may contain "Any"
69-
/// kinds. The \p context_chain should *not* contain any "Any" kinds.
70-
bool contextMatches(llvm::ArrayRef<CompilerContext> context_chain,
71-
llvm::ArrayRef<CompilerContext> pattern);
72-
7368
FLAGS_ENUM(TypeQueryOptions){
7469
e_none = 0u,
7570
/// If set, TypeQuery::m_context contains an exact context that must match
@@ -79,10 +74,13 @@ FLAGS_ENUM(TypeQueryOptions){
7974
/// If set, TypeQuery::m_context is a clang module compiler context. If not
8075
/// set TypeQuery::m_context is normal type lookup context.
8176
e_module_search = (1u << 1),
77+
/// If set, the query will ignore all Module entries in the type context,
78+
/// even for exact matches.
79+
e_ignore_modules = (1u << 2),
8280
/// When true, the find types call should stop the query as soon as a single
8381
/// matching type is found. When false, the type query should find all
8482
/// matching types.
85-
e_find_one = (1u << 2),
83+
e_find_one = (1u << 3),
8684
};
8785
LLDB_MARK_AS_BITMASK_ENUM(TypeQueryOptions)
8886

@@ -264,6 +262,10 @@ class TypeQuery {
264262
bool LanguageMatches(lldb::LanguageType language) const;
265263

266264
bool GetExactMatch() const { return (m_options & e_exact_match) != 0; }
265+
266+
bool GetIgnoreModules() const { return (m_options & e_ignore_modules) != 0; }
267+
void SetIgnoreModules() { m_options &= ~e_ignore_modules; }
268+
267269
/// The \a m_context can be used in two ways: normal types searching with
268270
/// the context containing a stanadard declaration context for a type, or
269271
/// with the context being more complete for exact matches in clang modules.

lldb/include/lldb/lldb-private-enumerations.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,6 @@ enum class CompilerContextKind : uint16_t {
207207
Builtin = 1 << 10,
208208

209209
Any = 1 << 15,
210-
/// Match 0..n nested modules.
211-
AnyModule = Any | Module,
212210
/// Match any type.
213211
AnyType = Any | ClassOrStruct | Union | Enum | Typedef | Builtin,
214212
/// Math any declaration context.

lldb/source/Symbol/Type.cpp

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include <algorithm>
910
#include <cstdio>
11+
#include <iterator>
1012
#include <optional>
1113

1214
#include "lldb/Core/Module.h"
@@ -30,6 +32,7 @@
3032
#include "lldb/Target/Process.h"
3133
#include "lldb/Target/Target.h"
3234
#include "lldb/lldb-enumerations.h"
35+
#include "lldb/lldb-private-enumerations.h"
3336

3437
#include "llvm/ADT/StringRef.h"
3538

@@ -43,35 +46,6 @@ llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &os,
4346
return os << lldb_stream.GetString();
4447
}
4548

46-
bool lldb_private::contextMatches(llvm::ArrayRef<CompilerContext> context_chain,
47-
llvm::ArrayRef<CompilerContext> pattern) {
48-
auto ctx = context_chain.begin();
49-
auto ctx_end = context_chain.end();
50-
for (const CompilerContext &pat : pattern) {
51-
// Early exit if the pattern is too long.
52-
if (ctx == ctx_end)
53-
return false;
54-
if (*ctx != pat) {
55-
// Skip any number of module matches.
56-
if (pat.kind == CompilerContextKind::AnyModule) {
57-
// Greedily match 0..n modules.
58-
ctx = std::find_if(ctx, ctx_end, [](const CompilerContext &ctx) {
59-
return ctx.kind != CompilerContextKind::Module;
60-
});
61-
continue;
62-
}
63-
// See if there is a kind mismatch; they should have 1 bit in common.
64-
if (((uint16_t)ctx->kind & (uint16_t)pat.kind) == 0)
65-
return false;
66-
// The name is ignored for AnyModule, but not for AnyType.
67-
if (pat.kind != CompilerContextKind::AnyModule && ctx->name != pat.name)
68-
return false;
69-
}
70-
++ctx;
71-
}
72-
return true;
73-
}
74-
7549
static CompilerContextKind ConvertTypeClass(lldb::TypeClass type_class) {
7650
if (type_class == eTypeClassAny)
7751
return CompilerContextKind::AnyType;
@@ -153,19 +127,36 @@ void TypeQuery::SetLanguages(LanguageSet languages) {
153127

154128
bool TypeQuery::ContextMatches(
155129
llvm::ArrayRef<CompilerContext> context_chain) const {
156-
if (GetExactMatch() || context_chain.size() == m_context.size())
157-
return ::contextMatches(context_chain, m_context);
130+
auto ctx = context_chain.rbegin(), ctx_end = context_chain.rend();
131+
for (auto pat = m_context.rbegin(), pat_end = m_context.rend();
132+
pat != pat_end;) {
133+
134+
if (ctx == ctx_end)
135+
return false; // Pattern too long.
136+
137+
// See if there is a kind mismatch; they should have 1 bit in common.
138+
if ((ctx->kind & pat->kind) == CompilerContextKind())
139+
return false;
140+
141+
if (ctx->name != pat->name)
142+
return false;
143+
144+
++ctx;
145+
++pat;
146+
}
147+
148+
// Skip over any remaining module entries if we were asked to do that.
149+
while (GetIgnoreModules() && ctx != ctx_end &&
150+
ctx->kind == CompilerContextKind::Module)
151+
++ctx;
158152

159-
// We don't have an exact match, we need to bottom m_context.size() items to
160-
// match for a successful lookup.
161-
if (context_chain.size() < m_context.size())
162-
return false; // Not enough items in context_chain to allow for a match.
153+
// At this point, we have exhausted the pattern and we have a partial match at
154+
// least. If that's all we're looking for, we're done.
155+
if (!GetExactMatch())
156+
return true;
163157

164-
size_t compare_count = context_chain.size() - m_context.size();
165-
return ::contextMatches(
166-
llvm::ArrayRef<CompilerContext>(context_chain.data() + compare_count,
167-
m_context.size()),
168-
m_context);
158+
// We have an exact match if we've exhausted the target context as well.
159+
return ctx == ctx_end;
169160
}
170161

171162
bool TypeQuery::LanguageMatches(lldb::LanguageType language) const {
@@ -223,9 +214,6 @@ void CompilerContext::Dump(Stream &s) const {
223214
case CompilerContextKind::Typedef:
224215
s << "Typedef";
225216
break;
226-
case CompilerContextKind::AnyModule:
227-
s << "AnyModule";
228-
break;
229217
case CompilerContextKind::AnyType:
230218
s << "AnyType";
231219
break;

lldb/test/Shell/SymbolFile/DWARF/clang-gmodules-type-lookup.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
// RUN: %clangxx_host -g -gmodules -fmodules -std=c99 -x c-header %S/Inputs/pch.h -g -c -o %t.pch
77
// RUN: %clangxx_host -g -gmodules -fmodules -std=c99 -x c -include-pch %t.pch %s -c -o %t.o
88
// RUN: %clangxx_host %t.o -o %t.exe
9-
// RUN: lldb-test symbols -dump-clang-ast -find type --language=C99 \
10-
// RUN: -compiler-context 'AnyModule:*,ClassOrStruct:TypeFromPCH' %t.exe | FileCheck %s
9+
// RUN: lldb-test symbols -dump-clang-ast -find type --find-in-any-module \
10+
// RUN: --language=C99 -compiler-context 'ClassOrStruct:TypeFromPCH' \
11+
// RUN: %t.exe | FileCheck %s
1112

1213
anchor_t anchor;
1314

lldb/test/Shell/SymbolFile/DWARF/x86/compilercontext.ll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@
99
; RUN: lldb-test symbols %t.o -find=type --language=C99 \
1010
; RUN: -compiler-context="Module:CModule,Module:SubModule,ClassOrStruct:FromSubmodule" \
1111
; RUN: | FileCheck %s
12-
; RUN: lldb-test symbols %t.o -find=type --language=C99 \
13-
; RUN: -compiler-context="Module:CModule,AnyModule:*,ClassOrStruct:FromSubmodule" \
14-
; RUN: | FileCheck %s
15-
; RUN: lldb-test symbols %t.o -find=type --language=C99 \
16-
; RUN: -compiler-context="AnyModule:*,ClassOrStruct:FromSubmodule" \
12+
; RUN: lldb-test symbols %t.o -find=type -find-in-any-module --language=C99 \
13+
; RUN: -compiler-context="ClassOrStruct:FromSubmodule" \
1714
; RUN: | FileCheck %s
1815
; RUN: lldb-test symbols %t.o -find=type --language=C99 \
1916
; RUN: -compiler-context="Module:CModule,Module:SubModule,AnyType:FromSubmodule" \

lldb/tools/lldb-test/lldb-test.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ static cl::opt<std::string> CompilerContext(
194194
cl::desc("Specify a compiler context as \"kind:name,...\"."),
195195
cl::value_desc("context"), cl::sub(SymbolsSubcommand));
196196

197+
static cl::opt<bool> FindInAnyModule(
198+
"find-in-any-module",
199+
cl::desc("If true, the type will be searched for in all modules. Otherwise "
200+
"the modules must be provided in -compiler-context"),
201+
cl::sub(SymbolsSubcommand));
202+
197203
static cl::opt<std::string>
198204
Language("language", cl::desc("Specify a language type, like C99."),
199205
cl::value_desc("language"), cl::sub(SymbolsSubcommand));
@@ -312,7 +318,6 @@ llvm::SmallVector<CompilerContext, 4> parseCompilerContext() {
312318
.Case("Variable", CompilerContextKind::Variable)
313319
.Case("Enum", CompilerContextKind::Enum)
314320
.Case("Typedef", CompilerContextKind::Typedef)
315-
.Case("AnyModule", CompilerContextKind::AnyModule)
316321
.Case("AnyType", CompilerContextKind::AnyType)
317322
.Default(CompilerContextKind::Invalid);
318323
if (value.empty()) {
@@ -581,11 +586,13 @@ Error opts::symbols::findTypes(lldb_private::Module &Module) {
581586
if (!ContextOr)
582587
return ContextOr.takeError();
583588

589+
TypeQueryOptions Opts = TypeQueryOptions::e_module_search;
590+
if (FindInAnyModule)
591+
Opts |= TypeQueryOptions::e_ignore_modules;
584592
TypeResults results;
585593
if (!Name.empty()) {
586594
if (ContextOr->IsValid()) {
587-
TypeQuery query(*ContextOr, ConstString(Name),
588-
TypeQueryOptions::e_module_search);
595+
TypeQuery query(*ContextOr, ConstString(Name), Opts);
589596
if (!Language.empty())
590597
query.AddLanguage(Language::GetLanguageTypeFromString(Language));
591598
Symfile.FindTypes(query, results);
@@ -596,7 +603,7 @@ Error opts::symbols::findTypes(lldb_private::Module &Module) {
596603
Symfile.FindTypes(query, results);
597604
}
598605
} else {
599-
TypeQuery query(parseCompilerContext(), TypeQueryOptions::e_module_search);
606+
TypeQuery query(parseCompilerContext(), Opts);
600607
if (!Language.empty())
601608
query.AddLanguage(Language::GetLanguageTypeFromString(Language));
602609
Symfile.FindTypes(query, results);
@@ -816,6 +823,9 @@ Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
816823
if (Regex && Name.empty())
817824
return make_string_error("-regex used without a -name");
818825

826+
if (FindInAnyModule && (Find != FindType::Type))
827+
return make_string_error("-find-in-any-module only works with -find=type");
828+
819829
switch (Find) {
820830
case FindType::None:
821831
if (!Context.empty() || !Name.empty() || !File.empty() || Line != 0)

lldb/unittests/Symbol/TestType.cpp

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
//
88
//===----------------------------------------------------------------------===//
99

10+
#include "gmock/gmock.h"
1011
#include "gtest/gtest.h"
1112

1213
#include "lldb/Symbol/Type.h"
1314
#include "lldb/lldb-enumerations.h"
15+
#include "lldb/lldb-private-enumerations.h"
1416

1517
using namespace lldb;
1618
using namespace lldb_private;
19+
using testing::Not;
1720

1821
TEST(Type, GetTypeScopeAndBasename) {
1922
EXPECT_EQ(Type::GetTypeScopeAndBasename("int"),
@@ -47,40 +50,65 @@ TEST(Type, GetTypeScopeAndBasename) {
4750
EXPECT_EQ(Type::GetTypeScopeAndBasename("foo<::bar"), std::nullopt);
4851
}
4952

53+
namespace {
54+
MATCHER_P(Matches, pattern, "") {
55+
TypeQuery query(pattern, TypeQueryOptions::e_none);
56+
return query.ContextMatches(arg);
57+
}
58+
MATCHER_P(MatchesIgnoringModules, pattern, "") {
59+
TypeQuery query(pattern, TypeQueryOptions::e_ignore_modules);
60+
return query.ContextMatches(arg);
61+
}
62+
} // namespace
63+
5064
TEST(Type, CompilerContextPattern) {
51-
std::vector<CompilerContext> mmc = {
52-
{CompilerContextKind::Module, ConstString("A")},
53-
{CompilerContextKind::Module, ConstString("B")},
54-
{CompilerContextKind::ClassOrStruct, ConstString("S")}};
55-
std::vector<CompilerContext> mc = {
56-
{CompilerContextKind::Module, ConstString("A")},
57-
{CompilerContextKind::ClassOrStruct, ConstString("S")}};
58-
std::vector<CompilerContext> mac = {
59-
{CompilerContextKind::Module, ConstString("A")},
60-
{CompilerContextKind::AnyModule, ConstString("*")},
61-
{CompilerContextKind::ClassOrStruct, ConstString("S")}};
62-
EXPECT_TRUE(contextMatches(mmc, mac));
63-
EXPECT_TRUE(contextMatches(mc, mac));
64-
EXPECT_FALSE(contextMatches(mac, mc));
65-
std::vector<CompilerContext> mmmc = {
66-
{CompilerContextKind::Module, ConstString("A")},
67-
{CompilerContextKind::Module, ConstString("B")},
68-
{CompilerContextKind::Module, ConstString("C")},
69-
{CompilerContextKind::ClassOrStruct, ConstString("S")}};
70-
EXPECT_TRUE(contextMatches(mmmc, mac));
71-
std::vector<CompilerContext> mme = {
72-
{CompilerContextKind::Module, ConstString("A")},
73-
{CompilerContextKind::Module, ConstString("B")},
74-
{CompilerContextKind::Enum, ConstString("S")}};
75-
std::vector<CompilerContext> mma = {
76-
{CompilerContextKind::Module, ConstString("A")},
77-
{CompilerContextKind::Module, ConstString("B")},
78-
{CompilerContextKind::AnyType, ConstString("S")}};
79-
EXPECT_TRUE(contextMatches(mme, mma));
80-
EXPECT_TRUE(contextMatches(mmc, mma));
81-
std::vector<CompilerContext> mme2 = {
82-
{CompilerContextKind::Module, ConstString("A")},
83-
{CompilerContextKind::Module, ConstString("B")},
84-
{CompilerContextKind::Enum, ConstString("S2")}};
85-
EXPECT_FALSE(contextMatches(mme2, mma));
65+
auto make_module = [](llvm::StringRef name) {
66+
return CompilerContext(CompilerContextKind::Module, ConstString(name));
67+
};
68+
auto make_class = [](llvm::StringRef name) {
69+
return CompilerContext(CompilerContextKind::ClassOrStruct,
70+
ConstString(name));
71+
};
72+
auto make_any_type = [](llvm::StringRef name) {
73+
return CompilerContext(CompilerContextKind::AnyType, ConstString(name));
74+
};
75+
auto make_enum = [](llvm::StringRef name) {
76+
return CompilerContext(CompilerContextKind::Enum, ConstString(name));
77+
};
78+
auto make_namespace = [](llvm::StringRef name) {
79+
return CompilerContext(CompilerContextKind::Namespace, ConstString(name));
80+
};
81+
82+
EXPECT_THAT(
83+
(std::vector{make_module("A"), make_module("B"), make_class("C")}),
84+
Matches(
85+
std::vector{make_module("A"), make_module("B"), make_class("C")}));
86+
EXPECT_THAT(
87+
(std::vector{make_module("A"), make_module("B"), make_class("C")}),
88+
Not(Matches(std::vector{make_class("C")})));
89+
EXPECT_THAT(
90+
(std::vector{make_module("A"), make_module("B"), make_class("C")}),
91+
MatchesIgnoringModules(std::vector{make_class("C")}));
92+
EXPECT_THAT(
93+
(std::vector{make_module("A"), make_module("B"), make_class("C")}),
94+
MatchesIgnoringModules(std::vector{make_module("B"), make_class("C")}));
95+
EXPECT_THAT(
96+
(std::vector{make_module("A"), make_module("B"), make_class("C")}),
97+
Not(MatchesIgnoringModules(
98+
std::vector{make_module("A"), make_class("C")})));
99+
EXPECT_THAT((std::vector{make_module("A"), make_module("B"), make_enum("C")}),
100+
Matches(std::vector{make_module("A"), make_module("B"),
101+
make_any_type("C")}));
102+
EXPECT_THAT(
103+
(std::vector{make_module("A"), make_module("B"), make_class("C")}),
104+
Matches(
105+
std::vector{make_module("A"), make_module("B"), make_any_type("C")}));
106+
EXPECT_THAT(
107+
(std::vector{make_module("A"), make_module("B"), make_enum("C2")}),
108+
Not(Matches(std::vector{make_module("A"), make_module("B"),
109+
make_any_type("C")})));
110+
EXPECT_THAT((std::vector{make_class("C")}),
111+
Matches(std::vector{make_class("C")}));
112+
EXPECT_THAT((std::vector{make_namespace("NS"), make_class("C")}),
113+
Not(Matches(std::vector{make_any_type("C")})));
86114
}

0 commit comments

Comments
 (0)