[clang-tools-extra] 765b125 - [clangd] Untangle Hover from XRefs, move into own file.

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 19 06:12:56 PST 2019


Author: Sam McCall
Date: 2019-11-19T15:11:37+01:00
New Revision: 765b1250f6845e765abf01908b122dab441c2a42

URL: https://github.com/llvm/llvm-project/commit/765b1250f6845e765abf01908b122dab441c2a42
DIFF: https://github.com/llvm/llvm-project/commit/765b1250f6845e765abf01908b122dab441c2a42.diff

LOG: [clangd] Untangle Hover from XRefs, move into own file.

Summary:
This is mostly mechanical, with a few exceptions:
 - getDeducedType moved into AST.h where it belongs. It now takes
   ASTContext instead of ParsedAST, and avoids using the preprocessor.
 - hover now uses SelectionTree directly rather than via
   getDeclAtPosition helper
 - hover on 'auto' used to find the decl that contained the 'auto' and
   use that to set Kind and documentation for the hover result.
   Now we use targetDecl() to find the decl matching the deduced type instead.
   This changes tests, e.g. 'variable' -> class for auto on lambdas.
   I think this is better, but the motivation was to avoid depending on
   the internals of DeducedTypeVisitor. This functionality is removed
   from the visitor.

Reviewers: kadircet

Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D70357

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

Modified: 
    clang-tools-extra/clangd/AST.cpp
    clang-tools-extra/clangd/AST.h
    clang-tools-extra/clangd/CMakeLists.txt
    clang-tools-extra/clangd/ClangdServer.h
    clang-tools-extra/clangd/XRefs.cpp
    clang-tools-extra/clangd/XRefs.h
    clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
    clang-tools-extra/clangd/unittests/ASTTests.cpp
    clang-tools-extra/clangd/unittests/CMakeLists.txt
    clang-tools-extra/clangd/unittests/XRefsTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index d04ebcf22a88..6c69367633bf 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -15,11 +15,13 @@
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Index/USRGeneration.h"
+#include "clang/Lex/Lexer.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ScopedPrinter.h"
@@ -253,5 +255,114 @@ QualType declaredType(const TypeDecl *D) {
   return D->getASTContext().getTypeDeclType(D);
 }
 
+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<DeducedTypeVisitor> {
+  SourceLocation SearchedLocation;
+
+public:
+  DeducedTypeVisitor(SourceLocation SearchedLocation)
+      : SearchedLocation(SearchedLocation) {}
+
+  // Handle auto initializers:
+  //- auto i = 1;
+  //- decltype(auto) i = 1;
+  //- auto& i = 1;
+  //- auto* i = &a;
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+    if (!D->getTypeSourceInfo() ||
+        D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
+      return true;
+
+    if (auto *AT = D->getType()->getContainedAutoType()) {
+      if (!AT->getDeducedType().isNull())
+        DeducedType = AT->getDeducedType();
+    }
+    return true;
+  }
+
+  // Handle auto return types:
+  //- auto foo() {}
+  //- auto& foo() {}
+  //- auto foo() -> int {}
+  //- 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<CXXConversionDecl>(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;
+
+    const AutoType *AT = D->getReturnType()->getContainedAutoType();
+    if (AT && !AT->getDeducedType().isNull()) {
+      DeducedType = AT->getDeducedType();
+    } else if (auto DT = dyn_cast<DecltypeType>(D->getReturnType())) {
+      // auto in a trailing return type just points to a DecltypeType and
+      // getContainedAutoType does not unwrap it.
+      if (!DT->getUnderlyingType().isNull())
+        DeducedType = DT->getUnderlyingType();
+    } else if (!D->getReturnType().isNull()) {
+      DeducedType = D->getReturnType();
+    }
+    return true;
+  }
+
+  // Handle non-auto decltype, e.g.:
+  // - auto foo() -> decltype(expr) {}
+  // - decltype(expr);
+  bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+    if (TL.getBeginLoc() != SearchedLocation)
+      return true;
+
+    // A DecltypeType's underlying type can be another DecltypeType! E.g.
+    //  int I = 0;
+    //  decltype(I) J = I;
+    //  decltype(J) K = J;
+    const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
+    while (DT && !DT->getUnderlyingType().isNull()) {
+      DeducedType = DT->getUnderlyingType();
+      DT = dyn_cast<DecltypeType>(DeducedType.getTypePtr());
+    }
+    return true;
+  }
+
+  QualType DeducedType;
+};
+} // namespace
+
+llvm::Optional<QualType> getDeducedType(ASTContext &ASTCtx,
+                                        SourceLocation Loc) {
+  Token Tok;
+  // Only try to find a deduced type if the token is auto or decltype.
+  if (!Loc.isValid() ||
+      Lexer::getRawToken(Loc, Tok, ASTCtx.getSourceManager(),
+                         ASTCtx.getLangOpts(), false) ||
+      !Tok.is(tok::raw_identifier) ||
+      !(Tok.getRawIdentifier() == "auto" ||
+        Tok.getRawIdentifier() == "decltype")) {
+    return {};
+  }
+  DeducedTypeVisitor V(Loc);
+  V.TraverseAST(ASTCtx);
+  if (V.DeducedType.isNull())
+    return llvm::None;
+  return V.DeducedType;
+}
+
 } // namespace clangd
 } // namespace clang

diff  --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h
index b106e06f8d91..3850ab4f6b4f 100644
--- a/clang-tools-extra/clangd/AST.h
+++ b/clang-tools-extra/clangd/AST.h
@@ -116,6 +116,11 @@ NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND);
 // (i.e. vector<T*> rather than vector<type-parameter-0-0 *>.
 QualType declaredType(const TypeDecl *D);
 
+/// Retrieves the deduced type at a given location (auto, decltype).
+/// Retuns None unless Loc starts an auto/decltype token.
+/// It will return the underlying type.
+llvm::Optional<QualType> getDeducedType(ASTContext &, SourceLocation Loc);
+
 } // namespace clangd
 } // namespace clang
 

diff  --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt
index d428c8ad2694..8ab2ae6b91d3 100644
--- a/clang-tools-extra/clangd/CMakeLists.txt
+++ b/clang-tools-extra/clangd/CMakeLists.txt
@@ -57,6 +57,7 @@ add_clang_library(clangDaemon
   GlobalCompilationDatabase.cpp
   Headers.cpp
   HeaderSourceSwitch.cpp
+  Hover.cpp
   IncludeFixer.cpp
   JSONTransport.cpp
   Logger.cpp

diff  --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index fdea9b389e36..cd0b91c08f08 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -16,6 +16,7 @@
 #include "FormattedString.h"
 #include "Function.h"
 #include "GlobalCompilationDatabase.h"
+#include "Hover.h"
 #include "Protocol.h"
 #include "SemanticHighlighting.h"
 #include "TUScheduler.h"

diff  --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
new file mode 100644
index 000000000000..0e28e30482eb
--- /dev/null
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -0,0 +1,443 @@
+//===--- Hover.cpp - Information about code at the cursor location --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Hover.h"
+
+#include "AST.h"
+#include "CodeCompletionStrings.h"
+#include "FindTarget.h"
+#include "Logger.h"
+#include "Selection.h"
+#include "SourceCode.h"
+#include "index/SymbolCollector.h"
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/PrettyPrinter.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
+  PrintingPolicy Policy(Base);
+
+  Policy.AnonymousTagLocations = false;
+  Policy.TerseOutput = true;
+  Policy.PolishForDeclaration = true;
+  Policy.ConstantsAsWritten = true;
+  Policy.SuppressTagKeyword = false;
+
+  return Policy;
+}
+
+/// Given a declaration \p D, return a human-readable string representing the
+/// local scope in which it is declared, i.e. class(es) and method name. Returns
+/// an empty string if it is not local.
+std::string getLocalScope(const Decl *D) {
+  std::vector<std::string> Scopes;
+  const DeclContext *DC = D->getDeclContext();
+  auto GetName = [](const TypeDecl *D) {
+    if (!D->getDeclName().isEmpty()) {
+      PrintingPolicy Policy = D->getASTContext().getPrintingPolicy();
+      Policy.SuppressScope = true;
+      return declaredType(D).getAsString(Policy);
+    }
+    if (auto RD = dyn_cast<RecordDecl>(D))
+      return ("(anonymous " + RD->getKindName() + ")").str();
+    return std::string("");
+  };
+  while (DC) {
+    if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
+      Scopes.push_back(GetName(TD));
+    else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
+      Scopes.push_back(FD->getNameAsString());
+    DC = DC->getParent();
+  }
+
+  return llvm::join(llvm::reverse(Scopes), "::");
+}
+
+/// Returns the human-readable representation for namespace containing the
+/// declaration \p D. Returns empty if it is contained global namespace.
+std::string getNamespaceScope(const Decl *D) {
+  const DeclContext *DC = D->getDeclContext();
+
+  if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
+    return getNamespaceScope(TD);
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
+    return getNamespaceScope(FD);
+  if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
+    return ND->getQualifiedNameAsString();
+
+  return "";
+}
+
+std::string printDefinition(const Decl *D) {
+  std::string Definition;
+  llvm::raw_string_ostream OS(Definition);
+  PrintingPolicy Policy =
+      printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
+  Policy.IncludeTagDefinition = false;
+  Policy.SuppressTemplateArgsInCXXConstructors = true;
+  D->print(OS, Policy);
+  OS.flush();
+  return Definition;
+}
+
+void printParams(llvm::raw_ostream &OS,
+                        const std::vector<HoverInfo::Param> &Params) {
+  for (size_t I = 0, E = Params.size(); I != E; ++I) {
+    if (I)
+      OS << ", ";
+    OS << Params.at(I);
+  }
+}
+
+std::vector<HoverInfo::Param>
+fetchTemplateParameters(const TemplateParameterList *Params,
+                        const PrintingPolicy &PP) {
+  assert(Params);
+  std::vector<HoverInfo::Param> TempParameters;
+
+  for (const Decl *Param : *Params) {
+    HoverInfo::Param P;
+    P.Type.emplace();
+    if (const auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+      P.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
+      if (TTP->isParameterPack())
+        *P.Type += "...";
+
+      if (!TTP->getName().empty())
+        P.Name = TTP->getNameAsString();
+      if (TTP->hasDefaultArgument())
+        P.Default = TTP->getDefaultArgument().getAsString(PP);
+    } else if (const auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+      if (IdentifierInfo *II = NTTP->getIdentifier())
+        P.Name = II->getName().str();
+
+      llvm::raw_string_ostream Out(*P.Type);
+      NTTP->getType().print(Out, PP);
+      if (NTTP->isParameterPack())
+        Out << "...";
+
+      if (NTTP->hasDefaultArgument()) {
+        P.Default.emplace();
+        llvm::raw_string_ostream Out(*P.Default);
+        NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
+      }
+    } else if (const auto TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+      llvm::raw_string_ostream OS(*P.Type);
+      OS << "template <";
+      printParams(OS,
+                  fetchTemplateParameters(TTPD->getTemplateParameters(), PP));
+      OS << "> class"; // FIXME: TemplateTemplateParameter doesn't store the
+                       // info on whether this param was a "typename" or
+                       // "class".
+      if (!TTPD->getName().empty())
+        P.Name = TTPD->getNameAsString();
+      if (TTPD->hasDefaultArgument()) {
+        P.Default.emplace();
+        llvm::raw_string_ostream Out(*P.Default);
+        TTPD->getDefaultArgument().getArgument().print(PP, Out);
+      }
+    }
+    TempParameters.push_back(std::move(P));
+  }
+
+  return TempParameters;
+}
+
+const FunctionDecl *getUnderlyingFunction(const Decl *D) {
+  // Extract lambda from variables.
+  if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) {
+    auto QT = VD->getType();
+    if (!QT.isNull()) {
+      while (!QT->getPointeeType().isNull())
+        QT = QT->getPointeeType();
+
+      if (const auto *CD = QT->getAsCXXRecordDecl())
+        return CD->getLambdaCallOperator();
+    }
+  }
+
+  // Non-lambda functions.
+  return D->getAsFunction();
+}
+
+// Look up information about D from the index, and add it to Hover.
+void enhanceFromIndex(HoverInfo &Hover, const Decl *D,
+                      const SymbolIndex *Index) {
+  if (!Index || !llvm::isa<NamedDecl>(D))
+    return;
+  const NamedDecl &ND = *cast<NamedDecl>(D);
+  // We only add documentation, so don't bother if we already have some.
+  if (!Hover.Documentation.empty())
+    return;
+  // Skip querying for non-indexable symbols, there's no point.
+  // We're searching for symbols that might be indexed outside this main file.
+  if (!SymbolCollector::shouldCollectSymbol(ND, ND.getASTContext(),
+                                            SymbolCollector::Options(),
+                                            /*IsMainFileOnly=*/false))
+    return;
+  auto ID = getSymbolID(&ND);
+  if (!ID)
+    return;
+  LookupRequest Req;
+  Req.IDs.insert(*ID);
+  Index->lookup(
+      Req, [&](const Symbol &S) { Hover.Documentation = S.Documentation; });
+}
+
+// Populates Type, ReturnType, and Parameters for function-like decls.
+void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
+                                      const FunctionDecl *FD,
+                                      const PrintingPolicy &Policy) {
+  HI.Parameters.emplace();
+  for (const ParmVarDecl *PVD : FD->parameters()) {
+    HI.Parameters->emplace_back();
+    auto &P = HI.Parameters->back();
+    if (!PVD->getType().isNull()) {
+      P.Type.emplace();
+      llvm::raw_string_ostream OS(*P.Type);
+      PVD->getType().print(OS, Policy);
+    } else {
+      std::string Param;
+      llvm::raw_string_ostream OS(Param);
+      PVD->dump(OS);
+      OS.flush();
+      elog("Got param with null type: {0}", Param);
+    }
+    if (!PVD->getName().empty())
+      P.Name = PVD->getNameAsString();
+    if (PVD->hasDefaultArg()) {
+      P.Default.emplace();
+      llvm::raw_string_ostream Out(*P.Default);
+      PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
+    }
+  }
+
+  if (const auto* CCD = llvm::dyn_cast<CXXConstructorDecl>(FD)) {
+    // Constructor's "return type" is the class type.
+    HI.ReturnType = declaredType(CCD->getParent()).getAsString(Policy);
+    // Don't provide any type for the constructor itself.
+  } else if (const auto* CDD = llvm::dyn_cast<CXXDestructorDecl>(FD)){
+    HI.ReturnType = "void";
+  } else {
+    HI.ReturnType = FD->getReturnType().getAsString(Policy);
+
+    QualType FunctionType = FD->getType();
+    if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) // Lambdas
+      FunctionType = VD->getType().getDesugaredType(D->getASTContext());
+    HI.Type = FunctionType.getAsString(Policy);
+  }
+  // FIXME: handle variadics.
+}
+
+/// Generate a \p Hover object given the declaration \p D.
+HoverInfo getHoverContents(const Decl *D, const SymbolIndex *Index) {
+  HoverInfo HI;
+  const ASTContext &Ctx = D->getASTContext();
+
+  HI.NamespaceScope = getNamespaceScope(D);
+  if (!HI.NamespaceScope->empty())
+    HI.NamespaceScope->append("::");
+  HI.LocalScope = getLocalScope(D);
+  if (!HI.LocalScope.empty())
+    HI.LocalScope.append("::");
+
+  PrintingPolicy Policy = printingPolicyForDecls(Ctx.getPrintingPolicy());
+  if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D)) {
+    HI.Documentation = getDeclComment(Ctx, *ND);
+    HI.Name = printName(Ctx, *ND);
+  }
+
+  HI.Kind = indexSymbolKindToSymbolKind(index::getSymbolInfo(D).Kind);
+
+  // Fill in template params.
+  if (const TemplateDecl *TD = D->getDescribedTemplate()) {
+    HI.TemplateParameters =
+        fetchTemplateParameters(TD->getTemplateParameters(), Policy);
+    D = TD;
+  } else if (const FunctionDecl *FD = D->getAsFunction()) {
+    if (const auto FTD = FD->getDescribedTemplate()) {
+      HI.TemplateParameters =
+          fetchTemplateParameters(FTD->getTemplateParameters(), Policy);
+      D = FTD;
+    }
+  }
+
+  // Fill in types and params.
+  if (const FunctionDecl *FD = getUnderlyingFunction(D)) {
+    fillFunctionTypeAndParams(HI, D, FD, Policy);
+  } else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
+    HI.Type.emplace();
+    llvm::raw_string_ostream OS(*HI.Type);
+    VD->getType().print(OS, Policy);
+  }
+
+  // Fill in value with evaluated initializer if possible.
+  // FIXME(kadircet): Also set Value field for expressions like "sizeof" and
+  // function calls.
+  if (const auto *Var = dyn_cast<VarDecl>(D)) {
+    if (const Expr *Init = Var->getInit()) {
+      Expr::EvalResult Result;
+      if (!Init->isValueDependent() && Init->EvaluateAsRValue(Result, Ctx)) {
+        HI.Value.emplace();
+        llvm::raw_string_ostream ValueOS(*HI.Value);
+        Result.Val.printPretty(ValueOS, const_cast<ASTContext &>(Ctx),
+                               Init->getType());
+      }
+    }
+  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
+    // Dependent enums (e.g. nested in template classes) don't have values yet.
+    if (!ECD->getType()->isDependentType())
+      HI.Value = ECD->getInitVal().toString(10);
+  }
+
+  HI.Definition = printDefinition(D);
+  enhanceFromIndex(HI, D, Index);
+  return HI;
+}
+
+/// Generate a \p Hover object given the type \p T.
+HoverInfo getHoverContents(QualType T, const Decl *D, ASTContext &ASTCtx,
+                                  const SymbolIndex *Index) {
+  HoverInfo HI;
+  llvm::raw_string_ostream OS(HI.Name);
+  PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
+  T.print(OS, Policy);
+  OS.flush();
+
+  if (D) {
+    HI.Kind = indexSymbolKindToSymbolKind(index::getSymbolInfo(D).Kind);
+    enhanceFromIndex(HI, D, Index);
+  }
+  return HI;
+}
+
+/// Generate a \p Hover object given the macro \p MacroDecl.
+HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
+  HoverInfo HI;
+  SourceManager &SM = AST.getSourceManager();
+  HI.Name = Macro.Name;
+  HI.Kind = indexSymbolKindToSymbolKind(
+      index::getSymbolInfoForMacro(*Macro.Info).Kind);
+  // FIXME: Populate documentation
+  // FIXME: Pupulate parameters
+
+  // Try to get the full definition, not just the name
+  SourceLocation StartLoc = Macro.Info->getDefinitionLoc();
+  SourceLocation EndLoc = Macro.Info->getDefinitionEndLoc();
+  if (EndLoc.isValid()) {
+    EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, SM,
+                                        AST.getASTContext().getLangOpts());
+    bool Invalid;
+    StringRef Buffer = SM.getBufferData(SM.getFileID(StartLoc), &Invalid);
+    if (!Invalid) {
+      unsigned StartOffset = SM.getFileOffset(StartLoc);
+      unsigned EndOffset = SM.getFileOffset(EndLoc);
+      if (EndOffset <= Buffer.size() && StartOffset < EndOffset)
+        HI.Definition =
+            ("#define " + Buffer.substr(StartOffset, EndOffset - StartOffset))
+                .str();
+    }
+  }
+  return HI;
+}
+
+} // namespace
+
+llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
+                                   format::FormatStyle Style,
+                                   const SymbolIndex *Index) {
+  const SourceManager &SM = AST.getSourceManager();
+  llvm::Optional<HoverInfo> HI;
+  SourceLocation SourceLocationBeg = SM.getMacroArgExpandedLocation(
+      getBeginningOfIdentifier(Pos, SM, AST.getASTContext().getLangOpts()));
+
+  if (auto Deduced = getDeducedType(AST.getASTContext(), SourceLocationBeg)) {
+    // Find the corresponding decl to populate kind and fetch documentation.
+    DeclRelationSet Rel = DeclRelation::TemplatePattern | DeclRelation::Alias;
+    auto Decls =
+        targetDecl(ast_type_traits::DynTypedNode::create(*Deduced), Rel);
+    HI = getHoverContents(*Deduced, Decls.empty() ? nullptr : Decls.front(),
+                          AST.getASTContext(), Index);
+  } else if (auto M = locateMacroAt(SourceLocationBeg, AST.getPreprocessor())) {
+    HI = getHoverContents(*M, AST);
+  } else {
+    auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
+    if (!Offset) {
+      llvm::consumeError(Offset.takeError());
+      return llvm::None;
+    }
+    SelectionTree Selection(AST.getASTContext(), AST.getTokens(), *Offset);
+    std::vector<const Decl *> Result;
+    if (const SelectionTree::Node *N = Selection.commonAncestor()) {
+      DeclRelationSet Rel = DeclRelation::TemplatePattern | DeclRelation::Alias;
+      auto Decls = targetDecl(N->ASTNode, Rel);
+      if (!Decls.empty())
+        HI = getHoverContents(Decls.front(), Index);
+    }
+  }
+
+  if (!HI)
+    return llvm::None;
+
+  auto Replacements = format::reformat(
+      Style, HI->Definition, tooling::Range(0, HI->Definition.size()));
+  if (auto Formatted =
+          tooling::applyAllReplacements(HI->Definition, Replacements))
+    HI->Definition = *Formatted;
+
+  HI->SymRange =
+      getTokenRange(AST.getASTContext().getSourceManager(),
+                    AST.getASTContext().getLangOpts(), SourceLocationBeg);
+  return HI;
+}
+
+FormattedString HoverInfo::present() const {
+  FormattedString Output;
+  if (NamespaceScope) {
+    Output.appendText("Declared in");
+    // Drop trailing "::".
+    if (!LocalScope.empty())
+      Output.appendInlineCode(llvm::StringRef(LocalScope).drop_back(2));
+    else if (NamespaceScope->empty())
+      Output.appendInlineCode("global namespace");
+    else
+      Output.appendInlineCode(llvm::StringRef(*NamespaceScope).drop_back(2));
+  }
+
+  if (!Definition.empty()) {
+    Output.appendCodeBlock(Definition);
+  } else {
+    // Builtin types
+    Output.appendCodeBlock(Name);
+  }
+
+  if (!Documentation.empty())
+    Output.appendText(Documentation);
+  return Output;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                              const HoverInfo::Param &P) {
+  std::vector<llvm::StringRef> Output;
+  if (P.Type)
+    Output.push_back(*P.Type);
+  if (P.Name)
+    Output.push_back(*P.Name);
+  OS << llvm::join(Output, " ");
+  if (P.Default)
+    OS << " = " << *P.Default;
+  return OS;
+}
+
+} // namespace clangd
+} // namespace clang

