[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-07-02 Thread Marc-Andre Laperle via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL336119: [clangd] Implement hover for auto and 
decltype (authored by malaperle, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D48159

Files:
  clang-tools-extra/trunk/clangd/XRefs.cpp
  clang-tools-extra/trunk/unittests/clangd/TestTU.cpp
  clang-tools-extra/trunk/unittests/clangd/TestTU.h
  clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp

Index: clang-tools-extra/trunk/clangd/XRefs.cpp
===
--- clang-tools-extra/trunk/clangd/XRefs.cpp
+++ clang-tools-extra/trunk/clangd/XRefs.cpp
@@ -12,6 +12,7 @@
 #include "SourceCode.h"
 #include "URI.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Index/IndexDataConsumer.h"
 #include "clang/Index/IndexingAction.h"
 #include "clang/Index/USRGeneration.h"
@@ -516,6 +517,18 @@
   return H;
 }
 
+/// Generate a \p Hover object given the type \p T.
+static Hover getHoverContents(QualType T, ASTContext ) {
+  Hover H;
+  std::string TypeText;
+  llvm::raw_string_ostream OS(TypeText);
+  PrintingPolicy Policy = PrintingPolicyForDecls(ASTCtx.getPrintingPolicy());
+  T.print(OS, Policy);
+  OS.flush();
+  H.contents.value += TypeText;
+  return H;
+}
+
 /// Generate a \p Hover object given the macro \p MacroInf.
 static Hover getHoverContents(StringRef MacroName) {
   Hover H;
@@ -526,6 +539,131 @@
   return H;
 }
 
+namespace {
+/// Computes the deduced type at a given location by visiting the relevant
+/// nodes. We use this to display the actual type when hovering over an "auto"
+/// keyword or "decltype()" expression.
+/// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
+/// seems that the AutoTypeLocs that can be visited along with their AutoType do
+/// not have the deduced type set. Instead, we have to go to the appropriate
+/// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
+/// a deduced type set. The AST should be improved to simplify this scenario.
+class DeducedTypeVisitor : public RecursiveASTVisitor {
+  SourceLocation SearchedLocation;
+  llvm::Optional DeducedType;
+
+public:
+  DeducedTypeVisitor(SourceLocation SearchedLocation)
+  : SearchedLocation(SearchedLocation) {}
+
+  llvm::Optional getDeducedType() { return DeducedType; }
+
+  // Handle auto initializers:
+  //- auto i = 1;
+  //- decltype(auto) i = 1;
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||
+D->getTypeSourceInfo()->getTypeLoc().getLocStart() != SearchedLocation)
+  return true;
+
+auto DeclT = D->getType();
+// "auto &" is represented as a ReferenceType containing an AutoType
+if (const ReferenceType *RT = dyn_cast(DeclT.getTypePtr()))
+  DeclT = RT->getPointeeType();
+
+const AutoType *AT = dyn_cast(DeclT.getTypePtr());
+if (AT && !AT->getDeducedType().isNull()) {
+  // For auto, use the underlying type because the const& would be
+  // represented twice: written in the code and in the hover.
+  // Example: "const auto I = 1", we only want "int" when hovering on auto,
+  // not "const int".
+  //
+  // For decltype(auto), take the type as is because it cannot be written
+  // with qualifiers or references but its decuded type can be const-ref.
+  DeducedType = AT->isDecltypeAuto() ? DeclT : DeclT.getUnqualifiedType();
+}
+return true;
+  }
+
+  // Handle auto return types:
+  //- auto foo() {}
+  //- auto& foo() {}
+  //- auto foo() -> decltype(1+1) {}
+  //- operator auto() const { return 10; }
+  bool VisitFunctionDecl(FunctionDecl *D) {
+if (!D->getTypeSourceInfo())
+  return true;
+// Loc of auto in return type (c++14).
+auto CurLoc = D->getReturnTypeSourceRange().getBegin();
+// Loc of "auto" in operator auto()
+if (CurLoc.isInvalid() && dyn_cast(D))
+  CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
+// Loc of "auto" in function with traling return type (c++11).
+if (CurLoc.isInvalid())
+  CurLoc = D->getSourceRange().getBegin();
+if (CurLoc != SearchedLocation)
+  return true;
+
+auto T = D->getReturnType();
+// "auto &" is represented as a ReferenceType containing an AutoType.
+if (const ReferenceType *RT = dyn_cast(T.getTypePtr()))
+  T = RT->getPointeeType();
+
+const AutoType *AT = dyn_cast(T.getTypePtr());
+if (AT && !AT->getDeducedType().isNull()) {
+  DeducedType = T.getUnqualifiedType();
+} else { // auto in a trailing return type just points to a DecltypeType.
+  const DecltypeType *DT = dyn_cast(T.getTypePtr());
+  if (!DT->getUnderlyingType().isNull())
+DeducedType = DT->getUnderlyingType();
+}
+return true;
+  }
+
+  // Handle non-auto decltype, e.g.:
+  // - auto foo() -> decltype(expr) {}
+  // - 

[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-07-02 Thread Marc-Andre Laperle via Phabricator via cfe-commits
malaperle added inline comments.



Comment at: clangd/XRefs.cpp:559
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||

klimek wrote:
> klimek wrote:
> > malaperle wrote:
> > > klimek wrote:
> > > > sammccall wrote:
> > > > > malaperle wrote:
> > > > > > sammccall wrote:
> > > > > > > out of curiosity, why not implement `VisitTypeLoc` and handle all 
> > > > > > > the cases where it turns out to be `auto` etc?
> > > > > > > Even for `auto&` I'd expect the inner `auto` to have a `TypeLoc` 
> > > > > > > you could visit, saving the trouble of unwrapping.
> > > > > > > 
> > > > > > > (I'm probably wrong about all this, I don't know the AST well. 
> > > > > > > But I'd like to learn!)
> > > > > > From what I saw, there are actually two different AutoType* for 
> > > > > > each textual "auto". The AutoType* containing the deduced type does 
> > > > > > not get visited via a typeloc. It's not entirely clear to me why 
> > > > > > since I don't know the AST well either. I was thinking maybe the 
> > > > > > first is created when the type is not deduced yet and later on, 
> > > > > > then the rest of the function or expression is parsed, a second one 
> > > > > > with the actual type deduced is created. If I look at the code 
> > > > > > paths where they are created, it seems like this is roughly what's 
> > > > > > happening. The first one is created when the declarator is parsed 
> > > > > > (no deduced type yet) and the second is created when the expression 
> > > > > > of the initializer (or return statement) is evaluated and the type 
> > > > > > is then deduced. The visitor only visits the first one's typeloc. I 
> > > > > > don't think I'm knowledgeable enough to say whether or not that's a 
> > > > > > bug but it seems on purpose that it is modelled this way. Although 
> > > > > > it would be much nicer to only have to visit typelocs...
> > > > > > The AutoType* containing the deduced type does not get visited via 
> > > > > > a typeloc
> > > > > Ah, OK.
> > > > > Could you add a high level comment (maybe on the class) saying this 
> > > > > is the reason for the implementation? Otherwise as a reader I'll 
> > > > > think "this seems unneccesarily complicated" but not understand why.
> > > > > 
> > > > > @klimek Can you shed any light on this?
> > > > Can't you go from AutoTypeLoc -> AutoType -> getDeducedType()?
> > > The visitor doesn't visit the AutoTypeLoc that has the deduced type. In 
> > > fact, there are two AutoType* instances. I'm not sure that's is a bug 
> > > that there are two AutoType*, or if not visiting both AutoTypeLoc is a 
> > > bug...or neither.
> > +Richard Smith:
> > 
> > This is weird. If I just create a minimal example:
> >   int f() {
> > auto i = f();
> > return i;
> >   }
> > 
> > I only get the undeduced auto type - Richard, in which cases are auto-typed 
> > being deduced? The AST dump doens't give an indication that there was an 
> > auto involved at all. Is this the famous syntactic vs. smenatic form 
> > problem? Do we have a backlink between the AutoTypeLoc and the deduced type 
> > somewhere?
> Given that Richard is known to have ~1 month ping times now and then I think 
> it's fine to land this with a FIXME above to figure out how to represent this 
> better in the AST. I'd still say it's a missing feature in the AST :)
Thanks! I'm looking forward to simplifying this code when the AST is improved.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159



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


[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-07-02 Thread Marc-Andre Laperle via Phabricator via cfe-commits
malaperle updated this revision to Diff 153737.
malaperle added a comment.

Tweak comment with FIXME.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159

Files:
  clangd/XRefs.cpp
  unittests/clangd/TestTU.cpp
  unittests/clangd/TestTU.h
  unittests/clangd/XRefsTests.cpp

Index: unittests/clangd/XRefsTests.cpp
===
--- unittests/clangd/XRefsTests.cpp
+++ unittests/clangd/XRefsTests.cpp
@@ -343,6 +343,13 @@
 
   OneTest Tests[] = {
   {
+  R"cpp(// No hover
+^int main() {
+}
+  )cpp",
+  "",
+  },
+  {
   R"cpp(// Local variable
 int main() {
   int bonjour;
@@ -637,16 +644,275 @@
   )cpp",
   "",
   },
+  {
+  R"cpp(// Simple initialization with auto
+void foo() {
+  ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto
+void foo() {
+  const ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto&
+void foo() {
+  const ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with auto&
+void foo() {
+  ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Auto with initializer list.
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^auto i = {1,2};
+}
+  )cpp",
+  "class std::initializer_list",
+  },
+  {
+  R"cpp(// User defined conversion to auto
+struct Bar {
+  operator ^auto() const { return 10; }
+};
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with decltype(auto)
+void foo() {
+  ^decltype(auto) i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const decltype(auto)
+void foo() {
+  const int j = 0;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int",
+  },
+  {
+  R"cpp(// Simple initialization with const& decltype(auto)
+void foo() {
+  int k = 0;
+  const int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int &",
+  },
+  {
+  R"cpp(// Simple initialization with & decltype(auto)
+void foo() {
+  int k = 0;
+  int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype with initializer list: nothing
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^decltype(auto) i = {1,2};
+}
+  )cpp",
+  "",
+  },
+  {
+  R"cpp(// auto function return with trailing type
+struct Bar {};
+^auto test() -> decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// trailing return type
+struct Bar {};
+auto test() -> ^decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto in function return
+struct Bar {};
+^auto test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto& in function return
+struct Bar {};
+^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// const auto& in function return
+struct Bar {};
+const ^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) in function return
+struct Bar {};
+^decltype(auto) test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) reference in function return
+struct Bar {};
+^decltype(auto) test() {
+  int a;
+  return (a);
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype lvalue reference
+void foo() {
+   

[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-07-02 Thread Manuel Klimek via Phabricator via cfe-commits
klimek accepted this revision.
klimek added inline comments.



Comment at: clangd/XRefs.cpp:559
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||

klimek wrote:
> malaperle wrote:
> > klimek wrote:
> > > sammccall wrote:
> > > > malaperle wrote:
> > > > > sammccall wrote:
> > > > > > out of curiosity, why not implement `VisitTypeLoc` and handle all 
> > > > > > the cases where it turns out to be `auto` etc?
> > > > > > Even for `auto&` I'd expect the inner `auto` to have a `TypeLoc` 
> > > > > > you could visit, saving the trouble of unwrapping.
> > > > > > 
> > > > > > (I'm probably wrong about all this, I don't know the AST well. But 
> > > > > > I'd like to learn!)
> > > > > From what I saw, there are actually two different AutoType* for each 
> > > > > textual "auto". The AutoType* containing the deduced type does not 
> > > > > get visited via a typeloc. It's not entirely clear to me why since I 
> > > > > don't know the AST well either. I was thinking maybe the first is 
> > > > > created when the type is not deduced yet and later on, then the rest 
> > > > > of the function or expression is parsed, a second one with the actual 
> > > > > type deduced is created. If I look at the code paths where they are 
> > > > > created, it seems like this is roughly what's happening. The first 
> > > > > one is created when the declarator is parsed (no deduced type yet) 
> > > > > and the second is created when the expression of the initializer (or 
> > > > > return statement) is evaluated and the type is then deduced. The 
> > > > > visitor only visits the first one's typeloc. I don't think I'm 
> > > > > knowledgeable enough to say whether or not that's a bug but it seems 
> > > > > on purpose that it is modelled this way. Although it would be much 
> > > > > nicer to only have to visit typelocs...
> > > > > The AutoType* containing the deduced type does not get visited via a 
> > > > > typeloc
> > > > Ah, OK.
> > > > Could you add a high level comment (maybe on the class) saying this is 
> > > > the reason for the implementation? Otherwise as a reader I'll think 
> > > > "this seems unneccesarily complicated" but not understand why.
> > > > 
> > > > @klimek Can you shed any light on this?
> > > Can't you go from AutoTypeLoc -> AutoType -> getDeducedType()?
> > The visitor doesn't visit the AutoTypeLoc that has the deduced type. In 
> > fact, there are two AutoType* instances. I'm not sure that's is a bug that 
> > there are two AutoType*, or if not visiting both AutoTypeLoc is a bug...or 
> > neither.
> +Richard Smith:
> 
> This is weird. If I just create a minimal example:
>   int f() {
> auto i = f();
> return i;
>   }
> 
> I only get the undeduced auto type - Richard, in which cases are auto-typed 
> being deduced? The AST dump doens't give an indication that there was an auto 
> involved at all. Is this the famous syntactic vs. smenatic form problem? Do 
> we have a backlink between the AutoTypeLoc and the deduced type somewhere?
Given that Richard is known to have ~1 month ping times now and then I think 
it's fine to land this with a FIXME above to figure out how to represent this 
better in the AST. I'd still say it's a missing feature in the AST :)


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159



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


[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-29 Thread Marc-Andre Laperle via Phabricator via cfe-commits
malaperle updated this revision to Diff 153612.
malaperle added a comment.

Add comment about AutoTypeLoc work-around.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159

Files:
  clangd/XRefs.cpp
  unittests/clangd/TestTU.cpp
  unittests/clangd/TestTU.h
  unittests/clangd/XRefsTests.cpp

Index: unittests/clangd/XRefsTests.cpp
===
--- unittests/clangd/XRefsTests.cpp
+++ unittests/clangd/XRefsTests.cpp
@@ -343,6 +343,13 @@
 
   OneTest Tests[] = {
   {
+  R"cpp(// No hover
+^int main() {
+}
+  )cpp",
+  "",
+  },
+  {
   R"cpp(// Local variable
 int main() {
   int bonjour;
@@ -637,16 +644,275 @@
   )cpp",
   "",
   },
+  {
+  R"cpp(// Simple initialization with auto
+void foo() {
+  ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto
+void foo() {
+  const ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto&
+void foo() {
+  const ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with auto&
+void foo() {
+  ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Auto with initializer list.
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^auto i = {1,2};
+}
+  )cpp",
+  "class std::initializer_list",
+  },
+  {
+  R"cpp(// User defined conversion to auto
+struct Bar {
+  operator ^auto() const { return 10; }
+};
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with decltype(auto)
+void foo() {
+  ^decltype(auto) i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const decltype(auto)
+void foo() {
+  const int j = 0;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int",
+  },
+  {
+  R"cpp(// Simple initialization with const& decltype(auto)
+void foo() {
+  int k = 0;
+  const int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int &",
+  },
+  {
+  R"cpp(// Simple initialization with & decltype(auto)
+void foo() {
+  int k = 0;
+  int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype with initializer list: nothing
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^decltype(auto) i = {1,2};
+}
+  )cpp",
+  "",
+  },
+  {
+  R"cpp(// auto function return with trailing type
+struct Bar {};
+^auto test() -> decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// trailing return type
+struct Bar {};
+auto test() -> ^decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto in function return
+struct Bar {};
+^auto test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto& in function return
+struct Bar {};
+^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// const auto& in function return
+struct Bar {};
+const ^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) in function return
+struct Bar {};
+^decltype(auto) test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) reference in function return
+struct Bar {};
+^decltype(auto) test() {
+  int a;
+  return (a);
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype lvalue reference
+

[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-29 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added a reviewer: rsmith.
klimek added inline comments.



Comment at: clangd/XRefs.cpp:559
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||

malaperle wrote:
> klimek wrote:
> > sammccall wrote:
> > > malaperle wrote:
> > > > sammccall wrote:
> > > > > out of curiosity, why not implement `VisitTypeLoc` and handle all the 
> > > > > cases where it turns out to be `auto` etc?
> > > > > Even for `auto&` I'd expect the inner `auto` to have a `TypeLoc` you 
> > > > > could visit, saving the trouble of unwrapping.
> > > > > 
> > > > > (I'm probably wrong about all this, I don't know the AST well. But 
> > > > > I'd like to learn!)
> > > > From what I saw, there are actually two different AutoType* for each 
> > > > textual "auto". The AutoType* containing the deduced type does not get 
> > > > visited via a typeloc. It's not entirely clear to me why since I don't 
> > > > know the AST well either. I was thinking maybe the first is created 
> > > > when the type is not deduced yet and later on, then the rest of the 
> > > > function or expression is parsed, a second one with the actual type 
> > > > deduced is created. If I look at the code paths where they are created, 
> > > > it seems like this is roughly what's happening. The first one is 
> > > > created when the declarator is parsed (no deduced type yet) and the 
> > > > second is created when the expression of the initializer (or return 
> > > > statement) is evaluated and the type is then deduced. The visitor only 
> > > > visits the first one's typeloc. I don't think I'm knowledgeable enough 
> > > > to say whether or not that's a bug but it seems on purpose that it is 
> > > > modelled this way. Although it would be much nicer to only have to 
> > > > visit typelocs...
> > > > The AutoType* containing the deduced type does not get visited via a 
> > > > typeloc
> > > Ah, OK.
> > > Could you add a high level comment (maybe on the class) saying this is 
> > > the reason for the implementation? Otherwise as a reader I'll think "this 
> > > seems unneccesarily complicated" but not understand why.
> > > 
> > > @klimek Can you shed any light on this?
> > Can't you go from AutoTypeLoc -> AutoType -> getDeducedType()?
> The visitor doesn't visit the AutoTypeLoc that has the deduced type. In fact, 
> there are two AutoType* instances. I'm not sure that's is a bug that there 
> are two AutoType*, or if not visiting both AutoTypeLoc is a bug...or neither.
+Richard Smith:

This is weird. If I just create a minimal example:
  int f() {
auto i = f();
return i;
  }

I only get the undeduced auto type - Richard, in which cases are auto-typed 
being deduced? The AST dump doens't give an indication that there was an auto 
involved at all. Is this the famous syntactic vs. smenatic form problem? Do we 
have a backlink between the AutoTypeLoc and the deduced type somewhere?


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159



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


[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-28 Thread Marc-Andre Laperle via Phabricator via cfe-commits
malaperle added inline comments.



Comment at: clangd/XRefs.cpp:559
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||

klimek wrote:
> sammccall wrote:
> > malaperle wrote:
> > > sammccall wrote:
> > > > out of curiosity, why not implement `VisitTypeLoc` and handle all the 
> > > > cases where it turns out to be `auto` etc?
> > > > Even for `auto&` I'd expect the inner `auto` to have a `TypeLoc` you 
> > > > could visit, saving the trouble of unwrapping.
> > > > 
> > > > (I'm probably wrong about all this, I don't know the AST well. But I'd 
> > > > like to learn!)
> > > From what I saw, there are actually two different AutoType* for each 
> > > textual "auto". The AutoType* containing the deduced type does not get 
> > > visited via a typeloc. It's not entirely clear to me why since I don't 
> > > know the AST well either. I was thinking maybe the first is created when 
> > > the type is not deduced yet and later on, then the rest of the function 
> > > or expression is parsed, a second one with the actual type deduced is 
> > > created. If I look at the code paths where they are created, it seems 
> > > like this is roughly what's happening. The first one is created when the 
> > > declarator is parsed (no deduced type yet) and the second is created when 
> > > the expression of the initializer (or return statement) is evaluated and 
> > > the type is then deduced. The visitor only visits the first one's 
> > > typeloc. I don't think I'm knowledgeable enough to say whether or not 
> > > that's a bug but it seems on purpose that it is modelled this way. 
> > > Although it would be much nicer to only have to visit typelocs...
> > > The AutoType* containing the deduced type does not get visited via a 
> > > typeloc
> > Ah, OK.
> > Could you add a high level comment (maybe on the class) saying this is the 
> > reason for the implementation? Otherwise as a reader I'll think "this seems 
> > unneccesarily complicated" but not understand why.
> > 
> > @klimek Can you shed any light on this?
> Can't you go from AutoTypeLoc -> AutoType -> getDeducedType()?
The visitor doesn't visit the AutoTypeLoc that has the deduced type. In fact, 
there are two AutoType* instances. I'm not sure that's is a bug that there are 
two AutoType*, or if not visiting both AutoTypeLoc is a bug...or neither.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159



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


[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-28 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added inline comments.



Comment at: clangd/XRefs.cpp:559
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||

sammccall wrote:
> malaperle wrote:
> > sammccall wrote:
> > > out of curiosity, why not implement `VisitTypeLoc` and handle all the 
> > > cases where it turns out to be `auto` etc?
> > > Even for `auto&` I'd expect the inner `auto` to have a `TypeLoc` you 
> > > could visit, saving the trouble of unwrapping.
> > > 
> > > (I'm probably wrong about all this, I don't know the AST well. But I'd 
> > > like to learn!)
> > From what I saw, there are actually two different AutoType* for each 
> > textual "auto". The AutoType* containing the deduced type does not get 
> > visited via a typeloc. It's not entirely clear to me why since I don't know 
> > the AST well either. I was thinking maybe the first is created when the 
> > type is not deduced yet and later on, then the rest of the function or 
> > expression is parsed, a second one with the actual type deduced is created. 
> > If I look at the code paths where they are created, it seems like this is 
> > roughly what's happening. The first one is created when the declarator is 
> > parsed (no deduced type yet) and the second is created when the expression 
> > of the initializer (or return statement) is evaluated and the type is then 
> > deduced. The visitor only visits the first one's typeloc. I don't think I'm 
> > knowledgeable enough to say whether or not that's a bug but it seems on 
> > purpose that it is modelled this way. Although it would be much nicer to 
> > only have to visit typelocs...
> > The AutoType* containing the deduced type does not get visited via a typeloc
> Ah, OK.
> Could you add a high level comment (maybe on the class) saying this is the 
> reason for the implementation? Otherwise as a reader I'll think "this seems 
> unneccesarily complicated" but not understand why.
> 
> @klimek Can you shed any light on this?
Can't you go from AutoTypeLoc -> AutoType -> getDeducedType()?


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159



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


[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-28 Thread Sam McCall via Phabricator via cfe-commits
sammccall accepted this revision.
sammccall added a subscriber: klimek.
sammccall added a comment.

All sounds good to me.




Comment at: clangd/XRefs.cpp:559
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||

malaperle wrote:
> sammccall wrote:
> > out of curiosity, why not implement `VisitTypeLoc` and handle all the cases 
> > where it turns out to be `auto` etc?
> > Even for `auto&` I'd expect the inner `auto` to have a `TypeLoc` you could 
> > visit, saving the trouble of unwrapping.
> > 
> > (I'm probably wrong about all this, I don't know the AST well. But I'd like 
> > to learn!)
> From what I saw, there are actually two different AutoType* for each textual 
> "auto". The AutoType* containing the deduced type does not get visited via a 
> typeloc. It's not entirely clear to me why since I don't know the AST well 
> either. I was thinking maybe the first is created when the type is not 
> deduced yet and later on, then the rest of the function or expression is 
> parsed, a second one with the actual type deduced is created. If I look at 
> the code paths where they are created, it seems like this is roughly what's 
> happening. The first one is created when the declarator is parsed (no deduced 
> type yet) and the second is created when the expression of the initializer 
> (or return statement) is evaluated and the type is then deduced. The visitor 
> only visits the first one's typeloc. I don't think I'm knowledgeable enough 
> to say whether or not that's a bug but it seems on purpose that it is 
> modelled this way. Although it would be much nicer to only have to visit 
> typelocs...
> The AutoType* containing the deduced type does not get visited via a typeloc
Ah, OK.
Could you add a high level comment (maybe on the class) saying this is the 
reason for the implementation? Otherwise as a reader I'll think "this seems 
unneccesarily complicated" but not understand why.

@klimek Can you shed any light on this?


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159



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


[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-27 Thread Marc-Andre Laperle via Phabricator via cfe-commits
malaperle updated this revision to Diff 153153.
malaperle added a comment.

Address comments.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159

Files:
  clangd/XRefs.cpp
  unittests/clangd/TestTU.cpp
  unittests/clangd/TestTU.h
  unittests/clangd/XRefsTests.cpp

Index: unittests/clangd/XRefsTests.cpp
===
--- unittests/clangd/XRefsTests.cpp
+++ unittests/clangd/XRefsTests.cpp
@@ -343,6 +343,13 @@
 
   OneTest Tests[] = {
   {
+  R"cpp(// No hover
+^int main() {
+}
+  )cpp",
+  "",
+  },
+  {
   R"cpp(// Local variable
 int main() {
   int bonjour;
@@ -637,16 +644,275 @@
   )cpp",
   "",
   },
+  {
+  R"cpp(// Simple initialization with auto
+void foo() {
+  ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto
+void foo() {
+  const ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto&
+void foo() {
+  const ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with auto&
+void foo() {
+  ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Auto with initializer list.
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^auto i = {1,2};
+}
+  )cpp",
+  "class std::initializer_list",
+  },
+  {
+  R"cpp(// User defined conversion to auto
+struct Bar {
+  operator ^auto() const { return 10; }
+};
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with decltype(auto)
+void foo() {
+  ^decltype(auto) i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const decltype(auto)
+void foo() {
+  const int j = 0;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int",
+  },
+  {
+  R"cpp(// Simple initialization with const& decltype(auto)
+void foo() {
+  int k = 0;
+  const int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int &",
+  },
+  {
+  R"cpp(// Simple initialization with & decltype(auto)
+void foo() {
+  int k = 0;
+  int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype with initializer list: nothing
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^decltype(auto) i = {1,2};
+}
+  )cpp",
+  "",
+  },
+  {
+  R"cpp(// auto function return with trailing type
+struct Bar {};
+^auto test() -> decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// trailing return type
+struct Bar {};
+auto test() -> ^decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto in function return
+struct Bar {};
+^auto test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto& in function return
+struct Bar {};
+^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// const auto& in function return
+struct Bar {};
+const ^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) in function return
+struct Bar {};
+^decltype(auto) test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) reference in function return
+struct Bar {};
+^decltype(auto) test() {
+  int a;
+  return (a);
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype lvalue reference
+void foo() {
+   

[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-27 Thread Marc-Andre Laperle via Phabricator via cfe-commits
malaperle marked 4 inline comments as done.
malaperle added inline comments.



Comment at: clangd/XRefs.cpp:559
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||

sammccall wrote:
> out of curiosity, why not implement `VisitTypeLoc` and handle all the cases 
> where it turns out to be `auto` etc?
> Even for `auto&` I'd expect the inner `auto` to have a `TypeLoc` you could 
> visit, saving the trouble of unwrapping.
> 
> (I'm probably wrong about all this, I don't know the AST well. But I'd like 
> to learn!)
From what I saw, there are actually two different AutoType* for each textual 
"auto". The AutoType* containing the deduced type does not get visited via a 
typeloc. It's not entirely clear to me why since I don't know the AST well 
either. I was thinking maybe the first is created when the type is not deduced 
yet and later on, then the rest of the function or expression is parsed, a 
second one with the actual type deduced is created. If I look at the code paths 
where they are created, it seems like this is roughly what's happening. The 
first one is created when the declarator is parsed (no deduced type yet) and 
the second is created when the expression of the initializer (or return 
statement) is evaluated and the type is then deduced. The visitor only visits 
the first one's typeloc. I don't think I'm knowledgeable enough to say whether 
or not that's a bug but it seems on purpose that it is modelled this way. 
Although it would be much nicer to only have to visit typelocs...



Comment at: clangd/XRefs.cpp:640
+/// Retrieves the deduced type at a given location (auto, decltype).
+llvm::Optional getDeducedType(ParsedAST ,
+SourceLocation SourceLocationBeg) {

sammccall wrote:
> This is a really nice standalone piece of logic.
> It might be slightly cleaner to put it in `AST.h` with fine-grained 
> unit-tests there, and just smoke test it here. That way this file is more 
> focused on *what* the features do, and the lower layer has details about how 
> they work.
> (And if we find another use for this, like a "replace with deduced type" 
> refactoring, we could easily reuse it).
> 
> That said, the current stuff in this file doesn't exhibit that 
> layering/separation today. Happy if you prefer to land it here, and I/someone 
> may do such a refactoring in the future.
Good idea! The refactoring would be a neat feature too. I think I'd prefer to 
leave this refactoring for a bit later since this patch looks like it's close 
to ready to go.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159



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


[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-27 Thread Sam McCall via Phabricator via cfe-commits
sammccall accepted this revision.
sammccall added a comment.
This revision is now accepted and ready to land.

This is so great, thank you!




Comment at: clangd/XRefs.cpp:544
+/// Computes the deduced type at a given location by visiting the relevant
+/// nodes.
+class DeducedTypeVisitor : public RecursiveASTVisitor {

maybe a bit more context: "we use this to display the actual type when hovering 
over an `auto` keyword or `decltype()` expression"



Comment at: clangd/XRefs.cpp:546
+class DeducedTypeVisitor : public RecursiveASTVisitor {
+  const SourceLocation 
+  llvm::Optional DeducedType;

nit: SourceLocation is 32 bits, just copy it?
(Reference seems fine here but less obvious than it could be)



Comment at: clangd/XRefs.cpp:559
+  //- auto& i = 1;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+if (!D->getTypeSourceInfo() ||

out of curiosity, why not implement `VisitTypeLoc` and handle all the cases 
where it turns out to be `auto` etc?
Even for `auto&` I'd expect the inner `auto` to have a `TypeLoc` you could 
visit, saving the trouble of unwrapping.

(I'm probably wrong about all this, I don't know the AST well. But I'd like to 
learn!)



Comment at: clangd/XRefs.cpp:640
+/// Retrieves the deduced type at a given location (auto, decltype).
+llvm::Optional getDeducedType(ParsedAST ,
+SourceLocation SourceLocationBeg) {

This is a really nice standalone piece of logic.
It might be slightly cleaner to put it in `AST.h` with fine-grained unit-tests 
there, and just smoke test it here. That way this file is more focused on 
*what* the features do, and the lower layer has details about how they work.
(And if we find another use for this, like a "replace with deduced type" 
refactoring, we could easily reuse it).

That said, the current stuff in this file doesn't exhibit that 
layering/separation today. Happy if you prefer to land it here, and I/someone 
may do such a refactoring in the future.



Comment at: clangd/XRefs.cpp:656
+  DeducedTypeVisitor V(SourceLocationBeg);
+  V.TraverseTranslationUnitDecl(ASTCtx.getTranslationUnitDecl());
+  return V.getDeducedType();

This will end up deserializing the whole preamble I think, which is slow.
The fix is just to traverse from each of the top-level *non-preamble* decls 
instead, i.e. `AST.getLocalTopLevelDecls()`.

(we've fixed this bug many times so far, it would be nice if there's a 
systematic way to fix/catch this but I can't think of one)



Comment at: unittests/clangd/TestTU.h:47
 
-  ParsedAST build() const;
+  ParsedAST build(const std::vector  = {}) const;
   SymbolSlab headerSymbols() const;

headerSymbols() and index() also depend on these flags - can you make these 
extra args a member instead? (can be public, just like Code)


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159



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


[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-26 Thread Marc-Andre Laperle via Phabricator via cfe-commits
malaperle updated this revision to Diff 152958.
malaperle added a comment.

Rebased.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159

Files:
  clangd/XRefs.cpp
  unittests/clangd/TestTU.cpp
  unittests/clangd/TestTU.h
  unittests/clangd/XRefsTests.cpp

Index: unittests/clangd/XRefsTests.cpp
===
--- unittests/clangd/XRefsTests.cpp
+++ unittests/clangd/XRefsTests.cpp
@@ -343,6 +343,13 @@
 
   OneTest Tests[] = {
   {
+  R"cpp(// No hover
+^int main() {
+}
+  )cpp",
+  "",
+  },
+  {
   R"cpp(// Local variable
 int main() {
   int bonjour;
@@ -637,16 +644,273 @@
   )cpp",
   "",
   },
+  {
+  R"cpp(// Simple initialization with auto
+void foo() {
+  ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto
+void foo() {
+  const ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto&
+void foo() {
+  const ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with auto&
+void foo() {
+  ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Auto with initializer list.
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^auto i = {1,2};
+}
+  )cpp",
+  "class std::initializer_list",
+  },
+  {
+  R"cpp(// User defined conversion to auto
+struct Bar {
+  operator ^auto() const { return 10; }
+};
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with decltype(auto)
+void foo() {
+  ^decltype(auto) i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const decltype(auto)
+void foo() {
+  const int j = 0;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int",
+  },
+  {
+  R"cpp(// Simple initialization with const& decltype(auto)
+void foo() {
+  int k = 0;
+  const int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int &",
+  },
+  {
+  R"cpp(// Simple initialization with & decltype(auto)
+void foo() {
+  int k = 0;
+  int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype with initializer list: nothing
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^decltype(auto) i = {1,2};
+}
+  )cpp",
+  "",
+  },
+  {
+  R"cpp(// auto function return with trailing type
+struct Bar {};
+^auto test() -> decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// trailing return type
+struct Bar {};
+auto test() -> ^decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto in function return
+struct Bar {};
+^auto test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto& in function return
+struct Bar {};
+^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// const auto& in function return
+struct Bar {};
+const ^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) in function return
+struct Bar {};
+^decltype(auto) test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) reference in function return
+struct Bar {};
+^decltype(auto) test() {
+  int a;
+  return (a);
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype lvalue reference
+void foo() {
+  int I 

[PATCH] D48159: [clangd] Implement hover for "auto" and "decltype"

2018-06-13 Thread Marc-Andre Laperle via Phabricator via cfe-commits
malaperle created this revision.
Herald added subscribers: cfe-commits, jkorous, MaskRay, ioeric, ilya-biryukov.

This allows hovering on keywords that refer to deduced types.
This should cover most useful cases. Not covered:

- auto template parameters: Since this can be instantiated with many types,

it would not be practical to show the types.

- Structured binding: This could be done later to show multiple deduced types

in the hover.

- auto:: (part of concepts): Outside the scope of this patch.

Signed-off-by: Marc-Andre Laperle 


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D48159

Files:
  clangd/XRefs.cpp
  unittests/clangd/TestTU.cpp
  unittests/clangd/TestTU.h
  unittests/clangd/XRefsTests.cpp

Index: unittests/clangd/XRefsTests.cpp
===
--- unittests/clangd/XRefsTests.cpp
+++ unittests/clangd/XRefsTests.cpp
@@ -343,6 +343,13 @@
 
   OneTest Tests[] = {
   {
+  R"cpp(// No hover
+^int main() {
+}
+  )cpp",
+  "",
+  },
+  {
   R"cpp(// Local variable
 int main() {
   int bonjour;
@@ -637,16 +644,273 @@
   )cpp",
   "",
   },
+  {
+  R"cpp(// Simple initialization with auto
+void foo() {
+  ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto
+void foo() {
+  const ^auto i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const auto&
+void foo() {
+  const ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with auto&
+void foo() {
+  ^auto& i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Auto with initializer list.
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^auto i = {1,2};
+}
+  )cpp",
+  "class std::initializer_list",
+  },
+  {
+  R"cpp(// User defined conversion to auto
+struct Bar {
+  operator ^auto() const { return 10; }
+};
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with decltype(auto)
+void foo() {
+  ^decltype(auto) i = 1;
+}
+  )cpp",
+  "int",
+  },
+  {
+  R"cpp(// Simple initialization with const decltype(auto)
+void foo() {
+  const int j = 0;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int",
+  },
+  {
+  R"cpp(// Simple initialization with const& decltype(auto)
+void foo() {
+  int k = 0;
+  const int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "const int &",
+  },
+  {
+  R"cpp(// Simple initialization with & decltype(auto)
+void foo() {
+  int k = 0;
+  int& j = k;
+  ^decltype(auto) i = j;
+}
+  )cpp",
+  "int &",
+  },
+  {
+  R"cpp(// decltype with initializer list: nothing
+namespace std
+{
+  template
+  class initializer_list {};
+}
+void foo() {
+  ^decltype(auto) i = {1,2};
+}
+  )cpp",
+  "",
+  },
+  {
+  R"cpp(// auto function return with trailing type
+struct Bar {};
+^auto test() -> decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// trailing return type
+struct Bar {};
+auto test() -> ^decltype(Bar()) {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto in function return
+struct Bar {};
+^auto test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// auto& in function return
+struct Bar {};
+^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// const auto& in function return
+struct Bar {};
+const ^auto& test() {
+  return Bar();
+}
+  )cpp",
+  "struct Bar",
+  },
+  {
+  R"cpp(// decltype(auto) in function return
+struct Bar {};
+^decltype(auto)