[analyzer] Fix resolving target kinds

As the analyzer is shipped with the SDK, it may have to analyze sources
using a newer version of package:meta than the one it was compiled
with. If that new version adds a new TargetKind, attempting to resolve
that constant with `TargetKind.values[index]` may cause a range error.

Further, if a new TargetKind is not added at the end of that enum, the
analyzer will misinterpret the constant values.

This CL fixes both issues by comparing target kinds by their name.
Unknown target kinds from a newer meta version are ignored since the
analyzer would not be capable of analyzing them either way.

Bug: 46183
Change-Id: Ibbb7063ae9939e95f846076d7fe462e222a8a5bb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/201760
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Simon Binder 2021-06-01 15:27:23 +00:00 committed by commit-bot@chromium.org
parent 10b83a4882
commit 8eba520115

View file

@ -41,6 +41,10 @@ import 'package:meta/meta_meta.dart';
class BestPracticesVerifier extends RecursiveAstVisitor<void> {
static const String _TO_INT_METHOD_NAME = "toInt";
static final Map<String, TargetKind> _targetKindsByName = {
for (final kind in TargetKind.values) kind.toString(): kind,
};
/// The class containing the AST nodes being visited, or `null` if we are not
/// in the scope of a class.
ClassElementImpl? _enclosingClass;
@ -1623,9 +1627,23 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
if (annotation.isTarget) {
var value = annotation.computeConstantValue()!;
var kinds = <TargetKind>{};
for (var kindObject in value.getField('kinds')!.toSetValue()!) {
// We can't directly translate the index from the analyzed TargetKind
// constant to TargetKinds.values because the analyzer from the SDK
// may have been compiled with a different version of pkg:meta.
var index = kindObject.getField('index')!.toIntValue()!;
kinds.add(TargetKind.values[index]);
var targetKindClass =
(kindObject.type as InterfaceType).element as EnumElementImpl;
// Instead, map constants to their TargetKind by comparing getter
// names.
var getter = targetKindClass.constants[index];
var name = 'TargetKind.${getter.name}';
var foundTargetKind = _targetKindsByName[name];
if (foundTargetKind != null) {
kinds.add(foundTargetKind);
}
}
return kinds;
}