[clang-tools-extra] r365792 - [clangd] Implementation of auto type expansion.

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 11 09:04:18 PDT 2019


Author: sammccall
Date: Thu Jul 11 09:04:18 2019
New Revision: 365792

URL: http://llvm.org/viewvc/llvm-project?rev=365792&view=rev
Log:
[clangd] Implementation of auto type expansion.

Add a tweak for clangd to replace an auto keyword to the deduced type.

This way a user can declare something with auto and then have the
IDE/clangd replace auto with whatever type clangd thinks it is. In case
of long/complext types this makes is reduces writing effort for the
user.

The functionality is similar to the hover over the auto keyword.

Example (from the header):

```
/// Before:
///    auto x = Something();
///    ^^^^
/// After:
///    MyClass x = Something();
///    ^^^^^^^
```

Patch by kuhnel! (Christian Kühnel)
Differential Revision: https://reviews.llvm.org/D62855

Added:
    clang-tools-extra/trunk/clangd/refactor/tweaks/ExpandAutoType.cpp
    clang-tools-extra/trunk/clangd/test/code-action-request.test
    clang-tools-extra/trunk/clangd/unittests/ASTTests.cpp
Modified:
    clang-tools-extra/trunk/clangd/AST.cpp
    clang-tools-extra/trunk/clangd/AST.h
    clang-tools-extra/trunk/clangd/Selection.cpp
    clang-tools-extra/trunk/clangd/Selection.h
    clang-tools-extra/trunk/clangd/XRefs.cpp
    clang-tools-extra/trunk/clangd/XRefs.h
    clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt
    clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt
    clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp
    clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp

Modified: clang-tools-extra/trunk/clangd/AST.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/AST.cpp?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/AST.cpp (original)
+++ clang-tools-extra/trunk/clangd/AST.cpp Thu Jul 11 09:04:18 2019
@@ -169,5 +169,35 @@ llvm::Optional<SymbolID> getSymbolID(con
   return SymbolID(USR);
 }
 
+std::string shortenNamespace(const llvm::StringRef OriginalName,
+                             const llvm::StringRef CurrentNamespace) {
+  llvm::SmallVector<llvm::StringRef, 8> OriginalParts;
+  llvm::SmallVector<llvm::StringRef, 8> CurrentParts;
+  llvm::SmallVector<llvm::StringRef, 8> Result;
+  OriginalName.split(OriginalParts, "::");
+  CurrentNamespace.split(CurrentParts, "::");
+  auto MinLength = std::min(CurrentParts.size(), OriginalParts.size());
+
+  unsigned DifferentAt = 0;
+  while (DifferentAt < MinLength &&
+      CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) {
+    DifferentAt++;
+  }
+
+  for (u_int i = DifferentAt; i < OriginalParts.size(); ++i) {
+    Result.push_back(OriginalParts[i]);
+  }
+  return join(Result, "::");
+}
+
+std::string printType(const QualType QT, const DeclContext & Context){
+  PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy());
+  PP.SuppressTagKeyword = 1;
+  return shortenNamespace(
+      QT.getAsString(PP),
+      printNamespaceScope(Context) );
+}
+
+
 } // namespace clangd
 } // namespace clang

Modified: clang-tools-extra/trunk/clangd/AST.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/AST.h?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/AST.h (original)
+++ clang-tools-extra/trunk/clangd/AST.h Thu Jul 11 09:04:18 2019
@@ -67,6 +67,22 @@ llvm::Optional<SymbolID> getSymbolID(con
                                      const MacroInfo *MI,
                                      const SourceManager &SM);
 
+/// Returns a QualType as string.
+std::string printType(const QualType QT, const DeclContext & Context);
+
+/// Try to shorten the OriginalName by removing namespaces from the left of
+/// the string that are redundant in the CurrentNamespace. This way the type
+/// idenfier become shorter and easier to read.
+/// Limitation: It only handles the qualifier of the type itself, not that of
+/// templates.
+/// FIXME: change type of parameter CurrentNamespace to DeclContext ,
+/// take in to account using directives etc
+/// Example: shortenNamespace("ns1::MyClass<ns1::OtherClass>", "ns1")
+///    --> "MyClass<ns1::OtherClass>"
+std::string  shortenNamespace(const llvm::StringRef OriginalName,
+                              const llvm::StringRef CurrentNamespace);
+
+
 } // namespace clangd
 } // namespace clang
 

