[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-28 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

can you give this another look, if you have some time @sammccall?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-29 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 440921.
upsj marked 14 inline comments as done.
upsj added a comment.

- simplify parameter pack detection
- improve function naming
- make handling of unexpanded packs and varargs more visible
- add tests involving template specializations
- make documentation more descriptive


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +223,36 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
+TEST(ParameterHints, NameInDefinitionVariadic) {
+  // Parameter name picked up from definition in a resolved forwarded parameter.
+  assertParameterHints(R"cpp(
+void foo(int, int);
+template 
+void bar(Args... args) {
+  foo(args...);
+}
+void baz() {
+  bar($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int b) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +325,389 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter using std::forward in a constructor call
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter in a constructor call
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter using std::forward in a new expression
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter in a new expression
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadi

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-29 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/AST.cpp:690
+getPackTemplateParameter(const FunctionDecl *Callee) {
+  if (const auto *TemplateDecl = Callee->getPrimaryTemplate()) {
+auto TemplateParams = TemplateDecl->getTemplateParameters()->asArray();

sammccall wrote:
> This is doing something pretty strange if Callee is a function template 
> specialization.
> 
> It's not clear to me whether this function should be handling that case 
> (which AFAICS it doesn't, but could inspect the specialization kind), or 
> whether resolveForwardingParameters is responsible for not calling this 
> function in that case (in which case we should probably have an assert here).
> 
> Can you also add a test case that function template specialization doesn't 
> confuse us? i.e. it should return the parmvardecls from the specialization's 
> definition.
Do the new tests `VariadicNameFromSpecialization(Recursive)?` match what you 
had in mind?



Comment at: clang-tools-extra/clangd/InlayHints.cpp:483
+   !Type.getNonReferenceType().isConstQualified() &&
+   !isExpandedParameterPack(Param);
   }

sammccall wrote:
> sammccall wrote:
> > nridge wrote:
> > > sammccall wrote:
> > > > why is this check needed if we already decline to provide a name for 
> > > > the parameter on line 534 in chooseParameterNames?
> > > `shouldHintName` and `shouldHintReference` are [two independent 
> > > conditions](https://searchfox.org/llvm/rev/508eb41d82ca956c30950d9a16b522a29aeeb333/clang-tools-extra/clangd/InlayHints.cpp#411-418)
> > >  governing whether we show the parameter name and/or a `&` indicating 
> > > pass-by-mutable-ref, respectively
> > > 
> > > (I did approve the [patch](https://reviews.llvm.org/D124359) that 
> > > introduced `shouldHintReference` myself, hope that's ok)
> > Thanks, that makes sense! I just hadn't understood that change.
> What exactly *is* the motivation for suppressing reference hints in the pack 
> case?
> 
> (I can imagine there are cases where they're annoying, but it's hard to know 
> if the condition is right without knowing what those are)
I added an explanation. Basically, if we are unable to figure out which 
parameter the arguments are being forwarded to, the type of the ParmVarDecl for 
`Args&&...` gets deduced as `T&` or `T&&`, so that would mean even though we 
don't know whether the argument will eventually be forwarded to a reference 
parameter, we still claim all mutable lvalue arguments will be mutated, which 
IMO introduces more noise than necessary. But I think there are also good 
arguments for adding them to be safe.

There is another detail here, which is that we don't record whether we used 
std::forward, so the corresponding rvalue-to-lvalue conversions may lead to 
some unnecessary & annotations for rvalue arguments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-29 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj marked an inline comment as done.
upsj added a comment.

yes, I have commit access




Comment at: clang-tools-extra/clangd/InlayHints.cpp:483
+   !Type.getNonReferenceType().isConstQualified() &&
+   !isExpandedParameterPack(Param);
   }

sammccall wrote:
> upsj wrote:
> > sammccall wrote:
> > > sammccall wrote:
> > > > nridge wrote:
> > > > > sammccall wrote:
> > > > > > why is this check needed if we already decline to provide a name 
> > > > > > for the parameter on line 534 in chooseParameterNames?
> > > > > `shouldHintName` and `shouldHintReference` are [two independent 
> > > > > conditions](https://searchfox.org/llvm/rev/508eb41d82ca956c30950d9a16b522a29aeeb333/clang-tools-extra/clangd/InlayHints.cpp#411-418)
> > > > >  governing whether we show the parameter name and/or a `&` indicating 
> > > > > pass-by-mutable-ref, respectively
> > > > > 
> > > > > (I did approve the [patch](https://reviews.llvm.org/D124359) that 
> > > > > introduced `shouldHintReference` myself, hope that's ok)
> > > > Thanks, that makes sense! I just hadn't understood that change.
> > > What exactly *is* the motivation for suppressing reference hints in the 
> > > pack case?
> > > 
> > > (I can imagine there are cases where they're annoying, but it's hard to 
> > > know if the condition is right without knowing what those are)
> > I added an explanation. Basically, if we are unable to figure out which 
> > parameter the arguments are being forwarded to, the type of the ParmVarDecl 
> > for `Args&&...` gets deduced as `T&` or `T&&`, so that would mean even 
> > though we don't know whether the argument will eventually be forwarded to a 
> > reference parameter, we still claim all mutable lvalue arguments will be 
> > mutated, which IMO introduces more noise than necessary. But I think there 
> > are also good arguments for adding them to be safe.
> > 
> > There is another detail here, which is that we don't record whether we used 
> > std::forward, so the corresponding rvalue-to-lvalue conversions may lead to 
> > some unnecessary & annotations for rvalue arguments.
> This makes sense, the comment explains well, thank you!
> I have a couple of quibbles, up to you whether to change the logic.
> 
> #1: There's an unstated assumption that pack arguments *will* be forwarded 
> (there are other things we can do with them, like use them in 
> fold-expressions). It's a pretty good assumption but if the comment talks 
> about forwarding, it should probably mention explicitly ("it's likely the 
> params will be somehow forwarded, and...")
> 
> #2: the idea is that if the reference-ness is deduced from the callsite, then 
> it's not meaningful as an "is the param modified" signal, it's just "is this 
> arg modifiable". Fair enough, but this is a property of universal/forwarding 
> references (T&& where T is a template param), not of packs. So I *think* this 
> check should rather be !isInstantiatedFromForwardingReference(Param).
> But maybe that's more complexity and what you have is a good heuristic - I 
> think at least we should call out that it's a heuristic for the true 
> condition.
> 
> 
#1: I agree, I'll make that more clear before committing.

#2: Now that I think about it, there are actually two things we don't keep 
track of: parameters could lose their reference-ness via `Args...` instead of 
`Args&&...` and their rvalue-ness by not using `std::forward`. We only look at 
whether the innermost call takes a reference parameter, but as I said, we may 
lose some of that information on the way, claiming the function may modify the 
argument when it actually creates a copy on the way (losing reference-ness). I 
think the case of an rvalue being mistaken for an lvalue should not be much of 
an issue, since the reference annotation almost makes sense.

To visualize the situation: These three snippets all add &: hints to the 
parameter of bar
```
void foo(int&);
template 
void bar(Args... args) { return foo(args...); }
void baz() {
  bar(1);
}
```
```
void foo(int&);
template 
void bar(Args&&... args) { return foo(args...); }
void baz() {
  bar(1);
}
```
```
void foo(int&);
template 
void bar(Args&&... args) { return foo(std::forward(args)...); }
void baz() {
  int a;
  bar(a);
}
```
Two of these three cases probably shouldn't have this annotation?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-30 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 441520.
upsj marked 3 inline comments as done.
upsj added a comment.

detect whether forwarding functions preserve reference-ness and value 
categories of their arguments


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +223,36 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
+TEST(ParameterHints, NameInDefinitionVariadic) {
+  // Parameter name picked up from definition in a resolved forwarded parameter.
+  assertParameterHints(R"cpp(
+void foo(int, int);
+template 
+void bar(Args... args) {
+  foo(args...);
+}
+void baz() {
+  bar($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int b) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +325,444 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter using std::forward in a constructor call
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter in a constructor call
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter using std::forward in a new expression
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter in a new expression
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter using std::forward
+  // This prototype of std::forward is sufficient for clang to recognize it

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-30 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/InlayHints.cpp:483
+   !Type.getNonReferenceType().isConstQualified() &&
+   !isExpandedParameterPack(Param);
   }

sammccall wrote:
> upsj wrote:
> > sammccall wrote:
> > > upsj wrote:
> > > > sammccall wrote:
> > > > > sammccall wrote:
> > > > > > nridge wrote:
> > > > > > > sammccall wrote:
> > > > > > > > why is this check needed if we already decline to provide a 
> > > > > > > > name for the parameter on line 534 in chooseParameterNames?
> > > > > > > `shouldHintName` and `shouldHintReference` are [two independent 
> > > > > > > conditions](https://searchfox.org/llvm/rev/508eb41d82ca956c30950d9a16b522a29aeeb333/clang-tools-extra/clangd/InlayHints.cpp#411-418)
> > > > > > >  governing whether we show the parameter name and/or a `&` 
> > > > > > > indicating pass-by-mutable-ref, respectively
> > > > > > > 
> > > > > > > (I did approve the [patch](https://reviews.llvm.org/D124359) that 
> > > > > > > introduced `shouldHintReference` myself, hope that's ok)
> > > > > > Thanks, that makes sense! I just hadn't understood that change.
> > > > > What exactly *is* the motivation for suppressing reference hints in 
> > > > > the pack case?
> > > > > 
> > > > > (I can imagine there are cases where they're annoying, but it's hard 
> > > > > to know if the condition is right without knowing what those are)
> > > > I added an explanation. Basically, if we are unable to figure out which 
> > > > parameter the arguments are being forwarded to, the type of the 
> > > > ParmVarDecl for `Args&&...` gets deduced as `T&` or `T&&`, so that 
> > > > would mean even though we don't know whether the argument will 
> > > > eventually be forwarded to a reference parameter, we still claim all 
> > > > mutable lvalue arguments will be mutated, which IMO introduces more 
> > > > noise than necessary. But I think there are also good arguments for 
> > > > adding them to be safe.
> > > > 
> > > > There is another detail here, which is that we don't record whether we 
> > > > used std::forward, so the corresponding rvalue-to-lvalue conversions 
> > > > may lead to some unnecessary & annotations for rvalue arguments.
> > > This makes sense, the comment explains well, thank you!
> > > I have a couple of quibbles, up to you whether to change the logic.
> > > 
> > > #1: There's an unstated assumption that pack arguments *will* be 
> > > forwarded (there are other things we can do with them, like use them in 
> > > fold-expressions). It's a pretty good assumption but if the comment talks 
> > > about forwarding, it should probably mention explicitly ("it's likely the 
> > > params will be somehow forwarded, and...")
> > > 
> > > #2: the idea is that if the reference-ness is deduced from the callsite, 
> > > then it's not meaningful as an "is the param modified" signal, it's just 
> > > "is this arg modifiable". Fair enough, but this is a property of 
> > > universal/forwarding references (T&& where T is a template param), not of 
> > > packs. So I *think* this check should rather be 
> > > !isInstantiatedFromForwardingReference(Param).
> > > But maybe that's more complexity and what you have is a good heuristic - 
> > > I think at least we should call out that it's a heuristic for the true 
> > > condition.
> > > 
> > > 
> > #1: I agree, I'll make that more clear before committing.
> > 
> > #2: Now that I think about it, there are actually two things we don't keep 
> > track of: parameters could lose their reference-ness via `Args...` instead 
> > of `Args&&...` and their rvalue-ness by not using `std::forward`. We only 
> > look at whether the innermost call takes a reference parameter, but as I 
> > said, we may lose some of that information on the way, claiming the 
> > function may modify the argument when it actually creates a copy on the way 
> > (losing reference-ness). I think the case of an rvalue being mistaken for 
> > an lvalue should not be much of an issue, since the reference annotation 
> > almost makes sense.
> > 
> > To visualize the situation: These three snippets all add &: hints to the 
> > parameter of bar
> > ```
> > void foo(int&);
> > template 
> > void bar(Args... args) { return foo(args...); }
> > void baz() {
> >   bar(1);
> > }
> > ```
> > ```
> > void foo(int&);
> > template 
> > void bar(Args&&... args) { return foo(args...); }
> > void baz() {
> >   bar(1);
> > }
> > ```
> > ```
> > void foo(int&);
> > template 
> > void bar(Args&&... args) { return foo(std::forward(args)...); }
> > void baz() {
> >   int a;
> >   bar(a);
> > }
> > ```
> > Two of these three cases probably shouldn't have this annotation?
> > parameters could lose their reference-ness via Args... instead of Args&&...
> (I'm not quite following what you mean here: if we deduce as `Args` rather 
> than `Args&&` then the parameters are not references in the first place, 
> we're passing by value)
> 
> > and their rvalue-ness by n

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-07-01 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 441646.
upsj added a comment.

don't add reference hints to unresolved parameter packs


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +223,36 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
+TEST(ParameterHints, NameInDefinitionVariadic) {
+  // Parameter name picked up from definition in a resolved forwarded parameter.
+  assertParameterHints(R"cpp(
+void foo(int, int);
+template 
+void bar(Args... args) {
+  foo(args...);
+}
+void baz() {
+  bar($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int b) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +325,455 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter using std::forward in a constructor call
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter in a constructor call
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter using std::forward in a new expression
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter in a new expression
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter using std::forward
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+  

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-07-05 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

@nridge @sammccall if you don't have any further comments, I will commit this 
tomorrow, and maybe think about how to extend it to signature help/code 
completion :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-07-06 Thread Tobias Ribizel via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGa638648fef76: [clangd] add inlay hints for std::forward-ed 
parameter packs (authored by upsj).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +223,36 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
+TEST(ParameterHints, NameInDefinitionVariadic) {
+  // Parameter name picked up from definition in a resolved forwarded parameter.
+  assertParameterHints(R"cpp(
+void foo(int, int);
+template 
+void bar(Args... args) {
+  foo(args...);
+}
+void baz() {
+  bar($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int b) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +325,455 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter using std::forward in a constructor call
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter in a constructor call
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter using std::forward in a new expression
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter in a new expression
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter using std::forward
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameter

[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-24 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added a reviewer: sammccall.
Herald added subscribers: usaxena95, kadircet, arphaman.
Herald added a project: All.
upsj requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

With the addition of inlay hints to clangd, it would be useful to output them 
during verbose `clangd --check`.
This patch adds an output step for inlay hints and unifies the way 
`--check-lines` are passed around


https://reviews.llvm.org/D124344

Files:
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp

Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -61,8 +61,7 @@
 namespace clangd {
 
 // Implemented in Check.cpp.
-bool check(const llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(const llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion);
 
@@ -955,8 +954,9 @@
   return 1;
 }
 log("Entering check mode (no LSP server)");
-uint32_t Begin = 0, End = std::numeric_limits::max();
+llvm::Optional CheckLineRange;
 if (!CheckFileLines.empty()) {
+  uint32_t Begin = 0, End = std::numeric_limits::max();
   StringRef RangeStr(CheckFileLines);
   bool ParseError = RangeStr.consumeInteger(0, Begin);
   if (RangeStr.empty()) {
@@ -965,19 +965,18 @@
 ParseError |= !RangeStr.consume_front("-");
 ParseError |= RangeStr.consumeInteger(0, End);
   }
-  if (ParseError || !RangeStr.empty()) {
-elog("Invalid --check-line specified. Use Begin-End format, e.g. 3-17");
+  if (ParseError || !RangeStr.empty() || Begin <= 0 || End < Begin) {
+elog(
+"Invalid --check-lines specified. Use Begin-End format, e.g. 3-17");
 return 1;
   }
+  CheckLineRange = Range{Position{static_cast(Begin - 1), 0},
+ Position{static_cast(End), 0}};
 }
-auto ShouldCheckLine = [&](const Position &Pos) {
-  uint32_t Line = Pos.line + 1; // Position::line is 0-based.
-  return Line >= Begin && Line <= End;
-};
 // For now code completion is enabled any time the range is limited via
 // --check-lines. If it turns out to be to slow, we can introduce a
 // dedicated flag for that instead.
-return check(Path, ShouldCheckLine, TFS, Opts,
+return check(Path, CheckLineRange, TFS, Opts,
  /*EnableCodeCompletion=*/!CheckFileLines.empty())
? 0
: static_cast(ErrorResultCode::CheckFailed);
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -30,8 +30,10 @@
 #include "Config.h"
 #include "GlobalCompilationDatabase.h"
 #include "Hover.h"
+#include "InlayHints.h"
 #include "ParsedAST.h"
 #include "Preamble.h"
+#include "Protocol.h"
 #include "SourceCode.h"
 #include "XRefs.h"
 #include "index/CanonicalIncludes.h"
@@ -190,10 +192,20 @@
 return true;
   }
 
+  // Build Inlay Hints for the entire AST
+  bool buildInlayHints(llvm::Optional LineRange) {
+log("Building inlay hints");
+auto Hints = inlayHints(*AST, LineRange);
+
+for (const auto &Hint : Hints) {
+  vlog("  {0} {1}", Hint.position, Hint.label);
+}
+return true;
+  }
+
   // Run AST-based features at each token in the file.
-  void testLocationFeatures(
-  llvm::function_ref ShouldCheckLine,
-  const bool EnableCodeCompletion) {
+  void testLocationFeatures(llvm::Optional LineRange,
+const bool EnableCodeCompletion) {
 trace::Span Trace("testLocationFeatures");
 log("Testing features at each token (may be slow in large files)");
 auto &SM = AST->getSourceManager();
@@ -207,7 +219,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (!ShouldCheckLine(Pos))
+  if (LineRange && LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -254,8 +266,7 @@
 
 } // namespace
 
-bool check(llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion) {
   llvm::SmallString<0> FakeFile;
@@ -282,9 +293,9 @@
   : /*Don't turn on local configs for an arbitrary temp path.*/ ""));
   Checker C(File, Opts);
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
-  !C.buildAST())
+  !C.buildAST() || !C.buildInlayHints(LineRange))
 

[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-24 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 424816.
upsj added a comment.

Output InlayHintKind and improve comments


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

https://reviews.llvm.org/D124344

Files:
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/tool/Check.cpp


Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -192,7 +192,7 @@
 return true;
   }
 
-  // Build Inlay Hints for the entire AST
+  // Build Inlay Hints for the entire AST or the specified range
   bool buildInlayHints(llvm::Optional LineRange) {
 log("Building inlay hints");
 auto Hints = inlayHints(*AST, LineRange);
Index: clang-tools-extra/clangd/Protocol.h
===
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1576,6 +1576,7 @@
   /// naturally when placed inline with the code.
   std::string label;
 };
+const char* toString(InlayHintKind);
 llvm::json::Value toJSON(const InlayHint &);
 bool operator==(const InlayHint &, const InlayHint &);
 bool operator<(const InlayHint &, const InlayHint &);
Index: clang-tools-extra/clangd/Protocol.cpp
===
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -1316,7 +1316,7 @@
   return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
 }
 
-llvm::json::Value toJSON(InlayHintKind K) {
+const char* toString(InlayHintKind K){
   switch (K) {
   case InlayHintKind::ParameterHint:
 return "parameter";
@@ -1328,6 +1328,10 @@
   llvm_unreachable("Unknown clang.clangd.InlayHintKind");
 }
 
+llvm::json::Value toJSON(InlayHintKind K) {
+  return toString(K);
+}
+
 llvm::json::Value toJSON(const InlayHint &H) {
   return llvm::json::Object{{"position", H.position},
 {"range", H.range},


Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -192,7 +192,7 @@
 return true;
   }
 
-  // Build Inlay Hints for the entire AST
+  // Build Inlay Hints for the entire AST or the specified range
   bool buildInlayHints(llvm::Optional LineRange) {
 log("Building inlay hints");
 auto Hints = inlayHints(*AST, LineRange);
Index: clang-tools-extra/clangd/Protocol.h
===
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1576,6 +1576,7 @@
   /// naturally when placed inline with the code.
   std::string label;
 };
+const char* toString(InlayHintKind);
 llvm::json::Value toJSON(const InlayHint &);
 bool operator==(const InlayHint &, const InlayHint &);
 bool operator<(const InlayHint &, const InlayHint &);
Index: clang-tools-extra/clangd/Protocol.cpp
===
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -1316,7 +1316,7 @@
   return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
 }
 
-llvm::json::Value toJSON(InlayHintKind K) {
+const char* toString(InlayHintKind K){
   switch (K) {
   case InlayHintKind::ParameterHint:
 return "parameter";
@@ -1328,6 +1328,10 @@
   llvm_unreachable("Unknown clang.clangd.InlayHintKind");
 }
 
+llvm::json::Value toJSON(InlayHintKind K) {
+  return toString(K);
+}
+
 llvm::json::Value toJSON(const InlayHint &H) {
   return llvm::json::Object{{"position", H.position},
 {"range", H.range},
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-24 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 424817.
upsj added a comment.

forgot to include the old changes in the diff


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

https://reviews.llvm.org/D124344

Files:
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp

Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -61,8 +61,7 @@
 namespace clangd {
 
 // Implemented in Check.cpp.
-bool check(const llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(const llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion);
 
@@ -955,8 +954,9 @@
   return 1;
 }
 log("Entering check mode (no LSP server)");
-uint32_t Begin = 0, End = std::numeric_limits::max();
+llvm::Optional CheckLineRange;
 if (!CheckFileLines.empty()) {
+  uint32_t Begin = 0, End = std::numeric_limits::max();
   StringRef RangeStr(CheckFileLines);
   bool ParseError = RangeStr.consumeInteger(0, Begin);
   if (RangeStr.empty()) {
@@ -965,19 +965,18 @@
 ParseError |= !RangeStr.consume_front("-");
 ParseError |= RangeStr.consumeInteger(0, End);
   }
-  if (ParseError || !RangeStr.empty()) {
-elog("Invalid --check-line specified. Use Begin-End format, e.g. 3-17");
+  if (ParseError || !RangeStr.empty() || Begin <= 0 || End < Begin) {
+elog(
+"Invalid --check-lines specified. Use Begin-End format, e.g. 3-17");
 return 1;
   }
+  CheckLineRange = Range{Position{static_cast(Begin - 1), 0},
+ Position{static_cast(End), 0}};
 }
-auto ShouldCheckLine = [&](const Position &Pos) {
-  uint32_t Line = Pos.line + 1; // Position::line is 0-based.
-  return Line >= Begin && Line <= End;
-};
 // For now code completion is enabled any time the range is limited via
 // --check-lines. If it turns out to be to slow, we can introduce a
 // dedicated flag for that instead.
-return check(Path, ShouldCheckLine, TFS, Opts,
+return check(Path, CheckLineRange, TFS, Opts,
  /*EnableCodeCompletion=*/!CheckFileLines.empty())
? 0
: static_cast(ErrorResultCode::CheckFailed);
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -30,8 +30,10 @@
 #include "Config.h"
 #include "GlobalCompilationDatabase.h"
 #include "Hover.h"
+#include "InlayHints.h"
 #include "ParsedAST.h"
 #include "Preamble.h"
+#include "Protocol.h"
 #include "SourceCode.h"
 #include "XRefs.h"
 #include "index/CanonicalIncludes.h"
@@ -190,10 +192,20 @@
 return true;
   }
 
+  // Build Inlay Hints for the entire AST or the specified range
+  bool buildInlayHints(llvm::Optional LineRange) {
+log("Building inlay hints");
+auto Hints = inlayHints(*AST, LineRange);
+
+for (const auto &Hint : Hints) {
+  vlog("  {0} {1} {2}", toString(Hint.kind), Hint.position, Hint.label);
+}
+return true;
+  }
+
   // Run AST-based features at each token in the file.
-  void testLocationFeatures(
-  llvm::function_ref ShouldCheckLine,
-  const bool EnableCodeCompletion) {
+  void testLocationFeatures(llvm::Optional LineRange,
+const bool EnableCodeCompletion) {
 trace::Span Trace("testLocationFeatures");
 log("Testing features at each token (may be slow in large files)");
 auto &SM = AST->getSourceManager();
@@ -207,7 +219,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (!ShouldCheckLine(Pos))
+  if (LineRange && LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -254,8 +266,7 @@
 
 } // namespace
 
-bool check(llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion) {
   llvm::SmallString<0> FakeFile;
@@ -282,9 +293,9 @@
   : /*Don't turn on local configs for an arbitrary temp path.*/ ""));
   Checker C(File, Opts);
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
-  !C.buildAST())
+  !C.buildAST() || !C.buildInlayHints(LineRange))
 return false;
-  C.testLocationFeatures(ShouldCheckLine, EnableCodeCompletion);
+  C.testLocationFeatures(LineRange, EnableCodeCompletion);
 
   log("All checks completed, {0} errors", C.ErrCount);
   ret

[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-24 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj marked 2 inline comments as done.
upsj added inline comments.



Comment at: clang-tools-extra/clangd/tool/Check.cpp:195
 
+  // Build Inlay Hints for the entire AST
+  bool buildInlayHints(llvm::Optional LineRange) {

nridge wrote:
> The comment should probably say "... for the entire AST or the specified 
> range"
done



Comment at: clang-tools-extra/clangd/tool/Check.cpp:201
+for (const auto &Hint : Hints) {
+  vlog("  {0} {1}", Hint.position, Hint.label);
+}

nridge wrote:
> Might be useful for print the hint kind as well?
right, is the current solution (adding a public toString) okay?


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

https://reviews.llvm.org/D124344

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


[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-04-25 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added a reviewer: nridge.
Herald added subscribers: usaxena95, kadircet, arphaman.
Herald added a project: All.
upsj requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

Add a & or && annotation to all parameter inlay hints that refer to a non-const 
reference. That makes it easier to identify them even if semantic highlighting 
is not used (where this is already available)


https://reviews.llvm.org/D124359

Files:
  clang-tools-extra/clangd/InlayHints.cpp


Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "HeuristicResolver.h"
 #include "ParsedAST.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -392,6 +393,7 @@
 // Don't show hints for variadic parameters.
 size_t FixedParamCount = getFixedParamCount(Callee);
 size_t ArgCount = std::min(FixedParamCount, Args.size());
+auto Params = Callee->parameters();
 
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
@@ -402,12 +404,18 @@
 
 for (size_t I = 0; I < ArgCount; ++I) {
   StringRef Name = ParameterNames[I];
-  if (!shouldHint(Args[I], Name))
-continue;
+  bool NameHint = shouldNameHint(Args[I], Name);
+  std::string Suffix = ": ";
+  if (!NameHint) {
+Name = "";
+Suffix = "";
+  }
+  Suffix += getRefSuffix(Params[I]);
 
-  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
-   InlayHintKind::ParameterHint, /*Prefix=*/"", Name,
-   /*Suffix=*/": ");
+  if (!Name.empty() || !Suffix.empty()) {
+addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
+ InlayHintKind::ParameterHint, /*Prefix=*/"", Name, 
Suffix);
+  }
 }
   }
 
@@ -434,12 +442,21 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
-  bool shouldHint(const Expr *Arg, StringRef ParamName) {
+  StringRef getRefSuffix(const ParmVarDecl *Param) {
+// If the parameter is a non-const reference type, print an inlay hint
+auto Type = Param->getType();
+return Type->isReferenceType() &&
+   !Type.getNonReferenceType().isConstQualified()
+   ? (Type->isLValueReferenceType() ? "&" : "&&")
+   : "";
+  }
+
+  bool shouldNameHint(const Expr *Arg, StringRef ParamName) {
 if (ParamName.empty())
   return false;
 
 // If the argument expression is a single name and it matches the
-// parameter name exactly, omit the hint.
+// parameter name exactly, omit the name hint.
 if (ParamName == getSpelledIdentifier(Arg))
   return false;
 


Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "HeuristicResolver.h"
 #include "ParsedAST.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -392,6 +393,7 @@
 // Don't show hints for variadic parameters.
 size_t FixedParamCount = getFixedParamCount(Callee);
 size_t ArgCount = std::min(FixedParamCount, Args.size());
+auto Params = Callee->parameters();
 
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
@@ -402,12 +404,18 @@
 
 for (size_t I = 0; I < ArgCount; ++I) {
   StringRef Name = ParameterNames[I];
-  if (!shouldHint(Args[I], Name))
-continue;
+  bool NameHint = shouldNameHint(Args[I], Name);
+  std::string Suffix = ": ";
+  if (!NameHint) {
+Name = "";
+Suffix = "";
+  }
+  Suffix += getRefSuffix(Params[I]);
 
-  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
-   InlayHintKind::ParameterHint, /*Prefix=*/"", Name,
-   /*Suffix=*/": ");
+  if (!Name.empty() || !Suffix.empty()) {
+addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
+ InlayHintKind::ParameterHint, /*Prefix=*/"", Name, Suffix);
+  }
 }
   }
 
@@ -434,12 +442,21 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
-  bool shouldHint(const Expr *Arg, StringRef ParamName) {
+  StringRef getRefSuffix(const ParmVarDecl *Param) {
+// If the parameter is a non-const reference type, print an inlay hint
+auto Type = Param->getType();
+return Type->isReferenceType() &&
+   !Type.getNonReferenceType().isConstQualified()
+   ? (Type->isLValueReferenceType() ? "&" : "&&")
+   : "";
+  

[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-25 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 424836.
upsj marked 2 inline comments as done.
upsj added a comment.

- format


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124344

Files:
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp

Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -61,8 +61,7 @@
 namespace clangd {
 
 // Implemented in Check.cpp.
-bool check(const llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(const llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion);
 
@@ -955,8 +954,9 @@
   return 1;
 }
 log("Entering check mode (no LSP server)");
-uint32_t Begin = 0, End = std::numeric_limits::max();
+llvm::Optional CheckLineRange;
 if (!CheckFileLines.empty()) {
+  uint32_t Begin = 0, End = std::numeric_limits::max();
   StringRef RangeStr(CheckFileLines);
   bool ParseError = RangeStr.consumeInteger(0, Begin);
   if (RangeStr.empty()) {
@@ -965,19 +965,18 @@
 ParseError |= !RangeStr.consume_front("-");
 ParseError |= RangeStr.consumeInteger(0, End);
   }
-  if (ParseError || !RangeStr.empty()) {
-elog("Invalid --check-line specified. Use Begin-End format, e.g. 3-17");
+  if (ParseError || !RangeStr.empty() || Begin <= 0 || End < Begin) {
+elog(
+"Invalid --check-lines specified. Use Begin-End format, e.g. 3-17");
 return 1;
   }
+  CheckLineRange = Range{Position{static_cast(Begin - 1), 0},
+ Position{static_cast(End), 0}};
 }
-auto ShouldCheckLine = [&](const Position &Pos) {
-  uint32_t Line = Pos.line + 1; // Position::line is 0-based.
-  return Line >= Begin && Line <= End;
-};
 // For now code completion is enabled any time the range is limited via
 // --check-lines. If it turns out to be to slow, we can introduce a
 // dedicated flag for that instead.
-return check(Path, ShouldCheckLine, TFS, Opts,
+return check(Path, CheckLineRange, TFS, Opts,
  /*EnableCodeCompletion=*/!CheckFileLines.empty())
? 0
: static_cast(ErrorResultCode::CheckFailed);
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -30,8 +30,10 @@
 #include "Config.h"
 #include "GlobalCompilationDatabase.h"
 #include "Hover.h"
+#include "InlayHints.h"
 #include "ParsedAST.h"
 #include "Preamble.h"
+#include "Protocol.h"
 #include "SourceCode.h"
 #include "XRefs.h"
 #include "index/CanonicalIncludes.h"
@@ -190,10 +192,20 @@
 return true;
   }
 
+  // Build Inlay Hints for the entire AST or the specified range
+  bool buildInlayHints(llvm::Optional LineRange) {
+log("Building inlay hints");
+auto Hints = inlayHints(*AST, LineRange);
+
+for (const auto &Hint : Hints) {
+  vlog("  {0} {1} {2}", toString(Hint.kind), Hint.position, Hint.label);
+}
+return true;
+  }
+
   // Run AST-based features at each token in the file.
-  void testLocationFeatures(
-  llvm::function_ref ShouldCheckLine,
-  const bool EnableCodeCompletion) {
+  void testLocationFeatures(llvm::Optional LineRange,
+const bool EnableCodeCompletion) {
 trace::Span Trace("testLocationFeatures");
 log("Testing features at each token (may be slow in large files)");
 auto &SM = AST->getSourceManager();
@@ -207,7 +219,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (!ShouldCheckLine(Pos))
+  if (LineRange && LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -254,8 +266,7 @@
 
 } // namespace
 
-bool check(llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion) {
   llvm::SmallString<0> FakeFile;
@@ -282,9 +293,9 @@
   : /*Don't turn on local configs for an arbitrary temp path.*/ ""));
   Checker C(File, Opts);
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
-  !C.buildAST())
+  !C.buildAST() || !C.buildInlayHints(LineRange))
 return false;
-  C.testLocationFeatures(ShouldCheckLine, EnableCodeCompletion);
+  C.testLocationFeatures(LineRange, EnableCodeCompletion);
 
   log("All checks co

[PATCH] D124365: review updates

2022-04-25 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
Herald added subscribers: usaxena95, kadircet, arphaman.
Herald added a project: All.
upsj requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

- Fix inverted check-lines condition
- Output InlayHintKind via ostream operators


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124365

Files:
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/tool/Check.cpp


Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -193,14 +193,13 @@
   }
 
   // Build Inlay Hints for the entire AST or the specified range
-  bool buildInlayHints(llvm::Optional LineRange) {
+  void buildInlayHints(llvm::Optional LineRange) {
 log("Building inlay hints");
 auto Hints = inlayHints(*AST, LineRange);
 
 for (const auto &Hint : Hints) {
-  vlog("  {0} {1} {2}", toString(Hint.kind), Hint.position, Hint.label);
+  vlog("  {0} {1} {2}", Hint.kind, Hint.position, Hint.label);
 }
-return true;
   }
 
   // Run AST-based features at each token in the file.
@@ -219,7 +218,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (LineRange && LineRange->contains(Pos))
+  if (LineRange && !LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -293,8 +292,9 @@
   : /*Don't turn on local configs for an arbitrary temp path.*/ ""));
   Checker C(File, Opts);
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
-  !C.buildAST() || !C.buildInlayHints(LineRange))
+  !C.buildAST())
 return false;
+  C.buildInlayHints(LineRange);
   C.testLocationFeatures(LineRange, EnableCodeCompletion);
 
   log("All checks completed, {0} errors", C.ErrCount);
Index: clang-tools-extra/clangd/Protocol.h
===
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1576,10 +1576,10 @@
   /// naturally when placed inline with the code.
   std::string label;
 };
-const char *toString(InlayHintKind);
 llvm::json::Value toJSON(const InlayHint &);
 bool operator==(const InlayHint &, const InlayHint &);
 bool operator<(const InlayHint &, const InlayHint &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, InlayHintKind);
 
 struct ReferenceContext {
   /// Include the declaration of the current symbol.
Index: clang-tools-extra/clangd/Protocol.cpp
===
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -1345,6 +1345,10 @@
  std::tie(B.position, B.range, B.kind, B.label);
 }
 
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) {
+  return OS << toString(Kind);
+}
+
 static const char *toString(OffsetEncoding OE) {
   switch (OE) {
   case OffsetEncoding::UTF8:


Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -193,14 +193,13 @@
   }
 
   // Build Inlay Hints for the entire AST or the specified range
-  bool buildInlayHints(llvm::Optional LineRange) {
+  void buildInlayHints(llvm::Optional LineRange) {
 log("Building inlay hints");
 auto Hints = inlayHints(*AST, LineRange);
 
 for (const auto &Hint : Hints) {
-  vlog("  {0} {1} {2}", toString(Hint.kind), Hint.position, Hint.label);
+  vlog("  {0} {1} {2}", Hint.kind, Hint.position, Hint.label);
 }
-return true;
   }
 
   // Run AST-based features at each token in the file.
@@ -219,7 +218,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (LineRange && LineRange->contains(Pos))
+  if (LineRange && !LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -293,8 +292,9 @@
   : /*Don't turn on local configs for an arbitrary temp path.*/ ""));
   Checker C(File, Opts);
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
-  !C.buildAST() || !C.buildInlayHints(LineRange))
+  !C.buildAST())
 return false;
+  C.buildInlayHints(LineRange);
   C.testLocationFeatures(LineRange, EnableCodeCompletion);
 
   log("All checks completed, {0} errors", C.ErrCount);
Index: clang-tools-extra/clangd/Protocol.h
===
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1576,10 +1576,10 @@
   /// naturally when placed inline with the code.
   std::string label;
 };
-const char *toString(InlayHintKind);
 llvm::json::Value toJSON(const InlayHint &)

[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-25 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 424838.
upsj added a comment.

Review updates

- Fix inverted check-lines condition
- Output InlayHintKind via ostream operators


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124344

Files:
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/tool/Check.cpp


Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -193,14 +193,13 @@
   }
 
   // Build Inlay Hints for the entire AST or the specified range
-  bool buildInlayHints(llvm::Optional LineRange) {
+  void buildInlayHints(llvm::Optional LineRange) {
 log("Building inlay hints");
 auto Hints = inlayHints(*AST, LineRange);
 
 for (const auto &Hint : Hints) {
-  vlog("  {0} {1} {2}", toString(Hint.kind), Hint.position, Hint.label);
+  vlog("  {0} {1} {2}", Hint.kind, Hint.position, Hint.label);
 }
-return true;
   }
 
   // Run AST-based features at each token in the file.
@@ -219,7 +218,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (LineRange && LineRange->contains(Pos))
+  if (LineRange && !LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -293,8 +292,9 @@
   : /*Don't turn on local configs for an arbitrary temp path.*/ ""));
   Checker C(File, Opts);
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
-  !C.buildAST() || !C.buildInlayHints(LineRange))
+  !C.buildAST())
 return false;
+  C.buildInlayHints(LineRange);
   C.testLocationFeatures(LineRange, EnableCodeCompletion);
 
   log("All checks completed, {0} errors", C.ErrCount);
Index: clang-tools-extra/clangd/Protocol.h
===
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1576,10 +1576,10 @@
   /// naturally when placed inline with the code.
   std::string label;
 };
-const char *toString(InlayHintKind);
 llvm::json::Value toJSON(const InlayHint &);
 bool operator==(const InlayHint &, const InlayHint &);
 bool operator<(const InlayHint &, const InlayHint &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, InlayHintKind);
 
 struct ReferenceContext {
   /// Include the declaration of the current symbol.
Index: clang-tools-extra/clangd/Protocol.cpp
===
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -1345,6 +1345,10 @@
  std::tie(B.position, B.range, B.kind, B.label);
 }
 
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) {
+  return OS << toString(Kind);
+}
+
 static const char *toString(OffsetEncoding OE) {
   switch (OE) {
   case OffsetEncoding::UTF8:


Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -193,14 +193,13 @@
   }
 
   // Build Inlay Hints for the entire AST or the specified range
-  bool buildInlayHints(llvm::Optional LineRange) {
+  void buildInlayHints(llvm::Optional LineRange) {
 log("Building inlay hints");
 auto Hints = inlayHints(*AST, LineRange);
 
 for (const auto &Hint : Hints) {
-  vlog("  {0} {1} {2}", toString(Hint.kind), Hint.position, Hint.label);
+  vlog("  {0} {1} {2}", Hint.kind, Hint.position, Hint.label);
 }
-return true;
   }
 
   // Run AST-based features at each token in the file.
@@ -219,7 +218,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (LineRange && LineRange->contains(Pos))
+  if (LineRange && !LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -293,8 +292,9 @@
   : /*Don't turn on local configs for an arbitrary temp path.*/ ""));
   Checker C(File, Opts);
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
-  !C.buildAST() || !C.buildInlayHints(LineRange))
+  !C.buildAST())
 return false;
+  C.buildInlayHints(LineRange);
   C.testLocationFeatures(LineRange, EnableCodeCompletion);
 
   log("All checks completed, {0} errors", C.ErrCount);
Index: clang-tools-extra/clangd/Protocol.h
===
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1576,10 +1576,10 @@
   /// naturally when placed inline with the code.
   std::string label;
 };
-const char *toString(InlayHintKind);
 llvm::json::Value toJSON(const InlayHint &);
 bool operator==(const InlayHint &, const InlayHint &);
 bool operator<(const InlayHint

[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-25 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 424839.
upsj added a comment.

push full patch


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124344

Files:
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp

Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -61,8 +61,7 @@
 namespace clangd {
 
 // Implemented in Check.cpp.
-bool check(const llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(const llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion);
 
@@ -955,8 +954,9 @@
   return 1;
 }
 log("Entering check mode (no LSP server)");
-uint32_t Begin = 0, End = std::numeric_limits::max();
+llvm::Optional CheckLineRange;
 if (!CheckFileLines.empty()) {
+  uint32_t Begin = 0, End = std::numeric_limits::max();
   StringRef RangeStr(CheckFileLines);
   bool ParseError = RangeStr.consumeInteger(0, Begin);
   if (RangeStr.empty()) {
@@ -965,19 +965,18 @@
 ParseError |= !RangeStr.consume_front("-");
 ParseError |= RangeStr.consumeInteger(0, End);
   }
-  if (ParseError || !RangeStr.empty()) {
-elog("Invalid --check-line specified. Use Begin-End format, e.g. 3-17");
+  if (ParseError || !RangeStr.empty() || Begin <= 0 || End < Begin) {
+elog(
+"Invalid --check-lines specified. Use Begin-End format, e.g. 3-17");
 return 1;
   }
+  CheckLineRange = Range{Position{static_cast(Begin - 1), 0},
+ Position{static_cast(End), 0}};
 }
-auto ShouldCheckLine = [&](const Position &Pos) {
-  uint32_t Line = Pos.line + 1; // Position::line is 0-based.
-  return Line >= Begin && Line <= End;
-};
 // For now code completion is enabled any time the range is limited via
 // --check-lines. If it turns out to be to slow, we can introduce a
 // dedicated flag for that instead.
-return check(Path, ShouldCheckLine, TFS, Opts,
+return check(Path, CheckLineRange, TFS, Opts,
  /*EnableCodeCompletion=*/!CheckFileLines.empty())
? 0
: static_cast(ErrorResultCode::CheckFailed);
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -30,8 +30,10 @@
 #include "Config.h"
 #include "GlobalCompilationDatabase.h"
 #include "Hover.h"
+#include "InlayHints.h"
 #include "ParsedAST.h"
 #include "Preamble.h"
+#include "Protocol.h"
 #include "SourceCode.h"
 #include "XRefs.h"
 #include "index/CanonicalIncludes.h"
@@ -190,10 +192,19 @@
 return true;
   }
 
+  // Build Inlay Hints for the entire AST or the specified range
+  void buildInlayHints(llvm::Optional LineRange) {
+log("Building inlay hints");
+auto Hints = inlayHints(*AST, LineRange);
+
+for (const auto &Hint : Hints) {
+  vlog("  {0} {1} {2}", Hint.kind, Hint.position, Hint.label);
+}
+  }
+
   // Run AST-based features at each token in the file.
-  void testLocationFeatures(
-  llvm::function_ref ShouldCheckLine,
-  const bool EnableCodeCompletion) {
+  void testLocationFeatures(llvm::Optional LineRange,
+const bool EnableCodeCompletion) {
 trace::Span Trace("testLocationFeatures");
 log("Testing features at each token (may be slow in large files)");
 auto &SM = AST->getSourceManager();
@@ -207,7 +218,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (!ShouldCheckLine(Pos))
+  if (LineRange && !LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -254,8 +265,7 @@
 
 } // namespace
 
-bool check(llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion) {
   llvm::SmallString<0> FakeFile;
@@ -284,7 +294,8 @@
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
   !C.buildAST())
 return false;
-  C.testLocationFeatures(ShouldCheckLine, EnableCodeCompletion);
+  C.buildInlayHints(LineRange);
+  C.testLocationFeatures(LineRange, EnableCodeCompletion);
 
   log("All checks completed, {0} errors", C.ErrCount);
   return C.ErrCount == 0;
Index: clang-tools-extra/clangd/Protocol.h
===
--- clang-too

[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-25 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 424846.
upsj added a comment.

- use string literal for toString result


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124344

Files:
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp

Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -61,8 +61,7 @@
 namespace clangd {
 
 // Implemented in Check.cpp.
-bool check(const llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(const llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion);
 
@@ -955,8 +954,9 @@
   return 1;
 }
 log("Entering check mode (no LSP server)");
-uint32_t Begin = 0, End = std::numeric_limits::max();
+llvm::Optional CheckLineRange;
 if (!CheckFileLines.empty()) {
+  uint32_t Begin = 0, End = std::numeric_limits::max();
   StringRef RangeStr(CheckFileLines);
   bool ParseError = RangeStr.consumeInteger(0, Begin);
   if (RangeStr.empty()) {
@@ -965,19 +965,18 @@
 ParseError |= !RangeStr.consume_front("-");
 ParseError |= RangeStr.consumeInteger(0, End);
   }
-  if (ParseError || !RangeStr.empty()) {
-elog("Invalid --check-line specified. Use Begin-End format, e.g. 3-17");
+  if (ParseError || !RangeStr.empty() || Begin <= 0 || End < Begin) {
+elog(
+"Invalid --check-lines specified. Use Begin-End format, e.g. 3-17");
 return 1;
   }
+  CheckLineRange = Range{Position{static_cast(Begin - 1), 0},
+ Position{static_cast(End), 0}};
 }
-auto ShouldCheckLine = [&](const Position &Pos) {
-  uint32_t Line = Pos.line + 1; // Position::line is 0-based.
-  return Line >= Begin && Line <= End;
-};
 // For now code completion is enabled any time the range is limited via
 // --check-lines. If it turns out to be to slow, we can introduce a
 // dedicated flag for that instead.
-return check(Path, ShouldCheckLine, TFS, Opts,
+return check(Path, CheckLineRange, TFS, Opts,
  /*EnableCodeCompletion=*/!CheckFileLines.empty())
? 0
: static_cast(ErrorResultCode::CheckFailed);
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -30,8 +30,10 @@
 #include "Config.h"
 #include "GlobalCompilationDatabase.h"
 #include "Hover.h"
+#include "InlayHints.h"
 #include "ParsedAST.h"
 #include "Preamble.h"
+#include "Protocol.h"
 #include "SourceCode.h"
 #include "XRefs.h"
 #include "index/CanonicalIncludes.h"
@@ -190,10 +192,19 @@
 return true;
   }
 
+  // Build Inlay Hints for the entire AST or the specified range
+  void buildInlayHints(llvm::Optional LineRange) {
+log("Building inlay hints");
+auto Hints = inlayHints(*AST, LineRange);
+
+for (const auto &Hint : Hints) {
+  vlog("  {0} {1} {2}", Hint.kind, Hint.position, Hint.label);
+}
+  }
+
   // Run AST-based features at each token in the file.
-  void testLocationFeatures(
-  llvm::function_ref ShouldCheckLine,
-  const bool EnableCodeCompletion) {
+  void testLocationFeatures(llvm::Optional LineRange,
+const bool EnableCodeCompletion) {
 trace::Span Trace("testLocationFeatures");
 log("Testing features at each token (may be slow in large files)");
 auto &SM = AST->getSourceManager();
@@ -207,7 +218,7 @@
   unsigned End = Start + Tok.length();
   Position Pos = offsetToPosition(Inputs.Contents, Start);
 
-  if (!ShouldCheckLine(Pos))
+  if (LineRange && !LineRange->contains(Pos))
 continue;
 
   trace::Span Trace("Token");
@@ -254,8 +265,7 @@
 
 } // namespace
 
-bool check(llvm::StringRef File,
-   llvm::function_ref ShouldCheckLine,
+bool check(llvm::StringRef File, llvm::Optional LineRange,
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts,
bool EnableCodeCompletion) {
   llvm::SmallString<0> FakeFile;
@@ -284,7 +294,8 @@
   if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
   !C.buildAST())
 return false;
-  C.testLocationFeatures(ShouldCheckLine, EnableCodeCompletion);
+  C.buildInlayHints(LineRange);
+  C.testLocationFeatures(LineRange, EnableCodeCompletion);
 
   log("All checks completed, {0} errors", C.ErrCount);
   return C.ErrCount == 0;
Index: clang-tools-extra/clangd/Protocol.h

[PATCH] D124373: [clang] add parameter pack/pack expansion matchers

2022-04-25 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added a reviewer: klimek.
Herald added a project: All.
upsj requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

There is no (obvious to me) way to match pack expansions and parameter packs, 
so I added two matchers for them.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124373

Files:
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp


Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -446,6 +446,7 @@
   REGISTER_MATCHER(isNoThrow);
   REGISTER_MATCHER(isNoneKind);
   REGISTER_MATCHER(isOverride);
+  REGISTER_MATCHER(isParameterPack);
   REGISTER_MATCHER(isPrivate);
   REGISTER_MATCHER(isProtected);
   REGISTER_MATCHER(isPublic);
@@ -513,6 +514,7 @@
   REGISTER_MATCHER(onImplicitObjectArgument);
   REGISTER_MATCHER(opaqueValueExpr);
   REGISTER_MATCHER(optionally);
+  REGISTER_MATCHER(packExpansionExpr);
   REGISTER_MATCHER(parameterCountIs);
   REGISTER_MATCHER(parenExpr);
   REGISTER_MATCHER(parenListExpr);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -981,6 +981,7 @@
 predefinedExpr;
 const internal::VariadicDynCastAllOfMatcher
 designatedInitExpr;
+const internal::VariadicDynCastAllOfMatcher 
packExpansionExpr;
 const internal::VariadicOperatorMatcherFunc<
 2, std::numeric_limits::max()>
 eachOf = {internal::DynTypedMatcher::VO_EachOf};
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -731,6 +731,27 @@
   InnerMatcher.matches(*Initializer, Finder, Builder));
 }
 
+/// Determines whether a declaration is a parameter pack.
+///
+/// Given
+/// \code
+/// template  class C,
+///   template  class... Ds>
+/// void foo(A param, Bs... params);
+/// \endcode
+/// templateTypeParmDecl(isParameterPack())
+///   matches 'typename... Bs', but not 'typename A'.
+/// nonTypeTemplateParmDecl(isParameterPack())
+///   matches 'int... js', but not 'int i'.
+/// templateTemplateParmDecl(isParameterPack())
+///   matches 'template  class... Ds', but not
+///   'template  class C'
+/// varDecl(isParameterPack())
+///   matches 'Bs... params', but not 'A param'.
+AST_MATCHER(Decl, isParameterPack) { return Node.isParameterPack(); }
+
 /// Determines whether the function is "main", which is the entry point
 /// into an executable program.
 AST_MATCHER(FunctionDecl, isMain) {
@@ -2699,6 +2720,21 @@
   return Node.size() == N;
 }
 
+/// Matches pack expansion expressions.
+///
+/// Given
+/// \code
+/// void bar(int, int);
+/// template 
+/// void foo(T arg, Args args...) {
+/// bar(arg + 1, (args + 1)...);
+/// }
+/// \endcode
+/// packExpansionExpr()
+///   matches '(args + 1)...', but not 'arg + 1'.
+extern const internal::VariadicDynCastAllOfMatcher
+packExpansionExpr;
+
 /// Matches \c QualTypes in the clang AST.
 extern const internal::VariadicAllOfMatcher qualType;
 


Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -446,6 +446,7 @@
   REGISTER_MATCHER(isNoThrow);
   REGISTER_MATCHER(isNoneKind);
   REGISTER_MATCHER(isOverride);
+  REGISTER_MATCHER(isParameterPack);
   REGISTER_MATCHER(isPrivate);
   REGISTER_MATCHER(isProtected);
   REGISTER_MATCHER(isPublic);
@@ -513,6 +514,7 @@
   REGISTER_MATCHER(onImplicitObjectArgument);
   REGISTER_MATCHER(opaqueValueExpr);
   REGISTER_MATCHER(optionally);
+  REGISTER_MATCHER(packExpansionExpr);
   REGISTER_MATCHER(parameterCountIs);
   REGISTER_MATCHER(parenExpr);
   REGISTER_MATCHER(parenListExpr);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -981,6 +981,7 @@
 predefinedExpr;
 const internal::VariadicDynCastAllOfMatcher
 designatedInitExpr;
+const internal::VariadicDynCastAllOfMatcher packExpansionExpr;
 const internal::VariadicOperatorMatcherFunc<
 2, std::numeric_limits::max()>
 eachOf = {internal::DynTypedMatcher::VO_EachOf};
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -731,6 +731,27 @@
  

[PATCH] D124344: [clangd] Output inlay hints with `clangd --check`

2022-04-26 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

@nridge Please do, I don't have commit permissions :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124344

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


[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-04-27 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 425432.
upsj added a comment.

add tests for reference inlay hints


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124359

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -138,6 +138,39 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameConstReference) {
+  // No hint for anonymous const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int&);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameReference) {
+  // Reference hint for anonymous l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"&", "param"});
+}
+
+TEST(ParameterHints, NoNameRValueReference) {
+  // Reference hint for anonymous r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&&);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"&&", "param"});
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -162,6 +195,40 @@
ExpectedHint{"good: ", "good"});
 }
 
+TEST(ParameterHints, NameConstReference) {
+  // Only name hint for const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
+TEST(ParameterHints, NameReference) {
+  // Reference and name hint for l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"param: &", "param"});
+}
+
+TEST(ParameterHints, NameRValueReference) {
+  // Reference and name hint for r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: &&", "param"});
+}
+
 TEST(ParameterHints, Operator) {
   // No hint for operator call with operator syntax.
   assertParameterHints(R"cpp(
@@ -301,6 +368,21 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, ArgMatchesParamReference) {
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void foo2(const int& param);
+void bar() {
+  int param;
+  // show reference hint on mutable reference
+  foo($param[[param]]);
+  // but not on const reference
+  foo2(param);
+}
+  )cpp",
+   ExpectedHint{"&", "param"});
+}
+
 TEST(ParameterHints, LeadingUnderscore) {
   assertParameterHints(R"cpp(
 void foo(int p1, int _p2, int __p3);
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "HeuristicResolver.h"
 #include "ParsedAST.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -392,6 +393,7 @@
 // Don't show hints for variadic parameters.
 size_t FixedParamCount = getFixedParamCount(Callee);
 size_t ArgCount = std::min(FixedParamCount, Args.size());
+auto Params = Callee->parameters();
 
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
@@ -402,12 +404,18 @@
 
 for (size_t I = 0; I < ArgCount; ++I) {
   StringRef Name = ParameterNames[I];
-  if (!shouldHint(Args[I], Name))
-continue;
+  bool NameHint = shouldNameHint(Args[I], Name);
+  std::string Suffix = ": ";
+  if (!NameHint) {
+Name = "";
+Suffix = "";
+  }
+  Suffix += getRefSuffix(Params[I]);
 
-  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
-   InlayHintKind::ParameterHint, /*Prefix=*/"", Name,
-   /*Suffix=*/": ");
+  if (!Name.empty() || !Suffix.empty()) {
+addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
+ InlayHintKind::ParameterHint, /*Prefix=*/"", Name, Suffix);
+  }
 }
   }
 
@@ -434,12 +442,21 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
-  bool shouldHint(const Expr *Arg, StringRef ParamName) {
+  StringRef getRefSuffix(const ParmVarDecl *Param) {
+// If the parameter is a non-const reference type, print an inlay hi

[PATCH] D124373: [clang] add parameter pack/pack expansion matchers

2022-04-27 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 425487.
upsj added a comment.

formatting


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124373

Files:
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp


Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -446,6 +446,7 @@
   REGISTER_MATCHER(isNoThrow);
   REGISTER_MATCHER(isNoneKind);
   REGISTER_MATCHER(isOverride);
+  REGISTER_MATCHER(isParameterPack);
   REGISTER_MATCHER(isPrivate);
   REGISTER_MATCHER(isProtected);
   REGISTER_MATCHER(isPublic);
@@ -513,6 +514,7 @@
   REGISTER_MATCHER(onImplicitObjectArgument);
   REGISTER_MATCHER(opaqueValueExpr);
   REGISTER_MATCHER(optionally);
+  REGISTER_MATCHER(packExpansionExpr);
   REGISTER_MATCHER(parameterCountIs);
   REGISTER_MATCHER(parenExpr);
   REGISTER_MATCHER(parenListExpr);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -981,6 +981,8 @@
 predefinedExpr;
 const internal::VariadicDynCastAllOfMatcher
 designatedInitExpr;
+const internal::VariadicDynCastAllOfMatcher
+packExpansionExpr;
 const internal::VariadicOperatorMatcherFunc<
 2, std::numeric_limits::max()>
 eachOf = {internal::DynTypedMatcher::VO_EachOf};
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -731,6 +731,27 @@
   InnerMatcher.matches(*Initializer, Finder, Builder));
 }
 
+/// Determines whether a declaration is a parameter pack.
+///
+/// Given
+/// \code
+/// template  class C,
+///   template  class... Ds>
+/// void foo(A param, Bs... params);
+/// \endcode
+/// templateTypeParmDecl(isParameterPack())
+///   matches 'typename... Bs', but not 'typename A'.
+/// nonTypeTemplateParmDecl(isParameterPack())
+///   matches 'int... js', but not 'int i'.
+/// templateTemplateParmDecl(isParameterPack())
+///   matches 'template  class... Ds', but not
+///   'template  class C'
+/// varDecl(isParameterPack())
+///   matches 'Bs... params', but not 'A param'.
+AST_MATCHER(Decl, isParameterPack) { return Node.isParameterPack(); }
+
 /// Determines whether the function is "main", which is the entry point
 /// into an executable program.
 AST_MATCHER(FunctionDecl, isMain) {
@@ -2699,6 +2720,21 @@
   return Node.size() == N;
 }
 
+/// Matches pack expansion expressions.
+///
+/// Given
+/// \code
+/// void bar(int, int);
+/// template 
+/// void foo(T arg, Args args...) {
+/// bar(arg + 1, (args + 1)...);
+/// }
+/// \endcode
+/// packExpansionExpr()
+///   matches '(args + 1)...', but not 'arg + 1'.
+extern const internal::VariadicDynCastAllOfMatcher
+packExpansionExpr;
+
 /// Matches \c QualTypes in the clang AST.
 extern const internal::VariadicAllOfMatcher qualType;
 


Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -446,6 +446,7 @@
   REGISTER_MATCHER(isNoThrow);
   REGISTER_MATCHER(isNoneKind);
   REGISTER_MATCHER(isOverride);
+  REGISTER_MATCHER(isParameterPack);
   REGISTER_MATCHER(isPrivate);
   REGISTER_MATCHER(isProtected);
   REGISTER_MATCHER(isPublic);
@@ -513,6 +514,7 @@
   REGISTER_MATCHER(onImplicitObjectArgument);
   REGISTER_MATCHER(opaqueValueExpr);
   REGISTER_MATCHER(optionally);
+  REGISTER_MATCHER(packExpansionExpr);
   REGISTER_MATCHER(parameterCountIs);
   REGISTER_MATCHER(parenExpr);
   REGISTER_MATCHER(parenListExpr);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -981,6 +981,8 @@
 predefinedExpr;
 const internal::VariadicDynCastAllOfMatcher
 designatedInitExpr;
+const internal::VariadicDynCastAllOfMatcher
+packExpansionExpr;
 const internal::VariadicOperatorMatcherFunc<
 2, std::numeric_limits::max()>
 eachOf = {internal::DynTypedMatcher::VO_EachOf};
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -731,6 +731,27 @@
   InnerMatcher.matches(*Initializer, Finder, Builder));
 }
 
+/// Determines whether a declaration is a parameter pack.
+///
+/// Given
+/// \code
+/// template 

[PATCH] D124373: [clang] add parameter pack/pack expansion matchers

2022-04-27 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

This is part of my long-term goal to add support for forwarding parameters and 
documentation for make_unique-like functions to clangd. To be fair, the details 
are not entirely fleshed out - for inlay hints (displaying parameter names 
inline), the entire function template is already available in an instantiated 
form, so I can work with existing matchers. For signature help (displaying 
which parameters are available, which one is active while typing), IIRC you 
only have the template instantiation pattern available, so I need to find the 
necessary parts of the AST myself.

My thought was to try and move towards this goal in small steps, but if this is 
an important build time/size consideration, I can also see whether both of them 
are actually necessary (I suspect isParameterPack might not be) before moving 
forward?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124373

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


[PATCH] D124373: [clang] add parameter pack/pack expansion matchers

2022-04-27 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj planned changes to this revision.
upsj added a comment.

I wasn't aware of that, sounds perfect, thanks! Then I'll put this on hold 
until I figure out if it's really necessary.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124373

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


[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-04-29 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added a reviewer: nridge.
Herald added subscribers: usaxena95, kadircet, arphaman.
Herald added a project: All.
upsj requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

I am working on support for forwarding parameter names in make_unique-like 
functions, first for inlay hints, later maybe for signature help.
For that to work generically, I'd like to parse all of these functions in the 
preamble. Not sure how this impacts performance on large codebases though.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/Preamble.cpp


Index: clang-tools-extra/clangd/Preamble.cpp
===
--- clang-tools-extra/clangd/Preamble.cpp
+++ clang-tools-extra/clangd/Preamble.cpp
@@ -137,14 +137,42 @@
   }
 
   bool shouldSkipFunctionBody(Decl *D) override {
-// Generally we skip function bodies in preambles for speed.
-// We can make exceptions for functions that are cheap to parse and
-// instantiate, widely used, and valuable (e.g. commonly produce errors).
-if (const auto *FT = llvm::dyn_cast(D)) {
-  if (const auto *II = FT->getDeclName().getAsIdentifierInfo())
-// std::make_unique is trivial, and we diagnose bad constructor calls.
-if (II->isStr("make_unique") && FT->isInStdNamespace())
-  return false;
+// Find functions with variadic template arguments:
+// Any templated function...
+if (auto *FT = llvm::dyn_cast(D)) {
+  // ... with a template parameter pack...
+  if (FT->getTemplateParameters()->hasParameterPack()) {
+auto PackIt = std::find_if(
+FT->getInjectedTemplateArgs().begin(),
+FT->getInjectedTemplateArgs().end(), [](const auto &Arg) {
+  return Arg.getKind() == TemplateArgument::Pack;
+});
+assert(PackIt != FT->getInjectedTemplateArgs().end() &&
+   "Can't find parameter pack in argument list!");
+const auto &Pack = PackIt->getPackAsArray();
+
+// ... that is a type parameter pack...
+if (Pack.size() == 1 && Pack[0].getKind() == TemplateArgument::Type) {
+  const auto *PackType =
+  Pack[0].getAsType().getNonPackExpansionType().getTypePtr();
+  const auto *FD = FT->getAsFunction();
+  const auto NumParams = FD->getNumParams();
+  if (NumParams > 0) {
+const auto *LastParam = FD->getParamDecl(NumParams - 1);
+// ... with its type matching the last parameter (pack) of the
+// function (minus references)...
+if (LastParam->isParameterPack()) {
+  if (LastParam->getType()
+  .getNonPackExpansionType()
+  .getNonReferenceType()
+  .getTypePtr() == PackType) {
+// ... we need to parse the body
+return false;
+  }
+}
+  }
+}
+  }
 }
 return true;
   }


Index: clang-tools-extra/clangd/Preamble.cpp
===
--- clang-tools-extra/clangd/Preamble.cpp
+++ clang-tools-extra/clangd/Preamble.cpp
@@ -137,14 +137,42 @@
   }
 
   bool shouldSkipFunctionBody(Decl *D) override {
-// Generally we skip function bodies in preambles for speed.
-// We can make exceptions for functions that are cheap to parse and
-// instantiate, widely used, and valuable (e.g. commonly produce errors).
-if (const auto *FT = llvm::dyn_cast(D)) {
-  if (const auto *II = FT->getDeclName().getAsIdentifierInfo())
-// std::make_unique is trivial, and we diagnose bad constructor calls.
-if (II->isStr("make_unique") && FT->isInStdNamespace())
-  return false;
+// Find functions with variadic template arguments:
+// Any templated function...
+if (auto *FT = llvm::dyn_cast(D)) {
+  // ... with a template parameter pack...
+  if (FT->getTemplateParameters()->hasParameterPack()) {
+auto PackIt = std::find_if(
+FT->getInjectedTemplateArgs().begin(),
+FT->getInjectedTemplateArgs().end(), [](const auto &Arg) {
+  return Arg.getKind() == TemplateArgument::Pack;
+});
+assert(PackIt != FT->getInjectedTemplateArgs().end() &&
+   "Can't find parameter pack in argument list!");
+const auto &Pack = PackIt->getPackAsArray();
+
+// ... that is a type parameter pack...
+if (Pack.size() == 1 && Pack[0].getKind() == TemplateArgument::Type) {
+  const auto *PackType =
+  Pack[0].getAsType().getNonPackExpansionType().getTypePtr();
+  const auto *FD = FT->getAsFunction();
+  const auto NumParams = FD->getNumParams();
+  if (NumParams > 0) {
+const auto *LastParam 

[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-04-29 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/InlayHints.cpp:448-450
+return Type->isReferenceType() &&
+   !Type.getNonReferenceType().isConstQualified()
+   ? (Type->isLValueReferenceType() ? "&" : "&&")

It probably doesn't make too much sense to highlight r-value references here, 
since it should be much clearer from context that they are either temporaries 
or explicitly std::move'd


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124359

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


[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-04-30 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

Thanks for checking! Putting it behind a flag was my intention from the start 
anyways, since ideally I would like to traverse the AST through something like 
emplace_back ->construct/realloc_insert -> allocator::construct until I reach a 
non-forwarding function.
Do you have some pointers on what needs to be done to add a new flag? I am 
still kind of new to LLVM development :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

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


[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-04-30 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 426217.
upsj added a comment.

don't add reference inlay hints for r-value refs


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124359

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -138,6 +138,38 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameConstReference) {
+  // No hint for anonymous const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int&);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameReference) {
+  // Reference hint for anonymous l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"&", "param"});
+}
+
+TEST(ParameterHints, NoNameRValueReference) {
+  // No reference hint for anonymous r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&&);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -162,6 +194,40 @@
ExpectedHint{"good: ", "good"});
 }
 
+TEST(ParameterHints, NameConstReference) {
+  // Only name hint for const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
+TEST(ParameterHints, NameReference) {
+  // Reference and name hint for l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"param: &", "param"});
+}
+
+TEST(ParameterHints, NameRValueReference) {
+  // Only name hint for r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
 TEST(ParameterHints, Operator) {
   // No hint for operator call with operator syntax.
   assertParameterHints(R"cpp(
@@ -301,6 +367,21 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, ArgMatchesParamReference) {
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void foo2(const int& param);
+void bar() {
+  int param;
+  // show reference hint on mutable reference
+  foo($param[[param]]);
+  // but not on const reference
+  foo2(param);
+}
+  )cpp",
+   ExpectedHint{"&", "param"});
+}
+
 TEST(ParameterHints, LeadingUnderscore) {
   assertParameterHints(R"cpp(
 void foo(int p1, int _p2, int __p3);
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "HeuristicResolver.h"
 #include "ParsedAST.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -392,6 +393,7 @@
 // Don't show hints for variadic parameters.
 size_t FixedParamCount = getFixedParamCount(Callee);
 size_t ArgCount = std::min(FixedParamCount, Args.size());
+auto Params = Callee->parameters();
 
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
@@ -402,12 +404,18 @@
 
 for (size_t I = 0; I < ArgCount; ++I) {
   StringRef Name = ParameterNames[I];
-  if (!shouldHint(Args[I], Name))
-continue;
+  bool NameHint = shouldNameHint(Args[I], Name);
+  std::string Suffix = ": ";
+  if (!NameHint) {
+Name = "";
+Suffix = "";
+  }
+  Suffix += getRefSuffix(Params[I]);
 
-  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
-   InlayHintKind::ParameterHint, /*Prefix=*/"", Name,
-   /*Suffix=*/": ");
+  if (!Name.empty() || !Suffix.empty()) {
+addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
+ InlayHintKind::ParameterHint, /*Prefix=*/"", Name, Suffix);
+  }
 }
   }
 
@@ -434,12 +442,21 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
-  bool shouldHint(const Expr *Arg, StringRef ParamName) {
+  StringRef getRefSuffix(const ParmVarDecl *Param) {
+// If the parameter is a non-const reference type, print an inlay hint
+auto Type = Param->getType();
+retur

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-04-30 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added a reviewer: nridge.
Herald added subscribers: usaxena95, kadircet, arphaman.
Herald added a project: All.
upsj updated this revision to Diff 426127.
upsj added a comment.
upsj added a reviewer: sammccall.
upsj updated this revision to Diff 426224.
upsj updated this revision to Diff 426225.
upsj published this revision for review.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

remove accidentally committed file


upsj added a comment.

remove dependency on D124359  and add tests


upsj added a comment.

remove unnecessary changes




Comment at: clang-tools-extra/clangd/InlayHints.cpp:388
+// arguments
+auto ForwardedParmMatcher = compoundStmt(forEachDescendant(
+invocation(

We tend not to use ASTMatchers for these kind of tasks in clangd (except when 
embedding clang-tidy checks of course).

I guess the biggest technical reason is it's hard to reason about their 
performance so they end up slow and opaque (and indeed the clang-tidy checks 
are slow and we haven't got a clear idea how to fix it). It's also easy to 
match too much.

But part of it is just convention - because we have more RecursiveASTVisitors, 
the maintainers are more familiar with the quirks there than the quirks of 
matchers.

---

To be clear, I don't see any specific problems with this code! But we still 
might ask to change it as there are costs to mixing styles, and we don't want 
to end up in a situation where a bug fix requires choosing between an expensive 
hasAncestor() matcher and rewriting the logic.



Comment at: clang-tools-extra/clangd/InlayHints.cpp:388
+// arguments
+auto ForwardedParmMatcher = compoundStmt(forEachDescendant(
+invocation(

sammccall wrote:
> We tend not to use ASTMatchers for these kind of tasks in clangd (except when 
> embedding clang-tidy checks of course).
> 
> I guess the biggest technical reason is it's hard to reason about their 
> performance so they end up slow and opaque (and indeed the clang-tidy checks 
> are slow and we haven't got a clear idea how to fix it). It's also easy to 
> match too much.
> 
> But part of it is just convention - because we have more 
> RecursiveASTVisitors, the maintainers are more familiar with the quirks there 
> than the quirks of matchers.
> 
> ---
> 
> To be clear, I don't see any specific problems with this code! But we still 
> might ask to change it as there are costs to mixing styles, and we don't want 
> to end up in a situation where a bug fix requires choosing between an 
> expensive hasAncestor() matcher and rewriting the logic.
That makes sense. From the Visitor standpoint, do I understand correctly that 
you mean something like remembering the top-level templated `FunctionDecl` (or 
stack of `FunctionDecl`s if we have something like nested Lambdas?) and check 
every `CallExpr` and `CXXConstructExpr` for `ParmVarDecls` or 
`std::forward(ParmVarDecl)` matching the parameters of the higher-level 
`FunctionDecls`? That means basically lazily evaluating the parameter names, so 
more storage inside the Visitor, but allows us to do recursive resolution in a 
rather straightforward fashion.



Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:255
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}

I haven't been able to figure out why, but for some reason the 
`CXXConstructExpr` and `CXXTemporaryObjectExpr` are not being picked up by the 
`RecursiveASTVisitor`, while in a similar situation below, the `CallExpr` gets 
picked up by `VisitCallExpr`.



Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:270
+  )cpp",
+   ExpectedHint{"a: ", "wrapped"},
+   ExpectedHint{"a: ", "param"});

This is a bit of an unfortunate side-effect of looking at instantiated 
templates.


This adds special-case treatment for parameter packs in make_unique-like 
functions to forward parameter names to inlay hints.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -162,6 +162,159 @@
ExpectedHint{"good: ", "good"});
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonym

[PATCH] D124373: [clang] add parameter pack/pack expansion matchers

2022-05-01 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj abandoned this revision.
upsj added a comment.

I think we should be able to do this without adding new matchers globally.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124373

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


[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-05-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 426343.
upsj marked 4 inline comments as done.
upsj added a comment.

address review comments: Move reference hint to the prefix, test type aliases


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124359

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -157,18 +157,17 @@
   foo($param[[i]]);
 }
   )cpp",
-   ExpectedHint{"&", "param"});
+   ExpectedHint{"&: ", "param"});
 }
 
 TEST(ParameterHints, NoNameRValueReference) {
-  // Reference hint for anonymous r-value ref parameter.
+  // No reference hint for anonymous r-value ref parameter.
   assertParameterHints(R"cpp(
 void foo(int&&);
 void bar() {
   foo($param[[42]]);
 }
-  )cpp",
-   ExpectedHint{"&&", "param"});
+  )cpp");
 }
 
 TEST(ParameterHints, NameInDefinition) {
@@ -215,18 +214,31 @@
   foo($param[[i]]);
 }
   )cpp",
-   ExpectedHint{"param: &", "param"});
+   ExpectedHint{"¶m: ", "param"});
+}
+
+TEST(ParameterHints, NameTypeAliasReference) {
+  // Reference and name hint for l-value ref parameter via type alias.
+  assertParameterHints(R"cpp(
+using alias = int&;
+void foo(alias param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"¶m: ", "param"});
 }
 
 TEST(ParameterHints, NameRValueReference) {
-  // Reference and name hint for r-value ref parameter.
+  // Only name hint for r-value ref parameter.
   assertParameterHints(R"cpp(
 void foo(int&& param);
 void bar() {
   foo($param[[42]]);
 }
   )cpp",
-   ExpectedHint{"param: &&", "param"});
+   ExpectedHint{"param: ", "param"});
 }
 
 TEST(ParameterHints, Operator) {
@@ -380,7 +392,7 @@
   foo2(param);
 }
   )cpp",
-   ExpectedHint{"&", "param"});
+   ExpectedHint{"&: ", "param"});
 }
 
 TEST(ParameterHints, LeadingUnderscore) {
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -404,17 +404,13 @@
 
 for (size_t I = 0; I < ArgCount; ++I) {
   StringRef Name = ParameterNames[I];
-  bool NameHint = shouldNameHint(Args[I], Name);
-  std::string Suffix = ": ";
-  if (!NameHint) {
-Name = "";
-Suffix = "";
-  }
-  Suffix += getRefSuffix(Params[I]);
+  bool NameHint = shouldHintName(Args[I], Name);
+  bool ReferenceHint = shouldHintReference(Params[I]);
 
-  if (!Name.empty() || !Suffix.empty()) {
+  if (NameHint || ReferenceHint) {
 addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
- InlayHintKind::ParameterHint, /*Prefix=*/"", Name, Suffix);
+ InlayHintKind::ParameterHint, ReferenceHint ? "&" : "",
+ NameHint ? Name : "", ": ");
   }
 }
   }
@@ -442,16 +438,7 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
-  StringRef getRefSuffix(const ParmVarDecl *Param) {
-// If the parameter is a non-const reference type, print an inlay hint
-auto Type = Param->getType();
-return Type->isReferenceType() &&
-   !Type.getNonReferenceType().isConstQualified()
-   ? (Type->isLValueReferenceType() ? "&" : "&&")
-   : "";
-  }
-
-  bool shouldNameHint(const Expr *Arg, StringRef ParamName) {
+  bool shouldHintName(const Expr *Arg, StringRef ParamName) {
 if (ParamName.empty())
   return false;
 
@@ -467,6 +454,13 @@
 return true;
   }
 
+  bool shouldHintReference(const ParmVarDecl *Param) {
+// If the parameter is a non-const reference type, print an inlay hint
+auto Type = Param->getType();
+return Type->isLValueReferenceType() &&
+   !Type.getNonReferenceType().isConstQualified();
+  }
+
   // Checks if "E" is spelled in the main file and preceded by a C-style comment
   // whose contents match ParamName (allowing for whitespace and an optional "="
   // at the end.
@@ -580,7 +574,7 @@
 return Result;
   }
 
-  // We pass HintSide rather than SourceLocation because we want to ensure 
+  // We pass HintSide rather than SourceLocation because we want to ensure
   // it is in the same file as the common file range.
   void addInlayHint(SourceRange R, HintSide Side, InlayHintKind Kind,
 llvm::StringRef Prefix, llvm::StringRef Label,

[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-05-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

Thanks, on second thought moving the hint to the prefix also makes more sense 
to me.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124359

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


[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-05-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 426344.
upsj added a comment.

right, arcanist doesn't entirely match my git mental model. Here's the 
(hopefully) complete patch


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124359

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -138,6 +138,38 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameConstReference) {
+  // No hint for anonymous const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int&);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameReference) {
+  // Reference hint for anonymous l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "param"});
+}
+
+TEST(ParameterHints, NoNameRValueReference) {
+  // No reference hint for anonymous r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&&);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -162,6 +194,53 @@
ExpectedHint{"good: ", "good"});
 }
 
+TEST(ParameterHints, NameConstReference) {
+  // Only name hint for const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
+TEST(ParameterHints, NameReference) {
+  // Reference and name hint for l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"¶m: ", "param"});
+}
+
+TEST(ParameterHints, NameTypeAliasReference) {
+  // Reference and name hint for l-value ref parameter via type alias.
+  assertParameterHints(R"cpp(
+using alias = int&;
+void foo(alias param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"¶m: ", "param"});
+}
+
+TEST(ParameterHints, NameRValueReference) {
+  // Only name hint for r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
 TEST(ParameterHints, Operator) {
   // No hint for operator call with operator syntax.
   assertParameterHints(R"cpp(
@@ -301,6 +380,21 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, ArgMatchesParamReference) {
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void foo2(const int& param);
+void bar() {
+  int param;
+  // show reference hint on mutable reference
+  foo($param[[param]]);
+  // but not on const reference
+  foo2(param);
+}
+  )cpp",
+   ExpectedHint{"&: ", "param"});
+}
+
 TEST(ParameterHints, LeadingUnderscore) {
   assertParameterHints(R"cpp(
 void foo(int p1, int _p2, int __p3);
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "HeuristicResolver.h"
 #include "ParsedAST.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -392,6 +393,7 @@
 // Don't show hints for variadic parameters.
 size_t FixedParamCount = getFixedParamCount(Callee);
 size_t ArgCount = std::min(FixedParamCount, Args.size());
+auto Params = Callee->parameters();
 
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
@@ -402,12 +404,14 @@
 
 for (size_t I = 0; I < ArgCount; ++I) {
   StringRef Name = ParameterNames[I];
-  if (!shouldHint(Args[I], Name))
-continue;
+  bool NameHint = shouldHintName(Args[I], Name);
+  bool ReferenceHint = shouldHintReference(Params[I]);
 
-  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
-   InlayHintKind::ParameterHint, /*Prefix=*/"", Name,
-   /*Suffix=*/": ");
+  if (NameHint || ReferenceHint) {
+addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
+ InlayHintKind::ParameterHint, ReferenceHint ? "&" : "",
+ NameHint ? Name : "", ": ");
+  }
  

[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-05-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 426346.
upsj marked an inline comment as done.
upsj added a comment.

add test for const ref inlay hint via type alias


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124359

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -138,6 +138,38 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameConstReference) {
+  // No hint for anonymous const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int&);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameReference) {
+  // Reference hint for anonymous l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "param"});
+}
+
+TEST(ParameterHints, NoNameRValueReference) {
+  // No reference hint for anonymous r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&&);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -162,6 +194,66 @@
ExpectedHint{"good: ", "good"});
 }
 
+TEST(ParameterHints, NameConstReference) {
+  // Only name hint for const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
+TEST(ParameterHints, NameTypeAliasConstReference) {
+  // Only name hint for const l-value ref parameter via type alias.
+  assertParameterHints(R"cpp(
+using alias = const int&;
+void foo(alias param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
+TEST(ParameterHints, NameReference) {
+  // Reference and name hint for l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"¶m: ", "param"});
+}
+
+TEST(ParameterHints, NameTypeAliasReference) {
+  // Reference and name hint for l-value ref parameter via type alias.
+  assertParameterHints(R"cpp(
+using alias = int&;
+void foo(alias param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"¶m: ", "param"});
+}
+
+TEST(ParameterHints, NameRValueReference) {
+  // Only name hint for r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
 TEST(ParameterHints, Operator) {
   // No hint for operator call with operator syntax.
   assertParameterHints(R"cpp(
@@ -301,6 +393,21 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, ArgMatchesParamReference) {
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void foo2(const int& param);
+void bar() {
+  int param;
+  // show reference hint on mutable reference
+  foo($param[[param]]);
+  // but not on const reference
+  foo2(param);
+}
+  )cpp",
+   ExpectedHint{"&: ", "param"});
+}
+
 TEST(ParameterHints, LeadingUnderscore) {
   assertParameterHints(R"cpp(
 void foo(int p1, int _p2, int __p3);
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "HeuristicResolver.h"
 #include "ParsedAST.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -392,6 +393,7 @@
 // Don't show hints for variadic parameters.
 size_t FixedParamCount = getFixedParamCount(Callee);
 size_t ArgCount = std::min(FixedParamCount, Args.size());
+auto Params = Callee->parameters();
 
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
@@ -402,12 +404,14 @@
 
 for (size_t I = 0; I < ArgCount; ++I) {
   StringRef Name = ParameterNames[I];
-  if (!shouldHint(Args[I], Name))
-continue;
+  bool NameHint = shouldHintName(Args[I], Name);
+  bool ReferenceHint = shouldHintReference(Params[I]);
 
-  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
-  

[PATCH] D124359: [clangd] Add inlay hints for mutable reference parameters

2022-05-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 426372.
upsj marked an inline comment as done.
upsj added a comment.

remove unnecessary annotation


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124359

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -138,6 +138,38 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameConstReference) {
+  // No hint for anonymous const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int&);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameReference) {
+  // Reference hint for anonymous l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "param"});
+}
+
+TEST(ParameterHints, NoNameRValueReference) {
+  // No reference hint for anonymous r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&&);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -162,6 +194,66 @@
ExpectedHint{"good: ", "good"});
 }
 
+TEST(ParameterHints, NameConstReference) {
+  // Only name hint for const l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(const int& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
+TEST(ParameterHints, NameTypeAliasConstReference) {
+  // Only name hint for const l-value ref parameter via type alias.
+  assertParameterHints(R"cpp(
+using alias = const int&;
+void foo(alias param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
+TEST(ParameterHints, NameReference) {
+  // Reference and name hint for l-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"¶m: ", "param"});
+}
+
+TEST(ParameterHints, NameTypeAliasReference) {
+  // Reference and name hint for l-value ref parameter via type alias.
+  assertParameterHints(R"cpp(
+using alias = int&;
+void foo(alias param);
+void bar() {
+  int i;
+  foo($param[[i]]);
+}
+  )cpp",
+   ExpectedHint{"¶m: ", "param"});
+}
+
+TEST(ParameterHints, NameRValueReference) {
+  // Only name hint for r-value ref parameter.
+  assertParameterHints(R"cpp(
+void foo(int&& param);
+void bar() {
+  foo($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"param: ", "param"});
+}
+
 TEST(ParameterHints, Operator) {
   // No hint for operator call with operator syntax.
   assertParameterHints(R"cpp(
@@ -301,6 +393,21 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, ArgMatchesParamReference) {
+  assertParameterHints(R"cpp(
+void foo(int& param);
+void foo2(const int& param);
+void bar() {
+  int param;
+  // show reference hint on mutable reference
+  foo($param[[param]]);
+  // but not on const reference
+  foo2(param);
+}
+  )cpp",
+   ExpectedHint{"&: ", "param"});
+}
+
 TEST(ParameterHints, LeadingUnderscore) {
   assertParameterHints(R"cpp(
 void foo(int p1, int _p2, int __p3);
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "HeuristicResolver.h"
 #include "ParsedAST.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -392,6 +393,7 @@
 // Don't show hints for variadic parameters.
 size_t FixedParamCount = getFixedParamCount(Callee);
 size_t ArgCount = std::min(FixedParamCount, Args.size());
+auto Params = Callee->parameters();
 
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
@@ -402,12 +404,14 @@
 
 for (size_t I = 0; I < ArgCount; ++I) {
   StringRef Name = ParameterNames[I];
-  if (!shouldHint(Args[I], Name))
-continue;
+  bool NameHint = shouldHintName(Args[I], Name);
+  bool ReferenceHint = shouldHintReference(Params[I]);
 
-  addInlayHint(Args[I]->getSourceRange(), HintSide::Left,
-   InlayHintKind::Parameter

[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 426387.
upsj marked 2 inline comments as done.
upsj added a comment.
Herald added a subscriber: javed.absar.

Rewrote detection of forwarding functions in preamble, added 
`--preamble-parse-forwarding` flag

I ran clangd over  `bits/stdc++.h`, and it seems like the condition works very 
well:

It picked up

- container::emplace and friends
- allocator::construct and friends
- make_unique, make_shared and friends
- some parts of `functional`
- some parts of `tuple`
- some parts of `thread`

most of which seem like good candidates for forwarding parameters.

In terms of runtime, I can't see any noticeable difference between parsing with 
or without `--preamble-parse-forwarding`, but of course, all of libstdc++ is 
not the most realistic scenario


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/Preamble.cpp
  clang-tools-extra/clangd/Preamble.h
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/TUScheduler.h
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/FileIndexTests.cpp
  clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
  clang-tools-extra/clangd/unittests/PreambleTests.cpp
  clang-tools-extra/clangd/unittests/TestTU.cpp

Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -101,7 +101,9 @@
   auto ModuleCacheDeleter = llvm::make_scope_exit(
   std::bind(deleteModuleCache, CI->getHeaderSearchOpts().ModuleCachePath));
   return clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
-  /*StoreInMemory=*/true, PreambleCallback);
+  /*StoreInMemory=*/true,
+  /*ParseForwardingFunctions=*/false,
+  PreambleCallback);
 }
 
 ParsedAST TestTU::build() const {
@@ -115,9 +117,10 @@
   auto ModuleCacheDeleter = llvm::make_scope_exit(
   std::bind(deleteModuleCache, CI->getHeaderSearchOpts().ModuleCachePath));
 
-  auto Preamble = clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
-   /*StoreInMemory=*/true,
-   /*PreambleCallback=*/nullptr);
+  auto Preamble =
+  clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
+   /*StoreInMemory=*/true,
+   /*PreambleCallback=*/false, nullptr);
   auto AST = ParsedAST::build(testPath(Filename), Inputs, std::move(CI),
   Diags.take(), Preamble);
   if (!AST.hasValue()) {
Index: clang-tools-extra/clangd/unittests/PreambleTests.cpp
===
--- clang-tools-extra/clangd/unittests/PreambleTests.cpp
+++ clang-tools-extra/clangd/unittests/PreambleTests.cpp
@@ -173,7 +173,8 @@
   TU.AdditionalFiles["c.h"] = "";
   auto PI = TU.inputs(FS);
   auto BaselinePreamble = buildPreamble(
-  TU.Filename, *buildCompilerInvocation(PI, Diags), PI, true, nullptr);
+  TU.Filename, *buildCompilerInvocation(PI, Diags), PI,
+  /*StoreInMemory=*/true, /*ParseForwardingFunctions=*/false, nullptr);
   // We drop c.h from modified and add a new header. Since the latter is patched
   // we should only get a.h in preamble includes.
   TU.Code = R"cpp(
Index: clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
===
--- clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
+++ clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
@@ -497,7 +497,8 @@
   auto Inputs = TU.inputs(FS);
   auto CI = buildCompilerInvocation(Inputs, Diags);
   auto EmptyPreamble =
-  buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
+  buildPreamble(testPath("foo.cpp"), *CI, Inputs, /*StoreInMemory=*/true,
+/*PreambleCallback=*/false, nullptr);
   ASSERT_TRUE(EmptyPreamble);
   EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, IsEmpty());
 
@@ -540,7 +541,8 @@
   auto Inputs = TU.inputs(FS);
   auto CI = buildCompilerInvocation(Inputs, Diags);
   auto BaselinePreamble =
-  buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
+  buildPreamble(testPath("foo.cpp"), *CI, Inputs, /*StoreInMemory=*/true,
+/*PreambleCallback=*/false, nullptr);
   ASSERT_TRUE(BaselinePreamble);
   EXPECT_THAT(BaselinePreamble->Includes.MainFileIncludes,
   ElementsAre(testing::Field(&Inclusion::Written, "

[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/Preamble.cpp:167
+// ... whose template parameter comes from the function directly
+if (FT->getTemplateParameters()->getDepth() ==
+PackTypePtr->getDepth()) {

Can PackTypePtr ever be nullptr?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/InlayHints.cpp:474
+// the parameter names from the wrapped function
+if (Args.size() > FixedParamCount && Args.size() == Params.size()) {
+  auto ForwardedParams = matchForwardedParams(

nridge wrote:
> What is the reason for the `Args.size() == Params.size()` condition?
> 
> Doesn't this break cases where there is more than one argument matching the 
> variadic parameter? For example:
> 
> ```
> void foo(int a, int b);
> template 
> void bar(Args&&... args) { foo(args...); }
> int main() {
>   bar(1, 2);
> }
> ```
> 
> Here, I expect we'd have `Args.size() == 2` and `Params.size() == 1`.
> 
> (We should probably have test coverage for such multiple-arguments cases as 
> well. We probably don't need it for all combinations, but we should have at 
> least one test case exercising it.)
The function we are looking at is an already instantiated template. The check 
`Args.size() == Params.size()` is only necessary because of va_args


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-04 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj planned changes to this revision.
upsj added a comment.

I will take a different approach to the matchers: For each CallExpr involving 
parameter packs, record the arguments (if they are a ParmVarDecl or 
stdForward(ParmVarDecl)) and the matching ParmVarDecl of the FunctionDecl in a 
map. Then I will compact that map to skip intermediate forwarding functions 
like emplace_back -> allocator::construct -> constructor and in a second pass 
resolve all previously unresolved forwarded parameters.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-05 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

> ! In D124690#3493246 , @sammccall 
> wrote:
>
> This makes sense to me.
>  This sounds more complicated, but if I'm reading correctly this multi-level 
> forwarding isn't handled in the current version of the patch either?
>  At some point we'll want to extract this logic out so it can be used by 
> hover etc, but not yet.

Yes, currently only direct forwarding works. I originally looked at this when 
inlay hints were not yet available, and it seemed possible to do this for 
signature help as well, only most likely based on the template instantiation 
pattern instead of the instantiated function declaration.




Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:255
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}

sammccall wrote:
> upsj wrote:
> > I haven't been able to figure out why, but for some reason the 
> > `CXXConstructExpr` and `CXXTemporaryObjectExpr` are not being picked up by 
> > the `RecursiveASTVisitor`, while in a similar situation below, the 
> > `CallExpr` gets picked up by `VisitCallExpr`.
> The AST here of the instantiated bar looks like
> ```
> -FunctionDecl  line:5:4 used bar 'S *(int &&)'
>   |-TemplateArgument type 'S'
>   |-TemplateArgument pack
>   | `-TemplateArgument type 'int'
>   |-ParmVarDecl  col:18 used args 'int &&'
>   `-CompoundStmt 
> `-ReturnStmt 
>   `-CXXNewExpr  'S *' Function 'operator new' 'void 
> *(unsigned long)'
> `-CXXConstructExpr  'S':'S' 'void (int)' list
>   `-ImplicitCastExpr  'int':'int' 
> `-DeclRefExpr  'int':'int' lvalue ParmVar 'args' 'int &&'
> ```
> 
> So there's no CXXTemporaryObjectExpr (the value here is a pointer), but 
> should be a CXXConstructExpr. 
> 
> Are you sure you're traversing bar's instantiation/specializaion, as opposed 
> to its templated/generic FunctionDecl? The AST of the templated FunctionDecl 
> indeed has an InitListExpr in place of the CXXConstructExpr because it's not 
> resolved yet.
It's quite possible this is related to the visitor not/only inconsistently 
traversing template instantiations due to shouldVisitTemplateInstantiations 
returning false. But I need to implement the new approach first, anyways.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-07 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427851.
upsj added a comment.
Herald added a subscriber: javed.absar.

use an RecursiveASTVisitor instead of ASTMatcher


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/Preamble.cpp
  clang-tools-extra/clangd/Preamble.h
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/TUScheduler.h
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/FileIndexTests.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp
  clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
  clang-tools-extra/clangd/unittests/PreambleTests.cpp
  clang-tools-extra/clangd/unittests/TestTU.cpp

Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -101,7 +101,9 @@
   auto ModuleCacheDeleter = llvm::make_scope_exit(
   std::bind(deleteModuleCache, CI->getHeaderSearchOpts().ModuleCachePath));
   return clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
-  /*StoreInMemory=*/true, PreambleCallback);
+  /*StoreInMemory=*/true,
+  /*ParseForwardingFunctions=*/false,
+  PreambleCallback);
 }
 
 ParsedAST TestTU::build() const {
@@ -115,9 +117,10 @@
   auto ModuleCacheDeleter = llvm::make_scope_exit(
   std::bind(deleteModuleCache, CI->getHeaderSearchOpts().ModuleCachePath));
 
-  auto Preamble = clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
-   /*StoreInMemory=*/true,
-   /*PreambleCallback=*/nullptr);
+  auto Preamble =
+  clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
+   /*StoreInMemory=*/true,
+   /*PreambleCallback=*/false, nullptr);
   auto AST = ParsedAST::build(testPath(Filename), Inputs, std::move(CI),
   Diags.take(), Preamble);
   if (!AST.hasValue()) {
Index: clang-tools-extra/clangd/unittests/PreambleTests.cpp
===
--- clang-tools-extra/clangd/unittests/PreambleTests.cpp
+++ clang-tools-extra/clangd/unittests/PreambleTests.cpp
@@ -173,7 +173,8 @@
   TU.AdditionalFiles["c.h"] = "";
   auto PI = TU.inputs(FS);
   auto BaselinePreamble = buildPreamble(
-  TU.Filename, *buildCompilerInvocation(PI, Diags), PI, true, nullptr);
+  TU.Filename, *buildCompilerInvocation(PI, Diags), PI,
+  /*StoreInMemory=*/true, /*ParseForwardingFunctions=*/false, nullptr);
   // We drop c.h from modified and add a new header. Since the latter is patched
   // we should only get a.h in preamble includes.
   TU.Code = R"cpp(
Index: clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
===
--- clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
+++ clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
@@ -497,7 +497,8 @@
   auto Inputs = TU.inputs(FS);
   auto CI = buildCompilerInvocation(Inputs, Diags);
   auto EmptyPreamble =
-  buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
+  buildPreamble(testPath("foo.cpp"), *CI, Inputs, /*StoreInMemory=*/true,
+/*PreambleCallback=*/false, nullptr);
   ASSERT_TRUE(EmptyPreamble);
   EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, IsEmpty());
 
@@ -540,7 +541,8 @@
   auto Inputs = TU.inputs(FS);
   auto CI = buildCompilerInvocation(Inputs, Diags);
   auto BaselinePreamble =
-  buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
+  buildPreamble(testPath("foo.cpp"), *CI, Inputs, /*StoreInMemory=*/true,
+/*PreambleCallback=*/false, nullptr);
   ASSERT_TRUE(BaselinePreamble);
   EXPECT_THAT(BaselinePreamble->Includes.MainFileIncludes,
   ElementsAre(testing::Field(&Inclusion::Written, "")));
Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -170,6 +170,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-07 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj marked 10 inline comments as done.
upsj added a comment.

This almost works now, the only thing that needs to be fixed is 
`isExpandedParameter`, which for some reason picks up the first call, but not 
the second: (Compare `ParameterHints.Forwarded` and 
`ParameterHints.VariadicPlain`)

  cpp
  void foo(int a);
  template 
  void bar(Args&&... args) { return foo(args...); }
  void baz() {
int b;
bar(42); // This parameter is recognized as expanded
bar(b); // This one doesn't, so its inlay hint is @args: instead of a:
  }




Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:178
+  // No hint for anonymous variadic parameter
+  // The prototype is not correct, but is converted into builtin anyways.
+  assertParameterHints(R"cpp(

nridge wrote:
> What does "converted into builtin" mean here?
I am talking about std::forward being a builtin function, which can be detected 
by its BuiltinID, so it doesn't matter if the signature doesn't match 100%.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-07 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427852.
upsj added a comment.

Work around the currently broken isExpandedParameter, also fix the broken diff


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -170,6 +170,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -254,6 +291,123 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, MatchingNameVariadicForwarded) {
+  // No name hint for variadic parameter with matching name
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int a;
+  bar(a);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, MatchingNameVariadicPlain) {
+  // No name hint for variadic parameter with matching name
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+void bar(Args&&... args) { return fo

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-07 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427853.
upsj marked an inline comment as done.
upsj added a comment.

Work around the currently broken isExpandedParameter, also fix the broken diff


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -170,6 +170,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -254,6 +291,123 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, MatchingNameVariadicForwarded) {
+  // No name hint for variadic parameter with matching name
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int a;
+  bar(a);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, MatchingNameVariadicPlain) {
+  // No name hint for variadic parameter with matching name
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+ 

[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-07 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427854.
upsj added a comment.

accidentally pushed to the wrong revision, this is the previous version


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/Preamble.cpp
  clang-tools-extra/clangd/Preamble.h
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/TUScheduler.h
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/FileIndexTests.cpp
  clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
  clang-tools-extra/clangd/unittests/PreambleTests.cpp
  clang-tools-extra/clangd/unittests/TestTU.cpp

Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -101,7 +101,9 @@
   auto ModuleCacheDeleter = llvm::make_scope_exit(
   std::bind(deleteModuleCache, CI->getHeaderSearchOpts().ModuleCachePath));
   return clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
-  /*StoreInMemory=*/true, PreambleCallback);
+  /*StoreInMemory=*/true,
+  /*ParseForwardingFunctions=*/false,
+  PreambleCallback);
 }
 
 ParsedAST TestTU::build() const {
@@ -115,9 +117,10 @@
   auto ModuleCacheDeleter = llvm::make_scope_exit(
   std::bind(deleteModuleCache, CI->getHeaderSearchOpts().ModuleCachePath));
 
-  auto Preamble = clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
-   /*StoreInMemory=*/true,
-   /*PreambleCallback=*/nullptr);
+  auto Preamble =
+  clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs,
+   /*StoreInMemory=*/true,
+   /*PreambleCallback=*/false, nullptr);
   auto AST = ParsedAST::build(testPath(Filename), Inputs, std::move(CI),
   Diags.take(), Preamble);
   if (!AST.hasValue()) {
Index: clang-tools-extra/clangd/unittests/PreambleTests.cpp
===
--- clang-tools-extra/clangd/unittests/PreambleTests.cpp
+++ clang-tools-extra/clangd/unittests/PreambleTests.cpp
@@ -173,7 +173,8 @@
   TU.AdditionalFiles["c.h"] = "";
   auto PI = TU.inputs(FS);
   auto BaselinePreamble = buildPreamble(
-  TU.Filename, *buildCompilerInvocation(PI, Diags), PI, true, nullptr);
+  TU.Filename, *buildCompilerInvocation(PI, Diags), PI,
+  /*StoreInMemory=*/true, /*ParseForwardingFunctions=*/false, nullptr);
   // We drop c.h from modified and add a new header. Since the latter is patched
   // we should only get a.h in preamble includes.
   TU.Code = R"cpp(
Index: clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
===
--- clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
+++ clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
@@ -497,7 +497,8 @@
   auto Inputs = TU.inputs(FS);
   auto CI = buildCompilerInvocation(Inputs, Diags);
   auto EmptyPreamble =
-  buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
+  buildPreamble(testPath("foo.cpp"), *CI, Inputs, /*StoreInMemory=*/true,
+/*PreambleCallback=*/false, nullptr);
   ASSERT_TRUE(EmptyPreamble);
   EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, IsEmpty());
 
@@ -540,7 +541,8 @@
   auto Inputs = TU.inputs(FS);
   auto CI = buildCompilerInvocation(Inputs, Diags);
   auto BaselinePreamble =
-  buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
+  buildPreamble(testPath("foo.cpp"), *CI, Inputs, /*StoreInMemory=*/true,
+/*PreambleCallback=*/false, nullptr);
   ASSERT_TRUE(BaselinePreamble);
   EXPECT_THAT(BaselinePreamble->Includes.MainFileIncludes,
   ElementsAre(testing::Field(&Inclusion::Written, "")));
Index: clang-tools-extra/clangd/unittests/FileIndexTests.cpp
===
--- clang-tools-extra/clangd/unittests/FileIndexTests.cpp
+++ clang-tools-extra/clangd/unittests/FileIndexTests.cpp
@@ -306,7 +306,7 @@
   FileIndex Index;
   bool IndexUpdated = false;
   buildPreamble(FooCpp, *CI, PI,
-/*StoreInMemory=*/true,
+/*StoreInMemory=*/true, /*ParseForwardingFunctions=*/false,
 [&](ASTContext &Ctx, Preprocessor &PP,
 const CanonicalIncludes &CanonIncludes) {
   EXPECT_FALSE(IndexUpdated)
Index: clang-

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-07 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427855.
upsj added a comment.

updated patch baseline


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -170,6 +170,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -254,6 +291,123 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, MatchingNameVariadicForwarded) {
+  // No name hint for variadic parameter with matching name
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int a;
+  bar(a);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, MatchingNameVariadicPlain) {
+  // No name hint for variadic parameter with matching name
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  int a;
+  bar

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-07 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427861.
upsj added a comment.

fix iterator invalidation issue, handle UnresolvedLookupExpr and test recursive 
and split variadic lookup


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -170,6 +170,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -182,6 +219,19 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -254,6 +304,168 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicSplitRecursive) {
+  // Name for va

[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-08 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427910.
upsj marked 13 inline comments as done.
upsj added a comment.

review updates:

- Pass ParseForwardingFunctions via ParseOptions
- Simplify check for forwarding function
- Add test checking diagnostics for make_shared


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/Compiler.h
  clang-tools-extra/clangd/Preamble.cpp
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
  clang-tools-extra/clangd/unittests/TestTU.cpp
  clang-tools-extra/clangd/unittests/TestTU.h

Index: clang-tools-extra/clangd/unittests/TestTU.h
===
--- clang-tools-extra/clangd/unittests/TestTU.h
+++ clang-tools-extra/clangd/unittests/TestTU.h
@@ -81,7 +81,7 @@
   // By default, build() will report Error diagnostics as GTest errors.
   // Suppress this behavior by adding an 'error-ok' comment to the code.
   // The result will always have getDiagnostics() populated.
-  ParsedAST build() const;
+  ParsedAST build(ParseOptions Opts = {}) const;
   std::shared_ptr
   preamble(PreambleParsedCallback PreambleCallback = nullptr) const;
   ParseInputs inputs(MockFS &FS) const;
Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -104,9 +104,10 @@
   /*StoreInMemory=*/true, PreambleCallback);
 }
 
-ParsedAST TestTU::build() const {
+ParsedAST TestTU::build(ParseOptions Opts) const {
   MockFS FS;
   auto Inputs = inputs(FS);
+  Inputs.Opts = Opts;
   StoreDiags Diags;
   auto CI = buildCompilerInvocation(Inputs, Diags);
   assert(CI && "Failed to build compilation invocation.");
Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
===
--- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -402,6 +402,31 @@
"no matching constructor for initialization of 'S'")));
 }
 
+TEST(DiagnosticTest, MakeShared) {
+  // We usually miss diagnostics from header functions as we don't parse them.
+  // std::make_shared is an exception.
+  Annotations Main(R"cpp(
+struct S { S(char*); };
+auto x = std::[[make_shared]](42); // error-ok
+  )cpp");
+  TestTU TU = TestTU::withCode(Main.code());
+  TU.HeaderCode = R"cpp(
+namespace std {
+// These mocks aren't quite right - we omit shared_ptr for simplicity.
+// forward is included to show its body is not needed to get the diagnostic.
+template  T&& forward(T& t) { return static_cast(t); }
+template  T* make_shared(A&&... args) {
+   return new T(std::forward(args)...);
+}
+}
+  )cpp";
+  EXPECT_THAT(
+  *TU.build({/*PreambleParseForwardingFunctions=*/true}).getDiagnostics(),
+  UnorderedElementsAre(Diag(
+  Main.range(), "in template: "
+"no matching constructor for initialization of 'S'")));
+}
+
 TEST(DiagnosticTest, NoMultipleDiagnosticInFlight) {
   Annotations Main(R"cpp(
 template  struct Foo {
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -498,6 +498,14 @@
   Hidden,
   init(ClangdServer::Options().UseDirtyHeaders)};
 
+opt PreambleParseForwardingFunctions{
+"parse-forwarding-functions",
+cat(Misc),
+desc("Parse all emplace-like functions in included headers"),
+Hidden,
+init(ParseOptions().PreambleParseForwardingFunctions),
+};
+
 #if defined(__GLIBC__) && CLANGD_MALLOC_TRIM
 opt EnableMallocTrim{
 "malloc-trim",
@@ -935,6 +943,7 @@
 Opts.ClangTidyProvider = ClangTidyOptProvider;
   }
   Opts.UseDirtyHeaders = UseDirtyHeaders;
+  Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
   Opts.QueryDriverGlobs = std::move(QueryDriverGlobs);
   Opts.TweakFilter = [&](const Tweak &T) {
 if (T.hidden() && !HiddenFeatures)
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -126,6 +126,8 @@
 Inputs.CompileCommand = Cmd;
 Inputs.TFS = &TFS;
 Inputs.ClangTidyProvider = Opts.ClangTidyProvider;
+Inputs.Opts.PreambleParseForwardingFunctions =
+Opts.PreambleParseForwardingFunctions;
 if (Contents.hasValue()) {
   Input

[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-08 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427911.
upsj added a comment.

update test docs


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/Compiler.h
  clang-tools-extra/clangd/Preamble.cpp
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
  clang-tools-extra/clangd/unittests/TestTU.cpp
  clang-tools-extra/clangd/unittests/TestTU.h

Index: clang-tools-extra/clangd/unittests/TestTU.h
===
--- clang-tools-extra/clangd/unittests/TestTU.h
+++ clang-tools-extra/clangd/unittests/TestTU.h
@@ -81,7 +81,7 @@
   // By default, build() will report Error diagnostics as GTest errors.
   // Suppress this behavior by adding an 'error-ok' comment to the code.
   // The result will always have getDiagnostics() populated.
-  ParsedAST build() const;
+  ParsedAST build(ParseOptions Opts = {}) const;
   std::shared_ptr
   preamble(PreambleParsedCallback PreambleCallback = nullptr) const;
   ParseInputs inputs(MockFS &FS) const;
Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -104,9 +104,10 @@
   /*StoreInMemory=*/true, PreambleCallback);
 }
 
-ParsedAST TestTU::build() const {
+ParsedAST TestTU::build(ParseOptions Opts) const {
   MockFS FS;
   auto Inputs = inputs(FS);
+  Inputs.Opts = Opts;
   StoreDiags Diags;
   auto CI = buildCompilerInvocation(Inputs, Diags);
   assert(CI && "Failed to build compilation invocation.");
Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
===
--- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -402,6 +402,31 @@
"no matching constructor for initialization of 'S'")));
 }
 
+TEST(DiagnosticTest, MakeShared) {
+  // We usually miss diagnostics from header functions as we don't parse them.
+  // std::make_shared is only parsed when --parse-forwarding-functions is set
+  Annotations Main(R"cpp(
+struct S { S(char*); };
+auto x = std::[[make_shared]](42); // error-ok
+  )cpp");
+  TestTU TU = TestTU::withCode(Main.code());
+  TU.HeaderCode = R"cpp(
+namespace std {
+// These mocks aren't quite right - we omit shared_ptr for simplicity.
+// forward is included to show its body is not needed to get the diagnostic.
+template  T&& forward(T& t) { return static_cast(t); }
+template  T* make_shared(A&&... args) {
+   return new T(std::forward(args)...);
+}
+}
+  )cpp";
+  EXPECT_THAT(
+  *TU.build({/*PreambleParseForwardingFunctions=*/true}).getDiagnostics(),
+  UnorderedElementsAre(Diag(
+  Main.range(), "in template: "
+"no matching constructor for initialization of 'S'")));
+}
+
 TEST(DiagnosticTest, NoMultipleDiagnosticInFlight) {
   Annotations Main(R"cpp(
 template  struct Foo {
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -498,6 +498,14 @@
   Hidden,
   init(ClangdServer::Options().UseDirtyHeaders)};
 
+opt PreambleParseForwardingFunctions{
+"parse-forwarding-functions",
+cat(Misc),
+desc("Parse all emplace-like functions in included headers"),
+Hidden,
+init(ParseOptions().PreambleParseForwardingFunctions),
+};
+
 #if defined(__GLIBC__) && CLANGD_MALLOC_TRIM
 opt EnableMallocTrim{
 "malloc-trim",
@@ -935,6 +943,7 @@
 Opts.ClangTidyProvider = ClangTidyOptProvider;
   }
   Opts.UseDirtyHeaders = UseDirtyHeaders;
+  Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
   Opts.QueryDriverGlobs = std::move(QueryDriverGlobs);
   Opts.TweakFilter = [&](const Tweak &T) {
 if (T.hidden() && !HiddenFeatures)
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -126,6 +126,8 @@
 Inputs.CompileCommand = Cmd;
 Inputs.TFS = &TFS;
 Inputs.ClangTidyProvider = Opts.ClangTidyProvider;
+Inputs.Opts.PreambleParseForwardingFunctions =
+Opts.PreambleParseForwardingFunctions;
 if (Contents.hasValue()) {
   Inputs.Contents = *Contents;
   log("Imaginary source file contents:\n{0}", Inputs.Contents);
Index: clang-tools-extra/clangd/Preamble.cpp
=

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-08 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427928.
upsj added a comment.

- add test for emplace-like functions
- fix RecursiveASTVisitor early exit
- fix handling of skipped parameters


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -170,6 +170,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -182,6 +219,19 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -254,6 +304,206 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicSplitRecursive) {
+  // Name f

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-08 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 427930.
upsj added a comment.

attempt to fix the patch issue


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -170,6 +170,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -182,6 +219,19 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -254,6 +304,206 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // The forward prototype is not correct, but is converted into builtin anyways
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar($param[[42]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicSplitRecursive) {
+  // Name for variadic parameter
+  // The forward prototype is not correct, but is converte

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-08 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/InlayHints.cpp:208
+// If the parameter is part of an expanded pack and not yet resolved
+if (/*isExpandedParameter(Param) && */
+ForwardedParams.find(Param) == ForwardedParams.end()) {

This needs to be fixed, see `ParameterHints.VariadicPlain` vs. 
`ParameterHints.VariadicForwarded` if uncommented - I'd need some input from 
somebody with more knowledge about the AST



Comment at: clang-tools-extra/clangd/InlayHints.cpp:314
+if (auto *FuncCandidate = dyn_cast_or_null(Candidate)) {
+  if (FuncCandidate->getNumParams() == D->getNumArgs()) {
+if (MatchingDecl) {

There is probably more generic functionality available for this?



Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:447
+namespace std { template  T&& forward(T&); }
+void *operator new(unsigned long, void *);
+struct S {

This is not portable, but I don't have access to size_t


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-08 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

It seems like except for the caveats I listed before, all the obvious cases 
seem to work: `make_unique`, `make_shared`, `emplace_back` with exact type 
matches. One point that still needs some work is if the parameter needs to be 
converted inside one of the forwarding functions (probably just needs another 
`unpack` inside ForwardingParameterVisitor), as well as a way to remove 
duplicate parameters that come from recursive templates like `std::tuple`. One 
obvious way would be removing inlay hints for duplicate parameters altogether, 
but that may not be enough/too heuristic? Alternatively, we could inspect the 
template instantiation pattern.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D130259: [clangd] fix crash and handle implicit conversions in inlay hints for forwarding functions

2022-07-21 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added reviewers: nridge, sammccall, kadircet.
upsj added a project: clang-tools-extra.
Herald added subscribers: usaxena95, arphaman.
Herald added a project: All.
upsj requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.

The `ForwardingCallVisitor` previously picked up on (constructor or function) 
calls inside a single argument of a variadic function, where the corresponding 
pack expression is (partially) expanded, but only consists of a single entry. 
This mismatch between expecting the full pack and finding only a single entry 
caused a crash, which the first half of this diff fixes.

The second half deals with the failure of `resolveForwardingParameters` to 
detect forwarded parameters when implicit conversions happen via constructor 
calls, not normal `ImplicitCastExpr`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130259

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -680,6 +680,71 @@
   ExpectedHint{"C: ", "param3"});
 }
 
+TEST(ParameterHints, VariadicWithConstructorConversion) {
+  // variadic call that involves a conversion via a (potentially implicitly
+  // provided) constructor, here move-construction Foo&& -> Foo
+  assertParameterHints(
+  R"cpp(
+struct Foo {};
+void foo(Foo s, int x);
+
+template 
+void bar(_Args ...__args) {
+  foo(__args...);
+}
+
+void foo() {
+  bar($param1[[Foo{}]], $param2[[3]]);
+}
+  )cpp",
+  ExpectedHint{"s: ", "param1"}, ExpectedHint{"x: ", "param2"});
+}
+
+TEST(ParameterHints, VariadicWithOperatorConversion) {
+  // variadic call that involves a conversion via an operator, here Foo -> Bar
+  assertParameterHints(
+  R"cpp(
+struct Bar {};
+struct Foo {
+  operator Bar();
+};
+void foo(Bar s, int x);
+
+template 
+void bar(_Args ...__args) {
+  foo(__args...);
+}
+
+void foo() {
+  bar($param1[[Foo{}]], $param2[[3]]);
+}
+  )cpp" /*, ExpectedHint{"s: ", "param1"}, ExpectedHint{"x: ", "param2"}*/);
+}
+
+TEST(ParameterHints, VariadicWithFunctionCall) {
+  // variadic call that involves an explicit transformation via a function, here
+  // we don't output an inlay hint, since it's not clear what transform does.
+  assertParameterHints(
+  R"cpp(
+struct Bar {};
+struct Foo {
+  operator Bar();
+};
+template 
+T transform(T);
+void foo(Bar s, int x);
+
+template 
+void bar(_Args ...__args) {
+  foo(transform(__args)...);
+}
+
+void foo() {
+  bar(Foo{}, 3);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, VariadicReferenceHint) {
   assertParameterHints(R"cpp(
 void foo(int&);
Index: clang-tools-extra/clangd/AST.cpp
===
--- clang-tools-extra/clangd/AST.cpp
+++ clang-tools-extra/clangd/AST.cpp
@@ -832,10 +832,26 @@
   }
   return false;
 });
-if (FirstMatch == Args.end()) {
-  return llvm::None;
+if (FirstMatch != Args.end()) {
+  const auto NumArgs =
+  static_cast(std::distance(Args.begin(), Args.end()));
+  const auto FirstMatchIdx =
+  static_cast(std::distance(Args.begin(), FirstMatch));
+  // Now we found the first parameter, check whether the last one also fits
+  // This is necessary because we may be matching a function call inside an
+  // argument of the variadic function if we didn't successfully match the
+  // outer variadic call.
+  const auto LastMatchIdx = FirstMatchIdx + Parameters.size() - 1;
+  if (LastMatchIdx < NumArgs) {
+if (const auto *RefArg =
+unwrapArgument(*(Args.begin() + LastMatchIdx))) {
+  if (Parameters.back() == dyn_cast(RefArg->getDecl())) {
+return FirstMatchIdx;
+  }
+}
+  }
 }
-return std::distance(Args.begin(), FirstMatch);
+return llvm::None;
   }
 
   static FunctionDecl *getCalleeDeclOrUniqueOverload(CallExpr *E) {
@@ -881,7 +897,7 @@
 return E;
   }
 
-  // Maps std::forward(E) to E, nullptr otherwise
+  // Maps std::forward(E) to E
   static const Expr *unwrapForward(const Expr *E) {
 if (const auto *Call = dyn_cast(E)) {
   const auto Callee = Call->getBuiltinCallee();
@@ -892,10 +908,26 @@
 return E;
   }
 
+  // Maps an argument implicitly calling a converting constructor to the
+  // constructor's argument
+  static const Expr *unwrapConstructorConversion(const Expr *E) {
+if (const auto *CBTE = dyn_cast(E)) {
+  E = CBTE->getSubExpr();
+}
+if (const auto *CCE = dyn_cast(E)) {
+  const auto *C = CCE->getConstructor();
+  

[PATCH] D130259: [clangd] fix crash and handle implicit conversions in inlay hints for forwarding functions

2022-07-21 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:721
+}
+  )cpp" /*, ExpectedHint{"s: ", "param1"}, ExpectedHint{"x: ", "param2"}*/);
+}

I'm not sure whether we should detect this case, since it would be nice to 
handle, but also involves digging deep through `CXXConstructExpression -> 
MaterializeTemporaryExpression -> CXXMemberCallExpr -> MemberExpr -> 
DeclRefExpr`


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130259

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


[PATCH] D130265: [clangd] resolve forwarded parameters in Hover

2022-07-21 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added reviewers: sammccall, kadircet.
upsj added a project: clang-tools-extra.
Herald added subscribers: usaxena95, arphaman.
Herald added a project: All.
upsj requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.

This uses `resolveForwardedParameters` to get parameter names in Hover. The 
patch currently produces a slight inconsistency, since the definition uses the 
original function decl, while the parameters are resolved correctly.
I could use some feedback on how this should be handled - maybe add a comment 
in the style of "This function involves forwarding" that explains why the 
parameter names don't match?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130265

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -263,6 +263,29 @@
  {{"bool"}, std::string("T"), std::string("false")},
  };
}},
+  // Forwarding function decl
+  {R"cpp(
+  void baz(int a);
+  template 
+  void foo(Args... args) {
+baz(args...);
+  }
+
+  void bar() {
+[[fo^o]](3);
+  }
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "foo";
+ HI.Kind = index::SymbolKind::Function;
+ HI.Definition = "template <> void foo << int >> (int args)";
+ HI.ReturnType = "void";
+ HI.Type = "void (int)";
+ HI.Parameters = {
+ {{"int"}, std::string("a"), llvm::None},
+ };
+   }},
   // Pointers to lambdas
   {R"cpp(
 void foo() {
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -369,7 +369,7 @@
const FunctionDecl *FD,
const PrintingPolicy &PP) {
   HI.Parameters.emplace();
-  for (const ParmVarDecl *PVD : FD->parameters())
+  for (const ParmVarDecl *PVD : resolveForwardingParameters(FD))
 HI.Parameters->emplace_back(toHoverInfoParam(PVD, PP));
 
   // We don't want any type info, if name already contains it. This is true for
@@ -385,7 +385,6 @@
   if (const VarDecl *VD = llvm::dyn_cast(D)) // Lambdas
 QT = VD->getType().getDesugaredType(D->getASTContext());
   HI.Type = printType(QT, D->getASTContext(), PP);
-  // FIXME: handle variadics.
 }
 
 // Non-negative numbers are printed using min digits


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -263,6 +263,29 @@
  {{"bool"}, std::string("T"), std::string("false")},
  };
}},
+  // Forwarding function decl
+  {R"cpp(
+  void baz(int a);
+  template 
+  void foo(Args... args) {
+baz(args...);
+  }
+
+  void bar() {
+[[fo^o]](3);
+  }
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "foo";
+ HI.Kind = index::SymbolKind::Function;
+ HI.Definition = "template <> void foo << int >> (int args)";
+ HI.ReturnType = "void";
+ HI.Type = "void (int)";
+ HI.Parameters = {
+ {{"int"}, std::string("a"), llvm::None},
+ };
+   }},
   // Pointers to lambdas
   {R"cpp(
 void foo() {
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -369,7 +369,7 @@
const FunctionDecl *FD,
const PrintingPolicy &PP) {
   HI.Parameters.emplace();
-  for (const ParmVarDecl *PVD : FD->parameters())
+  for (const ParmVarDecl *PVD : resolveForwardingParameters(FD))
 HI.Parameters->emplace_back(toHoverInfoParam(PVD, PP));
 
   // We don't want any type info, if name already contains it. This is true for
@@ -385,7 +385,6 @@
   if (const VarDecl *VD = llvm::dyn_cast(D)) // Lambdas
 QT = VD->getType().getDesugaredType(D->getASTContext());
   HI.Type = printType(QT, D->getASTContext(), PP);
-  // FIXME: handle variadics.
 }
 
 // Non-negative numbers are printed using min digits
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130259: [clangd] fix crash and handle implicit conversions in inlay hints for forwarding functions

2022-07-22 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj abandoned this revision.
upsj added a comment.

Superseded by https://reviews.llvm.org/D130260


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130259

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


[PATCH] D130260: [clangd] Make forwarding parameter detection logic resilient

2022-07-22 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

Your approach to handling implicit conversions is much nicer than mine, so I 
abandoned my revision. There is still one case (that might even occur in the 
code base I'm working on?) that this change would lead to incorrect hints on. 
WDYT about keeping the other changes, but using my pack detection logic?




Comment at: clang-tools-extra/clangd/AST.cpp:790
+// Skip functions with less parameters, they can't be the target.
+if (Callee->parameters().size() < Parameters.size())
+  return;

This is not a sufficient check, since the other parameters need not be from an 
expanded pack.
Example:
```
void foo(int a, int b);
int baz(int x, int y);
template 
void bar(Args... args) {
  foo(baz(args, 1)...);
}

void foo() {
  bar(1, 42);
}
```
Here we shouldn't print a hint at all, but we print `x:` and `y:`
The important distinction is between `Expr(args...)` and `Expr(args)...`, which 
can be decided in the instantiated case by the check I implemented in 
https://reviews.llvm.org/D130259 for all cases, except when `args` only 
consists of a single element.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130260

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


[PATCH] D130260: [clangd] Make forwarding parameter detection logic resilient

2022-07-22 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj accepted this revision.
upsj added a comment.
This revision is now accepted and ready to land.

Not sure I qualify as a suitable reviewer, but this looks really good to me, 
save for maybe a small safety measure :)




Comment at: clang-tools-extra/clangd/AST.cpp:833-837
+auto ParamEnd = It + Parameters.size() - 1;
+assert(std::distance(Args.begin(), ParamEnd) <
+   std::distance(Args.begin(), Args.end()) &&
+   "Only functions with greater than or equal number of parameters 
"
+   "should be checked.");

I think it would be safer to check this explicitly, since advancing the 
iterator past its end might be UB (depending on the implementation).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130260

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


[PATCH] D130260: [clangd] Make forwarding parameter detection logic resilient

2022-07-22 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/AST.cpp:832
   continue;
+// Check that this expands all the way until the last parameter.
+auto ParamEnd = It + Parameters.size() - 1;

sammccall wrote:
> The essence of this test seems to be "if we can't rule it out by counting 
> parameters, it must be right" which... doesn't seem very robust? Am I missing 
> something?
> 
> AIUI the idea here is that
> A) `foo(pack...)` is "expanded all the way" into consecutive arguments
> B) `foo(pack)...` is not considered forwarding for our purposes
> C) we want to treat `foo(bar(pack)...)` specially if `bar` is "just a cast" 
> like move or forward
> 
> The difference between cases A and B aren't about counting arguments though, 
> they're about what operations occur intercede between `pack` and the `...` 
> operator. (i.e. `foo((&pack)...)` is fine for the same reason `forward` is.
> 
> This seems like something best handled by:
>  - finding the `PackExpansionExpr` controlling `pack` in the non-instantiated 
> template AST
>  - walking down to try to find `pack`
>  - continue as we walk through e.g. parens or std::forward
>  - bail out if we walk through something unknown (e.g. another function call)
> 
> Does this seem sensible/feasible?
> (Walking up from `pack` is nicer but the AST doesn't support walking up 
> well...)
This goes a bit more generally into the question how to approach parameter 
packs across clangd. For inlay hints and hover, we are already looking at 
instantiated templates (is that true in all cases? Haven't dug in yet), so 
implementing forwarding there was straightforward. For signature help and code 
completion, we'd probably need to go via the uninstantiated template (and 
probably lose a bit of type information on the way, e.g. reference vs. value, 
l-value vs. r-value). If we wanted a generic way to deal with forwarding, the 
instantiation pattern would be my first choice, but I didn't have the time to 
go down this rabbit hole yet.
Unless there is a nice way to map between template and instantiation AST, I 
don't think combining them is feasible.

On the heuristic itself: Is there a way in C++ to "partially" unpack a 
parameter pack without this showing up in the AST? I am not aware of any, which 
is why the test "do the first and last parameters appear in a matching range of 
the arguments" seems sufficient and necessary in all but single-entry parameter 
packs.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D130260

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


[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-15 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

@sammccall @nridge can you give this another look? :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

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


[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-16 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 429630.
upsj marked an inline comment as done.
upsj added a comment.

remove std::forward bodies from diagnostic tests


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/Compiler.h
  clang-tools-extra/clangd/Preamble.cpp
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
  clang-tools-extra/clangd/unittests/TestTU.cpp
  clang-tools-extra/clangd/unittests/TestTU.h

Index: clang-tools-extra/clangd/unittests/TestTU.h
===
--- clang-tools-extra/clangd/unittests/TestTU.h
+++ clang-tools-extra/clangd/unittests/TestTU.h
@@ -81,7 +81,7 @@
   // By default, build() will report Error diagnostics as GTest errors.
   // Suppress this behavior by adding an 'error-ok' comment to the code.
   // The result will always have getDiagnostics() populated.
-  ParsedAST build() const;
+  ParsedAST build(ParseOptions Opts = {}) const;
   std::shared_ptr
   preamble(PreambleParsedCallback PreambleCallback = nullptr) const;
   ParseInputs inputs(MockFS &FS) const;
Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -104,9 +104,10 @@
   /*StoreInMemory=*/true, PreambleCallback);
 }
 
-ParsedAST TestTU::build() const {
+ParsedAST TestTU::build(ParseOptions Opts) const {
   MockFS FS;
   auto Inputs = inputs(FS);
+  Inputs.Opts = Opts;
   StoreDiags Diags;
   auto CI = buildCompilerInvocation(Inputs, Diags);
   assert(CI && "Failed to build compilation invocation.");
Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
===
--- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -389,7 +389,7 @@
 namespace std {
 // These mocks aren't quite right - we omit unique_ptr for simplicity.
 // forward is included to show its body is not needed to get the diagnostic.
-template  T&& forward(T& t) { return static_cast(t); }
+template  T&& forward(T& t);
 template  T* make_unique(A&&... args) {
return new T(std::forward(args)...);
 }
@@ -402,6 +402,31 @@
"no matching constructor for initialization of 'S'")));
 }
 
+TEST(DiagnosticTest, MakeShared) {
+  // We usually miss diagnostics from header functions as we don't parse them.
+  // std::make_shared is only parsed when --parse-forwarding-functions is set
+  Annotations Main(R"cpp(
+struct S { S(char*); };
+auto x = std::[[make_shared]](42); // error-ok
+  )cpp");
+  TestTU TU = TestTU::withCode(Main.code());
+  TU.HeaderCode = R"cpp(
+namespace std {
+// These mocks aren't quite right - we omit shared_ptr for simplicity.
+// forward is included to show its body is not needed to get the diagnostic.
+template  T&& forward(T& t);
+template  T* make_shared(A&&... args) {
+   return new T(std::forward(args)...);
+}
+}
+  )cpp";
+  EXPECT_THAT(
+  *TU.build({/*PreambleParseForwardingFunctions=*/true}).getDiagnostics(),
+  UnorderedElementsAre(Diag(
+  Main.range(), "in template: "
+"no matching constructor for initialization of 'S'")));
+}
+
 TEST(DiagnosticTest, NoMultipleDiagnosticInFlight) {
   Annotations Main(R"cpp(
 template  struct Foo {
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -498,6 +498,14 @@
   Hidden,
   init(ClangdServer::Options().UseDirtyHeaders)};
 
+opt PreambleParseForwardingFunctions{
+"parse-forwarding-functions",
+cat(Misc),
+desc("Parse all emplace-like functions in included headers"),
+Hidden,
+init(ParseOptions().PreambleParseForwardingFunctions),
+};
+
 #if defined(__GLIBC__) && CLANGD_MALLOC_TRIM
 opt EnableMallocTrim{
 "malloc-trim",
@@ -935,6 +943,7 @@
 Opts.ClangTidyProvider = ClangTidyOptProvider;
   }
   Opts.UseDirtyHeaders = UseDirtyHeaders;
+  Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
   Opts.QueryDriverGlobs = std::move(QueryDriverGlobs);
   Opts.TweakFilter = [&](const Tweak &T) {
 if (T.hidden() && !HiddenFeatures)
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clan

[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-16 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp:416
+// These mocks aren't quite right - we omit shared_ptr for simplicity.
+// forward is included to show its body is not needed to get the 
diagnostic.
+template  T&& forward(T& t) { return static_cast(t); }

nridge wrote:
> I'm confused about this line: you say "show its body is not needed" but 
> forward has a body here
Good catch, that was copy-pasted from std::make_unique above, but it doesn't 
seem to be necessary there either. I'll remove the bodies both.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

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


[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-16 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 429653.
upsj marked 4 inline comments as done.
upsj added a comment.

review updates


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/Compiler.h
  clang-tools-extra/clangd/Preamble.cpp
  clang-tools-extra/clangd/tool/Check.cpp
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
  clang-tools-extra/clangd/unittests/TestTU.cpp
  clang-tools-extra/clangd/unittests/TestTU.h

Index: clang-tools-extra/clangd/unittests/TestTU.h
===
--- clang-tools-extra/clangd/unittests/TestTU.h
+++ clang-tools-extra/clangd/unittests/TestTU.h
@@ -66,6 +66,9 @@
   // Simulate a header guard of the header (using an #import directive).
   bool ImplicitHeaderGuard = true;
 
+  // Parse options pass on to the ParseInputs
+  ParseOptions ParseOpts = {};
+
   // Whether to use overlay the TestFS over the real filesystem. This is
   // required for use of implicit modules.where the module file is written to
   // disk and later read back.
Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -107,6 +107,7 @@
 ParsedAST TestTU::build() const {
   MockFS FS;
   auto Inputs = inputs(FS);
+  Inputs.Opts = ParseOpts;
   StoreDiags Diags;
   auto CI = buildCompilerInvocation(Inputs, Diags);
   assert(CI && "Failed to build compilation invocation.");
Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
===
--- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -389,7 +389,7 @@
 namespace std {
 // These mocks aren't quite right - we omit unique_ptr for simplicity.
 // forward is included to show its body is not needed to get the diagnostic.
-template  T&& forward(T& t) { return static_cast(t); }
+template  T&& forward(T& t);
 template  T* make_unique(A&&... args) {
return new T(std::forward(args)...);
 }
@@ -402,6 +402,32 @@
"no matching constructor for initialization of 'S'")));
 }
 
+TEST(DiagnosticTest, MakeShared) {
+  // We usually miss diagnostics from header functions as we don't parse them.
+  // std::make_shared is only parsed when --parse-forwarding-functions is set
+  Annotations Main(R"cpp(
+struct S { S(char*); };
+auto x = std::[[make_shared]](42); // error-ok
+  )cpp");
+  TestTU TU = TestTU::withCode(Main.code());
+  TU.HeaderCode = R"cpp(
+namespace std {
+// These mocks aren't quite right - we omit shared_ptr for simplicity.
+// forward is included to show its body is not needed to get the diagnostic.
+template  T&& forward(T& t);
+template  T* make_shared(A&&... args) {
+   return new T(std::forward(args)...);
+}
+}
+  )cpp";
+  TU.ParseOpts.PreambleParseForwardingFunctions = true;
+  EXPECT_THAT(*TU.build().getDiagnostics(),
+  UnorderedElementsAre(
+  Diag(Main.range(),
+   "in template: "
+   "no matching constructor for initialization of 'S'")));
+}
+
 TEST(DiagnosticTest, NoMultipleDiagnosticInFlight) {
   Annotations Main(R"cpp(
 template  struct Foo {
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -498,6 +498,14 @@
   Hidden,
   init(ClangdServer::Options().UseDirtyHeaders)};
 
+opt PreambleParseForwardingFunctions{
+"parse-forwarding-functions",
+cat(Misc),
+desc("Parse all emplace-like functions in included headers"),
+Hidden,
+init(ParseOptions().PreambleParseForwardingFunctions),
+};
+
 #if defined(__GLIBC__) && CLANGD_MALLOC_TRIM
 opt EnableMallocTrim{
 "malloc-trim",
@@ -935,6 +943,7 @@
 Opts.ClangTidyProvider = ClangTidyOptProvider;
   }
   Opts.UseDirtyHeaders = UseDirtyHeaders;
+  Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
   Opts.QueryDriverGlobs = std::move(QueryDriverGlobs);
   Opts.TweakFilter = [&](const Tweak &T) {
 if (T.hidden() && !HiddenFeatures)
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -126,6 +126,8 @@
 Inputs.CompileCommand = Cmd;
 Inputs.TFS = &TFS;
 Inputs.ClangTidyProvider = Opts.ClangTidyProvider;
+Inputs

[PATCH] D124688: [clangd] parse all make_unique-like functions in preamble

2022-05-16 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

@sammccall Feel free to merge with Author: Tobias Ribizel 
Thanks for the vote of confidence, I'll apply once the forwarding stuff is done 
:)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124688

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-22 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj planned changes to this revision.
upsj marked 15 inline comments as done.
upsj added a comment.

I will update this to split up the control flow into a visitor just collecting 
a single recursion level and the high-level mapping. A general question here 
would be whether we should do the resolution by parameter or by parameter pack. 
Doing it by parameter (like I did it right now) is much easier for inlay hints, 
especially if the pack gets split up into different parts, but that may not 
necessarily be the case for template functions and more fuzzy cases like 
signature help/autocomplete.




Comment at: clang-tools-extra/clangd/InlayHints.cpp:261
+private:
+  void handleParmVarDeclName(const FunctionDecl *Callee, size_t I) {
+const auto *Param = Callee->getParamDecl(I);

sammccall wrote:
> Unless I'm missing something, going looking in the redecls of the function 
> for a parameter name doesn't seem in scope for this patch.
> 
> We don't support it in inlay hints elsewhere, and it's not clear it has 
> anything to do with forwarding functions.
> Maybe the added complexity is justifiable if this logic can be shared with 
> different functions (hover, signature help) but I don't think it belongs in 
> this patch.
This was already functionality previously available in `chooseParameterNames`, 
I thought I would need to do the same thing here, but turns out that I can get 
the `FunctionDecl` from a `ParmVarDecl`, so this can stay in its previous place.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-23 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

Yes, I think that's a good summary. Only a small clarification:

> we could query separately where each arg is forwarded to. For multiple 
> forwards, the recursive step is "what param is arg N of this callee 
> ultimately bound to"

I was thinking of implementing this as "what parameters are the following 
arguments bound to in a direct call", which doesn't have the aforementioned 
efficiency issues, and is basically a single recursion level of what I had 
previously implemented. Since (at least afaik) there is no way to have a 
parameter pack split up between different function calls (at least from the AST 
standpoint where we here only allow std::forward or plain parameters), the 
input would be a FunctionDecl and vector/set of ParmVarDecl and the output 
would be a map ParmVarDecl -> ParmVarDecl plus an Optional 
telling us whether we need to recurse further. Unrolling the recursion would 
also make it easier to limit the depth to which we unpack forwarded parameters.




Comment at: clang-tools-extra/clangd/InlayHints.cpp:261
+private:
+  void handleParmVarDeclName(const FunctionDecl *Callee, size_t I) {
+const auto *Param = Callee->getParamDecl(I);

sammccall wrote:
> upsj wrote:
> > sammccall wrote:
> > > Unless I'm missing something, going looking in the redecls of the 
> > > function for a parameter name doesn't seem in scope for this patch.
> > > 
> > > We don't support it in inlay hints elsewhere, and it's not clear it has 
> > > anything to do with forwarding functions.
> > > Maybe the added complexity is justifiable if this logic can be shared 
> > > with different functions (hover, signature help) but I don't think it 
> > > belongs in this patch.
> > This was already functionality previously available in 
> > `chooseParameterNames`, I thought I would need to do the same thing here, 
> > but turns out that I can get the `FunctionDecl` from a `ParmVarDecl`, so 
> > this can stay in its previous place.
> You're right, sorry!
> I think the the version we have is pretty opportunistic: this is a couple of 
> lines of code, so why not?
> I don't think we should aim for parity with it, but rather just handle 
> whatever cases are both useful & trivial to implement (in this patch)
> 
> > I can get the FunctionDecl from a ParmVarDecl, so this can stay in its 
> > previous place.
> This sounds good to me - means we can drop this map right? That was the main 
> piece I was concerned with.
Yes, we can do the same in the InlayHintVisitor, though it becomes a bit more 
complex there, since we don't have the index of the argument, which might 
require a linear search, as different forwarded ParmVarDecls can come from 
different FunctionDecls


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D135518: [clangAST] support TypeLoc in TextNodeDumper

2022-10-08 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added a reviewer: aaron.ballman.
Herald added a project: All.
upsj requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

TextNodeDumper currently doesn't support printing the `TypeLoc` hierarchy, 
which makes navigating `clang-query` output involving `TypeLoc` hard to 
understand.
This diff replicates the `Type` hierarchy as well as possible, relying on 
`Type` visitors for printing type-specific info.
The only exception where this doesn't work is most sugared types and any kinds 
of parameters (function or template), for which the `TypeLoc` is not easily 
accessible.

Example `clang-query` output:

  clang-query> set output dump
  clang-query> match typeLoc(loc(type().bind("type")))
  ...
  Binding for "root":
  QualifiedTypeLoc  
'matrix::Dense::type> *const' const
  `-PointerTypeLoc  'matrix::Dense::type> *'
`-ElaboratedTypeLoc  'matrix::Dense::type>'
  `-TemplateSpecializationTypeLoc  'Dense::type>' Dense
  
  Binding for "type":
  PointerType 0x261f2b0 'matrix::Dense::type> *' 
dependent
  `-ElaboratedType 0x261f250 'matrix::Dense::type>' sugar dependent
`-TemplateSpecializationType 0x261f210 'Dense::type>' dependent Dense
  `-TemplateArgument type 'typename remove_complex_t::type'
`-DependentNameType 0x261f190 'typename remove_complex_t::type' 
dependent


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D135518

Files:
  clang/include/clang/AST/ASTDumperUtils.h
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/AST/TextNodeDumper.h
  clang/include/clang/AST/TypeLoc.h
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/AST/TypeLoc.cpp

Index: clang/lib/AST/TypeLoc.cpp
===
--- clang/lib/AST/TypeLoc.cpp
+++ clang/lib/AST/TypeLoc.cpp
@@ -57,6 +57,22 @@
 
 namespace {
 
+class TypeNamer : public TypeLocVisitor {
+public:
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+  const char *Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { return #CLASS; }
+#include "clang/AST/TypeLocNodes.def"
+};
+
+} // namespace
+
+const char *TypeLoc::getTypeLocClassName() const {
+  return TypeNamer().Visit(*this);
+}
+
+namespace {
+
 class TypeAligner : public TypeLocVisitor {
 public:
 #define ABSTRACT_TYPELOC(CLASS, PARENT)
Index: clang/lib/AST/TextNodeDumper.cpp
===
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/LocInfoType.h"
 #include "clang/AST/Type.h"
+#include "clang/AST/TypeLocVisitor.h"
 #include "clang/Basic/Module.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
@@ -239,6 +240,18 @@
   OS << " " << T.split().Quals.getAsString();
 }
 
+void TextNodeDumper::Visit(TypeLoc TL) {
+  {
+ColorScope Color(OS, ShowColors, TypeLocColor);
+OS << TL.getTypeLocClassName() << "TypeLoc";
+  }
+  dumpSourceRange(TL.getSourceRange());
+  OS << " ";
+  dumpBareType(TL.getType(), false);
+
+  TypeLocVisitor::Visit(TL);
+}
+
 void TextNodeDumper::Visit(const Decl *D) {
   if (!D) {
 ColorScope Color(OS, ShowColors, NullColor);
@@ -1622,6 +1635,118 @@
 OS << " expansions " << *N;
 }
 
+void TextNodeDumper::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
+  OS << " " << TL.getType().split().Quals.getAsString();
+}
+
+void TextNodeDumper::VisitRValueReferenceTypeLoc(ReferenceTypeLoc TL) {
+  VisitReferenceType(dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+  VisitArrayType(dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
+  VisitConstantArrayType(
+  dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
+  VisitVariableArrayType(
+  dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitDependentSizedArrayTypeLoc(
+DependentSizedArrayTypeLoc TL) {
+  VisitDependentSizedArrayType(
+  dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitDependentSizedExtVectorTypeLoc(
+DependentSizedExtVectorTypeLoc TL) {
+  VisitDependentSizedExtVectorType(
+  dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitVectorTypeLoc(VectorTypeLoc TL) {
+  VisitVectorType(dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
+  VisitFunctionType(dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
+  VisitFunctionProtoType(
+  dyn_cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+  VisitUnresolvedUsingType(
+  dyn_cast(TL.getType().get

[PATCH] D135518: [clangAST] support TypeLoc in TextNodeDumper

2022-10-14 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 467698.
upsj marked 6 inline comments as done.
upsj added a comment.

I incorporated the `cast`, `ASTContext` and `StringRef` suggestions. About 
JSONDumper, I was surprised to see that it doesn't seem to use `AddChild` for 
the AST hierarchy at all, so I'm not quite clear how (if?) it builds a nested 
output. What's the easiest way to invoke it?


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

https://reviews.llvm.org/D135518

Files:
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/AST/TextNodeDumper.h
  clang/include/clang/AST/TypeLoc.h
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/AST/TypeLoc.cpp

Index: clang/lib/AST/TypeLoc.cpp
===
--- clang/lib/AST/TypeLoc.cpp
+++ clang/lib/AST/TypeLoc.cpp
@@ -57,6 +57,22 @@
 
 namespace {
 
+class TypeNamer : public TypeLocVisitor {
+public:
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+  llvm::StringRef Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { return #CLASS; }
+#include "clang/AST/TypeLocNodes.def"
+};
+
+} // namespace
+
+llvm::StringRef TypeLoc::getTypeLocClassName() const {
+  return TypeNamer().Visit(*this);
+}
+
+namespace {
+
 class TypeAligner : public TypeLocVisitor {
 public:
 #define ABSTRACT_TYPELOC(CLASS, PARENT)
Index: clang/lib/AST/TextNodeDumper.cpp
===
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/LocInfoType.h"
 #include "clang/AST/Type.h"
+#include "clang/AST/TypeLocVisitor.h"
 #include "clang/Basic/Module.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
@@ -239,6 +240,18 @@
   OS << " " << T.split().Quals.getAsString();
 }
 
+void TextNodeDumper::Visit(TypeLoc TL) {
+  {
+ColorScope Color(OS, ShowColors, TypeColor);
+OS << TL.getTypeLocClassName() << "TypeLoc";
+  }
+  dumpSourceRange(TL.getSourceRange());
+  OS << " ";
+  dumpBareType(TL.getType(), false);
+
+  TypeLocVisitor::Visit(TL);
+}
+
 void TextNodeDumper::Visit(const Decl *D) {
   if (!D) {
 ColorScope Color(OS, ShowColors, NullColor);
@@ -1622,6 +1635,116 @@
 OS << " expansions " << *N;
 }
 
+void TextNodeDumper::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
+  OS << " " << TL.getType().split().Quals.getAsString();
+}
+
+void TextNodeDumper::VisitRValueReferenceTypeLoc(ReferenceTypeLoc TL) {
+  VisitReferenceType(cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+  if (Context)
+VisitArrayType(Context->getAsArrayType(TL.getType()));
+}
+
+void TextNodeDumper::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
+  if (Context)
+VisitConstantArrayType(Context->getAsConstantArrayType(TL.getType()));
+}
+
+void TextNodeDumper::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
+  if (Context)
+VisitVariableArrayType(Context->getAsVariableArrayType(TL.getType()));
+}
+
+void TextNodeDumper::VisitDependentSizedArrayTypeLoc(
+DependentSizedArrayTypeLoc TL) {
+  if (Context)
+VisitDependentSizedArrayType(
+Context->getAsDependentSizedArrayType(TL.getType()));
+}
+
+void TextNodeDumper::VisitDependentSizedExtVectorTypeLoc(
+DependentSizedExtVectorTypeLoc TL) {
+  VisitDependentSizedExtVectorType(
+  cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitVectorTypeLoc(VectorTypeLoc TL) {
+  VisitVectorType(cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
+  VisitFunctionType(cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
+  VisitFunctionProtoType(cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+  VisitUnresolvedUsingType(
+  cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitUsingTypeLoc(UsingTypeLoc TL) {
+  VisitUsingType(cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+  VisitTypedefType(cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+  VisitUnaryTransformType(cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitTagTypeLoc(TagTypeLoc TL) {
+  VisitTagType(cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+  VisitTemplateTypeParmType(
+  cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitSubstTemplateTypeParmTypeLoc(
+SubstTemplateTypeParmTypeLoc TL) {
+  VisitSubstTemplateTypeParmType(
+  cast(TL.getType().getTypePtr()));
+}
+
+void TextNodeDumper::VisitAutoTypeLoc(AutoTypeLoc TL) {
+  VisitAutoType(cast(TL.getType().getTypePtr()));
+

[PATCH] D135518: [clangAST] support TypeLoc in TextNodeDumper

2022-10-14 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang/include/clang/AST/TextNodeDumper.h:337
+  void VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL);
+  void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL);
+  void VisitDependentSizedArrayTypeLoc(DependentSizedArrayTypeLoc TL);

aaron.ballman wrote:
> Should you also handle `IncompleteArrayTypeLoc` as well?
Not sure about this one, since it has no additional metadata - the type 
location visitor already prints out the type class name


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

https://reviews.llvm.org/D135518

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


[PATCH] D135518: [clangAST] support TypeLoc in TextNodeDumper

2022-10-14 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

Let me backtrack my previous question: I misremembered where AddChild is 
actually being called in the traversal (ASTNodeTraverser, not TextNodeDumper), 
so I'll see if adding this to the JSON output is feasible


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

https://reviews.llvm.org/D135518

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


[PATCH] D127859: [clangd] Don't add inlay hints on std::move/forward

2022-06-15 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj created this revision.
upsj added a reviewer: nridge.
Herald added subscribers: usaxena95, kadircet, arphaman.
Herald added a project: All.
upsj requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

This removes parameter inlay hints from a few builtin functions like 
std::move/std::forward


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D127859

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -555,6 +555,17 @@
ExpectedHint{"timeout_millis: ", "timeout_millis"});
 }
 
+TEST(ParameterHints, BuiltinFunctions) {
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo() {
+  int i;
+  std::forward(i);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, IncludeAtNonGlobalScope) {
   Annotations FooInc(R"cpp(
 void bar() { foo(42); }
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/ScopeExit.h"
 
@@ -400,8 +401,9 @@
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
 // Exclude setters (i.e. functions with one argument whose name begins with
-// "set"), as their parameter name is also not likely to be interesting.
-if (isSetter(Callee, ParameterNames))
+// "set"), and builtins like std::move/forward/... as their parameter name
+// is also not likely to be interesting.
+if (isSetter(Callee, ParameterNames) || isSimpleBuiltin(Callee))
   return;
 
 for (size_t I = 0; I < ArgCount; ++I) {
@@ -440,6 +442,21 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
+  // Checks if the callee is one of the builtins
+  // addressof, as_const, forward, move(_if_noexcept)
+  static bool isSimpleBuiltin(const FunctionDecl *Callee) {
+switch (Callee->getBuiltinID()) {
+case Builtin::BIaddressof:
+case Builtin::BIas_const:
+case Builtin::BIforward:
+case Builtin::BImove:
+case Builtin::BImove_if_noexcept:
+  return true;
+default:
+  return false;
+}
+  }
+
   bool shouldHintName(const Expr *Arg, StringRef ParamName) {
 if (ParamName.empty())
   return false;


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -555,6 +555,17 @@
ExpectedHint{"timeout_millis: ", "timeout_millis"});
 }
 
+TEST(ParameterHints, BuiltinFunctions) {
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo() {
+  int i;
+  std::forward(i);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, IncludeAtNonGlobalScope) {
   Annotations FooInc(R"cpp(
 void bar() { foo(42); }
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/ScopeExit.h"
 
@@ -400,8 +401,9 @@
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
 // Exclude setters (i.e. functions with one argument whose name begins with
-// "set"), as their parameter name is also not likely to be interesting.
-if (isSetter(Callee, ParameterNames))
+// "set"), and builtins like std::move/forward/... as their parameter name
+// is also not likely to be interesting.
+if (isSetter(Callee, ParameterNames) || isSimpleBuiltin(Callee))
   return;
 
 for (size_t I = 0; I < ArgCount; ++I) {
@@ -440,6 +442,21 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
+  // Checks if the callee is one of the builtins
+  // addressof, as_const, forward, move(_if_noexcept)
+  static bool isSimpleBuiltin(const FunctionDecl *Callee) {
+switch (Callee->getBuiltinID()) {
+case Builtin::BIaddressof:

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-15 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 437194.
upsj marked 9 inline comments as done.
upsj added a comment.

- improve documentation
- add more edge case tests
- fix reference hints for parameter packs
- remove unnecessary headers
- fix bug in handling of tail parameters


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,44 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  bar(42);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"});
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +224,36 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
+TEST(ParameterHints, NameInDefinitionVariadic) {
+  // Parameter name picked up from definition in a resolved forwarded parameter.
+  assertParameterHints(R"cpp(
+void foo(int, int);
+template 
+void bar(Args... args) {
+  foo(args...);
+}
+void baz() {
+  bar($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int b) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +326,337 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter using std::forward in a constructor call
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter in a constructor call
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter using std::forward in a new expression
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter in a new expression
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-15 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/AST.cpp:682
+  if (const auto *TTPD =
+  dyn_cast(TemplateParams.back())) {
+const auto *TTPT =

nridge wrote:
> I don't think there is any requirement that a pack be a trailing **template** 
> parameter. For example, the following is valid:
> 
> ```
> template 
> void foo(A, B...);
> 
> void bar() {
>   foo(1, 2, 3);
> }
> ```
Do you have a suggestion for how to find this pack in general? I would like to 
keep this function as efficient as possible, since it's used everywhere



Comment at: clang-tools-extra/clangd/InlayHints.cpp:541
 
+// Remove parameter names that occur multiple times completely.
+llvm::StringMap NameLastSeen;

nridge wrote:
> This is an interesting approach for handling `VariadicRecursive`.
> 
> I had in mind a different approach, something like keeping a 
> `std::set SeenFunctionTemplates` in 
> `resolveForwardingParameters()`, populating it with 
> `CurrentFunction->getPrimaryTemplate()` on each iteration, and bailing if the 
> same function template is seen more than once (indicating recursion). But 
> this approach seems to work too, as a parameter name can't legitimately 
> appear twice in a function declaration.
> 
> That said, maybe having such a `SeenFunctionTemplates` recursion guard would 
> be helpful anyways, so that e.g. in `VariadicInfinite`, we would bail after a 
> single recursion rather than going until `MaxDepth`?
I see your point here - I would also like an AST based approach more than this 
purely string-based one. The main issue is that if I deduplicate based on the 
function templates, I would still be left with the first parameter being named, 
which doesn't make much sense in something like make_tuple.



Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:200
+  )cpp",
+   ExpectedHint{"&: ", "fwd"});
+}

nridge wrote:
> As an aside, `&` does not seem like a useful hint to show for `std::forward` 
> -- should we try to omit it? (We don't need to do it in this patch as it's 
> not really related.)
see https://reviews.llvm.org/D127859 ;)



Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:467
+
+TEST(ParameterHints, VariadicVarargs) {
+  assertParameterHints(R"cpp(

nridge wrote:
> I think a variation of this test case where `foo` is also variadic, would be 
> valuable to add:
> 
> ```
> template 
> void foo(int fixed, Args&&... args);
> 
> template 
> void bar(Args&&... args) {
>   foo(args...);
> }
> 
> void baz() { 
>   bar($fixed[[41]], 42, 43);
> }
> ```
> 
> This case does seem to already work with the current patch, and I think it's 
> the more common case; I'm happy to defer the varargs one as a less important 
> edge case.
The main reason I added this is to test that the visitor doesn't break on 
varargs, the output is not that important anyways. I added your suggestion as 
well, which highlighted another issue, thanks :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D127859: [clangd] Don't add inlay hints on std::move/forward

2022-06-16 Thread Tobias Ribizel via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe984e1cd6137: [clangd] Don't add inlay hints on 
std::move/forward (authored by upsj).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D127859

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -555,6 +555,17 @@
ExpectedHint{"timeout_millis: ", "timeout_millis"});
 }
 
+TEST(ParameterHints, BuiltinFunctions) {
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo() {
+  int i;
+  std::forward(i);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, IncludeAtNonGlobalScope) {
   Annotations FooInc(R"cpp(
 void bar() { foo(42); }
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/ScopeExit.h"
 
@@ -400,8 +401,9 @@
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
 // Exclude setters (i.e. functions with one argument whose name begins with
-// "set"), as their parameter name is also not likely to be interesting.
-if (isSetter(Callee, ParameterNames))
+// "set"), and builtins like std::move/forward/... as their parameter name
+// is also not likely to be interesting.
+if (isSetter(Callee, ParameterNames) || isSimpleBuiltin(Callee))
   return;
 
 for (size_t I = 0; I < ArgCount; ++I) {
@@ -440,6 +442,21 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
+  // Checks if the callee is one of the builtins
+  // addressof, as_const, forward, move(_if_noexcept)
+  static bool isSimpleBuiltin(const FunctionDecl *Callee) {
+switch (Callee->getBuiltinID()) {
+case Builtin::BIaddressof:
+case Builtin::BIas_const:
+case Builtin::BIforward:
+case Builtin::BImove:
+case Builtin::BImove_if_noexcept:
+  return true;
+default:
+  return false;
+}
+  }
+
   bool shouldHintName(const Expr *Arg, StringRef ParamName) {
 if (ParamName.empty())
   return false;


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -555,6 +555,17 @@
ExpectedHint{"timeout_millis: ", "timeout_millis"});
 }
 
+TEST(ParameterHints, BuiltinFunctions) {
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo() {
+  int i;
+  std::forward(i);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, IncludeAtNonGlobalScope) {
   Annotations FooInc(R"cpp(
 void bar() { foo(42); }
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/ScopeExit.h"
 
@@ -400,8 +401,9 @@
 NameVec ParameterNames = chooseParameterNames(Callee, ArgCount);
 
 // Exclude setters (i.e. functions with one argument whose name begins with
-// "set"), as their parameter name is also not likely to be interesting.
-if (isSetter(Callee, ParameterNames))
+// "set"), and builtins like std::move/forward/... as their parameter name
+// is also not likely to be interesting.
+if (isSetter(Callee, ParameterNames) || isSimpleBuiltin(Callee))
   return;
 
 for (size_t I = 0; I < ArgCount; ++I) {
@@ -440,6 +442,21 @@
 return WhatItIsSetting.equals_insensitive(ParamNames[0]);
   }
 
+  // Checks if the callee is one of the builtins
+  // addressof, as_const, forward, move(_if_noexcept)
+  static bool isSimpleBuiltin(const FunctionDecl *Callee) {
+switch (Callee->getBuiltinID()) {
+case Builtin::BIaddressof:
+case Builtin::BIas_const:
+case Builtin::BIforward:
+case Builtin::BImove:
+case Builtin::BImove_if_noexcept:
+  retur

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-16 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 437508.
upsj marked 4 inline comments as done.
upsj added a comment.

- remove inlay hints from std::forward in tests
- identify recursive variadic calls from template, not post-processing
- allow template parameter packs to appear at any place
- improve documentation


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,43 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward(args)...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +223,36 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
+TEST(ParameterHints, NameInDefinitionVariadic) {
+  // Parameter name picked up from definition in a resolved forwarded parameter.
+  assertParameterHints(R"cpp(
+void foo(int, int);
+template 
+void bar(Args... args) {
+  foo(args...);
+}
+void baz() {
+  bar($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int b) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +325,349 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter using std::forward in a constructor call
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter in a constructor call
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter using std::forward in a new expression
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward(args)...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter in a new expression
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic paramete

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-16 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/AST.cpp:682
+  if (const auto *TTPD =
+  dyn_cast(TemplateParams.back())) {
+const auto *TTPT =

nridge wrote:
> upsj wrote:
> > nridge wrote:
> > > I don't think there is any requirement that a pack be a trailing 
> > > **template** parameter. For example, the following is valid:
> > > 
> > > ```
> > > template 
> > > void foo(A, B...);
> > > 
> > > void bar() {
> > >   foo(1, 2, 3);
> > > }
> > > ```
> > Do you have a suggestion for how to find this pack in general? I would like 
> > to keep this function as efficient as possible, since it's used everywhere
> > Do you have a suggestion for how to find this pack in general?
> 
> Just iterate backwards through `TemplateParams` rather than only considering 
> `TemplateParams.back()`, I suppose.
> 
> > I would like to keep this function as efficient as possible, since it's 
> > used everywhere
> 
> The `ParmVarDecl*` overload of `getPackTemplateParameter()` is called a lot 
> via the `IsExpandedPack` lambdas, but this overload is only called once per 
> depth level.
Ah thanks, of course! I got tricked by my own overloads.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-26 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

I've hit a roadblock I'm not sure how to proceed with. It seems that in some 
cases, a `ParmVarDecl` of an instantiated function template indeed doesn't 
preserve the `SubstTemplateTypeParmType` type sugar allowing me to check which 
template parameter it was instantiated from. This might be related to reference 
collapsing on type deduction, since `Args...` preserves the sugar, but 
`Args&&...` doesn't. Without this ability to distinguish between expanded packs 
and normal parameters, I risk recursing into other functions and pulling up 
unrelated type names. Any ideas how to proceed here? Essentially, it's the same 
issue that @nridge already provided a partial solution for by not using 
`getNonReferenceType()`, but more complex. I would really like to avoid having 
to reconstruct parameter indices from arbitrarily many levels of template 
parameters packs from surrounding scopes.

Example where this pops up:

  cpp
  namespace std { template  T&& forward(T&); }
  struct S { S(int a); };
  template 
  T bar(Args&&... args) { return T{std::forward($fwd[[args]])...}; }
  void baz() {
int b;
bar($param[[b]]);
  }


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-27 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 432518.
upsj added a comment.

Of course, I forgot to create a new diff. There is some debug output and logic 
errors for some of the tests, but the simple ones already show the issue.
The function in question is `getPackTemplateParameter`, which provides similar 
functionality to `isExpandedParameter` before


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,44 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  bar(42);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"});
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +224,19 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +309,276 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-05-30 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 432900.
upsj marked an inline comment as done.
upsj added a comment.

Thanks Nathan, that was exactly it. I thought I looked at getTypePtr() 
directly, but I must have been mistaken.
After a small fix (only adding inlay hints until the first unexpanded pack 
expression, it seems to work now).

Short explanation of what is going on: I split the parameters into head, pack 
and tail where pack are all parameters matching the variadic template type 
parameter we are expanding.
This way, I need to make no allocations inside the visitor.

The only thing to be fixed is a `make_tuple`-like call, where each parameter is 
called `head`, probably simple deduplication makes most sense.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,44 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  bar(42);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"});
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +224,19 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +309,276 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // This p

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-02 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 433732.
upsj added a comment.

- fix varargs, again :)
- remove parameter names entirely if they occur multiple times


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,44 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  bar(42);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"});
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +224,19 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +309,276 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void 

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-04 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 434257.
upsj added a comment.

This is now ready to review, only needed to fix a formatting issue


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,44 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  bar(42);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"});
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +224,19 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +309,276 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int a);
+tem

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-04 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj updated this revision to Diff 434262.
upsj added a comment.

add test for varargs function called from forwarding function


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

Files:
  clang-tools-extra/clangd/AST.cpp
  clang-tools-extra/clangd/AST.h
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -174,6 +174,44 @@
   )cpp");
 }
 
+TEST(ParameterHints, NoNameVariadicDeclaration) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+template 
+void foo(Args&& ...);
+void bar() {
+  foo(42);
+}
+  )cpp");
+}
+
+TEST(ParameterHints, NoNameVariadicForwarded) {
+  // No hint for anonymous variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  bar(42);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"});
+}
+
+TEST(ParameterHints, NoNameVariadicPlain) {
+  // No hint for anonymous variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int);
+template 
+void bar(Args&&... args) { return foo(args...); }
+void baz() {
+  bar(42);
+}
+  )cpp");
+}
+
 TEST(ParameterHints, NameInDefinition) {
   // Parameter name picked up from definition if necessary.
   assertParameterHints(R"cpp(
@@ -186,6 +224,19 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, NamePartiallyInDefinition) {
+  // Parameter name picked up from definition if necessary.
+  assertParameterHints(R"cpp(
+void foo(int, int b);
+void bar() {
+  foo($param1[[42]], $param2[[42]]);
+}
+void foo(int a, int) {};
+  )cpp",
+   ExpectedHint{"a: ", "param1"},
+   ExpectedHint{"b: ", "param2"});
+}
+
 TEST(ParameterHints, NameMismatch) {
   // Prefer name from declaration.
   assertParameterHints(R"cpp(
@@ -258,6 +309,291 @@
ExpectedHint{"param: ", "param"});
 }
 
+TEST(ParameterHints, VariadicForwardedConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T bar(Args&&... args) { return T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwardedNewConstructor) {
+  // Name hint for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{std::forward($fwd[[args]])...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlainNewConstructor) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+struct S { S(int a); };
+template 
+T* bar(Args&&... args) { return new T{args...}; }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicForwarded) {
+  // Name for variadic parameter
+  // This prototype of std::forward is sufficient for clang to recognize it
+  assertParameterHints(R"cpp(
+namespace std { template  T&& forward(T&); }
+void foo(int a);
+template 
+void bar(Args&&... args) { return foo(std::forward($fwd[[args]])...); }
+void baz() {
+  int b;
+  bar($param[[b]]);
+}
+  )cpp",
+   ExpectedHint{"&: ", "fwd"},
+   ExpectedHint{"a: ", "param"});
+}
+
+TEST(ParameterHints, VariadicPlain) {
+  // Name hint for variadic parameter
+  assertParameterHints(R"cpp(
+void foo(int a);
+template

[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-04 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added inline comments.



Comment at: clang-tools-extra/clangd/AST.cpp:772
+  size_t PackLocation = OptPackLocation.getValue();
+  ArrayRef MatchingParams =
+  Callee->parameters().slice(PackLocation, Parameters.size());

Similar to processCall in InlayHints.cpp, this may have issues with varargs 
functions. Maybe on top of checking for unexpanded pack expression arguments, I 
should add a check `Callee->getNumParams() == Args.size()`. A corresponding 
test fails by not forwarding a fixed parameter right now.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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


[PATCH] D124690: [clangd] add inlay hints for std::forward-ed parameter packs

2022-06-10 Thread Tobias Ribizel via Phabricator via cfe-commits
upsj added a comment.

@nridge @sammccall can you give this another look?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D124690

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