This is an archive of the discontinued LLVM Phabricator instance.

[clang][transformer] Finish plumbing `Note` all the way to the output.
ClosedPublic

Authored by courbet on Jun 29 2022, 5:09 AM.

Details

Summary

Right now we can only add a single warning, notes are not possible.

Apparently some provisions were made to allow notes (ASTEdit::Note), but they were never
propagated all the way to the diagnostics.

Diff Detail

Event Timeline

courbet created this revision.Jun 29 2022, 5:09 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 29 2022, 5:09 AM
courbet requested review of this revision.Jun 29 2022, 5:09 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptJun 29 2022, 5:09 AM
courbet updated this revision to Diff 440948.Jun 29 2022, 5:11 AM

Format patch

courbet edited the summary of this revision. (Show Details)Jun 29 2022, 5:12 AM

Overall, looks good. But my main question is whether this functionality should be supported in the Edit's Metadata field instead.

Eric -- what do you think? You've thought a lot more about metadata recently.

clang/lib/Tooling/Transformer/RewriteRule.cpp
56–73

Can this ever be null? I assume the intent was "no" (in which case I'd recommend an assert instead), but I'm open to the idea that it's valid, just want to understand better.

courbet added inline comments.Jun 30 2022, 12:46 AM
clang/lib/Tooling/Transformer/RewriteRule.cpp
56–73

Given that we provide an EditGenerator edit(ASTEdit), we can't ever be sure that the user won't give us an empty replacement.

I've split this off to a separate patch here with a test to show the issue: https://reviews.llvm.org/D128887

Eric -- what do you think? You've thought a lot more about metadata recently.

(Apologies for the delay. Still struggling to figure out a good workflow for reviewing patches...)

Can you say more about what your intended use of the note is? Perhaps that can motivate some of the discussion.

From what I can see, here's my thoughts:

  • A note being a part of an edit seems weird at best. An ASTEdit and Edit are fragments of a greater, logical change. That a note should semantically be associated with the insertion of an open paren "(" but not the close paren ")" seems odd to me.
  • The note takes the location of the edit it is attached to. Perhaps that could be of some convenience when those coincide, but I don't believe that should necessarily be the case. I'm imagining notes could be used to point out other parts of the source that are interesting.

I don't have a lot of experience with how notes appear when surfaced, but I suspect that this interface might encourage callers to tack notes on without putting a lot of thought to where the note shows up. As is, I'm inclined to think that extending the metadata from std::string to something richer would be a better design.

Let me know if I'm misunderstanding the code or the intent of the patch.

clang/include/clang/Tooling/Transformer/RewriteRule.h
254–255

Are we sure that this is what someone would want? Perhaps I am not creative enough, but this seems like it could explode a large number of notes that coincide to edits, which seems like an odd thing to want.

  • A note being a part of an edit seems weird at best. An ASTEdit and Edit are fragments of a greater, logical change. That a note should semantically be associated with the insertion of an open paren "(" but not the close paren ")" seems odd to me.
  • The note takes the location of the edit it is attached to. Perhaps that could be of some convenience when those coincide, but I don't believe that should necessarily be the case. I'm imagining notes could be used to point out other parts of the source that are interesting.

Eric, these are great points. Originally, the idea for note (IIRC) came from the observation that sometimes a single match will generate edits in multiple locations, each which deserve a different diagnostic note (perhaps the same text, but appearing at the respective location). The intent was *not* to allow noting the insertion of paren, for example. So, I think it was a mistake. Yes, sometimes an ASTEdit is a coherent change, but sometimes (as the paren example demonstrates) its just a fragment.

So, from my original intent, I think that we'd just want to support multiple notes per rule, with each keyed on a source range. That said, we could decide to use ASTEdit for that purpose, assuming we're ok with ASTEdit with a null Replacement field. But, we'd have to think about th implications before we go down that route.

Clement -- what was your intended application? That may help clarify.

  • A note being a part of an edit seems weird at best. An ASTEdit and Edit are fragments of a greater, logical change. That a note should semantically be associated with the insertion of an open paren "(" but not the close paren ")" seems odd to me.
  • The note takes the location of the edit it is attached to. Perhaps that could be of some convenience when those coincide, but I don't believe that should necessarily be the case. I'm imagining notes could be used to point out other parts of the source that are interesting.

Eric, these are great points. Originally, the idea for note (IIRC) came from the observation that sometimes a single match will generate edits in multiple locations, each which deserve a different diagnostic note (perhaps the same text, but appearing at the respective location). The intent was *not* to allow noting the insertion of paren, for example. So, I think it was a mistake. Yes, sometimes an ASTEdit is a coherent change, but sometimes (as the paren example demonstrates) its just a fragment.

So, from my original intent, I think that we'd just want to support multiple notes per rule, with each keyed on a source range.

Clement -- what was your intended application? That may help clarify.

Thank for the comments.

For my particular case, I just need multiple notes per rule. I don't need them to be associated to a particular edit (and in that very particular case, I don't even need a source location).
Right now I have a check that is implemented as a transformer check. I want to emit an extra note. However, because transformer do not support notes I will have to rewrite the check to a traditional non-transformer one, which is a large change and could be a one-liner if transformer supported notes.

