tupos updated this revision to Diff 506220.
tupos marked 11 inline comments as done.

Repository:
  rG LLVM Github Monorepo

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

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,189 @@
+//===-- 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 {
+      [[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) { }]]
+      void baz(char b) {^ }
+    }
+  )cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, AvailableUnavailableOnDefinition) {
+  EXPECT_AVAILABLE(R"cpp(
+    void bar^(char b);
+    void bar(char b) { (void)b; }
+  )cpp");
+  EXPECT_UNAVAILABLE(R"cpp(
+    void bar(char b);
+    void bar^(char b) { (void)b; }
+  )cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, AvailableUnavailableOnMemberFunc) {
+  EXPECT_AVAILABLE(R"cpp(
+    class Foo {
+      void foo^(){}
+      void bar^();
+    };
+  )cpp");
+  EXPECT_UNAVAILABLE(R"cpp(
+    class Foo {
+      void bar();
+    };
+    void Foo::bar^(){}
+  )cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, AvailableUnavailableOnTemplate) {
+  EXPECT_AVAILABLE(R"cpp(
+    template<class T>
+    class Foo {
+      void foo^(){}
+      void bar^();
+    };
+  )cpp");
+  EXPECT_UNAVAILABLE(R"cpp(
+    template<class T>
+    class Foo {
+      void bar();
+    };
+    template<class T>
+    void Foo<T>::bar^(){}
+  )cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, AvailableUnavailableOnDeductionGuide) {
+  EXPECT_UNAVAILABLE(R"cpp(
+    template<typename T> struct A { A(); A(T); };
+    A^() -> A<int>;
+  )cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, AvailableUnavailableObjC) {
+  FileName = "TestTU.m";
+  EXPECT_AVAILABLE(R"objc(
+    @interface Foo
+    + (id)^fooWithValue:(int)value fooey:(unsigned int)fooey;
+    @end
+  )objc");
+}
+
+TEST_F(AddDoxygenCommentTest, ApplyTemplate) {
+  EXPECT_EQ(apply(R"cpp(
+template<class T>
+void foo^(T x) {})cpp"),
+            R"cpp(
+/// TODO Add description
+///
+/// @param x
+///
+template<class T>
+void foo(T x) {})cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, ApplyObjCIdReturn) {
+  FileName = "TestTU.m";
+  EXPECT_EQ(apply(R"objc(
+@interface Foo
++ (id)^fooWithValue:(int)value fooey:(unsigned int)fooey;
+@end)objc"),
+            R"objc(
+@interface Foo
+/// TODO Add description
+///
+/// @param value
+/// @param fooey
+///
++ (id)fooWithValue:(int)value fooey:(unsigned int)fooey;
+@end)objc");
+}
+TEST_F(AddDoxygenCommentTest, ApplyObjCNonIdReturn) {
+  FileName = "TestTU.m";
+  EXPECT_EQ(apply(R"objc(
+@interface Foo
++ (int)^fooWithValue:(int)value fooey:(unsigned int)fooey;
+@end)objc"),
+            R"objc(
+@interface Foo
+/// TODO Add description
+///
+/// @param value
+/// @param fooey
+/// @return
+///
++ (int)fooWithValue:(int)value fooey:(unsigned int)fooey;
+@end)objc");
+}
+
+TEST_F(AddDoxygenCommentTest, ApplyInsideNS) {
+  EXPECT_EQ(apply(R"cpp(
+namespace ns1 {
+  int foo^(int y, char* s) {
+    int x;
+    return x;
+  }
+}
+  )cpp"),
+            R"cpp(
+namespace ns1 {
+  /// TODO Add description
+///
+/// @param y
+/// @param s
+/// @return
+///
+int foo(int y, char* s) {
+    int x;
+    return x;
+  }
+}
+  )cpp");
+}
+
+TEST_F(AddDoxygenCommentTest, ApplyInsideTU) {
+  EXPECT_EQ(apply(R"cpp(
+void foo();
+void ^bar();
+)cpp"),
+            R"cpp(
+void foo();
+/// TODO Add description
+///
+///
+void bar();
+)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
@@ -113,6 +113,7 @@
   support/ThreadingTests.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,148 @@
+//===--- 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/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include <variant>
+
+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
+//   /// TODO Add description
+//   /// @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:
+  std::variant<FunctionDecl const *, ObjCMethodDecl const *> D;
+  std::string buildCommentCode() const;
+};
+
+REGISTER_TWEAK(AddDoxygenComment)
+
+std::string AddDoxygenComment::title() const {
+  return "Add documentation comment";
+}
+
+bool AddDoxygenComment::prepare(const Selection &Inputs) {
+  if (auto *N = Inputs.ASTSelection.commonAncestor()) {
+    if (const FunctionDecl *FD = N->ASTNode.get<FunctionDecl>()) {
+      if (FD->getASTContext().getRawCommentForDeclNoCache(FD)) {
+        return false;
+      }
+      const FunctionDecl *Def;
+      // we are at the definition, but there was a previous declaration
+      // do not suggest a tweak as it is wrong to suggest it not in the header
+      if (FD->isDefined(Def) && FD == Def && FD->getPreviousDecl() != nullptr) {
+        return false;
+      }
+      // no tweak for user defined deduction guide
+      if (llvm::dyn_cast<CXXDeductionGuideDecl>(FD) != nullptr) {
+        return false;
+      }
+      this->D = FD;
+      return true;
+    }
+    if (const ObjCMethodDecl *MD = N->ASTNode.get<ObjCMethodDecl>()) {
+      if (MD->getASTContext().getRawCommentForDeclNoCache(MD)) {
+        return false;
+      }
+      this->D = MD;
+      return true;
+    }
+  }
+  return false;
+}
+
+template <class... Ts> struct Overloaded : Ts... {
+  using Ts::operator()...;
+};
+template <class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;
+
+std::string AddDoxygenComment::buildCommentCode() const {
+  std::string Res;
+  llvm::raw_string_ostream OS(Res);
+  OS << "/// TODO Add description\n///\n";
+  auto PrintParams = [&OS](llvm::ArrayRef<clang::ParmVarDecl *> Params,
+                           QualType Ret) {
+    for (auto const *P : Params) {
+      if (auto PN = P->getName(); PN.empty()) {
+        continue;
+      }
+      OS << "/// @param " << P->getName() << '\n';
+    }
+    if (auto const *RT = Ret.getTypePtr()) {
+      if (!RT->isVoidType() && !RT->isObjCIdType()) {
+        OS << "/// @return\n";
+      }
+    }
+  };
+  std::visit(Overloaded{[&PrintParams](const FunctionDecl *FD) {
+                          PrintParams(FD->parameters(), FD->getReturnType());
+                        },
+                        [&PrintParams](const ObjCMethodDecl *MD) {
+                          PrintParams(MD->parameters(), MD->getReturnType());
+                        }},
+             D);
+  OS << "///\n";
+  return Res;
+}
+
+Expected<Tweak::Effect> AddDoxygenComment::apply(const Selection &Inputs) {
+  auto &SrcMgr = Inputs.AST->getSourceManager();
+  auto SrcRange = std::visit(
+      Overloaded{[](const FunctionDecl *FD) {
+                   if (const auto *T = FD->getDescribedFunctionTemplate()) {
+                     return T->getSourceRange();
+                   }
+                   return FD->getSourceRange();
+                 },
+                 [](const ObjCMethodDecl *MD) { return MD->getSourceRange(); }},
+      D);
+  const tooling::Replacement InsertDocComment(SrcMgr, SrcRange.getBegin(), 0,
+                                              buildCommentCode());
+  return Effect::mainFileEdit(
+      SrcMgr, tooling::Replacements{std::move(InsertDocComment)});
+}
+} // 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