kadircet updated this revision to Diff 226046.
kadircet added a comment.

- Rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D69298

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
@@ -1562,6 +1562,21 @@
     }]]]])cpp");
 }
 
+TEST_F(DefineOutlineTest, ApplyTest) {
+  FileName = "Test.hpp";
+
+  // No implementation file.
+  EXPECT_EQ(apply("void fo^o() { return; }"),
+            "fail: Couldn't find a suitable implementation file.");
+
+  llvm::StringMap<std::string> EditedFiles;
+  ExtraFiles["Test.cpp"] = "";
+  EXPECT_EQ(apply("void fo^o() { return; }", &EditedFiles), "void foo() ;");
+  EXPECT_THAT(EditedFiles,
+              testing::ElementsAre(FileWithContents(testPath("Test.cpp"),
+                                                    "void foo() { return; }")));
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang
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
@@ -9,12 +9,18 @@
 #include "HeaderSourceSwitch.h"
 #include "Path.h"
 #include "Selection.h"
+#include "SourceCode.h"
 #include "refactor/Tweak.h"
 #include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Stmt.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Driver/Types.h"
+#include "clang/Tooling/Core/Replacement.h"
 #include "llvm/ADT/Optional.h"
-#include "llvm/Support/Path.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
 
 namespace clang {
 namespace clangd {
@@ -39,6 +45,29 @@
   return nullptr;
 }
 
+llvm::Optional<Path> getSourceFile(llvm::StringRef FileName,
+                                   const Tweak::Selection &Sel) {
+  if (auto Source = getCorrespondingHeaderOrSource(
+          FileName,
+          &Sel.AST.getSourceManager().getFileManager().getVirtualFileSystem()))
+    return *Source;
+  return getCorrespondingHeaderOrSource(FileName, Sel.AST, Sel.Index);
+}
+
+// Creates a modified version of function definition that can be inserted at a
+// different location. Contains both function signature and body.
+llvm::Optional<llvm::StringRef> moveFunctionDef(const FunctionDecl *FD) {
+  auto &SM = FD->getASTContext().getSourceManager();
+  auto CharRange = toHalfOpenFileRange(SM, FD->getASTContext().getLangOpts(),
+                                       FD->getSourceRange());
+  if (!CharRange)
+    return llvm::None;
+
+  // FIXME: Qualify return type.
+  // FIXME: Qualify function name depending on the target context.
+  return toSourceCode(SM, *CharRange);
+}
+
 /// Moves definition of a function/method to an appropriate implementation file.
 ///
 /// Before:
@@ -84,8 +113,66 @@
   }
 
   Expected<Effect> apply(const Selection &Sel) override {
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "Not implemented yet");
+    const SourceManager &SM = Sel.AST.getSourceManager();
+    llvm::StringRef FileName = SM.getFilename(Sel.Cursor);
+
+    auto SourceFile = getSourceFile(FileName, Sel);
+    if (!SourceFile)
+      return llvm::createStringError(
+          llvm::inconvertibleErrorCode(),
+          "Couldn't find a suitable implementation file.");
+
+    auto &FS =
+        Sel.AST.getSourceManager().getFileManager().getVirtualFileSystem();
+    auto Buffer = FS.getBufferForFile(*SourceFile);
+    // FIXME: Maybe we should consider creating the implementation file if it
+    // doesn't exist?
+    if (!Buffer)
+      return llvm::createStringError(Buffer.getError(),
+                                     Buffer.getError().message());
+    auto Contents = Buffer->get()->getBuffer();
+    auto Region =
+        getEligiblePoints(Contents, Source->getQualifiedNameAsString(),
+                          getFormatStyleForFile(*SourceFile, Contents, &FS));
+
+    assert(!Region.EligiblePoints.empty());
+    // FIXME: This selection can be made smarter by looking at the definition
+    // locations for adjacent decls to Source. Unfortunately psudeo parsing in
+    // getEligibleRegions only knows about namespace begin/end events so we
+    // can't match function start/end positions yet.
+    auto InsertionPoint = Region.EligiblePoints.back();
+    auto InsertionOffset = positionToOffset(Contents, InsertionPoint);
+    if (!InsertionOffset)
+      return InsertionOffset.takeError();
+
+    auto FuncDef = moveFunctionDef(Source);
+    if (!FuncDef)
+      return llvm::createStringError(
+          llvm::inconvertibleErrorCode(),
+          "Couldn't get full source for function definition.");
+
+    SourceManagerForFile SMFF(*SourceFile, Contents);
+    auto InsertLoc =
+        SMFF.get().getComposedLoc(SMFF.get().getMainFileID(), *InsertionOffset);
+    const tooling::Replacement InsertFunctionDef(SMFF.get(), InsertLoc, 0,
+                                                 *FuncDef);
+    auto Effect = Effect::mainFileEdit(
+        SMFF.get(), tooling::Replacements(InsertFunctionDef));
+    if (!Effect)
+      return Effect.takeError();
+
+    const tooling::Replacement DeleteFuncBody(
+        Sel.AST.getSourceManager(),
+        CharSourceRange(Source->getBody()->getSourceRange(), /*ITR=*/true),
+        ";");
+    auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(),
+                                     tooling::Replacements(DeleteFuncBody));
+    if (!HeaderFE)
+      return HeaderFE.takeError();
+
+    Effect->ApplyEdits.try_emplace(HeaderFE->first,
+                                   std::move(HeaderFE->second));
+    return std::move(*Effect);
   }
 
 private:
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to