In terms of the overall design requirements, non-transformer checks can have multiple notes per rule, associated to a source location (and multiple checks are using the note location to point to somewhere else in the code, so that is a required feature if we want to be as powerful as the original clang-tidies, which I think we do). Notes cannot be associated to a particular FixitHint, and I'm not sure whether that's useful.

I went with the design in this patch (notes associated to edits) because:

  • it looked like associating a note with an ASTEdit was the original intent, given that ASTEdit already had a Note field.
  • we can plumb notes inside Metadata, but Metadata is already used for the warning, so that looks a bit more involved.

No strong opinion on that front though :)

For my particular case, I just need multiple notes per rule. I don't need them to be associated to a particular edit (and in that very particular case, I don't even need a source location).

I'm not sure I understand: you need this additional note, but it doesn't need to be tied to a source location, so, why can't you concatenate it to the main note?

In terms of the overall design requirements, non-transformer checks can have multiple notes per rule, associated to a source location (and multiple checks are using the note location to point to somewhere else in the code, so that is a required feature if we want to be as powerful as the original clang-tidies, which I think we do).

Yes, that's the goal, essentially. And the Note field came from exactly that observation.

Notes cannot be associated to a particular FixitHint, and I'm not sure whether that's useful.

Right. I'm not sure about that. It seems more intuitive for the note to be bundled with the associated FixitHint in the same DiagnosticBuilder. That is, if we want to (mostly) go with this design, I would think we'd create a separate diagnostic per note or somesuch.

Overall, I'm fine with adding support for additional notes, but I want to get these details sorted out first, since they subtly change the API.

I went with the design in this patch (notes associated to edits) because:

  • it looked like associating a note with an ASTEdit was the original intent, given that ASTEdit already had a Note field.
  • we can plumb notes inside Metadata, but Metadata is already used for the warning, so that looks a bit more involved.

No strong opinion on that front though :)

For my particular case, I just need multiple notes per rule. I don't need them to be associated to a particular edit (and in that very particular case, I don't even need a source location).

I'm not sure I understand: you need this additional note, but it doesn't need to be tied to a source location, so, why can't you concatenate it to the main note?

For my specific check the notes carry structure beyond what's typically in a warning, so I need the information to be separate.

For my particular case, I just need multiple notes per rule. I don't need them to be associated to a particular edit (and in that very particular case, I don't even need a source location).

I'm not sure I understand: you need this additional note, but it doesn't need to be tied to a source location, so, why can't you concatenate it to the main note?

For my specific check the notes carry structure beyond what's typically in a warning, so I need the information to be separate.

Based on our conversation offline, I'm inclined towards the change with the note below about API. Thanks!

clang/include/clang/Tooling/Transformer/RewriteRule.h
254–255

Agreed. I'm more inclined to only include the ASTEdit version. I see the value of the other one, but seems easy to get wrong. Alternatively, implement it to either only add to the first edit or append/prepend a separate edit with the note.

Either way, I think the primary use should be with a standalone note generator like ASTEdit note(TextGenerator Note). The idea is that the new combinator allows adding notes to a rule and we happen to store notes in ASTEdits. Then, withNote is really the uncommon case where you want to supplement an existing edit or set of edits with a note. WDYT?

259–260
clang/lib/Tooling/Transformer/RewriteRule.cpp
56–73

Agreed. Thanks!

courbet updated this revision to Diff 451425.Aug 10 2022, 5:30 AM

Replace both versions of withNote() with a single ASTEdit note() generator.

Thanks for the comments.

clang/include/clang/Tooling/Transformer/RewriteRule.h
254–255

I'm more inclined to only include the ASTEdit version. I see the value of the other one, but seems easy to get wrong. Alternatively, implement it to either only add to the first edit or append/prepend a separate edit with the note.

The EditGenerator version was so that we can always add a note. Some generators return an EditGenerator instead of an ASTEdit. For example, noopEdit needs access to the match result to generate an empty range . The second version is required to work with these:

withNote(changeTo(anchor1, ...));   // OK, changeTo returns an `ASTEdit`.
withNote(noopEdit(...));   // not OK, noopEdit returns an `EditGenerator`, we need the second version.

Either way, I think the primary use should be with a standalone note generator like ASTEdit note(TextGenerator Note). The idea is that the new combinator allows adding notes to a rule and we happen to store notes in ASTEdits. Then, withNote is really the uncommon case where you want to supplement an existing edit or set of edits with a note. WDYT?

I think you're right, we don't need the notes to be attached to a particular edit. I expect most notes to be standalone: that's actually what I need in my case, and it's also actually what the diag API presents to the user.

diag(loc1, "some warning") << FixItHint::CreateReplacement(...);
diag(loc2, "some note", clang::DiagnosticIDs::Note)

becomes, in transformerland:

makeRule(matcher, flatten(changeTo(...), note(anchor2, cat("some note"))), cat("some warning"))

So I think we only really need an ASTEdit note() generator. I went with that solution.

ymandel accepted this revision.Aug 10 2022, 12:42 PM

Thanks!

This revision is now accepted and ready to land.Aug 10 2022, 12:42 PM
This revision was landed with ongoing or failed builds.Aug 10 2022, 11:07 PM
This revision was automatically updated to reflect the committed changes.