[clang] Pass FoundDecl to DeclRefExpr creator for operator overloads

Without the "found declaration" it is later not possible to know where the operator declaration
was brought into the scope calling it.

The initial motivation for this fix came from #55095. However, this also has an influence on
`clang -ast-dump` which now prints a `UsingShadow` attribute for operators only visible through
`using` statements. Also, clangd now correctly references the `using` statement instead of the
operator directly.

Reviewed By: shafik

Differential Revision: https://reviews.llvm.org/D129973
This commit is contained in:
Danny Mösch 2022-07-17 21:28:36 +02:00
parent 0538e5431a
commit 4e94f66531
8 changed files with 94 additions and 47 deletions

View File

@ -229,6 +229,11 @@ Changes in existing checks
where invalid parameters were implicitly being treated as being unused.
This fixes `Issue 56152 <https://github.com/llvm/llvm-project/issues/56152>`_.
- Fixed false positives in :doc:`misc-unused-using-decls
<clang-tidy/checks/misc/unused-using-decls>` where `using` statements bringing
operators into the scope where incorrectly marked as unused.
This fixes `issue 55095 <https://github.com/llvm/llvm-project/issues/55095>`_.
- Fixed a false positive in :doc:`modernize-deprecated-headers
<clang-tidy/checks/modernize/deprecated-headers>` involving including
C header files from C++ files wrapped by ``extern "C" { ... }`` blocks.

View File

@ -210,3 +210,14 @@ template <typename T, template <typename> class U> class Bar {};
// We used to report Q unsued, because we only checked the first template
// argument.
Bar<int, Q> *bar;
namespace internal {
struct S {};
int operator+(S s1, S s2);
}
// Make sure this statement is not reported as unused.
using internal::operator+;
using internal::S;
int j() { return S() + S(); }

View File

@ -202,6 +202,10 @@ Bug Fixes
considered to have one positive bit in order to represent the underlying
value. This effects whether we consider the store of the value one to be well
defined.
- An operator introduced to the scope via a `using` statement now correctly references this
statement in clangd (hover over the symbol, jump to definition) as well as in the AST dump.
This also fixes `issue 55095 <https://github.com/llvm/llvm-project/issues/#55095>`_ as a
side-effect.
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -63,8 +63,9 @@ static ExprResult CreateFunctionRefExpr(
// being used.
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
DeclRefExpr *DRE = new (S.Context)
DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
DeclRefExpr *DRE =
DeclRefExpr::Create(S.Context, Fn->getQualifierLoc(), SourceLocation(),
Fn, false, Loc, Fn->getType(), VK_LValue, FoundDecl);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);

View File

