Skip to content

Commit 0939101

Browse files
srawlinscommit-bot@chromium.org
authored andcommitted
When reporting unused elements, do not count a CommentReference as usage
Fixes #37116 Change-Id: I9ac563036a367a5e5da4fbba8ab521f174062570 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/127223 Commit-Queue: Samuel Rawlins <srawlins@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
1 parent 7075032 commit 0939101

File tree

3 files changed

+85
-19
lines changed

3 files changed

+85
-19
lines changed

pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor {
8888
if (node.inDeclarationContext()) {
8989
return;
9090
}
91+
if (_inCommentReference(node)) {
92+
return;
93+
}
9194
Element element = node.staticElement;
9295
// Store un-parameterized members.
9396
if (element is ExecutableMember) {
@@ -131,18 +134,18 @@ class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor {
131134
if (element == null) {
132135
return;
133136
}
134-
// check if a local element
137+
// Check if [element] is a local element.
135138
if (!identical(element.library, _enclosingLibrary)) {
136139
return;
137140
}
138-
// ignore references to an element from itself
141+
// Ignore references to an element from itself.
139142
if (identical(element, _enclosingClass)) {
140143
return;
141144
}
142145
if (identical(element, _enclosingExec)) {
143146
return;
144147
}
145-
// ignore places where the element is not actually used
148+
// Ignore places where the element is not actually used.
146149
if (node.parent is TypeName) {
147150
if (element is ClassElement) {
148151
AstNode parent2 = node.parent.parent;
@@ -161,13 +164,24 @@ class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor {
161164
usedElements.addElement(element);
162165
}
163166

167+
/// Returns whether [identifier] is found in a [CommentReference].
168+
static bool _inCommentReference(SimpleIdentifier identifier) {
169+
var parent = identifier.parent;
170+
return parent is CommentReference || parent?.parent is CommentReference;
171+
}
172+
173+
/// Returns whether the value of [node] is _only_ being read at this position.
174+
///
175+
/// Returns `false` if [node] is not a read access, or if [node] is a combined
176+
/// read/write access.
164177
static bool _isReadIdentifier(SimpleIdentifier node) {
165-
// not reading at all
178+
// Not reading at all.
166179
if (!node.inGetterContext()) {
167180
return false;
168181
}
169-
// check if useless reading
182+
// Check if useless reading.
170183
AstNode parent = node.parent;
184+
171185
if (parent.parent is ExpressionStatement) {
172186
if (parent is PrefixExpression || parent is PostfixExpression) {
173187
// v++;

pkg/analyzer/test/src/diagnostics/unused_element_test.dart

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,15 @@ main() {
264264
]);
265265
}
266266

267+
test_functionTop_notUsed_referenceInComment() async {
268+
await assertErrorsInCode(r'''
269+
/// [_f] is a great function.
270+
_f(int p) => 7;
271+
''', [
272+
error(HintCode.UNUSED_ELEMENT, 30, 2),
273+
]);
274+
}
275+
267276
test_functionTypeAlias_isUsed_isExpression() async {
268277
await assertNoErrorsInCode(r'''
269278
typedef _F(a, b);
@@ -461,20 +470,6 @@ class A {
461470
]);
462471
}
463472

464-
test_method_isNotUsed_hasSameNameAsUsed() async {
465-
await assertErrorsInCode(r'''
466-
class A {
467-
void _m1() {}
468-
}
469-
class B {
470-
void public() => _m1();
471-
void _m1() {}
472-
}
473-
''', [
474-
error(HintCode.UNUSED_ELEMENT, 17, 3),
475-
]);
476-
}
477-
478473
test_method_isUsed_hasReference_implicitThis() async {
479474
await assertNoErrorsInCode(r'''
480475
class A {
@@ -645,6 +640,20 @@ main() {
645640
''');
646641
}
647642

643+
test_method_notUsed_hasSameNameAsUsed() async {
644+
await assertErrorsInCode(r'''
645+
class A {
646+
void _m1() {}
647+
}
648+
class B {
649+
void public() => _m1();
650+
void _m1() {}
651+
}
652+
''', [
653+
error(HintCode.UNUSED_ELEMENT, 17, 3),
654+
]);
655+
}
656+
648657
test_method_notUsed_noReference() async {
649658
await assertErrorsInCode(r'''
650659
class A {
@@ -667,6 +676,29 @@ class A {
667676
]);
668677
}
669678

679+
test_method_notUsed_referenceInComment() async {
680+
await assertErrorsInCode(r'''
681+
/// [A] has a method, [_f].
682+
class A {
683+
int _f(int p) => 7;
684+
}
685+
''', [
686+
error(HintCode.UNUSED_ELEMENT, 44, 2),
687+
]);
688+
}
689+
690+
test_method_notUsed_referenceInComment_outsideEnclosingClass() async {
691+
await assertErrorsInCode(r'''
692+
class A {
693+
int _f(int p) => 7;
694+
}
695+
/// This is similar to [A._f].
696+
int g() => 7;
697+
''', [
698+
error(HintCode.UNUSED_ELEMENT, 16, 2),
699+
]);
700+
}
701+
670702
test_setter_isUsed_invocation_implicitThis() async {
671703
await assertNoErrorsInCode(r'''
672704
class A {
@@ -753,4 +785,13 @@ main() {
753785
error(HintCode.UNUSED_ELEMENT, 4, 2),
754786
]);
755787
}
788+
789+
test_topLevelVariable_notUsed_referenceInComment() async {
790+
await assertErrorsInCode(r'''
791+
/// [_a] is a great variable.
792+
int _a = 7;
793+
''', [
794+
error(HintCode.UNUSED_ELEMENT, 34, 2),
795+
]);
796+
}
756797
}

pkg/analyzer/test/src/diagnostics/unused_field_test.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,17 @@ class A {
278278
]);
279279
}
280280

281+
test_notUsed_referenceInComment() async {
282+
await assertErrorsInCode(r'''
283+
/// [A._f] is great.
284+
class A {
285+
int _f;
286+
}
287+
''', [
288+
error(HintCode.UNUSED_FIELD, 37, 2),
289+
]);
290+
}
291+
281292
test_notUsed_simpleAssignment() async {
282293
await assertErrorsInCode(r'''
283294
class A {

0 commit comments

Comments
 (0)