Skip to content

Commit f00dc3d

Browse files
pqcommit-bot@chromium.org
authored andcommitted
@useResult verification
See: https://github.com/dart-lang/linter/issues/1888 Change-Id: I3d5ed31f3a1dd0d69da5f47ae38496a4fe6051c0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/201160 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Phil Quitslund <[email protected]>
1 parent fd8607c commit f00dc3d

File tree

4 files changed

+767
-1
lines changed

4 files changed

+767
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analyzer/dart/ast/ast.dart';
6+
import 'package:analyzer/dart/element/element.dart';
7+
import 'package:analyzer/error/listener.dart';
8+
import 'package:analyzer/src/dart/error/hint_codes.dart';
9+
import 'package:collection/collection.dart';
10+
11+
class UseResultVerifier {
12+
final ErrorReporter _errorReporter;
13+
14+
UseResultVerifier(this._errorReporter);
15+
16+
void checkMethodInvocation(MethodInvocation node) {
17+
var element = node.methodName.staticElement;
18+
if (element == null) {
19+
return;
20+
}
21+
22+
_check(node, element);
23+
}
24+
25+
void checkPropertyAccess(PropertyAccess node) {
26+
var element = node.propertyName.staticElement;
27+
if (element == null) {
28+
return null;
29+
}
30+
31+
_check(node, element);
32+
}
33+
34+
void checkSimpleIdentifier(SimpleIdentifier node) {
35+
if (node.inDeclarationContext()) {
36+
return;
37+
}
38+
39+
var parent = node.parent;
40+
// Covered by checkPropertyAccess and checkMethodInvocation respectively.
41+
if (parent is PropertyAccess || parent is MethodInvocation) {
42+
return;
43+
}
44+
45+
var element = node.staticElement;
46+
if (element == null) {
47+
return null;
48+
}
49+
50+
_check(node, element);
51+
}
52+
53+
void _check(AstNode node, Element element) {
54+
var annotation = _getUseResultMetadata(element);
55+
if (annotation == null) {
56+
return;
57+
}
58+
59+
if (_isUsed(node)) {
60+
return;
61+
}
62+
63+
var displayName = element.displayName;
64+
65+
var message = _getUseResultMessage(annotation);
66+
if (message == null || message.isEmpty) {
67+
_errorReporter
68+
.reportErrorForNode(HintCode.UNUSED_RESULT, node, [displayName]);
69+
} else {
70+
_errorReporter.reportErrorForNode(
71+
HintCode.UNUSED_RESULT_WITH_MESSAGE, node, [displayName, message]);
72+
}
73+
}
74+
75+
static String? _getUseResultMessage(ElementAnnotation annotation) {
76+
if (annotation.element is PropertyAccessorElement) {
77+
return null;
78+
}
79+
var constantValue = annotation.computeConstantValue();
80+
return constantValue?.getField('message')?.toStringValue();
81+
}
82+
83+
static ElementAnnotation? _getUseResultMetadata(Element element) {
84+
// Implicit getters/setters.
85+
if (element.isSynthetic && element is PropertyAccessorElement) {
86+
element = element.variable;
87+
}
88+
return element.metadata.firstWhereOrNull((e) => e.isUseResult);
89+
}
90+
91+
static bool _isUsed(AstNode node) {
92+
var parent = node.parent;
93+
if (parent == null) {
94+
return false;
95+
}
96+
97+
if (parent is ParenthesizedExpression || parent is ConditionalExpression) {
98+
return _isUsed(parent);
99+
}
100+
101+
return parent is ArgumentList ||
102+
parent is VariableDeclaration ||
103+
parent is MethodInvocation ||
104+
parent is PropertyAccess ||
105+
parent is ExpressionFunctionBody ||
106+
parent is ReturnStatement ||
107+
parent is FunctionExpressionInvocation ||
108+
parent is ListLiteral ||
109+
parent is SetOrMapLiteral ||
110+
parent is MapLiteralEntry;
111+
}
112+
}

pkg/analyzer/lib/src/generated/error_verifier.dart

+6-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import 'package:analyzer/src/error/literal_element_verifier.dart';
3838
import 'package:analyzer/src/error/required_parameters_verifier.dart';
3939
import 'package:analyzer/src/error/return_type_verifier.dart';
4040
import 'package:analyzer/src/error/type_arguments_verifier.dart';
41+
import 'package:analyzer/src/error/use_result_verifier.dart';
4142
import 'package:analyzer/src/generated/element_resolver.dart';
4243
import 'package:analyzer/src/generated/engine.dart';
4344
import 'package:analyzer/src/generated/error_detection_helpers.dart';
@@ -249,6 +250,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
249250

250251
final RequiredParametersVerifier _requiredParametersVerifier;
251252
final DuplicateDefinitionVerifier _duplicateDefinitionVerifier;
253+
final UseResultVerifier _checkUseVerifier;
252254
late final TypeArgumentsVerifier _typeArgumentsVerifier;
253255
late final ConstructorFieldsVerifier _constructorFieldsVerifier;
254256
late final ReturnTypeVerifier _returnTypeVerifier;
@@ -258,6 +260,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
258260
this._inheritanceManager)
259261
: _uninstantiatedBoundChecker =
260262
_UninstantiatedBoundChecker(errorReporter),
263+
_checkUseVerifier = UseResultVerifier(errorReporter),
261264
_requiredParametersVerifier = RequiredParametersVerifier(errorReporter),
262265
_duplicateDefinitionVerifier =
263266
DuplicateDefinitionVerifier(_currentLibrary, errorReporter) {
@@ -930,6 +933,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
930933
}
931934
_typeArgumentsVerifier.checkMethodInvocation(node);
932935
_requiredParametersVerifier.visitMethodInvocation(node);
936+
_checkUseVerifier.checkMethodInvocation(node);
933937
super.visitMethodInvocation(node);
934938
}
935939

@@ -1029,7 +1033,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
10291033
_checkForInstanceAccessToStaticMember(
10301034
typeReference, node.target, propertyName);
10311035
_checkForUnnecessaryNullAware(target, node.operator);
1032-
1036+
_checkUseVerifier.checkPropertyAccess(node);
10331037
super.visitPropertyAccess(node);
10341038
}
10351039

@@ -1100,6 +1104,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
11001104
if (!_isUnqualifiedReferenceToNonLocalStaticMemberAllowed(node)) {
11011105
_checkForUnqualifiedReferenceToNonLocalStaticMember(node);
11021106
}
1107+
_checkUseVerifier.checkSimpleIdentifier(node);
11031108
super.visitSimpleIdentifier(node);
11041109
}
11051110

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

+2
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ import 'uri_with_interpolation_test.dart' as uri_with_interpolation;
685685
import 'use_of_native_extension_test.dart' as use_of_native_extension;
686686
import 'use_of_nullable_value_test.dart' as use_of_nullable_value_test;
687687
import 'use_of_void_result_test.dart' as use_of_void_result;
688+
import 'use_result_test.dart' as use_result;
688689
import 'variable_type_mismatch_test.dart' as variable_type_mismatch;
689690
import 'void_with_type_arguments_test.dart' as void_with_type_arguments_test;
690691
import 'wrong_number_of_parameters_for_operator_test.dart'
@@ -1165,6 +1166,7 @@ main() {
11651166
use_of_native_extension.main();
11661167
use_of_nullable_value_test.main();
11671168
use_of_void_result.main();
1169+
use_result.main();
11681170
variable_type_mismatch.main();
11691171
void_with_type_arguments_test.main();
11701172
wrong_number_of_parameters_for_operator.main();

0 commit comments

Comments
 (0)