-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clangd] Carefully handle PseudoObjectExprs for inlay hints #71366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clangd] Carefully handle PseudoObjectExprs for inlay hints #71366
Conversation
@llvm/pr-subscribers-clangd Author: Younan Zhang (zyn0217) ChangesThis closes clangd/clangd#1813. PseudoObjectExprs in C++ are currently not very interesting but probably mess up inlay hints. Full diff: https://github.com/llvm/llvm-project/pull/71366.diff 2 Files Affected:
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 3da047f95421385..867c70e5dbc80c6 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -589,6 +589,19 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
return true;
}
+ bool dataTraverseStmtPre(Stmt *S) {
+ // Do not show inlay hints for PseudoObjectExprs. They're never
+ // genuine user codes in C++.
+ //
+ // For example, __builtin_dump_struct would expand to a PseudoObjectExpr
+ // that includes a couple of calls to a printf function. Printing parameter
+ // names for that anyway would end up with duplicate parameter names (which,
+ // however, got de-duplicated after visiting) for the printf function.
+ if (AST.getLangOpts().CPlusPlus && isa<PseudoObjectExpr>(S))
+ return false;
+ return true;
+ }
+
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 20c1cdd985dbc01..2b6c27b17b537a9 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1724,6 +1724,30 @@ 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 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.
+ return s.x[1][2]; // Not `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)));
+}
+
TEST(ParameterHints, ArgPacksAndConstructors) {
assertParameterHints(
R"cpp(
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
On second thought I think I should not kill all the expressions involving |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it not possible to tell based on the CallExpr
only (rather than checking an ancestor of it during traversal of the tree) that "this CallExpr
is not explicitly written in the source"?
I'm not quite sure - Looking into the construction process for a llvm-project/clang/lib/Sema/SemaChecking.cpp Lines 482 to 509 in 4d5a8cc
the part that makes the call unordinary might be the nullish scope. I don't know if that implies "the expression is not written by users"; even so, extracting the scope of a call expression then performing the check doesn't look much more straightforward than this way. |
I see; it's a bit unfortunate that such an "invented" call expression gets an ordinary What do you think about the following idea: override the traversal of That leave the door open to a future enhancement where the arguments in the syntactic form (the |
Out of curiosity, I dialled into today's LLVM office hours and asked Aaron Ballman about this. He also did not see an obvious way to tell apart the invented |
Thank you so much for making the effort on this issue. :)
Interesting idea and I'll explore it. |
This closes clangd/clangd#1813. PseudoObjectExprs in C++ are currently not very interesting but probably mess up inlay hints.
…t to empty This reflects the comment in llvm#71366 (comment). As that PR suggests, the invented CallExpr's source location previously pointed to the beginning of the __builtin_dump_struct. These spurious AST nodes confused clangd while displaying parameter inlay hints. This patch takes another approach to address the same issue, by turning the location for each _argument_ within an invented call to printf to empty, (maybe) at the risk of breaking the invariant for CallExpr -- The source location for an argument could be invalid from now on.
9de5c59
to
c88aad6
Compare
Since the other PR turned out to be infeasible, I'm overriding |
Sorry for putting this off; I've updated it and please take another look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you!
This closes clangd/clangd#1813.
Not all subexpressions for a PseudoObjectExpr are interesting, and they probably mess up inlay hints.