-
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
Nested wrapper header support #615
Nested wrapper header support #615
Conversation
Thank you, this looks interesting. I can't claim to understand the premise of the original code, but the improvement as described sounds useful. I would much prefer if the test was free-standing -- is it possible to create this double re-export without mappings, e.g. with nested I'll try and get my head around this in the meantime. |
43c1029
to
74d2b68
Compare
Sure. Test rewritten to be simpler (using just pragmas) and independent of the other tests. |
I've been looking at this for a while, and I honestly can't get my head around it :) Can you explain in more detail why that direct-includes check solves the problem of nested exporting? It seems to me this indicates a problem in Note that your testcase would succeed even without the Thanks for any clarifications. |
So, firstly, a private header can only be included from headers which are somehow explicitly marked up as exporting that private header (by export pragmas, a mapping file, or other means). The code computes the transitive closure of these relationships, and all transitive public headers are correctly returned from The problem is that the code prior to this change also enforces the reverse relationship: any header which is considered to export a particular private header must include that private header (at least, if it happens to use any symbols from it). This pre-empts most of the other logic about deciding what header is suitable for a symbol. That is not desirable in this use case. Here's the relevant logic (as on current master); this is the very first thing that happens to assign an include to a use: include-what-you-use/iwyu_output.cc Lines 740 to 766 in cd358ea
So for any full use without an existing suggested header, we hit the problematic code; this part: include-what-you-use/iwyu_output.cc Lines 757 to 759 in cd358ea
i.e. if the decl was in a private header and we export that header then we are forced to include it. My change is attempting to weaken that. So now, any header that already includes a private header which it exports can keep that include (whereas it would have been removed were the included file a private header which it doesn't export), but it is not forced to be added when not already present.
The includes of |
Thanks for the elaboration.
I think this may be include-what-you-use policy -- IWYU does its best to flatten the header dependency graph. What if we included I guess explicit exports/mappings could override that, but I guess I don't understand how your change takes them into account.
OK, so reading the implementation with your explanation in mind, I think I understand what you're changing, at least :) Current behavior: if a mapping leads back from decl-file to use-file, attribute use to decl-file. This implies there's some case where a mapping can occur from decl-file to use-file, without use-file directly including decl-file. Why can we assume this happened because of nested re-exports? Sorry for being slow, I just want to make sure we don't regress some other common scenario. |
Yes, and we would, because we don't export Even if we were a public header for
The explicit mappings are taken account inside the call to
Well, there are other ways. It can happen via exports, mapping files,
In any code that was previously IWYU-compliant, this logic (before the change) will have ensured that use-file already includes decl-file. And in that situation the new behaviour matches the current behaviour. So, this change ought not to have any impact on code already using IWYU; it only matters for new code. (It's possible there's some corner case e.g. when including decl-file through a symlink that something might go wrong; I don't understand IWYU's path canonicalization well enough to be certain what will happen there) |
Thanks for the extensive explanation, now I understand. I have some style comments on the tests, I'll get back to that later today. Otherwise, looks good! |
tests/cxx/export_nesting_1.h
Outdated
@@ -0,0 +1,15 @@ | |||
//===--- export_nesting_1.h - test input file for iwyu --------------------===// |
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.
Additional includes are usually called -d1.h
and -i1.h
, I think for "direct" and "indirect".
So I think these two supporting headers should be renamed:
export_nesting_1.h
->export_nesting-d1.h
export_nesting_2.h
->export_nesting-i1.h
Left a few nits inline, otherwise I think this is ready to go. |
tests/cxx/export_nesting.h
Outdated
#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPORT_NESTING_H_ | ||
|
||
// We export a header which already re-exports things to verify that nested | ||
// exports are acceptable |
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.
Full stop at end of sentence
Oh, and please squash the commits together. |
The existing code coped poorly with the case where header A includes B includes C includes D where D is a private header and B and C are both public headers for a symbol in D. In this case B would be forced to include D directly when it ought only to be including C. Fix this by an additional condition on the special case intended to handle these sorts of situations. For further detail, see discussion at include-what-you-use#615 Also test.
74d2b68
to
148434b
Compare
Bingo, thanks! |
The existing code coped poorly with the case where header A includes B includes C includes D where D is a private header and B and C are both public headers for a symbol in D. In this case B would be forced to include D directly when it ought only to be including C. Fix this by an additional condition on the special case intended to handle these sorts of situations. For further detail, see discussion at include-what-you-use/include-what-you-use#615 Also test.
I ran into a problem attempting to use IWYU on a project with the following pattern:
The existing special case code for handling private headers forces the last header to include the first one, even when a mapping exists from the first to the second.
This PR fixes that, by tweaking the logic so that we will retain private includes when they exist, but not necessarily add them whenever we are a potential public header for them.
The test I've added piggy-backs on an existing test to take advantage of its mapping file. Let me know if that's inappropriate and I should make this test independent of existing test files.