tupos created this revision.
tupos added reviewers: sammccall, njames93.
tupos added a project: clang-tools-extra.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
tupos requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140275

Files:
  clang-tools-extra/clangd/refactor/tweaks/AddDoxygenComment.cpp
  clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
  clang-tools-extra/clangd/unittests/CMakeLists.txt
  clang-tools-extra/clangd/unittests/tweaks/AddDoxygenCommentTests.cpp

Index: clang-tools-extra/clangd/unittests/tweaks/AddDoxygenCommentTests.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/unittests/tweaks/AddDoxygenCommentTests.cpp
@@ -0,0 +1,98 @@
+//===-- AddDoxygenCommentTests.cpp ------------------------*- 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 "TweakTesting.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+TWEAK_TEST(AddDoxygenComment);
+
+TEST_F(AddDoxygenCommentTest, AvailableUnavailable) {
+  EXPECT_AVAILABLE(R"cpp(
+    void bar(char b) {^ }
+    [[int foo(int x) { }]]
+    namespace ns1 {
+      void bar(char b) {^ }
+      [[int foo(int x) { }]]
+    }
+  )cpp");
+  EXPECT_UNAVAILABLE(R"cpp(
+    namespace ns1 {
+      /*!
+       */
+      void bar(char b) {^ }
+      // comment
+      [[int foo(int x) { }]]
+      /// comment
+      [[int meaw(int x) { }]]
+    }
+  )cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, Apply1) {
+  EXPECT_EQ(apply(R"cpp(
+namespace ns1 {
+  int foo(int y, char* s) {
+    ^int x;
+    return x;
+  }
+}
+  )cpp"),
+            R"cpp(
+namespace ns1 {
+  
+/*!
+ * @brief
+ *
+* @param y
+* @param s
+* @return
+*/
+int foo(int y, char* s) {
+    int x;
+    return x;
+  }
+}
+  )cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, Apply2) {
+  EXPECT_EQ(apply(R"cpp(
+void foo();
+void ^bar();
+namespace ns1 {
+  int foo(int y, char* s) {
+    int x;
+    return x;
+  }
+}
+)cpp"),
+            R"cpp(
+void foo();
+
+/*!
+ * @brief
+ *
+*/
+void bar();
+namespace ns1 {
+  int foo(int y, char* s) {
+    int x;
+    return x;
+  }
+}
+)cpp");
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
Index: clang-tools-extra/clangd/unittests/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -107,6 +107,7 @@
   support/TestTracer.cpp
   support/TraceTests.cpp
 
+  tweaks/AddDoxygenCommentTests.cpp
   tweaks/AddUsingTests.cpp
   tweaks/AnnotateHighlightingsTests.cpp
   tweaks/DefineInlineTests.cpp
Index: clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
+++ clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
@@ -12,6 +12,7 @@
 # $<TARGET_OBJECTS:obj.clangDaemonTweaks> to a list of sources, see
 # clangd/tool/CMakeLists.txt for an example.
 add_clang_library(clangDaemonTweaks OBJECT
+  AddDoxygenComment.cpp
   AddUsing.cpp
   AnnotateHighlightings.cpp
   DumpAST.cpp
Index: clang-tools-extra/clangd/refactor/tweaks/AddDoxygenComment.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/refactor/tweaks/AddDoxygenComment.cpp
@@ -0,0 +1,147 @@
+//===--- AddDoxydgenComment.cpp ---------------------------------*- 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 "AST.h"
+#include "Selection.h"
+#include "refactor/InsertionPoint.h"
+#include "refactor/Tweak.h"
+#include "support/Logger.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+// A tweak that adds a doxygen comment to the function declaration
+//
+// Given:
+//   int func(int x, char const* s, Bar bar) {}
+// the tweak add the doxygen comment to the function in the form
+//   /*!
+//    * @brief
+//    * @param x
+//    * @param s
+//    * @param bar
+//    * @return
+//    */
+//   int func(int x, char const* s, Bar bar) {}
+//   if the function return type is void no @return is added to the doxygen
+//   comment
+//
+class AddDoxygenComment : public Tweak {
+public:
+  const char *id() const final;
+  llvm::StringLiteral kind() const override {
+    return CodeAction::REFACTOR_KIND;
+  }
+  bool prepare(const Selection &Inputs) override;
+  Expected<Effect> apply(const Selection &Inputs) override;
+  std::string title() const override;
+
+private:
+  FunctionDecl const *FD;
+  std::string buildCommentCode() const;
+  static bool isCommentExist(FunctionDecl const *FD);
+};
+
+REGISTER_TWEAK(AddDoxygenComment)
+
+std::string AddDoxygenComment::title() const {
+  return "Add doxygen comment to the function declaration";
+}
+
+bool AddDoxygenComment::isCommentExist(FunctionDecl const *FD) {
+  if (RawComment *Comment =
+          FD->getASTContext().getRawCommentForDeclNoCache(FD)) {
+    return true;
+  }
+  return false;
+}
+
+bool AddDoxygenComment::prepare(const Selection &Inputs) {
+  if (!Inputs.AST->getLangOpts().CPlusPlus) {
+    return false;
+  }
+  if (auto *N = Inputs.ASTSelection.commonAncestor()) {
+    if (FunctionDecl const *FD = N->ASTNode.get<FunctionDecl>()) {
+      if (isCommentExist(FD)) {
+        return false;
+      }
+      this->FD = FD;
+      return true;
+    }
+    for (auto *P = N->Parent; P != nullptr; P = P->Parent) {
+      if (FunctionDecl const *FD = P->ASTNode.get<FunctionDecl>()) {
+        if (isCommentExist(FD)) {
+          return false;
+        }
+        this->FD = FD;
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+std::string AddDoxygenComment::buildCommentCode() const {
+  std::string Res;
+  llvm::raw_string_ostream OS(Res);
+  OS << R"cpp(
+/*!
+ * @brief
+ *
+)cpp";
+  for (auto const *P : FD->parameters()) {
+    OS << "* @param " << P->getName() << '\n';
+  }
+  if (auto const *RT = FD->getReturnType().getTypePtr()) {
+    if (!RT->isVoidType()) {
+      OS << "* @return\n";
+    }
+  }
+  OS << "*/\n";
+  return Res;
+}
+
+Expected<Tweak::Effect> AddDoxygenComment::apply(const Selection &Inputs) {
+  auto &SrcMgr = Inputs.AST->getSourceManager();
+  std::vector<Anchor> Anchors = {{[this](Decl const *D) {
+                                    if (auto const *FD =
+                                            llvm::dyn_cast<FunctionDecl>(D)) {
+                                      if (FD == this->FD) {
+                                        return true;
+                                      }
+                                    }
+                                    return false;
+                                  },
+                                  Anchor::Above}};
+  auto const *Parent = FD->getParent();
+  if (!Parent) {
+    return error("Parent for the FuncDecl is nullptr");
+  }
+  // we cannot use here insertDecl as if the Parent is TranslationUnitDecl
+  // it will fail, as TranslationUnitDecl does not have a valid location
+  auto Loc = insertionPoint(*Parent, Anchors);
+  if (Loc.isInvalid()) {
+    return error("Location for Declatation {0} is invalid",
+                 Parent->getDeclKindName());
+  }
+  tooling::Replacement Replacement(SrcMgr, Loc, 0, buildCommentCode());
+  return Effect::mainFileEdit(SrcMgr,
+                              tooling::Replacements{std::move(Replacement)});
+}
+} // namespace
+} // namespace clangd
+} // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to