[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/95712 >From 07e5dcc71dc20c9d7482fc076cbeeb5e97a797d7 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Wed, 19 Jun 2024 09:55:34 -0400 Subject: [PATCH 1/2] after comments --- clang-tools-extra/clangd/Config.h | 2 + clang-tools-extra/clangd/ConfigCompile.cpp| 11 ++- clang-tools-extra/clangd/ConfigFragment.h | 5 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 9 +- clang-tools-extra/clangd/InlayHints.cpp | 87 ++- clang-tools-extra/clangd/Protocol.cpp | 6 ++ clang-tools-extra/clangd/Protocol.h | 15 .../clangd/unittests/InlayHintTests.cpp | 57 8 files changed, 187 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 41143b9ebc8d2..5100214244454 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -148,6 +148,8 @@ struct Config { bool DeducedTypes = true; bool Designators = true; bool BlockEnd = false; +bool LambdaCaptures = false; +bool DefaultArguments = false; // Limit the length of type names in inlay hints. (0 means no limit) uint32_t TypeNameLimit = 32; } InlayHints; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index f32f674443ffe..89486ce9fa034 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -43,7 +43,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" -#include #include #include #include @@ -654,6 +653,16 @@ struct FragmentCompiler { Out.Apply.push_back([Value(**F.BlockEnd)](const Params &, Config ) { C.InlayHints.BlockEnd = Value; }); +if (F.LambdaCaptures) + Out.Apply.push_back( + [Value(**F.LambdaCaptures)](const Params &, Config ) { +C.InlayHints.LambdaCaptures = Value; + }); +if (F.DefaultArguments) + Out.Apply.push_back( + [Value(**F.DefaultArguments)](const Params &, Config ) { +C.InlayHints.DefaultArguments = Value; + }); if (F.TypeNameLimit) Out.Apply.push_back( [Value(**F.TypeNameLimit)](const Params &, Config ) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index f3e51a9b6dbc4..ad30b43f34874 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -331,6 +331,11 @@ struct Fragment { std::optional> Designators; /// Show defined symbol names at the end of a definition block. std::optional> BlockEnd; +/// Show names of captured variables by default capture groups in lambdas. +std::optional> LambdaCaptures; +/// Show parameter names and default values of default arguments after all +/// of the explicit arguments. +std::optional> DefaultArguments; /// Limit the length of type name hints. (0 means no limit) std::optional> TypeNameLimit; }; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 3e9b6a07d3b32..58e5f8bead101 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -14,7 +14,6 @@ #include "llvm/Support/YAMLParser.h" #include #include -#include namespace clang { namespace clangd { @@ -264,6 +263,14 @@ class Parser { if (auto Value = boolValue(N, "BlockEnd")) F.BlockEnd = *Value; }); +Dict.handle("LambdaCaptures", [&](Node ) { + if (auto Value = boolValue(N, "LambdaCaptures")) +F.LambdaCaptures = *Value; +}); +Dict.handle("DefaultArguments", [&](Node ) { + if (auto Value = boolValue(N, "DefaultArguments")) +F.DefaultArguments = *Value; +}); Dict.handle("TypeNameLimit", [&](Node ) { if (auto Value = uint32Value(N, "TypeNameLimit")) F.TypeNameLimit = *Value; diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index cd4f1931b3ce1..2631c17409eab 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -11,27 +11,37 @@ #include "Config.h" #include "HeuristicResolver.h" #include "ParsedAST.h" +#include "Protocol.h" #include "SourceCode.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/Lambda.h" #include "clang/Basic/OperatorKinds.h" +#include
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
torshepherd wrote: Ok I took a stab at doing lambda captures as hover instead. - Targeting the exact '=' or '&' is nontrivial since the capture list isn't in the AST, the lambda is just `LambdaExpr` with children for the parameters and the CompoundStmt body. - `auto MyLambda = [...` already produces a nice function-like hover over the variable. I tested adding a "Captures:" bullet-list, it works well enough but isn't very noticeable. - We could take the above HoverInfo over the variable containing the lambda and apply it to hovering the lambda itself as well? It strikes me, if we could either add HoverInfo or styling to the variables within the body of the lambda themselves, that would be the most readable representation probably. For instance: - Can we add an inlay hint like `[&] ` before actual variables in the body of the lambda? - Can we apply a semantic token to style lambda captures differently? Maybe as `property` since they are similar conceptually to struct members? - Can we use the `mutable`-ness of the lambda to color tokens as const if they are captured by copy and the lambda is not mutable? Overall I think capture hints should be removed from this PR so we can get default args in in the meantime. https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/95712 >From 3830a49faf5e20781f864d459f5478221740ac3d Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Wed, 19 Jun 2024 09:55:34 -0400 Subject: [PATCH 1/2] after comments --- clang-tools-extra/clangd/Config.h | 2 + clang-tools-extra/clangd/ConfigCompile.cpp| 11 ++- clang-tools-extra/clangd/ConfigFragment.h | 5 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 9 +- clang-tools-extra/clangd/InlayHints.cpp | 87 ++- clang-tools-extra/clangd/Protocol.cpp | 6 ++ clang-tools-extra/clangd/Protocol.h | 15 .../clangd/unittests/InlayHintTests.cpp | 57 8 files changed, 187 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 41143b9ebc8d2..5100214244454 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -148,6 +148,8 @@ struct Config { bool DeducedTypes = true; bool Designators = true; bool BlockEnd = false; +bool LambdaCaptures = false; +bool DefaultArguments = false; // Limit the length of type names in inlay hints. (0 means no limit) uint32_t TypeNameLimit = 32; } InlayHints; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index f32f674443ffe..89486ce9fa034 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -43,7 +43,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" -#include #include #include #include @@ -654,6 +653,16 @@ struct FragmentCompiler { Out.Apply.push_back([Value(**F.BlockEnd)](const Params &, Config ) { C.InlayHints.BlockEnd = Value; }); +if (F.LambdaCaptures) + Out.Apply.push_back( + [Value(**F.LambdaCaptures)](const Params &, Config ) { +C.InlayHints.LambdaCaptures = Value; + }); +if (F.DefaultArguments) + Out.Apply.push_back( + [Value(**F.DefaultArguments)](const Params &, Config ) { +C.InlayHints.DefaultArguments = Value; + }); if (F.TypeNameLimit) Out.Apply.push_back( [Value(**F.TypeNameLimit)](const Params &, Config ) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index f3e51a9b6dbc4..ad30b43f34874 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -331,6 +331,11 @@ struct Fragment { std::optional> Designators; /// Show defined symbol names at the end of a definition block. std::optional> BlockEnd; +/// Show names of captured variables by default capture groups in lambdas. +std::optional> LambdaCaptures; +/// Show parameter names and default values of default arguments after all +/// of the explicit arguments. +std::optional> DefaultArguments; /// Limit the length of type name hints. (0 means no limit) std::optional> TypeNameLimit; }; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 3e9b6a07d3b32..58e5f8bead101 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -14,7 +14,6 @@ #include "llvm/Support/YAMLParser.h" #include #include -#include namespace clang { namespace clangd { @@ -264,6 +263,14 @@ class Parser { if (auto Value = boolValue(N, "BlockEnd")) F.BlockEnd = *Value; }); +Dict.handle("LambdaCaptures", [&](Node ) { + if (auto Value = boolValue(N, "LambdaCaptures")) +F.LambdaCaptures = *Value; +}); +Dict.handle("DefaultArguments", [&](Node ) { + if (auto Value = boolValue(N, "DefaultArguments")) +F.DefaultArguments = *Value; +}); Dict.handle("TypeNameLimit", [&](Node ) { if (auto Value = uint32Value(N, "TypeNameLimit")) F.TypeNameLimit = *Value; diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index cd4f1931b3ce1..2631c17409eab 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -11,27 +11,37 @@ #include "Config.h" #include "HeuristicResolver.h" #include "ParsedAST.h" +#include "Protocol.h" #include "SourceCode.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/Lambda.h" #include "clang/Basic/OperatorKinds.h" +#include
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/95712 >From 3830a49faf5e20781f864d459f5478221740ac3d Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Wed, 19 Jun 2024 09:55:34 -0400 Subject: [PATCH 1/2] after comments --- clang-tools-extra/clangd/Config.h | 2 + clang-tools-extra/clangd/ConfigCompile.cpp| 11 ++- clang-tools-extra/clangd/ConfigFragment.h | 5 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 9 +- clang-tools-extra/clangd/InlayHints.cpp | 87 ++- clang-tools-extra/clangd/Protocol.cpp | 6 ++ clang-tools-extra/clangd/Protocol.h | 15 .../clangd/unittests/InlayHintTests.cpp | 57 8 files changed, 187 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 41143b9ebc8d2..5100214244454 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -148,6 +148,8 @@ struct Config { bool DeducedTypes = true; bool Designators = true; bool BlockEnd = false; +bool LambdaCaptures = false; +bool DefaultArguments = false; // Limit the length of type names in inlay hints. (0 means no limit) uint32_t TypeNameLimit = 32; } InlayHints; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index f32f674443ffe..89486ce9fa034 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -43,7 +43,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" -#include #include #include #include @@ -654,6 +653,16 @@ struct FragmentCompiler { Out.Apply.push_back([Value(**F.BlockEnd)](const Params &, Config ) { C.InlayHints.BlockEnd = Value; }); +if (F.LambdaCaptures) + Out.Apply.push_back( + [Value(**F.LambdaCaptures)](const Params &, Config ) { +C.InlayHints.LambdaCaptures = Value; + }); +if (F.DefaultArguments) + Out.Apply.push_back( + [Value(**F.DefaultArguments)](const Params &, Config ) { +C.InlayHints.DefaultArguments = Value; + }); if (F.TypeNameLimit) Out.Apply.push_back( [Value(**F.TypeNameLimit)](const Params &, Config ) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index f3e51a9b6dbc4..ad30b43f34874 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -331,6 +331,11 @@ struct Fragment { std::optional> Designators; /// Show defined symbol names at the end of a definition block. std::optional> BlockEnd; +/// Show names of captured variables by default capture groups in lambdas. +std::optional> LambdaCaptures; +/// Show parameter names and default values of default arguments after all +/// of the explicit arguments. +std::optional> DefaultArguments; /// Limit the length of type name hints. (0 means no limit) std::optional> TypeNameLimit; }; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 3e9b6a07d3b32..58e5f8bead101 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -14,7 +14,6 @@ #include "llvm/Support/YAMLParser.h" #include #include -#include namespace clang { namespace clangd { @@ -264,6 +263,14 @@ class Parser { if (auto Value = boolValue(N, "BlockEnd")) F.BlockEnd = *Value; }); +Dict.handle("LambdaCaptures", [&](Node ) { + if (auto Value = boolValue(N, "LambdaCaptures")) +F.LambdaCaptures = *Value; +}); +Dict.handle("DefaultArguments", [&](Node ) { + if (auto Value = boolValue(N, "DefaultArguments")) +F.DefaultArguments = *Value; +}); Dict.handle("TypeNameLimit", [&](Node ) { if (auto Value = uint32Value(N, "TypeNameLimit")) F.TypeNameLimit = *Value; diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index cd4f1931b3ce1..2631c17409eab 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -11,27 +11,37 @@ #include "Config.h" #include "HeuristicResolver.h" #include "ParsedAST.h" +#include "Protocol.h" #include "SourceCode.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/Lambda.h" #include "clang/Basic/OperatorKinds.h" +#include
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
@@ -372,6 +382,34 @@ maybeDropCxxExplicitObjectParameters(ArrayRef Params) { return Params; } +llvm::StringRef getLambdaCaptureName(const LambdaCapture ) { + if (Capture.capturesVariable()) +return Capture.getCapturedVar()->getName(); + if (Capture.capturesThis()) +return llvm::StringRef{"this"}; + return llvm::StringRef{"unknown"}; +} + +template +std::string joinAndTruncate(R &, size_t MaxLength, +P &) { + std::string Out; + bool IsFirst = true; + for (auto & : Range) { +if (!IsFirst) + Out.append(", "); +else + IsFirst = false; torshepherd wrote: Changed this to use raw_string_ostream, lmk how it looks https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
@@ -372,6 +382,34 @@ maybeDropCxxExplicitObjectParameters(ArrayRef Params) { return Params; } +llvm::StringRef getLambdaCaptureName(const LambdaCapture ) { + if (Capture.capturesVariable()) +return Capture.getCapturedVar()->getName(); + if (Capture.capturesThis()) +return llvm::StringRef{"this"}; + return llvm::StringRef{"unknown"}; torshepherd wrote: Changed this to a switch case https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
@@ -15,9 +15,12 @@ #include "support/Context.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/raw_ostream.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include #include +#include torshepherd wrote: Yep, move https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/95712 >From 3830a49faf5e20781f864d459f5478221740ac3d Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Wed, 19 Jun 2024 09:55:34 -0400 Subject: [PATCH 1/2] after comments --- clang-tools-extra/clangd/Config.h | 2 + clang-tools-extra/clangd/ConfigCompile.cpp| 11 ++- clang-tools-extra/clangd/ConfigFragment.h | 5 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 9 +- clang-tools-extra/clangd/InlayHints.cpp | 87 ++- clang-tools-extra/clangd/Protocol.cpp | 6 ++ clang-tools-extra/clangd/Protocol.h | 15 .../clangd/unittests/InlayHintTests.cpp | 57 8 files changed, 187 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 41143b9ebc8d2..5100214244454 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -148,6 +148,8 @@ struct Config { bool DeducedTypes = true; bool Designators = true; bool BlockEnd = false; +bool LambdaCaptures = false; +bool DefaultArguments = false; // Limit the length of type names in inlay hints. (0 means no limit) uint32_t TypeNameLimit = 32; } InlayHints; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index f32f674443ffe..89486ce9fa034 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -43,7 +43,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" -#include #include #include #include @@ -654,6 +653,16 @@ struct FragmentCompiler { Out.Apply.push_back([Value(**F.BlockEnd)](const Params &, Config ) { C.InlayHints.BlockEnd = Value; }); +if (F.LambdaCaptures) + Out.Apply.push_back( + [Value(**F.LambdaCaptures)](const Params &, Config ) { +C.InlayHints.LambdaCaptures = Value; + }); +if (F.DefaultArguments) + Out.Apply.push_back( + [Value(**F.DefaultArguments)](const Params &, Config ) { +C.InlayHints.DefaultArguments = Value; + }); if (F.TypeNameLimit) Out.Apply.push_back( [Value(**F.TypeNameLimit)](const Params &, Config ) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index f3e51a9b6dbc4..ad30b43f34874 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -331,6 +331,11 @@ struct Fragment { std::optional> Designators; /// Show defined symbol names at the end of a definition block. std::optional> BlockEnd; +/// Show names of captured variables by default capture groups in lambdas. +std::optional> LambdaCaptures; +/// Show parameter names and default values of default arguments after all +/// of the explicit arguments. +std::optional> DefaultArguments; /// Limit the length of type name hints. (0 means no limit) std::optional> TypeNameLimit; }; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 3e9b6a07d3b32..58e5f8bead101 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -14,7 +14,6 @@ #include "llvm/Support/YAMLParser.h" #include #include -#include namespace clang { namespace clangd { @@ -264,6 +263,14 @@ class Parser { if (auto Value = boolValue(N, "BlockEnd")) F.BlockEnd = *Value; }); +Dict.handle("LambdaCaptures", [&](Node ) { + if (auto Value = boolValue(N, "LambdaCaptures")) +F.LambdaCaptures = *Value; +}); +Dict.handle("DefaultArguments", [&](Node ) { + if (auto Value = boolValue(N, "DefaultArguments")) +F.DefaultArguments = *Value; +}); Dict.handle("TypeNameLimit", [&](Node ) { if (auto Value = uint32Value(N, "TypeNameLimit")) F.TypeNameLimit = *Value; diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index cd4f1931b3ce1..2631c17409eab 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -11,27 +11,37 @@ #include "Config.h" #include "HeuristicResolver.h" #include "ParsedAST.h" +#include "Protocol.h" #include "SourceCode.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/Lambda.h" #include "clang/Basic/OperatorKinds.h" +#include
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/95712 >From 77bb21454b2110bed491689a4c323cff1c745207 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Sun, 16 Jun 2024 10:54:43 -0400 Subject: [PATCH] Add default arguments and lambda captures only --- clang-tools-extra/clangd/Config.h | 2 + clang-tools-extra/clangd/ConfigCompile.cpp| 19 ++-- clang-tools-extra/clangd/ConfigFragment.h | 5 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 9 +- clang-tools-extra/clangd/InlayHints.cpp | 87 ++- clang-tools-extra/clangd/Protocol.cpp | 8 +- clang-tools-extra/clangd/Protocol.h | 33 +-- .../clangd/unittests/InlayHintTests.cpp | 66 +- 8 files changed, 206 insertions(+), 23 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 41143b9ebc8d2..5100214244454 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -148,6 +148,8 @@ struct Config { bool DeducedTypes = true; bool Designators = true; bool BlockEnd = false; +bool LambdaCaptures = false; +bool DefaultArguments = false; // Limit the length of type names in inlay hints. (0 means no limit) uint32_t TypeNameLimit = 32; } InlayHints; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index f32f674443ffe..dcdb71ea01bb2 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -43,7 +43,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" -#include #include #include #include @@ -504,10 +503,10 @@ struct FragmentCompiler { auto Fast = isFastTidyCheck(Str); if (!Fast.has_value()) { diag(Warning, - llvm::formatv( - "Latency of clang-tidy check '{0}' is not known. " - "It will only run if ClangTidy.FastCheckFilter is Loose or None", - Str) + llvm::formatv("Latency of clang-tidy check '{0}' is not known. " + "It will only run if ClangTidy.FastCheckFilter is " + "Loose or None", + Str) .str(), Arg.Range); } else if (!*Fast) { @@ -654,6 +653,16 @@ struct FragmentCompiler { Out.Apply.push_back([Value(**F.BlockEnd)](const Params &, Config ) { C.InlayHints.BlockEnd = Value; }); +if (F.LambdaCaptures) + Out.Apply.push_back( + [Value(**F.LambdaCaptures)](const Params &, Config ) { +C.InlayHints.LambdaCaptures = Value; + }); +if (F.DefaultArguments) + Out.Apply.push_back( + [Value(**F.DefaultArguments)](const Params &, Config ) { +C.InlayHints.DefaultArguments = Value; + }); if (F.TypeNameLimit) Out.Apply.push_back( [Value(**F.TypeNameLimit)](const Params &, Config ) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index f3e51a9b6dbc4..ad30b43f34874 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -331,6 +331,11 @@ struct Fragment { std::optional> Designators; /// Show defined symbol names at the end of a definition block. std::optional> BlockEnd; +/// Show names of captured variables by default capture groups in lambdas. +std::optional> LambdaCaptures; +/// Show parameter names and default values of default arguments after all +/// of the explicit arguments. +std::optional> DefaultArguments; /// Limit the length of type name hints. (0 means no limit) std::optional> TypeNameLimit; }; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 3e9b6a07d3b32..58e5f8bead101 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -14,7 +14,6 @@ #include "llvm/Support/YAMLParser.h" #include #include -#include namespace clang { namespace clangd { @@ -264,6 +263,14 @@ class Parser { if (auto Value = boolValue(N, "BlockEnd")) F.BlockEnd = *Value; }); +Dict.handle("LambdaCaptures", [&](Node ) { + if (auto Value = boolValue(N, "LambdaCaptures")) +F.LambdaCaptures = *Value; +}); +Dict.handle("DefaultArguments", [&](Node ) { + if (auto Value = boolValue(N, "DefaultArguments")) +F.DefaultArguments = *Value; +}); Dict.handle("TypeNameLimit", [&](Node ) { if (auto Value = uint32Value(N, "TypeNameLimit")) F.TypeNameLimit = *Value; diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index cd4f1931b3ce1..2631c17409eab 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
@@ -504,10 +503,10 @@ struct FragmentCompiler { auto Fast = isFastTidyCheck(Str); if (!Fast.has_value()) { diag(Warning, - llvm::formatv( - "Latency of clang-tidy check '{0}' is not known. " - "It will only run if ClangTidy.FastCheckFilter is Loose or None", - Str) + llvm::formatv("Latency of clang-tidy check '{0}' is not known. " + "It will only run if ClangTidy.FastCheckFilter is " + "Loose or None", + Str) torshepherd wrote: Sorry, I think this was the formatter messing with it https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
@@ -1568,7 +1626,7 @@ TEST(TypeHints, SubstTemplateParameterAliases) { )cpp"; llvm::StringRef VectorIntPtr = R"cpp( -vector array; +vector $init[[array]]; torshepherd wrote: Another artifact, sorry https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
@@ -1458,13 +1463,66 @@ TEST(TypeHints, DefaultTemplateArgs) { struct A {}; A foo(); auto $var[[var]] = foo(); -A bar[1]; +A baz; +A bar[1]{}; torshepherd wrote: My fault, an artifact from a different set of inlay hints I decided not to include (show implicit default constructions with '{}') https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
@@ -15,9 +15,12 @@ #include "support/Context.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/raw_ostream.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include #include +#include torshepherd wrote: I believe std::move - let me check if they're still used in the latest revision though https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
torshepherd wrote: Aha, that's a great suggestion. I agree that beyond the trivial case of 2 captured variables it gets a bit noisy. On-hover would be quite nice though! To clarify, you mean hovering over the default capture '=' or '&' right? I'm happy to remove the lambdas from this PR in favor of the hover approach. Thoughts on the default arguments? https://github.com/llvm/llvm-project/pull/95712 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add inlay hints for default function arguments and implicit lambda captures (PR #95712)
https://github.com/torshepherd created https://github.com/llvm/llvm-project/pull/95712 Title. This PR adds support for showing implicit lambda captures: ![image](https://github.com/llvm/llvm-project/assets/49597791/d0150817-f71e-4971-8d8b-e25d2b1e8bf8) and defaulted function arguments: ![image](https://github.com/llvm/llvm-project/assets/49597791/2a6b83a9-b918-4363-be67-d79ce244b067) as inlay hints. If the list of captures (or default args) is too long (based on TypeNameLimit), shows "..." instead: ![image](https://github.com/llvm/llvm-project/assets/49597791/9bd5ee8c-ed73-44f9-821f-f2b29e612432) ![image](https://github.com/llvm/llvm-project/assets/49597791/c48acd28-091a-4d7d-9344-01e12c622024) Note: I wrote this before https://github.com/llvm/llvm-project/pull/85497 landed. With this we should probably also follow up with go-to-definition on the lambda captures at least; I could see that being helpful >From 741921857955983e1bce2ba828ec369568948688 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Sun, 16 Jun 2024 10:54:43 -0400 Subject: [PATCH] Add default arguments and lambda captures only --- clang-tools-extra/clangd/Config.h | 2 + clang-tools-extra/clangd/ConfigCompile.cpp| 19 ++-- clang-tools-extra/clangd/ConfigFragment.h | 5 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 9 +- clang-tools-extra/clangd/InlayHints.cpp | 87 ++- clang-tools-extra/clangd/Protocol.cpp | 8 +- clang-tools-extra/clangd/Protocol.h | 33 +-- .../clangd/unittests/InlayHintTests.cpp | 66 +- 8 files changed, 206 insertions(+), 23 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 41143b9ebc8d2..5100214244454 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -148,6 +148,8 @@ struct Config { bool DeducedTypes = true; bool Designators = true; bool BlockEnd = false; +bool LambdaCaptures = false; +bool DefaultArguments = false; // Limit the length of type names in inlay hints. (0 means no limit) uint32_t TypeNameLimit = 32; } InlayHints; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index f32f674443ffe..dcdb71ea01bb2 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -43,7 +43,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" -#include #include #include #include @@ -504,10 +503,10 @@ struct FragmentCompiler { auto Fast = isFastTidyCheck(Str); if (!Fast.has_value()) { diag(Warning, - llvm::formatv( - "Latency of clang-tidy check '{0}' is not known. " - "It will only run if ClangTidy.FastCheckFilter is Loose or None", - Str) + llvm::formatv("Latency of clang-tidy check '{0}' is not known. " + "It will only run if ClangTidy.FastCheckFilter is " + "Loose or None", + Str) .str(), Arg.Range); } else if (!*Fast) { @@ -654,6 +653,16 @@ struct FragmentCompiler { Out.Apply.push_back([Value(**F.BlockEnd)](const Params &, Config ) { C.InlayHints.BlockEnd = Value; }); +if (F.LambdaCaptures) + Out.Apply.push_back( + [Value(**F.LambdaCaptures)](const Params &, Config ) { +C.InlayHints.LambdaCaptures = Value; + }); +if (F.DefaultArguments) + Out.Apply.push_back( + [Value(**F.DefaultArguments)](const Params &, Config ) { +C.InlayHints.DefaultArguments = Value; + }); if (F.TypeNameLimit) Out.Apply.push_back( [Value(**F.TypeNameLimit)](const Params &, Config ) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index f3e51a9b6dbc4..ad30b43f34874 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -331,6 +331,11 @@ struct Fragment { std::optional> Designators; /// Show defined symbol names at the end of a definition block. std::optional> BlockEnd; +/// Show names of captured variables by default capture groups in lambdas. +std::optional> LambdaCaptures; +/// Show parameter names and default values of default arguments after all +/// of the explicit arguments. +std::optional> DefaultArguments; /// Limit the length of type name hints. (0 means no limit) std::optional> TypeNameLimit; }; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 3e9b6a07d3b32..58e5f8bead101 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -14,7 +14,6 @@ #include
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
torshepherd wrote: @HighCommander4 I've pushed up the change that doesn't allow conflicting fixits. I'll now be smoke-testing this over the coming weeks while I work, but consider it ready for review again whenever you have a chance https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/79867 >From 94dee94becb7d79b087e183754602e08a5c4669d Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Mon, 29 Jan 2024 11:44:25 -0500 Subject: [PATCH 1/2] [clangd] Add fix-all CodeActions --- clang-tools-extra/clangd/Diagnostics.cpp | 72 ++- clang-tools-extra/clangd/Protocol.h | 22 +- .../clangd/unittests/DiagnosticsTests.cpp | 200 +- 3 files changed, 227 insertions(+), 67 deletions(-) diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp index d5eca083eb651..37ee5cd8fbc7a 100644 --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -339,6 +339,72 @@ std::string noteMessage(const Diag , const DiagBase , return capitalize(std::move(Result)); } +std::optional +generateApplyAllFromOption(const llvm::StringRef Name, + llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto *const Diag : AllDiagnostics) { +for (const auto : Diag->Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + // Skip diagnostic categories that don't have multiple fixes to apply + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = llvm::formatv("apply all '{0}' fixes", Name); + return ApplyAll; +} + +std::optional +generateApplyAllFixesOption(llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto const : AllDiagnostics) { +for (const auto : Diag.Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = "apply all clangd fixes"; + return ApplyAll; +} + +void appendApplyAlls(std::vector ) { + llvm::DenseMap> CategorizedFixes; + + for (auto : AllDiagnostics) { +// Keep track of fixable diagnostics for generating "apply all fixes" +if (!Diag.Fixes.empty()) { + if (auto [It, DidEmplace] = CategorizedFixes.try_emplace( + Diag.Name, std::vector{}); + !DidEmplace) +It->second.emplace_back(); +} + } + + auto FixAllClangd = generateApplyAllFixesOption(AllDiagnostics); + for (const auto &[Name, DiagsForThisCategory] : CategorizedFixes) { +auto FixAllForCategory = +generateApplyAllFromOption(Name, DiagsForThisCategory); +for (auto *Diag : DiagsForThisCategory) { + if (DiagsForThisCategory.size() >= 2U && FixAllForCategory.has_value()) +Diag->Fixes.emplace_back(*FixAllForCategory); + if (CategorizedFixes.size() >= 2U && FixAllClangd.has_value()) +Diag->Fixes.emplace_back(*FixAllClangd); +} + } +} + void setTags(clangd::Diag ) { static const auto *DeprecatedDiags = new llvm::DenseSet{ diag::warn_access_decl_deprecated, @@ -575,7 +641,8 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { // Do not forget to emit a pending diagnostic if there is one. flushLastDiag(); - // Fill in name/source now that we have all the context needed to map them. + // Fill in name/source now that we have all the context needed to map + // them. for (auto : Output) { if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) { // Warnings controlled by -Wfoo are better recognized by that name. @@ -619,6 +686,9 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { llvm::erase_if(Output, [&](const Diag ) { return !SeenDiags.emplace(D.Range, D.Message).second; }); + + appendApplyAlls(Output); + return std::move(Output); } diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index 358d4c6feaf87..113629f138e41 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -257,6 +257,10 @@ inline bool operator==(const TextEdit , const TextEdit ) { return std::tie(L.newText, L.range, L.annotationId) == std::tie(R.newText, R.range, L.annotationId); } +inline bool operator<(const TextEdit , const TextEdit ) { + return std::tie(L.newText, L.range, L.annotationId) < + std::tie(R.newText, R.range, L.annotationId); +} bool fromJSON(const llvm::json::Value &, TextEdit &, llvm::json::Path); llvm::json::Value toJSON(const TextEdit &); llvm::raw_ostream <<(llvm::raw_ostream &, const TextEdit &); @@ -281,7 +285,7 @@ struct TextDocumentEdit { /// The text document to change. VersionedTextDocumentIdentifier textDocument; - /// The edits to be
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
torshepherd wrote: Ah, awesome. In that case note that I'll make the option not show up when changes would have conflicting overlap ranges https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [llvm] [clangd] Add CodeAction to swap operands to binary operators (PR #78999)
torshepherd wrote: Ping https://github.com/llvm/llvm-project/pull/78999 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
torshepherd wrote: Bump @HighCommander4 - did you get a chance to review this? I've been using this with great success in my local build for several months now, and the feature is _extremely_ handy. There is a slight bug that overlapping fixes are troublesome if you choose "clangd apply all", but it's minor. I can pretty easily push a fix to this, but I don't want to work more on this unless it has a chance of being reviewed/accepted https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/79867 >From 94dee94becb7d79b087e183754602e08a5c4669d Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Mon, 29 Jan 2024 11:44:25 -0500 Subject: [PATCH] [clangd] Add fix-all CodeActions --- clang-tools-extra/clangd/Diagnostics.cpp | 72 ++- clang-tools-extra/clangd/Protocol.h | 22 +- .../clangd/unittests/DiagnosticsTests.cpp | 200 +- 3 files changed, 227 insertions(+), 67 deletions(-) diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp index d5eca083eb6512..37ee5cd8fbc7ae 100644 --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -339,6 +339,72 @@ std::string noteMessage(const Diag , const DiagBase , return capitalize(std::move(Result)); } +std::optional +generateApplyAllFromOption(const llvm::StringRef Name, + llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto *const Diag : AllDiagnostics) { +for (const auto : Diag->Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + // Skip diagnostic categories that don't have multiple fixes to apply + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = llvm::formatv("apply all '{0}' fixes", Name); + return ApplyAll; +} + +std::optional +generateApplyAllFixesOption(llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto const : AllDiagnostics) { +for (const auto : Diag.Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = "apply all clangd fixes"; + return ApplyAll; +} + +void appendApplyAlls(std::vector ) { + llvm::DenseMap> CategorizedFixes; + + for (auto : AllDiagnostics) { +// Keep track of fixable diagnostics for generating "apply all fixes" +if (!Diag.Fixes.empty()) { + if (auto [It, DidEmplace] = CategorizedFixes.try_emplace( + Diag.Name, std::vector{}); + !DidEmplace) +It->second.emplace_back(); +} + } + + auto FixAllClangd = generateApplyAllFixesOption(AllDiagnostics); + for (const auto &[Name, DiagsForThisCategory] : CategorizedFixes) { +auto FixAllForCategory = +generateApplyAllFromOption(Name, DiagsForThisCategory); +for (auto *Diag : DiagsForThisCategory) { + if (DiagsForThisCategory.size() >= 2U && FixAllForCategory.has_value()) +Diag->Fixes.emplace_back(*FixAllForCategory); + if (CategorizedFixes.size() >= 2U && FixAllClangd.has_value()) +Diag->Fixes.emplace_back(*FixAllClangd); +} + } +} + void setTags(clangd::Diag ) { static const auto *DeprecatedDiags = new llvm::DenseSet{ diag::warn_access_decl_deprecated, @@ -575,7 +641,8 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { // Do not forget to emit a pending diagnostic if there is one. flushLastDiag(); - // Fill in name/source now that we have all the context needed to map them. + // Fill in name/source now that we have all the context needed to map + // them. for (auto : Output) { if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) { // Warnings controlled by -Wfoo are better recognized by that name. @@ -619,6 +686,9 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { llvm::erase_if(Output, [&](const Diag ) { return !SeenDiags.emplace(D.Range, D.Message).second; }); + + appendApplyAlls(Output); + return std::move(Output); } diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index 358d4c6feaf87d..113629f138e416 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -257,6 +257,10 @@ inline bool operator==(const TextEdit , const TextEdit ) { return std::tie(L.newText, L.range, L.annotationId) == std::tie(R.newText, R.range, L.annotationId); } +inline bool operator<(const TextEdit , const TextEdit ) { + return std::tie(L.newText, L.range, L.annotationId) < + std::tie(R.newText, R.range, L.annotationId); +} bool fromJSON(const llvm::json::Value &, TextEdit &, llvm::json::Path); llvm::json::Value toJSON(const TextEdit &); llvm::raw_ostream <<(llvm::raw_ostream &, const TextEdit &); @@ -281,7 +285,7 @@ struct TextDocumentEdit { /// The text document to change. VersionedTextDocumentIdentifier textDocument; - /// The edits to be
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
torshepherd wrote: Ping https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [llvm] [clangd] Add CodeAction to swap operands to binary operators (PR #78999)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/78999 >From 6abe2b5af090329bfca42d144597fbd5ca41d511 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Sun, 21 Jan 2024 17:53:31 -0500 Subject: [PATCH] [clangd] Swap binary operands --- .../clangd/refactor/tweaks/CMakeLists.txt | 1 + .../refactor/tweaks/SwapBinaryOperands.cpp| 210 ++ .../clangd/unittests/CMakeLists.txt | 1 + .../tweaks/SwapBinaryOperandsTests.cpp| 38 .../clangd/refactor/tweaks/BUILD.gn | 1 + .../clangd/unittests/BUILD.gn | 1 + 6 files changed, 252 insertions(+) create mode 100644 clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp create mode 100644 clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp diff --git a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt index 2e948c23569f68..59475b0dfd3d22 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt +++ b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangDaemonTweaks OBJECT RemoveUsingNamespace.cpp ScopifyEnum.cpp SpecialMembers.cpp + SwapBinaryOperands.cpp SwapIfBranches.cpp LINK_LIBS diff --git a/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp new file mode 100644 index 00..2241b0ac37b52a --- /dev/null +++ b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp @@ -0,0 +1,210 @@ +//===--- SwapBinaryOperands.cpp --*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +#include "ParsedAST.h" +#include "SourceCode.h" +#include "refactor/Tweak.h" +#include "support/Logger.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace clangd { +namespace { +/// Check whether it makes logical sense to swap operands to an operator. +/// Assignment or member access operators are rarely swappable +/// while keeping the meaning intact, whereas comparison operators, mathematical +/// operators, etc. are often desired to be swappable for readability, avoiding +/// bugs by assigning to nullptr when comparison was desired, etc. +auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool { + switch (Opcode) { + case BinaryOperatorKind::BO_Mul: + case BinaryOperatorKind::BO_Add: + case BinaryOperatorKind::BO_Cmp: + case BinaryOperatorKind::BO_LT: + case BinaryOperatorKind::BO_GT: + case BinaryOperatorKind::BO_LE: + case BinaryOperatorKind::BO_GE: + case BinaryOperatorKind::BO_EQ: + case BinaryOperatorKind::BO_NE: + case BinaryOperatorKind::BO_And: + case BinaryOperatorKind::BO_Xor: + case BinaryOperatorKind::BO_Or: + case BinaryOperatorKind::BO_LAnd: + case BinaryOperatorKind::BO_LOr: + case BinaryOperatorKind::BO_Comma: +return true; + // Noncommutative operators: + case BinaryOperatorKind::BO_Div: + case BinaryOperatorKind::BO_Sub: + case BinaryOperatorKind::BO_Shl: + case BinaryOperatorKind::BO_Shr: + case BinaryOperatorKind::BO_Rem: + // Member access: + case BinaryOperatorKind::BO_PtrMemD: + case BinaryOperatorKind::BO_PtrMemI: + // Assignment: + case BinaryOperatorKind::BO_Assign: + case BinaryOperatorKind::BO_MulAssign: + case BinaryOperatorKind::BO_DivAssign: + case BinaryOperatorKind::BO_RemAssign: + case BinaryOperatorKind::BO_AddAssign: + case BinaryOperatorKind::BO_SubAssign: + case BinaryOperatorKind::BO_ShlAssign: + case BinaryOperatorKind::BO_ShrAssign: + case BinaryOperatorKind::BO_AndAssign: + case BinaryOperatorKind::BO_XorAssign: + case BinaryOperatorKind::BO_OrAssign: +return false; + } + return false; +} + +/// Some operators are asymmetric and need to be flipped when swapping their +/// operands +/// @param[out] Opcode the opcode to potentially swap +/// If the opcode does not need to be swapped or is not swappable, does nothing +void swapOperator(BinaryOperatorKind ) { + switch (Opcode) { + case BinaryOperatorKind::BO_LT: +Opcode = BinaryOperatorKind::BO_GT; +return; + case BinaryOperatorKind::BO_GT: +Opcode = BinaryOperatorKind::BO_LT; +return; + case BinaryOperatorKind::BO_LE: +Opcode = BinaryOperatorKind::BO_GE; +return; + case
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/79867 >From 636e8286b38839c9d90e9eb147ba59d588c3241c Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Mon, 29 Jan 2024 11:44:25 -0500 Subject: [PATCH] [clangd] Add fix-all CodeActions --- clang-tools-extra/clangd/Diagnostics.cpp | 72 ++- clang-tools-extra/clangd/Protocol.h | 22 +- .../clangd/unittests/DiagnosticsTests.cpp | 200 +- 3 files changed, 227 insertions(+), 67 deletions(-) diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp index d5eca083eb6512..37ee5cd8fbc7ae 100644 --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -339,6 +339,72 @@ std::string noteMessage(const Diag , const DiagBase , return capitalize(std::move(Result)); } +std::optional +generateApplyAllFromOption(const llvm::StringRef Name, + llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto *const Diag : AllDiagnostics) { +for (const auto : Diag->Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + // Skip diagnostic categories that don't have multiple fixes to apply + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = llvm::formatv("apply all '{0}' fixes", Name); + return ApplyAll; +} + +std::optional +generateApplyAllFixesOption(llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto const : AllDiagnostics) { +for (const auto : Diag.Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = "apply all clangd fixes"; + return ApplyAll; +} + +void appendApplyAlls(std::vector ) { + llvm::DenseMap> CategorizedFixes; + + for (auto : AllDiagnostics) { +// Keep track of fixable diagnostics for generating "apply all fixes" +if (!Diag.Fixes.empty()) { + if (auto [It, DidEmplace] = CategorizedFixes.try_emplace( + Diag.Name, std::vector{}); + !DidEmplace) +It->second.emplace_back(); +} + } + + auto FixAllClangd = generateApplyAllFixesOption(AllDiagnostics); + for (const auto &[Name, DiagsForThisCategory] : CategorizedFixes) { +auto FixAllForCategory = +generateApplyAllFromOption(Name, DiagsForThisCategory); +for (auto *Diag : DiagsForThisCategory) { + if (DiagsForThisCategory.size() >= 2U && FixAllForCategory.has_value()) +Diag->Fixes.emplace_back(*FixAllForCategory); + if (CategorizedFixes.size() >= 2U && FixAllClangd.has_value()) +Diag->Fixes.emplace_back(*FixAllClangd); +} + } +} + void setTags(clangd::Diag ) { static const auto *DeprecatedDiags = new llvm::DenseSet{ diag::warn_access_decl_deprecated, @@ -575,7 +641,8 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { // Do not forget to emit a pending diagnostic if there is one. flushLastDiag(); - // Fill in name/source now that we have all the context needed to map them. + // Fill in name/source now that we have all the context needed to map + // them. for (auto : Output) { if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) { // Warnings controlled by -Wfoo are better recognized by that name. @@ -619,6 +686,9 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { llvm::erase_if(Output, [&](const Diag ) { return !SeenDiags.emplace(D.Range, D.Message).second; }); + + appendApplyAlls(Output); + return std::move(Output); } diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index e88c804692568f..d1e6cf35f9d9de 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -257,6 +257,10 @@ inline bool operator==(const TextEdit , const TextEdit ) { return std::tie(L.newText, L.range, L.annotationId) == std::tie(R.newText, R.range, L.annotationId); } +inline bool operator<(const TextEdit , const TextEdit ) { + return std::tie(L.newText, L.range, L.annotationId) < + std::tie(R.newText, R.range, L.annotationId); +} bool fromJSON(const llvm::json::Value &, TextEdit &, llvm::json::Path); llvm::json::Value toJSON(const TextEdit &); llvm::raw_ostream <<(llvm::raw_ostream &, const TextEdit &); @@ -281,7 +285,7 @@ struct TextDocumentEdit { /// The text document to change. VersionedTextDocumentIdentifier textDocument; - /// The edits to be
[llvm] [clang] [clang-tools-extra] [clangd] Add CodeAction to swap operands to binary operators (PR #78999)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/78999 >From c22c4fc969af0860b1fb2c371d31c2757da70e01 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Sun, 21 Jan 2024 17:53:31 -0500 Subject: [PATCH 1/2] swap binary --- .../clangd/refactor/tweaks/CMakeLists.txt | 1 + .../refactor/tweaks/SwapBinaryOperands.cpp| 214 ++ .../clangd/unittests/CMakeLists.txt | 1 + .../tweaks/SwapBinaryOperandsTests.cpp| 29 +++ .../clangd/refactor/tweaks/BUILD.gn | 1 + .../clangd/unittests/BUILD.gn | 1 + 6 files changed, 247 insertions(+) create mode 100644 clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp create mode 100644 clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp diff --git a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt index 2e948c23569f6..59475b0dfd3d2 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt +++ b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangDaemonTweaks OBJECT RemoveUsingNamespace.cpp ScopifyEnum.cpp SpecialMembers.cpp + SwapBinaryOperands.cpp SwapIfBranches.cpp LINK_LIBS diff --git a/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp new file mode 100644 index 0..e457319dfc303 --- /dev/null +++ b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp @@ -0,0 +1,214 @@ +//===--- SwapBinaryOperands.cpp --*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +#include "ParsedAST.h" +#include "SourceCode.h" +#include "refactor/Tweak.h" +#include "support/Logger.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace clangd { +namespace { +/// Check whether it makes logical sense to swap operands to an operator. +/// Assignment or member access operators are rarely swappable +/// while keeping the meaning intact, whereas comparison operators, mathematical +/// operators, etc. are often desired to be swappable for readability, avoiding +/// bugs by assigning to nullptr when comparison was desired, etc. +auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool { + switch (Opcode) { + case BinaryOperatorKind::BO_Mul: + case BinaryOperatorKind::BO_Add: + case BinaryOperatorKind::BO_Cmp: + case BinaryOperatorKind::BO_LT: + case BinaryOperatorKind::BO_GT: + case BinaryOperatorKind::BO_LE: + case BinaryOperatorKind::BO_GE: + case BinaryOperatorKind::BO_EQ: + case BinaryOperatorKind::BO_NE: + case BinaryOperatorKind::BO_And: + case BinaryOperatorKind::BO_Xor: + case BinaryOperatorKind::BO_Or: + case BinaryOperatorKind::BO_LAnd: + case BinaryOperatorKind::BO_LOr: + case BinaryOperatorKind::BO_Comma: +return true; + // Noncommutative operators: + case BinaryOperatorKind::BO_Div: + case BinaryOperatorKind::BO_Sub: + case BinaryOperatorKind::BO_Shl: + case BinaryOperatorKind::BO_Shr: + case BinaryOperatorKind::BO_Rem: + // Member access: + case BinaryOperatorKind::BO_PtrMemD: + case BinaryOperatorKind::BO_PtrMemI: + // Assignment: + case BinaryOperatorKind::BO_Assign: + case BinaryOperatorKind::BO_MulAssign: + case BinaryOperatorKind::BO_DivAssign: + case BinaryOperatorKind::BO_RemAssign: + case BinaryOperatorKind::BO_AddAssign: + case BinaryOperatorKind::BO_SubAssign: + case BinaryOperatorKind::BO_ShlAssign: + case BinaryOperatorKind::BO_ShrAssign: + case BinaryOperatorKind::BO_AndAssign: + case BinaryOperatorKind::BO_XorAssign: + case BinaryOperatorKind::BO_OrAssign: +return false; + } + return false; +} + +/// Some operators are asymmetric and need to be flipped when swapping their +/// operands +/// @param[out] Opcode the opcode to potentially swap +/// If the opcode does not need to be swapped or is not swappable, does nothing +void swapOperator(BinaryOperatorKind ) { + switch (Opcode) { + case BinaryOperatorKind::BO_LT: +Opcode = BinaryOperatorKind::BO_GT; +return; + case BinaryOperatorKind::BO_GT: +Opcode = BinaryOperatorKind::BO_LT; +return; + case BinaryOperatorKind::BO_LE: +Opcode = BinaryOperatorKind::BO_GE; +return; + case BinaryOperatorKind::BO_GE: +Opcode =
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
torshepherd wrote: Also pinging @kadircet who recently worked on Include Cleaner's similar batch fixes https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/79867 >From 7cb9e7b604a16414f31309b59747abbd7d3c0025 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Mon, 29 Jan 2024 11:44:25 -0500 Subject: [PATCH] [clangd] Add fix-all CodeActions --- clang-tools-extra/clangd/Diagnostics.cpp | 72 ++- clang-tools-extra/clangd/Protocol.h | 22 +- .../clangd/unittests/DiagnosticsTests.cpp | 200 +- 3 files changed, 227 insertions(+), 67 deletions(-) diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp index 704e61b1e4dd7..edef233be0290 100644 --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -339,6 +339,72 @@ std::string noteMessage(const Diag , const DiagBase , return capitalize(std::move(Result)); } +std::optional +generateApplyAllFromOption(const llvm::StringRef Name, + llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto *const Diag : AllDiagnostics) { +for (const auto : Diag->Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + // Skip diagnostic categories that don't have multiple fixes to apply + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = llvm::formatv("apply all '{0}' fixes", Name); + return ApplyAll; +} + +std::optional +generateApplyAllFixesOption(llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto const : AllDiagnostics) { +for (const auto : Diag.Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = "apply all clangd fixes"; + return ApplyAll; +} + +void appendApplyAlls(std::vector ) { + llvm::DenseMap> CategorizedFixes; + + for (auto : AllDiagnostics) { +// Keep track of fixable diagnostics for generating "apply all fixes" +if (!Diag.Fixes.empty()) { + if (auto [It, DidEmplace] = CategorizedFixes.try_emplace( + Diag.Name, std::vector{}); + !DidEmplace) +It->second.emplace_back(); +} + } + + auto FixAllClangd = generateApplyAllFixesOption(AllDiagnostics); + for (const auto &[Name, DiagsForThisCategory] : CategorizedFixes) { +auto FixAllForCategory = +generateApplyAllFromOption(Name, DiagsForThisCategory); +for (auto *Diag : DiagsForThisCategory) { + if (DiagsForThisCategory.size() >= 2U && FixAllForCategory.has_value()) +Diag->Fixes.emplace_back(*FixAllForCategory); + if (CategorizedFixes.size() >= 2U && FixAllClangd.has_value()) +Diag->Fixes.emplace_back(*FixAllClangd); +} + } +} + void setTags(clangd::Diag ) { static const auto *DeprecatedDiags = new llvm::DenseSet{ diag::warn_access_decl_deprecated, @@ -575,7 +641,8 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { // Do not forget to emit a pending diagnostic if there is one. flushLastDiag(); - // Fill in name/source now that we have all the context needed to map them. + // Fill in name/source now that we have all the context needed to map + // them. for (auto : Output) { if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) { // Warnings controlled by -Wfoo are better recognized by that name. @@ -619,6 +686,9 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { llvm::erase_if(Output, [&](const Diag ) { return !SeenDiags.emplace(D.Range, D.Message).second; }); + + appendApplyAlls(Output); + return std::move(Output); } diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index e88c804692568..d1e6cf35f9d9d 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -257,6 +257,10 @@ inline bool operator==(const TextEdit , const TextEdit ) { return std::tie(L.newText, L.range, L.annotationId) == std::tie(R.newText, R.range, L.annotationId); } +inline bool operator<(const TextEdit , const TextEdit ) { + return std::tie(L.newText, L.range, L.annotationId) < + std::tie(R.newText, R.range, L.annotationId); +} bool fromJSON(const llvm::json::Value &, TextEdit &, llvm::json::Path); llvm::json::Value toJSON(const TextEdit &); llvm::raw_ostream <<(llvm::raw_ostream &, const TextEdit &); @@ -281,7 +285,7 @@ struct TextDocumentEdit { /// The text document to change. VersionedTextDocumentIdentifier textDocument; - /// The edits to be
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/79867 >From 0ed7667a5b48064a492f7f125a4002912a35fec7 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Mon, 29 Jan 2024 11:44:25 -0500 Subject: [PATCH 1/2] initial cut --- clang-tools-extra/clangd/Diagnostics.cpp | 74 ++- clang-tools-extra/clangd/Protocol.h | 22 +- .../clangd/unittests/DiagnosticsTests.cpp | 200 +- 3 files changed, 229 insertions(+), 67 deletions(-) diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp index 704e61b1e4dd7..cf6d87cd45181 100644 --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -339,6 +339,74 @@ std::string noteMessage(const Diag , const DiagBase , return capitalize(std::move(Result)); } +std::optional +generateApplyAllFromOption(const llvm::StringRef Name, + llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto *const Diag : AllDiagnostics) { +for (const auto : Diag->Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + // Skip diagnostic categories that don't have multiple fixes to apply + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = llvm::formatv("apply all '{0}' fixes", Name); + return ApplyAll; +} + +std::optional +generateApplyAllFixesOption(llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto const : AllDiagnostics) { +for (const auto : Diag.Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = "apply all clangd fixes"; + return ApplyAll; +} + +void appendApplyAlls(std::vector ) { + llvm::DenseMap> CategorizedFixes; + size_t FixableOverall = 0U; + + for (auto : AllDiagnostics) { +// Keep track of fixable diagnostics for generating "apply all fixes" +if (!Diag.Fixes.empty()) { + ++FixableOverall; + if (auto [It, DidEmplace] = CategorizedFixes.try_emplace( + Diag.Name, std::vector{}); + !DidEmplace) +It->second.emplace_back(); +} + } + + auto FixAllClangd = generateApplyAllFixesOption(AllDiagnostics); + for (const auto &[Name, DiagsForThisCategory] : CategorizedFixes) { +auto FixAllForCategory = +generateApplyAllFromOption(Name, DiagsForThisCategory); +for (auto *Diag : DiagsForThisCategory) { + if (DiagsForThisCategory.size() >= 2U && FixAllForCategory.has_value()) +Diag->Fixes.emplace_back(*FixAllForCategory); + if (FixableOverall >= 2U && FixAllClangd.has_value()) +Diag->Fixes.emplace_back(*FixAllClangd); +} + } +} + void setTags(clangd::Diag ) { static const auto *DeprecatedDiags = new llvm::DenseSet{ diag::warn_access_decl_deprecated, @@ -575,7 +643,8 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { // Do not forget to emit a pending diagnostic if there is one. flushLastDiag(); - // Fill in name/source now that we have all the context needed to map them. + // Fill in name/source now that we have all the context needed to map + // them. for (auto : Output) { if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) { // Warnings controlled by -Wfoo are better recognized by that name. @@ -619,6 +688,9 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { llvm::erase_if(Output, [&](const Diag ) { return !SeenDiags.emplace(D.Range, D.Message).second; }); + + appendApplyAlls(Output); + return std::move(Output); } diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index e88c804692568..d1e6cf35f9d9d 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -257,6 +257,10 @@ inline bool operator==(const TextEdit , const TextEdit ) { return std::tie(L.newText, L.range, L.annotationId) == std::tie(R.newText, R.range, L.annotationId); } +inline bool operator<(const TextEdit , const TextEdit ) { + return std::tie(L.newText, L.range, L.annotationId) < + std::tie(R.newText, R.range, L.annotationId); +} bool fromJSON(const llvm::json::Value &, TextEdit &, llvm::json::Path); llvm::json::Value toJSON(const TextEdit &); llvm::raw_ostream <<(llvm::raw_ostream &, const TextEdit &); @@ -281,7 +285,7 @@ struct TextDocumentEdit { /// The text document to change. VersionedTextDocumentIdentifier textDocument; -
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
https://github.com/torshepherd edited https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
https://github.com/torshepherd edited https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
torshepherd wrote: Hmm I noticed another mini-issue. Ideally we shouldn't have a 'fix all clangd' quick fix if all of the issues come from the same source, only the 'fix all _' option https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
torshepherd wrote: Also, I noticed that the conversion function `toCodeAction(const Fix& F, ...)` specifically hardcodes all Fix objects to `QUICKFIX_KIND`. When we do https://github.com/clangd/clangd/issues/1446, it would be good to add a string for `SOURCE_FIX_ALL_KIND` and set these fix-alls to that `kind` https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
torshepherd wrote: Another thing that would be nice to solve in a follow-up (applies to unused includes as well btw) is to clean up the list of fixes when someone selects all and presses quick fix: ![image](https://github.com/llvm/llvm-project/assets/49597791/974d1426-0b8d-41f7-8532-0a5b454e3ac9) Not sure if this is possible server-side though https://github.com/llvm/llvm-project/pull/79867 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add 'apply all clangd fixes' and 'apply all '_' fixes' QuickFixes (PR #79867)
https://github.com/torshepherd created https://github.com/llvm/llvm-project/pull/79867 This PR adds the following features 1. If there are at least 2 distinct fixable diagnostics stemming from either `clang` or `clang-tidy` overall and their edits are distinct as well, we add a Fix to each one that applies all edits. 2. If there are at least 2 distinct fixable diagnostics stemming from the same code (either clang error source or clang-tidy check name) and their edits are distinct as well, we add a Fix to each one that applies all edits from that category. For example, ![image](https://github.com/llvm/llvm-project/assets/49597791/c419cf60-b689-4e87-8453-fecafba2d81b) This addresses https://github.com/clangd/clangd/issues/830 (the server-side approach). In a follow-up, I plan to address https://github.com/clangd/clangd/issues/1446 and listen for client-side fix all commands to do the same effect as 'apply all clangd fixes'. That only leaves https://github.com/clangd/clangd/issues/1536 as the last open thread on auto-fixes, and I think we can close that one as "won't do unless we get more interest". >From 0ed7667a5b48064a492f7f125a4002912a35fec7 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Mon, 29 Jan 2024 11:44:25 -0500 Subject: [PATCH] initial cut --- clang-tools-extra/clangd/Diagnostics.cpp | 74 ++- clang-tools-extra/clangd/Protocol.h | 22 +- .../clangd/unittests/DiagnosticsTests.cpp | 200 +- 3 files changed, 229 insertions(+), 67 deletions(-) diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp index 704e61b1e4dd792..cf6d87cd4518145 100644 --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -339,6 +339,74 @@ std::string noteMessage(const Diag , const DiagBase , return capitalize(std::move(Result)); } +std::optional +generateApplyAllFromOption(const llvm::StringRef Name, + llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto *const Diag : AllDiagnostics) { +for (const auto : Diag->Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + // Skip diagnostic categories that don't have multiple fixes to apply + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = llvm::formatv("apply all '{0}' fixes", Name); + return ApplyAll; +} + +std::optional +generateApplyAllFixesOption(llvm::ArrayRef AllDiagnostics) { + Fix ApplyAll; + for (auto const : AllDiagnostics) { +for (const auto : Diag.Fixes) + ApplyAll.Edits.insert(ApplyAll.Edits.end(), Fix.Edits.begin(), +Fix.Edits.end()); + } + llvm::sort(ApplyAll.Edits); + ApplyAll.Edits.erase( + std::unique(ApplyAll.Edits.begin(), ApplyAll.Edits.end()), + ApplyAll.Edits.end()); + if (ApplyAll.Edits.size() < 2U) { +return std::nullopt; + } + ApplyAll.Message = "apply all clangd fixes"; + return ApplyAll; +} + +void appendApplyAlls(std::vector ) { + llvm::DenseMap> CategorizedFixes; + size_t FixableOverall = 0U; + + for (auto : AllDiagnostics) { +// Keep track of fixable diagnostics for generating "apply all fixes" +if (!Diag.Fixes.empty()) { + ++FixableOverall; + if (auto [It, DidEmplace] = CategorizedFixes.try_emplace( + Diag.Name, std::vector{}); + !DidEmplace) +It->second.emplace_back(); +} + } + + auto FixAllClangd = generateApplyAllFixesOption(AllDiagnostics); + for (const auto &[Name, DiagsForThisCategory] : CategorizedFixes) { +auto FixAllForCategory = +generateApplyAllFromOption(Name, DiagsForThisCategory); +for (auto *Diag : DiagsForThisCategory) { + if (DiagsForThisCategory.size() >= 2U && FixAllForCategory.has_value()) +Diag->Fixes.emplace_back(*FixAllForCategory); + if (FixableOverall >= 2U && FixAllClangd.has_value()) +Diag->Fixes.emplace_back(*FixAllClangd); +} + } +} + void setTags(clangd::Diag ) { static const auto *DeprecatedDiags = new llvm::DenseSet{ diag::warn_access_decl_deprecated, @@ -575,7 +643,8 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { // Do not forget to emit a pending diagnostic if there is one. flushLastDiag(); - // Fill in name/source now that we have all the context needed to map them. + // Fill in name/source now that we have all the context needed to map + // them. for (auto : Output) { if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) { // Warnings controlled by -Wfoo are better recognized by that name. @@ -619,6 +688,9 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { llvm::erase_if(Output, [&](const
[clang-tools-extra] [clangd] Attempt to fix https://github.com/clangd/clangd/issues/1536 (PR #79448)
torshepherd wrote: I'll close this patch and pursue the other things we discussed https://github.com/llvm/llvm-project/pull/79448 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Attempt to fix https://github.com/clangd/clangd/issues/1536 (PR #79448)
https://github.com/torshepherd closed https://github.com/llvm/llvm-project/pull/79448 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang-tools-extra] [clangd] Add CodeAction to swap operands to binary operators (PR #78999)
@@ -0,0 +1,210 @@ +//===--- SwapBinaryOperands.cpp --*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +#include "ParsedAST.h" +#include "SourceCode.h" +#include "refactor/Tweak.h" +#include "support/Logger.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace clangd { +namespace { +/// Check whether it makes logical sense to swap operands to an operator. +/// Assignment or member access operators are rarely swappable +/// while keeping the meaning intact, whereas comparison operators, mathematical +/// operators, etc. are often desired to be swappable for readability, avoiding +/// bugs by assigning to nullptr when comparison was desired, etc. +auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool { + switch (Opcode) { + case BinaryOperatorKind::BO_Mul: + case BinaryOperatorKind::BO_Add: + case BinaryOperatorKind::BO_Cmp: + case BinaryOperatorKind::BO_LT: + case BinaryOperatorKind::BO_GT: + case BinaryOperatorKind::BO_LE: + case BinaryOperatorKind::BO_GE: + case BinaryOperatorKind::BO_EQ: + case BinaryOperatorKind::BO_NE: + case BinaryOperatorKind::BO_And: + case BinaryOperatorKind::BO_Xor: + case BinaryOperatorKind::BO_Or: + case BinaryOperatorKind::BO_LAnd: + case BinaryOperatorKind::BO_LOr: + case BinaryOperatorKind::BO_Comma: +return true; + // Noncommutative operators: + case BinaryOperatorKind::BO_Div: + case BinaryOperatorKind::BO_Sub: + case BinaryOperatorKind::BO_Shl: + case BinaryOperatorKind::BO_Shr: + case BinaryOperatorKind::BO_Rem: + // Member access: + case BinaryOperatorKind::BO_PtrMemD: + case BinaryOperatorKind::BO_PtrMemI: + // Assignment: + case BinaryOperatorKind::BO_Assign: + case BinaryOperatorKind::BO_MulAssign: + case BinaryOperatorKind::BO_DivAssign: + case BinaryOperatorKind::BO_RemAssign: + case BinaryOperatorKind::BO_AddAssign: + case BinaryOperatorKind::BO_SubAssign: + case BinaryOperatorKind::BO_ShlAssign: + case BinaryOperatorKind::BO_ShrAssign: + case BinaryOperatorKind::BO_AndAssign: + case BinaryOperatorKind::BO_XorAssign: + case BinaryOperatorKind::BO_OrAssign: +return false; + } + return false; +} + +/// Some operators are asymmetric and need to be flipped when swapping their +/// operands +/// @param[out] Opcode the opcode to potentially swap +/// If the opcode does not need to be swapped or is not swappable, does nothing +void swapOperator(BinaryOperatorKind ) { + switch (Opcode) { + case BinaryOperatorKind::BO_LT: +Opcode = BinaryOperatorKind::BO_GT; +return; + case BinaryOperatorKind::BO_GT: +Opcode = BinaryOperatorKind::BO_LT; +return; + case BinaryOperatorKind::BO_LE: +Opcode = BinaryOperatorKind::BO_GE; +return; + case BinaryOperatorKind::BO_GE: +Opcode = BinaryOperatorKind::BO_LE; +return; + case BinaryOperatorKind::BO_Mul: + case BinaryOperatorKind::BO_Add: + case BinaryOperatorKind::BO_Cmp: + case BinaryOperatorKind::BO_EQ: + case BinaryOperatorKind::BO_NE: + case BinaryOperatorKind::BO_And: + case BinaryOperatorKind::BO_Xor: + case BinaryOperatorKind::BO_Or: + case BinaryOperatorKind::BO_LAnd: + case BinaryOperatorKind::BO_LOr: + case BinaryOperatorKind::BO_Comma: + case BinaryOperatorKind::BO_Div: + case BinaryOperatorKind::BO_Sub: + case BinaryOperatorKind::BO_Shl: + case BinaryOperatorKind::BO_Shr: + case BinaryOperatorKind::BO_Rem: + case BinaryOperatorKind::BO_PtrMemD: + case BinaryOperatorKind::BO_PtrMemI: + case BinaryOperatorKind::BO_Assign: + case BinaryOperatorKind::BO_MulAssign: + case BinaryOperatorKind::BO_DivAssign: + case BinaryOperatorKind::BO_RemAssign: + case BinaryOperatorKind::BO_AddAssign: + case BinaryOperatorKind::BO_SubAssign: + case BinaryOperatorKind::BO_ShlAssign: + case BinaryOperatorKind::BO_ShrAssign: + case BinaryOperatorKind::BO_AndAssign: + case BinaryOperatorKind::BO_XorAssign: + case BinaryOperatorKind::BO_OrAssign: +return; + } +} + +/// Swaps the operands to a binary operator +/// Before: +/// x != nullptr +/// ^^^^ +/// After: +/// nullptr != x +class SwapBinaryOperands : public Tweak { +public: + const char *id() const final; + + bool prepare(const Selection ) override; + Expected apply(const Selection ) override; + std::string title() const override { +return llvm::formatv("Swap operands to {0}", +
[clang-tools-extra] [clangd] Attempt to fix https://github.com/clangd/clangd/issues/1536 (PR #79448)
https://github.com/torshepherd created https://github.com/llvm/llvm-project/pull/79448 This PR attempts to fix [1536.](https://github.com/clangd/clangd/issues/1536). See in the unit tests, when all quick fixes are of the same `code`, `isPreferred` will be true. However, this doesn't seem to change the behavior in vscode: ![image](https://github.com/llvm/llvm-project/assets/49597791/1d8236c3-3e43-4260-b655-d33d6cac6e42) >From 6bb871f64073132683bab2318c228a4ef7723c8e Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Wed, 24 Jan 2024 23:43:52 -0500 Subject: [PATCH 1/2] second try --- clang-tools-extra/clangd/ClangdLSPServer.cpp | 78 ++-- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index a87da252b7a7e9b..5fbd09fdcfdf420 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -27,7 +27,9 @@ #include "clang/Tooling/Core/Replacement.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Allocator.h" @@ -117,10 +119,9 @@ CodeAction toCodeAction(const Fix , const URIForFile , Edit.textDocument = VersionedTextDocumentIdentifier{{File}, Version}; for (const auto : F.Edits) Edit.edits.push_back( - {E.range, E.newText, - SupportChangeAnnotation ? E.annotationId : ""}); + {E.range, E.newText, SupportChangeAnnotation ? E.annotationId : ""}); if (SupportChangeAnnotation) { - for (const auto &[AID, Annotation]: F.Annotations) + for (const auto &[AID, Annotation] : F.Annotations) Action.edit->changeAnnotations[AID] = Annotation; } } @@ -861,24 +862,24 @@ void ClangdLSPServer::onRename(const RenameParams , if (!Server->getDraft(File)) return Reply(llvm::make_error( "onRename called for non-added file", ErrorCode::InvalidParams)); - Server->rename(File, Params.position, Params.newName, Opts.Rename, - [File, Params, Reply = std::move(Reply), - this](llvm::Expected R) mutable { - if (!R) - return Reply(R.takeError()); - if (auto Err = validateEdits(*Server, R->GlobalChanges)) - return Reply(std::move(Err)); - WorkspaceEdit Result; - // FIXME: use documentChanges if SupportDocumentChanges is - // true. - Result.changes.emplace(); - for (const auto : R->GlobalChanges) { - (*Result - .changes)[URI::createFile(Rep.first()).toString()] = - Rep.second.asTextEdits(); - } - Reply(Result); - }); + Server->rename( + File, Params.position, Params.newName, Opts.Rename, + [File, Params, Reply = std::move(Reply), + this](llvm::Expected R) mutable { +if (!R) + return Reply(R.takeError()); +if (auto Err = validateEdits(*Server, R->GlobalChanges)) + return Reply(std::move(Err)); +WorkspaceEdit Result; +// FIXME: use documentChanges if SupportDocumentChanges is +// true. +Result.changes.emplace(); +for (const auto : R->GlobalChanges) { + (*Result.changes)[URI::createFile(Rep.first()).toString()] = + Rep.second.asTextEdits(); +} +Reply(Result); + }); } void ClangdLSPServer::onDocumentDidClose( @@ -1014,7 +1015,7 @@ void ClangdLSPServer::onCodeAction(const CodeActionParams , std::map ToLSPDiags; ClangdServer::CodeActionInputs Inputs; - for (const auto& LSPDiag : Params.context.diagnostics) { + for (const auto : Params.context.diagnostics) { if (auto DiagRef = getDiagRef(File.file(), LSPDiag)) { ToLSPDiags[*DiagRef] = LSPDiag; Inputs.Diagnostics.push_back(*DiagRef); @@ -1023,13 +1024,9 @@ void ClangdLSPServer::onCodeAction(const CodeActionParams , Inputs.File = File.file(); Inputs.Selection = Params.range; Inputs.RequestedActionKinds = Params.context.only; - Inputs.TweakFilter = [this](const Tweak ) { -return Opts.TweakFilter(T); - }; - auto CB = [this, - Reply = std::move(Reply), - ToLSPDiags = std::move(ToLSPDiags), File, - Selection = Params.range]( + Inputs.TweakFilter = [this](const Tweak ) { return Opts.TweakFilter(T); }; + auto CB = [this, Reply = std::move(Reply), ToLSPDiags = std::move(ToLSPDiags), + File, Selection = Params.range]( llvm::Expected Fixits) mutable { if (!Fixits) return Reply(Fixits.takeError()); @@ -1038,27 +1035,34 @@ void
[llvm] [clang-tools-extra] [clangd] Add CodeAction to swap operands to binary operators (PR #78999)
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/78999 >From c22c4fc969af0860b1fb2c371d31c2757da70e01 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Sun, 21 Jan 2024 17:53:31 -0500 Subject: [PATCH 1/2] swap binary --- .../clangd/refactor/tweaks/CMakeLists.txt | 1 + .../refactor/tweaks/SwapBinaryOperands.cpp| 214 ++ .../clangd/unittests/CMakeLists.txt | 1 + .../tweaks/SwapBinaryOperandsTests.cpp| 29 +++ .../clangd/refactor/tweaks/BUILD.gn | 1 + .../clangd/unittests/BUILD.gn | 1 + 6 files changed, 247 insertions(+) create mode 100644 clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp create mode 100644 clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp diff --git a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt index 2e948c23569f686..59475b0dfd3d222 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt +++ b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangDaemonTweaks OBJECT RemoveUsingNamespace.cpp ScopifyEnum.cpp SpecialMembers.cpp + SwapBinaryOperands.cpp SwapIfBranches.cpp LINK_LIBS diff --git a/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp new file mode 100644 index 000..e457319dfc30370 --- /dev/null +++ b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp @@ -0,0 +1,214 @@ +//===--- SwapBinaryOperands.cpp --*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +#include "ParsedAST.h" +#include "SourceCode.h" +#include "refactor/Tweak.h" +#include "support/Logger.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace clangd { +namespace { +/// Check whether it makes logical sense to swap operands to an operator. +/// Assignment or member access operators are rarely swappable +/// while keeping the meaning intact, whereas comparison operators, mathematical +/// operators, etc. are often desired to be swappable for readability, avoiding +/// bugs by assigning to nullptr when comparison was desired, etc. +auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool { + switch (Opcode) { + case BinaryOperatorKind::BO_Mul: + case BinaryOperatorKind::BO_Add: + case BinaryOperatorKind::BO_Cmp: + case BinaryOperatorKind::BO_LT: + case BinaryOperatorKind::BO_GT: + case BinaryOperatorKind::BO_LE: + case BinaryOperatorKind::BO_GE: + case BinaryOperatorKind::BO_EQ: + case BinaryOperatorKind::BO_NE: + case BinaryOperatorKind::BO_And: + case BinaryOperatorKind::BO_Xor: + case BinaryOperatorKind::BO_Or: + case BinaryOperatorKind::BO_LAnd: + case BinaryOperatorKind::BO_LOr: + case BinaryOperatorKind::BO_Comma: +return true; + // Noncommutative operators: + case BinaryOperatorKind::BO_Div: + case BinaryOperatorKind::BO_Sub: + case BinaryOperatorKind::BO_Shl: + case BinaryOperatorKind::BO_Shr: + case BinaryOperatorKind::BO_Rem: + // Member access: + case BinaryOperatorKind::BO_PtrMemD: + case BinaryOperatorKind::BO_PtrMemI: + // Assignment: + case BinaryOperatorKind::BO_Assign: + case BinaryOperatorKind::BO_MulAssign: + case BinaryOperatorKind::BO_DivAssign: + case BinaryOperatorKind::BO_RemAssign: + case BinaryOperatorKind::BO_AddAssign: + case BinaryOperatorKind::BO_SubAssign: + case BinaryOperatorKind::BO_ShlAssign: + case BinaryOperatorKind::BO_ShrAssign: + case BinaryOperatorKind::BO_AndAssign: + case BinaryOperatorKind::BO_XorAssign: + case BinaryOperatorKind::BO_OrAssign: +return false; + } + return false; +} + +/// Some operators are asymmetric and need to be flipped when swapping their +/// operands +/// @param[out] Opcode the opcode to potentially swap +/// If the opcode does not need to be swapped or is not swappable, does nothing +void swapOperator(BinaryOperatorKind ) { + switch (Opcode) { + case BinaryOperatorKind::BO_LT: +Opcode = BinaryOperatorKind::BO_GT; +return; + case BinaryOperatorKind::BO_GT: +Opcode = BinaryOperatorKind::BO_LT; +return; + case BinaryOperatorKind::BO_LE: +Opcode = BinaryOperatorKind::BO_GE; +return; + case BinaryOperatorKind::BO_GE: +
[llvm] [clang-tools-extra] [clangd] Add CodeAction to swap operands to binary operators (PR #78999)
https://github.com/torshepherd created https://github.com/llvm/llvm-project/pull/78999 This MR resolves https://github.com/llvm/llvm-project/issues/78998 >From c22c4fc969af0860b1fb2c371d31c2757da70e01 Mon Sep 17 00:00:00 2001 From: Tor Shepherd Date: Sun, 21 Jan 2024 17:53:31 -0500 Subject: [PATCH 1/2] swap binary --- .../clangd/refactor/tweaks/CMakeLists.txt | 1 + .../refactor/tweaks/SwapBinaryOperands.cpp| 214 ++ .../clangd/unittests/CMakeLists.txt | 1 + .../tweaks/SwapBinaryOperandsTests.cpp| 29 +++ .../clangd/refactor/tweaks/BUILD.gn | 1 + .../clangd/unittests/BUILD.gn | 1 + 6 files changed, 247 insertions(+) create mode 100644 clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp create mode 100644 clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp diff --git a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt index 2e948c23569f68..59475b0dfd3d22 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt +++ b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangDaemonTweaks OBJECT RemoveUsingNamespace.cpp ScopifyEnum.cpp SpecialMembers.cpp + SwapBinaryOperands.cpp SwapIfBranches.cpp LINK_LIBS diff --git a/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp new file mode 100644 index 00..e457319dfc3037 --- /dev/null +++ b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp @@ -0,0 +1,214 @@ +//===--- SwapBinaryOperands.cpp --*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +#include "ParsedAST.h" +#include "SourceCode.h" +#include "refactor/Tweak.h" +#include "support/Logger.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace clangd { +namespace { +/// Check whether it makes logical sense to swap operands to an operator. +/// Assignment or member access operators are rarely swappable +/// while keeping the meaning intact, whereas comparison operators, mathematical +/// operators, etc. are often desired to be swappable for readability, avoiding +/// bugs by assigning to nullptr when comparison was desired, etc. +auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool { + switch (Opcode) { + case BinaryOperatorKind::BO_Mul: + case BinaryOperatorKind::BO_Add: + case BinaryOperatorKind::BO_Cmp: + case BinaryOperatorKind::BO_LT: + case BinaryOperatorKind::BO_GT: + case BinaryOperatorKind::BO_LE: + case BinaryOperatorKind::BO_GE: + case BinaryOperatorKind::BO_EQ: + case BinaryOperatorKind::BO_NE: + case BinaryOperatorKind::BO_And: + case BinaryOperatorKind::BO_Xor: + case BinaryOperatorKind::BO_Or: + case BinaryOperatorKind::BO_LAnd: + case BinaryOperatorKind::BO_LOr: + case BinaryOperatorKind::BO_Comma: +return true; + // Noncommutative operators: + case BinaryOperatorKind::BO_Div: + case BinaryOperatorKind::BO_Sub: + case BinaryOperatorKind::BO_Shl: + case BinaryOperatorKind::BO_Shr: + case BinaryOperatorKind::BO_Rem: + // Member access: + case BinaryOperatorKind::BO_PtrMemD: + case BinaryOperatorKind::BO_PtrMemI: + // Assignment: + case BinaryOperatorKind::BO_Assign: + case BinaryOperatorKind::BO_MulAssign: + case BinaryOperatorKind::BO_DivAssign: + case BinaryOperatorKind::BO_RemAssign: + case BinaryOperatorKind::BO_AddAssign: + case BinaryOperatorKind::BO_SubAssign: + case BinaryOperatorKind::BO_ShlAssign: + case BinaryOperatorKind::BO_ShrAssign: + case BinaryOperatorKind::BO_AndAssign: + case BinaryOperatorKind::BO_XorAssign: + case BinaryOperatorKind::BO_OrAssign: +return false; + } + return false; +} + +/// Some operators are asymmetric and need to be flipped when swapping their +/// operands +/// @param[out] Opcode the opcode to potentially swap +/// If the opcode does not need to be swapped or is not swappable, does nothing +void swapOperator(BinaryOperatorKind ) { + switch (Opcode) { + case BinaryOperatorKind::BO_LT: +Opcode = BinaryOperatorKind::BO_GT; +return; + case BinaryOperatorKind::BO_GT: +Opcode = BinaryOperatorKind::BO_LT; +return; + case BinaryOperatorKind::BO_LE: +Opcode =