@ -24,21 +24,44 @@ void test() {
// CHECK-NEXT: |-FunctionDecl {{.*}} <line:12:1, col:19> col:6{{( imported)?}} used operator, 'void (E, E)'
// CHECK-NEXT: | |-ParmVarDecl {{.*}} <col:16> col:17{{( imported)?}} 'E'
// CHECK-NEXT: | `-ParmVarDecl {{.*}} <col:18> col:19{{( imported)?}} 'E'
// CHECK-NEXT: `-FunctionDecl {{.*}} <line:14:1, line:18:1> line:14:6{{( imported)?}} test 'void ()'
// CHECK-NEXT: `-CompoundStmt {{.*}} <col:13, line:18:1>
// CHECK-NEXT: |-DeclStmt {{.*}} <line:15:3, col:6>
// CHECK-NEXT: | `-VarDecl {{.*}} <col:3, col:5> col:5{{( imported)?}} used e 'E'
// CHECK-NEXT: |-CXXOperatorCallExpr {{.*}} <line:16:3, col:7> 'void' '+'
// CHECK-NEXT: | |-ImplicitCastExpr {{.*}} <col:5> 'void (*)(E, E)' <FunctionToPointerDecay>
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} <col:5> 'void (E, E)' lvalue Function {{.*}} 'operator+' 'void (E, E)'
// CHECK-NEXT: | |-ImplicitCastExpr {{.*}} <col:3> 'E' <LValueToRValue>
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} <col:3> 'E' lvalue Var {{.*}} 'e' 'E'
// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} <col:7> 'E' <LValueToRValue>
// CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:7> 'E' lvalue Var {{.*}} 'e' 'E'
// CHECK-NEXT: `-CXXOperatorCallExpr {{.*}} <line:17:3, col:7> 'void' ','
// CHECK-NEXT: |-ImplicitCastExpr {{.*}} <col:5> 'void (*)(E, E)' <FunctionToPointerDecay>
// CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:5> 'void (E, E)' lvalue Function {{.*}} 'operator,' 'void (E, E)'
// CHECK-NEXT: |-ImplicitCastExpr {{.*}} <col:3> 'E' <LValueToRValue>
// CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:3> 'E' lvalue Var {{.*}} 'e' 'E'
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} <col:7> 'E' <LValueToRValue>
// CHECK-NEXT: `-DeclRefExpr {{.*}} <col:7> 'E' lvalue Var {{.*}} 'e' 'E'
// CHECK-NEXT: |-FunctionDecl {{.*}} <line:14:1, line:18:1> line:14:6{{( imported)?}} test 'void ()'
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:13, line:18:1>
// CHECK-NEXT: | |-DeclStmt {{.*}} <line:15:3, col:6>
// CHECK-NEXT: | | `-VarDecl {{.*}} <col:3, col:5> col:5{{( imported)?}} used e 'E'
// CHECK-NEXT: | |-CXXOperatorCallExpr {{.*}} <line:16:3, col:7> 'void' '+'
// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} <col:5> 'void (*)(E, E)' <FunctionToPointerDecay>
// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} <col:5> 'void (E, E)' lvalue Function {{.*}} 'operator+' 'void (E, E)'
// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} <col:3> 'E' <LValueToRValue>
// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} <col:3> 'E' lvalue Var {{.*}} 'e' 'E'
// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} <col:7> 'E' <LValueToRValue>
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} <col:7> 'E' lvalue Var {{.*}} 'e' 'E'
// CHECK-NEXT: | `-CXXOperatorCallExpr {{.*}} <line:17:3, col:7> 'void' ','
// CHECK-NEXT: | |-ImplicitCastExpr {{.*}} <col:5> 'void (*)(E, E)' <FunctionToPointerDecay>
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} <col:5> 'void (E, E)' lvalue Function {{.*}} 'operator,' 'void (E, E)'
// CHECK-NEXT: | |-ImplicitCastExpr {{.*}} <col:3> 'E' <LValueToRValue>
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} <col:3> 'E' lvalue Var {{.*}} 'e' 'E'
// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} <col:7> 'E' <LValueToRValue>
// CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:7> 'E' lvalue Var {{.*}} 'e' 'E'
namespace a {
void operator-(E, E);
}
using a::operator-;
void f() {
E() - E();
}
// CHECK: |-NamespaceDecl {{.*}} <line:46:1, line:48:1> line:46:11{{( imported <undeserialized declarations>)?}} a
// CHECK-NEXT: | `-FunctionDecl {{.*}} <line:47:3, col:22> col:8{{( imported)?}} used operator- 'void (E, E)'
// CHECK-NEXT: | |-ParmVarDecl {{.*}} <col:18> col:19{{( imported)?}} 'E'
// CHECK-NEXT: | `-ParmVarDecl {{.*}} <col:21> col:22{{( imported)?}} 'E'
// CHECK-NEXT: |-UsingDecl {{.*}} <line:50:1, col:18> col:10{{( imported)?}} a::operator-
// CHECK-NEXT: |-UsingShadowDecl {{.*}} <col:10> col:10{{( imported)?}} implicit Function {{.*}} 'operator-' 'void (E, E)'
// CHECK-NEXT: `-FunctionDecl {{.*}} <line:52:1, line:54:1> line:52:6{{( imported)?}} f 'void ()'
// CHECK-NEXT: `-CompoundStmt {{.*}} <col:10, line:54:1>
// CHECK-NEXT: `-CXXOperatorCallExpr {{.*}} <line:53:3, col:11> 'void' '-'
// CHECK-NEXT: |-ImplicitCastExpr {{.*}} <col:7> 'void (*)(E, E)' <FunctionToPointerDecay>
// CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:7> 'void (E, E)' lvalue Function {{.*}} 'operator-' 'void (E, E)' (UsingShadow {{.*}} 'operator-')
// CHECK-NEXT: |-CXXScalarValueInitExpr {{.*}} <col:3, col:5> 'E'
// CHECK-NEXT: `-CXXScalarValueInitExpr {{.*}} <col:9, col:11> 'E'

View File

