nridge added a comment.

Ok, I've made `HeuristicResolver` nullable, in the sense that I've added null 
checks arounds its use in `TargetFinder`.

I haven't refactored the tests to pass in a null resolver / annotate the ones 
that do or don't need one. Would you like that done in this patch, or a 
follow-up?



================
Comment at: clang-tools-extra/clangd/HeuristicResolver.h:60
+  // or more declarations that it likely references.
+  std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E);
+
----------------
sammccall wrote:
> nridge wrote:
> > sammccall wrote:
> > > This is pretty vaguely defined. From reading the implementation, this can 
> > > choose to return two things:
> > > 
> > > 1. a ValueDecl representing the value of E
> > > 2. a TypeDecl representing the type of E
> > > 
> > > Case 1 is used by heuristic go-to-def, which never hits case 2 because it 
> > > only passes certain kinds of E.
> > > Case 1+2 are used internally by the heuristic resolver to resolve base 
> > > types, and are unified by resolveDeclsToType which handles them as two 
> > > cases.
> > > 
> > > This doesn't seem like a clean public API :-) It also seems to lead to 
> > > some convolution internally.
> > > 
> > > --- 
> > > 
> > > I think we should distribute the work of this function into a few smaller 
> > > functions with couple of flavors.
> > > 
> > > Some that deal with specific node types, extracted from 
> > > resolveExprToDecls:
> > >  - `Decl* memberExprTarget(CXXDependentMemberExpr*)`. Uses exprToType 
> > > (for the base type), pointee (for arrow exprs), resolveDependentMember 
> > > (the final lookup).
> > >  - `Type* callExprType(CallExpr*)`. Uses exprToType (for the callee type).
> > >  - `Decl* declRefExprTarget(DependentScopeDeclRefExpr*)` - this is 
> > > currently a trivial wrapper for resolveDependentMember.
> > > 
> > > And some that are more generic building blocks:
> > >  - `Type* exprType(Expr*)`, which tries to handle any expr, dispatching 
> > > to the node-specific function and falling back to Expr::getType().
> > >  - `getPointeeType(Type*)` and `resolveDependentMember(...)` as now
> > > 
> > > It's not entirely clear what should be public vs private, but one idea I 
> > > quite like is: all the node-specific methods are public, and all the 
> > > building blocks are private.
> > > - This would mean adding some more node-specific methods to cover the 
> > > external callers of `resolveDependentMember`, but in each case I looked 
> > > at this seems to make sense.
> > >   (This neatly deals with the slightly grungy signature of 
> > > resolveDependentMember by hiding it)
> > > - it also mostly answers the question about contracts on non-dependent 
> > > code: most non-dependent node types simply can't be passed in
> > Thanks, you make some good points about this method being messy (and 
> > particularly that we're duplicating some "resolve the type of a 
> > non-dependent expression" logic, which has bothered me as well).
> > 
> > I like your proposed breakdown into smaller methods, and I partially 
> > implemented it.
> > 
> > A couple of notes:
> > 
> >  * I had to keep the [MemberExpr 
> > case](https://searchfox.org/llvm/rev/b3d7e761e347d562333893652dcf3837fa55d777/clang-tools-extra/clangd/FindTarget.cpp#218)
> >  around. It could not be subsumed by `Expr::getType()`, because for a 
> > `MemberExpr` that returns [this 
> > thing](https://searchfox.org/llvm/rev/b3d7e761e347d562333893652dcf3837fa55d777/clang/include/clang/AST/BuiltinTypes.def#283),
> >  while `getMemberDecl()->getType()` returns the function type of the member 
> > function, and we want the latter (for [this call 
> > site](https://searchfox.org/llvm/rev/b3d7e761e347d562333893652dcf3837fa55d777/clang-tools-extra/clangd/FindTarget.cpp#205)).
> >  * We don't quite achieve "non-dependent node types simply can't be passed 
> > in", because `resolveCallExpr()` can be called with a non-dependent call 
> > expr. However, it currently has no external callers -- perhaps we should 
> > make it private?
> > 
> > I left `resolveDependentMember()` public (and left its external callers 
> > alone) for now. I can make it private and add additional public wrappers if 
> > you'd like, but I'm wondering what the motivation is (especially as you've 
> > described it as "a really nice example of a heuristic lookup with a clear 
> > contract" :-)).
> Those notes/caveats seem totally fine to me.
> 
> > resolveCallExpr ... perhaps we should make it private?
> >  left resolveDependentMember() public ... I can make it private... I'm 
> > wondering what the motivation is
> 
> I just think it's a little easier to understand how to use this class, and 
> how to maintain/extend it, if the public methods form a consistent set with 
> the same level of abstraction. Having all the public methods handle node 
> types is tempting from this point of view.
> 
> I won't insist on this. We can inline the handling of UnusedUsingValueDecl 
> into the caller as it happens to be simple, but I don't see a strong reason 
> to do so.
Your argument for consistency, together with the fact that this allows moving 
the `Filter` lambdas out of the header file, has convinced me. Done!


================
Comment at: clang-tools-extra/clangd/ParsedAST.h:113
 
+  HeuristicResolver *getHeuristicResolver() const { return Resolver.get(); }
+
----------------
sammccall wrote:
> is this intended to be nullable? (If not, why the pointer type?)
I changed this to return `const HeuristicResolver *`, but kept it as a pointer 
for a couple of reasons:

 * I couldn't make `ParsedAST` store `HeuristicResolver` by value because it 
would make `ParsedAST` non-movable (`HeuristicResolver` is non-movable because 
it has a member of reference type (`ASTContext&`)).
 * The consumer functions (targetDecl() etc.) expect a pointer, so this avoids 
writing `&AST->getHeuristicResolver()` at every call site).


================
Comment at: clang-tools-extra/clangd/ParsedAST.h:150
   CanonicalIncludes CanonIncludes;
+  std::unique_ptr<HeuristicResolver> Resolver;
 };
----------------
nridge wrote:
> sammccall wrote:
> > Optional<HeuristicResolver> or simply HeuristicResolver?
> I wanted to make it just `HeuristicResolver` but it's accessed through a 
> `const ParsedAST` which would only expose a `const HeuristicResolver *`, and 
> I had already sprinkled `HeuristicResolver *` (without the const) everywhere 
> :)
> 
> I'll clean this up after we settle the nullability question.
See previous comment for why I couldn't make it `HeuristicResolver`. 
(`Optional` doesn't work for the same reason.)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D92290/new/

https://reviews.llvm.org/D92290

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to