hokein created this revision.
hokein added a reviewer: ilya-biryukov.
Herald added subscribers: kadircet, arphaman, jkorous, MaskRay, ioeric.
Herald added a project: clang.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D57739

Files:
  clangd/ClangdLSPServer.cpp
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/Format.h
  unittests/clangd/TweakTests.cpp

Index: unittests/clangd/TweakTests.cpp
===================================================================
--- unittests/clangd/TweakTests.cpp
+++ unittests/clangd/TweakTests.cpp
@@ -9,6 +9,7 @@
 
 #include "Annotations.h"
 #include "SourceCode.h"
+#include "Format.h"
 #include "TestTU.h"
 #include "refactor/Tweak.h"
 #include "clang/AST/Expr.h"
@@ -77,7 +78,8 @@
 void checkNotAvailable(StringRef ID, llvm::StringRef Input) {
   return checkAvailable(ID, Input, /*Available=*/false);
 }
-llvm::Expected<std::string> apply(StringRef ID, llvm::StringRef Input) {
+llvm::Expected<std::string> apply(StringRef ID, llvm::StringRef Input,
+                                  bool Format) {
   Annotations Code(Input);
   Range SelectionRng;
   if (Code.points().size() != 0) {
@@ -102,12 +104,19 @@
   auto Replacements = (*T)->apply(S);
   if (!Replacements)
     return Replacements.takeError();
+  if (Format) {
+    Replacements = cleanupAndFormat(
+        Code.code(), *Replacements,
+        clang::format::getGoogleStyle(::clang::format::FormatStyle::LK_Cpp));
+    if (!Replacements)
+      return Replacements.takeError();
+  }
   return applyAllReplacements(Code.code(), *Replacements);
 }
 
 void checkTransform(llvm::StringRef ID, llvm::StringRef Input,
-                    llvm::StringRef Output) {
-  EXPECT_THAT_EXPECTED(apply(ID, Input), HasValue(Output))
+                    llvm::StringRef Output, bool Format = false) {
+  EXPECT_THAT_EXPECTED(apply(ID, Input, Format), HasValue(Output))
       << "action id is" << ID;
 }
 
@@ -150,6 +159,22 @@
   )cpp";
   checkTransform(ID, Input, Output);
 
+  Input = R"cpp(
+    void test() {
+      ^if () { return 100; } else { continue; }
+    }
+  )cpp";
+  Output = R"cpp(
+    void test() {
+      if () {
+        continue;
+      } else {
+        return 100;
+      }
+    }
+  )cpp";
+  checkTransform(ID, Input, Output, /*Format=*/true);
+
   // Available in subexpressions of the condition.
   checkAvailable(ID, R"cpp(
     void test() {
Index: clangd/Format.h
===================================================================
--- /dev/null
+++ clangd/Format.h
@@ -0,0 +1,28 @@
+//===--- Format.h ------------------------------------------*- 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 "clang/Format/Format.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace clangd {
+
+// Cleanup and format the given replacements.
+inline llvm::Expected<tooling::Replacements>
+cleanupAndFormat(StringRef Code, const tooling::Replacements &Replaces,
+                 const format::FormatStyle &Style) {
+  auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
+  if (!CleanReplaces)
+    return CleanReplaces;
+  return formatReplacements(Code, std::move(*CleanReplaces), Style);
+}
+
+} // namespace clangd
+} // namespace clang
\ No newline at end of file
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -23,6 +23,7 @@
 #include "index/FileIndex.h"
 #include "index/Index.h"
 #include "refactor/Tweak.h"
+#include "clang/Format/Format.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "clang/Tooling/Core/Replacement.h"
 #include "llvm/ADT/FunctionExtras.h"
@@ -223,7 +224,7 @@
                        Callback<std::vector<TweakRef>> CB);
 
   /// Apply the code tweak with a specified \p ID.
-  void applyTweak(PathRef File, Range Sel, StringRef ID,
+  void applyTweak(StringRef Code, PathRef File, Range Sel, StringRef ID,
                   Callback<tooling::Replacements> CB);
 
   /// Only for testing purposes.
@@ -257,12 +258,15 @@
   blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10);
 
 private:
