This is an archive of the discontinued LLVM Phabricator instance.

[clang][module] Improve incomplete-umbrella warning
ClosedPublic

Authored by zixuw on Jun 18 2020, 12:31 PM.

Details

Summary
  • Change the warning message for -Wincomplete-umbrella to report the location of the umbrella header;

Diff Detail

Event Timeline

zixuw created this revision.Jun 18 2020, 12:31 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 18 2020, 12:31 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript

Didn't get into details but overall GenModuleActionWrapper approach looks pretty complicated. Haven't tried to accomplish the same myself, so cannot say if such complexity is warranted or not. What happens with fixits in modules when you don't have GenModuleActionWrapper? How does it work with modules disabled? Also looks like there are no tests for incomplete umbrella warning when modules are disabled.

zixuw added a comment.Jul 15 2020, 2:04 PM

Didn't get into details but overall GenModuleActionWrapper approach looks pretty complicated. Haven't tried to accomplish the same myself, so cannot say if such complexity is warranted or not.

Yes the approach is complicated. But one thing to note is that the GenModuleActionWrapper-related facilities are upstreamed from apple/llvm-project. I adopted this approach just because it was available. Haven't explored other ways, but yes there might be a simpler approach.

What happens with fixits in modules when you don't have GenModuleActionWrapper?

If the fixit action is not forwarded to the new compiler instance, it will be handled by the 'outer' compiler instance, which has a different source manager that does not see the module files, so the source location cannot be correctly interpreted. From my experiments, the fixit hint is trying to write into the <builtin> file buffer in this test case, when I don't have the action forwarded using GenModuleActionWrapper. In this case the fixit rewriter quietly fails because <builtin> cannot be rewritten, but since this is not caught I think there might be cases where the wrong file ends up getting updated.

How does it work with modules disabled? Also looks like there are no tests for incomplete umbrella warning when modules are disabled.

Haven't tested this, will give a try.

Didn't get into details but overall GenModuleActionWrapper approach looks pretty complicated. Haven't tried to accomplish the same myself, so cannot say if such complexity is warranted or not.

Yes the approach is complicated. But one thing to note is that the GenModuleActionWrapper-related facilities are upstreamed from apple/llvm-project. I adopted this approach just because it was available. Haven't explored other ways, but yes there might be a simpler approach.

My concern about this approach is that it doesn't seem to be composable and propagating specific frontend actions to building modules looks ad-hoc and error-prone. Specifically, from the composition perspective what should we do when both indexing and fix-it are enabled? We can claim they should be mutually exclusive but don't know if it is applicable in general case. From the perspective of propagating other frontend actions to building modules I'm wondering if we need to have custom handling for other actions or not. Personally, I haven't checked that yet.

What happens with fixits in modules when you don't have GenModuleActionWrapper?

If the fixit action is not forwarded to the new compiler instance, it will be handled by the 'outer' compiler instance, which has a different source manager that does not see the module files, so the source location cannot be correctly interpreted. From my experiments, the fixit hint is trying to write into the <builtin> file buffer in this test case, when I don't have the action forwarded using GenModuleActionWrapper. In this case the fixit rewriter quietly fails because <builtin> cannot be rewritten, but since this is not caught I think there might be cases where the wrong file ends up getting updated.

That doesn't sound good. Though making a source manager support multiple compiler instances doesn't look like an easy task (and maybe not worthwhile).

Hi Zixu, thanks for working on improving this.

I agree with @vsapsai on the the GenModuleActionWrapper approach. Also, it seems to me that even though it would somehow improve the accuracy, it would be solving a more general problem, not really specific to this patch. What about CHECKs for the introduced fix-its? I don't see a #include or #import being matched in the tests.

clang/lib/Lex/PPLexerChange.cpp
301

Is it possible to incorporate the string selection as part of the diagnostic description in the .td file?

Hey Bruno! Thanks for the review.

Hi Zixu, thanks for working on improving this.

I agree with @vsapsai on the the GenModuleActionWrapper approach. Also, it seems to me that even though it would somehow improve the accuracy, it would be solving a more general problem, not really specific to this patch.

Yes the wrapper is definitely problematic. I'm checking how the diagnostic itself is handled correctly and start from there when I have time. For now would it be better to separate this into multiple patches and get the diagnostic improvement in first?

