-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[lldb] Better matching of types in anonymous namespaces #102111
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -134,6 +134,20 @@ bool TypeQuery::ContextMatches( | |
if (ctx == ctx_end) | ||
return false; // Pattern too long. | ||
|
||
if (ctx->kind == CompilerContextKind::Namespace && ctx->name.IsEmpty()) { | ||
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. Do we need to check for 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. The anonymous namespace is detected and nullified on line 815. I'm not aware of such code, but if anyone was constructing these contexts without going through the name parser, then they'd have to make sure they use the expected (empty) encoding for anonymous namespaces. I think that's reasonable, because ensuring this when constructing the names from some kind of a structured source is easy, and noone should be parsing name strings by hand as the process is very nontrivial. They should rather call the function in this file (which will do the nullification for them). |
||
// We're matching an anonymous namespace. These are optional, so we check | ||
// if the pattern expects an anonymous namespace. | ||
if (pat->name.IsEmpty() && (pat->kind & CompilerContextKind::Namespace) == | ||
CompilerContextKind::Namespace) { | ||
// Match, advance both iterators. | ||
++pat; | ||
} | ||
// Otherwise, only advance the context to skip over the anonymous | ||
// namespace, and try matching again. | ||
++ctx; | ||
continue; | ||
} | ||
|
||
// See if there is a kind mismatch; they should have 1 bit in common. | ||
if ((ctx->kind & pat->kind) == CompilerContextKind()) | ||
return false; | ||
|
@@ -145,10 +159,16 @@ bool TypeQuery::ContextMatches( | |
++pat; | ||
} | ||
|
||
// Skip over any remaining module entries if we were asked to do that. | ||
while (GetIgnoreModules() && ctx != ctx_end && | ||
ctx->kind == CompilerContextKind::Module) | ||
++ctx; | ||
// Skip over any remaining module and anonymous namespace entries if we were | ||
// asked to do that. | ||
auto should_skip = [this](const CompilerContext &ctx) { | ||
if (ctx.kind == CompilerContextKind::Module) | ||
return GetIgnoreModules(); | ||
if (ctx.kind == CompilerContextKind::Namespace && ctx.name.IsEmpty()) | ||
labath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return !GetStrictNamespaces(); | ||
return false; | ||
}; | ||
ctx = std::find_if_not(ctx, ctx_end, should_skip); | ||
|
||
// 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. | ||
|
@@ -788,7 +808,13 @@ Type::GetTypeScopeAndBasename(llvm::StringRef name) { | |
switch (pos.value()) { | ||
case ':': | ||
if (prev_is_colon && template_depth == 0) { | ||
result.scope.push_back(name.slice(name_begin, pos.index() - 1)); | ||
llvm::StringRef scope_name = name.slice(name_begin, pos.index() - 1); | ||
labath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// The itanium demangler uses this string to represent anonymous | ||
// namespaces. Convert it to a more language-agnostic form (which is | ||
// also used in DWARF). | ||
if (scope_name == "(anonymous namespace)") | ||
scope_name = ""; | ||
Comment on lines
+815
to
+816
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. So we can catch this here and NULL out the name, but what is the user wants to find something in an anonymous namespace with 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. Yes, that also goes through this piece of code. I'll add a test for that path. |
||
result.scope.push_back(scope_name); | ||
name_begin = pos.index() + 1; | ||
} | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
CXX_SOURCES := pass-to-base.cpp | ||
CXX_SOURCES := pass-to-base.cpp anonymous-b.cpp | ||
|
||
include Makefile.rules |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#ifndef A_H | ||
#define A_H | ||
|
||
#include <cstdio> | ||
#include <memory> | ||
|
||
class A { | ||
public: | ||
A(int value) : m_a_value(value) {} | ||
A(int value, A *client_A) : m_a_value(value), m_client_A(client_A) {} | ||
|
||
virtual ~A() {} | ||
|
||
virtual void doSomething(A &anotherA); | ||
|
||
int Value() { return m_a_value; } | ||
|
||
private: | ||
int m_a_value; | ||
std::auto_ptr<A> m_client_A; | ||
}; | ||
|
||
A *make_anonymous_B(); | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#include "a.h" | ||
|
||
namespace { | ||
class B : public A { | ||
public: | ||
B() : A(42) {} | ||
|
||
private: | ||
int m_anon_b_value = 47; | ||
}; | ||
} // namespace | ||
|
||
A *make_anonymous_B() { return new B(); } |
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 want to only pull out this match if this is a
DW_TAG_namespace
? Or is it useful to have unnamed structs/unions/classes in the contenxt?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.
unnamed structs cannot contain named structs, so the only place these can appear is at the top (bottom?) level. We don't currently have a way to look them up from our APIs taking strings (we'd need something like an
(anonymous struct)
), but they could be looked up internally by code which constructs CompilerContexts directly. So yeah, I think including them here is the right choice for this function.