[clang-tools-extra] [clangd] Let DefineOutline tweak handle member functions (PR #95235)

2024-06-12 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler created 
https://github.com/llvm/llvm-project/pull/95235

... of class templates.

>From fc3a907ab2550a999801d37400268fdc31df054d Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Tue, 14 Nov 2023 16:35:46 +0100
Subject: [PATCH] [clangd] Let DefineOutline tweak handle member functions

... of class templates.
---
 clang-tools-extra/clangd/AST.cpp  |  7 ++-
 .../clangd/refactor/tweaks/DefineOutline.cpp  | 47 ++--
 .../unittests/tweaks/DefineOutlineTests.cpp   | 55 ++-
 3 files changed, 89 insertions(+), 20 deletions(-)

diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index fda1e5fdf8d82..2f2f8437d6ed9 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -144,8 +144,13 @@ getQualification(ASTContext , const DeclContext 
*DestContext,
   // since we stored inner-most parent first.
   std::string Result;
   llvm::raw_string_ostream OS(Result);
-  for (const auto *Parent : llvm::reverse(Parents))
+  for (const auto *Parent : llvm::reverse(Parents)) {
+if (Parent != *Parents.rbegin() && Parent->isDependent() &&
+Parent->getAsRecordDecl() &&
+Parent->getAsRecordDecl()->getDescribedClassTemplate())
+  OS << "template ";
 Parent->print(OS, Context.getPrintingPolicy());
+  }
   return OS.str();
 }
 
diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
index f43f2417df8fc..15cb586e6c21e 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
@@ -128,7 +128,27 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD,
   SM.getBufferData(SM.getMainFileID()), Replacements);
   if (!QualifiedFunc)
 return QualifiedFunc.takeError();
-  return QualifiedFunc->substr(FuncBegin, FuncEnd - FuncBegin + 1);
+
+  std::string TemplatePrefix;
+  if (auto *MD = llvm::dyn_cast(FD)) {
+for (const CXXRecordDecl *Parent = MD->getParent(); Parent;
+ Parent =
+ llvm::dyn_cast_or_null(Parent->getParent())) 
{
+  if (auto Params = Parent->getDescribedTemplateParams()) {
+std::string S;
+llvm::raw_string_ostream Stream(S);
+Params->print(Stream, FD->getASTContext());
+if (!S.empty())
+  *S.rbegin() = '\n'; // Replace space with newline
+TemplatePrefix.insert(0, S);
+  }
+}
+  }
+
+  auto Source = QualifiedFunc->substr(FuncBegin, FuncEnd - FuncBegin + 1);
+  if (!TemplatePrefix.empty())
+Source.insert(0, TemplatePrefix);
+  return Source;
 }
 
 // Returns replacements to delete tokens with kind `Kind` in the range
@@ -212,9 +232,13 @@ getFunctionSourceCode(const FunctionDecl *FD, const 
DeclContext *TargetContext,
   }
 }
 const NamedDecl *ND = Ref.Targets.front();
-const std::string Qualifier =
+std::string Qualifier =
 getQualification(AST, TargetContext,
  SM.getLocForStartOfFile(SM.getMainFileID()), ND);
+if (ND->getDeclContext()->isDependentContext()) {
+  if (llvm::isa(ND))
+Qualifier.insert(0, "typename ");
+}
 if (auto Err = DeclarationCleanups.add(
 tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier)))
   Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
@@ -407,10 +431,21 @@ class DefineOutline : public Tweak {
   return !SameFile;
 }
 
-// Bail out in templated classes, as it is hard to spell the class name,
-// i.e if the template parameter is unnamed.
-if (MD->getParent()->isTemplated())
-  return false;
+for (const CXXRecordDecl *Parent = MD->getParent(); Parent;
+ Parent =
+ llvm::dyn_cast_or_null(Parent->getParent())) 
{
+  if (auto Params = Parent->getDescribedTemplateParams()) {
+
+// Class template member functions must be defined in the
+// same file.
+SameFile = true;
+
+for (NamedDecl *P : *Params) {
+  if (!P->getIdentifier())
+return false;
+}
+  }
+}
 
 // The refactoring is meaningless for unnamed classes and namespaces,
 // unless we're outlining in the same file
diff --git a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp 
b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp
index 906ff33db8734..6a9e90c3bfa70 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp
@@ -105,8 +105,8 @@ TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) {
   F^oo(const Foo&) = delete;
 };)cpp");
 
-  // Not available within templated classes, as it is hard to spell class name
-  // out-of-line in such cases.
+  // Not available within templated classes with unnamed parameters, as it is
+  // hard 