clang/test/Modules/Inputs/incomplete-umbrella/normal-module/Umbrella.h
1–3 ↗(On Diff #271810)

What about CHECKs for the introduced fix-its? I don't see a #include or #import being matched in the tests.

Is this the check you're looking for? It is checked in incomplete-umbrella-fixit.m:

RUN: %clang_cc1 -fmodules -fmodule-map-file=%t/module.modulemap -fmodules-cache-path=%t -Wno-everything -Wincomplete-umbrella -fixit %s && FileCheck %t/Umbrella.h --input-file %t/Umbrella.h --match-full-lines

Yes the wrapper is definitely problematic. I'm checking how the diagnostic itself is handled correctly and start from there when I have time. For now would it be better to separate this into multiple patches and get the diagnostic improvement in first?

Yep, that would be better!

clang/test/Modules/Inputs/incomplete-umbrella/normal-module/Umbrella.h
1–3 ↗(On Diff #271810)

Oh, right. my bad! Can we get a test for #include too?

zixuw added a comment.Sep 3 2020, 3:19 PM

Okay so I think I traced down to the root problem: the diagnostic message prints out fine because TextDiagnosticPrinter uses FullSourceLoc, which actually embeds an appropriate SourceManager within it:

TextDiag->emitDiagnostic(
    FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level,
    DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints());

However, FixItHint is handled by a different path: a FixItHint only stores a trivial location (a SourceRange) which does not embed a SourceManager. And when a FixItRewriter constructs, it initializes a bunch of helper objects (Editor, Rewriter, Commit, etc.) using the current SourceManager. When trying to commit a fix-it hint, the helper objects use their (const ref to) SourceManager, which is used by the main compilation, to resolve the plain location in the FixItHint, which is generated in the new compiler instance for building a module. Therefore the location resolution is wrong.
To fix this, we can make FixItHint use FullSourceLoc instead, and also modify all relevant parties (FixItRewriter, EditedSource, Rewriter, Commit, ...) to use the embedded SourceManager instead of having a const ref to one initialized SourceManager.
My main concern is that I'm not very familiar with all the rewrite facilities, and changing EditedSource etc. might affect other users of the facilities.
What do you think? @arphaman @bruno @vsapsai

zixuw updated this revision to Diff 291364.Sep 11 2020, 6:16 PM

Separate warning message improvement and fix-it hint.

zixuw edited the summary of this revision. (Show Details)Sep 11 2020, 6:17 PM
zixuw added a comment.Sep 14 2020, 3:22 PM

@arphaman @vsapsai @bruno
This diff has been sitting here for too long. I've separated out the fix-it hint part (working on implementing a 'FullSourceRange' to be used by FixItHint now) and this is just a concise change for the warning message now. Does it look good?

Noticed that the warning and the fix-it might not work well with pragmas suppressing diagnostic and with header guards. But it's not a regression and I don't think it is worth improving these use cases preemptively.

clang/lib/Lex/PPLexerChange.cpp
266–271

I was going to suggest to spell out the type explicitly instead of auto because I wasn't able to guess the type. But when I've checked, Module::Header didn't look particularly better. I'll leave it up to you to decide which one is more readable, for wider context there was a discussion RFC: Modernizing our use of auto.

269

Can we rename EndLoc to better convey its purpose, not how it was computed? I was thinking about something like SuggestedHeadersLoc or ExpectedHeadersLoc.

zixuw updated this revision to Diff 292058.EditedSep 15 2020, 4:45 PM

Address review:

  • Use explicit type name Module::Header instead of auto since it's a short typename and using auto does not improve readability;
  • Change variable EndLoc to ExpectedHeadersLoc so it's self-explanatory.
zixuw marked 2 inline comments as done.Sep 15 2020, 4:47 PM
vsapsai accepted this revision.Sep 16 2020, 6:05 PM

Looks good to me. I would wait a few days before committing in case other reviewers have comments but not too long as you can address extra comments post-commit.

This revision is now accepted and ready to land.Sep 16 2020, 6:05 PM
This revision was landed with ongoing or failed builds.Sep 18 2020, 2:57 PM
This revision was automatically updated to reflect the committed changes.