kadircet created this revision.
kadircet added reviewers: hokein, ilya-biryukov.
Herald added subscribers: cfe-commits, usaxena95, arphaman, jkorous, MaskRay.
Herald added a project: clang.

Currently we only delete function body from declaration, in addition to
that we should also drop ctor initializers.

Unfortunately CXXConstructorDecl doesn't store the location of `:` before
initializers, therefore we make use of token buffer to figure out where to start
deletion.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D71188

Files:
  clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
  clang-tools-extra/clangd/unittests/TweakTests.cpp

Index: clang-tools-extra/clangd/unittests/TweakTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/TweakTests.cpp
+++ clang-tools-extra/clangd/unittests/TweakTests.cpp
@@ -1941,6 +1941,24 @@
             "void foo(int x, int y = 5, int = 2) ;",
             "void foo(int x, int y, int ) {}",
       },
+      // Ctor initializers.
+      {
+          R"cpp(
+              class Foo {
+                int y = 2;
+                F^oo() : bar(2){}
+                int bar;
+                int z = 2;
+              };)cpp",
+          R"cpp(
+              class Foo {
+                int y = 2;
+                Foo() ;
+                int bar;
+                int z = 2;
+              };)cpp",
+          "Foo::Foo() : bar(2){}\n",
+      },
   };
   for (const auto &Case : Cases) {
     SCOPED_TRACE(Case.Test);
Index: clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
===================================================================
--- clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
+++ clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
@@ -18,16 +18,20 @@
 #include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Stmt.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TokenKinds.h"
 #include "clang/Driver/Types.h"
 #include "clang/Format/Format.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Syntax/Tokens.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Error.h"
@@ -228,6 +232,46 @@
   return InsertionPoint{Region.EnclosingNamespace, *Offset};
 }
 
+// Returns the range that should be deleted from declaration, which always
+// contains function body. In addition to that it might contain constructor
+// initializers.
+SourceRange getDeletionRange(const FunctionDecl *FD,
+                             const syntax::TokenBuffer &TokBuf) {
+  auto DeletionRange = FD->getBody()->getSourceRange();
+  if (auto *CD = llvm::dyn_cast<CXXConstructorDecl>(FD)) {
+    const auto &SM = TokBuf.sourceManager();
+    // AST doesn't contain the location for ":" in ctor initializers. Therefore
+    // we find it by finding the first ":" before the first ctor initializer.
+    SourceLocation InitStart;
+    // Find the first initializer.
+    for (const auto *CInit : CD->inits()) {
+      // We don't care about in-class initializers.
+      if (CInit->isInClassMemberInitializer())
+        continue;
+      if (InitStart.isInvalid() ||
+          SM.isBeforeInTranslationUnit(CInit->getSourceLocation(), InitStart))
+        InitStart = CInit->getSourceLocation();
+    }
+    if (InitStart.isValid()) {
+      auto Toks = TokBuf.expandedTokens(CD->getSourceRange());
+      // Drop any tokens after the initializer.
+      Toks = Toks.take_while([&TokBuf, &InitStart](const syntax::Token &Tok) {
+        return TokBuf.sourceManager().isBeforeInTranslationUnit(Tok.location(),
+                                                                InitStart);
+      });
+      // Look for the first colon.
+      for (auto &Tok : llvm::reverse(Toks)) {
+        if (Tok.kind() == tok::colon) {
+          InitStart = Tok.location();
+          break;
+        }
+      }
+      DeletionRange.setBegin(InitStart);
+    }
+  }
+  return DeletionRange;
+}
+
 /// Moves definition of a function/method to an appropriate implementation file.
 ///
 /// Before:
@@ -328,7 +372,8 @@
     const tooling::Replacement DeleteFuncBody(
         Sel.AST.getSourceManager(),
         CharSourceRange::getTokenRange(*toHalfOpenFileRange(
-            SM, Sel.AST.getLangOpts(), Source->getBody()->getSourceRange())),
+            SM, Sel.AST.getLangOpts(),
+            getDeletionRange(Source, Sel.AST.getTokens()))),
         ";");
     auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(),
                                      tooling::Replacements(DeleteFuncBody));
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to