kbobyrev updated this revision to Diff 321055.
kbobyrev added a comment.

Revert last change: leads to incomplete types.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95925

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

Index: clang-tools-extra/clangd/unittests/RenameTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/RenameTests.cpp
+++ clang-tools-extra/clangd/unittests/RenameTests.cpp
@@ -1010,13 +1010,68 @@
       )cpp",
        "conflict", !HeaderFile, nullptr, "Conflict"},
 
-      {R"cpp(// FIXME: detecting local variables is not supported yet.
+      {R"cpp(
         void func() {
           int Conflict;
-          int [[V^ar]];
+          int V^ar;
+        }
+      )cpp",
+       "conflict", !HeaderFile, nullptr, "Conflict"},
+
+      {R"cpp(
+        void func() {
+          if (int Conflict = 42) {
+            int V^ar;
+          }
+        }
+      )cpp",
+       "conflict", !HeaderFile, nullptr, "Conflict"},
+
+      {R"cpp(
+        void func() {
+          if (int Conflict = 42) {
+          } else {
+            bool V^ar;
+          }
+        }
+      )cpp",
+       "conflict", !HeaderFile, nullptr, "Conflict"},
+
+      {R"cpp(
+        void func() {
+          if (int V^ar = 42) {
+          } else {
+            bool Conflict;
+          }
         }
       )cpp",