diff  --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h
new file mode 100644
index 000000000000..704e5c4b14e5
--- /dev/null
+++ b/clang-tools-extra/clangd/Hover.h
@@ -0,0 +1,93 @@
+//===--- Hover.h - Information about code at the cursor location -*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_HOVER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_HOVER_H
+
+#include "FormattedString.h"
+#include "ParsedAST.h"
+#include "Protocol.h"
+
+namespace clang {
+namespace clangd {
+
+/// Contains detailed information about a Symbol. Especially useful when
+/// generating hover responses. It can be rendered as a hover panel, or
+/// embedding clients can use the structured information to provide their own
+/// UI.
+struct HoverInfo {
+  /// Represents parameters of a function, a template or a macro.
+  /// For example:
+  /// - void foo(ParamType Name = DefaultValue)
+  /// - #define FOO(Name)
+  /// - template <ParamType Name = DefaultType> class Foo {};
+  struct Param {
+    /// The pretty-printed parameter type, e.g. "int", or "typename" (in
+    /// TemplateParameters)
+    llvm::Optional<std::string> Type;
+    /// None for unnamed parameters.
+    llvm::Optional<std::string> Name;
+    /// None if no default is provided.
+    llvm::Optional<std::string> Default;
+  };
+
+  /// For a variable named Bar, declared in clang::clangd::Foo::getFoo the
+  /// following fields will hold:
+  /// - NamespaceScope: clang::clangd::
+  /// - LocalScope: Foo::getFoo::
+  /// - Name: Bar
+
+  /// Scopes might be None in cases where they don't make sense, e.g. macros and
+  /// auto/decltype.
+  /// Contains all of the enclosing namespaces, empty string means global
+  /// namespace.
+  llvm::Optional<std::string> NamespaceScope;
+  /// Remaining named contexts in symbol's qualified name, empty string means
+  /// symbol is not local.
+  std::string LocalScope;
+  /// Name of the symbol, does not contain any "::".
+  std::string Name;
+  llvm::Optional<Range> SymRange;
+  /// Scope containing the symbol. e.g, "global namespace", "function x::Y"
+  /// - None for deduced types, e.g "auto", "decltype" keywords.
+  SymbolKind Kind;
+  std::string Documentation;
+  /// Source code containing the definition of the symbol.
+  std::string Definition;
+
+  /// Pretty-printed variable type.
+  /// Set only for variables.
+  llvm::Optional<std::string> Type;
+  /// Set for functions and lambadas.
+  llvm::Optional<std::string> ReturnType;
+  /// Set for functions, lambdas and macros with parameters.
+  llvm::Optional<std::vector<Param>> Parameters;
+  /// Set for all templates(function, class, variable).
+  llvm::Optional<std::vector<Param>> TemplateParameters;
+  /// Contains the evaluated value of the symbol if available.
+  llvm::Optional<std::string> Value;
+
+  /// Produce a user-readable information.
+  FormattedString present() const;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const HoverInfo::Param &);
+inline bool operator==(const HoverInfo::Param &LHS,
+                       const HoverInfo::Param &RHS) {
+  return std::tie(LHS.Type, LHS.Name, LHS.Default) ==
+         std::tie(RHS.Type, RHS.Name, RHS.Default);
+}
+
+/// Get the hover information when hovering at \p Pos.
+llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
+                                   format::FormatStyle Style,
+                                   const SymbolIndex *Index);
+
+} // namespace clangd
+} // namespace clang
+
+#endif

diff  --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index 3165633e60f9..de10e3c48e20 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -10,7 +10,6 @@
 #include "CodeCompletionStrings.h"
 #include "FindSymbols.h"
 #include "FindTarget.h"
-#include "FormattedString.h"
 #include "Logger.h"
 #include "ParsedAST.h"
 #include "Protocol.h"
@@ -20,15 +19,12 @@
 #include "index/Index.h"
 #include "index/Merge.h"
 #include "index/Relation.h"
-#include "index/SymbolCollector.h"
 #include "index/SymbolLocation.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
@@ -44,7 +40,6 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
-#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -396,500 +391,6 @@ std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
   return Result;
 }
 
