diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "InlayHints.h" #include "ParsedAST.h" +#include "SourceCode.h" #include "support/Logger.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExprCXX.h" @@ -102,11 +103,34 @@ if (ParamName == getSpelledIdentifier(Arg)) return false; - // FIXME: Exclude argument expressions preceded by a /*paramName=*/ comment. + // Exclude argument expressions preceded by a /*paramName*/. + // Allow the comment to contain spaces and optionally an "=" at the end. + if (getPrecedingComment(Arg).trim().rtrim("=").trim() == ParamName) + return false; return true; } + // If "E" is spelled in the main file and is preceded by a C-style comment, + // return the contents of that comment. + StringRef getPrecedingComment(const Expr *E) { + auto &SM = AST.getSourceManager(); + auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc()); + if (!ExprStartLoc.isFileID()) + return {}; + + StringRef SourcePrefix = sourcePrefix(ExprStartLoc, SM); + // Trim whitespace preceding expression. + SourcePrefix = SourcePrefix.rtrim(); + // Preceding token is not a C-style comment. + if (!SourcePrefix.endswith("*/")) + return {}; + // Trim end of comment. + SourcePrefix = SourcePrefix.substr(0, SourcePrefix.size() - 2); + // Find start of comment and get contents. + return SourcePrefix.substr(SourcePrefix.rfind("/*") + 2); + } + // If "E" spells a single unqualified identifier, return that name. // Otherwise, return an empty string. static StringRef getSpelledIdentifier(const Expr *E) { diff --git a/clang-tools-extra/clangd/SourceCode.h b/clang-tools-extra/clangd/SourceCode.h --- a/clang-tools-extra/clangd/SourceCode.h +++ b/clang-tools-extra/clangd/SourceCode.h @@ -321,6 +321,9 @@ /// Returns true if the given location is in a generated protobuf file. bool isProtoFile(SourceLocation Loc, const SourceManager &SourceMgr); +// Return the source code of the file containing Loc, from the start up to Loc. +llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM); + } // namespace clangd } // namespace clang #endif diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -1173,5 +1173,14 @@ return SM.getBufferData(FID).startswith(PROTO_HEADER_COMMENT); } +llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM) { + auto D = SM.getDecomposedLoc(Loc); + bool Invalid = false; + llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid); + if (Invalid || D.second > Buf.size()) + return ""; + return Buf.substr(0, D.second); +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -530,15 +530,6 @@ return !ExpandedTokens.empty(); } -llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM) { - auto D = SM.getDecomposedLoc(Loc); - bool Invalid = false; - llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid); - if (Invalid || D.second > Buf.size()) - return ""; - return Buf.substr(0, D.second); -} - bool isDependentName(ASTNodeKind NodeKind) { return NodeKind.isSame(ASTNodeKind::getFromNodeKind()) || NodeKind.isSame( diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -322,6 +322,20 @@ )cpp"); } +TEST(ParameterHints, ParamNameComment) { + // Do not hint an argument which already has a comment + // with the parameter name preceding it. + assertParameterHints(R"cpp( + void foo(int param); + void bar() { + foo(/*param*/42); + foo( /* param = */ 42); + foo(/* the answer */$param[[42]]); + } + )cpp", + ExpectedHint{"param: ", "param"}); +} + } // namespace } // namespace clangd } // namespace clang