Modified: clang-tools-extra/trunk/clangd/Selection.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Selection.cpp?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Selection.cpp (original)
+++ clang-tools-extra/trunk/clangd/Selection.cpp Thu Jul 11 09:04:18 2019
@@ -364,5 +364,18 @@ const Node *SelectionTree::commonAncesto
   return Ancestor;
 }
 
+const DeclContext& SelectionTree::Node::getDeclContext() const {
+  for (const Node* CurrentNode = this; CurrentNode != nullptr;
+       CurrentNode = CurrentNode->Parent) {
+    if (const Decl* Current = CurrentNode->ASTNode.get<Decl>()) {
+      if (CurrentNode != this)
+        if (auto *DC = dyn_cast<DeclContext>(Current))
+          return *DC;
+      return *Current->getDeclContext();
+    }
+  }
+  llvm_unreachable("A tree must always be rooted at TranslationUnitDecl.");
+}
+
 } // namespace clangd
 } // namespace clang

Modified: clang-tools-extra/trunk/clangd/Selection.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Selection.h?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Selection.h (original)
+++ clang-tools-extra/trunk/clangd/Selection.h Thu Jul 11 09:04:18 2019
@@ -93,6 +93,9 @@ public:
     ast_type_traits::DynTypedNode ASTNode;
     // The extent to which this node is covered by the selection.
     Selection Selected;
+    // Walk up the AST to get the DeclContext of this Node,
+    // which is not the node itself.
+    const DeclContext& getDeclContext() const;
   };
 
   // The most specific common ancestor of all the selected nodes.

Modified: clang-tools-extra/trunk/clangd/XRefs.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/XRefs.cpp?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/XRefs.cpp (original)
+++ clang-tools-extra/trunk/clangd/XRefs.cpp Thu Jul 11 09:04:18 2019
@@ -870,7 +870,9 @@ public:
 } // namespace
 
 /// Retrieves the deduced type at a given location (auto, decltype).
-bool hasDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg) {
+/// 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.
@@ -878,12 +880,20 @@ bool hasDeducedType(ParsedAST &AST, Sour
       Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
                          ASTCtx.getLangOpts(), false) ||
       !Tok.is(tok::raw_identifier)) {
-    return false;
+    return {};
   }
   AST.getPreprocessor().LookUpIdentifierInfo(Tok);
   if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
-    return false;
-  return true;
+    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,

Modified: clang-tools-extra/trunk/clangd/XRefs.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/XRefs.h?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/XRefs.h (original)
+++ clang-tools-extra/trunk/clangd/XRefs.h Thu Jul 11 09:04:18 2019
@@ -141,6 +141,16 @@ llvm::Optional<TypeHierarchyItem> getTyp
     ParsedAST &AST, Position Pos, int Resolve, TypeHierarchyDirection Direction,
     const SymbolIndex *Index = nullptr, PathRef TUPath = PathRef{});
 
+/// 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);
+
 } // namespace clangd
 } // namespace clang
 