-static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
-  PrintingPolicy Policy(Base);
-
-  Policy.AnonymousTagLocations = false;
-  Policy.TerseOutput = true;
-  Policy.PolishForDeclaration = true;
-  Policy.ConstantsAsWritten = true;
-  Policy.SuppressTagKeyword = false;
-
-  return Policy;
-}
-
-/// Given a declaration \p D, return a human-readable string representing the
-/// local scope in which it is declared, i.e. class(es) and method name. Returns
-/// an empty string if it is not local.
-static std::string getLocalScope(const Decl *D) {
-  std::vector<std::string> Scopes;
-  const DeclContext *DC = D->getDeclContext();
-  auto GetName = [](const TypeDecl *D) {
-    if (!D->getDeclName().isEmpty()) {
-      PrintingPolicy Policy = D->getASTContext().getPrintingPolicy();
-      Policy.SuppressScope = true;
-      return declaredType(D).getAsString(Policy);
-    }
-    if (auto RD = dyn_cast<RecordDecl>(D))
-      return ("(anonymous " + RD->getKindName() + ")").str();
-    return std::string("");
-  };
-  while (DC) {
-    if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
-      Scopes.push_back(GetName(TD));
-    else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
-      Scopes.push_back(FD->getNameAsString());
-    DC = DC->getParent();
-  }
-
-  return llvm::join(llvm::reverse(Scopes), "::");
-}
-
-/// Returns the human-readable representation for namespace containing the
-/// declaration \p D. Returns empty if it is contained global namespace.
-static std::string getNamespaceScope(const Decl *D) {
-  const DeclContext *DC = D->getDeclContext();
-
-  if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
-    return getNamespaceScope(TD);
-  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
-    return getNamespaceScope(FD);
-  if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
-    return ND->getQualifiedNameAsString();
-
-  return "";
-}
-
-static std::string printDefinition(const Decl *D) {
-  std::string Definition;
-  llvm::raw_string_ostream OS(Definition);
-  PrintingPolicy Policy =
-      printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
-  Policy.IncludeTagDefinition = false;
-  Policy.SuppressTemplateArgsInCXXConstructors = true;
-  D->print(OS, Policy);
-  OS.flush();
-  return Definition;
-}
-
-static void printParams(llvm::raw_ostream &OS,
-                        const std::vector<HoverInfo::Param> &Params) {
-  for (size_t I = 0, E = Params.size(); I != E; ++I) {
-    if (I)
-      OS << ", ";
-    OS << Params.at(I);
-  }
-}
-
-static std::vector<HoverInfo::Param>
-fetchTemplateParameters(const TemplateParameterList *Params,
-                        const PrintingPolicy &PP) {
-  assert(Params);
-  std::vector<HoverInfo::Param> TempParameters;
-
-  for (const Decl *Param : *Params) {
-    HoverInfo::Param P;
-    P.Type.emplace();
-    if (const auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
-      P.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
-      if (TTP->isParameterPack())
-        *P.Type += "...";
-
-      if (!TTP->getName().empty())
-        P.Name = TTP->getNameAsString();
-      if (TTP->hasDefaultArgument())
-        P.Default = TTP->getDefaultArgument().getAsString(PP);
-    } else if (const auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
-      if (IdentifierInfo *II = NTTP->getIdentifier())
-        P.Name = II->getName().str();
-
-      llvm::raw_string_ostream Out(*P.Type);
-      NTTP->getType().print(Out, PP);
-      if (NTTP->isParameterPack())
-        Out << "...";
-
-      if (NTTP->hasDefaultArgument()) {
-        P.Default.emplace();
-        llvm::raw_string_ostream Out(*P.Default);
-        NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
-      }
-    } else if (const auto TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
-      llvm::raw_string_ostream OS(*P.Type);
-      OS << "template <";
-      printParams(OS,
-                  fetchTemplateParameters(TTPD->getTemplateParameters(), PP));
-      OS << "> class"; // FIXME: TemplateTemplateParameter doesn't store the
-                       // info on whether this param was a "typename" or
-                       // "class".
-      if (!TTPD->getName().empty())
-        P.Name = TTPD->getNameAsString();
-      if (TTPD->hasDefaultArgument()) {
-        P.Default.emplace();
-        llvm::raw_string_ostream Out(*P.Default);
-        TTPD->getDefaultArgument().getArgument().print(PP, Out);
-      }
-    }
-    TempParameters.push_back(std::move(P));
-  }
-
-  return TempParameters;
-}
-
-static const FunctionDecl *getUnderlyingFunction(const Decl *D) {
-  // Extract lambda from variables.
-  if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) {
-    auto QT = VD->getType();
-    if (!QT.isNull()) {
-      while (!QT->getPointeeType().isNull())
-        QT = QT->getPointeeType();
-
-      if (const auto *CD = QT->getAsCXXRecordDecl())
-        return CD->getLambdaCallOperator();
-    }
-  }
-
-  // Non-lambda functions.
-  return D->getAsFunction();
-}
-
-// Look up information about D from the index, and add it to Hover.
-static void enhanceFromIndex(HoverInfo &Hover, const Decl *D,
-                             const SymbolIndex *Index) {
-  if (!Index || !llvm::isa<NamedDecl>(D))
-    return;
-  const NamedDecl &ND = *cast<NamedDecl>(D);
-  // We only add documentation, so don't bother if we already have some.
-  if (!Hover.Documentation.empty())
-    return;
-  // Skip querying for non-indexable symbols, there's no point.
-  // We're searching for symbols that might be indexed outside this main file.
-  if (!SymbolCollector::shouldCollectSymbol(ND, ND.getASTContext(),
-                                            SymbolCollector::Options(),
-                                            /*IsMainFileOnly=*/false))
-    return;
-  auto ID = getSymbolID(&ND);
-  if (!ID)
-    return;
-  LookupRequest Req;
-  Req.IDs.insert(*ID);
-  Index->lookup(
-      Req, [&](const Symbol &S) { Hover.Documentation = S.Documentation; });
-}
-
-// Populates Type, ReturnType, and Parameters for function-like decls.
-static void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
-                                      const FunctionDecl *FD,
-                                      const PrintingPolicy &Policy) {
-  HI.Parameters.emplace();
-  for (const ParmVarDecl *PVD : FD->parameters()) {
-    HI.Parameters->emplace_back();
-    auto &P = HI.Parameters->back();
-    if (!PVD->getType().isNull()) {
-      P.Type.emplace();
-      llvm::raw_string_ostream OS(*P.Type);
-      PVD->getType().print(OS, Policy);
-    } else {
-      std::string Param;
-      llvm::raw_string_ostream OS(Param);
-      PVD->dump(OS);
-      OS.flush();
-      elog("Got param with null type: {0}", Param);
-    }
-    if (!PVD->getName().empty())
-      P.Name = PVD->getNameAsString();
-    if (PVD->hasDefaultArg()) {
-      P.Default.emplace();
-      llvm::raw_string_ostream Out(*P.Default);
-      PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
-    }
-  }
-
-  if (const auto* CCD = llvm::dyn_cast<CXXConstructorDecl>(FD)) {
-    // Constructor's "return type" is the class type.
-    HI.ReturnType = declaredType(CCD->getParent()).getAsString(Policy);
-    // Don't provide any type for the constructor itself.
-  } else if (const auto* CDD = llvm::dyn_cast<CXXDestructorDecl>(FD)){
-    HI.ReturnType = "void";
-  } else {
-    HI.ReturnType = FD->getReturnType().getAsString(Policy);
-
-    QualType FunctionType = FD->getType();
-    if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) // Lambdas
-      FunctionType = VD->getType().getDesugaredType(D->getASTContext());
-    HI.Type = FunctionType.getAsString(Policy);
-  }
-  // FIXME: handle variadics.
-}
-
-/// Generate a \p Hover object given the declaration \p D.
-static HoverInfo getHoverContents(const Decl *D, const SymbolIndex *Index) {
-  HoverInfo HI;
-  const ASTContext &Ctx = D->getASTContext();
-
-  HI.NamespaceScope = getNamespaceScope(D);
-  if (!HI.NamespaceScope->empty())
-    HI.NamespaceScope->append("::");
-  HI.LocalScope = getLocalScope(D);
-  if (!HI.LocalScope.empty())
-    HI.LocalScope.append("::");
-
-  PrintingPolicy Policy = printingPolicyForDecls(Ctx.getPrintingPolicy());
-  if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D)) {
-    HI.Documentation = getDeclComment(Ctx, *ND);
-    HI.Name = printName(Ctx, *ND);
-  }
-
-  HI.Kind = indexSymbolKindToSymbolKind(index::getSymbolInfo(D).Kind);
-
-  // Fill in template params.
-  if (const TemplateDecl *TD = D->getDescribedTemplate()) {
-    HI.TemplateParameters =
-        fetchTemplateParameters(TD->getTemplateParameters(), Policy);
-    D = TD;
-  } else if (const FunctionDecl *FD = D->getAsFunction()) {
-    if (const auto FTD = FD->getDescribedTemplate()) {
-      HI.TemplateParameters =
-          fetchTemplateParameters(FTD->getTemplateParameters(), Policy);
-      D = FTD;
-    }
-  }
-
-  // Fill in types and params.
-  if (const FunctionDecl *FD = getUnderlyingFunction(D)) {
-    fillFunctionTypeAndParams(HI, D, FD, Policy);
-  } else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
-    HI.Type.emplace();
-    llvm::raw_string_ostream OS(*HI.Type);
-    VD->getType().print(OS, Policy);
-  }
-
-  // Fill in value with evaluated initializer if possible.
-  // FIXME(kadircet): Also set Value field for expressions like "sizeof" and
-  // function calls.
-  if (const auto *Var = dyn_cast<VarDecl>(D)) {
-    if (const Expr *Init = Var->getInit()) {
-      Expr::EvalResult Result;
-      if (!Init->isValueDependent() && Init->EvaluateAsRValue(Result, Ctx)) {
-        HI.Value.emplace();
-        llvm::raw_string_ostream ValueOS(*HI.Value);
-        Result.Val.printPretty(ValueOS, const_cast<ASTContext &>(Ctx),
-                               Init->getType());
-      }
-    }
-  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
-    // Dependent enums (e.g. nested in template classes) don't have values yet.
-    if (!ECD->getType()->isDependentType())
-      HI.Value = ECD->getInitVal().toString(10);
-  }
-
-  HI.Definition = printDefinition(D);
-  enhanceFromIndex(HI, D, Index);
-  return HI;
-}
-
-/// Generate a \p Hover object given the type \p T.
-static HoverInfo getHoverContents(QualType T, const Decl *D, ASTContext &ASTCtx,
-                                  const SymbolIndex *Index) {
-  HoverInfo HI;
-  llvm::raw_string_ostream OS(HI.Name);
-  PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
-  T.print(OS, Policy);
-  OS.flush();
-
-  if (D) {
-    HI.Kind = indexSymbolKindToSymbolKind(index::getSymbolInfo(D).Kind);
-    enhanceFromIndex(HI, D, Index);
-  }
-  return HI;
-}
-
-/// Generate a \p Hover object given the macro \p MacroDecl.
-static HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
-  HoverInfo HI;
-  SourceManager &SM = AST.getSourceManager();
-  HI.Name = Macro.Name;
-  HI.Kind = indexSymbolKindToSymbolKind(
-      index::getSymbolInfoForMacro(*Macro.Info).Kind);
-  // FIXME: Populate documentation
-  // FIXME: Pupulate parameters
-
-  // Try to get the full definition, not just the name
-  SourceLocation StartLoc = Macro.Info->getDefinitionLoc();
-  SourceLocation EndLoc = Macro.Info->getDefinitionEndLoc();
-  if (EndLoc.isValid()) {
-    EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, SM,
-                                        AST.getASTContext().getLangOpts());
-    bool Invalid;
-    StringRef Buffer = SM.getBufferData(SM.getFileID(StartLoc), &Invalid);
-    if (!Invalid) {
-      unsigned StartOffset = SM.getFileOffset(StartLoc);
-      unsigned EndOffset = SM.getFileOffset(EndLoc);
-      if (EndOffset <= Buffer.size() && StartOffset < EndOffset)
-        HI.Definition =
-            ("#define " + Buffer.substr(StartOffset, EndOffset - StartOffset))
-                .str();
-    }
-  }
-  return HI;
-}
-
-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<DeducedTypeVisitor> {
-  SourceLocation SearchedLocation;
-
-public:
-  DeducedTypeVisitor(SourceLocation SearchedLocation)
-      : SearchedLocation(SearchedLocation) {}
-
-  // Handle auto initializers:
-  //- auto i = 1;
-  //- decltype(auto) i = 1;
-  //- auto& i = 1;
-  //- auto* i = &a;
-  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
-    if (!D->getTypeSourceInfo() ||
-        D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
-      return true;
-
-    if (auto *AT = D->getType()->getContainedAutoType()) {
-      if (!AT->getDeducedType().isNull()) {
-        DeducedType = AT->getDeducedType();
-        this->D = D;
-      }
-    }
-    return true;
-  }
-
-  // Handle auto return types:
-  //- auto foo() {}
-  //- auto& foo() {}
-  //- auto foo() -> int {}
-  //- 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<CXXConversionDecl>(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;
-
-    const AutoType *AT = D->getReturnType()->getContainedAutoType();
-    if (AT && !AT->getDeducedType().isNull()) {
-      DeducedType = AT->getDeducedType();
-      this->D = D;
-    } else if (auto DT = dyn_cast<DecltypeType>(D->getReturnType())) {
-      // auto in a trailing return type just points to a DecltypeType and
-      // getContainedAutoType does not unwrap it.
-      if (!DT->getUnderlyingType().isNull()) {
-        DeducedType = DT->getUnderlyingType();
-        this->D = D;
-      }
-    } else if (!D->getReturnType().isNull()) {
-      DeducedType = D->getReturnType();
-      this->D = D;
-    }
-    return true;
-  }
-
-  // Handle non-auto decltype, e.g.:
-  // - auto foo() -> decltype(expr) {}
-  // - decltype(expr);
-  bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
-    if (TL.getBeginLoc() != SearchedLocation)
-      return true;
-
-    // A DecltypeType's underlying type can be another DecltypeType! E.g.
-    //  int I = 0;
-    //  decltype(I) J = I;
-    //  decltype(J) K = J;
-    const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
-    while (DT && !DT->getUnderlyingType().isNull()) {
-      DeducedType = DT->getUnderlyingType();
-      D = DT->getAsTagDecl();
-      DT = dyn_cast<DecltypeType>(DeducedType.getTypePtr());
-    }
-    return true;
-  }
-
-  QualType DeducedType;
-  const Decl *D = nullptr;
-};
-} // namespace
-
-/// Retrieves the deduced type at a given location (auto, decltype).
-/// SourceLocationBeg must point to the first character of the token
-llvm::Optional<QualType> getDeducedType(ParsedAST &AST,
-                                        SourceLocation SourceLocationBeg) {
-  Token Tok;
-  auto &ASTCtx = AST.getASTContext();
-  // Only try to find a deduced type if the token is auto or decltype.
-  if (!SourceLocationBeg.isValid() ||
-      Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
-                         ASTCtx.getLangOpts(), false) ||
-      !Tok.is(tok::raw_identifier)) {
-    return {};
-  }
-  AST.getPreprocessor().LookUpIdentifierInfo(Tok);
-  if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
-    return {};
-
-  DeducedTypeVisitor V(SourceLocationBeg);
-  V.TraverseAST(AST.getASTContext());
-  return V.DeducedType;
-}
-
-/// Retrieves the deduced type at a given location (auto, decltype).
-bool hasDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg) {
-  return (bool)getDeducedType(AST, SourceLocationBeg);
-}
-
-llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
-                                   format::FormatStyle Style,
-                                   const SymbolIndex *Index) {
-  const SourceManager &SM = AST.getSourceManager();
-  llvm::Optional<HoverInfo> HI;
-  SourceLocation SourceLocationBeg = SM.getMacroArgExpandedLocation(
-      getBeginningOfIdentifier(Pos, SM, AST.getASTContext().getLangOpts()));
-
-  if (hasDeducedType(AST, SourceLocationBeg)) {
-    DeducedTypeVisitor V(SourceLocationBeg);
-    V.TraverseAST(AST.getASTContext());
-    if (!V.DeducedType.isNull())
-      HI = getHoverContents(V.DeducedType, V.D, AST.getASTContext(), Index);
-  }
-
-  if (!HI) {
-    if (auto M = locateMacroAt(SourceLocationBeg, AST.getPreprocessor())) {
-      HI = getHoverContents(*M, AST);
-    } else {
-      DeclRelationSet Relations =
-          DeclRelation::TemplatePattern | DeclRelation::Alias;
-      auto Decls = getDeclAtPosition(AST, SourceLocationBeg, Relations);
-      if (!Decls.empty())
-        HI = getHoverContents(Decls.front(), Index);
-    }
-  }
-
-  if (!HI)
-    return llvm::None;
-
-  auto Replacements = format::reformat(
-      Style, HI->Definition, tooling::Range(0, HI->Definition.size()));
-  if (auto Formatted =
-          tooling::applyAllReplacements(HI->Definition, Replacements))
-    HI->Definition = *Formatted;
-
-  HI->SymRange =
-      getTokenRange(AST.getASTContext().getSourceManager(),
-                    AST.getASTContext().getLangOpts(), SourceLocationBeg);
-  return HI;
-}
-
 ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
                                 const SymbolIndex *Index) {
   if (!Limit)
@@ -1255,44 +756,6 @@ void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
   }
 }
 
