This is an archive of the discontinued LLVM Phabricator instance.

[libTooling] Simplify type structure of `Stencil`s.
ClosedPublic

Authored by ymandel on Oct 30 2019, 5:41 AM.

Details

Summary

Currently, stencils are defined as a sequence of StencilParts. This
differentiation adds an unneeded layer of complexity to the definition of
Stencils. This change significantly simplifies the type structure: a stencil is
now conceptually any object implementing StencilInterface and Stencil is
just an alias for pointers to this interface.

To account for the sequencing that was supported by the old Stencil type, we
introduce a sequencing class that implements StencilInterface. That is,
sequences are just another kind of Stencil and no longer have any special
status.

Corresponding to this change in the type structure, we change the way cat is
used (and defined). cat bundles multiple features: it builds a stencil from a
sequence of subcomponents and admits multiple different types for its arguments,
while coercing them into the right type. Previously, cat was also used to
coerce a single StencilPart into a Stencil. With that distinction gone, many
uses of cat (e.g. in the tests) are unnecessary and have, therefore, been
removed.

Finally, we expose the "coercion" functionality with the first-class function
makeStencil, which was, previously, the private method wrap. This way, other
functions with Stencil-typed arguments can leverage makeStencil.

Diff Detail

Event Timeline

ymandel created this revision.Oct 30 2019, 5:41 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 30 2019, 5:41 AM
ymandel updated this revision to Diff 227072.Oct 30 2019, 5:55 AM

commented sequence operator

ymandel updated this revision to Diff 227156.Oct 30 2019, 12:13 PM

added simple overload of cat -- needed to support client transition to new type structure.

ymandel updated this revision to Diff 227159.Oct 30 2019, 12:19 PM

rebasing onto parent

Harbormaster completed remote builds in B40296: Diff 227159.
gribozavr2 added inline comments.Oct 31 2019, 11:07 AM
clang/include/clang/Tooling/Transformer/Stencil.h
51

s/Part// (2x)

91

I feel like this should be an implementation detail of cat (or other stencil combinators who want to support such implicit conversions). Users writing stencils should use concrete factory functions below.

158

It is the same operation as cat, right? So WDYT about cat_vector?

161–162

Like I said in the other review, I don't feel great about an overload set with universal references and anything else.

161–162

I think it is better to remove the first sentence.

163

"Creates a MatchConsumer that evaluates a given Stencil."

165

I'm a bit confused by the name. The function returns a MatchConsumer, but it is called "stencil". What is the intended usage?

166

I'm not sure the convenience of being able to avoid to say "cat(...)" at the callsite is worth the API complexity. In other words, my suggestion is to make this function take a single stencil.

clang/lib/Tooling/Transformer/Stencil.cpp
97

I think these comments can be deleted now.

259

There isn't much logic left in StencilImpl.

Would the code be simpler if we made the various Data classes implement StencilInterface directly?

ymandel marked 5 inline comments as done.Oct 31 2019, 11:37 AM

Thanks for the review! I agreed w/ all the comments, just responding early w/ those I had further thoughts/questions on.

clang/include/clang/Tooling/Transformer/Stencil.h
91

Agreed, but I wasn't sure if it was worth introducing a "detail" namespace for just one (overloaded) function. I liked when these were private methods of Stencil, but we don't have that option now. Should I use a namespace detail? something else?

158

not quite. cat is "smart" and optimizes case of one argument to just return that argument. in the future, it might also handle the case of 0 arguments specially. sequence just blindly constructs a sequence stencil.

that said, i can see the argument that the user doesn't care about such details and instead of the three functions:

cat(...)
cat(vector)
sequence(vector)

we should just have the two

cat(...)
catVector(vector)

with no "plain" sequence constructor. WDYT?

161–162

Sorry, I'd forgotten we'd discussed this before. I see your point -- I was surprised it worked, but when it did just barelled along. That should have been a red flag. :) I'm happy to rework this, per the comment above,.

165

Intended use is something like makeRule(matcher, change(stencil(...))).

The naming is the same as we previously had for text(). Since MatchConsumer is so general, the function name describes its argument, not its particular type. But, I'm open to other suggestions.