Modified: clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt Thu Jul 11 09:04:18 2019
@@ -18,6 +18,7 @@ add_clang_library(clangDaemonTweaks OBJE
   RawStringLiteral.cpp
   SwapIfBranches.cpp
   ExtractVariable.cpp
+  ExpandAutoType.cpp
 
   LINK_LIBS
   clangAST

Added: clang-tools-extra/trunk/clangd/refactor/tweaks/ExpandAutoType.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/tweaks/ExpandAutoType.cpp?rev=365792&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/tweaks/ExpandAutoType.cpp (added)
+++ clang-tools-extra/trunk/clangd/refactor/tweaks/ExpandAutoType.cpp Thu Jul 11 09:04:18 2019
@@ -0,0 +1,119 @@
+//===--- ReplaceAutoType.cpp -------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+#include "refactor/Tweak.h"
+
+#include "Logger.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include <climits>
+#include <memory>
+#include <string>
+#include <AST.h>
+#include "XRefs.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace clang {
+namespace clangd {
+
+/// Expand the "auto" type to the derived type
+/// Before:
+///    auto x = Something();
+///    ^^^^
+/// After:
+///    MyClass x = Something();
+///    ^^^^^^^
+/// FIXME: Handle decltype as well
+class ExpandAutoType : public Tweak {
+public:
+  const char *id() const final;
+  Intent intent() const override { return Intent::Refactor;}
+  bool prepare(const Selection &Inputs) override;
+  Expected<Effect> apply(const Selection &Inputs) override;
+  std::string title() const override;
+
+private:
+  /// Cache the AutoTypeLoc, so that we do not need to search twice.
+  llvm::Optional<clang::AutoTypeLoc> CachedLocation;
+
+  /// Create an error message with filename and line number in it
+  llvm::Error createErrorMessage(const std::string& Message,
+                                 const Selection &Inputs);
+
+};
+
+REGISTER_TWEAK(ExpandAutoType)
+
+std::string ExpandAutoType::title() const { return "expand auto type"; }
+
+bool ExpandAutoType::prepare(const Selection& Inputs) {
+  CachedLocation = llvm::None;
+  if (auto *Node = Inputs.ASTSelection.commonAncestor()) {
+    if (auto *TypeNode = Node->ASTNode.get<TypeLoc>()) {
+      if (const AutoTypeLoc Result = TypeNode->getAs<AutoTypeLoc>()) {
+        CachedLocation = Result;
+      }
+    }
+  }
+  return (bool) CachedLocation;
+}
+
+Expected<Tweak::Effect> ExpandAutoType::apply(const Selection& Inputs) {
+  auto& SrcMgr = Inputs.AST.getASTContext().getSourceManager();
+
+  llvm::Optional<clang::QualType> DeducedType =
+      getDeducedType(Inputs.AST, CachedLocation->getBeginLoc());
+
+  // if we can't resolve the type, return an error message
+  if (DeducedType == llvm::None || DeducedType->isNull()) {
+    return createErrorMessage("Could not deduce type for 'auto' type", Inputs);
+  }
+
+  // if it's a lambda expression, return an error message
+  if (isa<RecordType>(*DeducedType) and
+      dyn_cast<RecordType>(*DeducedType)->getDecl()->isLambda()) {
+    return createErrorMessage("Could not expand type of lambda expression",
+                              Inputs);
+  }
+
+  // if it's a function expression, return an error message
+  // naively replacing 'auto' with the type will break declarations.
+  // FIXME: there are other types that have similar problems
+  if (DeducedType->getTypePtr()->isFunctionPointerType()) {
+    return createErrorMessage("Could not expand type of function pointer",
+                              Inputs);
+  }
+
+  std::string PrettyTypeName = printType(*DeducedType,
+      Inputs.ASTSelection.commonAncestor()->getDeclContext());
+
+  tooling::Replacement
+      Expansion(SrcMgr, CharSourceRange(CachedLocation->getSourceRange(), true),
+                PrettyTypeName);
+
+  return Tweak::Effect::applyEdit(tooling::Replacements(Expansion));
+}
+
+llvm::Error ExpandAutoType::createErrorMessage(const std::string& Message,
+                                               const Selection& Inputs) {
+  auto& SrcMgr = Inputs.AST.getASTContext().getSourceManager();
+  std::string ErrorMessage =
+      Message + ": " +
+          SrcMgr.getFilename(Inputs.Cursor).str() + " Line " +
+          std::to_string(SrcMgr.getExpansionLineNumber(Inputs.Cursor));
+
+  return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                 ErrorMessage.c_str());
+}
+
+} // namespace clangd
+} // namespace clang

