[clang-tools-extra] [clangd] Add tweak to abbreviate function templates (PR #74710)

2023-12-07 Thread Jeremy Stucki via cfe-commits

https://github.com/jeremystucki created 
https://github.com/llvm/llvm-project/pull/74710

# Description

This introduces a new refactoring for function templates. It converts them to 
their abbreviated form using auto parameters.

Here is an example of what it does:

**Before**
```cpp
template 
void foo(T, U, V... params);
```
**After**
```cpp
void foo(auto, std::integral auto, auto... params);
```

# Demo

[Screencast from 2023-12-07 
10-44-46.webm](https://github.com/sa-concept-refactoring/llvm-project/assets/7629727/8d5f2bf1-03ce-4644-9311-1b3942594adc)


>From b0507f05e5b2fa4d840757b8d7fce1b60df626ec Mon Sep 17 00:00:00 2001
From: Jeremy Stucki 
Date: Fri, 27 Oct 2023 16:33:13 +0200
Subject: [PATCH] [clangd] Add tweak to abbreviate function templates

Co-authored-by: Vina Zahnd 
---
 .../tweaks/AbbreviateFunctionTemplate.cpp | 352 ++
 .../clangd/refactor/tweaks/CMakeLists.txt |   1 +
 .../clangd/unittests/CMakeLists.txt   |   1 +
 .../AbbreviateFunctionTemplateTests.cpp   |  76 
 clang-tools-extra/docs/ReleaseNotes.rst   |   3 +
 5 files changed, 433 insertions(+)
 create mode 100644 
clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
 create mode 100644 
clang-tools-extra/clangd/unittests/tweaks/AbbreviateFunctionTemplateTests.cpp

diff --git 
a/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
new file mode 100644
index 0..a2cfc6e13b01f
--- /dev/null
+++ b/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
@@ -0,0 +1,352 @@
+//===-- AbbreviateFunctionTemplate.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 "FindTarget.h"
+#include "SourceCode.h"
+#include "XRefs.h"
+#include "refactor/Tweak.h"
+#include "support/Logger.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include 
+
+namespace clang {
+namespace clangd {
+namespace {
+/// Converts a function template to its abbreviated form using auto parameters.
+/// Before:
+/// template 
+/// auto foo(T param) { }
+///  ^^^
+/// After:
+/// auto foo(std::integral auto param) { }
+class AbbreviateFunctionTemplate : public Tweak {
+public:
+  const char *id() const final;
+
+  auto prepare(const Selection &Inputs) -> bool override;
+  auto apply(const Selection &Inputs) -> Expected override;
+
+  auto title() const -> std::string override {
+return llvm::formatv("Abbreviate function template");
+  }
+
+  auto kind() const -> llvm::StringLiteral override {
+return CodeAction::REFACTOR_KIND;
+  }
+
+private:
+  static const char *AutoKeywordSpelling;
+  const FunctionTemplateDecl *FunctionTemplateDeclaration;
+
+  struct TemplateParameterInfo {
+const TypeConstraint *Constraint;
+unsigned int FunctionParameterIndex;
+std::vector FunctionParameterQualifiers;
+std::vector FunctionParameterTypeQualifiers;
+  };
+
+  std::vector TemplateParameterInfoList;
+
+  auto traverseFunctionParameters(size_t NumberOfTemplateParameters) -> bool;
+
+  auto generateFunctionParameterReplacements(const ASTContext &Context)
+  -> llvm::Expected;
+
+  auto generateFunctionParameterReplacement(
+  const TemplateParameterInfo &TemplateParameterInfo,
+  const ASTContext &Context) -> llvm::Expected;
+
+  auto generateTemplateDeclarationReplacement(const ASTContext &Context)
+  -> llvm::Expected;
+
+  static auto deconstructType(QualType Type)
+  -> std::tuple,
+std::vector>;
+};
+
+REGISTER_TWEAK(AbbreviateFunctionTemplate)
+
+const char *AbbreviateFunctionTemplate::AutoKeywordSpelling =
+getKeywordSpelling(tok::kw_auto);
+
+template 
+auto findDeclaration(const SelectionTree::Node &Root) -> const T * {
+  for (const auto *Node = &Root; Node; Node = Node->Parent) {
+if (const T *Result = dyn_cast_or_null(Node->ASTNode.get()))
+  return Result;
+  }
+
+  return nullptr;
+}
+
+auto getSpellingForQualifier(tok::TokenKind const &Qualifier) -> const char * {
+  if (const auto *Spelling = getKeywordSpelling(Qualifier))
+return Spelling;
+
+  if (const auto *Spelling = getPunctuatorSpelling(Qualifier))
+return Spelling;
+
+  return nullptr;
+}
+
+bool AbbreviateFunctionTemplate::prepare(const Selection &Inputs) {
+  const auto *CommonAncestor = Inputs.ASTSelection.commonAncestor();
+  if (!CommonAncestor)
+return false;
+
+  FunctionTemplateDeclaration =
+  findDeclaration(*CommonAncestor);
+
+  if (!Function

[clang-tools-extra] [clangd] Add tweak to abbreviate function templates (PR #74710)

2023-12-07 Thread Jeremy Stucki via cfe-commits

https://github.com/jeremystucki updated 
https://github.com/llvm/llvm-project/pull/74710

>From b3ae4235ccca0b2c859b33f7d12ee7940daabd1a Mon Sep 17 00:00:00 2001
From: Jeremy Stucki 
Date: Fri, 27 Oct 2023 16:33:13 +0200
Subject: [PATCH] [clangd] Add tweak to abbreviate function templates

Co-authored-by: Vina Zahnd 
---
 .../tweaks/AbbreviateFunctionTemplate.cpp | 352 ++
 .../clangd/refactor/tweaks/CMakeLists.txt |   1 +
 .../clangd/unittests/CMakeLists.txt   |   1 +
 .../AbbreviateFunctionTemplateTests.cpp   |  76 
 clang-tools-extra/docs/ReleaseNotes.rst   |   3 +
 5 files changed, 433 insertions(+)
 create mode 100644 
clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
 create mode 100644 
clang-tools-extra/clangd/unittests/tweaks/AbbreviateFunctionTemplateTests.cpp

diff --git 
a/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
new file mode 100644
index 0..a2cfc6e13b01f
--- /dev/null
+++ b/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
@@ -0,0 +1,352 @@
+//===-- AbbreviateFunctionTemplate.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 "FindTarget.h"
+#include "SourceCode.h"
+#include "XRefs.h"
+#include "refactor/Tweak.h"
+#include "support/Logger.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include 
+
+namespace clang {
+namespace clangd {
+namespace {
+/// Converts a function template to its abbreviated form using auto parameters.
+/// Before:
+/// template 
+/// auto foo(T param) { }
+///  ^^^
+/// After:
+/// auto foo(std::integral auto param) { }
+class AbbreviateFunctionTemplate : public Tweak {
+public:
+  const char *id() const final;
+
+  auto prepare(const Selection &Inputs) -> bool override;
+  auto apply(const Selection &Inputs) -> Expected override;
+
+  auto title() const -> std::string override {
+return llvm::formatv("Abbreviate function template");
+  }
+
+  auto kind() const -> llvm::StringLiteral override {
+return CodeAction::REFACTOR_KIND;
+  }
+
+private:
+  static const char *AutoKeywordSpelling;
+  const FunctionTemplateDecl *FunctionTemplateDeclaration;
+
+  struct TemplateParameterInfo {
+const TypeConstraint *Constraint;
+unsigned int FunctionParameterIndex;
+std::vector FunctionParameterQualifiers;
+std::vector FunctionParameterTypeQualifiers;
+  };
+
+  std::vector TemplateParameterInfoList;
+
+  auto traverseFunctionParameters(size_t NumberOfTemplateParameters) -> bool;
+
+  auto generateFunctionParameterReplacements(const ASTContext &Context)
+  -> llvm::Expected;
+
+  auto generateFunctionParameterReplacement(
+  const TemplateParameterInfo &TemplateParameterInfo,
+  const ASTContext &Context) -> llvm::Expected;
+
+  auto generateTemplateDeclarationReplacement(const ASTContext &Context)
+  -> llvm::Expected;
+
+  static auto deconstructType(QualType Type)
+  -> std::tuple,
+std::vector>;
+};
+
+REGISTER_TWEAK(AbbreviateFunctionTemplate)
+
+const char *AbbreviateFunctionTemplate::AutoKeywordSpelling =
+getKeywordSpelling(tok::kw_auto);
+
+template 
+auto findDeclaration(const SelectionTree::Node &Root) -> const T * {
+  for (const auto *Node = &Root; Node; Node = Node->Parent) {
+if (const T *Result = dyn_cast_or_null(Node->ASTNode.get()))
+  return Result;
+  }
+
+  return nullptr;
+}
+
+auto getSpellingForQualifier(tok::TokenKind const &Qualifier) -> const char * {
+  if (const auto *Spelling = getKeywordSpelling(Qualifier))
+return Spelling;
+
+  if (const auto *Spelling = getPunctuatorSpelling(Qualifier))
+return Spelling;
+
+  return nullptr;
+}
+
+bool AbbreviateFunctionTemplate::prepare(const Selection &Inputs) {
+  const auto *CommonAncestor = Inputs.ASTSelection.commonAncestor();
+  if (!CommonAncestor)
+return false;
+
+  FunctionTemplateDeclaration =
+  findDeclaration(*CommonAncestor);
+
+  if (!FunctionTemplateDeclaration)
+return false;
+
+  auto *TemplateParameters =
+  FunctionTemplateDeclaration->getTemplateParameters();
+
+  auto NumberOfTemplateParameters = TemplateParameters->size();
+  TemplateParameterInfoList =
+  std::vector(NumberOfTemplateParameters);
+
+  // Check how many times each template parameter is referenced.
+  // Depending on the number of references it can be checked
+  // if the refactoring is possible:
+  // - exactly one: The tem

[clang-tools-extra] [clangd] Add tweak to abbreviate function templates (PR #74710)

2023-12-07 Thread Jeremy Stucki via cfe-commits

https://github.com/jeremystucki updated 
https://github.com/llvm/llvm-project/pull/74710

>From b0b22b716bfc60274814cedc82c237d13477869c Mon Sep 17 00:00:00 2001
From: Jeremy Stucki 
Date: Fri, 27 Oct 2023 16:33:13 +0200
Subject: [PATCH] [clangd] Add tweak to abbreviate function templates

Co-authored-by: Vina Zahnd 
---
 .../tweaks/AbbreviateFunctionTemplate.cpp | 352 ++
 .../clangd/refactor/tweaks/CMakeLists.txt |   1 +
 .../clangd/unittests/CMakeLists.txt   |   1 +
 .../AbbreviateFunctionTemplateTests.cpp   |  76 
 clang-tools-extra/docs/ReleaseNotes.rst   |   3 +
 5 files changed, 433 insertions(+)
 create mode 100644 
clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
 create mode 100644 
clang-tools-extra/clangd/unittests/tweaks/AbbreviateFunctionTemplateTests.cpp

diff --git 
a/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
new file mode 100644
index 0..a2cfc6e13b01f
--- /dev/null
+++ b/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
@@ -0,0 +1,352 @@
+//===-- AbbreviateFunctionTemplate.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 "FindTarget.h"
+#include "SourceCode.h"
+#include "XRefs.h"
+#include "refactor/Tweak.h"
+#include "support/Logger.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include 
+
+namespace clang {
+namespace clangd {
+namespace {
+/// Converts a function template to its abbreviated form using auto parameters.
+/// Before:
+/// template 
+/// auto foo(T param) { }
+///  ^^^
+/// After:
+/// auto foo(std::integral auto param) { }
+class AbbreviateFunctionTemplate : public Tweak {
+public:
+  const char *id() const final;
+
+  auto prepare(const Selection &Inputs) -> bool override;
+  auto apply(const Selection &Inputs) -> Expected override;
+
+  auto title() const -> std::string override {
+return llvm::formatv("Abbreviate function template");
+  }
+
+  auto kind() const -> llvm::StringLiteral override {
+return CodeAction::REFACTOR_KIND;
+  }
+
+private:
+  static const char *AutoKeywordSpelling;
+  const FunctionTemplateDecl *FunctionTemplateDeclaration;
+
+  struct TemplateParameterInfo {
+const TypeConstraint *Constraint;
+unsigned int FunctionParameterIndex;
+std::vector FunctionParameterQualifiers;
+std::vector FunctionParameterTypeQualifiers;
+  };
+
+  std::vector TemplateParameterInfoList;
+
+  auto traverseFunctionParameters(size_t NumberOfTemplateParameters) -> bool;
+
+  auto generateFunctionParameterReplacements(const ASTContext &Context)
+  -> llvm::Expected;
+
+  auto generateFunctionParameterReplacement(
+  const TemplateParameterInfo &TemplateParameterInfo,
+  const ASTContext &Context) -> llvm::Expected;
+
+  auto generateTemplateDeclarationReplacement(const ASTContext &Context)
+  -> llvm::Expected;
+
+  static auto deconstructType(QualType Type)
+  -> std::tuple,
+std::vector>;
+};
+
+REGISTER_TWEAK(AbbreviateFunctionTemplate)
+
+const char *AbbreviateFunctionTemplate::AutoKeywordSpelling =
+getKeywordSpelling(tok::kw_auto);
+
+template 
+auto findDeclaration(const SelectionTree::Node &Root) -> const T * {
+  for (const auto *Node = &Root; Node; Node = Node->Parent) {
+if (const T *Result = dyn_cast_or_null(Node->ASTNode.get()))
+  return Result;
+  }
+
+  return nullptr;
+}
+
+auto getSpellingForQualifier(tok::TokenKind const &Qualifier) -> const char * {
+  if (const auto *Spelling = getKeywordSpelling(Qualifier))
+return Spelling;
+
+  if (const auto *Spelling = getPunctuatorSpelling(Qualifier))
+return Spelling;
+
+  return nullptr;
+}
+
+bool AbbreviateFunctionTemplate::prepare(const Selection &Inputs) {
+  const auto *CommonAncestor = Inputs.ASTSelection.commonAncestor();
+  if (!CommonAncestor)
+return false;
+
+  FunctionTemplateDeclaration =
+  findDeclaration(*CommonAncestor);
+
+  if (!FunctionTemplateDeclaration)
+return false;
+
+  auto *TemplateParameters =
+  FunctionTemplateDeclaration->getTemplateParameters();
+
+  auto NumberOfTemplateParameters = TemplateParameters->size();
+  TemplateParameterInfoList =
+  std::vector(NumberOfTemplateParameters);
+
+  // Check how many times each template parameter is referenced.
+  // Depending on the number of references it can be checked
+  // if the refactoring is possible:
+  // - exactly one: The tem

[clang-tools-extra] [clangd] Add tweak to abbreviate function templates (PR #74710)

2023-12-07 Thread Jeremy Stucki via cfe-commits

https://github.com/jeremystucki updated 
https://github.com/llvm/llvm-project/pull/74710

>From 64573476024103cf94f6cfc690e5396a368fc3df Mon Sep 17 00:00:00 2001
From: Jeremy Stucki 
Date: Fri, 27 Oct 2023 16:33:13 +0200
Subject: [PATCH] [clangd] Add tweak to abbreviate function templates

Co-authored-by: Vina Zahnd 
---
 .../tweaks/AbbreviateFunctionTemplate.cpp | 352 ++
 .../clangd/refactor/tweaks/CMakeLists.txt |   1 +
 .../clangd/unittests/CMakeLists.txt   |   1 +
 .../AbbreviateFunctionTemplateTests.cpp   |  76 
 clang-tools-extra/docs/ReleaseNotes.rst   |   3 +
 5 files changed, 433 insertions(+)
 create mode 100644 
clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
 create mode 100644 
clang-tools-extra/clangd/unittests/tweaks/AbbreviateFunctionTemplateTests.cpp

diff --git 
a/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
new file mode 100644
index 0..a2cfc6e13b01f
--- /dev/null
+++ b/clang-tools-extra/clangd/refactor/tweaks/AbbreviateFunctionTemplate.cpp
@@ -0,0 +1,352 @@
+//===-- AbbreviateFunctionTemplate.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 "FindTarget.h"
+#include "SourceCode.h"
+#include "XRefs.h"
+#include "refactor/Tweak.h"
+#include "support/Logger.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include 
+
+namespace clang {
+namespace clangd {
+namespace {
+/// Converts a function template to its abbreviated form using auto parameters.
+/// Before:
+/// template 
+/// auto foo(T param) { }
+///  ^^^
+/// After:
+/// auto foo(std::integral auto param) { }
+class AbbreviateFunctionTemplate : public Tweak {
+public:
+  const char *id() const final;
+
+  auto prepare(const Selection &Inputs) -> bool override;
+  auto apply(const Selection &Inputs) -> Expected override;
+
+  auto title() const -> std::string override {
+return llvm::formatv("Abbreviate function template");
+  }
+
+  auto kind() const -> llvm::StringLiteral override {
+return CodeAction::REFACTOR_KIND;
+  }
+
+private:
+  static const char *AutoKeywordSpelling;
+  const FunctionTemplateDecl *FunctionTemplateDeclaration;
+
+  struct TemplateParameterInfo {
+const TypeConstraint *Constraint;
+unsigned int FunctionParameterIndex;
+std::vector FunctionParameterQualifiers;
+std::vector FunctionParameterTypeQualifiers;
+  };
+
+  std::vector TemplateParameterInfoList;
+
+  auto traverseFunctionParameters(size_t NumberOfTemplateParameters) -> bool;
+
+  auto generateFunctionParameterReplacements(const ASTContext &Context)
+  -> llvm::Expected;
+
+  auto generateFunctionParameterReplacement(
+  const TemplateParameterInfo &TemplateParameterInfo,
+  const ASTContext &Context) -> llvm::Expected;
+
+  auto generateTemplateDeclarationReplacement(const ASTContext &Context)
+  -> llvm::Expected;
+
+  static auto deconstructType(QualType Type)
+  -> std::tuple,
+std::vector>;
+};
+
+REGISTER_TWEAK(AbbreviateFunctionTemplate)
+
+const char *AbbreviateFunctionTemplate::AutoKeywordSpelling =
+getKeywordSpelling(tok::kw_auto);
+
+template 
+auto findDeclaration(const SelectionTree::Node &Root) -> const T * {
+  for (const auto *Node = &Root; Node; Node = Node->Parent) {
+if (const T *Result = dyn_cast_or_null(Node->ASTNode.get()))
+  return Result;
+  }
+
+  return nullptr;
+}
+
+auto getSpellingForQualifier(tok::TokenKind const &Qualifier) -> const char * {
+  if (const auto *Spelling = getKeywordSpelling(Qualifier))
+return Spelling;
+
+  if (const auto *Spelling = getPunctuatorSpelling(Qualifier))
+return Spelling;
+
+  return nullptr;
+}
+
+bool AbbreviateFunctionTemplate::prepare(const Selection &Inputs) {
+  const auto *CommonAncestor = Inputs.ASTSelection.commonAncestor();
+  if (!CommonAncestor)
+return false;
+
+  FunctionTemplateDeclaration =
+  findDeclaration(*CommonAncestor);
+
+  if (!FunctionTemplateDeclaration)
+return false;
+
+  auto *TemplateParameters =
+  FunctionTemplateDeclaration->getTemplateParameters();
+
+  auto NumberOfTemplateParameters = TemplateParameters->size();
+  TemplateParameterInfoList =
+  std::vector(NumberOfTemplateParameters);
+
+  // Check how many times each template parameter is referenced.
+  // Depending on the number of references it can be checked
+  // if the refactoring is possible:
+  // - exactly one: The tem