Skip to content

Commit

Permalink
[clangd] Omit parameter hint if parameter name comment is present
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D100715
  • Loading branch information
HighCommander4 committed Apr 25, 2021
1 parent 337a024 commit 753b247
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 2 deletions.
38 changes: 36 additions & 2 deletions clang-tools-extra/clangd/InlayHints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ namespace clangd {
class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
public:
InlayHintVisitor(std::vector<InlayHint> &Results, ParsedAST &AST)
: Results(Results), AST(AST.getASTContext()) {}
: Results(Results), AST(AST.getASTContext()),
MainFileID(AST.getSourceManager().getMainFileID()) {
bool Invalid = false;
llvm::StringRef Buf =
AST.getSourceManager().getBufferData(MainFileID, &Invalid);
MainFileBuf = Invalid ? StringRef{} : Buf;
}

bool VisitCXXConstructExpr(CXXConstructExpr *E) {
// Weed out constructor calls that don't look like a function call with
Expand Down Expand Up @@ -102,11 +108,37 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
if (ParamName == getSpelledIdentifier(Arg))
return false;

// FIXME: Exclude argument expressions preceded by a /*paramName=*/ comment.
// Exclude argument expressions preceded by a /*paramName*/.
if (isPrecededByParamNameComment(Arg, ParamName))
return false;

return true;
}

// Checks if "E" is spelled in the main file and preceded by a C-style comment
// whose contents match ParamName (allowing for whitespace and an optional "="
// at the end.
bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
auto &SM = AST.getSourceManager();
auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
if (Decomposed.first != MainFileID)
return false;

StringRef SourcePrefix = MainFileBuf.substr(0, Decomposed.second);
// Allow whitespace between comment and expression.
SourcePrefix = SourcePrefix.rtrim();
// Check for comment ending.
if (!SourcePrefix.consume_back("*/"))
return false;
// Allow whitespace and "=" at end of comment.
SourcePrefix = SourcePrefix.rtrim().rtrim('=').rtrim();
// Other than that, the comment must contain exactly ParamName.
if (!SourcePrefix.consume_back(ParamName))
return false;
return SourcePrefix.rtrim().endswith("/*");
}

// If "E" spells a single unqualified identifier, return that name.
// Otherwise, return an empty string.
static StringRef getSpelledIdentifier(const Expr *E) {
Expand Down Expand Up @@ -208,6 +240,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {

std::vector<InlayHint> &Results;
ASTContext &AST;
FileID MainFileID;
StringRef MainFileBuf;
};

std::vector<InlayHint> inlayHints(ParsedAST &AST) {
Expand Down
14 changes: 14 additions & 0 deletions clang-tools-extra/clangd/unittests/InlayHintTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,20 @@ TEST(ParameterHints, UserDefinedLiteral) {
)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

0 comments on commit 753b247

Please sign in to comment.