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" 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" @@ -362,8 +363,9 @@ void ClangdServer::applyTweak(PathRef File, Range Sel, StringRef TweakID, Callback CB) { - auto Action = [Sel](decltype(CB) CB, std::string File, std::string TweakID, - Expected InpAST) { + auto Action = [Sel, this](decltype(CB) CB, std::string File, + std::string TweakID, + Expected InpAST) { if (!InpAST) return CB(InpAST.takeError()); auto Selection = tweakSelection(Sel, *InpAST); @@ -372,8 +374,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()); + // FIXME: this function has I/O operations (find .clang-format file), figure + // out a way to cache the format style. + auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents, + FSProvider.getFileSystem().get()); + return CB( + cleanupAndFormat(InpAST->Inputs.Contents, *ResultReplacements, Style)); }; WorkScheduler.runWithAST( "ApplyTweak", File, 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 +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 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 apply(StringRef ID, llvm::StringRef Input) { +llvm::Expected 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::getLLVMStyle()); + 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() {