-FormattedString HoverInfo::present() const {
-  FormattedString Output;
-  if (NamespaceScope) {
-    Output.appendText("Declared in");
-    // Drop trailing "::".
-    if (!LocalScope.empty())
-      Output.appendInlineCode(llvm::StringRef(LocalScope).drop_back(2));
-    else if (NamespaceScope->empty())
-      Output.appendInlineCode("global namespace");
-    else
-      Output.appendInlineCode(llvm::StringRef(*NamespaceScope).drop_back(2));
-  }
-
-  if (!Definition.empty()) {
-    Output.appendCodeBlock(Definition);
-  } else {
-    // Builtin types
-    Output.appendCodeBlock(Name);
-  }
-
-  if (!Documentation.empty())
-    Output.appendText(Documentation);
-  return Output;
-}
-
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
-                              const HoverInfo::Param &P) {
-  std::vector<llvm::StringRef> Output;
-  if (P.Type)
-    Output.push_back(*P.Type);
-  if (P.Name)
-    Output.push_back(*P.Name);
-  OS << llvm::join(Output, " ");
-  if (P.Default)
-    OS << " = " << *P.Default;
-  return OS;
-}
-
 llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
                                                  const FunctionDecl *FD) {
   if (!FD->hasBody())

diff  --git a/clang-tools-extra/clangd/XRefs.h b/clang-tools-extra/clangd/XRefs.h
index 8bd91024be3d..dc9e4f23f1ad 100644
--- a/clang-tools-extra/clangd/XRefs.h
+++ b/clang-tools-extra/clangd/XRefs.h
@@ -53,77 +53,6 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
                                                       Position Pos);
 
-/// Contains detailed information about a Symbol. Especially useful when
-/// generating hover responses. It can be rendered as a hover panel, or
-/// embedding clients can use the structured information to provide their own
-/// UI.
-struct HoverInfo {
-  /// Represents parameters of a function, a template or a macro.
-  /// For example:
-  /// - void foo(ParamType Name = DefaultValue)
-  /// - #define FOO(Name)
-  /// - template <ParamType Name = DefaultType> class Foo {};
-  struct Param {
-    /// The pretty-printed parameter type, e.g. "int", or "typename" (in
-    /// TemplateParameters)
-    llvm::Optional<std::string> Type;
-    /// None for unnamed parameters.
-    llvm::Optional<std::string> Name;
-    /// None if no default is provided.
-    llvm::Optional<std::string> Default;
-  };
-
-  /// For a variable named Bar, declared in clang::clangd::Foo::getFoo the
-  /// following fields will hold:
-  /// - NamespaceScope: clang::clangd::
-  /// - LocalScope: Foo::getFoo::
-  /// - Name: Bar
-
-  /// Scopes might be None in cases where they don't make sense, e.g. macros and
-  /// auto/decltype.
-  /// Contains all of the enclosing namespaces, empty string means global
-  /// namespace.
-  llvm::Optional<std::string> NamespaceScope;
-  /// Remaining named contexts in symbol's qualified name, empty string means
-  /// symbol is not local.
-  std::string LocalScope;
-  /// Name of the symbol, does not contain any "::".
-  std::string Name;
-  llvm::Optional<Range> SymRange;
-  /// Scope containing the symbol. e.g, "global namespace", "function x::Y"
-  /// - None for deduced types, e.g "auto", "decltype" keywords.
-  SymbolKind Kind;
-  std::string Documentation;
-  /// Source code containing the definition of the symbol.
-  std::string Definition;
-
-  /// Pretty-printed variable type.
-  /// Set only for variables.
-  llvm::Optional<std::string> Type;
-  /// Set for functions and lambadas.
-  llvm::Optional<std::string> ReturnType;
-  /// Set for functions, lambdas and macros with parameters.
-  llvm::Optional<std::vector<Param>> Parameters;
-  /// Set for all templates(function, class, variable).
-  llvm::Optional<std::vector<Param>> TemplateParameters;
-  /// Contains the evaluated value of the symbol if available.
-  llvm::Optional<std::string> Value;
-
-  /// Produce a user-readable information.
-  FormattedString present() const;
-};
-llvm::raw_ostream &operator<<(llvm::raw_ostream &, const HoverInfo::Param &);
-inline bool operator==(const HoverInfo::Param &LHS,
-                       const HoverInfo::Param &RHS) {
-  return std::tie(LHS.Type, LHS.Name, LHS.Default) ==
-         std::tie(RHS.Type, RHS.Name, RHS.Default);
-}
-
-/// Get the hover information when hovering at \p Pos.
-llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
-                                   format::FormatStyle Style,
-                                   const SymbolIndex *Index);
-
 struct ReferencesResult {
   std::vector<Location> References;
   bool HasMore = false;
@@ -151,16 +80,6 @@ void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
                           TypeHierarchyDirection Direction,
                           const SymbolIndex *Index);
 
-/// Retrieves the deduced type at a given location (auto, decltype).
-/// Retuns None unless SourceLocationBeg starts an auto/decltype token.
-/// It will return the underlying type.
-llvm::Optional<QualType> getDeducedType(ParsedAST &AST,
-                                        SourceLocation SourceLocationBeg);
-
-/// Check if there is a deduced type at a given location (auto, decltype).
-/// SourceLocationBeg must point to the first character of the token
-bool hasDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg);
-
 /// Returns all decls that are referenced in the \p FD except local symbols.
 llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
                                                  const FunctionDecl *FD);