Added: clang-tools-extra/trunk/clangd/test/code-action-request.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/test/code-action-request.test?rev=365792&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/test/code-action-request.test (added)
+++ clang-tools-extra/trunk/clangd/test/code-action-request.test Thu Jul 11 09:04:18 2019
@@ -0,0 +1,70 @@
+# RUN: clangd -log=verbose -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"auto i = 0;"}}}
+---
+{
+	"jsonrpc": "2.0",
+	"id": 1,
+	"method": "textDocument/codeAction",
+	"params": {
+		"textDocument": {
+			"uri": "test:///main.cpp"
+		},
+        "range": {
+            "start": {
+                "line": 0,
+                "character": 0
+            },
+            "end": {
+                "line": 0,
+                "character": 4
+            }
+        },
+        "context": {
+            "diagnostics": []
+        }
+    }
+}
+#      CHECK:  "id": 1,
+# CHECK-NEXT:  "jsonrpc": "2.0",
+# CHECK-NEXT:  "result": [
+# CHECK-NEXT:    {
+# CHECK-NEXT:      "arguments": [
+# CHECK-NEXT:        {
+# CHECK-NEXT:          "file": "file:///clangd-test/main.cpp",
+# CHECK-NEXT:          "selection": {
+# CHECK-NEXT:            "end": {
+# CHECK-NEXT:              "character": 4,
+# CHECK-NEXT:              "line": 0
+# CHECK-NEXT:            },
+# CHECK-NEXT:            "start": {
+# CHECK-NEXT:              "character": 0,
+# CHECK-NEXT:              "line": 0
+# CHECK-NEXT:            }
+# CHECK-NEXT:          },
+# CHECK-NEXT:          "tweakID": "ExpandAutoType"
+# CHECK-NEXT:        }
+# CHECK-NEXT:      ],
+# CHECK-NEXT:      "command": "clangd.applyTweak",
+# CHECK-NEXT:      "title": "expand auto type"
+# CHECK-NEXT:    }
+# CHECK-NEXT:  ]
+---
+{"jsonrpc":"2.0","id":4,"method":"workspace/executeCommand","params":{"command":"clangd.applyTweak","arguments":[{"file":"file:///clangd-test/main.cpp","selection":{"end":{"character":4,"line":0},"start":{"character":0,"line":0}},"tweakID":"ExpandAutoType"}]}}
+#      CHECK:    "newText": "int",
+# CHECK-NEXT:    "range": {
+# CHECK-NEXT:      "end": {
+# CHECK-NEXT:        "character": 4,
+# CHECK-NEXT:        "line": 0
+# CHECK-NEXT:      },
+# CHECK-NEXT:      "start": {
+# CHECK-NEXT:        "character": 0,
+# CHECK-NEXT:        "line": 0
+# CHECK-NEXT:      }
+# CHECK-NEXT:    }
+---
+{"jsonrpc":"2.0","id":4,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
+---
\ No newline at end of file

Added: clang-tools-extra/trunk/clangd/unittests/ASTTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/ASTTests.cpp?rev=365792&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/ASTTests.cpp (added)
+++ clang-tools-extra/trunk/clangd/unittests/ASTTests.cpp Thu Jul 11 09:04:18 2019
@@ -0,0 +1,42 @@
+//===-- ASTTests.cpp --------------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "AST.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+TEST(ExpandAutoType, ShortenNamespace) {
+  ASSERT_EQ("TestClass", shortenNamespace("TestClass", ""));
+
+  ASSERT_EQ("TestClass", shortenNamespace(
+      "testnamespace::TestClass", "testnamespace"));
+
+  ASSERT_EQ(
+      "namespace1::TestClass",
+      shortenNamespace("namespace1::TestClass", "namespace2"));
+
+  ASSERT_EQ("TestClass",
+            shortenNamespace("testns1::testns2::TestClass",
+                             "testns1::testns2"));
+
+  ASSERT_EQ(
+      "testns2::TestClass",
+      shortenNamespace("testns1::testns2::TestClass", "testns1"));
+
+  ASSERT_EQ("TestClass<testns1::OtherClass>",
+            shortenNamespace(
+                "testns1::TestClass<testns1::OtherClass>", "testns1"));
+}
+
+
+} // namespace
+} // namespace clangd
+} // namespace clang

Modified: clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/unittests/CMakeLists.txt Thu Jul 11 09:04:18 2019
@@ -23,6 +23,7 @@ endif()
 add_custom_target(ClangdUnitTests)
 add_unittest(ClangdUnitTests ClangdTests
   Annotations.cpp
+  ASTTests.cpp
   BackgroundIndexTests.cpp
   CancellationTests.cpp
   CanonicalIncludesTests.cpp

Modified: clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp Thu Jul 11 09:04:18 2019
@@ -11,6 +11,7 @@
 #include "TestTU.h"
 #include "refactor/Tweak.h"
 #include "clang/AST/Expr.h"
+#include "clang/Basic/LLVM.h"
 #include "clang/Rewrite/Core/Rewriter.h"
 #include "clang/Tooling/Core/Replacement.h"
 #include "llvm/ADT/StringRef.h"
@@ -126,6 +127,19 @@ void checkTransform(llvm::StringRef ID,
   EXPECT_EQ(Output, std::string(*Result)) << Input;
 }
 
+/// Check if apply returns an error and that the @ErrorMessage is contained
+/// in that error
+void checkApplyContainsError(llvm::StringRef ID, llvm::StringRef Input,
+                             const std::string& ErrorMessage) {
+  auto Result = apply(ID, Input);
+  ASSERT_FALSE(Result) << "expected error message:\n   " << ErrorMessage <<
+                       "\non input:" << Input;
+  EXPECT_NE(std::string::npos,
+            llvm::toString(Result.takeError()).find(ErrorMessage))
+            << "Wrong error message:\n  " << llvm::toString(Result.takeError())
+            << "\nexpected:\n  " << ErrorMessage;
+}
+
 TEST(TweakTest, SwapIfBranches) {
   llvm::StringLiteral ID = "SwapIfBranches";
 
@@ -517,6 +531,140 @@ int a = 123 EMPTY_FN(1) ;
   )cpp");
 }
 