-       nullptr, !HeaderFile, nullptr, "Conflict"},
+       "conflict", !HeaderFile, nullptr, "Conflict"},
+
+      {R"cpp(
+        void func() {
+          while (int V^ar = 10) {
+            bool Conflict = true;
+          }
+        }
+      )cpp",
+       "conflict", !HeaderFile, nullptr, "Conflict"},
+
+      {R"cpp(
+        void func() {
+          for (int Something = 9000, Anything = 14, Conflict = 42; Anything > 9;
+               ++Something) {
+            int V^ar;
+          }
+        }
+      )cpp",
+       "conflict", !HeaderFile, nullptr, "Conflict"},
+
+      {R"cpp(
+        void func(int Conflict) {
+          bool V^ar;
+        }
+      )cpp",
+       "conflict", !HeaderFile, nullptr, "Conflict"},
 
       {R"cpp(// Trying to rename into the same name, SameName == SameName.
         void func() {
Index: clang-tools-extra/clangd/refactor/Rename.cpp
===================================================================
--- clang-tools-extra/clangd/refactor/Rename.cpp
+++ clang-tools-extra/clangd/refactor/Rename.cpp
@@ -15,8 +15,14 @@
 #include "index/SymbolCollector.h"
 #include "support/Logger.h"
 #include "support/Trace.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ParentMapContext.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Tooling/Syntax/Tokens.h"
 #include "llvm/ADT/None.h"
@@ -318,13 +324,83 @@
   return Results;
 }
 
+// Detect name conflict with othter DeclStmts in the same enclosing scope.
+const NamedDecl *lookupSiblingWithinEnclosingScope(ASTContext &Ctx,
+                                                   const NamedDecl &RenamedDecl,
+                                                   StringRef NewName) {
+  DynTypedNodeList Parents = Ctx.getParents(RenamedDecl);
+  if (Parents.size() != 1 || !Parents.begin()->get<DeclStmt>())
+    return nullptr;
+  Parents = Ctx.getParents(*Parents.begin()->get<DeclStmt>());
+  if (Parents.size() != 1)
+    return nullptr;
+  // This helper checks if any statement within DeclStmt has NewName.
+  auto CheckDeclStmt = [&](const DeclStmt *DS) -> const NamedDecl * {
+    if (!DS)
+      return nullptr;
+    for (const auto &Child : DS->getDeclGroup())
+      if (const auto *ND = dyn_cast<NamedDecl>(Child))
+        if (ND != &RenamedDecl && ND->getName() == NewName)
+          return ND;
+    return nullptr;
+  };
+  auto CheckCompoundStmt = [&](const CompoundStmt *CS) -> const NamedDecl * {
+    if (!CS)
+      return nullptr;
+    for (const auto *Node : CS->children())
+      if (const auto *Result = CheckDeclStmt(dyn_cast<DeclStmt>(Node)))
+        return Result;
+    return nullptr;
+  };
+  // This helper checks if there is a condition variable has NewName.
+  auto CheckConditionVariable = [&](const auto *Scope) -> const NamedDecl * {
+    if (!Scope)
+      return nullptr;
+    if (const auto *Result =
+            CheckDeclStmt(Scope->getConditionVariableDeclStmt()))
+      return Result;
+    return nullptr;
+  };
+  const auto *ParentNode = Parents.begin();
+  if (const auto *EnclosingCS = ParentNode->get<CompoundStmt>()) {
+    if (const auto *Result = CheckCompoundStmt(EnclosingCS))
+      return Result;
+    Parents = Ctx.getParents(*EnclosingCS);
+    if (Parents.size() != 1)
+      return nullptr;
+    const auto *Parent = Parents.begin();
+    if (const auto *Result = CheckConditionVariable(Parent->get<IfStmt>()))
+      return Result;
+    if (const auto *Result = CheckConditionVariable(Parent->get<WhileStmt>()))
+      return Result;
+    if (const auto *For = Parent->get<ForStmt>())
+      if (const auto *Result =
+              CheckDeclStmt(dyn_cast<DeclStmt>(For->getInit())))
+        return Result;
+    if (const auto *Function = Parent->get<FunctionDecl>())
+      for (const auto *Parameter : Function->parameters())
+        if (Parameter->getName() == NewName)
+          return Parameter;
+  }
+  if (const auto *EnclosingIf = ParentNode->get<IfStmt>()) {
+    if (const auto *Result = CheckCompoundStmt(
+            dyn_cast_or_null<CompoundStmt>(EnclosingIf->getElse())))
+      return Result;
+    return CheckCompoundStmt(dyn_cast<CompoundStmt>(EnclosingIf->getThen()));
+  }
+  if (const auto *EnclosingWhile = ParentNode->get<WhileStmt>())
+    return CheckCompoundStmt(dyn_cast<CompoundStmt>(EnclosingWhile->getBody()));
+  if (const auto *EnclosingFor = ParentNode->get<ForStmt>())
+    return CheckCompoundStmt(dyn_cast<CompoundStmt>(EnclosingFor->getBody()));
+  return nullptr;
+}
+
 // Lookup the declarations (if any) with the given Name in the context of
 // RenameDecl.
-const NamedDecl *lookupSiblingWithName(const ASTContext &Ctx,
-                                       const NamedDecl &RenamedDecl,
-                                       llvm::StringRef Name) {
-  trace::Span Tracer("LookupSiblingWithName");
-  const auto &II = Ctx.Idents.get(Name);
+const NamedDecl *lookupSiblingsWithinContext(ASTContext &Ctx,
+                                             const NamedDecl &RenamedDecl,
+                                             llvm::StringRef NewName) {
+  const auto &II = Ctx.Idents.get(NewName);
   DeclarationName LookupName(&II);
   DeclContextLookupResult LookupResult;
   const auto *DC = RenamedDecl.getDeclContext();
@@ -356,6 +432,16 @@
   return nullptr;
 }
 
+const NamedDecl *lookupSiblingWithName(ASTContext &Ctx,
+                                       const NamedDecl &RenamedDecl,
+                                       llvm::StringRef NewName) {
+  trace::Span Tracer("LookupSiblingWithName");
+  if (const auto *Result =
+          lookupSiblingsWithinContext(Ctx, RenamedDecl, NewName))
+    return Result;
+  return lookupSiblingWithinEnclosingScope(Ctx, RenamedDecl, NewName);
+}
+
 struct InvalidName {
   enum Kind {
     Keywords,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to