diff  --git a/clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
index 02c9cdb8280f..31e79d27d06f 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
@@ -74,12 +74,11 @@ Expected<Tweak::Effect> ExpandAutoType::apply(const Selection& Inputs) {
   auto& SrcMgr = Inputs.AST.getASTContext().getSourceManager();
 
   llvm::Optional<clang::QualType> DeducedType =
-      getDeducedType(Inputs.AST, CachedLocation->getBeginLoc());
+      getDeducedType(Inputs.AST.getASTContext(), CachedLocation->getBeginLoc());
 
   // if we can't resolve the type, return an error message
-  if (DeducedType == llvm::None || DeducedType->isNull()) {
+  if (DeducedType == llvm::None)
     return createErrorMessage("Could not deduce type for 'auto' type", Inputs);
-  }
 
   // if it's a lambda expression, return an error message
   if (isa<RecordType>(*DeducedType) &&

diff  --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp
index cbd18b5bf901..b3040e2a7ed7 100644
--- a/clang-tools-extra/clangd/unittests/ASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp
@@ -7,13 +7,17 @@
 //===----------------------------------------------------------------------===//
 
 #include "AST.h"
+
+#include "Annotations.h"
+#include "TestTU.h"
+#include "clang/Basic/SourceManager.h"
 #include "gtest/gtest.h"
 
 namespace clang {
 namespace clangd {
 namespace {
 
-TEST(ExpandAutoType, ShortenNamespace) {
+TEST(ShortenNamespace, All) {
   ASSERT_EQ("TestClass", shortenNamespace("TestClass", ""));
 
   ASSERT_EQ("TestClass", shortenNamespace(
@@ -36,6 +40,30 @@ TEST(ExpandAutoType, ShortenNamespace) {
                 "testns1::TestClass<testns1::OtherClass>", "testns1"));
 }
 
+TEST(GetDeducedType, KwAutoExpansion) {
+  struct Test {
+    StringRef AnnotatedCode;
+    const char *DeducedType;
+  } Tests[] = {
+      {"^auto i = 0;", "int"},
+      {"^auto f(){ return 1;};", "int"},
+  };
+  for (Test T : Tests) {
+    Annotations File(T.AnnotatedCode);
+    auto AST = TestTU::withCode(File.code()).build();
+    ASSERT_TRUE(AST.getDiagnostics().empty())
+        << AST.getDiagnostics().begin()->Message;
+    SourceManagerForFile SM("foo.cpp", File.code());
+
+    for (Position Pos : File.points()) {
+      auto Location = sourceLocationInMainFile(SM.get(), Pos);
+      ASSERT_TRUE(!!Location) << llvm::toString(Location.takeError());
+      auto DeducedType = getDeducedType(AST.getASTContext(), *Location);
+      EXPECT_EQ(DeducedType->getAsString(), T.DeducedType);
+    }
+  }
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang

diff  --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt
index 21c29196034f..a991fe26d27a 100644
--- a/clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -48,6 +48,7 @@ add_unittest(ClangdUnitTests ClangdTests
   GlobalCompilationDatabaseTests.cpp
   HeadersTests.cpp
   HeaderSourceSwitchTests.cpp
+  HoverTests.cpp
   IndexActionTests.cpp
   IndexTests.cpp
   JSONTransportTests.cpp

diff  --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
new file mode 100644
index 000000000000..7b5907faaa2c
--- /dev/null
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -0,0 +1,1339 @@
+//===-- HoverTests.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Annotations.h"
+#include "Hover.h"
+#include "TestIndex.h"
+#include "TestTU.h"
+#include "index/MemIndex.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+TEST(Hover, Structured) {
+  struct {
+    const char *const Code;
+    const std::function<void(HoverInfo &)> ExpectedBuilder;
+  } Cases[] = {
+      // Global scope.
+      {R"cpp(
+          // Best foo ever.
+          void [[fo^o]]() {}
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "foo";
+         HI.Kind = SymbolKind::Function;
+         HI.Documentation = "Best foo ever.";
+         HI.Definition = "void foo()";
+         HI.ReturnType = "void";
+         HI.Type = "void ()";
+         HI.Parameters.emplace();
+       }},
+      // Inside namespace
+      {R"cpp(
+          namespace ns1 { namespace ns2 {
+            /// Best foo ever.
+            void [[fo^o]]() {}
+          }}
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "ns1::ns2::";
+         HI.Name = "foo";
+         HI.Kind = SymbolKind::Function;
+         HI.Documentation = "Best foo ever.";
+         HI.Definition = "void foo()";
+         HI.ReturnType = "void";
+         HI.Type = "void ()";
+         HI.Parameters.emplace();
+       }},
+      // Field
+      {R"cpp(
+          namespace ns1 { namespace ns2 {
+            struct Foo {
+              int [[b^ar]];
+            };
+          }}
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "ns1::ns2::";
+         HI.LocalScope = "Foo::";
+         HI.Name = "bar";
+         HI.Kind = SymbolKind::Field;
+         HI.Definition = "int bar";
+         HI.Type = "int";
+       }},
+      // Local to class method.
+      {R"cpp(
+          namespace ns1 { namespace ns2 {
+            struct Foo {
+              void foo() {
+                int [[b^ar]];
+              }
+            };
+          }}
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "ns1::ns2::";
+         HI.LocalScope = "Foo::foo::";
+         HI.Name = "bar";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "int bar";
+         HI.Type = "int";
+       }},
+      // Anon namespace and local scope.
+      {R"cpp(
+          namespace ns1 { namespace {
+            struct {
+              int [[b^ar]];
+            } T;
+          }}
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "ns1::(anonymous)::";
+         HI.LocalScope = "(anonymous struct)::";
+         HI.Name = "bar";
+         HI.Kind = SymbolKind::Field;
+         HI.Definition = "int bar";
+         HI.Type = "int";
+       }},
+      // Variable with template type
+      {R"cpp(
+          template <typename T, class... Ts> class Foo { public: Foo(int); };
+          Foo<int, char, bool> [[fo^o]] = Foo<int, char, bool>(5);
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "foo";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "Foo<int, char, bool> foo = Foo<int, char, bool>(5)";
+         HI.Type = "Foo<int, char, bool>";
+       }},
+      // Implicit template instantiation
+      {R"cpp(
+          template <typename T> class vector{};
+          [[vec^tor]]<int> foo;
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "vector";
+         HI.Kind = SymbolKind::Class;
+         HI.Definition = "template <typename T> class vector {}";
+         HI.TemplateParameters = {
+             {std::string("typename"), std::string("T"), llvm::None},
+         };
+       }},
+      // Class template
+      {R"cpp(
+          template <template<typename, bool...> class C,
+                    typename = char,
+                    int = 0,
+                    bool Q = false,
+                    class... Ts> class Foo {};
+          template <template<typename, bool...> class T>
+          [[F^oo]]<T> foo;
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "Foo";
+         HI.Kind = SymbolKind::Class;
+         HI.Definition =
+             R"cpp(template <template <typename, bool...> class C, typename = char, int = 0,
+          bool Q = false, class... Ts>
+class Foo {})cpp";
+         HI.TemplateParameters = {
+             {std::string("template <typename, bool...> class"),
+              std::string("C"), llvm::None},
+             {std::string("typename"), llvm::None, std::string("char")},
+             {std::string("int"), llvm::None, std::string("0")},
+             {std::string("bool"), std::string("Q"), std::string("false")},
+             {std::string("class..."), std::string("Ts"), llvm::None},
+         };
+       }},
+      // Function template
+      {R"cpp(
+          template <template<typename, bool...> class C,
+                    typename = char,
+                    int = 0,
+                    bool Q = false,
+                    class... Ts> void foo();
+          template<typename, bool...> class Foo;
+
+          void bar() {
+            [[fo^o]]<Foo>();
+          }
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "foo";
+         HI.Kind = SymbolKind::Function;
+         HI.Definition =
+             R"cpp(template <template <typename, bool...> class C, typename = char, int = 0,
+          bool Q = false, class... Ts>
+void foo())cpp";
+         HI.ReturnType = "void";
+         HI.Type = "void ()";
+         HI.Parameters.emplace();
+         HI.TemplateParameters = {
+             {std::string("template <typename, bool...> class"),
+              std::string("C"), llvm::None},
+             {std::string("typename"), llvm::None, std::string("char")},
+             {std::string("int"), llvm::None, std::string("0")},
+             {std::string("bool"), std::string("Q"), std::string("false")},
+             {std::string("class..."), std::string("Ts"), llvm::None},
+         };
+       }},
+      // Function decl
+      {R"cpp(
+          template<typename, bool...> class Foo {};
+          Foo<bool, true, false> foo(int, bool T = false);
+
+          void bar() {
+            [[fo^o]](3);
+          }
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "foo";
+         HI.Kind = SymbolKind::Function;
+         HI.Definition = "Foo<bool, true, false> foo(int, bool T = false)";
+         HI.ReturnType = "Foo<bool, true, false>";
+         HI.Type = "Foo<bool, true, false> (int, bool)";
+         HI.Parameters = {
+             {std::string("int"), llvm::None, llvm::None},
+             {std::string("bool"), std::string("T"), std::string("false")},
+         };
+       }},
+      // Pointers to lambdas
+      {R"cpp(
+        void foo() {
+          auto lamb = [](int T, bool B) -> bool { return T && B; };
+          auto *b = &lamb;
+          auto *[[^c]] = &b;
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.LocalScope = "foo::";
+         HI.Name = "c";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "auto *c = &b";
+         HI.Type = "class (lambda) **";
+         HI.ReturnType = "bool";
+         HI.Parameters = {
+             {std::string("int"), std::string("T"), llvm::None},
+             {std::string("bool"), std::string("B"), llvm::None},
+         };
+         return HI;
+       }},
+      // Lambda parameter with decltype reference
+      {R"cpp(
+        auto lamb = [](int T, bool B) -> bool { return T && B; };
+        void foo(decltype(lamb)& bar) {
+          [[ba^r]](0, false);
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.LocalScope = "foo::";
+         HI.Name = "bar";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "decltype(lamb) &bar";
+         HI.Type = "decltype(lamb) &";
+         HI.ReturnType = "bool";
+         HI.Parameters = {
+             {std::string("int"), std::string("T"), llvm::None},
+             {std::string("bool"), std::string("B"), llvm::None},
+         };
+         return HI;
+       }},
+      // Lambda parameter with decltype
+      {R"cpp(
+        auto lamb = [](int T, bool B) -> bool { return T && B; };
+        void foo(decltype(lamb) bar) {
+          [[ba^r]](0, false);
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.LocalScope = "foo::";
+         HI.Name = "bar";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "decltype(lamb) bar";
+         HI.Type = "class (lambda)";
+         HI.ReturnType = "bool";
+         HI.Parameters = {
+             {std::string("int"), std::string("T"), llvm::None},
+             {std::string("bool"), std::string("B"), llvm::None},
+         };
+         return HI;
+       }},
+      // Lambda variable
+      {R"cpp(
+        void foo() {
+          int bar = 5;
+          auto lamb = [&bar](int T, bool B) -> bool { return T && B && bar; };
+          bool res = [[lam^b]](bar, false);
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.LocalScope = "foo::";
+         HI.Name = "lamb";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "auto lamb = [&bar](int T, bool B) -> bool {}";
+         HI.Type = "class (lambda)";
+         HI.ReturnType = "bool";
+         HI.Parameters = {
+             {std::string("int"), std::string("T"), llvm::None},
+             {std::string("bool"), std::string("B"), llvm::None},
+         };
+         return HI;
+       }},
+      // Local variable in lambda
+      {R"cpp(
+        void foo() {
+          auto lamb = []{int [[te^st]];};
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.LocalScope = "foo::(anonymous class)::operator()::";
+         HI.Name = "test";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "int test";
+         HI.Type = "int";
+       }},
+      // Partially-specialized class template. (formerly type-parameter-0-0)
+      {R"cpp(
+        template <typename T> class X;
+        template <typename T> class [[^X]]<T*> {};
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "X<T *>";
+         HI.NamespaceScope = "";
+         HI.Kind = SymbolKind::Class;
+         HI.Definition = "template <typename T> class X<T *> {}";
+       }},
+      // Constructor of partially-specialized class template
+      {R"cpp(
+          template<typename, typename=void> struct X;
+          template<typename T> struct X<T*>{ [[^X]](); };
+          )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "X";
+         HI.LocalScope = "X<T *>::"; // FIXME: X<T *, void>::
+         HI.Kind = SymbolKind::Constructor;
+         HI.ReturnType = "X<T *>";
+         HI.Definition = "X()";
+         HI.Parameters.emplace();
+       }},
+      {"class X { [[^~]]X(); };", // FIXME: Should be [[~X]]()
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "~X";
+         HI.LocalScope = "X::";
+         HI.Kind = SymbolKind::Constructor;
+         HI.ReturnType = "void";
+         HI.Definition = "~X()";
+         HI.Parameters.emplace();
+       }},
+
+      // auto on lambda
+      {R"cpp(
+        void foo() {
+          [[au^to]] lamb = []{};
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "class (lambda)";
+         HI.Kind = SymbolKind::Class;
+       }},
+      // auto on template instantiation
+      {R"cpp(
+        template<typename T> class Foo{};
+        void foo() {
+          [[au^to]] x = Foo<int>();
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "class Foo<int>";
+         HI.Kind = SymbolKind::Class;
+       }},
+      // auto on specialized template
+      {R"cpp(
+        template<typename T> class Foo{};
+        template<> class Foo<int>{};
+        void foo() {
+          [[au^to]] x = Foo<int>();
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "class Foo<int>";
+         HI.Kind = SymbolKind::Class;
+       }},
+
+      // macro
+      {R"cpp(
+        // Best MACRO ever.
+        #define MACRO(x,y,z) void foo(x, y, z);
+        [[MAC^RO]](int, double d, bool z = false);
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "MACRO", HI.Kind = SymbolKind::String,
+         HI.Definition = "#define MACRO(x, y, z) void foo(x, y, z);";
+       }},
+
+      // constexprs
+      {R"cpp(
+        constexpr int add(int a, int b) { return a + b; }
+        int [[b^ar]] = add(1, 2);
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "bar";
+         HI.Definition = "int bar = add(1, 2)";
+         HI.Kind = SymbolKind::Variable;
+         HI.Type = "int";
+         HI.NamespaceScope = "";
+         HI.Value = "3";
+       }},
+      {R"cpp(
+        int [[b^ar]] = sizeof(char);
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "bar";
+         HI.Definition = "int bar = sizeof(char)";
+         HI.Kind = SymbolKind::Variable;
+         HI.Type = "int";
+         HI.NamespaceScope = "";
+         HI.Value = "1";
+       }},
+      {R"cpp(
+        template<int a, int b> struct Add {
+          static constexpr int result = a + b;
+        };
+        int [[ba^r]] = Add<1, 2>::result;
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "bar";
+         HI.Definition = "int bar = Add<1, 2>::result";
+         HI.Kind = SymbolKind::Variable;
+         HI.Type = "int";
+         HI.NamespaceScope = "";
+         HI.Value = "3";
+       }},
+      {R"cpp(
+        enum Color { RED, GREEN, };
+        Color x = [[GR^EEN]];
+       )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "GREEN";
+         HI.NamespaceScope = "";
+         HI.LocalScope = "Color::";
+         HI.Definition = "GREEN";
+         HI.Kind = SymbolKind::EnumMember;
+         HI.Type = "enum Color";
+         HI.Value = "1";
+       }},
+      // FIXME: We should use the Decl referenced, even if from an implicit
+      // instantiation. Then the scope would be Add<1, 2> and the value 3.
+      {R"cpp(
+        template<int a, int b> struct Add {
+          static constexpr int result = a + b;
+        };
+        int bar = Add<1, 2>::[[resu^lt]];
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "result";
+         HI.Definition = "static constexpr int result = a + b";
+         HI.Kind = SymbolKind::Property;
+         HI.Type = "const int";
+         HI.NamespaceScope = "";
+         HI.LocalScope = "Add<a, b>::";
+       }},
+      {R"cpp(
+        const char *[[ba^r]] = "1234";
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "bar";
+         HI.Definition = "const char *bar = \"1234\"";
+         HI.Kind = SymbolKind::Variable;
+         HI.Type = "const char *";
+         HI.NamespaceScope = "";
+         HI.Value = "&\"1234\"[0]";
+       }},
+  };
+  for (const auto &Case : Cases) {
+    SCOPED_TRACE(Case.Code);
+
+    Annotations T(Case.Code);
+    TestTU TU = TestTU::withCode(T.code());
+    TU.ExtraArgs.push_back("-std=c++17");
+    auto AST = TU.build();
+    ASSERT_TRUE(AST.getDiagnostics().empty());
+
+    auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+    ASSERT_TRUE(H);
+    HoverInfo Expected;
+    Expected.SymRange = T.range();
+    Case.ExpectedBuilder(Expected);
+
+    EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
+    EXPECT_EQ(H->LocalScope, Expected.LocalScope);
+    EXPECT_EQ(H->Name, Expected.Name);
+    EXPECT_EQ(H->Kind, Expected.Kind);
+    EXPECT_EQ(H->Documentation, Expected.Documentation);
+    EXPECT_EQ(H->Definition, Expected.Definition);
+    EXPECT_EQ(H->Type, Expected.Type);
+    EXPECT_EQ(H->ReturnType, Expected.ReturnType);
+    EXPECT_EQ(H->Parameters, Expected.Parameters);
+    EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
+    EXPECT_EQ(H->SymRange, Expected.SymRange);
+    EXPECT_EQ(H->Value, Expected.Value);
+  }
+}
+
+TEST(Hover, All) {
+  struct OneTest {
+    StringRef Input;
+    StringRef ExpectedHover;
+  };
+
+  OneTest Tests[] = {
+      {
+          R"cpp(// No hover
+            ^int main() {
+            }
+          )cpp",
+          "",
+      },
+      {
+          R"cpp(// Local variable
+            int main() {
+              int bonjour;
+              ^bonjour = 2;
+              int test1 = bonjour;
+            }
+          )cpp",
+          "text[Declared in]code[main]\n"
+          "codeblock(cpp) [\n"
+          "int bonjour\n"
+          "]",
+      },
+      {
+          R"cpp(// Local variable in method
+            struct s {
+              void method() {
+                int bonjour;
+                ^bonjour = 2;
+              }
+            };
+          )cpp",
+          "text[Declared in]code[s::method]\n"
+          "codeblock(cpp) [\n"
+          "int bonjour\n"
+          "]",
+      },
+      {
+          R"cpp(// Struct
+            namespace ns1 {
+              struct MyClass {};
+            } // namespace ns1
+            int main() {
+              ns1::My^Class* Params;
+            }
+          )cpp",
+          "text[Declared in]code[ns1]\n"
+          "codeblock(cpp) [\n"
+          "struct MyClass {}\n"
+          "]",
+      },
+      {
+          R"cpp(// Class
+            namespace ns1 {
+              class MyClass {};
+            } // namespace ns1
+            int main() {
+              ns1::My^Class* Params;
+            }
+          )cpp",
+          "text[Declared in]code[ns1]\n"
+          "codeblock(cpp) [\n"
+          "class MyClass {}\n"
+          "]",
+      },
+      {
+          R"cpp(// Union
+            namespace ns1 {
+              union MyUnion { int x; int y; };
+            } // namespace ns1
+            int main() {
+              ns1::My^Union Params;
+            }
+          )cpp",
+          "text[Declared in]code[ns1]\n"
+          "codeblock(cpp) [\n"
+          "union MyUnion {}\n"
+          "]",
+      },
+      {
+          R"cpp(// Function definition via pointer
+            int foo(int) {}
+            int main() {
+              auto *X = &^foo;
+            }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "int foo(int)\n"
+          "]\n"
+          "text[Function definition via pointer]",
+      },
+      {
+          R"cpp(// Function declaration via call
+            int foo(int);
+            int main() {
+              return ^foo(42);
+            }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "int foo(int)\n"
+          "]\n"
+          "text[Function declaration via call]",
+      },
+      {
+          R"cpp(// Field
+            struct Foo { int x; };
+            int main() {
+              Foo bar;
+              bar.^x;
+            }
+          )cpp",
+          "text[Declared in]code[Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x\n"
+          "]",
+      },
+      {
+          R"cpp(// Field with initialization
+            struct Foo { int x = 5; };
+            int main() {
+              Foo bar;
+              bar.^x;
+            }
+          )cpp",
+          "text[Declared in]code[Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x = 5\n"
+          "]",
+      },
+      {
+          R"cpp(// Static field
+            struct Foo { static int x; };
+            int main() {
+              Foo::^x;
+            }
+          )cpp",
+          "text[Declared in]code[Foo]\n"
+          "codeblock(cpp) [\n"
+          "static int x\n"
+          "]",
+      },
+      {
+          R"cpp(// Field, member initializer
+            struct Foo {
+              int x;
+              Foo() : ^x(0) {}
+            };
+          )cpp",
+          "text[Declared in]code[Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x\n"
+          "]",
+      },
+      {
+          R"cpp(// Field, GNU old-style field designator
+            struct Foo { int x; };
+            int main() {
+              Foo bar = { ^x : 1 };
+            }
+          )cpp",
+          "text[Declared in]code[Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x\n"
+          "]",
+      },
+      {
+          R"cpp(// Field, field designator
+            struct Foo { int x; };
+            int main() {
+              Foo bar = { .^x = 2 };
+            }
+          )cpp",
+          "text[Declared in]code[Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x\n"
+          "]",
+      },
+      {
+          R"cpp(// Method call
+            struct Foo { int x(); };
+            int main() {
+              Foo bar;
+              bar.^x();
+            }
+          )cpp",
+          "text[Declared in]code[Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x()\n"
+          "]",
+      },
+      {
+          R"cpp(// Static method call
+            struct Foo { static int x(); };
+            int main() {
+              Foo::^x();
+            }
+          )cpp",
+          "text[Declared in]code[Foo]\n"
+          "codeblock(cpp) [\n"
+          "static int x()\n"
+          "]",
+      },
+      {
+          R"cpp(// Typedef
+            typedef int Foo;
+            int main() {
+              ^Foo bar;
+            }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "typedef int Foo\n"
+          "]\n"
+          "text[Typedef]",
+      },
+      {
+          R"cpp(// Typedef with embedded definition
+            typedef struct Bar {} Foo;
+            int main() {
+              ^Foo bar;
+            }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "typedef struct Bar Foo\n"
+          "]\n"
+          "text[Typedef with embedded definition]",
+      },
+      {
+          R"cpp(// Namespace
+            namespace ns {
+            struct Foo { static void bar(); }
+            } // namespace ns
+            int main() { ^ns::Foo::bar(); }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "namespace ns {}\n"
+          "]",
+      },
+      {
+          R"cpp(// Anonymous namespace
+            namespace ns {
+              namespace {
+                int foo;
+              } // anonymous namespace
+            } // namespace ns
+            int main() { ns::f^oo++; }
+          )cpp",
+          "text[Declared in]code[ns::(anonymous)]\n"
+          "codeblock(cpp) [\n"
+          "int foo\n"
+          "]",
+      },
+      {
+          R"cpp(// Macro
+            #define MACRO 0
+            #define MACRO 1
+            int main() { return ^MACRO; }
+            #define MACRO 2
+            #undef macro
+          )cpp",
+          "codeblock(cpp) [\n"
+          "#define MACRO 1\n"
+          "]",
+      },
+      {
+          R"cpp(// Macro
+            #define MACRO 0
+            #define MACRO2 ^MACRO
+          )cpp",
+          "codeblock(cpp) [\n"
+          "#define MACRO 0\n"
+          "]",
+      },
+      {
+          R"cpp(// Macro
+            #define MACRO {\
+              return 0;\
+            }
+            int main() ^MACRO
+          )cpp",
+          R"cpp(codeblock(cpp) [
+#define MACRO                                                                  \
+  { return 0; }
+])cpp",
+      },
+      {
+          R"cpp(// Forward class declaration
+            class Foo;
+            class Foo {};
+            F^oo* foo();
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "class Foo {}\n"
+          "]\n"
+          "text[Forward class declaration]",
+      },
+      {
+          R"cpp(// Function declaration
+            void foo();
+            void g() { f^oo(); }
+            void foo() {}
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "void foo()\n"
+          "]\n"
+          "text[Function declaration]",
+      },
+      {
+          R"cpp(// Enum declaration
+            enum Hello {
+              ONE, TWO, THREE,
+            };
+            void foo() {
+              Hel^lo hello = ONE;
+            }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "enum Hello {}\n"
+          "]\n"
+          "text[Enum declaration]",
+      },
+      {
+          R"cpp(// Enumerator
+            enum Hello {
+              ONE, TWO, THREE,
+            };
+            void foo() {
+              Hello hello = O^NE;
+            }
+          )cpp",
+          "text[Declared in]code[Hello]\n"
+          "codeblock(cpp) [\n"
+          "ONE\n"
+          "]",
+      },
+      {
+          R"cpp(// Enumerator in anonymous enum
+            enum {
+              ONE, TWO, THREE,
+            };
+            void foo() {
+              int hello = O^NE;
+            }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "ONE\n"
+          "]",
+      },
+      {
+          R"cpp(// Global variable
+            static int hey = 10;
+            void foo() {
+              he^y++;
+            }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "static int hey = 10\n"
+          "]\n"
+          "text[Global variable]",
+      },
+      {
+          R"cpp(// Global variable in namespace
+            namespace ns1 {
+              static int hey = 10;
+            }
+            void foo() {
+              ns1::he^y++;
+            }
+          )cpp",
+          "text[Declared in]code[ns1]\n"
+          "codeblock(cpp) [\n"
+          "static int hey = 10\n"
+          "]",
+      },
+      {
+          R"cpp(// Field in anonymous struct
+            static struct {
+              int hello;
+            } s;
+            void foo() {
+              s.he^llo++;
+            }
+          )cpp",
+          "text[Declared in]code[(anonymous struct)]\n"
+          "codeblock(cpp) [\n"
+          "int hello\n"
+          "]",
+      },
+      {
+          R"cpp(// Templated function
+            template <typename T>
+            T foo() {
+              return 17;
+            }
+            void g() { auto x = f^oo<int>(); }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "template <typename T> T foo()\n"
+          "]\n"
+          "text[Templated function]",
+      },
+      {
+          R"cpp(// Anonymous union
+            struct outer {
+              union {
+                int abc, def;
+              } v;
+            };
+            void g() { struct outer o; o.v.d^ef++; }
+          )cpp",
+          "text[Declared in]code[outer::(anonymous union)]\n"
+          "codeblock(cpp) [\n"
+          "int def\n"
+          "]",
+      },
+      {
+          R"cpp(// documentation from index
+            int nextSymbolIsAForwardDeclFromIndexWithNoLocalDocs;
+            void indexSymbol();
+            void g() { ind^exSymbol(); }
+          )cpp",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "void indexSymbol()\n"
+          "]\n"
+          "text[comment from index]",
+      },
+      {
+          R"cpp(// Nothing
+            void foo() {
+              ^
+            }
+          )cpp",
+          "",
+      },
+      {
+          R"cpp(// Simple initialization with auto
+            void foo() {
+              ^auto i = 1;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// Simple initialization with const auto
+            void foo() {
+              const ^auto i = 1;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// Simple initialization with const auto&
+            void foo() {
+              const ^auto& i = 1;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// Simple initialization with auto&
+            void foo() {
+              ^auto& i = 1;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// Simple initialization with auto*
+            void foo() {
+              int a = 1;
+              ^auto* i = &a;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// Auto with initializer list.
+            namespace std
+            {
+              template<class _E>
+              class initializer_list {};
+            }
+            void foo() {
+              ^auto i = {1,2};
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "class std::initializer_list<int>\n"
+          "]",
+      },
+      {
+          R"cpp(// User defined conversion to auto
+            struct Bar {
+              operator ^auto() const { return 10; }
+            };
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// Simple initialization with decltype(auto)
+            void foo() {
+              ^decltype(auto) i = 1;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// Simple initialization with const decltype(auto)
+            void foo() {
+              const int j = 0;
+              ^decltype(auto) i = j;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "const int\n"
+          "]",
+      },
+      {
+          R"cpp(// Simple initialization with const& decltype(auto)
+            void foo() {
+              int k = 0;
+              const int& j = k;
+              ^decltype(auto) i = j;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "const int &\n"
+          "]",
+      },
+      {
+          R"cpp(// Simple initialization with & decltype(auto)
+            void foo() {
+              int k = 0;
+              int& j = k;
+              ^decltype(auto) i = j;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int &\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype with initializer list: nothing
+            namespace std
+            {
+              template<class _E>
+              class initializer_list {};
+            }
+            void foo() {
+              ^decltype(auto) i = {1,2};
+            }
+          )cpp",
+          "",
+      },
+      {
+          R"cpp(// simple trailing return type
+            ^auto main() -> int {
+              return 0;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// auto function return with trailing type
+            struct Bar {};
+            ^auto test() -> decltype(Bar()) {
+              return Bar();
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
+      },
+      {
+          R"cpp(// trailing return type
+            struct Bar {};
+            auto test() -> ^decltype(Bar()) {
+              return Bar();
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
+      },
+      {
+          R"cpp(// auto in function return
+            struct Bar {};
+            ^auto test() {
+              return Bar();
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
+      },
+      {
+          R"cpp(// auto& in function return
+            struct Bar {};
+            ^auto& test() {
+              return Bar();
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
+      },
+      {
+          R"cpp(// auto* in function return
+            struct Bar {};
+            ^auto* test() {
+              Bar* bar;
+              return bar;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
+      },
+      {
+          R"cpp(// const auto& in function return
+            struct Bar {};
+            const ^auto& test() {
+              return Bar();
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype(auto) in function return
+            struct Bar {};
+            ^decltype(auto) test() {
+              return Bar();
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype(auto) reference in function return
+            struct Bar {};
+            ^decltype(auto) test() {
+              int a;
+              return (a);
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int &\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype lvalue reference
+            void foo() {
+              int I = 0;
+              ^decltype(I) J = I;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype lvalue reference
+            void foo() {
+              int I= 0;
+              int &K = I;
+              ^decltype(K) J = I;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int &\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype lvalue reference parenthesis
+            void foo() {
+              int I = 0;
+              ^decltype((I)) J = I;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int &\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype rvalue reference
+            void foo() {
+              int I = 0;
+              ^decltype(static_cast<int&&>(I)) J = static_cast<int&&>(I);
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int &&\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype rvalue reference function call
+            int && bar();
+            void foo() {
+              int I = 0;
+              ^decltype(bar()) J = bar();
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int &&\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype of function with trailing return type.
+            struct Bar {};
+            auto test() -> decltype(Bar()) {
+              return Bar();
+            }
+            void foo() {
+              ^decltype(test()) i = test();
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
+      },
+      {
+          R"cpp(// decltype of var with decltype.
+            void foo() {
+              int I = 0;
+              decltype(I) J = I;
+              ^decltype(J) K = J;
+            }
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// structured binding. Not supported yet
+            struct Bar {};
+            void foo() {
+              Bar a[2];
+              ^auto [x,y] = a;
+            }
+          )cpp",
+          "",
+      },
+      {
+          R"cpp(// Template auto parameter. Nothing (Not useful).
+            template<^auto T>
+            void func() {
+            }
+            void foo() {
+               func<1>();
+            }
+          )cpp",
+          "",
+      },
+      {
+          R"cpp(// More compilcated structured types.
+            int bar();
+            ^auto (*foo)() = bar;
+          )cpp",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
+      },
+      {
+          R"cpp(// Should not crash when evaluating the initializer.
+            struct Test {};
+            void test() { Test && te^st = {}; }
+          )cpp",
+          "text[Declared in]code[test]\n"
+          "codeblock(cpp) [\n"
+          "struct Test &&test = {}\n"
+          "]",
+      },
+  };
+
+  // Create a tiny index, so tests above can verify documentation is fetched.
+  Symbol IndexSym = func("indexSymbol");
+  IndexSym.Documentation = "comment from index";
+  SymbolSlab::Builder Symbols;
+  Symbols.insert(IndexSym);
+  auto Index =
+      MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
+
+  for (const OneTest &Test : Tests) {
+    Annotations T(Test.Input);
+    TestTU TU = TestTU::withCode(T.code());
+    TU.ExtraArgs.push_back("-std=c++17");
+    auto AST = TU.build();
+    if (auto H =
+            getHover(AST, T.point(), format::getLLVMStyle(), Index.get())) {
+      EXPECT_NE("", Test.ExpectedHover) << Test.Input;
+      EXPECT_EQ(H->present().renderForTests(), Test.ExpectedHover.str())
+          << Test.Input;
+    } else
+      EXPECT_EQ("", Test.ExpectedHover.str()) << Test.Input;
+  }
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang

diff  --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index 483f216ca666..b6115065d1b7 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -603,1321 +603,6 @@ int [[bar_not_preamble]];
                               HeaderNotInPreambleAnnotations.range())));
 }
 
-TEST(Hover, Structured) {
-  struct {
-    const char *const Code;
-    const std::function<void(HoverInfo &)> ExpectedBuilder;
-  } Cases[] = {
-      // Global scope.
-      {R"cpp(
-          // Best foo ever.
-          void [[fo^o]]() {}
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.Name = "foo";
-         HI.Kind = SymbolKind::Function;
-         HI.Documentation = "Best foo ever.";
-         HI.Definition = "void foo()";
-         HI.ReturnType = "void";
-         HI.Type = "void ()";
-         HI.Parameters.emplace();
-       }},
-      // Inside namespace
-      {R"cpp(
-          namespace ns1 { namespace ns2 {
-            /// Best foo ever.
-            void [[fo^o]]() {}
-          }}
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "ns1::ns2::";
-         HI.Name = "foo";
-         HI.Kind = SymbolKind::Function;
-         HI.Documentation = "Best foo ever.";
-         HI.Definition = "void foo()";
-         HI.ReturnType = "void";
-         HI.Type = "void ()";
-         HI.Parameters.emplace();
-       }},
-      // Field
-      {R"cpp(
-          namespace ns1 { namespace ns2 {
-            struct Foo {
-              int [[b^ar]];
-            };
-          }}
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "ns1::ns2::";
-         HI.LocalScope = "Foo::";
-         HI.Name = "bar";
-         HI.Kind = SymbolKind::Field;
-         HI.Definition = "int bar";
-         HI.Type = "int";
-       }},
-      // Local to class method.
-      {R"cpp(
-          namespace ns1 { namespace ns2 {
-            struct Foo {
-              void foo() {
-                int [[b^ar]];
-              }
-            };
-          }}
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "ns1::ns2::";
-         HI.LocalScope = "Foo::foo::";
-         HI.Name = "bar";
-         HI.Kind = SymbolKind::Variable;
-         HI.Definition = "int bar";
-         HI.Type = "int";
-       }},
-      // Anon namespace and local scope.
-      {R"cpp(
-          namespace ns1 { namespace {
-            struct {
-              int [[b^ar]];
-            } T;
-          }}
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "ns1::(anonymous)::";
-         HI.LocalScope = "(anonymous struct)::";
-         HI.Name = "bar";
-         HI.Kind = SymbolKind::Field;
-         HI.Definition = "int bar";
-         HI.Type = "int";
-       }},
-      // Variable with template type
-      {R"cpp(
-          template <typename T, class... Ts> class Foo { public: Foo(int); };
-          Foo<int, char, bool> [[fo^o]] = Foo<int, char, bool>(5);
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.Name = "foo";
-         HI.Kind = SymbolKind::Variable;
-         HI.Definition = "Foo<int, char, bool> foo = Foo<int, char, bool>(5)";
-         HI.Type = "Foo<int, char, bool>";
-       }},
-      // Implicit template instantiation
-      {R"cpp(
-          template <typename T> class vector{};
-          [[vec^tor]]<int> foo;
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.Name = "vector";
-         HI.Kind = SymbolKind::Class;
-         HI.Definition = "template <typename T> class vector {}";
-         HI.TemplateParameters = {
-             {std::string("typename"), std::string("T"), llvm::None},
-         };
-       }},
-      // Class template
-      {R"cpp(
-          template <template<typename, bool...> class C,
-                    typename = char,
-                    int = 0,
-                    bool Q = false,
-                    class... Ts> class Foo {};
-          template <template<typename, bool...> class T>
-          [[F^oo]]<T> foo;
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.Name = "Foo";
-         HI.Kind = SymbolKind::Class;
-         HI.Definition =
-             R"cpp(template <template <typename, bool...> class C, typename = char, int = 0,
-          bool Q = false, class... Ts>
-class Foo {})cpp";
-         HI.TemplateParameters = {
-             {std::string("template <typename, bool...> class"),
-              std::string("C"), llvm::None},
-             {std::string("typename"), llvm::None, std::string("char")},
-             {std::string("int"), llvm::None, std::string("0")},
-             {std::string("bool"), std::string("Q"), std::string("false")},
-             {std::string("class..."), std::string("Ts"), llvm::None},
-         };
-       }},
-      // Function template
-      {R"cpp(
-          template <template<typename, bool...> class C,
-                    typename = char,
-                    int = 0,
-                    bool Q = false,
-                    class... Ts> void foo();
-          template<typename, bool...> class Foo;
-
-          void bar() {
-            [[fo^o]]<Foo>();
-          }
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.Name = "foo";
-         HI.Kind = SymbolKind::Function;
-         HI.Definition =
-             R"cpp(template <template <typename, bool...> class C, typename = char, int = 0,
-          bool Q = false, class... Ts>
-void foo())cpp";
-         HI.ReturnType = "void";
-         HI.Type = "void ()";
-         HI.Parameters.emplace();
-         HI.TemplateParameters = {
-             {std::string("template <typename, bool...> class"),
-              std::string("C"), llvm::None},
-             {std::string("typename"), llvm::None, std::string("char")},
-             {std::string("int"), llvm::None, std::string("0")},
-             {std::string("bool"), std::string("Q"), std::string("false")},
-             {std::string("class..."), std::string("Ts"), llvm::None},
-         };
-       }},
-      // Function decl
-      {R"cpp(
-          template<typename, bool...> class Foo {};
-          Foo<bool, true, false> foo(int, bool T = false);
-
-          void bar() {
-            [[fo^o]](3);
-          }
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.Name = "foo";
-         HI.Kind = SymbolKind::Function;
-         HI.Definition = "Foo<bool, true, false> foo(int, bool T = false)";
-         HI.ReturnType = "Foo<bool, true, false>";
-         HI.Type = "Foo<bool, true, false> (int, bool)";
-         HI.Parameters = {
-             {std::string("int"), llvm::None, llvm::None},
-             {std::string("bool"), std::string("T"), std::string("false")},
-         };
-       }},
-      // Pointers to lambdas
-      {R"cpp(
-        void foo() {
-          auto lamb = [](int T, bool B) -> bool { return T && B; };
-          auto *b = &lamb;
-          auto *[[^c]] = &b;
-        }
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.LocalScope = "foo::";
-         HI.Name = "c";
-         HI.Kind = SymbolKind::Variable;
-         HI.Definition = "auto *c = &b";
-         HI.Type = "class (lambda) **";
-         HI.ReturnType = "bool";
-         HI.Parameters = {
-             {std::string("int"), std::string("T"), llvm::None},
-             {std::string("bool"), std::string("B"), llvm::None},
-         };
-         return HI;
-       }},
-      // Lambda parameter with decltype reference
-      {R"cpp(
-        auto lamb = [](int T, bool B) -> bool { return T && B; };
-        void foo(decltype(lamb)& bar) {
-          [[ba^r]](0, false);
-        }
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.LocalScope = "foo::";
-         HI.Name = "bar";
-         HI.Kind = SymbolKind::Variable;
-         HI.Definition = "decltype(lamb) &bar";
-         HI.Type = "decltype(lamb) &";
-         HI.ReturnType = "bool";
-         HI.Parameters = {
-             {std::string("int"), std::string("T"), llvm::None},
-             {std::string("bool"), std::string("B"), llvm::None},
-         };
-         return HI;
-       }},
-      // Lambda parameter with decltype
-      {R"cpp(
-        auto lamb = [](int T, bool B) -> bool { return T && B; };
-        void foo(decltype(lamb) bar) {
-          [[ba^r]](0, false);
-        }
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.LocalScope = "foo::";
-         HI.Name = "bar";
-         HI.Kind = SymbolKind::Variable;
-         HI.Definition = "decltype(lamb) bar";
-         HI.Type = "class (lambda)";
-         HI.ReturnType = "bool";
-         HI.Parameters = {
-             {std::string("int"), std::string("T"), llvm::None},
-             {std::string("bool"), std::string("B"), llvm::None},
-         };
-         return HI;
-       }},
-      // Lambda variable
-      {R"cpp(
-        void foo() {
-          int bar = 5;
-          auto lamb = [&bar](int T, bool B) -> bool { return T && B && bar; };
-          bool res = [[lam^b]](bar, false);
-        }
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.LocalScope = "foo::";
-         HI.Name = "lamb";
-         HI.Kind = SymbolKind::Variable;
-         HI.Definition = "auto lamb = [&bar](int T, bool B) -> bool {}";
-         HI.Type = "class (lambda)";
-         HI.ReturnType = "bool";
-         HI.Parameters = {
-             {std::string("int"), std::string("T"), llvm::None},
-             {std::string("bool"), std::string("B"), llvm::None},
-         };
-         return HI;
-       }},
-      // Local variable in lambda
-      {R"cpp(
-        void foo() {
-          auto lamb = []{int [[te^st]];};
-        }
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.LocalScope = "foo::(anonymous class)::operator()::";
-         HI.Name = "test";
-         HI.Kind = SymbolKind::Variable;
-         HI.Definition = "int test";
-         HI.Type = "int";
-       }},
-      // Partially-specialized class template. (formerly type-parameter-0-0)
-      {R"cpp(
-        template <typename T> class X;
-        template <typename T> class [[^X]]<T*> {};
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "X<T *>";
-         HI.NamespaceScope = "";
-         HI.Kind = SymbolKind::Class;
-         HI.Definition = "template <typename T> class X<T *> {}";
-       }},
-      // Constructor of partially-specialized class template
-      {R"cpp(
-          template<typename, typename=void> struct X;
-          template<typename T> struct X<T*>{ [[^X]](); };
-          )cpp",
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.Name = "X";
-         HI.LocalScope = "X<T *>::"; // FIXME: X<T *, void>::
-         HI.Kind = SymbolKind::Constructor;
-         HI.ReturnType = "X<T *>";
-         HI.Definition = "X()";
-         HI.Parameters.emplace();
-       }},
-      {"class X { [[^~]]X(); };", // FIXME: Should be [[~X]]()
-       [](HoverInfo &HI) {
-         HI.NamespaceScope = "";
-         HI.Name = "~X";
-         HI.LocalScope = "X::";
-         HI.Kind = SymbolKind::Constructor;
-         HI.ReturnType = "void";
-         HI.Definition = "~X()";
-         HI.Parameters.emplace();
-       }},
-
-      // auto on lambda
-      {R"cpp(
-        void foo() {
-          [[au^to]] lamb = []{};
-        }
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "class (lambda)";
-         HI.Kind = SymbolKind::Variable;
-       }},
-      // auto on template instantiation
-      {R"cpp(
-        template<typename T> class Foo{};
-        void foo() {
-          [[au^to]] x = Foo<int>();
-        }
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "class Foo<int>";
-         HI.Kind = SymbolKind::Variable;
-       }},
-      // auto on specialized template
-      {R"cpp(
-        template<typename T> class Foo{};
-        template<> class Foo<int>{};
-        void foo() {
-          [[au^to]] x = Foo<int>();
-        }
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "class Foo<int>";
-         HI.Kind = SymbolKind::Variable;
-       }},
-
-      // macro
-      {R"cpp(
-        // Best MACRO ever.
-        #define MACRO(x,y,z) void foo(x, y, z);
-        [[MAC^RO]](int, double d, bool z = false);
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "MACRO", HI.Kind = SymbolKind::String,
-         HI.Definition = "#define MACRO(x, y, z) void foo(x, y, z);";
-       }},
-
-      // constexprs
-      {R"cpp(
-        constexpr int add(int a, int b) { return a + b; }
-        int [[b^ar]] = add(1, 2);
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "bar";
-         HI.Definition = "int bar = add(1, 2)";
-         HI.Kind = SymbolKind::Variable;
-         HI.Type = "int";
-         HI.NamespaceScope = "";
-         HI.Value = "3";
-       }},
-      {R"cpp(
-        int [[b^ar]] = sizeof(char);
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "bar";
-         HI.Definition = "int bar = sizeof(char)";
-         HI.Kind = SymbolKind::Variable;
-         HI.Type = "int";
-         HI.NamespaceScope = "";
-         HI.Value = "1";
-       }},
-      {R"cpp(
-        template<int a, int b> struct Add {
-          static constexpr int result = a + b;
-        };
-        int [[ba^r]] = Add<1, 2>::result;
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "bar";
-         HI.Definition = "int bar = Add<1, 2>::result";
-         HI.Kind = SymbolKind::Variable;
-         HI.Type = "int";
-         HI.NamespaceScope = "";
-         HI.Value = "3";
-       }},
-      {R"cpp(
-        enum Color { RED, GREEN, };
-        Color x = [[GR^EEN]];
-       )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "GREEN";
-         HI.NamespaceScope = "";
-         HI.LocalScope = "Color::";
-         HI.Definition = "GREEN";
-         HI.Kind = SymbolKind::EnumMember;
-         HI.Type = "enum Color";
-         HI.Value = "1";
-       }},
-      // FIXME: We should use the Decl referenced, even if from an implicit
-      // instantiation. Then the scope would be Add<1, 2> and the value 3.
-      {R"cpp(
-        template<int a, int b> struct Add {
-          static constexpr int result = a + b;
-        };
-        int bar = Add<1, 2>::[[resu^lt]];
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "result";
-         HI.Definition = "static constexpr int result = a + b";
-         HI.Kind = SymbolKind::Property;
-         HI.Type = "const int";
-         HI.NamespaceScope = "";
-         HI.LocalScope = "Add<a, b>::";
-       }},
-      {R"cpp(
-        const char *[[ba^r]] = "1234";
-        )cpp",
-       [](HoverInfo &HI) {
-         HI.Name = "bar";
-         HI.Definition = "const char *bar = \"1234\"";
-         HI.Kind = SymbolKind::Variable;
-         HI.Type = "const char *";
-         HI.NamespaceScope = "";
-         HI.Value = "&\"1234\"[0]";
-       }},
-  };
-  for (const auto &Case : Cases) {
-    SCOPED_TRACE(Case.Code);
-
-    Annotations T(Case.Code);
-    TestTU TU = TestTU::withCode(T.code());
-    TU.ExtraArgs.push_back("-std=c++17");
-    auto AST = TU.build();
-    ASSERT_TRUE(AST.getDiagnostics().empty());
-
-    auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
-    ASSERT_TRUE(H);
-    HoverInfo Expected;
-    Expected.SymRange = T.range();
-    Case.ExpectedBuilder(Expected);
-
-    EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
-    EXPECT_EQ(H->LocalScope, Expected.LocalScope);
-    EXPECT_EQ(H->Name, Expected.Name);
-    EXPECT_EQ(H->Kind, Expected.Kind);
-    EXPECT_EQ(H->Documentation, Expected.Documentation);
-    EXPECT_EQ(H->Definition, Expected.Definition);
-    EXPECT_EQ(H->Type, Expected.Type);
-    EXPECT_EQ(H->ReturnType, Expected.ReturnType);
-    EXPECT_EQ(H->Parameters, Expected.Parameters);
-    EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters);
-    EXPECT_EQ(H->SymRange, Expected.SymRange);
-    EXPECT_EQ(H->Value, Expected.Value);
-  }
-} // namespace clang
-
-TEST(Hover, All) {
-  struct OneTest {
-    StringRef Input;
-    StringRef ExpectedHover;
-  };
-
-  OneTest Tests[] = {
-      {
-          R"cpp(// No hover
-            ^int main() {
-            }
-          )cpp",
-          "",
-      },
-      {
-          R"cpp(// Local variable
-            int main() {
-              int bonjour;
-              ^bonjour = 2;
-              int test1 = bonjour;
-            }
-          )cpp",
-          "text[Declared in]code[main]\n"
-          "codeblock(cpp) [\n"
-          "int bonjour\n"
-          "]",
-      },
-      {
-          R"cpp(// Local variable in method
-            struct s {
-              void method() {
-                int bonjour;
-                ^bonjour = 2;
-              }
-            };
-          )cpp",
-          "text[Declared in]code[s::method]\n"
-          "codeblock(cpp) [\n"
-          "int bonjour\n"
-          "]",
-      },
-      {
-          R"cpp(// Struct
-            namespace ns1 {
-              struct MyClass {};
-            } // namespace ns1
-            int main() {
-              ns1::My^Class* Params;
-            }
-          )cpp",
-          "text[Declared in]code[ns1]\n"
-          "codeblock(cpp) [\n"
-          "struct MyClass {}\n"
-          "]",
-      },
-      {
-          R"cpp(// Class
-            namespace ns1 {
-              class MyClass {};
-            } // namespace ns1
-            int main() {
-              ns1::My^Class* Params;
-            }
-          )cpp",
-          "text[Declared in]code[ns1]\n"
-          "codeblock(cpp) [\n"
-          "class MyClass {}\n"
-          "]",
-      },
-      {
-          R"cpp(// Union
-            namespace ns1 {
-              union MyUnion { int x; int y; };
-            } // namespace ns1
-            int main() {
-              ns1::My^Union Params;
-            }
-          )cpp",
-          "text[Declared in]code[ns1]\n"
-          "codeblock(cpp) [\n"
-          "union MyUnion {}\n"
-          "]",
-      },
-      {
-          R"cpp(// Function definition via pointer
-            int foo(int) {}
-            int main() {
-              auto *X = &^foo;
-            }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "int foo(int)\n"
-          "]\n"
-          "text[Function definition via pointer]",
-      },
-      {
-          R"cpp(// Function declaration via call
-            int foo(int);
-            int main() {
-              return ^foo(42);
-            }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "int foo(int)\n"
-          "]\n"
-          "text[Function declaration via call]",
-      },
-      {
-          R"cpp(// Field
-            struct Foo { int x; };
-            int main() {
-              Foo bar;
-              bar.^x;
-            }
-          )cpp",
-          "text[Declared in]code[Foo]\n"
-          "codeblock(cpp) [\n"
-          "int x\n"
-          "]",
-      },
-      {
-          R"cpp(// Field with initialization
-            struct Foo { int x = 5; };
-            int main() {
-              Foo bar;
-              bar.^x;
-            }
-          )cpp",
-          "text[Declared in]code[Foo]\n"
-          "codeblock(cpp) [\n"
-          "int x = 5\n"
-          "]",
-      },
-      {
-          R"cpp(// Static field
-            struct Foo { static int x; };
-            int main() {
-              Foo::^x;
-            }
-          )cpp",
-          "text[Declared in]code[Foo]\n"
-          "codeblock(cpp) [\n"
-          "static int x\n"
-          "]",
-      },
-      {
-          R"cpp(// Field, member initializer
-            struct Foo {
-              int x;
-              Foo() : ^x(0) {}
-            };
-          )cpp",
-          "text[Declared in]code[Foo]\n"
-          "codeblock(cpp) [\n"
-          "int x\n"
-          "]",
-      },
-      {
-          R"cpp(// Field, GNU old-style field designator
-            struct Foo { int x; };
-            int main() {
-              Foo bar = { ^x : 1 };
-            }
-          )cpp",
-          "text[Declared in]code[Foo]\n"
-          "codeblock(cpp) [\n"
-          "int x\n"
-          "]",
-      },
-      {
-          R"cpp(// Field, field designator
-            struct Foo { int x; };
-            int main() {
-              Foo bar = { .^x = 2 };
-            }
-          )cpp",
-          "text[Declared in]code[Foo]\n"
-          "codeblock(cpp) [\n"
-          "int x\n"
-          "]",
-      },
-      {
-          R"cpp(// Method call
-            struct Foo { int x(); };
-            int main() {
-              Foo bar;
-              bar.^x();
-            }
-          )cpp",
-          "text[Declared in]code[Foo]\n"
-          "codeblock(cpp) [\n"
-          "int x()\n"
-          "]",
-      },
-      {
-          R"cpp(// Static method call
-            struct Foo { static int x(); };
-            int main() {
-              Foo::^x();
-            }
-          )cpp",
-          "text[Declared in]code[Foo]\n"
-          "codeblock(cpp) [\n"
-          "static int x()\n"
-          "]",
-      },
-      {
-          R"cpp(// Typedef
-            typedef int Foo;
-            int main() {
-              ^Foo bar;
-            }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "typedef int Foo\n"
-          "]\n"
-          "text[Typedef]",
-      },
-      {
-          R"cpp(// Typedef with embedded definition
-            typedef struct Bar {} Foo;
-            int main() {
-              ^Foo bar;
-            }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "typedef struct Bar Foo\n"
-          "]\n"
-          "text[Typedef with embedded definition]",
-      },
-      {
-          R"cpp(// Namespace
-            namespace ns {
-            struct Foo { static void bar(); }
-            } // namespace ns
-            int main() { ^ns::Foo::bar(); }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "namespace ns {}\n"
-          "]",
-      },
-      {
-          R"cpp(// Anonymous namespace
-            namespace ns {
-              namespace {
-                int foo;
-              } // anonymous namespace
-            } // namespace ns
-            int main() { ns::f^oo++; }
-          )cpp",
-          "text[Declared in]code[ns::(anonymous)]\n"
-          "codeblock(cpp) [\n"
-          "int foo\n"
-          "]",
-      },
-      {
-          R"cpp(// Macro
-            #define MACRO 0
-            #define MACRO 1
-            int main() { return ^MACRO; }
-            #define MACRO 2
-            #undef macro
-          )cpp",
-          "codeblock(cpp) [\n"
-          "#define MACRO 1\n"
-          "]",
-      },
-      {
-          R"cpp(// Macro
-            #define MACRO 0
-            #define MACRO2 ^MACRO
-          )cpp",
-          "codeblock(cpp) [\n"
-          "#define MACRO 0\n"
-          "]",
-      },
-      {
-          R"cpp(// Macro
-            #define MACRO {\
-              return 0;\
-            }
-            int main() ^MACRO
-          )cpp",
-          R"cpp(codeblock(cpp) [
-#define MACRO                                                                  \
-  { return 0; }
-])cpp",
-      },
-      {
-          R"cpp(// Forward class declaration
-            class Foo;
-            class Foo {};
-            F^oo* foo();
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "class Foo {}\n"
-          "]\n"
-          "text[Forward class declaration]",
-      },
-      {
-          R"cpp(// Function declaration
-            void foo();
-            void g() { f^oo(); }
-            void foo() {}
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "void foo()\n"
-          "]\n"
-          "text[Function declaration]",
-      },
-      {
-          R"cpp(// Enum declaration
-            enum Hello {
-              ONE, TWO, THREE,
-            };
-            void foo() {
-              Hel^lo hello = ONE;
-            }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "enum Hello {}\n"
-          "]\n"
-          "text[Enum declaration]",
-      },
-      {
-          R"cpp(// Enumerator
-            enum Hello {
-              ONE, TWO, THREE,
-            };
-            void foo() {
-              Hello hello = O^NE;
-            }
-          )cpp",
-          "text[Declared in]code[Hello]\n"
-          "codeblock(cpp) [\n"
-          "ONE\n"
-          "]",
-      },
-      {
-          R"cpp(// Enumerator in anonymous enum
-            enum {
-              ONE, TWO, THREE,
-            };
-            void foo() {
-              int hello = O^NE;
-            }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "ONE\n"
-          "]",
-      },
-      {
-          R"cpp(// Global variable
-            static int hey = 10;
-            void foo() {
-              he^y++;
-            }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "static int hey = 10\n"
-          "]\n"
-          "text[Global variable]",
-      },
-      {
-          R"cpp(// Global variable in namespace
-            namespace ns1 {
-              static int hey = 10;
-            }
-            void foo() {
-              ns1::he^y++;
-            }
-          )cpp",
-          "text[Declared in]code[ns1]\n"
-          "codeblock(cpp) [\n"
-          "static int hey = 10\n"
-          "]",
-      },
-      {
-          R"cpp(// Field in anonymous struct
-            static struct {
-              int hello;
-            } s;
-            void foo() {
-              s.he^llo++;
-            }
-          )cpp",
-          "text[Declared in]code[(anonymous struct)]\n"
-          "codeblock(cpp) [\n"
-          "int hello\n"
-          "]",
-      },
-      {
-          R"cpp(// Templated function
-            template <typename T>
-            T foo() {
-              return 17;
-            }
-            void g() { auto x = f^oo<int>(); }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "template <typename T> T foo()\n"
-          "]\n"
-          "text[Templated function]",
-      },
-      {
-          R"cpp(// Anonymous union
-            struct outer {
-              union {
-                int abc, def;
-              } v;
-            };
-            void g() { struct outer o; o.v.d^ef++; }
-          )cpp",
-          "text[Declared in]code[outer::(anonymous union)]\n"
-          "codeblock(cpp) [\n"
-          "int def\n"
-          "]",
-      },
-      {
-          R"cpp(// documentation from index
-            int nextSymbolIsAForwardDeclFromIndexWithNoLocalDocs;
-            void indexSymbol();
-            void g() { ind^exSymbol(); }
-          )cpp",
-          "text[Declared in]code[global namespace]\n"
-          "codeblock(cpp) [\n"
-          "void indexSymbol()\n"
-          "]\n"
-          "text[comment from index]",
-      },
-      {
-          R"cpp(// Nothing
-            void foo() {
-              ^
-            }
-          )cpp",
-          "",
-      },
-      {
-          R"cpp(// Simple initialization with auto
-            void foo() {
-              ^auto i = 1;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// Simple initialization with const auto
-            void foo() {
-              const ^auto i = 1;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// Simple initialization with const auto&
-            void foo() {
-              const ^auto& i = 1;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// Simple initialization with auto&
-            void foo() {
-              ^auto& i = 1;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// Simple initialization with auto*
-            void foo() {
-              int a = 1;
-              ^auto* i = &a;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// Auto with initializer list.
-            namespace std
-            {
-              template<class _E>
-              class initializer_list {};
-            }
-            void foo() {
-              ^auto i = {1,2};
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "class std::initializer_list<int>\n"
-          "]",
-      },
-      {
-          R"cpp(// User defined conversion to auto
-            struct Bar {
-              operator ^auto() const { return 10; }
-            };
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// Simple initialization with decltype(auto)
-            void foo() {
-              ^decltype(auto) i = 1;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// Simple initialization with const decltype(auto)
-            void foo() {
-              const int j = 0;
-              ^decltype(auto) i = j;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "const int\n"
-          "]",
-      },
-      {
-          R"cpp(// Simple initialization with const& decltype(auto)
-            void foo() {
-              int k = 0;
-              const int& j = k;
-              ^decltype(auto) i = j;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "const int &\n"
-          "]",
-      },
-      {
-          R"cpp(// Simple initialization with & decltype(auto)
-            void foo() {
-              int k = 0;
-              int& j = k;
-              ^decltype(auto) i = j;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int &\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype with initializer list: nothing
-            namespace std
-            {
-              template<class _E>
-              class initializer_list {};
-            }
-            void foo() {
-              ^decltype(auto) i = {1,2};
-            }
-          )cpp",
-          "",
-      },
-      {
-          R"cpp(// simple trailing return type
-            ^auto main() -> int {
-              return 0;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// auto function return with trailing type
-            struct Bar {};
-            ^auto test() -> decltype(Bar()) {
-              return Bar();
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "struct Bar\n"
-          "]",
-      },
-      {
-          R"cpp(// trailing return type
-            struct Bar {};
-            auto test() -> ^decltype(Bar()) {
-              return Bar();
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "struct Bar\n"
-          "]",
-      },
-      {
-          R"cpp(// auto in function return
-            struct Bar {};
-            ^auto test() {
-              return Bar();
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "struct Bar\n"
-          "]",
-      },
-      {
-          R"cpp(// auto& in function return
-            struct Bar {};
-            ^auto& test() {
-              return Bar();
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "struct Bar\n"
-          "]",
-      },
-      {
-          R"cpp(// auto* in function return
-            struct Bar {};
-            ^auto* test() {
-              Bar* bar;
-              return bar;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "struct Bar\n"
-          "]",
-      },
-      {
-          R"cpp(// const auto& in function return
-            struct Bar {};
-            const ^auto& test() {
-              return Bar();
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "struct Bar\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype(auto) in function return
-            struct Bar {};
-            ^decltype(auto) test() {
-              return Bar();
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "struct Bar\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype(auto) reference in function return
-            struct Bar {};
-            ^decltype(auto) test() {
-              int a;
-              return (a);
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int &\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype lvalue reference
-            void foo() {
-              int I = 0;
-              ^decltype(I) J = I;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype lvalue reference
-            void foo() {
-              int I= 0;
-              int &K = I;
-              ^decltype(K) J = I;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int &\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype lvalue reference parenthesis
-            void foo() {
-              int I = 0;
-              ^decltype((I)) J = I;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int &\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype rvalue reference
-            void foo() {
-              int I = 0;
-              ^decltype(static_cast<int&&>(I)) J = static_cast<int&&>(I);
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int &&\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype rvalue reference function call
-            int && bar();
-            void foo() {
-              int I = 0;
-              ^decltype(bar()) J = bar();
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int &&\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype of function with trailing return type.
-            struct Bar {};
-            auto test() -> decltype(Bar()) {
-              return Bar();
-            }
-            void foo() {
-              ^decltype(test()) i = test();
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "struct Bar\n"
-          "]",
-      },
-      {
-          R"cpp(// decltype of var with decltype.
-            void foo() {
-              int I = 0;
-              decltype(I) J = I;
-              ^decltype(J) K = J;
-            }
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// structured binding. Not supported yet
-            struct Bar {};
-            void foo() {
-              Bar a[2];
-              ^auto [x,y] = a;
-            }
-          )cpp",
-          "",
-      },
-      {
-          R"cpp(// Template auto parameter. Nothing (Not useful).
-            template<^auto T>
-            void func() {
-            }
-            void foo() {
-               func<1>();
-            }
-          )cpp",
-          "",
-      },
-      {
-          R"cpp(// More compilcated structured types.
-            int bar();
-            ^auto (*foo)() = bar;
-          )cpp",
-          "codeblock(cpp) [\n"
-          "int\n"
-          "]",
-      },
-      {
-          R"cpp(// Should not crash when evaluating the initializer.
-            struct Test {};
-            void test() { Test && te^st = {}; }
-          )cpp",
-          "text[Declared in]code[test]\n"
-          "codeblock(cpp) [\n"
-          "struct Test &&test = {}\n"
-          "]",
-      },
-  };
-
-  // Create a tiny index, so tests above can verify documentation is fetched.
-  Symbol IndexSym = func("indexSymbol");
-  IndexSym.Documentation = "comment from index";
-  SymbolSlab::Builder Symbols;
-  Symbols.insert(IndexSym);
-  auto Index =
-      MemIndex::build(std::move(Symbols).build(), RefSlab(), RelationSlab());
-
-  for (const OneTest &Test : Tests) {
-    Annotations T(Test.Input);
-    TestTU TU = TestTU::withCode(T.code());
-    TU.ExtraArgs.push_back("-std=c++17");
-    auto AST = TU.build();
-    if (auto H =
-            getHover(AST, T.point(), format::getLLVMStyle(), Index.get())) {
-      EXPECT_NE("", Test.ExpectedHover) << Test.Input;
-      EXPECT_EQ(H->present().renderForTests(), Test.ExpectedHover.str())
-          << Test.Input;
-    } else
-      EXPECT_EQ("", Test.ExpectedHover.str()) << Test.Input;
-  }
-}
-
 TEST(GoToInclude, All) {
   MockFSProvider FS;
   IgnoreDiagnostics DiagConsumer;
@@ -2256,30 +941,6 @@ TEST(FindReferences, NoQueryForLocalSymbols) {
   }
 }
 
-TEST(GetDeducedType, KwAutoExpansion) {
-  struct Test {
-    StringRef AnnotatedCode;
-    const char *DeducedType;
-  } Tests[] = {
-      {"^auto i = 0;", "int"},
-      {"^auto f(){ return 1;};", "int"},
-  };
-  for (Test T : Tests) {
-    Annotations File(T.AnnotatedCode);
-    auto AST = TestTU::withCode(File.code()).build();
-    ASSERT_TRUE(AST.getDiagnostics().empty())
-        << AST.getDiagnostics().begin()->Message;
-    SourceManagerForFile SM("foo.cpp", File.code());
-
-    for (Position Pos : File.points()) {
-      auto Location = sourceLocationInMainFile(SM.get(), Pos);
-      ASSERT_TRUE(!!Location) << llvm::toString(Location.takeError());
-      auto DeducedType = getDeducedType(AST, *Location);
-      EXPECT_EQ(DeducedType->getAsString(), T.DeducedType);
-    }
-  }
-}
-
 TEST(GetNonLocalDeclRefs, All) {
   struct Case {
     llvm::StringRef AnnotatedCode;


        


More information about the cfe-commits mailing list