+TEST(TweakTest, ExpandAutoType) {
+  llvm::StringLiteral ID = "ExpandAutoType";
+
+  checkAvailable(ID, R"cpp(
+    ^a^u^t^o^ i = 0;
+  )cpp");
+
+  checkNotAvailable(ID, R"cpp(
+    auto ^i^ ^=^ ^0^;^
+  )cpp");
+
+  llvm::StringLiteral Input = R"cpp(
+    [[auto]] i = 0;
+  )cpp";
+  llvm::StringLiteral Output = R"cpp(
+    int i = 0;
+  )cpp";
+  checkTransform(ID, Input, Output);
+
+  // check primitive type
+  Input = R"cpp(
+    au^to i = 0;
+  )cpp";
+  Output = R"cpp(
+    int i = 0;
+  )cpp";
+  checkTransform(ID, Input, Output);
+
+  // check classes and namespaces
+  Input = R"cpp(
+    namespace testns {
+      class TestClass {
+        class SubClass {};
+      };
+    }
+    ^auto C = testns::TestClass::SubClass();
+  )cpp";
+  Output = R"cpp(
+    namespace testns {
+      class TestClass {
+        class SubClass {};
+      };
+    }
+    testns::TestClass::SubClass C = testns::TestClass::SubClass();
+  )cpp";
+  checkTransform(ID, Input, Output);
+
+  // check that namespaces are shortened
+  Input = R"cpp(
+    namespace testns {
+    class TestClass {
+    };
+    void func() { ^auto C = TestClass(); }
+    }
+  )cpp";
+  Output = R"cpp(
+    namespace testns {
+    class TestClass {
+    };
+    void func() { TestClass C = TestClass(); }
+    }
+  )cpp";
+  checkTransform(ID, Input, Output);
+
+  // unknown types in a template should not be replaced
+  Input = R"cpp(
+    template <typename T> void x() {
+        ^auto y =  T::z();
+        }
+  )cpp";
+  checkApplyContainsError(ID, Input, "Could not deduce type for 'auto' type");
+
+  // undefined functions should not be replaced
+  Input = R"cpp(
+    a^uto x = doesnt_exist();
+  )cpp";
+  checkApplyContainsError(ID, Input, "Could not deduce type for 'auto' type");
+
+  // function pointers should not be replaced
+  Input = R"cpp(
+    int foo();
+    au^to x = &foo;
+  )cpp";
+  checkApplyContainsError(ID, Input,
+      "Could not expand type of function pointer");
+
+  // lambda types are not replaced
+  Input = R"cpp(
+    au^to x = []{};
+  )cpp";
+  checkApplyContainsError(ID, Input,
+      "Could not expand type of lambda expression");
+
+  // inline namespaces
+  Input = R"cpp(
+    inline namespace x {
+      namespace { struct S; }
+    }
+    au^to y = S();
+  )cpp";
+  Output = R"cpp(
+    inline namespace x {
+      namespace { struct S; }
+    }
+    S y = S();
+  )cpp";
+
+  // local class
+  Input = R"cpp(
+  namespace x {
+    void y() {
+      struct S{};
+      a^uto z = S();
+  }}
+  )cpp";
+  Output = R"cpp(
+  namespace x {
+    void y() {
+      struct S{};
+      S z = S();
+  }}
+  )cpp";
+  checkTransform(ID, Input, Output);
+
+  // replace array types
+  Input = R"cpp(
+    au^to x = "test";
+  )cpp";
+  Output = R"cpp(
+    const char * x = "test";
+  )cpp";
+  checkTransform(ID, Input, Output);
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang

Modified: clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp?rev=365792&r1=365791&r2=365792&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp Thu Jul 11 09:04:18 2019
@@ -2139,6 +2139,28 @@ TEST(FindReferences, NoQueryForLocalSymb
   }
 }
 
+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);
+      auto DeducedType = getDeducedType(AST, *Location);
+      EXPECT_EQ(DeducedType->getAsString(), T.DeducedType);
+    }
+  }
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang




More information about the cfe-commits mailing list