llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra Author: Mythreya Kuricheti (MythreyaK) <details> <summary>Changes</summary> Adds designator hints for direct init Fixes clangd/clangd#<!-- -->2541 --- Full diff: https://github.com/llvm/llvm-project/pull/176635.diff 5 Files Affected: - (modified) clang-tools-extra/clangd/AST.cpp (+17-3) - (modified) clang-tools-extra/clangd/AST.h (+2-1) - (modified) clang-tools-extra/clangd/Hover.cpp (+9-1) - (modified) clang-tools-extra/clangd/InlayHints.cpp (+30-1) - (modified) clang-tools-extra/clangd/unittests/InlayHintTests.cpp (+61) ``````````diff diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index 3bcc89d360cdb..d30968f580e2b 100644 --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -38,6 +38,7 @@ #include <iterator> #include <optional> #include <string> +#include <utility> #include <vector> namespace clang { @@ -824,6 +825,11 @@ class ForwardingCallVisitor return !Info.has_value(); } + bool VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { + RecordInfo = E->getType()->getAsCXXRecordDecl(); + return true; + } + bool VisitCXXConstructExpr(CXXConstructExpr *E) { auto *Callee = E->getConstructor(); if (Callee) { @@ -857,6 +863,7 @@ class ForwardingCallVisitor // The output of this visitor std::optional<ForwardingInfo> Info; + const CXXRecordDecl *RecordInfo{}; private: // inspects the given callee with the given args to check whether it @@ -977,7 +984,7 @@ class ForwardingCallVisitor } // namespace -SmallVector<const ParmVarDecl *> +std::variant<SmallVector<const ParmVarDecl *>, const CXXRecordDecl *> resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) { auto Parameters = D->parameters(); // If the function has a template parameter pack @@ -1006,9 +1013,15 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) { // Find call expressions involving the pack ForwardingCallVisitor V{Pack}; V.TraverseStmt(CurrentFunction->getBody()); + + // if fields are direct-initialized, then no more forwarding + if (V.RecordInfo) + return V.RecordInfo; + if (!V.Info) { break; } + // If we found something: Fill in non-pack parameters auto Info = *V.Info; HeadIt = std::copy(Info.Head.begin(), Info.Head.end(), HeadIt); @@ -1022,7 +1035,8 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) { if (const auto *Template = CurrentFunction->getPrimaryTemplate()) { bool NewFunction = SeenTemplates.insert(Template).second; if (!NewFunction) { - return {Parameters.begin(), Parameters.end()}; + return SmallVector<const ParmVarDecl *>{Parameters.begin(), + Parameters.end()}; } } } @@ -1032,7 +1046,7 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) { assert(TailIt.base() == HeadIt); return Result; } - return {Parameters.begin(), Parameters.end()}; + return SmallVector<const ParmVarDecl *>{Parameters.begin(), Parameters.end()}; } bool isExpandedFromParameterPack(const ParmVarDecl *D) { diff --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h index 2bb4943b6de0b..09fd109515d62 100644 --- a/clang-tools-extra/clangd/AST.h +++ b/clang-tools-extra/clangd/AST.h @@ -17,6 +17,7 @@ #include "index/Symbol.h" #include "index/SymbolID.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/SourceLocation.h" @@ -244,7 +245,7 @@ bool isDeeplyNested(const Decl *D, unsigned MaxDepth = 10); /// parameters to another function via variadic template parameters. This can /// for example be used to retrieve the constructor parameter ParmVarDecl for a /// make_unique or emplace_back call. -llvm::SmallVector<const ParmVarDecl *> +std::variant<SmallVector<const ParmVarDecl *>, const CXXRecordDecl *> resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth = 10); /// Checks whether D is instantiated from a function parameter pack diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 3ce0d6258ea62..86d2b3ee83b25 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -63,6 +63,7 @@ #include <algorithm> #include <optional> #include <string> +#include <variant> #include <vector> namespace clang { @@ -1062,7 +1063,14 @@ void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI, HoverInfo::PassType PassType; - auto Parameters = resolveForwardingParameters(FD); + const auto Params = resolveForwardingParameters(FD); + + auto Parameters = [&]() -> SmallVector<const ParmVarDecl *> { + if (std::holds_alternative<SmallVector<const ParmVarDecl *>>(Params)) { + return std::get<SmallVector<const ParmVarDecl *>>(Params); + } + return {}; + }(); // Find argument index for N. for (unsigned I = 0; I < Args.size() && I < Parameters.size(); ++I) { diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index 2290fbd98056d..3d3dbff2a4d14 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -773,11 +773,26 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> { bool HasNonDefaultArgs = false; ArrayRef<const ParmVarDecl *> Params, ForwardedParams; + // Resolve parameter packs to their forwarded parameter SmallVector<const ParmVarDecl *> ForwardedParamsStorage; + // If args are direct-initialized + const CXXRecordDecl *CxxRecord{}; + if (Callee.Decl) { Params = maybeDropCxxExplicitObjectParameters(Callee.Decl->parameters()); - ForwardedParamsStorage = resolveForwardingParameters(Callee.Decl); + + [&]() { + auto Params = resolveForwardingParameters(Callee.Decl); + if (std::holds_alternative<decltype(ForwardedParamsStorage)>(Params)) { + ForwardedParamsStorage = + std::get<decltype(ForwardedParamsStorage)>(Params); + } + if (std::holds_alternative<decltype(CxxRecord)>(Params)) { + CxxRecord = std::get<decltype(CxxRecord)>(Params); + } + }(); + ForwardedParams = maybeDropCxxExplicitObjectParameters(ForwardedParamsStorage); } else { @@ -787,6 +802,20 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> { NameVec ParameterNames = chooseParameterNames(ForwardedParams); + if (CxxRecord) { + const auto ParamArgs = Args.drop_front(CxxRecord->getNumBases()); + const auto Iter = llvm::zip(ParamArgs, CxxRecord->fields()); + + for (const auto &[ParamArg, Field] : Iter) { + addInlayHint(ParamArg->getSourceRange(), HintSide::Left, + InlayHintKind::Parameter, + Field->getType()->isReferenceType() ? "&." : ".", + Field->getName(), ": "); + } + + return; + } + // Exclude setters (i.e. functions with one argument whose name begins with // "set"), and builtins like std::move/forward/... as their parameter name // is also not likely to be interesting. diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp index 5552aa178a354..f6ed9683fd0db 100644 --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -1955,6 +1955,67 @@ TEST(ParameterHints, DoesntExpandAllArgs) { ExpectedHint{"c: ", "param3"}); } +TEST(ParameterHints, CXX20AggregateParenInitNoCtor) { + assertParameterHints( + R"cpp( + namespace std { + // This prototype of std::forward is sufficient for clang to recognize it + template <typename T> T&& forward(T&); + } + + template<typename T, typename ...Args> + T* make_unique(Args&&...args) { + return new T(std::forward<Args>(args)...); + } + + struct Point { + int& x; + int y; + int z; + }; + + int foo() { + int t = 42; + make_unique<Point>($px[[t]], $py[[2]]); + } + )cpp", + ExpectedHint{"&.x: ", "px"}, ExpectedHint{".y: ", "py"}); +} + +TEST(ParameterHints, CXX20AggregateParenInitNoCtorDerived) { + assertParameterHints( + R"cpp( + namespace std { + // This prototype of std::forward is sufficient for clang to recognize it + template <typename T> T&& forward(T&); + } + + template<typename T, typename ...Args> + T* make_unique(Args&&...args) { + return new T(std::forward<Args>(args)...); + } + + struct Col { + unsigned short r {}; + unsigned short g {}; + unsigned short b {}; + }; + + struct Point : public Col { + int& x; + int y; + int z; + }; + + int foo() { + Col c {}; + int t = 42; + make_unique<Point>(c, $px[[t]], $py[[2]]); + } + )cpp", + ExpectedHint{"&.x: ", "px"}, ExpectedHint{".y: ", "py"}); +} + TEST(BlockEndHints, Functions) { assertBlockEndHints(R"cpp( int foo() { `````````` </details> https://github.com/llvm/llvm-project/pull/176635 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
