-
Notifications
You must be signed in to change notification settings - Fork 382
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
Aliases in templates #775
Aliases in templates #775
Conversation
0a6ed21
to
d3c6300
Compare
I've pushed some further updates. This is now feature-complete in the sense that it is sufficient to allow for use of The major behavioural change in these new commits is that IWYU now performs more recursive template visitation. Specifically, when an template being visited uses another template in a full-use context, passing down to it an argument that originates from the user's top-level template instantiation, it now recursively visits that other template specialization. Currently this is unnecessarily slow, because it does so every time. I still need to hook this into the I've refactored and renamed The commit history still needs cleaning up, but in terms of the overall change, this is (I think) close to what I want, so your thoughts are welcome. |
Impressive! This is a lot to chew through, so it will take me a while. But just looking at the new succeeding test cases makes me really hopeful. |
I can recommend https://github.com/kimgr/git-format if you want to clean up your commit series wrt clang-format. |
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.
Nicely done!
I haven't looked at the commit series or commit messages yet, but I guess there's some work there to turn this into a comprehensible story.
Left some notes inline, will spend some more time trying to understand the bigger picture.
6a153a1
to
6acbfe2
Compare
OK, I think I've actioned or responded to all your comments. I've also rebased the commit history into something which is hopefully somewhat logical and comprehensible. Reinstating the old test cases actually revealed a case which is not currently handled correctly, but it's a non-full-use being treated as a full-use, which is less bad than the opposite, so I've left it as is, with a TODO in the test case for now. Ready for you to take another look now. |
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.
Very nice!
I went over the commits one by one in my local repo, and they tell a nice story, progressing in small steps. Some of the test TODO
cleanups are truly impressive!
A few notes on commit messages:
Fix another alias-in-template issue
I wish this commit message had a small example with real code. The fix is so small (good thing) that it's hard to understand where and how it has effect (bad thing) :)
Commit-message typo:
The CanIgnoreType is suitable for determining whether a type was
reportable, but not whether it was expandansion-worthy.
expandansion -> expansion
tests/cxx/typedef_in_template.cc
Outdated
@@ -7,6 +7,7 @@ | |||
// | |||
//===----------------------------------------------------------------------===// | |||
|
|||
#include "direct.h" |
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.
Prefer tests/cxx/direct.h
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.
Fixed.
iwyu_ast_util.h
Outdated
@@ -694,6 +698,11 @@ bool IsClassType(const clang::Type* type); | |||
// However, vector<T> is *not* converted to vector<int>. | |||
const clang::Type* RemoveSubstTemplateTypeParm(const clang::Type* type); | |||
|
|||
// Returns true if any type involved (recursively examinging template |
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.
typo: examinging
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.
Fixed.
This tracks aliases of template parameters and treats uses thereof similarly to uses of the original parameters.
The previous code to catch aliases of template parameters would not catch the case where the template parameter was elaborated. Walk past the relevant ASTNodes to catch such cases.
It wasn't correct to ignore all uses of a template argument somewhere below a TypedefNameDecl ASTNode. When a template specialization happens between the two, the typedef is irrelevant. Account for that, and add a suitable test case. This makes cases like this count as a full use of the argument T: template<typename T> struct Container { using value_type = pair<T>; }; which may not always be correct, but is sometimes necessary. Currently this is erring on the side of too many full-uses.
6acbfe2
to
8c8c67e
Compare
You have good instincts. This is actually the most dubious change, and isn't always correct. If you're concerned, we can drop this commit and the remainder still works. But I think it's a step in the right direction. In any case, I expanded the commit message to clarify. I think I've addressed your other comments. Over to you 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.
Looks good! Just a few small nits remaining. Thank you.
tests/cxx/sizeof_in_template_arg.cc
Outdated
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "direct.h" |
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.
tests/cxx/direct.h
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.
Fixed.
iwyu.cc
Outdated
@@ -2897,10 +2903,22 @@ class InstantiatedTemplateVisitor | |||
|
|||
string GetSymbolAnnotation() const override { return " in tpl"; } | |||
|
|||
bool CanIgnoreType(const Type* type) const override { | |||
if (!IsTypeInteresting(type) || !IsKnownTemplateParam(type)) | |||
bool CanIgnoreType(const Type* type, IgnoreKind ignore_type = |
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.
ignore_type
-> ignore_kind
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.
Fixed.
When using sizeof(T) in a forward-declare context, the argument (T) should *not* be considered to be in a forward-declare context. Fix and add test case.
Type argument needs to be the pre-resugaring type in order to correctly detect whether it's a template argument. Factor out the question of whether the use is a full use to new function IsTemplateTypeParmUseFullUse.
When an expanded template param is itself a template specialization, and is being full-used, and involves a user-provided template argument, then we need to recursively expand that template to find more uses.
In walking the AST there were various places where types were only expanded if !CanIgnoreType. But the criteria were wrong The CanIgnoreType is suitable for determining whether a type was reportable, but not whether it was expansion-worthy. Add a new parameter to CanIgnoreType to distinguish the two use cases, and pass it in a couple of cases. Also, tweak the resugar map construction code. Now it is capable of handling template aliases as well as template classes and functions. Add a new test that now passes with these changes. This also resolves a couple of TODOs in an existing test, so update that accordingly.
8c8c67e
to
90fe9c5
Compare
OK, nits fixed. |
Thank you! |
It was introduced in include-what-you-use#742 to report underlying type aliases but it is seemingly not needed anymore, probably after include-what-you-use#775 where `TypedefType` visitation has been added. No functional change.
I've been working to fix the issues around uses of typedefs / aliases in templates. This PR replaces #707, fixes #431 and fixes #780.
However, it's not a complete solution yet. In particular, it's still not correctly handling
libstdc++
'sstd::unordered_map
, which was the issue that originally inspired me to work on this.So, I hope to continue to improve the solution until it does handle that case correctly.
For now, I'm posting the PR to get feedback on the general approach taken, which is as follows:
The existing code detected uses of template arguments via
VisitSubstTemplateTypeParmType
which appears in the AST whenever a template argument is used in a template instantiation.However, when an alias of a template argument is used, no such node appears. Instead, we get
VisitTypedefType
.The approach of this PR is to track all aliases of template arguments in a
map
, and whenVisitTypedefType
is called on an expression using such an alias, treat it similarly to howVisitSubstTemplateTypeParmType
used to work (the two now use a common helper function for the bulk of their functionality).The test I've rewritten demonstrates a few cases where IWYU used to (incorrectly) suggest forward declarations were sufficient, and now treats as full-uses.
There are more cases which still fail, so (as mentioned above) I hope to understand them and improve this further. (However, this is nevertheless an improvement on the status quo, so if you're reading this a few months after I wrote it and I haven't made further progress then it might be worth merging anyway.)