-  /// FIXME: This stats several files to find a .clang-format file. I/O can be
-  /// slow. Think of a way to cache this.
   llvm::Expected<tooling::Replacements>
   formatCode(llvm::StringRef Code, PathRef File,
              ArrayRef<tooling::Range> Ranges);
 
+  /// FIXME: This stats several files to find a .clang-format file. I/O can be
+  /// slow. Think of a way to cache this.
+  llvm::Expected<format::FormatStyle> getFormatStyle(llvm::StringRef Code,
+                                                     PathRef File);
+
   tooling::CompileCommand getCompileCommand(PathRef File);
 
   const GlobalCompilationDatabase &CDB;
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -10,6 +10,7 @@
 #include "ClangdUnit.h"
 #include "CodeComplete.h"
 #include "FindSymbols.h"
+#include "Format.h"
 #include "Headers.h"
 #include "SourceCode.h"
 #include "Trace.h"
@@ -358,9 +359,14 @@
                            Bind(Action, std::move(CB), File.str()));
 }
 
-void ClangdServer::applyTweak(PathRef File, Range Sel, StringRef TweakID,
+void ClangdServer::applyTweak(StringRef Code, PathRef File, Range Sel,
+                              StringRef TweakID,
                               Callback<tooling::Replacements> CB) {
+  auto Style = getFormatStyle(Code, File);
+  if (!Style)
+    return;
   auto Action = [Sel](decltype(CB) CB, std::string File, std::string TweakID,
+                      format::FormatStyle Style,
                       Expected<InputsAndAST> InpAST) {
     if (!InpAST)
       return CB(InpAST.takeError());
@@ -370,12 +376,15 @@
     auto A = prepareTweak(TweakID, *Selection);
     if (!A)
       return CB(A.takeError());
-    // FIXME: run formatter on top of resulting replacements.
-    return CB((*A)->apply(*Selection));
+    auto ResultReplacements = (*A)->apply(*Selection);
+    if (!ResultReplacements)
+      return CB(ResultReplacements.takeError());
+    return CB(
+        cleanupAndFormat(InpAST->Inputs.Contents, *ResultReplacements, Style));
   };
   WorkScheduler.runWithAST(
       "ApplyTweak", File,
-      Bind(Action, std::move(CB), File.str(), TweakID.str()));
+      Bind(Action, std::move(CB), File.str(), TweakID.str(), *Style));
 }
 
 void ClangdServer::dumpAST(PathRef File,
@@ -471,9 +480,7 @@
 ClangdServer::formatCode(llvm::StringRef Code, PathRef File,
                          llvm::ArrayRef<tooling::Range> Ranges) {
   // Call clang-format.
-  auto FS = FSProvider.getFileSystem();
-  auto Style = format::getStyle(format::DefaultFormatStyle, File,
-                                format::DefaultFallbackStyle, Code, FS.get());
+  auto Style = getFormatStyle(Code, File);
   if (!Style)
     return Style.takeError();
 
@@ -489,6 +496,13 @@
       File));
 }
 
+llvm::Expected<format::FormatStyle>
+ClangdServer::getFormatStyle(llvm::StringRef Code, PathRef File) {
+  return format::getStyle(format::DefaultFormatStyle, File,
+                          format::DefaultFallbackStyle, Code,
+                          FSProvider.getFileSystem().get());
+}
+
 void ClangdServer::findDocumentHighlights(
     PathRef File, Position Pos, Callback<std::vector<DocumentHighlight>> CB) {
   auto Action = [Pos](Callback<std::vector<DocumentHighlight>> CB,
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -469,10 +469,10 @@
       Reply("Fix applied.");
       ApplyEdit(std::move(WE));
     };
-    Server->applyTweak(Params.tweakArgs->file.file(),
-                       Params.tweakArgs->selection, Params.tweakArgs->tweakID,
-                       Bind(Action, std::move(Reply), Params.tweakArgs->file,
-                            std::move(*Code)));
+    Server->applyTweak(
+        *Code, Params.tweakArgs->file.file(), Params.tweakArgs->selection,
+        Params.tweakArgs->tweakID,
+        Bind(Action, std::move(Reply), Params.tweakArgs->file, *Code));
   } else {
     // We should not get here because ExecuteCommandParams would not have
     // parsed in the first place and this handler should not be called. But if
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to