[clang-tools-extra] 0fc69b1 - [clangd] Carefully handle PseudoObjectExprs for inlay hints (#71366)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Dec 2 23:27:49 PST 2023
Author: Younan Zhang
Date: 2023-12-03T02:27:45-05:00
New Revision: 0fc69b1402d75704744c73e15d278dcc8f437f0e
URL: https://github.com/llvm/llvm-project/commit/0fc69b1402d75704744c73e15d278dcc8f437f0e
DIFF: https://github.com/llvm/llvm-project/commit/0fc69b1402d75704744c73e15d278dcc8f437f0e.diff
LOG: [clangd] Carefully handle PseudoObjectExprs for inlay hints (#71366)
Not all subexpressions for a PseudoObjectExpr are interesting, and they
probably mess up inlay hints.
Fixes https://github.com/clangd/clangd/issues/1813.
Added:
Modified:
clang-tools-extra/clangd/InlayHints.cpp
clang-tools-extra/clangd/unittests/InlayHintTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 3da047f954213..b540c273cbd59 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -589,6 +589,31 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
return true;
}
+ // Carefully recurse into PseudoObjectExprs, which typically incorporate
+ // a syntactic expression and several semantic expressions.
+ bool TraversePseudoObjectExpr(PseudoObjectExpr *E) {
+ Expr *SyntacticExpr = E->getSyntacticForm();
+ if (isa<CallExpr>(SyntacticExpr))
+ // Since the counterpart semantics usually get the identical source
+ // locations as the syntactic one, visiting those would end up presenting
+ // confusing hints e.g., __builtin_dump_struct.
+ // Thus, only traverse the syntactic forms if this is written as a
+ // CallExpr. This leaves the door open in case the arguments in the
+ // syntactic form could possibly get parameter names.
+ return RecursiveASTVisitor<InlayHintVisitor>::TraverseStmt(SyntacticExpr);
+ // We don't want the hints for some of the MS property extensions.
+ // e.g.
+ // struct S {
+ // __declspec(property(get=GetX, put=PutX)) int x[];
+ // void PutX(int y);
+ // void Work(int y) { x = y; } // Bad: `x = y: y`.
+ // };
+ if (isa<BinaryOperator>(SyntacticExpr))
+ return true;
+ // FIXME: Handle other forms of a pseudo object expression.
+ return RecursiveASTVisitor<InlayHintVisitor>::TraversePseudoObjectExpr(E);
+ }
+
bool VisitCallExpr(CallExpr *E) {
if (!Cfg.InlayHints.Parameters)
return true;
diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 20c1cdd985dbc..6e91053632e00 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1709,7 +1709,8 @@ TEST(DesignatorHints, NoCrash) {
void test() {
Foo f{A(), $b[[1]]};
}
- )cpp", ExpectedHint{".b=", "b"});
+ )cpp",
+ ExpectedHint{".b=", "b"});
}
TEST(InlayHints, RestrictRange) {
@@ -1724,6 +1725,38 @@ TEST(InlayHints, RestrictRange) {
ElementsAre(labelIs(": int"), labelIs(": char")));
}
+TEST(ParameterHints, PseudoObjectExpr) {
+ Annotations Code(R"cpp(
+ struct S {
+ __declspec(property(get=GetX, put=PutX)) int x[];
+ int GetX(int y, int z) { return 42 + y; }
+ void PutX(int) { }
+
+ // This is a PseudoObjectExpression whose syntactic form is a binary
+ // operator.
+ void Work(int y) { x = y; } // Not `x = y: y`.
+ };
+
+ int printf(const char *Format, ...);
+
+ int main() {
+ S s;
+ __builtin_dump_struct(&s, printf); // Not `Format: __builtin_dump_struct()`
+ printf($Param[["Hello, %d"]], 42); // Normal calls are not affected.
+ // This builds a PseudoObjectExpr, but here it's useful for showing the
+ // arguments from the semantic form.
+ return s.x[ $one[[1]] ][ $two[[2]] ]; // `x[y: 1][z: 2]`
+ }
+ )cpp");
+ auto TU = TestTU::withCode(Code.code());
+ TU.ExtraArgs.push_back("-fms-extensions");
+ auto AST = TU.build();
+ EXPECT_THAT(inlayHints(AST, std::nullopt),
+ ElementsAre(HintMatcher(ExpectedHint{"Format: ", "Param"}, Code),
+ HintMatcher(ExpectedHint{"y: ", "one"}, Code),
+ HintMatcher(ExpectedHint{"z: ", "two"}, Code)));
+}
+
TEST(ParameterHints, ArgPacksAndConstructors) {
assertParameterHints(
R"cpp(
More information about the cfe-commits
mailing list