[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2024-06-03 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler closed 
https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2024-06-03 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

I'm going to merge this without explicit format approval based on the following:
  - There was a general LGTM.
  - I addressed the remaining issues.
  - There was no further feedback for more than half a year.

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Support callHierarchy/outgoingCalls (PR #91191)

2024-05-07 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

> If I'm understanding correctly, the implementation approach in this PR only 
> finds callees in the current translation 
> unit.
> The approach in #77556 uses the project's index to find callees across 
> translation unit boundaries.

Right, that's obviously nicer.

> Regarding reviews: yes, it seems quite unfortunate that the original 
> developers seem to have largely moved on to 
> other things. I will do my best to make some progress of the project's review 
> backlog (including in particular 
> #86629 and #67802) as time permits.

Your work is highly appreciated, but I don't think it's reasonable to expect a 
single unpaid contributor to maintain the entire project, as appears to be the 
case right now.



https://github.com/llvm/llvm-project/pull/91191
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Support callHierarchy/outgoingCalls (PR #91191)

2024-05-06 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

> I remembered @HighCommander4 had filed a similar PR at #77556. Is this one 
> separate, or are they actually the same (i.e. both are salvaged from 
> https://reviews.llvm.org/D93829)?

I didn't know about that one. Seems nothing gets reviewed anymore these days.

https://github.com/llvm/llvm-project/pull/91191
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Support callHierarchy/outgoingCalls (PR #91191)

2024-05-06 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler closed 
https://github.com/llvm/llvm-project/pull/91191
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Support callHierarchy/outgoingCalls (PR #91191)

2024-05-06 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler created 
https://github.com/llvm/llvm-project/pull/91191

None

>From d7cfeb6599fd507eed8935e452efd782fc3f0481 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Tue, 30 Apr 2024 18:20:05 +0200
Subject: [PATCH] [clangd] Support callHierarchy/outgoingCalls

---
 clang-tools-extra/clangd/ClangdLSPServer.cpp  |   7 +
 clang-tools-extra/clangd/ClangdLSPServer.h|   3 +
 clang-tools-extra/clangd/ClangdServer.cpp |  13 +
 clang-tools-extra/clangd/ClangdServer.h   |   4 +
 clang-tools-extra/clangd/XRefs.cpp|  71 ++
 clang-tools-extra/clangd/XRefs.h  |   3 +
 .../clangd/unittests/CallHierarchyTests.cpp   | 226 +++---
 7 files changed, 293 insertions(+), 34 deletions(-)

diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp 
b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 7fd599d4e1a0b0..5820a644088e3e 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -1368,6 +1368,12 @@ void ClangdLSPServer::onCallHierarchyIncomingCalls(
   Server->incomingCalls(Params.item, std::move(Reply));
 }
 
+void ClangdLSPServer::onCallHierarchyOutgoingCalls(
+const CallHierarchyOutgoingCallsParams ,
+Callback> Reply) {
+  Server->outgoingCalls(Params.item, std::move(Reply));
+}
+
 void ClangdLSPServer::onClangdInlayHints(const InlayHintsParams ,
  Callback Reply) {
   // Our extension has a different representation on the wire than the 
standard.
@@ -1688,6 +1694,7 @@ void ClangdLSPServer::bindMethods(LSPBinder ,
   Bind.method("typeHierarchy/subtypes", this, ::onSubTypes);
   Bind.method("textDocument/prepareCallHierarchy", this, 
::onPrepareCallHierarchy);
   Bind.method("callHierarchy/incomingCalls", this, 
::onCallHierarchyIncomingCalls);
+  Bind.method("callHierarchy/outgoingCalls", this, 
::onCallHierarchyOutgoingCalls);
   Bind.method("textDocument/selectionRange", this, 
::onSelectionRange);
   Bind.method("textDocument/documentLink", this, 
::onDocumentLink);
   Bind.method("textDocument/semanticTokens/full", this, 
::onSemanticTokens);
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h 
b/clang-tools-extra/clangd/ClangdLSPServer.h
index 8bcb29522509b7..4981027372cb57 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.h
+++ b/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -153,6 +153,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks,
   void onCallHierarchyIncomingCalls(
   const CallHierarchyIncomingCallsParams &,
   Callback>);
+  void onCallHierarchyOutgoingCalls(
+  const CallHierarchyOutgoingCallsParams &,
+  Callback>);
   void onClangdInlayHints(const InlayHintsParams &,
   Callback);
   void onInlayHint(const InlayHintsParams &, Callback>);
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp 
b/clang-tools-extra/clangd/ClangdServer.cpp
index 1c4c2a79b5c051..19d01dfbd873e2 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -898,6 +898,19 @@ void ClangdServer::incomingCalls(
  });
 }
 
+void ClangdServer::outgoingCalls(
+const CallHierarchyItem ,
+Callback> CB) {
+  auto Action = [Item,
+ CB = std::move(CB)](Expected InpAST) mutable {
+if (!InpAST)
+  return CB(InpAST.takeError());
+CB(clangd::outgoingCalls(InpAST->AST, Item));
+  };
+  WorkScheduler->runWithAST("Outgoing Calls", Item.uri.file(),
+std::move(Action));
+}
+
 void ClangdServer::inlayHints(PathRef File, std::optional RestrictRange,
   Callback> CB) {
   auto Action = [RestrictRange(std::move(RestrictRange)),
diff --git a/clang-tools-extra/clangd/ClangdServer.h 
b/clang-tools-extra/clangd/ClangdServer.h
index 1661028be88b4e..4caef917c1ec16 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -288,6 +288,10 @@ class ClangdServer {
   void incomingCalls(const CallHierarchyItem ,
  Callback>);
 
+  /// Resolve outgoing calls for a given call hierarchy item.
+  void outgoingCalls(const CallHierarchyItem ,
+ Callback>);
+
   /// Resolve inlay hints for a given document.
   void inlayHints(PathRef File, std::optional RestrictRange,
   Callback>);
diff --git a/clang-tools-extra/clangd/XRefs.cpp 
b/clang-tools-extra/clangd/XRefs.cpp
index cd909266489a85..b9bf944a7bba98 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -42,6 +42,7 @@
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/Type.h"
+#include "clang/Analysis/CallGraph.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
@@ -2303,6 +2304,76 @@ incomingCalls(const CallHierarchyItem , const 
SymbolIndex *Index) {
   return Results;
 }
 

[clang] [clang-tools-extra] [clangd] Collect comments from function definitions into the index (PR #67802)

2024-05-02 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

ping

https://github.com/llvm/llvm-project/pull/67802
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2024-05-02 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

ping

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-05-02 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler closed 
https://github.com/llvm/llvm-project/pull/83412
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-05-02 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler reopened 
https://github.com/llvm/llvm-project/pull/83412
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-05-02 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler closed 
https://github.com/llvm/llvm-project/pull/83412
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-05-02 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

Underscore separators get removed now.

https://github.com/llvm/llvm-project/pull/83412
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-05-02 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler updated 
https://github.com/llvm/llvm-project/pull/83412

>From 349edc160e9c13068c42b35321814296bb713a09 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Thu, 29 Feb 2024 12:26:52 +0100
Subject: [PATCH] [clangd] Remove potential prefix from enum value names

... when converting unscoped to scoped enums.
With traditional enums, a popular technique to guard against potential
name clashes is to use the enum name as a pseudo-namespace, like this:
  enum MyEnum { MyEnumValue1, MyEnumValue2 };
With scoped enums, this makes no sense, making it extremely unlikely
that the user wants to keep such a prefix when modernizing. Therefore, our
tweak now removes it.
---
 .../clangd/refactor/tweaks/ScopifyEnum.cpp| 61 -
 .../unittests/tweaks/ScopifyEnumTests.cpp | 66 +--
 clang-tools-extra/docs/ReleaseNotes.rst   |  3 +
 3 files changed, 108 insertions(+), 22 deletions(-)

diff --git a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
index e36b3249bc7b92..2be2bbc422af75 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
@@ -40,15 +40,12 @@ namespace {
 ///   void f() { E e1 = EV1; }
 ///
 /// After:
-///   enum class E { EV1, EV2 };
-///   void f() { E e1 = E::EV1; }
+///   enum class E { V1, V2 };
+///   void f() { E e1 = E::V1; }
 ///
 /// Note that the respective project code might not compile anymore
 /// if it made use of the now-gone implicit conversion to int.
 /// This is out of scope for this tweak.
-///
-/// TODO: In the above example, we could detect that the values
-///   start with the enum name, and remove that prefix.
 
 class ScopifyEnum : public Tweak {
   const char *id() const final;
@@ -63,7 +60,8 @@ class ScopifyEnum : public Tweak {
   std::function;
   llvm::Error addClassKeywordToDeclarations();
   llvm::Error scopifyEnumValues();
-  llvm::Error scopifyEnumValue(const EnumConstantDecl , StringRef Prefix);
+  llvm::Error scopifyEnumValue(const EnumConstantDecl , StringRef EnumName,
+   bool StripPrefix);
   llvm::Expected getContentForFile(StringRef FilePath);
   unsigned getOffsetFromPosition(const Position , StringRef Content) const;
   llvm::Error addReplacementForReference(const ReferencesResult::Reference 
,
@@ -125,25 +123,45 @@ llvm::Error ScopifyEnum::addClassKeywordToDeclarations() {
 }
 
 llvm::Error ScopifyEnum::scopifyEnumValues() {
-  std::string PrefixToInsert(D->getName());
-  PrefixToInsert += "::";
-  for (auto E : D->enumerators()) {
-if (auto Err = scopifyEnumValue(*E, PrefixToInsert))
+  StringRef EnumName(D->getName());
+  bool StripPrefix = true;
+  for (const EnumConstantDecl *E : D->enumerators()) {
+if (!E->getName().starts_with(EnumName)) {
+  StripPrefix = false;
+  break;
+}
+  }
+  for (const EnumConstantDecl *E : D->enumerators()) {
+if (auto Err = scopifyEnumValue(*E, EnumName, StripPrefix))
   return Err;
   }
   return llvm::Error::success();
 }
 
 llvm::Error ScopifyEnum::scopifyEnumValue(const EnumConstantDecl ,
-  StringRef Prefix) {
+  StringRef EnumName,
+  bool StripPrefix) {
   for (const auto  :
findReferences(*S->AST, getPosition(CD), 0, S->Index, false)
.References) {
-if (Ref.Attributes & ReferencesResult::Declaration)
+if (Ref.Attributes & ReferencesResult::Declaration) {
+  if (StripPrefix) {
+const auto MakeReplacement = [](StringRef FilePath,
+ StringRef Content,
+ unsigned Offset) {
+  unsigned Length = EnumName.size();
+  if (Content[Offset + Length] == '_')
+++Length;
+  return tooling::Replacement(FilePath, Offset, Length, {});
+};
+if (auto Err = addReplacementForReference(Ref, MakeReplacement))
+  return Err;
+  }
   continue;
+}
 
-const auto MakeReplacement = [](StringRef FilePath,
-   StringRef Content, unsigned Offset) 
{
+const auto MakeReplacement = [&](StringRef FilePath, StringRef Content,
+ unsigned Offset) {
   const auto IsAlreadyScoped = [Content, Offset] {
 if (Offset < 2)
   return false;
@@ -164,9 +182,18 @@ llvm::Error ScopifyEnum::scopifyEnumValue(const 
EnumConstantDecl ,
 }
 return false;
   };
-  return IsAlreadyScoped()
- ? tooling::Replacement()
- : tooling::Replacement(FilePath, Offset, 0, Prefix);
+  if (StripPrefix) {
+const int ExtraLength =
+Content[Offset + EnumName.size()] == '_' ? 1 : 0;
+if (IsAlreadyScoped())
+ 

[clang-tools-extra] [clangd] Let DefineOutline tweak create a definition from scratch (PR #71950)

2024-04-18 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

We should probably rekindle the discussion on the associated bug report; I 
think users (rightly) expect this feature.

https://github.com/llvm/llvm-project/pull/71950
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] use existing function for code locations in the scopify enum tweak (PR #88737)

2024-04-15 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler approved this pull request.


https://github.com/llvm/llvm-project/pull/88737
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-04-15 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

Incorporated review comments.

https://github.com/llvm/llvm-project/pull/83412
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-04-15 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler updated 
https://github.com/llvm/llvm-project/pull/83412

>From 78393d26e62f2f9a30f366501f8e61b1a32d6af4 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Thu, 29 Feb 2024 12:26:52 +0100
Subject: [PATCH] [clangd] Remove potential prefix from enum value names

... when converting unscoped to scoped enums.
With traditional enums, a popular technique to guard against potential
name clashes is to use the enum name as a pseudo-namespace, like this:
  enum MyEnum { MyEnumValue1, MyEnumValue2 };
With scoped enums, this makes no sense, making it extremely unlikely
that the user wants to keep such a prefix when modernizing. Therefore, our
tweak now removes it.
---
 .../clangd/refactor/tweaks/ScopifyEnum.cpp| 55 +--
 .../unittests/tweaks/ScopifyEnumTests.cpp | 38 +++--
 clang-tools-extra/docs/ReleaseNotes.rst   |  3 +
 3 files changed, 74 insertions(+), 22 deletions(-)

diff --git a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
index e36b3249bc7b92..d44f2bb862ed07 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
@@ -40,15 +40,12 @@ namespace {
 ///   void f() { E e1 = EV1; }
 ///
 /// After:
-///   enum class E { EV1, EV2 };
-///   void f() { E e1 = E::EV1; }
+///   enum class E { V1, V2 };
+///   void f() { E e1 = E::V1; }
 ///
 /// Note that the respective project code might not compile anymore
 /// if it made use of the now-gone implicit conversion to int.
 /// This is out of scope for this tweak.
-///
-/// TODO: In the above example, we could detect that the values
-///   start with the enum name, and remove that prefix.
 
 class ScopifyEnum : public Tweak {
   const char *id() const final;
@@ -63,7 +60,8 @@ class ScopifyEnum : public Tweak {
   std::function;
   llvm::Error addClassKeywordToDeclarations();
   llvm::Error scopifyEnumValues();
-  llvm::Error scopifyEnumValue(const EnumConstantDecl , StringRef Prefix);
+  llvm::Error scopifyEnumValue(const EnumConstantDecl , StringRef EnumName,
+   bool StripPrefix);
   llvm::Expected getContentForFile(StringRef FilePath);
   unsigned getOffsetFromPosition(const Position , StringRef Content) const;
   llvm::Error addReplacementForReference(const ReferencesResult::Reference 
,
@@ -125,25 +123,42 @@ llvm::Error ScopifyEnum::addClassKeywordToDeclarations() {
 }
 
 llvm::Error ScopifyEnum::scopifyEnumValues() {
-  std::string PrefixToInsert(D->getName());
-  PrefixToInsert += "::";
-  for (auto E : D->enumerators()) {
-if (auto Err = scopifyEnumValue(*E, PrefixToInsert))
+  StringRef EnumName(D->getName());
+  bool StripPrefix = true;
+  for (const EnumConstantDecl *E : D->enumerators()) {
+if (!E->getName().starts_with(EnumName)) {
+  StripPrefix = false;
+  break;
+}
+  }
+  for (const EnumConstantDecl *E : D->enumerators()) {
+if (auto Err = scopifyEnumValue(*E, EnumName, StripPrefix))
   return Err;
   }
   return llvm::Error::success();
 }
 
 llvm::Error ScopifyEnum::scopifyEnumValue(const EnumConstantDecl ,
-  StringRef Prefix) {
+  StringRef EnumName,
+  bool StripPrefix) {
   for (const auto  :
findReferences(*S->AST, getPosition(CD), 0, S->Index, false)
.References) {
-if (Ref.Attributes & ReferencesResult::Declaration)
+if (Ref.Attributes & ReferencesResult::Declaration) {
+  if (StripPrefix) {
+const auto MakeReplacement = [](StringRef FilePath,
+ StringRef /* Content */,
+ unsigned Offset) {
+  return tooling::Replacement(FilePath, Offset, EnumName.size(), {});
+};
+if (auto Err = addReplacementForReference(Ref, MakeReplacement))
+  return Err;
+  }
   continue;
+}
 
-const auto MakeReplacement = [](StringRef FilePath,
-   StringRef Content, unsigned Offset) 
{
+const auto MakeReplacement = [&](StringRef FilePath, StringRef Content,
+ unsigned Offset) {
   const auto IsAlreadyScoped = [Content, Offset] {
 if (Offset < 2)
   return false;
@@ -164,9 +179,15 @@ llvm::Error ScopifyEnum::scopifyEnumValue(const 
EnumConstantDecl ,
 }
 return false;
   };
-  return IsAlreadyScoped()
- ? tooling::Replacement()
- : tooling::Replacement(FilePath, Offset, 0, Prefix);
+  if (StripPrefix) {
+if (IsAlreadyScoped())
+  return tooling::Replacement(FilePath, Offset, EnumName.size(), {});
+return tooling::Replacement(FilePath, Offset + EnumName.size(), 0,
+"::");
+  }

[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2024-04-08 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

ping

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clangd] Collect comments from function definitions into the index (PR #67802)

2024-04-08 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

ping

https://github.com/llvm/llvm-project/pull/67802
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Fix JSON conversion for symbol tags (PR #84747)

2024-03-11 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler created 
https://github.com/llvm/llvm-project/pull/84747

The wrong constructor of json::Value got called, making every tag an array 
instead of a number.

>From f67994902314acd8ae0f0c561b07b8c014172e17 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Mon, 11 Mar 2024 13:04:21 +0100
Subject: [PATCH] [clangd] Fix JSON conversion for symbol tags

The wrong constructor of json::Value got called, making every tag an
array instead of a number.
---
 clang-tools-extra/clangd/Protocol.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clangd/Protocol.cpp 
b/clang-tools-extra/clangd/Protocol.cpp
index 8aa18bb0058abe..c6553e00dcae28 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -1412,7 +1412,7 @@ bool fromJSON(const llvm::json::Value , 
ReferenceParams ,
 }
 
 llvm::json::Value toJSON(SymbolTag Tag) {
-  return llvm::json::Value{static_cast(Tag)};
+  return llvm::json::Value(static_cast(Tag));
 }
 
 llvm::json::Value toJSON(const CallHierarchyItem ) {

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2024-03-04 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

ping

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-03-01 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler updated 
https://github.com/llvm/llvm-project/pull/83412

>From 01f74ddece947755938ccecbcc5f9d18a41eb793 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Thu, 29 Feb 2024 12:26:52 +0100
Subject: [PATCH] [clangd] Remove potential prefix from enum value names

... when converting unscoped to scoped enums.
With traditional enums, a popular technique to guard against potential
name clashes is to use the enum name as a pseudo-namespace, like this:
  enum MyEnum { MyEnumValue1, MyEnumValue2 };
With scoped enums, this makes no sense, making it extremely unlikely
that the user wants to keep such a prefix when modernizing. Therefore, our
tweak now removes it.
---
 .../clangd/refactor/tweaks/ScopifyEnum.cpp| 53 +--
 .../unittests/tweaks/ScopifyEnumTests.cpp | 38 +++--
 2 files changed, 70 insertions(+), 21 deletions(-)

diff --git a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
index e36b3249bc7b92..8e13ae52d121a6 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
@@ -40,15 +40,12 @@ namespace {
 ///   void f() { E e1 = EV1; }
 ///
 /// After:
-///   enum class E { EV1, EV2 };
-///   void f() { E e1 = E::EV1; }
+///   enum class E { V1, V2 };
+///   void f() { E e1 = E::V1; }
 ///
 /// Note that the respective project code might not compile anymore
 /// if it made use of the now-gone implicit conversion to int.
 /// This is out of scope for this tweak.
-///
-/// TODO: In the above example, we could detect that the values
-///   start with the enum name, and remove that prefix.
 
 class ScopifyEnum : public Tweak {
   const char *id() const final;
@@ -63,7 +60,8 @@ class ScopifyEnum : public Tweak {
   std::function;
   llvm::Error addClassKeywordToDeclarations();
   llvm::Error scopifyEnumValues();
-  llvm::Error scopifyEnumValue(const EnumConstantDecl , StringRef Prefix);
+  llvm::Error scopifyEnumValue(const EnumConstantDecl , StringRef EnumName,
+   bool StripPrefix);
   llvm::Expected getContentForFile(StringRef FilePath);
   unsigned getOffsetFromPosition(const Position , StringRef Content) const;
   llvm::Error addReplacementForReference(const ReferencesResult::Reference 
,
@@ -125,25 +123,42 @@ llvm::Error ScopifyEnum::addClassKeywordToDeclarations() {
 }
 
 llvm::Error ScopifyEnum::scopifyEnumValues() {
-  std::string PrefixToInsert(D->getName());
-  PrefixToInsert += "::";
+  StringRef EnumName(D->getName());
+  bool StripPrefix = true;
+  for (auto E : D->enumerators()) {
+if (!E->getName().starts_with(EnumName)) {
+  StripPrefix = false;
+  break;
+}
+  }
   for (auto E : D->enumerators()) {
-if (auto Err = scopifyEnumValue(*E, PrefixToInsert))
+if (auto Err = scopifyEnumValue(*E, EnumName, StripPrefix))
   return Err;
   }
   return llvm::Error::success();
 }
 
 llvm::Error ScopifyEnum::scopifyEnumValue(const EnumConstantDecl ,
-  StringRef Prefix) {
+  StringRef EnumName,
+  bool StripPrefix) {
   for (const auto  :
findReferences(*S->AST, getPosition(CD), 0, S->Index, false)
.References) {
-if (Ref.Attributes & ReferencesResult::Declaration)
+if (Ref.Attributes & ReferencesResult::Declaration) {
+  if (StripPrefix) {
+const auto MakeReplacement = [](StringRef FilePath,
+ StringRef /* Content */,
+ unsigned Offset) {
+  return tooling::Replacement(FilePath, Offset, EnumName.size(), {});
+};
+if (auto Err = addReplacementForReference(Ref, MakeReplacement))
+  return Err;
+  }
   continue;
+}
 
-const auto MakeReplacement = [](StringRef FilePath,
-   StringRef Content, unsigned Offset) 
{
+const auto MakeReplacement = [&](StringRef FilePath, StringRef Content,
+ unsigned Offset) {
   const auto IsAlreadyScoped = [Content, Offset] {
 if (Offset < 2)
   return false;
@@ -164,9 +179,15 @@ llvm::Error ScopifyEnum::scopifyEnumValue(const 
EnumConstantDecl ,
 }
 return false;
   };
-  return IsAlreadyScoped()
- ? tooling::Replacement()
- : tooling::Replacement(FilePath, Offset, 0, Prefix);
+  if (StripPrefix) {
+if (IsAlreadyScoped())
+  return tooling::Replacement(FilePath, Offset, EnumName.size(), {});
+return tooling::Replacement(FilePath, Offset + EnumName.size(), 0,
+"::");
+  }
+  return IsAlreadyScoped() ? tooling::Replacement()
+   : tooling::Replacement(FilePath, Offset, 

[clang-tools-extra] [clangd] Remove potential prefix from enum value names (PR #83412)

2024-02-29 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler created 
https://github.com/llvm/llvm-project/pull/83412

... when converting unscoped to scoped enums.
With traditional enums, a popular technique to guard against potential name 
clashes is to use the enum name as a pseudo-namespace, like this:
  enum MyEnum { MyEnumValue1, MyEnumValue2 };
With scoped enums, this makes no sense, making it extremely unlikely that the 
user wants to keep such a prefix when modernizing. Therefore, our tweak now 
removes it.

>From c687b73939821eba285b35e50c241738ba7915e4 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Thu, 29 Feb 2024 12:26:52 +0100
Subject: [PATCH] [clangd] Remove potential prefix from enum value names

... when converting unscoped to scoped enums.
With traditional enums, a popular technique to guard against potential
name clashes is to use the enum name as a pseudo-namespace, like this:
  enum MyEnum { MyEnumValue1, MyEnumValue2 };
With scoped enums, this makes no sense, making it extremely unlikely
that the user wants to keep such a prefix when modernizing. Therefore, our
tweak now removes it.
---
 .../clangd/refactor/tweaks/ScopifyEnum.cpp| 49 +--
 .../unittests/tweaks/ScopifyEnumTests.cpp |  8 +--
 2 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
index e36b3249bc7b92..5c042ee7b782b9 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp
@@ -40,15 +40,12 @@ namespace {
 ///   void f() { E e1 = EV1; }
 ///
 /// After:
-///   enum class E { EV1, EV2 };
-///   void f() { E e1 = E::EV1; }
+///   enum class E { V1, V2 };
+///   void f() { E e1 = E::V1; }
 ///
 /// Note that the respective project code might not compile anymore
 /// if it made use of the now-gone implicit conversion to int.
 /// This is out of scope for this tweak.
-///
-/// TODO: In the above example, we could detect that the values
-///   start with the enum name, and remove that prefix.
 
 class ScopifyEnum : public Tweak {
   const char *id() const final;
@@ -63,7 +60,8 @@ class ScopifyEnum : public Tweak {
   std::function;
   llvm::Error addClassKeywordToDeclarations();
   llvm::Error scopifyEnumValues();
-  llvm::Error scopifyEnumValue(const EnumConstantDecl , StringRef Prefix);
+  llvm::Error scopifyEnumValue(const EnumConstantDecl , StringRef EnumName,
+   bool StripPrefix);
   llvm::Expected getContentForFile(StringRef FilePath);
   unsigned getOffsetFromPosition(const Position , StringRef Content) const;
   llvm::Error addReplacementForReference(const ReferencesResult::Reference 
,
@@ -125,25 +123,42 @@ llvm::Error ScopifyEnum::addClassKeywordToDeclarations() {
 }
 
 llvm::Error ScopifyEnum::scopifyEnumValues() {
-  std::string PrefixToInsert(D->getName());
-  PrefixToInsert += "::";
+  StringRef EnumName(D->getName());
+  bool StripPrefix = true;
+  for (auto E : D->enumerators()) {
+if (!E->getName().starts_with(EnumName)) {
+  StripPrefix = false;
+  break;
+}
+  }
   for (auto E : D->enumerators()) {
-if (auto Err = scopifyEnumValue(*E, PrefixToInsert))
+if (auto Err = scopifyEnumValue(*E, EnumName, StripPrefix))
   return Err;
   }
   return llvm::Error::success();
 }
 
 llvm::Error ScopifyEnum::scopifyEnumValue(const EnumConstantDecl ,
-  StringRef Prefix) {
+  StringRef EnumName,
+  bool StripPrefix) {
   for (const auto  :
findReferences(*S->AST, getPosition(CD), 0, S->Index, false)
.References) {
-if (Ref.Attributes & ReferencesResult::Declaration)
+if (Ref.Attributes & ReferencesResult::Declaration) {
+  if (StripPrefix) {
+const auto MakeReplacement = [](StringRef FilePath,
+ StringRef /* Content */,
+ unsigned Offset) {
+  return tooling::Replacement(FilePath, Offset, EnumName.size(), {});
+};
+if (auto Err = addReplacementForReference(Ref, MakeReplacement))
+  return Err;
+  }
   continue;
+}
 
-const auto MakeReplacement = [](StringRef FilePath,
-   StringRef Content, unsigned Offset) 
{
+const auto MakeReplacement = [&](StringRef FilePath, StringRef Content,
+ unsigned Offset) {
   const auto IsAlreadyScoped = [Content, Offset] {
 if (Offset < 2)
   return false;
@@ -164,9 +179,15 @@ llvm::Error ScopifyEnum::scopifyEnumValue(const 
EnumConstantDecl ,
 }
 return false;
   };
+  if (StripPrefix) {
+if (IsAlreadyScoped())
+  return tooling::Replacement(FilePath, Offset, EnumName.size(), {});
+

[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-02-19 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler closed 
https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-02-19 Thread Christian Kandeler via cfe-commits


@@ -490,6 +491,13 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
 BO->getRHS() == OuterImplicit.ASTNode.get())
   return false;
   }
+  if (const auto *Decl = Parent->ASTNode.get()) {
+if (!Decl->isInitCapture() &&

ckandeler wrote:

Note also that there are already (pre-existing) tests for such selections, e.g.:
```
  {R"cpp(void f() {
   int x = 1 + 2 + [[3 + 4 + 5]];
 })cpp",
   R"cpp(void f() {
   auto placeholder = 3 + 4 + 5; int x = 1 + 2 + placeholder;
 })cpp"},
```

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-02-19 Thread Christian Kandeler via cfe-commits


@@ -490,6 +491,13 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
 BO->getRHS() == OuterImplicit.ASTNode.get())
   return false;
   }
+  if (const auto *Decl = Parent->ASTNode.get()) {
+if (!Decl->isInitCapture() &&

ckandeler wrote:

> * "end":{"character":18,"

But that's [[2 + ]]3, no? I get an end character position of 19 with both Qt 
Creator and VSCode for the [[2 + 3]] selection.

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-02-19 Thread Christian Kandeler via cfe-commits


@@ -490,6 +491,13 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
 BO->getRHS() == OuterImplicit.ASTNode.get())
   return false;
   }
+  if (const auto *Decl = Parent->ASTNode.get()) {
+if (!Decl->isInitCapture() &&

ckandeler wrote:

> For this case in particular, even if you said the refactoring is available 
> for selection of `x = 1 + [[2 + 3]]` through 
> these heuristics, clangd will still end up extracting the full RHS, because 
> that's the AST node we associated with that 
> selection.

I'm not sure I follow. In the example given above, invoking the tweak on the 
selection results in:
```
auto placeholder = 2 + 3;
int x = 1 + placeholder;
```
Which is exactly what I (the user) wanted. Am I misunderstanding something?

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clangd] Collect comments from function definitions into the index (PR #67802)

2024-02-02 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

I have removed the extra Symbol member and extended the Flags enum instead.
I benchmarked with Qt as the test project (qtbase, to be exact), which is 
heavily documented and has all its function documentation in the cpp files, so 
it should provide an upper bound on the effects of this patch.
Index size before this patch : 68MB on-disk, 552MB in-memory
With original patch (extra Symbol member): 70MB/576MB
With latest patch set: 70MB/564 MB
I only did one measurement each, so I don't know if there might be unrelated 
fluctuations there.

https://github.com/llvm/llvm-project/pull/67802
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clangd] Collect comments from function definitions into the index (PR #67802)

2024-02-02 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler updated 
https://github.com/llvm/llvm-project/pull/67802

>From fb3711aa040aa2a986ed7d0c503042adecc6662a Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Fri, 29 Sep 2023 15:01:58 +0200
Subject: [PATCH] [clangd] Collect comments from function definitions into the
 index

This is useful with projects that put their (doxygen) comments at the
implementation site, rather than the header.
---
 clang-tools-extra/clangd/index/Symbol.h   |  4 ++-
 .../clangd/index/SymbolCollector.cpp  | 29 +--
 clang/lib/AST/ASTContext.cpp  | 11 ++-
 3 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clangd/index/Symbol.h 
b/clang-tools-extra/clangd/index/Symbol.h
index 1aa5265299231..62c47ddfc5758 100644
--- a/clang-tools-extra/clangd/index/Symbol.h
+++ b/clang-tools-extra/clangd/index/Symbol.h
@@ -145,9 +145,11 @@ struct Symbol {
 ImplementationDetail = 1 << 2,
 /// Symbol is visible to other files (not e.g. a static helper function).
 VisibleOutsideFile = 1 << 3,
+/// Symbol has an attached documentation comment.
+HasDocComment = 1 << 4
   };
-
   SymbolFlag Flags = SymbolFlag::None;
+
   /// FIXME: also add deprecation message and fixit?
 };
 
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp 
b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index bf838e53f2a21..d071228455836 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -1020,15 +1020,17 @@ const Symbol *SymbolCollector::addDeclaration(const 
NamedDecl , SymbolID ID,
   *ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator,
   *CompletionTUInfo,
   /*IncludeBriefComments*/ false);
-  std::string Documentation =
-  formatDocumentation(*CCS, getDocComment(Ctx, SymbolCompletion,
-  /*CommentsFromHeaders=*/true));
+  std::string DocComment = getDocComment(Ctx, SymbolCompletion,
+ /*CommentsFromHeaders=*/true);
+  std::string Documentation = formatDocumentation(*CCS, DocComment);
   if (!(S.Flags & Symbol::IndexedForCodeCompletion)) {
 if (Opts.StoreAllDocumentation)
   S.Documentation = Documentation;
 Symbols.insert(S);
 return Symbols.find(S.ID);
   }
+  if (!DocComment.empty())
+S.Flags |= Symbol::HasDocComment;
   S.Documentation = Documentation;
   std::string Signature;
   std::string SnippetSuffix;
@@ -1069,6 +1071,27 @@ void SymbolCollector::addDefinition(const NamedDecl ,
   Symbol S = DeclSym;
   // FIXME: use the result to filter out symbols.
   S.Definition = *DefLoc;
+
+  std::string DocComment;
+  std::string Documentation;
+  if (!(S.Flags & Symbol::HasDocComment) &&
+  (llvm::isa(ND) || llvm::isa(ND))) {
+CodeCompletionResult SymbolCompletion((ND), 0);
+const auto *CCS = SymbolCompletion.CreateCodeCompletionString(
+*ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator,
+*CompletionTUInfo,
+/*IncludeBriefComments*/ false);
+DocComment = getDocComment(ND.getASTContext(), SymbolCompletion,
+   /*CommentsFromHeaders=*/true);
+if (!S.Documentation.empty())
+  Documentation = S.Documentation.str() + '\n' + DocComment;
+else
+  Documentation = formatDocumentation(*CCS, DocComment);
+if (!DocComment.empty())
+  S.Flags |= Symbol::HasDocComment;
+S.Documentation = Documentation;
+  }
+
   Symbols.insert(S);
 }
 
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index f7c9e4521b5f1..aa06a1ada4ba7 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -448,8 +448,17 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(
 if (LastCheckedRedecl) {
   if (LastCheckedRedecl == Redecl) {
 LastCheckedRedecl = nullptr;
+continue;
+  }
+  if (auto F = llvm::dyn_cast(Redecl)) {
+if (!F->isThisDeclarationADefinition())
+  continue;
+  } else if (auto M = llvm::dyn_cast(Redecl)) {
+if (!M->isThisDeclarationADefinition())
+  continue;
+  } else {
+continue;
   }
-  continue;
 }
 const RawComment *RedeclComment = getRawCommentForDeclNoCache(Redecl);
 if (RedeclComment) {

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang] [clangd] Collect comments from function definitions into the index (PR #67802)

2024-02-01 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

> Ok, I see. (I was confused because nothing in the patch looks at the contents 
> of `Symbol::DocComment` other than 
> an `empty()` check; maybe a `bool HasDocComment` flag is sufficient?)

Right, we just need to save the information whether there was a doc comment 
before clangd put default values into the Documentation field. 

> I'll have a more detailed look when I get a chance, but one suggestion I 
> wanted to make in the meantime: for 
> changes that add new information to the index, it helps to have a sense of 
> how large of an increase to the index's 
> disk and memory footprint they entail. In the past, I've measured this with 
> the LLVM codebase's index as a "test 
> case".

Will check.


https://github.com/llvm/llvm-project/pull/67802
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang] [clangd] Collect comments from function definitions into the index (PR #67802)

2024-02-01 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

> Do you have another patch where you use the new `DocComment` field?  Is it 
> for showing in a hover?

Yes, it is for showing documentation in a hover. clangd already supports that; 
it's just that it currently works only if the comments are attached to the 
declaration. With this patch it works also for comments at the implementation 
site,   (which I think was the intended behavior all along). No additional 
patch is necessary.



https://github.com/llvm/llvm-project/pull/67802
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2024-02-01 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

ping

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-02-01 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

ping

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang] [clangd] Collect comments from function definitions into the index (PR #67802)

2024-02-01 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

ping

https://github.com/llvm/llvm-project/pull/67802
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-01-11 Thread Christian Kandeler via cfe-commits

ckandeler wrote:

The latest patch set addresses all the comments.

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-01-11 Thread Christian Kandeler via cfe-commits


@@ -490,6 +491,13 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
 BO->getRHS() == OuterImplicit.ASTNode.get())
   return false;
   }
+  if (const auto *Decl = Parent->ASTNode.get()) {
+if (!Decl->isInitCapture() &&

ckandeler wrote:

I think I found a not-too-horrible solution.

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-01-11 Thread Christian Kandeler via cfe-commits


@@ -504,68 +502,6 @@ TEST_F(ExtractVariableTest, Test) {
 int main() {
   auto placeholder = []() { return 42; }(); return  placeholder ;
 })cpp"},
-  {R"cpp(
-template 
-void foo(Ts ...args) {
-  auto x = [[ []() {} ]];
-}
-  )cpp",
-   R"cpp(
-template 
-void foo(Ts ...args) {
-  auto placeholder = []() {}; auto x =  placeholder ;
-}
-  )cpp"},
-  {R"cpp(

ckandeler wrote:

Done.

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-01-11 Thread Christian Kandeler via cfe-commits


@@ -504,68 +502,6 @@ TEST_F(ExtractVariableTest, Test) {
 int main() {
   auto placeholder = []() { return 42; }(); return  placeholder ;
 })cpp"},
-  {R"cpp(

ckandeler wrote:

Done.

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-01-11 Thread Christian Kandeler via cfe-commits


@@ -422,8 +422,6 @@ TEST_F(ExtractVariableTest, Test) {
 int member = 42;
 };
 )cpp"},
-  {R"cpp(void f() { auto x = [[ [](){ return 42; }]]; })cpp",

ckandeler wrote:

Done.

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-01-11 Thread Christian Kandeler via cfe-commits


@@ -27,10 +27,10 @@ TEST_F(ExtractVariableTest, Test) {
   return t.b[[a]]r]]([[t.z]])]];
 }
 void f() {
-  int a = [[5 +]] [[4 * xyz]]();
+  int a = 5 + [[4 * xyz]]();
   // multivariable initialization
   if(1)
-int x = [[1]], y = [[a + 1]], a = [[1]], z = a + 1;
+int x = [[1]] + 1, y = [[a + 1]], a = [[1]] + 2, z = a + 1;

ckandeler wrote:

Yes, I got side-tracked by fixing all the regressions, and in the end the patch 
didn't fulfill its original purpose anymore.
Fixed  now.

https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-01-11 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler updated 
https://github.com/llvm/llvm-project/pull/69477

>From 0ad973446c970e110f1b9c1213e97a7d3da8 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Wed, 18 Oct 2023 17:24:04 +0200
Subject: [PATCH] [clangd] Do not offer extraction to variable for decl init
 expression

That would turn:
  int x = f() + 1;
into:
  auto placeholder = f() + 1;
  int x = placeholder;
which makes little sense and is clearly not intended, as stated
explicitly by a comment in eligibleForExtraction(). It appears that the
declaration case was simply forgotten (the assignment case was already
implemented).
---
 .../refactor/tweaks/ExtractVariable.cpp   | 44 +--
 .../unittests/tweaks/ExtractVariableTests.cpp | 27 +++-
 2 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
index 79bf962544242b..3b378153eafd52 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
@@ -468,7 +468,8 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
   // Extracting Exprs like a = 1 gives placeholder = a = 1 which isn't useful.
   // FIXME: we could still hoist the assignment, and leave the variable there?
   ParsedBinaryOperator BinOp;
-  if (BinOp.parse(*N) && BinaryOperator::isAssignmentOp(BinOp.Kind))
+  bool IsBinOp = BinOp.parse(*N);
+  if (IsBinOp && BinaryOperator::isAssignmentOp(BinOp.Kind))
 return false;
 
   const SelectionTree::Node  = N->outerImplicit();
@@ -483,13 +484,48 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
   OuterImplicit.ASTNode.get()))
 return false;
 
+  std::function IsFullySelected =
+  [&](const SelectionTree::Node *N) {
+if (N->ASTNode.getSourceRange().isValid() &&
+N->Selected != SelectionTree::Complete)
+  return false;
+for (const auto *Child : N->Children) {
+  if (!IsFullySelected(Child))
+return false;
+}
+return true;
+  };
+  auto ExprIsFullySelectedTargetNode = [&](const Expr *E) {
+if (E != OuterImplicit.ASTNode.get())
+  return false;
+
+// The above condition is the only relevant one except for binary 
operators.
+// Without the following code, we would fail to offer extraction for e.g.:
+//   int x = 1 + 2 + [[3 + 4 + 5]];
+// See the documentation of ParsedBinaryOperator for further details.
+if (!IsBinOp)
+  return true;
+return IsFullySelected(N);
+  };
+
   // Disable extraction of full RHS on assignment operations, e.g:
-  // auto x = [[RHS_EXPR]];
+  // x = [[RHS_EXPR]];
   // This would just result in duplicating the code.
   if (const auto *BO = Parent->ASTNode.get()) {
-if (BO->isAssignmentOp() &&
-BO->getRHS() == OuterImplicit.ASTNode.get())
+if (BO->isAssignmentOp() && ExprIsFullySelectedTargetNode(BO->getRHS()))
+  return false;
+  }
+
+  // The same logic as for assignments applies to initializations.
+  // However, we do allow extracting the RHS of an init capture, as it is
+  // a valid use case to move non-trivial expressions out of the capture 
clause.
+  // FIXME: In that case, the extracted variable should be captured directly,
+  //rather than an explicit copy.
+  if (const auto *Decl = Parent->ASTNode.get()) {
+if (!Decl->isInitCapture() &&
+ExprIsFullySelectedTargetNode(Decl->getInit())) {
   return false;
+}
   }
 
   return true;
diff --git a/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp 
b/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
index eb5b06cfee4316..42dd612c46 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
@@ -27,10 +27,10 @@ TEST_F(ExtractVariableTest, Test) {
   return t.b[[a]]r]]([[t.z]])]];
 }
 void f() {
-  int a = [[5 +]] [[4 * xyz]]();
+  int a = 5 + [[4 * xyz]]();
   // multivariable initialization
   if(1)
-int x = [[1]], y = [[a + 1]], a = [[1]], z = a + 1;
+int x = [[1]] + 1, y = a + [[1]], a = [[1]] + 2, z = a + 1;
   // if without else
   if([[1]])
 a = [[1]] + 1;
@@ -61,7 +61,7 @@ TEST_F(ExtractVariableTest, Test) {
   ExtraArgs = {"-xc"};
   const char *AvailableC = R"cpp(
 void foo() {
-  int x = [[1]];
+  int x = [[1]] + 1;
 })cpp";
   EXPECT_AVAILABLE(AvailableC);
 
@@ -79,7 +79,7 @@ TEST_F(ExtractVariableTest, Test) {
 @end
 @implementation Foo
 - (void)method {
-  int x = [[1 + 2]];
+  int x = [[1]] + 2;
 }
 @end)cpp";
   EXPECT_AVAILABLE(AvailableObjC);
@@ -103,6 +103,9 @@ TEST_F(ExtractVariableTest, Test) {
 }
 int z = [[1]];
   } t;
+  int x = [[1 + 2]];
+   

[clang-tools-extra] [clangd] Do not offer extraction to variable for decl init expression (PR #69477)

2024-01-08 Thread Christian Kandeler via cfe-commits


@@ -490,6 +491,13 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
 BO->getRHS() == OuterImplicit.ASTNode.get())
   return false;
   }
+  if (const auto *Decl = Parent->ASTNode.get()) {
+if (!Decl->isInitCapture() &&

ckandeler wrote:

Presumably, with the BinOp check I intended to prevent a false negative for 
this case:
`int x = 1 + 2 + [[3 + 4 + 5]];`
Apparently, the parser considers the last "+" to be the top-level expression, 
so we would erroneously fail to offer extraction for the above expression.
However, the same problem already existed for the assignment case, so it's 
probably wrong anyway to add such a workaround for initialization only. On the 
other hand, I don't want to introduce a regression either. Do you have a good 
idea as to how a proper check could look like?


https://github.com/llvm/llvm-project/pull/69477
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2023-11-21 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler updated 
https://github.com/llvm/llvm-project/pull/69704

>From 40df0527b2a3af8012f32d771a1bb2c861d42ed3 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Thu, 19 Oct 2023 17:51:11 +0200
Subject: [PATCH] [clangd] Allow "move function body out-of-line" in non-header
 files

Moving the body of member functions out-of-line makes sense for classes
defined in implementation files too.
---
 .../clangd/refactor/tweaks/DefineOutline.cpp  | 150 +++---
 .../unittests/tweaks/DefineOutlineTests.cpp   |  73 -
 2 files changed, 164 insertions(+), 59 deletions(-)

diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
index b84ae04072f2c19..98cb3a8770c696d 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
@@ -179,14 +179,11 @@ deleteTokensWithKind(const syntax::TokenBuffer , 
tok::TokenKind Kind,
 // looked up in the context containing the function/method.
 // FIXME: Drop attributes in function signature.
 llvm::Expected
-getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace,
+getFunctionSourceCode(const FunctionDecl *FD, const DeclContext *TargetContext,
   const syntax::TokenBuffer ,
   const HeuristicResolver *Resolver) {
   auto  = FD->getASTContext();
   auto  = AST.getSourceManager();
-  auto TargetContext = findContextForNS(TargetNamespace, FD->getDeclContext());
-  if (!TargetContext)
-return error("define outline: couldn't find a context for target");
 
   llvm::Error Errors = llvm::Error::success();
   tooling::Replacements DeclarationCleanups;
@@ -216,7 +213,7 @@ getFunctionSourceCode(const FunctionDecl *FD, 
llvm::StringRef TargetNamespace,
 }
 const NamedDecl *ND = Ref.Targets.front();
 const std::string Qualifier =
-getQualification(AST, *TargetContext,
+getQualification(AST, TargetContext,
  SM.getLocForStartOfFile(SM.getMainFileID()), ND);
 if (auto Err = DeclarationCleanups.add(
 tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier)))
@@ -232,7 +229,7 @@ getFunctionSourceCode(const FunctionDecl *FD, 
llvm::StringRef TargetNamespace,
   if (const auto *Destructor = llvm::dyn_cast(FD)) {
 if (auto Err = DeclarationCleanups.add(tooling::Replacement(
 SM, Destructor->getLocation(), 0,
-getQualification(AST, *TargetContext,
+getQualification(AST, TargetContext,
  SM.getLocForStartOfFile(SM.getMainFileID()),
  Destructor
   Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
@@ -319,29 +316,9 @@ getFunctionSourceCode(const FunctionDecl *FD, 
llvm::StringRef TargetNamespace,
 }
 
 struct InsertionPoint {
-  std::string EnclosingNamespace;
+  const DeclContext *EnclosingNamespace = nullptr;
   size_t Offset;
 };
-// Returns the most natural insertion point for \p QualifiedName in \p 
Contents.
-// This currently cares about only the namespace proximity, but in feature it
-// should also try to follow ordering of declarations. For example, if decls
-// come in order `foo, bar, baz` then this function should return some point
-// between foo and baz for inserting bar.
-llvm::Expected getInsertionPoint(llvm::StringRef Contents,
- llvm::StringRef QualifiedName,
- const LangOptions ) {
-  auto Region = getEligiblePoints(Contents, QualifiedName, LangOpts);
-
-  assert(!Region.EligiblePoints.empty());
-  // FIXME: This selection can be made smarter by looking at the definition
-  // locations for adjacent decls to Source. Unfortunately pseudo parsing in
-  // getEligibleRegions only knows about namespace begin/end events so we
-  // can't match function start/end positions yet.
-  auto Offset = positionToOffset(Contents, Region.EligiblePoints.back());
-  if (!Offset)
-return Offset.takeError();
-  return InsertionPoint{Region.EnclosingNamespace, *Offset};
-}
 
 // Returns the range that should be deleted from declaration, which always
 // contains function body. In addition to that it might contain constructor
@@ -409,14 +386,9 @@ class DefineOutline : public Tweak {
   }
 
   bool prepare(const Selection ) override {
-// Bail out if we are not in a header file.
-// FIXME: We might want to consider moving method definitions below class
-// definition even if we are inside a source file.
-if (!isHeaderFile(Sel.AST->getSourceManager().getFilename(Sel.Cursor),
-  Sel.AST->getLangOpts()))
-  return false;
-
+SameFile = !isHeaderFile(Sel.AST->tuPath(), Sel.AST->getLangOpts());
 Source = getSelectedFunction(Sel.ASTSelection.commonAncestor());
+
 // Bail out if the selection is not 

[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2023-11-21 Thread Christian Kandeler via cfe-commits


@@ -349,6 +358,36 @@ TEST_F(DefineOutlineTest, ApplyTest) {
   }
 }
 
+TEST_F(DefineOutlineTest, InCppFile) {
+  FileName = "Test.cpp";
+
+  struct {
+llvm::StringRef Test;
+llvm::StringRef ExpectedSource;
+  } Cases[] = {
+  {
+  R"cpp(
+namespace foo {
+namespace {
+struct Foo { void ba^r() {} };

ckandeler wrote:

Hm, the SourceLocations are weird: getEndLoc() points to the closing brace of 
the class. Do I really have to look for the semicolon manually?

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2023-11-21 Thread Christian Kandeler via cfe-commits


@@ -349,6 +358,36 @@ TEST_F(DefineOutlineTest, ApplyTest) {
   }
 }
 
+TEST_F(DefineOutlineTest, InCppFile) {
+  FileName = "Test.cpp";
+
+  struct {
+llvm::StringRef Test;
+llvm::StringRef ExpectedSource;
+  } Cases[] = {
+  {
+  R"cpp(
+namespace foo {
+namespace {
+struct Foo { void ba^r() {} };

ckandeler wrote:

Ah, maybe getOuterLexicalRecordContext().

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2023-11-21 Thread Christian Kandeler via cfe-commits


@@ -349,6 +358,36 @@ TEST_F(DefineOutlineTest, ApplyTest) {
   }
 }
 
+TEST_F(DefineOutlineTest, InCppFile) {
+  FileName = "Test.cpp";
+
+  struct {
+llvm::StringRef Test;
+llvm::StringRef ExpectedSource;
+  } Cases[] = {
+  {
+  R"cpp(
+namespace foo {
+namespace {
+struct Foo { void ba^r() {} };

ckandeler wrote:

> so what about changing this logic to get to enclosing decl instead (i.e. 
> TagDecl) and insert right after its end location?

That will break with nested classes, won't it?

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2023-11-21 Thread Christian Kandeler via cfe-commits

https://github.com/ckandeler updated 
https://github.com/llvm/llvm-project/pull/69704

>From 27af98b5a9b71255b2873f25943ed23e42946b27 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Thu, 19 Oct 2023 17:51:11 +0200
Subject: [PATCH] [clangd] Allow "move function body out-of-line" in non-header
 files

Moving the body of member functions out-of-line makes sense for classes
defined in implementation files too.
---
 .../clangd/refactor/tweaks/DefineOutline.cpp  | 135 ++
 .../unittests/tweaks/DefineOutlineTests.cpp   |  43 +-
 2 files changed, 119 insertions(+), 59 deletions(-)

diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
index b84ae04072f2c19..67d13f3eb4a6b07 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
@@ -179,14 +179,11 @@ deleteTokensWithKind(const syntax::TokenBuffer , 
tok::TokenKind Kind,
 // looked up in the context containing the function/method.
 // FIXME: Drop attributes in function signature.
 llvm::Expected
-getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace,
+getFunctionSourceCode(const FunctionDecl *FD, const DeclContext *TargetContext,
   const syntax::TokenBuffer ,
   const HeuristicResolver *Resolver) {
   auto  = FD->getASTContext();
   auto  = AST.getSourceManager();
-  auto TargetContext = findContextForNS(TargetNamespace, FD->getDeclContext());
-  if (!TargetContext)
-return error("define outline: couldn't find a context for target");
 
   llvm::Error Errors = llvm::Error::success();
   tooling::Replacements DeclarationCleanups;
@@ -216,7 +213,7 @@ getFunctionSourceCode(const FunctionDecl *FD, 
llvm::StringRef TargetNamespace,
 }
 const NamedDecl *ND = Ref.Targets.front();
 const std::string Qualifier =
-getQualification(AST, *TargetContext,
+getQualification(AST, TargetContext,
  SM.getLocForStartOfFile(SM.getMainFileID()), ND);
 if (auto Err = DeclarationCleanups.add(
 tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier)))
@@ -232,7 +229,7 @@ getFunctionSourceCode(const FunctionDecl *FD, 
llvm::StringRef TargetNamespace,
   if (const auto *Destructor = llvm::dyn_cast(FD)) {
 if (auto Err = DeclarationCleanups.add(tooling::Replacement(
 SM, Destructor->getLocation(), 0,
-getQualification(AST, *TargetContext,
+getQualification(AST, TargetContext,
  SM.getLocForStartOfFile(SM.getMainFileID()),
  Destructor
   Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
@@ -319,29 +316,9 @@ getFunctionSourceCode(const FunctionDecl *FD, 
llvm::StringRef TargetNamespace,
 }
 
 struct InsertionPoint {
-  std::string EnclosingNamespace;
+  const DeclContext *EnclosingNamespace = nullptr;
   size_t Offset;
 };
-// Returns the most natural insertion point for \p QualifiedName in \p 
Contents.
-// This currently cares about only the namespace proximity, but in feature it
-// should also try to follow ordering of declarations. For example, if decls
-// come in order `foo, bar, baz` then this function should return some point
-// between foo and baz for inserting bar.
-llvm::Expected getInsertionPoint(llvm::StringRef Contents,
- llvm::StringRef QualifiedName,
- const LangOptions ) {
-  auto Region = getEligiblePoints(Contents, QualifiedName, LangOpts);
-
-  assert(!Region.EligiblePoints.empty());
-  // FIXME: This selection can be made smarter by looking at the definition
-  // locations for adjacent decls to Source. Unfortunately pseudo parsing in
-  // getEligibleRegions only knows about namespace begin/end events so we
-  // can't match function start/end positions yet.
-  auto Offset = positionToOffset(Contents, Region.EligiblePoints.back());
-  if (!Offset)
-return Offset.takeError();
-  return InsertionPoint{Region.EnclosingNamespace, *Offset};
-}
 
 // Returns the range that should be deleted from declaration, which always
 // contains function body. In addition to that it might contain constructor
@@ -409,14 +386,9 @@ class DefineOutline : public Tweak {
   }
 
   bool prepare(const Selection ) override {
-// Bail out if we are not in a header file.
-// FIXME: We might want to consider moving method definitions below class
-// definition even if we are inside a source file.
-if (!isHeaderFile(Sel.AST->getSourceManager().getFilename(Sel.Cursor),
-  Sel.AST->getLangOpts()))
-  return false;
-
+SameFile = !isHeaderFile(Sel.AST->tuPath(), Sel.AST->getLangOpts());
 Source = getSelectedFunction(Sel.ASTSelection.commonAncestor());
+
 // Bail out if the selection is not a 

[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2023-11-21 Thread Christian Kandeler via cfe-commits


@@ -19,7 +19,7 @@ TWEAK_TEST(DefineOutline);
 
 TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) {
   FileName = "Test.cpp";
-  // Not available unless in a header file.
+  // Not available for free function unless in a header file.

ckandeler wrote:

Do you have suggestions? anon namespace in header is already covered.

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clangd] Allow "move function body out-of-line" in non-header files (PR #69704)

2023-11-21 Thread Christian Kandeler via cfe-commits


@@ -499,17 +473,64 @@ class DefineOutline : public Tweak {
   HeaderUpdates = HeaderUpdates.merge(*DelInline);
 }
 
-auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(), HeaderUpdates);
-if (!HeaderFE)
-  return HeaderFE.takeError();
-
-Effect->ApplyEdits.try_emplace(HeaderFE->first,
-   std::move(HeaderFE->second));
+if (SameFile) {
+  tooling::Replacements  = Effect->ApplyEdits[*CCFile].Replacements;
+  R = R.merge(HeaderUpdates);
+} else {
+  auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(), HeaderUpdates);
+  if (!HeaderFE)
+return HeaderFE.takeError();
+  Effect->ApplyEdits.try_emplace(HeaderFE->first,
+ std::move(HeaderFE->second));
+}
 return std::move(*Effect);
   }
 
+  // Returns the most natural insertion point for \p QualifiedName in \p
+  // Contents. This currently cares about only the namespace proximity, but in
+  // feature it should also try to follow ordering of declarations. For 
example,
+  // if decls come in order `foo, bar, baz` then this function should return
+  // some point between foo and baz for inserting bar.
+  llvm::Expected getInsertionPoint(llvm::StringRef Contents,
+   const Selection ) {
+// If the definition goes to the same file and there is a namespace,
+// we should (and, in the case of anonymous namespaces, need to)
+// put the definition into the original namespace block.
+// Within this constraint, the same considerations apply as in
+// the FIXME below.
+if (SameFile) {
+  if (auto *Namespace = Source->getEnclosingNamespaceContext()) {

ckandeler wrote:

You mean this also covers the global namespace? I wasn't sure about that. But 
don't we need special handling for that case, then? As I'd assume it won't have 
a proper location?

https://github.com/llvm/llvm-project/pull/69704
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 535f34d - [index][clangd] Consider labels when indexing function bodies

2023-08-01 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2023-08-01T09:07:05+02:00
New Revision: 535f34dd80c2200c35971632021a5ed375774d9b

URL: 
https://github.com/llvm/llvm-project/commit/535f34dd80c2200c35971632021a5ed375774d9b
DIFF: 
https://github.com/llvm/llvm-project/commit/535f34dd80c2200c35971632021a5ed375774d9b.diff

LOG: [index][clangd] Consider labels when indexing function bodies

It's valuable to have document highlights for labels and be able to find
references to them.

Reviewed By: nridge

Differential Revision: https://reviews.llvm.org/D150124

Added: 


Modified: 
clang-tools-extra/clangd/unittests/XRefsTests.cpp
clang/lib/Index/IndexBody.cpp
clang/unittests/Index/IndexTests.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp 
b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index 05cf891e71db40..6d7fd62016991a 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -125,6 +125,13 @@ TEST(HighlightsTest, All) {
   [Foo [[x]]:2 [[^y]]:4];
 }
   )cpp",
+  R"cpp( // Label
+int main() {
+  goto [[^theLabel]];
+  [[theLabel]]:
+return 1;
+}
+  )cpp",
   };
   for (const char *Test : Tests) {
 Annotations T(Test);

diff  --git a/clang/lib/Index/IndexBody.cpp b/clang/lib/Index/IndexBody.cpp
index e5f1764550ffa7..e88f321f18a712 100644
--- a/clang/lib/Index/IndexBody.cpp
+++ b/clang/lib/Index/IndexBody.cpp
@@ -144,6 +144,17 @@ class BodyIndexer : public 
RecursiveASTVisitor {
 Parent, ParentDC, Roles, Relations, E);
   }
 
+  bool VisitGotoStmt(GotoStmt *S) {
+return IndexCtx.handleReference(S->getLabel(), S->getLabelLoc(), Parent,
+ParentDC);
+  }
+
+  bool VisitLabelStmt(LabelStmt *S) {
+if (IndexCtx.shouldIndexFunctionLocalSymbols())
+  return IndexCtx.handleDecl(S->getDecl());
+return true;
+  }
+
   bool VisitMemberExpr(MemberExpr *E) {
 SourceLocation Loc = E->getMemberLoc();
 if (Loc.isInvalid())

diff  --git a/clang/unittests/Index/IndexTests.cpp 
b/clang/unittests/Index/IndexTests.cpp
index 690673a1072b00..4d19f47283c285 100644
--- a/clang/unittests/Index/IndexTests.cpp
+++ b/clang/unittests/Index/IndexTests.cpp
@@ -218,6 +218,28 @@ TEST(IndexTest, IndexParametersInDecls) {
   EXPECT_THAT(Index->Symbols, Not(Contains(QName("bar";
 }
 
+TEST(IndexTest, IndexLabels) {
+  std::string Code = R"cpp(
+int main() {
+  goto theLabel;
+  theLabel:
+return 1;
+}
+  )cpp";
+  auto Index = std::make_shared();
+  IndexingOptions Opts;
+  Opts.IndexFunctionLocals = true;
+  tooling::runToolOnCode(std::make_unique(Index, Opts), Code);
+  EXPECT_THAT(Index->Symbols,
+  Contains(AllOf(QName("theLabel"), WrittenAt(Position(3, 16)),
+ DeclAt(Position(4, 11);
+
+  Opts.IndexFunctionLocals = false;
+  Index->Symbols.clear();
+  tooling::runToolOnCode(std::make_unique(Index, Opts), Code);
+  EXPECT_THAT(Index->Symbols, Not(Contains(QName("theLabel";
+}
+
 TEST(IndexTest, IndexExplicitTemplateInstantiation) {
   std::string Code = R"cpp(
 template 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] e72baa7 - [clangd] Add semantic token for labels

2023-06-07 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2023-06-07T12:28:06+02:00
New Revision: e72baa76b91fbcb2b16747cb7d2088723478a754

URL: 
https://github.com/llvm/llvm-project/commit/e72baa76b91fbcb2b16747cb7d2088723478a754
DIFF: 
https://github.com/llvm/llvm-project/commit/e72baa76b91fbcb2b16747cb7d2088723478a754.diff

LOG: [clangd] Add semantic token for labels

Reviewed By: kadircet

Differential Revision: https://reviews.llvm.org/D143260

Added: 


Modified: 
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp 
b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index ec37476cf94ea..6a835f31f064b 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -166,6 +166,8 @@ std::optional kindForDecl(const NamedDecl 
*D,
 return HighlightingKind::TemplateParameter;
   if (isa(D))
 return HighlightingKind::Concept;
+  if (isa(D))
+return HighlightingKind::Label;
   if (const auto *UUVD = dyn_cast(D)) {
 auto Targets = Resolver->resolveUsingValueDecl(UUVD);
 if (!Targets.empty() && Targets[0] != UUVD) {
@@ -1271,6 +1273,8 @@ llvm::raw_ostream <<(llvm::raw_ostream , 
HighlightingKind K) {
 return OS << "Operator";
   case HighlightingKind::Bracket:
 return OS << "Bracket";
+  case HighlightingKind::Label:
+return OS << "Label";
   case HighlightingKind::InactiveCode:
 return OS << "InactiveCode";
   }
@@ -1470,6 +1474,8 @@ llvm::StringRef toSemanticTokenType(HighlightingKind 
Kind) {
 return "operator";
   case HighlightingKind::Bracket:
 return "bracket";
+  case HighlightingKind::Label:
+return "label";
   case HighlightingKind::InactiveCode:
 return "comment";
   }

diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.h 
b/clang-tools-extra/clangd/SemanticHighlighting.h
index c9db598ff08c9..59d742b83ee52 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.h
+++ b/clang-tools-extra/clangd/SemanticHighlighting.h
@@ -52,6 +52,7 @@ enum class HighlightingKind {
   Modifier,
   Operator,
   Bracket,
+  Label,
 
   // This one is 
diff erent from the other kinds as it's a line style
   // rather than a token style.

diff  --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp 
b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
index 9c6e5246f5c37..ff052e6be9549 100644
--- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -1028,6 +1028,16 @@ sizeof...($TemplateParameter[[Elements]]);
 template $Bracket[[<]]$Concept[[C2]]$Bracket[[<]]int$Bracket[[>]] 
$TemplateParameter_def[[A]]$Bracket[[>]]
 class $Class_def[[B]] {};
   )cpp",
+  // Labels
+  R"cpp(
+bool $Function_def[[funcWithGoto]](bool $Parameter_def[[b]]) {
+  if ($Parameter[[b]])
+goto $Label[[return_true]];
+  return false;
+  $Label_decl[[return_true]]:
+return true;
+}
+  )cpp",
   // no crash
   R"cpp(
 struct $Class_def[[Foo]] {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] 008cb29 - [clangd] Renaming: Treat member functions like other functions

2023-05-22 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2023-05-22T12:50:38+02:00
New Revision: 008cb29f87f3af391eb6c3747bdad16f2e386161

URL: 
https://github.com/llvm/llvm-project/commit/008cb29f87f3af391eb6c3747bdad16f2e386161
DIFF: 
https://github.com/llvm/llvm-project/commit/008cb29f87f3af391eb6c3747bdad16f2e386161.diff

LOG: [clangd] Renaming: Treat member functions like other functions

... by skipping the conflict check. The same considerations apply.

Reviewed By: hokein

Differential Revision: https://reviews.llvm.org/D150685

Added: 


Modified: 
clang-tools-extra/clangd/refactor/Rename.cpp
clang-tools-extra/clangd/unittests/RenameTests.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/refactor/Rename.cpp 
b/clang-tools-extra/clangd/refactor/Rename.cpp
index 6362768f9b475..b3270534b13b1 100644
--- a/clang-tools-extra/clangd/refactor/Rename.cpp
+++ b/clang-tools-extra/clangd/refactor/Rename.cpp
@@ -515,7 +515,8 @@ std::optional checkName(const NamedDecl 
,
   else {
 // Name conflict detection.
 // Function conflicts are subtle (overloading), so ignore them.
-if (RenameDecl.getKind() != Decl::Function) {
+if (RenameDecl.getKind() != Decl::Function &&
+RenameDecl.getKind() != Decl::CXXMethod) {
   if (auto *Conflict = lookupSiblingWithName(ASTCtx, RenameDecl, NewName))
 Result = InvalidName{
 InvalidName::Conflict,

diff  --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp 
b/clang-tools-extra/clangd/unittests/RenameTests.cpp
index 5b99f8c4fc44c..9be4a970a7cfb 100644
--- a/clang-tools-extra/clangd/unittests/RenameTests.cpp
+++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp
@@ -1062,6 +1062,19 @@ TEST(RenameTest, Renameable) {
   )cpp",
"conflict", !HeaderFile, "Conflict"},
 
+  {R"cpp(
+void func(int);
+void [[o^therFunc]](double);
+  )cpp",
+   nullptr, !HeaderFile, "func"},
+  {R"cpp(
+struct S {
+  void func(int);
+  void [[o^therFunc]](double);
+};
+  )cpp",
+   nullptr, !HeaderFile, "func"},
+
   {R"cpp(
 int V^ar;
   )cpp",
@@ -1121,9 +1134,7 @@ TEST(RenameTest, Renameable) {
 } else {
   EXPECT_TRUE(bool(Results)) << "rename returned an error: "
  << llvm::toString(Results.takeError());
-  ASSERT_EQ(1u, Results->GlobalChanges.size());
-  EXPECT_EQ(applyEdits(std::move(Results->GlobalChanges)).front().second,
-expectedResult(T, NewName));
+  EXPECT_EQ(Results->LocalChanges, T.ranges());
 }
   }
 }



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] bbddbe5 - [clangd] Add semantic token for angle brackets

2023-01-31 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2023-01-31T17:15:31+01:00
New Revision: bbddbe580bca5fa1c0478a3ec6edd0e0c40b9d96

URL: 
https://github.com/llvm/llvm-project/commit/bbddbe580bca5fa1c0478a3ec6edd0e0c40b9d96
DIFF: 
https://github.com/llvm/llvm-project/commit/bbddbe580bca5fa1c0478a3ec6edd0e0c40b9d96.diff

LOG: [clangd] Add semantic token for angle brackets

This is needed for clients that would like to visualize matching
opening and closing angle brackets, which can be valuable in non-trivial
template declarations or instantiations.
It is not possible to do this with simple lexing, as the tokens
could also refer to operators.

Reviewed By: kadircet

Differential Revision: https://reviews.llvm.org/D139926

Added: 


Modified: 
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp 
b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index a516c688efc1..e3022ad131ff 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -369,6 +369,47 @@ class HighlightingsBuilder {
 return addToken(*Range, Kind);
   }
 
+  // Most of this function works around
+  // https://github.com/clangd/clangd/issues/871.
+  void addAngleBracketTokens(SourceLocation LLoc, SourceLocation RLoc) {
+if (!LLoc.isValid() || !RLoc.isValid())
+  return;
+
+auto LRange = getRangeForSourceLocation(LLoc);
+if (!LRange)
+  return;
+
+// RLoc might be pointing at a virtual buffer when it's part of a `>>`
+// token.
+RLoc = SourceMgr.getFileLoc(RLoc);
+// Make sure token is part of the main file.
+RLoc = getHighlightableSpellingToken(RLoc, SourceMgr);
+if (!RLoc.isValid())
+  return;
+
+const auto *RTok = TB.spelledTokenAt(RLoc);
+// Handle `>>`. RLoc is always pointing at the right location, just change
+// the end to be offset by 1.
+// We'll either point at the beginning of `>>`, hence get a proper spelled
+// or point in the middle of `>>` hence get no spelled tok.
+if (!RTok || RTok->kind() == tok::greatergreater) {
+  Position Begin = sourceLocToPosition(SourceMgr, RLoc);
+  Position End = sourceLocToPosition(SourceMgr, RLoc.getLocWithOffset(1));
+  addToken(*LRange, HighlightingKind::Bracket);
+  addToken({Begin, End}, HighlightingKind::Bracket);
+  return;
+}
+
+// Easy case, we have the `>` token directly available.
+if (RTok->kind() == tok::greater) {
+  if (auto RRange = getRangeForSourceLocation(RLoc)) {
+addToken(*LRange, HighlightingKind::Bracket);
+addToken(*RRange, HighlightingKind::Bracket);
+  }
+  return;
+}
+  }
+
   HighlightingToken (Range R, HighlightingKind Kind) {
 HighlightingToken HT;
 HT.R = std::move(R);
@@ -559,6 +600,12 @@ class CollectExtraHighlightings
 return Base::TraverseConstructorInitializer(Init);
   }
 
+  bool TraverseTypeConstraint(const TypeConstraint *C) {
+if (auto *Args = C->getTemplateArgsAsWritten())
+  H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
+return Base::TraverseTypeConstraint(C);
+  }
+
   bool VisitPredefinedExpr(PredefinedExpr *E) {
 H.addToken(E->getLocation(), HighlightingKind::LocalVariable)
 .addModifier(HighlightingModifier::Static)
@@ -567,6 +614,77 @@ class CollectExtraHighlightings
 return true;
   }
 
+  bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
+if (auto *Args = E->getTemplateArgsAsWritten())
+  H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
+return true;
+  }
+
+  bool VisitTemplateDecl(TemplateDecl *D) {
+if (auto *TPL = D->getTemplateParameters())
+  H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
+return true;
+  }
+
+  bool VisitTagDecl(TagDecl *D) {
+for (unsigned i = 0; i < D->getNumTemplateParameterLists(); ++i) {
+  if (auto *TPL = D->getTemplateParameterList(i))
+H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
+}
+return true;
+  }
+
+  bool VisitClassTemplatePartialSpecializationDecl(
+  ClassTemplatePartialSpecializationDecl *D) {
+if (auto *TPL = D->getTemplateParameters())
+  H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
+if (auto *Args = D->getTemplateArgsAsWritten())
+  H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
+return true;
+  }
+
+  bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
+if (auto *Args = D->getTemplateArgsInfo())
+  H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
+return true;
+  }
+
+  bool VisitVarTemplatePartialSpecializationDecl(
+  

[clang-tools-extra] 647d314 - [clangd] Add support for semantic token type "operator"

2022-12-12 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2022-12-12T16:17:43+01:00
New Revision: 647d314eb059b6d2e7c00d7eefe6a7afc37dff25

URL: 
https://github.com/llvm/llvm-project/commit/647d314eb059b6d2e7c00d7eefe6a7afc37dff25
DIFF: 
https://github.com/llvm/llvm-project/commit/647d314eb059b6d2e7c00d7eefe6a7afc37dff25.diff

LOG: [clangd] Add support for semantic token type "operator"

Also add new modifier for differentiating between built-in and user-
provided operators.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D136594

Added: 


Modified: 
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/test/initialize-params.test
clang-tools-extra/clangd/test/semantic-tokens.test
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp 
b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index ccdaab89620b2..6745e2594ead3 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -566,6 +566,71 @@ class CollectExtraHighlightings
 return true;
   }
 
+  bool VisitFunctionDecl(FunctionDecl *D) {
+if (D->isOverloadedOperator()) {
+  const auto addOpDeclToken = [&](SourceLocation Loc) {
+auto  = H.addToken(Loc, HighlightingKind::Operator)
+  .addModifier(HighlightingModifier::Declaration);
+if (D->isThisDeclarationADefinition())
+  Token.addModifier(HighlightingModifier::Definition);
+  };
+  const auto Range = D->getNameInfo().getCXXOperatorNameRange();
+  addOpDeclToken(Range.getBegin());
+  const auto Kind = D->getOverloadedOperator();
+  if (Kind == OO_Call || Kind == OO_Subscript)
+addOpDeclToken(Range.getEnd());
+}
+return true;
+  }
+
+  bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+const auto addOpToken = [&](SourceLocation Loc) {
+  H.addToken(Loc, HighlightingKind::Operator)
+  .addModifier(HighlightingModifier::UserDefined);
+};
+addOpToken(E->getOperatorLoc());
+const auto Kind = E->getOperator();
+if (Kind == OO_Call || Kind == OO_Subscript) {
+  if (auto *Callee = E->getCallee())
+addOpToken(Callee->getBeginLoc());
+}
+return true;
+  }
+
+  bool VisitUnaryOperator(UnaryOperator *Op) {
+auto  = H.addToken(Op->getOperatorLoc(), HighlightingKind::Operator);
+if (Op->getSubExpr()->isTypeDependent())
+  Token.addModifier(HighlightingModifier::UserDefined);
+return true;
+  }
+
+  bool VisitBinaryOperator(BinaryOperator *Op) {
+auto  = H.addToken(Op->getOperatorLoc(), HighlightingKind::Operator);
+if (Op->getLHS()->isTypeDependent() || Op->getRHS()->isTypeDependent())
+  Token.addModifier(HighlightingModifier::UserDefined);
+return true;
+  }
+
+  bool VisitConditionalOperator(ConditionalOperator *Op) {
+H.addToken(Op->getQuestionLoc(), HighlightingKind::Operator);
+H.addToken(Op->getColonLoc(), HighlightingKind::Operator);
+return true;
+  }
+
+  bool VisitCXXNewExpr(CXXNewExpr *E) {
+auto  = H.addToken(E->getBeginLoc(), HighlightingKind::Operator);
+if (isa(E->getOperatorNew()))
+  Token.addModifier(HighlightingModifier::UserDefined);
+return true;
+  }
+
+  bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+auto  = H.addToken(E->getBeginLoc(), HighlightingKind::Operator);
+if (isa(E->getOperatorDelete()))
+  Token.addModifier(HighlightingModifier::UserDefined);
+return true;
+  }
+
   bool VisitCallExpr(CallExpr *E) {
 // Highlighting parameters passed by non-const reference does not really
 // make sense for literals...
@@ -671,12 +736,20 @@ class CollectExtraHighlightings
   bool VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) {
 // getMethodDecl can return nullptr with member pointers, e.g.
 // `(foo.*pointer_to_member_fun)(arg);`
-if (isa_and_present(CE->getMethodDecl())) {
-  if (auto *ME = dyn_cast(CE->getCallee())) {
-if (auto *TI = ME->getMemberNameInfo().getNamedTypeInfo()) {
-  H.addExtraModifier(TI->getTypeLoc().getBeginLoc(),
- HighlightingModifier::ConstructorOrDestructor);
+if (auto *D = CE->getMethodDecl()) {
+  if (isa(D)) {
+if (auto *ME = dyn_cast(CE->getCallee())) {
+  if (auto *TI = ME->getMemberNameInfo().getNamedTypeInfo()) {
+H.addExtraModifier(TI->getTypeLoc().getBeginLoc(),
+   HighlightingModifier::ConstructorOrDestructor);
+  }
 }
+  } else if (D->isOverloadedOperator()) {
+if (auto *ME = dyn_cast(CE->getCallee()))
+  H.addToken(
+   ME->getMemberNameInfo().getCXXOperatorNameRange().getBegin(),
+   HighlightingKind::Operator)
+  

[clang-tools-extra] 699a59a - [clangd] Mark "override" and "final" as modifiers

2022-11-21 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2022-11-21T22:01:12+01:00
New Revision: 699a59aa5865d8b10f42284f68c424a9123cb8b2

URL: 
https://github.com/llvm/llvm-project/commit/699a59aa5865d8b10f42284f68c424a9123cb8b2
DIFF: 
https://github.com/llvm/llvm-project/commit/699a59aa5865d8b10f42284f68c424a9123cb8b2.diff

LOG: [clangd] Mark "override" and "final" as modifiers

... in semantic highlighting.
These specifiers cannot be identified by simple lexing (since e.g.
variables with these names can legally be declared), which means they
should be semantic tokens.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D137943

Added: 


Modified: 
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp 
b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index dd9392b029df8..dd25a2f31230c 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -809,6 +809,18 @@ class CollectExtraHighlightings
 return true;
   }
 
+  bool VisitAttr(Attr *A) {
+switch (A->getKind()) {
+case attr::Override:
+case attr::Final:
+  H.addToken(A->getLocation(), HighlightingKind::Modifier);
+  break;
+default:
+  break;
+}
+return true;
+  }
+
   bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
 H.addToken(L.getNameLoc(), HighlightingKind::Type)
 .addModifier(HighlightingModifier::DependentName)
@@ -985,6 +997,8 @@ llvm::raw_ostream <<(llvm::raw_ostream , 
HighlightingKind K) {
 return OS << "Primitive";
   case HighlightingKind::Macro:
 return OS << "Macro";
+  case HighlightingKind::Modifier:
+return OS << "Modifier";
   case HighlightingKind::InactiveCode:
 return OS << "InactiveCode";
   }
@@ -1119,6 +1133,8 @@ llvm::StringRef toSemanticTokenType(HighlightingKind 
Kind) {
 return "type";
   case HighlightingKind::Macro:
 return "macro";
+  case HighlightingKind::Modifier:
+return "modifier";
   case HighlightingKind::InactiveCode:
 return "comment";
   }

diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.h 
b/clang-tools-extra/clangd/SemanticHighlighting.h
index 64ad431909faa..e8f60c13000e1 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.h
+++ b/clang-tools-extra/clangd/SemanticHighlighting.h
@@ -49,6 +49,7 @@ enum class HighlightingKind {
   Concept,
   Primitive,
   Macro,
+  Modifier,
 
   // This one is 
diff erent from the other kinds as it's a line style
   // rather than a token style.

diff  --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp 
b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
index 3ea4a58a83a70..70d8f91f129e4 100644
--- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -864,6 +864,12 @@ sizeof...($TemplateParameter[[Elements]]);
 const char *$LocalVariable_def_readonly[[s]] = 
$LocalVariable_readonly_static[[__func__]];
 }
   )cpp",
+  // override and final
+  R"cpp(
+class $Class_def_abstract[[Base]] { virtual void 
$Method_decl_abstract_virtual[[m]]() = 0; };
+class $Class_def[[override]] : public $Class_abstract[[Base]] { void 
$Method_decl_virtual[[m]]() $Modifier[[override]]; };
+class $Class_def[[final]] : public $Class[[override]] { void 
$Method_decl_virtual[[m]]() $Modifier[[override]] $Modifier[[final]]; };
+  )cpp",
   // Issue 1222: readonly modifier for generic parameter
   R"cpp(
 template 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] 2bf960a - [clangd] Add "usedAsMutablePointer" highlighting modifier

2022-11-07 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2022-11-07T11:58:33+01:00
New Revision: 2bf960aef08e93d687f21e6d636186561b56cbf3

URL: 
https://github.com/llvm/llvm-project/commit/2bf960aef08e93d687f21e6d636186561b56cbf3
DIFF: 
https://github.com/llvm/llvm-project/commit/2bf960aef08e93d687f21e6d636186561b56cbf3.diff

LOG: [clangd] Add "usedAsMutablePointer" highlighting modifier

Counterpart to "usedAsMutableReference". Just as for references, there
are const and non-const pointer parameters, and it's valuable to be able
to have different highlighting for the two cases at the call site.
We could have re-used the existing modifier, but having a dedicated one
maximizes client flexibility.

Reviewed By: nridge

Differential Revision: https://reviews.llvm.org/D130015

Added: 


Modified: 
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/test/initialize-params.test
clang-tools-extra/clangd/test/semantic-tokens.test
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp 
b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index af3a3e6f8e941..dd9392b029df8 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -597,19 +597,27 @@ class CollectExtraHighlightings
 if (!Arg)
   return;
 
-// Is this parameter passed by non-const reference?
+// Is this parameter passed by non-const pointer or reference?
 // FIXME The condition T->idDependentType() could be relaxed a bit,
 // e.g. std::vector& is dependent but we would want to highlight it
-if (!T->isLValueReferenceType() ||
-T.getNonReferenceType().isConstQualified() || T->isDependentType()) {
+bool IsRef = T->isLValueReferenceType();
+bool IsPtr = T->isPointerType();
+if ((!IsRef && !IsPtr) || T->getPointeeType().isConstQualified() ||
+T->isDependentType()) {
   return;
 }
 
 llvm::Optional Location;
 
-// FIXME Add "unwrapping" for ArraySubscriptExpr and UnaryOperator,
+// FIXME Add "unwrapping" for ArraySubscriptExpr,
 //  e.g. highlight `a` in `a[i]`
 // FIXME Handle dependent expression types
+if (auto *IC = dyn_cast(Arg))
+  Arg = IC->getSubExprAsWritten();
+if (auto *UO = dyn_cast(Arg)) {
+  if (UO->getOpcode() == UO_AddrOf)
+Arg = UO->getSubExpr();
+}
 if (auto *DR = dyn_cast(Arg))
   Location = DR->getLocation();
 else if (auto *M = dyn_cast(Arg))
@@ -617,7 +625,8 @@ class CollectExtraHighlightings
 
 if (Location)
   H.addExtraModifier(*Location,
- HighlightingModifier::UsedAsMutableReference);
+ IsRef ? HighlightingModifier::UsedAsMutableReference
+   : HighlightingModifier::UsedAsMutablePointer);
   }
 
   void
@@ -1140,6 +1149,8 @@ llvm::StringRef 
toSemanticTokenModifier(HighlightingModifier Modifier) {
 return "defaultLibrary";
   case HighlightingModifier::UsedAsMutableReference:
 return "usedAsMutableReference"; // nonstandard
+  case HighlightingModifier::UsedAsMutablePointer:
+return "usedAsMutablePointer"; // nonstandard
   case HighlightingModifier::ConstructorOrDestructor:
 return "constructorOrDestructor"; // nonstandard
   case HighlightingModifier::FunctionScope:

diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.h 
b/clang-tools-extra/clangd/SemanticHighlighting.h
index 79ecb344275d1..64ad431909faa 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.h
+++ b/clang-tools-extra/clangd/SemanticHighlighting.h
@@ -71,6 +71,7 @@ enum class HighlightingModifier {
   DependentName,
   DefaultLibrary,
   UsedAsMutableReference,
+  UsedAsMutablePointer,
   ConstructorOrDestructor,
 
   FunctionScope,

diff  --git a/clang-tools-extra/clangd/test/initialize-params.test 
b/clang-tools-extra/clangd/test/initialize-params.test
index eb958cac20279..a2df61ca75235 100644
--- a/clang-tools-extra/clangd/test/initialize-params.test
+++ b/clang-tools-extra/clangd/test/initialize-params.test
@@ -68,6 +68,7 @@
 # CHECK-NEXT:"dependentName",
 # CHECK-NEXT:"defaultLibrary",
 # CHECK-NEXT:"usedAsMutableReference",
+# CHECK-NEXT:"usedAsMutablePointer",
 # CHECK-NEXT:"constructorOrDestructor",
 # CHECK-NEXT:"functionScope",
 # CHECK-NEXT:"classScope",

diff  --git a/clang-tools-extra/clangd/test/semantic-tokens.test 
b/clang-tools-extra/clangd/test/semantic-tokens.test
index 5abe78e9a51e1..b3a92b7cc737b 100644
--- a/clang-tools-extra/clangd/test/semantic-tokens.test
+++ b/clang-tools-extra/clangd/test/semantic-tokens.test
@@ -23,7 +23,7 @@
 # CHECK-NEXT:  4,
 # CHECK-NEXT:  1,
 # CHECK-NEXT:  0,
-# CHECK-NEXT:  32771

[clang-tools-extra] 6ed4a54 - [clangd] Make file limit for textDocument/rename configurable

2022-10-22 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2022-10-22T10:17:41+02:00
New Revision: 6ed4a543b8b3ab38ddb30cf4c15b70ed11266388

URL: 
https://github.com/llvm/llvm-project/commit/6ed4a543b8b3ab38ddb30cf4c15b70ed11266388
DIFF: 
https://github.com/llvm/llvm-project/commit/6ed4a543b8b3ab38ddb30cf4c15b70ed11266388.diff

LOG: [clangd] Make file limit for textDocument/rename configurable

Without this, clients are unable to rename often-used symbols in larger
projects.

Reviewed By: kadircet

Differential Revision: https://reviews.llvm.org/D136454

Added: 


Modified: 
clang-tools-extra/clangd/tool/ClangdMain.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp 
b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 68c0a51a2d74d..53b6653c51f20 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -327,6 +327,14 @@ opt ReferencesLimit{
 init(1000),
 };
 
+opt RenameFileLimit{
+"rename-file-limit",
+cat(Features),
+desc("Limit the number of files to be affected by symbol renaming. "
+ "0 means no limit (default=50)"),
+init(50),
+};
+
 list TweakList{
 "tweaks",
 cat(Features),
@@ -891,6 +899,7 @@ clangd accepts flags on the commandline, and in the 
CLANGD_FLAGS environment var
   Opts.BackgroundIndex = EnableBackgroundIndex;
   Opts.BackgroundIndexPriority = BackgroundIndexPriority;
   Opts.ReferencesLimit = ReferencesLimit;
+  Opts.Rename.LimitFiles = RenameFileLimit;
   auto PAI = createProjectAwareIndex(loadExternalIndex, Sync);
   if (StaticIdx) {
 IdxStack.emplace_back(std::move(StaticIdx));



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] 8b36687 - [clangd] Add highlighting modifier "constructorOrDestructor"

2022-10-21 Thread Christian Kandeler via cfe-commits

Author: Christian Kandeler
Date: 2022-10-21T15:14:38+02:00
New Revision: 8b3668754c889a9412a76035235b6fc581ca9863

URL: 
https://github.com/llvm/llvm-project/commit/8b3668754c889a9412a76035235b6fc581ca9863
DIFF: 
https://github.com/llvm/llvm-project/commit/8b3668754c889a9412a76035235b6fc581ca9863.diff

LOG: [clangd] Add highlighting modifier "constructorOrDestructor"

This is useful for clients that want to highlight constructors and
destructors different from classes, e.g. like functions.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D134728

Added: 


Modified: 
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/test/initialize-params.test
clang-tools-extra/clangd/test/semantic-tokens.test
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Removed: 




diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp 
b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index 1a6fa528acced..08cca2203667b 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -649,6 +649,29 @@ class CollectExtraHighlightings
 return true;
   }
 
+  bool VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+if (auto *TI = D->getNameInfo().getNamedTypeInfo()) {
+  SourceLocation Loc = TI->getTypeLoc().getBeginLoc();
+  H.addExtraModifier(Loc, HighlightingModifier::ConstructorOrDestructor);
+  H.addExtraModifier(Loc, HighlightingModifier::Declaration);
+  if (D->isThisDeclarationADefinition())
+H.addExtraModifier(Loc, HighlightingModifier::Definition);
+}
+return true;
+  }
+
+  bool VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) {
+if (isa(CE->getMethodDecl())) {
+  if (auto *ME = dyn_cast(CE->getCallee())) {
+if (auto *TI = ME->getMemberNameInfo().getNamedTypeInfo()) {
+  H.addExtraModifier(TI->getTypeLoc().getBeginLoc(),
+ HighlightingModifier::ConstructorOrDestructor);
+}
+  }
+}
+return true;
+  }
+
   bool VisitDeclaratorDecl(DeclaratorDecl *D) {
 auto *AT = D->getType()->getContainedAutoType();
 if (!AT)
@@ -879,6 +902,8 @@ std::vector 
getSemanticHighlightings(ParsedAST ) {
 Tok.addModifier(HighlightingModifier::DefaultLibrary);
   if (Decl->isDeprecated())
 Tok.addModifier(HighlightingModifier::Deprecated);
+  if (isa(Decl))
+Tok.addModifier(HighlightingModifier::ConstructorOrDestructor);
   if (R.IsDecl) {
 // Do not treat an UnresolvedUsingValueDecl as a declaration.
 // It's more common to think of it as a reference to the
@@ -960,6 +985,8 @@ llvm::raw_ostream <<(llvm::raw_ostream , 
HighlightingModifier K) {
 return OS << "decl"; // abbreviation for common case
   case HighlightingModifier::Definition:
 return OS << "def"; // abbrevation for common case
+  case HighlightingModifier::ConstructorOrDestructor:
+return OS << "constrDestr";
   default:
 return OS << toSemanticTokenModifier(K);
   }
@@ -,6 +1138,8 @@ llvm::StringRef 
toSemanticTokenModifier(HighlightingModifier Modifier) {
 return "defaultLibrary";
   case HighlightingModifier::UsedAsMutableReference:
 return "usedAsMutableReference"; // nonstandard
+  case HighlightingModifier::ConstructorOrDestructor:
+return "constructorOrDestructor"; // nonstandard
   case HighlightingModifier::FunctionScope:
 return "functionScope"; // nonstandard
   case HighlightingModifier::ClassScope:

diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.h 
b/clang-tools-extra/clangd/SemanticHighlighting.h
index 4fe2fc7aee54d..79ecb344275d1 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.h
+++ b/clang-tools-extra/clangd/SemanticHighlighting.h
@@ -71,6 +71,7 @@ enum class HighlightingModifier {
   DependentName,
   DefaultLibrary,
   UsedAsMutableReference,
+  ConstructorOrDestructor,
 
   FunctionScope,
   ClassScope,

diff  --git a/clang-tools-extra/clangd/test/initialize-params.test 
b/clang-tools-extra/clangd/test/initialize-params.test
index 031be9e147f74..eb958cac20279 100644
--- a/clang-tools-extra/clangd/test/initialize-params.test
+++ b/clang-tools-extra/clangd/test/initialize-params.test
@@ -68,6 +68,7 @@
 # CHECK-NEXT:"dependentName",
 # CHECK-NEXT:"defaultLibrary",
 # CHECK-NEXT:"usedAsMutableReference",
+# CHECK-NEXT:"constructorOrDestructor",
 # CHECK-NEXT:"functionScope",
 # CHECK-NEXT:"classScope",
 # CHECK-NEXT:"fileScope",

diff  --git a/clang-tools-extra/clangd/test/semantic-tokens.test 
b/clang-tools-extra/clangd/test/semantic-tokens.test
index b85d720ff5137..5abe78e9a51e1 100644
--- a/clang-tools-extra/clangd/test/semantic-tokens.test
+++