[clangd] Add support for within-file rename of complicated fields
authorKirill Bobyrev <kbobyrev@google.com>
Fri, 27 Nov 2020 02:59:24 +0000 (03:59 +0100)
committerKirill Bobyrev <kbobyrev@google.com>
Fri, 27 Nov 2020 02:59:28 +0000 (03:59 +0100)
This was originally a part of D71880 but is separated for simplicity and ease
of reviewing.

Fixes: https://github.com/clangd/clangd/issues/582

Reviewed By: hokein

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

clang-tools-extra/clangd/refactor/Rename.cpp
clang-tools-extra/clangd/unittests/RenameTests.cpp

index 78aaa99..946daaf 100644 (file)
@@ -124,6 +124,28 @@ const NamedDecl *canonicalRenameDecl(const NamedDecl *D) {
   if (const auto *Function = dyn_cast<FunctionDecl>(D))
     if (const FunctionTemplateDecl *Template = Function->getPrimaryTemplate())
       return canonicalRenameDecl(Template);
+  if (const auto *Field = dyn_cast<FieldDecl>(D)) {
+    // This is a hacky way to do something like
+    // CXXMethodDecl::getInstantiatedFromMemberFunction for the field because
+    // Clang AST does not store relevant information about the field that is
+    // instantiated.
+    const auto *FieldParent = dyn_cast<CXXRecordDecl>(Field->getParent());
+    if (!FieldParent)
+      return Field->getCanonicalDecl();
+    FieldParent = FieldParent->getTemplateInstantiationPattern();
+    // Field is not instantiation.
+    if (!FieldParent || Field->getParent() == FieldParent)
+      return Field->getCanonicalDecl();
+    for (const FieldDecl *Candidate : FieldParent->fields())
+      if (Field->getDeclName() == Candidate->getDeclName())
+        return Candidate->getCanonicalDecl();
+    elog("FieldParent should have field with the same name as Field.");
+  }
+  if (const auto *VD = dyn_cast<VarDecl>(D)) {
+    if (const VarDecl *OriginalVD = VD->getInstantiatedFromStaticDataMember())
+      VD = OriginalVD;
+    return VD->getCanonicalDecl();
+  }
   return dyn_cast<NamedDecl>(D->getCanonicalDecl());
 }
 
index c67339f..2382dba 100644 (file)
@@ -540,6 +540,94 @@ TEST(RenameTest, WithinFileRename) {
         }
       )cpp",
 
+      // Fields in classes & partial and full specialiations.
+      R"cpp(
+        template<typename T>
+        struct Foo {
+          T [[Vari^able]] = 42;
+        };
+
+        void foo() {
+          Foo<int> f;
+          f.[[Varia^ble]] = 9000;
+        }
+      )cpp",
+      R"cpp(
+        template<typename T, typename U>
+        struct Foo {
+          T Variable[42];
+          U Another;
+
+          void bar() {}
+        };
+
+        template<typename T>
+        struct Foo<T, bool> {
+          T [[Var^iable]];
+          void bar() { ++[[Var^iable]]; }
+        };
+
+        void foo() {
+          Foo<unsigned, bool> f;
+          f.[[Var^iable]] = 9000;
+        }
+      )cpp",
+      R"cpp(
+        template<typename T, typename U>
+        struct Foo {
+          T Variable[42];
+          U Another;
+
+          void bar() {}
+        };
+
+        template<typename T>
+        struct Foo<T, bool> {
+          T Variable;
+          void bar() { ++Variable; }
+        };
+
+        template<>
+        struct Foo<unsigned, bool> {
+          unsigned [[Var^iable]];
+          void bar() { ++[[Var^iable]]; }
+        };
+
+        void foo() {
+          Foo<unsigned, bool> f;
+          f.[[Var^iable]] = 9000;
+        }
+      )cpp",
+      // Static fields.
+      R"cpp(
+        struct Foo {
+          static int [[Var^iable]];
+        };
+
+        int Foo::[[Var^iable]] = 42;
+
+        void foo() {
+          int LocalInt = Foo::[[Var^iable]];
+        }
+      )cpp",
+      R"cpp(
+        template<typename T>
+        struct Foo {
+          static T [[Var^iable]];
+        };
+
+        template <>
+        int Foo<int>::[[Var^iable]] = 42;
+
+        template <>
+        bool Foo<bool>::[[Var^iable]] = true;
+
+        void foo() {
+          int LocalInt = Foo<int>::[[Var^iable]];
+          bool LocalBool = Foo<bool>::[[Var^iable]];
+        }
+      )cpp",
+
       // Template parameters.
       R"cpp(
         template <typename [[^T]]>