-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lldb] Refactor TypeQuery::ContextMatches #99305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -6,7 +6,9 @@ | |||||||||||
// | ||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||
|
||||||||||||
#include <algorithm> | ||||||||||||
#include <cstdio> | ||||||||||||
#include <iterator> | ||||||||||||
#include <optional> | ||||||||||||
|
||||||||||||
#include "lldb/Core/Module.h" | ||||||||||||
|
@@ -30,6 +32,7 @@ | |||||||||||
#include "lldb/Target/Process.h" | ||||||||||||
#include "lldb/Target/Target.h" | ||||||||||||
#include "lldb/lldb-enumerations.h" | ||||||||||||
#include "lldb/lldb-private-enumerations.h" | ||||||||||||
|
||||||||||||
#include "llvm/ADT/StringRef.h" | ||||||||||||
|
||||||||||||
|
@@ -43,35 +46,6 @@ llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &os, | |||||||||||
return os << lldb_stream.GetString(); | ||||||||||||
} | ||||||||||||
|
||||||||||||
bool lldb_private::contextMatches(llvm::ArrayRef<CompilerContext> context_chain, | ||||||||||||
llvm::ArrayRef<CompilerContext> pattern) { | ||||||||||||
auto ctx = context_chain.begin(); | ||||||||||||
auto ctx_end = context_chain.end(); | ||||||||||||
for (const CompilerContext &pat : pattern) { | ||||||||||||
// Early exit if the pattern is too long. | ||||||||||||
if (ctx == ctx_end) | ||||||||||||
return false; | ||||||||||||
if (*ctx != pat) { | ||||||||||||
// Skip any number of module matches. | ||||||||||||
if (pat.kind == CompilerContextKind::AnyModule) { | ||||||||||||
// Greedily match 0..n modules. | ||||||||||||
ctx = std::find_if(ctx, ctx_end, [](const CompilerContext &ctx) { | ||||||||||||
return ctx.kind != CompilerContextKind::Module; | ||||||||||||
}); | ||||||||||||
continue; | ||||||||||||
} | ||||||||||||
// See if there is a kind mismatch; they should have 1 bit in common. | ||||||||||||
if (((uint16_t)ctx->kind & (uint16_t)pat.kind) == 0) | ||||||||||||
return false; | ||||||||||||
// The name is ignored for AnyModule, but not for AnyType. | ||||||||||||
if (pat.kind != CompilerContextKind::AnyModule && ctx->name != pat.name) | ||||||||||||
return false; | ||||||||||||
} | ||||||||||||
++ctx; | ||||||||||||
} | ||||||||||||
return true; | ||||||||||||
} | ||||||||||||
|
||||||||||||
static CompilerContextKind ConvertTypeClass(lldb::TypeClass type_class) { | ||||||||||||
if (type_class == eTypeClassAny) | ||||||||||||
return CompilerContextKind::AnyType; | ||||||||||||
|
@@ -153,19 +127,89 @@ void TypeQuery::SetLanguages(LanguageSet languages) { | |||||||||||
|
||||||||||||
bool TypeQuery::ContextMatches( | ||||||||||||
llvm::ArrayRef<CompilerContext> context_chain) const { | ||||||||||||
if (GetExactMatch() || context_chain.size() == m_context.size()) | ||||||||||||
return ::contextMatches(context_chain, m_context); | ||||||||||||
|
||||||||||||
// We don't have an exact match, we need to bottom m_context.size() items to | ||||||||||||
// match for a successful lookup. | ||||||||||||
if (context_chain.size() < m_context.size()) | ||||||||||||
return false; // Not enough items in context_chain to allow for a match. | ||||||||||||
|
||||||||||||
size_t compare_count = context_chain.size() - m_context.size(); | ||||||||||||
return ::contextMatches( | ||||||||||||
llvm::ArrayRef<CompilerContext>(context_chain.data() + compare_count, | ||||||||||||
m_context.size()), | ||||||||||||
m_context); | ||||||||||||
auto ctx = context_chain.rbegin(), ctx_end = context_chain.rend(); | ||||||||||||
for (auto pat = m_context.rbegin(), pat_end = m_context.rend(); | ||||||||||||
pat != pat_end;) { | ||||||||||||
|
||||||||||||
// Handle AnyModule matches. These are tricky as they can match any number | ||||||||||||
// of modules. | ||||||||||||
if (pat->kind == CompilerContextKind::AnyModule) { | ||||||||||||
// Successive wildcards are equivalent to a single wildcard. | ||||||||||||
while (pat->kind == CompilerContextKind::AnyModule) | ||||||||||||
++pat; | ||||||||||||
|
||||||||||||
// [ctx, ctx_module_end) is the range of entries that may be matched by | ||||||||||||
// our wildcard. | ||||||||||||
auto ctx_module_end = | ||||||||||||
std::find_if(ctx, ctx_end, [](const CompilerContext &c) { | ||||||||||||
return c.kind != CompilerContextKind::Module; | ||||||||||||
}); | ||||||||||||
|
||||||||||||
// [pat, exact_pat_end) is the range of exact module match patterns. If | ||||||||||||
// it's not empty, we need to make sure our wildcard does not consume | ||||||||||||
// entries matched by those. | ||||||||||||
auto exact_pat_end = | ||||||||||||
std::find_if(pat, pat_end, [](const CompilerContext &p) { | ||||||||||||
return (p.kind & CompilerContextKind::AnyModule) != | ||||||||||||
CompilerContextKind::Module; | ||||||||||||
Comment on lines
+152
to
+154
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't this just be:
Suggested change
Since we've already skipped all the |
||||||||||||
}); | ||||||||||||
|
||||||||||||
if (pat == exact_pat_end) { | ||||||||||||
// No exact matches, just consume everything. | ||||||||||||
ctx = ctx_module_end; | ||||||||||||
continue; | ||||||||||||
} | ||||||||||||
|
||||||||||||
// We have a non-empty module sequence after the wildcard. Now we need to | ||||||||||||
// look at what comes *after* that. If that's another wildcard, we want | ||||||||||||
// *this* wildcard to match as little as possible to give the other | ||||||||||||
// wildcard (and whatever comes after it) as much freedom as possible. If | ||||||||||||
// it's *not* another wildcard (we've reached the end of the pattern, or | ||||||||||||
// we have some non-module patterns after this), we want to match as much | ||||||||||||
// as possible, as there will be nothing left to match any remaining | ||||||||||||
// module entries. | ||||||||||||
bool greedy_match = exact_pat_end == pat_end || | ||||||||||||
exact_pat_end->kind != CompilerContextKind::AnyModule; | ||||||||||||
|
||||||||||||
auto pred = [](const CompilerContext &c, const CompilerContext &p) { | ||||||||||||
return c.name == p.name; | ||||||||||||
}; | ||||||||||||
auto pos = | ||||||||||||
greedy_match | ||||||||||||
? std::find_end(ctx, ctx_module_end, pat, exact_pat_end, pred) | ||||||||||||
: std::search(ctx, ctx_module_end, pat, exact_pat_end, pred); | ||||||||||||
|
||||||||||||
if (pos == ctx_module_end) | ||||||||||||
return false; // Matching failed. | ||||||||||||
|
||||||||||||
// We've successfully matched the wildcard and the exact-module sequence | ||||||||||||
// that comes after it. | ||||||||||||
ctx = std::next(pos, std::distance(pat, exact_pat_end)); | ||||||||||||
pat = exact_pat_end; | ||||||||||||
continue; | ||||||||||||
} | ||||||||||||
|
||||||||||||
if (ctx == ctx_end) | ||||||||||||
return false; // Pattern too long. | ||||||||||||
|
||||||||||||
// See if there is a kind mismatch; they should have 1 bit in common. | ||||||||||||
if ((ctx->kind & pat->kind) == CompilerContextKind()) | ||||||||||||
return false; | ||||||||||||
|
||||||||||||
if (ctx->name != pat->name) | ||||||||||||
return false; | ||||||||||||
|
||||||||||||
++ctx; | ||||||||||||
++pat; | ||||||||||||
} | ||||||||||||
|
||||||||||||
// At this point, we have exhausted the pattern and we have a partial match at | ||||||||||||
// least. If that's all we're looking for, we're done. | ||||||||||||
if (!GetExactMatch()) | ||||||||||||
return true; | ||||||||||||
|
||||||||||||
// We have an exact match if we've exhausted the target context as well. | ||||||||||||
return ctx == ctx_end; | ||||||||||||
} | ||||||||||||
|
||||||||||||
bool TypeQuery::LanguageMatches(lldb::LanguageType language) const { | ||||||||||||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know why
AnyModule
allows for this wildcard behaviour? I don't see it used anywhere, only exactModule
matchesThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a very good question actually. I'm pretty sure we're not using it. I assumed it was being used for some Apple thing with -gmodules or whatever, but now mention that, it doesn't appear to be actually used except for some specialized tests.
So, as much as I loved implementing a glob algorithm, I would love even more to delete it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually just grepped for this in the
apple/llvm-project
fork and looks like we're using it in the Swift plugin: https://github.com/swiftlang/llvm-project/blob/ee8bc8b8d30eb99807adbcd3c1f044e00af66cdd/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp#L219-L225@adrian-prantl @augusto2112 @kastiglione could you elaborate on the usage of this lookup-type here and why it's needed? An unfortunate side-effect of only having it be exercised in the Swift plugin is that we need to support this non-trivial matching algorithm while having the tests in a different repo.
That being said, I don't want to block this PR on this question, since the change itself LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with waiting, as this is a non-trivial piece of code, and if that's the only use case, then we can probably come up with something simpler. For example, some new TypeQuery flag which basically says "exact match except for modules" (that's something we may want to do for anonymous namespaces as well).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
Generally, it seems like following two concepts have been conflated in
CompilerDeclContextKind
: having wildcards in a TypeQuery versus matching two entities regardless of DeclContextKind (e.g., if a union or enum have the same name, thenAnyType
would allow a match). And as you say, having the wildcard behaviour live separately would make theCompilerDeclContextKind
easier to understand again.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm... Ping? Do we still need to wait for opinions from @adrian-prantl @augusto2112 @kastiglione or should I just go ahead and implement the simplified version?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adrian-prantl was OOO for a couple of weeks, but should be back today. Not sure he'll see this today though (I suspect the review queue might be quite high). I can help run the swift plugin tests if you end up refactoring this. Think it would also be fine to merge this and rework it afterwards. Whatever you prefer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try to create simplified version of the patch (probably tomorrow). I'd appreciate if you could give it a spin.