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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits