ilya-biryukov added inline comments.
================
Comment at: clang-tools-extra/clangd/FindTarget.h:194
+llvm::SmallVector<const NamedDecl *, 1>
+explicitReferenceTargets(ast_type_traits::DynTypedNode N,
+ DeclRelationSet Mask = {});
----------------
sammccall wrote:
> ilya-biryukov wrote:
> > sammccall wrote:
> > > ilya-biryukov wrote:
> > > > sammccall wrote:
> > > > > ilya-biryukov wrote:
> > > > > > sammccall wrote:
> > > > > > > ilya-biryukov wrote:
> > > > > > > > sammccall wrote:
> > > > > > > > > ilya-biryukov wrote:
> > > > > > > > > > No need to fix this.
> > > > > > > > > >
> > > > > > > > > > The name could probably be better, but we can fix this
> > > > > > > > > > later. Don't have any good ideas.
> > > > > > > > > I think as a public API this should be clearer on how/when to
> > > > > > > > > use and its relation to other things (planning to send a
> > > > > > > > > patch, but wanted to discuss a bit here first).
> > > > > > > > >
> > > > > > > > > - This is essentially a filter of allTargetDecls (as is
> > > > > > > > > targetDecl), but the relationship between the two isn't
> > > > > > > > > clear. They should have closely related names (variant) or
> > > > > > > > > maybe better be more orthogonal and composed at the callsite.
> > > > > > > > > - The most distinctive word in the name is `explicit`, but
> > > > > > > > > this function doesn't actually have anything to do with
> > > > > > > > > explicit vs non-explicit references (just history?)
> > > > > > > > > - It's not clear to me whether we actually want to
> > > > > > > > > encapsulate/hide the preference for instantiations over
> > > > > > > > > templates here, or whether it should be expressed at the
> > > > > > > > > callsite because the policy is decided feature-by-feature.
> > > > > > > > > `chooseBest(...)` vs `prefer(TemplateInstantiation,
> > > > > > > > > TemplatePattern, ...)`. The latter seems safer to me, based
> > > > > > > > > on experience with targetDecl so far.
> > > > > > > > >
> > > > > > > > > A couple of ideas:
> > > > > > > > > - caller invokes allTargetDecls() and then this is a helper
> > > > > > > > > function `prefer(DeclRelation, DeclRelation, Results)` that
> > > > > > > > > mutates Results
> > > > > > > > > - targetDecl() becomes the swiss-army filter and accepts a
> > > > > > > > > list of "prefer-X-over-Y", which it applies before returning
> > > > > > > > > the results with flags dropped
> > > > > > > > I don't like the idea of `targetDecl` becoming the swiss-army
> > > > > > > > knife, it's complicated to use as is.
> > > > > > > > The contract of `explicitReferenceTargets` is to expose only
> > > > > > > > the decls written in the source code and nothing else, it's
> > > > > > > > much simpler to explain and to use.
> > > > > > > >
> > > > > > > > It's useful for many things, essentially for anything that
> > > > > > > > needs to answer the question of "what does this name in the
> > > > > > > > source code refers to".
> > > > > > > >
> > > > > > > > The name could be clearer, the comments might need to be
> > > > > > > > improved.
> > > > > > > > The only crucial improvement that I'd attempt is getting rid of
> > > > > > > > the `Mask` parameter, I think there was just one or two cases
> > > > > > > > where it was useful.
> > > > > > > >
> > > > > > > >
> > > > > > > > I don't like the idea of targetDecl becoming the swiss-army
> > > > > > > > knife
> > > > > > > Fair enough. I'll poke more in the direction of making it easier
> > > > > > > to compose allTargetDecls then.
> > > > > > >
> > > > > > > > The contract of explicitReferenceTargets is to expose only the
> > > > > > > > decls written in the source code and nothing else, it's much
> > > > > > > > simpler to explain and to use.
> > > > > > > So I agree that the interface of targetDecl() is complicated, but
> > > > > > > I don't think this one is simpler to explain or use - or at least
> > > > > > > it hasn't been well-explained so far.
> > > > > > >
> > > > > > > For example,
> > > > > > > - "to expose only the decls written in the source code" -
> > > > > > > `vector<int>` isn't a decl written in the source code.
> > > > > > > - "find declarations explicitly referenced in the source code" -
> > > > > > > `return [[{foo}]];` - the class/constructor isn't explicitly
> > > > > > > referenced, but this function returns it.
> > > > > > > - "what does this name in the source code refers to" - a
> > > > > > > template name refers to the primary template, the (possible)
> > > > > > > partial specialization, and specialization all at once. Features
> > > > > > > like find refs/highlight show the equivalence class of names that
> > > > > > > refer to the same thing, but they don't prefer the specialization
> > > > > > > for that.
> > > > > > > - none of these explanations explains why the function is
> > > > > > > opinionated about template vs expansion but not about alias vs
> > > > > > > underlying.
> > > > > > >
> > > > > > > > No need to fix this.
> > > > > > > > The name could probably be better, but we can fix this later.
> > > > > > > > Don't have any good ideas.
> > > > > > >
> > > > > > > I think it's fine (and good!) that we this got added to unblock
> > > > > > > the hover work and to understand more use cases for this API. But
> > > > > > > I do think it's time to fix it now, and I'm not convinced a
> > > > > > > better name will do it (I can't think of a good name to describe
> > > > > > > the current functionality, either). Let me put a patch together
> > > > > > > and take a look?
> > > > > > What's the proposed fix?
> > > > > >
> > > > > > I might miss some context with the examples you provided, but
> > > > > > here's my view on how each of those should be handled:
> > > > > > - `vector<int>`. This function **can** return decls, not written in
> > > > > > the source code (e.g. template instantiations). References to those
> > > > > > decls should be written in the source code explicitly, not the
> > > > > > decls themselves.
> > > > > > - `return {foo}`. I agree this one is a corner case that we should
> > > > > > describe. It still provides sensible results that could be used by
> > > > > > hover, etc.
> > > > > > - "what does this name in the source code refers to". That's
> > > > > > exactly what this function is about. We want to pick the most
> > > > > > specific thing possible (i.e. the instantiation). Client code can
> > > > > > go from instantiation to template pattern, it can't go the other
> > > > > > way. There are exceptions where returning instantiation is not
> > > > > > possible - instantiations of template type aliases, dependent
> > > > > > template instantiations. We choose template pattern there, but we
> > > > > > don't really loose any information (if we choose to return Decl,
> > > > > > there's nothing else we can return).
> > > > > > - "none of these explanations explains why the function is
> > > > > > opinionated about template vs expansion but not about alias vs
> > > > > > underlying." That I agree with, I think it's possible to make it
> > > > > > opinionated there and remove the `Mask` parameter. I'm happy to
> > > > > > take a look, but don't want to clash with you if you're doing the
> > > > > > same thing. Would you want me to give it a try?
> > > > > >
> > > > > > What's the proposed fix?
> > > > > (FWIW I wrote this post upside-down, because I don't/didn't have the
> > > > > ideas worked out and this discussion has shaped my thinking a lot)
> > > > >
> > > > > My proposal would be to evolve both `targetDecl()` and
> > > > > `explicitReferenceTargets` into composable functions that help select
> > > > > the desired results of `allTargetDecls()`. Policy would be encoded at
> > > > > callsites, so functions would be quite specific (e.g.
> > > > > `preferTemplateInstantations`), or data-driven
> > > > > `filter(DeclRelationSet)`.
> > > > > Some reasoning below - basically I'm not convinced that the "do what
> > > > > I mean" behavior is well-defined here.
> > > > >
> > > > > > I agree this one is a corner case that we should describe. It still
> > > > > > provides sensible results that could be used by hover, etc.
> > > > >
> > > > > Yeah, it's the right behaviour. My point is that I don't think the
> > > > > policy being implemented here is "explicitness" - another example
> > > > > from a recent patch, CTAD `^vector x{1,2,3}` we want the
> > > > > instantiation.
> > > > >
> > > > > Maybe it's "specificness", but this raises questions:
> > > > > - how often is "most specific" the thing we want, vs "decl that's in
> > > > > source code" or "everything for completeness"
> > > > > - does the concept of 'specificness' generalize to alias vs
> > > > > underlying?
> > > > >
> > > > > My impression is that it's *sometimes* what we want, but not
> > > > > overwhelmingly often (e.g. not go-to-def or documentHighlights) and
> > > > > that it doesn't generalize well[1]. If that's the case, I think this
> > > > > should be apolicy expressed at callsites in features
> > > > > (`preferTemplateInstantiations` or something).
> > > > >
> > > > > It would be nice if there's some global concept of "preferredness",
> > > > > but looking at the needs of different features, I really don't see
> > > > > one - that's why targetDecl is so complicated.
> > > > >
> > > > > [1] Example of it not generalizing well - for hover we want
> > > > > instantiations over patterns, but after discussing with Kadir I think
> > > > > we want *both* the alias and the underlying so we can show the
> > > > > docs/association from the alias and the structured info from the
> > > > > underlying.
> > > > - `vector x{1,2,3}` should definitely return an instantiation, that
> > > > aligns with the contract of the function.
> > > > I know explicit is a bad name for this concept, it's more intricate.
> > > >
> > > > I would argue we want the most specific one for hover and if we want to
> > > > look into the underlying decls hover code is simple if it does so
> > > > explicitly, rather than passing custom filters to `allTargetDecls`.
> > > >
> > > > My impression is that evolving this into custom filter for
> > > > `allTargetDecls` makes the callsites more complicated. Having a single
> > > > "swiss-knife"-style function is good for sharing implementation, but
> > > > the client code is more complicated and error-prone with it.
> > > >
> > > > I would strongly suggest to keep `explicitReferenceTargets`, most code
> > > > is simpler with it. Most "filtering" and "getting underlying decls" can
> > > > be done in the client code and the client code is more straightforward
> > > > with it.
> > > > I know explicit is a bad name for this concept, it's more intricate.
> > > So at this point, I don't understand what the concept is, neither the
> > > name nor the doc comment describe it well. If you want to keep it, can
> > > you describe what the concept is at a high level and how it should
> > > interact with aliases, and suggest a name that is specific enough that it
> > > at least hints at the true distinction vs generic allTargetDecls()?
> > >
> > > > rather than passing custom filters to allTargetDecls
> > > allTargetDecls doesn't accept filters, and I don't suggest changing that.
> > > Are you referring to targetDecls? If so I think we're agreed on that
> > > point.
> > >
> > > > I would argue we want the most specific one for hover and if we want to
> > > > look into the underlying decls hover code is simple if it does so
> > > > explicitly
> > > I guess you're saying the alias is more specific here? Unfortunately the
> > > alias doesn't preserve the underlying decl in general. We need both decls
> > > - one preserving the alias and the other preserving the type arg/overload.
> > >
> > > > I would strongly suggest to keep explicitReferenceTargets, most code is
> > > > simpler with it. Most "filtering" and "getting underlying decls" can be
> > > > done in the client code and the client code is more straightforward
> > > > with it.
> > > This is what I'm not convinced of. Currently there are 2 users of
> > > explicitReferenceTargets, the original internal user and now hover. Which
> > > of the other targetDecl callsites (Rename and 5 in XRefs) can use
> > > explicitReferenceTargets? How much "getting underlying decls" would they
> > > become responsible for? targetDecl() was in part an effort to unify this
> > > unwrapping because I found it too difficult to maintain the mechanical
> > > bits when they were embedded in each feature.
> > >
> > Here's rough description of the concept:
> > - pick the most specific Decl, whenever possible. That means instantiations
> > for templates instead of patterns and never look through typedefs (Mask has
> > to be removed, this needs a separate refactoring).
> > - I described behaviour on particular examples you mentioned.
> >
> > It's useful because it's a simple way to get the most specific thing
> > written in the source code (even for implicit nodes, we choose to not do
> > complicated things like looking through typedefs).
> >
> > I suggest to call it `getReferencedDecls`.
> >
> > > I guess you're saying the alias is more specific here? Unfortunately the
> > > alias doesn't preserve the underlying decl in general. We need both decls
> > > - one preserving the alias and the other preserving the type arg/overload.
> >
> > We can get the underlying type in that particular case inside hover, it's
> > just a few lines of code. I don't think there are other cases where we
> > loose information.
> >
> >
> > > This is what I'm not convinced of. Currently there are 2 users of
> > > explicitReferenceTargets, the original internal user and now hover. Which
> > > of the other targetDecl callsites (Rename and 5 in XRefs) can use
> > > explicitReferenceTargets?
> > Rename uses `findExplicitReferences`, which uses `explicitReferenceTargets`
> > internally. XRefs, Rename, Code actions and any refactorings (if we ever do
> > any of those) will benefit from it, but mostly indirectly by using
> > `findExplicitReferences`. It also provides information about source
> > locations of the identifiers that name things, which is crucial for many of
> > those features.
> >
> >
> > > How much "getting underlying decls" would they become responsible for?
> > > targetDecl() was in part an effort to unify this unwrapping because I
> > > found it too difficult to maintain the mechanical bits when they were
> > > embedded in each feature.
> >
> > They would sometimes need to go from template instantiation to template
> > declaration or template pattern and (very rarely) get from typedef to its
> > underlying type. Both are very simple operations.
> > I described behaviour on particular examples you mentioned.
> Those examples weren't cases where I was questioning the behavior, they were
> examples of where the behavior wasn't motivated by the description.
>
> The questions I'm referring to are:
> > - how often is "most specific" the thing we want, vs "decl that's in source
> > code" or "everything for completeness"
> > - does the concept of 'specificness' generalize to alias vs underlying?
>
> I think the latter is answered but not the former.
>
> > We can get the underlying type in that particular case inside hover, it's
> > just a few lines of code. I don't think there are other cases where we
> > loose information.
> There are several cases - at least alias instantiations and using decls of
> overloads. Note that the reported alias decl is the UsingDecl, not the
> UsingShadowDecl. (Changing that case is possible, but would make more work
> for all the other callers).
>
> > I suggest to call it getReferencedDecls.
> This doesn't describe the distinction from targetDecl().
>
> > Rename uses findExplicitReferences, which uses explicitReferenceTargets
> > internally. XRefs, Rename, Code actions and any refactorings (if we ever do
> > any of those) will benefit from it, but mostly indirectly by using
> > findExplicitReferences.
>
> findExplicitReferences is certainly useful and has a clear API, but that
> doens't require `explicitReferenceTargets` to be public, which is what I'm
> asking here.
>
> Rename uses `targetDecl` together with `TemplatePattern`, which is the
> callsite I was referring to there.
>
> If the answer is that 2/7 current callsites will prefer
> `explicitReferenceTargets` and 5/7 need `targetDecl`, that doesn't seem like
> most code, nor does it seem self-evident that code actions added in the
> future will fall into the first bucket.
> how often is "most specific" the thing we want, vs "decl that's in source
> code" or "everything for completeness"
As mentioned before, I believe the following features would benefit from this:
rename, cross-references, code actions and other refactorings.
> Note that the reported alias decl is the UsingDecl, not the UsingShadowDecl.
> (Changing that case is possible, but would make more work for all the other
> callers).
What are the callers that would need more work for `UsingShadowDecl`? I lack
context to understand this example.
This function is useful because it's simpler to use in some cases than
`targetDecl` (if we get rid of `Mask`).
Sure, you **could** write all code using `targetDecl`, it's also ok to add a
few helpers like this to simplify some common cases from my POV.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D71596/new/
https://reviews.llvm.org/D71596
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits