Skip to content

Commit 04910d6

Browse files
bwilkersoncommit-bot@chromium.org
authored andcommitted
Include the deprecation message in diagnostics (issue 38667)
Change-Id: Ib1fa24fa4b112b9675d1f1900cbdda15319080a5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119780 Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
1 parent 3cdfd90 commit 04910d6

File tree

6 files changed

+94
-117
lines changed

6 files changed

+94
-117
lines changed

pkg/analyzer/lib/error/error.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ const List<ErrorCode> errorCodeValues = const [
325325
HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION,
326326
HintCode.DEPRECATED_MEMBER_USE,
327327
HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE,
328+
HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE,
329+
HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE,
328330
HintCode.DEPRECATED_MIXIN_FUNCTION,
329331
HintCode.DIVISION_OPTIMIZATION,
330332
HintCode.DUPLICATE_IMPORT,

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

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,34 @@ class HintCode extends AnalyzerErrorCode {
132132
"replacement.",
133133
hasPublishedDocs: true);
134134

135+
/**
136+
* Parameters:
137+
* 0: the name of the member
138+
* 1: message details
139+
*/
140+
static const HintCode DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE =
141+
const HintCodeWithUniqueName(
142+
'DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE',
143+
'HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE',
144+
"'{0}' is deprecated and shouldn't be used. {1}.",
145+
correction: "Try replacing the use of the deprecated member with the "
146+
"replacement.",
147+
hasPublishedDocs: true);
148+
149+
/**
150+
* Parameters:
151+
* 0: the name of the member
152+
* 1: message details
153+
*/
154+
static const HintCode DEPRECATED_MEMBER_USE_WITH_MESSAGE =
155+
const HintCodeWithUniqueName(
156+
'DEPRECATED_MEMBER_USE',
157+
'HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE',
158+
"'{0}' is deprecated and shouldn't be used. {1}.",
159+
correction: "Try replacing the use of the deprecated member with the "
160+
"replacement.",
161+
hasPublishedDocs: true);
162+
135163
/**
136164
* `Function` should not be mixed in anymore.
137165
*/
@@ -785,7 +813,7 @@ class HintCode extends AnalyzerErrorCode {
785813
// #### Common fixes
786814
//
787815
// If you don't need to support older versions of the SDK, then you can
788-
// ncrease the SDK constraint to allow the expression to be used:
816+
// increase the SDK constraint to allow the expression to be used:
789817
//
790818
// ```yaml
791819
// environment:
@@ -1584,3 +1612,13 @@ class HintCode extends AnalyzerErrorCode {
15841612
@override
15851613
ErrorType get type => ErrorType.HINT;
15861614
}
1615+
1616+
class HintCodeWithUniqueName extends HintCode {
1617+
@override
1618+
final String uniqueName;
1619+
1620+
const HintCodeWithUniqueName(String name, this.uniqueName, String message,
1621+
{String correction, bool hasPublishedDocs})
1622+
: super(name, message,
1623+
correction: correction, hasPublishedDocs: hasPublishedDocs);
1624+
}

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

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,9 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
585585
return false;
586586
}
587587

588-
/// Given some [Element], look at the associated metadata and report the use
589-
/// of the member if it is declared as deprecated.
590-
///
591-
/// @param element some element to check for deprecated use of
592-
/// @param node the node use for the location of the error
593-
/// See [HintCode.DEPRECATED_MEMBER_USE].
588+
/// Given some [element], look at the associated metadata and report the use
589+
/// of the member if it is declared as deprecated. If a diagnostic is reported
590+
/// it should be reported at the given [node].
594591
void _checkForDeprecatedMemberUse(Element element, AstNode node) {
595592
bool isDeprecated(Element element) {
596593
if (element is PropertyAccessorElement && element.isSynthetic) {
@@ -650,10 +647,19 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
650647
}
651648
LibraryElement library =
652649
element is LibraryElement ? element : element.library;
653-
HintCode hintCode = _isLibraryInWorkspacePackage(library)
654-
? HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE
655-
: HintCode.DEPRECATED_MEMBER_USE;
656-
_errorReporter.reportErrorForNode(hintCode, node, [displayName]);
650+
String message = _deprecatedMessage(element);
651+
if (message == null || message.isEmpty) {
652+
HintCode hintCode = _isLibraryInWorkspacePackage(library)
653+
? HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE
654+
: HintCode.DEPRECATED_MEMBER_USE;
655+
_errorReporter.reportErrorForNode(hintCode, node, [displayName]);
656+
} else {
657+
HintCode hintCode = _isLibraryInWorkspacePackage(library)
658+
? HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE
659+
: HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE;
660+
_errorReporter
661+
.reportErrorForNode(hintCode, node, [displayName, message]);
662+
}
657663
}
658664
}
659665

@@ -1234,6 +1240,22 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
12341240
return _workspacePackage.contains(library.source);
12351241
}
12361242

1243+
/// Return the message in the deprecated annotation on the given [element], or
1244+
/// `null` if the element doesn't have a deprecated annotation or if the
1245+
/// annotation does not have a message.
1246+
static String _deprecatedMessage(Element element) {
1247+
ElementAnnotationImpl annotation = element.metadata.firstWhere(
1248+
(e) => e.isDeprecated,
1249+
orElse: () => null,
1250+
);
1251+
if (annotation == null || annotation.element is PropertyAccessorElement) {
1252+
return null;
1253+
}
1254+
DartObject constantValue = annotation.computeConstantValue();
1255+
return constantValue?.getField('message')?.toStringValue() ??
1256+
constantValue?.getField('expires')?.toStringValue();
1257+
}
1258+
12371259
/// Check for the passed class declaration for the
12381260
/// [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
12391261
///

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ class A {
306306
m() {}
307307
n() {m();}
308308
}
309-
''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
309+
''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE]);
310310
}
311311

312312
test_operator() async {
@@ -614,7 +614,8 @@ class A {
614614
await assertErrorsInCode(r'''
615615
import 'package:foo/foo.dart';
616616
void main() => A().m();
617-
''', [HintCode.DEPRECATED_MEMBER_USE], sourceName: '/pkg1/lib/lib1.dart');
617+
''', [HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE],
618+
sourceName: '/pkg1/lib/lib1.dart');
618619
}
619620

620621
test_packageBuildWorkspace() async {

pkg/analyzer/test/src/task/options_test.dart

Lines changed: 17 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import 'package:analyzer/source/error_processor.dart';
1111
import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
1212
import 'package:analyzer/src/analysis_options/error/option_codes.dart';
1313
import 'package:analyzer/src/dart/error/hint_codes.dart';
14-
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
1514
import 'package:analyzer/src/error/codes.dart';
1615
import 'package:analyzer/src/file_system/file_system.dart';
1716
import 'package:analyzer/src/generated/engine.dart';
@@ -149,14 +148,21 @@ analyzer:
149148
@reflectiveTest
150149
class ErrorCodeValuesTest {
151150
test_errorCodes() {
151+
// Now that we're using unique names for comparison, the only reason to
152+
// split the codes by class is to find all of the classes that need to be
153+
// checked against `errorCodeValues`.
152154
var errorTypeMap = <Type, List<ErrorCode>>{};
153155
for (ErrorCode code in errorCodeValues) {
154-
errorTypeMap.putIfAbsent(code.runtimeType, () => <ErrorCode>[]).add(code);
156+
Type type = code.runtimeType;
157+
if (type == HintCodeWithUniqueName) {
158+
type = HintCode;
159+
}
160+
errorTypeMap.putIfAbsent(type, () => <ErrorCode>[]).add(code);
155161
}
156162

157-
int missingErrorCodeCount = 0;
163+
StringBuffer missingCodes = StringBuffer();
158164
errorTypeMap.forEach((Type errorType, List<ErrorCode> codes) {
159-
var listedNames = codes.map((ErrorCode code) => code.name).toSet();
165+
var listedNames = codes.map((ErrorCode code) => code.uniqueName).toSet();
160166

161167
var declaredNames = reflectClass(errorType)
162168
.declarations
@@ -165,115 +171,23 @@ class ErrorCodeValuesTest {
165171
String name = declarationMirror.simpleName.toString();
166172
//TODO(danrubel): find a better way to extract the text from the symbol
167173
assert(name.startsWith('Symbol("') && name.endsWith('")'));
168-
return name.substring(8, name.length - 2);
174+
return errorType.toString() + '.' + name.substring(8, name.length - 2);
169175
}).where((String name) {
170176
return name == name.toUpperCase();
171177
}).toList();
172178

173-
// Remove declared names that are not supposed to be in errorCodeValues
174-
175-
if (errorType == AnalysisOptionsErrorCode) {
176-
declaredNames
177-
.remove(AnalysisOptionsErrorCode.INCLUDED_FILE_PARSE_ERROR.name);
178-
} else if (errorType == AnalysisOptionsWarningCode) {
179-
declaredNames
180-
.remove(AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND.name);
181-
declaredNames
182-
.remove(AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING.name);
183-
declaredNames
184-
.remove(AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT.name);
185-
} else if (errorType == StaticWarningCode) {
186-
declaredNames.remove(
187-
StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS.name +
188-
'_PLUS');
189-
declaredNames.remove('EXTRA_POSITIONAL_ARGUMENTS');
190-
declaredNames.remove('EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED');
191-
declaredNames.remove('IMPORT_OF_NON_LIBRARY');
192-
declaredNames.remove('NOT_ENOUGH_REQUIRED_ARGUMENTS');
193-
declaredNames.remove('REDIRECT_TO_MISSING_CONSTRUCTOR');
194-
declaredNames.remove('REDIRECT_TO_NON_CLASS');
195-
declaredNames.remove('UNDEFINED_CLASS');
196-
declaredNames.remove('UNDEFINED_NAMED_PARAMETER');
197-
} else if (errorType == StrongModeCode) {
198-
void removeCode(StrongModeCode code) {
199-
declaredNames.remove(code.name);
200-
}
201-
202-
removeCode(StrongModeCode.DOWN_CAST_COMPOSITE);
203-
removeCode(StrongModeCode.DOWN_CAST_IMPLICIT);
204-
removeCode(StrongModeCode.DOWN_CAST_IMPLICIT_ASSIGN);
205-
removeCode(StrongModeCode.DYNAMIC_CAST);
206-
removeCode(StrongModeCode.ASSIGNMENT_CAST);
207-
removeCode(StrongModeCode.INVALID_PARAMETER_DECLARATION);
208-
removeCode(StrongModeCode.COULD_NOT_INFER);
209-
removeCode(StrongModeCode.INFERRED_TYPE);
210-
removeCode(StrongModeCode.INFERRED_TYPE_LITERAL);
211-
removeCode(StrongModeCode.INFERRED_TYPE_ALLOCATION);
212-
removeCode(StrongModeCode.INFERRED_TYPE_CLOSURE);
213-
removeCode(StrongModeCode.INVALID_CAST_LITERAL);
214-
removeCode(StrongModeCode.INVALID_CAST_LITERAL_LIST);
215-
removeCode(StrongModeCode.INVALID_CAST_LITERAL_MAP);
216-
removeCode(StrongModeCode.INVALID_CAST_LITERAL_SET);
217-
removeCode(StrongModeCode.INVALID_CAST_FUNCTION_EXPR);
218-
removeCode(StrongModeCode.INVALID_CAST_NEW_EXPR);
219-
removeCode(StrongModeCode.INVALID_CAST_METHOD);
220-
removeCode(StrongModeCode.INVALID_CAST_FUNCTION);
221-
removeCode(StrongModeCode.INVALID_SUPER_INVOCATION);
222-
removeCode(StrongModeCode.NON_GROUND_TYPE_CHECK_INFO);
223-
removeCode(StrongModeCode.DYNAMIC_INVOKE);
224-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_PARAMETER);
225-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_RETURN);
226-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_VARIABLE);
227-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_FIELD);
228-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_TYPE);
229-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_LIST_LITERAL);
230-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_MAP_LITERAL);
231-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_FUNCTION);
232-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_METHOD);
233-
removeCode(StrongModeCode.IMPLICIT_DYNAMIC_INVOKE);
234-
removeCode(StrongModeCode.NOT_INSTANTIATED_BOUND);
235-
removeCode(StrongModeCode.TOP_LEVEL_CYCLE);
236-
removeCode(StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_BLOCK);
237-
removeCode(StrongModeCode.TOP_LEVEL_IDENTIFIER_NO_TYPE);
238-
removeCode(StrongModeCode.TOP_LEVEL_INSTANCE_GETTER);
239-
removeCode(StrongModeCode.TOP_LEVEL_INSTANCE_METHOD);
240-
} else if (errorType == TodoCode) {
241-
declaredNames.remove('TODO_REGEX');
242-
} else if (errorType == CompileTimeErrorCode) {
243-
declaredNames.remove('ANNOTATION_WITH_TYPE_ARGUMENTS');
244-
declaredNames.remove('NOT_ENOUGH_REQUIRED_ARGUMENTS');
245-
} else if (errorType == ParserErrorCode) {
246-
declaredNames.remove('CONST_AFTER_FACTORY');
247-
declaredNames.remove('CONST_AND_COVARIANT');
248-
declaredNames.remove('CONST_AND_VAR');
249-
declaredNames.remove('COVARIANT_AFTER_FINAL');
250-
declaredNames.remove('COVARIANT_AFTER_VAR');
251-
declaredNames.remove('EXTERNAL_AFTER_CONST');
252-
declaredNames.remove('EXTERNAL_AFTER_FACTORY');
253-
declaredNames.remove('EXTERNAL_AFTER_STATIC');
254-
declaredNames.remove('MISSING_CLASS_BODY');
255-
declaredNames.remove('STATIC_AFTER_CONST');
256-
declaredNames.remove('STATIC_AFTER_FINAL');
257-
declaredNames.remove('STATIC_AFTER_VAR');
258-
}
259-
260-
// Assert that all remaining declared names are in errorCodeValues
179+
// Assert that all declared names are in errorCodeValues
261180

262181
for (String declaredName in declaredNames) {
263182
if (!listedNames.contains(declaredName)) {
264-
++missingErrorCodeCount;
265-
print(' errorCodeValues is missing $errorType $declaredName');
183+
missingCodes.writeln();
184+
missingCodes.write(' $declaredName');
266185
}
267186
}
268187
});
269-
expect(missingErrorCodeCount, 0, reason: 'missing error code names');
270-
271-
// Apparently, duplicate error codes are allowed
272-
// expect(
273-
// ErrorFilterOptionValidator.errorCodes.length,
274-
// errorCodeValues.length,
275-
// reason: 'some errorCodeValues have the same name',
276-
// );
188+
if (missingCodes.isNotEmpty) {
189+
fail('Missing error codes:$missingCodes');
190+
}
277191
}
278192
}
279193

pkg/analyzer/tool/diagnostics/diagnostics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1937,7 +1937,7 @@ const int i = [!n as int!];
19371937
#### Common fixes
19381938

19391939
If you don't need to support older versions of the SDK, then you can
1940-
ncrease the SDK constraint to allow the expression to be used:
1940+
increase the SDK constraint to allow the expression to be used:
19411941

19421942
```yaml
19431943
environment:

0 commit comments

Comments
 (0)