ilya-biryukov created this revision.
ilya-biryukov added a reviewer: sammccall.
Herald added subscribers: kadircet, arphaman, jkorous, MaskRay, ioeric, mgorny.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D56611

Files:
  clangd/CMakeLists.txt
  clangd/CodeActions.cpp
  clangd/refactor/actions/SwapIfBranches.cpp
  clangd/refactor/actions/SwapIfBranches.h

Index: clangd/refactor/actions/SwapIfBranches.h
===================================================================
--- /dev/null
+++ clangd/refactor/actions/SwapIfBranches.h
@@ -0,0 +1,31 @@
+//===--- SwapIfBrances.h -----------------------------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// A code action that swaps the 'then' and 'else' branch of the if statement.
+// Before:
+//   if (foo) { return 10; } else { continue; }
+// After:
+//   if (foo) { continue; } else { return 10; }
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_ACTIONS_SWAPIFBRANCHES_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_ACTIONS_SWAPIFBRANCHES_H
+
+#include "refactor/ActionProvider.h"
+
+namespace clang {
+namespace clangd {
+
+class SwapIfBranches : public ActionProvider {
+  llvm::Optional<PreparedAction> prepare(const ActionInputs &Inputs) override;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
\ No newline at end of file
Index: clangd/refactor/actions/SwapIfBranches.cpp
===================================================================
--- /dev/null
+++ clangd/refactor/actions/SwapIfBranches.cpp
@@ -0,0 +1,94 @@
+//===--- SwapIfBranches.cpp --------------------------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "SwapIfBranches.h"
+#include "ClangdUnit.h"
+#include "CodeActions.h"
+#include "Logger.h"
+#include "SourceCode.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace clangd {
+
+class FindIfUnderCursor : public RecursiveASTVisitor<FindIfUnderCursor> {
+public:
+  FindIfUnderCursor(ASTContext &Ctx, SourceLocation CursorLoc, IfStmt *&Result)
+      : Ctx(Ctx), CursorLoc(CursorLoc), Result(Result) {}
+
+  bool VisitIfStmt(IfStmt *If) {
+    auto R = toHalfOpenFileRange(Ctx.getSourceManager(), Ctx.getLangOpts(),
+                                 SourceRange(If->getIfLoc()));
+    if (!R)
+      return true;
+    if (!halfOpenRangeContains(Ctx.getSourceManager(), *R, CursorLoc))
+      return true;
+    Result = If;
+    return false;
+  }
+
+private:
+  ASTContext &Ctx;
+  SourceLocation CursorLoc;
+  IfStmt *&Result;
+};
+
+llvm::Optional<PreparedAction>
+SwapIfBranches::prepare(const ActionInputs &Inputs) {
+  auto &Ctx = Inputs.AST.getASTContext();
+  auto &SrcMgr = Ctx.getSourceManager();
+  IfStmt *If = nullptr;
+  FindIfUnderCursor(Ctx, Inputs.Cursor, If).TraverseAST(Ctx);
+  if (!If)
+    return llvm::None;
+
+  // avoid dealing with single-statement brances, they require careful handling
+  // to avoid changing semantics of the code (i.e. dangling else).
+  if (!llvm::dyn_cast_or_null<CompoundStmt>(If->getThen()) ||
+      !llvm::dyn_cast_or_null<CompoundStmt>(If->getElse()))
+    return llvm::None;
+
+  auto ThenRng = toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(),
+                                     If->getThen()->getSourceRange());
+  if (!ThenRng)
+    return llvm::None;
+  auto ElseRng = toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(),
+                                     If->getElse()->getSourceRange());
+  if (!ElseRng)
+    return llvm::None;
+
+  llvm::StringRef ThenCode = toSourceCode(SrcMgr, *ThenRng);
+  llvm::StringRef ElseCode = toSourceCode(SrcMgr, *ElseRng);
+
+  tooling::Replacements R;
+  if (auto Err = R.add(tooling::Replacement(SrcMgr, ThenRng->getBegin(),
+                                            ThenCode.size(), ElseCode))) {
+    llvm::consumeError(std::move(Err));
+    return llvm::None;
+  }
+  if (auto Err = R.add(tooling::Replacement(SrcMgr, ElseRng->getBegin(),
+                                            ElseCode.size(), ThenCode))) {
+    llvm::consumeError(std::move(Err));
+    return llvm::None;
+  }
+  return PreparedAction("Swap if branches", std::move(R));
+}
+} // namespace clangd
+} // namespace clang
Index: clangd/CodeActions.cpp
===================================================================
--- clangd/CodeActions.cpp
+++ clangd/CodeActions.cpp
@@ -9,6 +9,7 @@
 #include "CodeActions.h"
 #include "Logger.h"
 #include "refactor/actions/QualifyName.h"
+#include "refactor/actions/SwapIfBranches.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -22,6 +23,7 @@
 CodeActions::CodeActions() {
   // FIXME: provide a registry of the providers.
   Actions.push_back(llvm::make_unique<QualifyName>());
+  Actions.push_back(llvm::make_unique<SwapIfBranches>());
 }
 
 std::vector<PreparedAction>
Index: clangd/CMakeLists.txt
===================================================================
--- clangd/CMakeLists.txt
+++ clangd/CMakeLists.txt
@@ -65,6 +65,7 @@
 
   refactor/ActionProvider.cpp
   refactor/actions/QualifyName.cpp
+  refactor/actions/SwapIfBranches.cpp
 
   LINK_LIBS
   clangAST
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to