clang/lib/Tooling/Transformer/Stencil.cpp
259

Yes! I plan to do that in a followup revision, though I was really tempted to do it here already. :)

That said, we could also use a llvm::PointerSumType and implement it in functional style, fwiw. I'm fine either way.

gribozavr2 added inline comments.Oct 31 2019, 5:12 PM
clang/include/clang/Tooling/Transformer/Stencil.h
91

I don't have a strong opinion, but namespace detail should be fine.

158

i can see the argument that the user doesn't care about such details

I agree, and I would also say that we probably don't even want the users of the library to depend on such details either. So I agree, cat(...) and catVector(vector) look like the best option to me.

165

I see -- thanks. change() takes a TextGenerator. Aside from stencils, what are the other text generators? If those are not important, could we change change() to take a stencil directly? Or if those other text generators are important, we could add overloads to change() that accept a stencil.

My thinking here is that the user is not really concerned with the fact that Stencil-to-TextGenerator conversion is happening here. I think the more complicated operation is the combining of stencils -- and we already have cat for that; so adding another way to spell that is better avoided. So, not emphasizing the conversion by making it a part of the change() seems fine, and spelling the operation as cat seems to be an improvement to me.

ymandel marked 8 inline comments as done.Oct 31 2019, 6:38 PM
ymandel added inline comments.
clang/include/clang/Tooling/Transformer/Stencil.h
165

I see -- thanks. change() takes a TextGenerator. Aside from stencils, what are the other text generators? If those are not important, could we change change() to take a stencil directly?

Actually, that was the original design of the library. We changed it in the first submitted version on Ilya's suggestion to avoid the dependency between Transformer and Stencil. In fact, the reason TextGenerator exists is to abstract away that dependency.

Looking back, I think it was a reasonable choice at the time, keeping the commits, etc. independent.
But, based on my experience with the library over the last six months, I'd say these are clearly a single package and we'd be better off re-introducing the dependency in exactly the way you describe.

I think we can start (here) by taking the Stencil as an argument and wrapping it as a TextGenerator. But, I should follow up with a cleanup to actually store the value as a Stencil rather than wrapped as a TextGenerator.

I see. Some decoupling is desirable, I agree. Maybe move StencilInterface and Stencil into a separate header that RewriteRule can depend on, and then define the library of stencils in another header?

ymandel marked an inline comment as done.Nov 1 2019, 8:38 AM

I see. Some decoupling is desirable, I agree. Maybe move StencilInterface and Stencil into a separate header that RewriteRule can depend on, and then define the library of stencils in another header?

This sounds good. I'll put together a (stacked) revision to do this. It seems worth doing separately given that it will involve a substantial to the RewriteRule library & tests.

ymandel updated this revision to Diff 227473.Nov 1 2019, 10:12 AM

addressed to comments

ymandel marked 12 inline comments as done.Nov 1 2019, 10:19 AM

I see. Some decoupling is desirable, I agree. Maybe move StencilInterface and Stencil into a separate header that RewriteRule can depend on, and then define the library of stencils in another header?

This sounds good. I'll put together a (stacked) revision to do this. It seems worth doing separately given that it will involve a substantial to the RewriteRule library & tests.

In order to keep the client unaffected by the change, I reinstated a simple Stencil class to wrap the shared_ptr and provide the call operator. This means that the code is now backwards compatible and forwards compatible (to the change we've discussed in RewriteRule to be stencil-aware). This was simpler than adding temporary(?) overloads in RewriteRule.h for every function with a TextGenerator argument.

I included an overload of operator-> so that we can collapse it back to just a type alias.

clang/include/clang/Tooling/Transformer/Stencil.h
166

Based on discussion, removed this entirely.

ymandel updated this revision to Diff 227478.Nov 1 2019, 10:31 AM
ymandel marked an inline comment as done.

remove stray comments; clang-format

gribozavr2 accepted this revision.Nov 1 2019, 11:07 AM
This revision is now accepted and ready to land.Nov 1 2019, 11:07 AM
This revision was automatically updated to reflect the committed changes.