@ -17,68 +17,68 @@ void testFoo(Foo foo, int index) {
// RUN: c-index-test -test-annotate-tokens=%s:7:1:7:100 %s -std=c++11 -Wno-unused-value | FileCheck %s -check-prefix=CHECK1
// CHECK1: Identifier: "foo" [7:3 - 7:6] DeclRefExpr=foo:6:18
// CHECK1: Punctuation: "(" [7:6 - 7:7] DeclRefExpr=operator():3:7 RefName=[7:6 - 7:7] RefName=[7:7 - 7:8]
// CHECK1: Punctuation: ")" [7:7 - 7:8] DeclRefExpr=operator():3:7 RefName=[7:6 - 7:7] RefName=[7:7 - 7:8]
// CHECK1: Punctuation: "(" [7:6 - 7:7] CallExpr=operator():3:7
// CHECK1: Punctuation: ")" [7:7 - 7:8] CallExpr=operator():3:7
// CHECK1: Punctuation: ";" [7:8 - 7:9] CompoundStmt=
// RUN: c-index-test -test-annotate-tokens=%s:8:1:8:100 %s -std=c++11 -Wno-unused-value | FileCheck %s -check-prefix=CHECK2
// CHECK2: Punctuation: "(" [8:6 - 8:7] DeclRefExpr=operator():3:7 RefName=[8:6 - 8:7] RefName=[8:12 - 8:13]
// CHECK2: Punctuation: "(" [8:6 - 8:7] CallExpr=operator():3:7
// CHECK2: Identifier: "index" [8:7 - 8:12] DeclRefExpr=index:6:27
// CHECK2: Punctuation: ")" [8:12 - 8:13] DeclRefExpr=operator():3:7 RefName=[8:6 - 8:7] RefName=[8:12 - 8:13]
// CHECK2: Punctuation: ")" [8:12 - 8:13] CallExpr=operator():3:7
// CHECK2: Punctuation: ";" [8:13 - 8:14] CompoundStmt=
// RUN: c-index-test -test-annotate-tokens=%s:10:1:10:100 %s -std=c++11 -Wno-unused-value | FileCheck %s -check-prefix=CHECK3
// CHECK3: Identifier: "foo" [10:3 - 10:6] DeclRefExpr=foo:6:18
// CHECK3: Punctuation: "[" [10:6 - 10:7] DeclRefExpr=operator[]:2:7 RefName=[10:6 - 10:7] RefName=[10:12 - 10:13]
// CHECK3: Punctuation: "[" [10:6 - 10:7] CallExpr=operator[]:2:7
// CHECK3: Identifier: "index" [10:7 - 10:12] DeclRefExpr=index:6:27
// CHECK3: Punctuation: "]" [10:12 - 10:13] DeclRefExpr=operator[]:2:7 RefName=[10:6 - 10:7] RefName=[10:12 - 10:13]
// CHECK3: Punctuation: "]" [10:12 - 10:13] CallExpr=operator[]:2:7
// CHECK3: Punctuation: ";" [10:13 - 10:14] CompoundStmt=
// RUN: c-index-test -test-annotate-tokens=%s:11:1:11:100 %s -std=c++11 -Wno-unused-value | FileCheck %s -check-prefix=CHECK4
// CHECK4: Identifier: "foo" [11:3 - 11:6] DeclRefExpr=foo:6:18
// CHECK4: Punctuation: "[" [11:6 - 11:7] DeclRefExpr=operator[]:2:7 RefName=[11:6 - 11:7] RefName=[11:20 - 11:21]
// CHECK4: Punctuation: "[" [11:6 - 11:7] CallExpr=operator[]:2:7
// CHECK4: Identifier: "index" [11:7 - 11:12] DeclRefExpr=index:6:27
// CHECK4: Punctuation: "+" [11:13 - 11:14] BinaryOperator=
// CHECK4: Identifier: "index" [11:15 - 11:20] DeclRefExpr=index:6:27
// CHECK4: Punctuation: "]" [11:20 - 11:21] DeclRefExpr=operator[]:2:7 RefName=[11:6 - 11:7] RefName=[11:20 - 11:21]
// CHECK4: Punctuation: "]" [11:20 - 11:21] CallExpr=operator[]:2:7
// CHECK4: Punctuation: ";" [11:21 - 11:22] CompoundStmt=
// RUN: c-index-test -test-annotate-tokens=%s:13:1:13:100 %s -std=c++11 -Wno-unused-value | FileCheck %s -check-prefix=CHECK5
// CHECK5: Identifier: "foo" [13:3 - 13:6] DeclRefExpr=foo:6:18
// CHECK5: Punctuation: "[" [13:6 - 13:7] DeclRefExpr=operator[]:2:7 RefName=[13:6 - 13:7] RefName=[13:17 - 13:18]
// CHECK5: Punctuation: "[" [13:6 - 13:7] CallExpr=operator[]:2:7
// CHECK5: Identifier: "foo" [13:7 - 13:10] DeclRefExpr=foo:6:18
// CHECK5: Punctuation: "[" [13:10 - 13:11] DeclRefExpr=operator[]:2:7 RefName=[13:10 - 13:11] RefName=[13:16 - 13:17]
// CHECK5: Punctuation: "[" [13:10 - 13:11] CallExpr=operator[]:2:7
// CHECK5: Identifier: "index" [13:11 - 13:16] DeclRefExpr=index:6:27
// CHECK5: Punctuation: "]" [13:16 - 13:17] DeclRefExpr=operator[]:2:7 RefName=[13:10 - 13:11] RefName=[13:16 - 13:17]
// CHECK5: Punctuation: "]" [13:17 - 13:18] DeclRefExpr=operator[]:2:7 RefName=[13:6 - 13:7] RefName=[13:17 - 13:18]
// CHECK5: Punctuation: "]" [13:16 - 13:17] CallExpr=operator[]:2:7
// CHECK5: Punctuation: "]" [13:17 - 13:18] CallExpr=operator[]:2:7
// CHECK5: Punctuation: ";" [13:18 - 13:19] CompoundStmt=
// RUN: c-index-test -test-annotate-tokens=%s:14:1:14:100 %s -std=c++11 -Wno-unused-value | FileCheck %s -check-prefix=CHECK6
// CHECK6: Identifier: "foo" [14:3 - 14:6] DeclRefExpr=foo:6:18
// CHECK6: Punctuation: "[" [14:6 - 14:7] DeclRefExpr=operator[]:2:7 RefName=[14:6 - 14:7] RefName=[14:25 - 14:26]
// CHECK6: Punctuation: "[" [14:6 - 14:7] CallExpr=operator[]:2:7
// CHECK6: Identifier: "foo" [14:7 - 14:10] DeclRefExpr=foo:6:18
// CHECK6: Punctuation: "(" [14:10 - 14:11] DeclRefExpr=operator():3:7 RefName=[14:10 - 14:11] RefName=[14:11 - 14:12]
// CHECK6: Punctuation: ")" [14:11 - 14:12] DeclRefExpr=operator():3:7 RefName=[14:10 - 14:11] RefName=[14:11 - 14:12]
// CHECK6: Punctuation: "(" [14:10 - 14:11] CallExpr=operator():3:7
// CHECK6: Punctuation: ")" [14:11 - 14:12] CallExpr=operator():3:7
// CHECK6: Punctuation: "+" [14:13 - 14:14] BinaryOperator=
// CHECK6: Identifier: "foo" [14:15 - 14:18] DeclRefExpr=foo:6:18
// CHECK6: Punctuation: "[" [14:18 - 14:19] DeclRefExpr=operator[]:2:7 RefName=[14:18 - 14:19] RefName=[14:24 - 14:25]
// CHECK6: Identifier: "index" [14:19 - 14:24] DeclRefExpr=operator[]:2:7 RefName=[14:6 - 14:7] RefName=[14:25 - 14:26]
// CHECK6: Punctuation: "]" [14:24 - 14:25] DeclRefExpr=operator[]:2:7 RefName=[14:18 - 14:19] RefName=[14:24 - 14:25]
// CHECK6: Punctuation: "]" [14:25 - 14:26] DeclRefExpr=operator[]:2:7 RefName=[14:6 - 14:7] RefName=[14:25 - 14:26]
// CHECK6: Punctuation: "[" [14:18 - 14:19] CallExpr=operator[]:2:7
// CHECK6: Identifier: "index" [14:19 - 14:24] DeclRefExpr=index:6:27
// CHECK6: Punctuation: "]" [14:24 - 14:25] CallExpr=operator[]:2:7
// CHECK6: Punctuation: "]" [14:25 - 14:26] CallExpr=operator[]:2:7
// CHECK6: Punctuation: ";" [14:26 - 14:27] CompoundStmt=
// RUN: c-index-test -test-annotate-tokens=%s:15:1:15:100 %s -std=c++11 -Wno-unused-value | FileCheck %s -check-prefix=CHECK7
// CHECK7: Identifier: "foo" [15:3 - 15:6] DeclRefExpr=foo:6:18
// CHECK7: Punctuation: "[" [15:6 - 15:7] DeclRefExpr=operator[]:2:7 RefName=[15:6 - 15:7] RefName=[15:30 - 15:31]
// CHECK7: Punctuation: "[" [15:6 - 15:7] CallExpr=operator[]:2:7
// CHECK7: Identifier: "foo" [15:7 - 15:10] DeclRefExpr=foo:6:18
// CHECK7: Punctuation: "(" [15:10 - 15:11] DeclRefExpr=operator():3:7 RefName=[15:10 - 15:11] RefName=[15:16 - 15:17]
// CHECK7: Punctuation: "(" [15:10 - 15:11] CallExpr=operator():3:7
// CHECK7: Identifier: "index" [15:11 - 15:16] DeclRefExpr=index:6:27
// CHECK7: Punctuation: ")" [15:16 - 15:17] DeclRefExpr=operator():3:7 RefName=[15:10 - 15:11] RefName=[15:16 - 15:17]
// CHECK7: Punctuation: ")" [15:16 - 15:17] CallExpr=operator():3:7
// CHECK7: Punctuation: "+" [15:18 - 15:19] BinaryOperator=
// CHECK7: Identifier: "foo" [15:20 - 15:23] DeclRefExpr=foo:6:18
// CHECK7: Punctuation: "[" [15:23 - 15:24] DeclRefExpr=operator[]:2:7 RefName=[15:23 - 15:24] RefName=[15:29 - 15:30]
// CHECK7: Punctuation: "[" [15:23 - 15:24] CallExpr=operator[]:2:7
// CHECK7: Identifier: "index" [15:24 - 15:29] DeclRefExpr=index:6:27
// CHECK7: Punctuation: "]" [15:29 - 15:30] DeclRefExpr=operator[]:2:7 RefName=[15:23 - 15:24] RefName=[15:29 - 15:30]
// CHECK7: Punctuation: "]" [15:30 - 15:31] DeclRefExpr=operator[]:2:7 RefName=[15:6 - 15:7] RefName=[15:30 - 15:31]
// CHECK7: Punctuation: "]" [15:29 - 15:30] CallExpr=operator[]:2:7
// CHECK7: Punctuation: "]" [15:30 - 15:31] CallExpr=operator[]:2:7
// CHECK7: Punctuation: ";" [15:31 - 15:32] CompoundStmt=

View File

@ -33,9 +33,9 @@ int main()
// CHECK: cursor-ref-names.cpp:18:5: CallExpr=func:8:10 Extent=[18:5 - 18:16]
// CHECK: cursor-ref-names.cpp:18:10: MemberRefExpr=func:8:10 SingleRefName=[18:10 - 18:14] RefName=[18:10 - 18:14] Extent=[18:5 - 18:14]
// CHECK: cursor-ref-names.cpp:18:5: DeclRefExpr=inst:17:9 Extent=[18:5 - 18:9]
// CHECK: cursor-ref-names.cpp:19:5: CallExpr=operator[]:4:9 SingleRefName=[19:9 - 19:12] RefName=[19:9 - 19:10] RefName=[19:11 - 19:12] Extent=[19:5 - 19:12]
// CHECK: cursor-ref-names.cpp:19:5: CallExpr=operator[]:4:9 Extent=[19:5 - 19:12]
// CHECK: cursor-ref-names.cpp:19:5: DeclRefExpr=inst:17:9 Extent=[19:5 - 19:9]
// CHECK: cursor-ref-names.cpp:19:9: DeclRefExpr=operator[]:4:9 RefName=[19:9 - 19:10] RefName=[19:11 - 19:12] Extent=[19:9 - 19:12]
// CHECK: cursor-ref-names.cpp:19:9: DeclRefExpr=operator[]:4:9 Extent=[19:9 - 19:10]
// CHECK: cursor-ref-names.cpp:20:5: CallExpr=operator[]:4:9 Extent=[20:5 - 20:23]
// CHECK: cursor-ref-names.cpp:20:10: MemberRefExpr=operator[]:4:9 SingleRefName=[20:10 - 20:20] RefName=[20:10 - 20:18] RefName=[20:18 - 20:19] RefName=[20:19 - 20:20] Extent=[20:5 - 20:20]
// CHECK: cursor-ref-names.cpp:20:5: DeclRefExpr=inst:17:9 Extent=[20:5 - 20:9]

View File

@ -4675,6 +4675,9 @@ TEST(UsingDeclaration, ThroughUsingDeclaration) {
EXPECT_TRUE(notMatches(
"namespace a { void f(); } using a::f; void g() { a::f(); }",
declRefExpr(throughUsingDecl(anything()))));
EXPECT_TRUE(matches("struct S {}; namespace a { int operator+(S s1, S s2); } "
"using a::operator+; int g() { return S() + S(); }",
declRefExpr(throughUsingDecl(anything()))));
}
TEST(SingleDecl, IsSingleDecl) {