OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library engine.resolver; | 5 library engine.resolver; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 | 8 |
9 import 'package:analyzer/src/generated/scanner.dart'; | |
10 | |
11 import 'ast.dart'; | 9 import 'ast.dart'; |
12 import 'constant.dart'; | 10 import 'constant.dart'; |
13 import 'element.dart'; | 11 import 'element.dart'; |
14 import 'element_resolver.dart'; | 12 import 'element_resolver.dart'; |
15 import 'engine.dart'; | 13 import 'engine.dart'; |
16 import 'error.dart'; | 14 import 'error.dart'; |
17 import 'error_verifier.dart'; | 15 import 'error_verifier.dart'; |
18 import 'html.dart' as ht; | 16 import 'html.dart' as ht; |
19 import 'java_core.dart'; | 17 import 'java_core.dart'; |
20 import 'java_engine.dart'; | 18 import 'java_engine.dart'; |
| 19 import 'scanner.dart'; |
21 import 'scanner.dart' as sc; | 20 import 'scanner.dart' as sc; |
22 import 'sdk.dart' show DartSdk, SdkLibrary; | 21 import 'sdk.dart' show DartSdk, SdkLibrary; |
23 import 'source.dart'; | 22 import 'source.dart'; |
24 import 'static_type_analyzer.dart'; | 23 import 'static_type_analyzer.dart'; |
| 24 import 'type_system.dart'; |
25 import 'utilities_dart.dart'; | 25 import 'utilities_dart.dart'; |
26 | 26 |
| 27 export 'type_system.dart'; |
| 28 |
27 /** | 29 /** |
28 * Callback signature used by ImplicitConstructorBuilder to register | 30 * Callback signature used by ImplicitConstructorBuilder to register |
29 * computations to be performed, and their dependencies. A call to this | 31 * computations to be performed, and their dependencies. A call to this |
30 * callback indicates that [computation] may be used to compute implicit | 32 * callback indicates that [computation] may be used to compute implicit |
31 * constructors for [classElement], but that the computation may not be invoked | 33 * constructors for [classElement], but that the computation may not be invoked |
32 * until after implicit constructors have been built for [superclassElement]. | 34 * until after implicit constructors have been built for [superclassElement]. |
33 */ | 35 */ |
34 typedef void ImplicitConstructorBuilderCallback(ClassElement classElement, | 36 typedef void ImplicitConstructorBuilderCallback(ClassElement classElement, |
35 ClassElement superclassElement, void computation()); | 37 ClassElement superclassElement, void computation()); |
36 | 38 |
37 typedef LibraryResolver LibraryResolverFactory(AnalysisContext context); | 39 typedef LibraryResolver LibraryResolverFactory(AnalysisContext context); |
38 | 40 |
39 typedef ResolverVisitor ResolverVisitorFactory( | 41 typedef ResolverVisitor ResolverVisitorFactory( |
40 Library library, Source source, TypeProvider typeProvider); | 42 Library library, Source source, TypeProvider typeProvider); |
41 | 43 |
42 typedef StaticTypeAnalyzer StaticTypeAnalyzerFactory(ResolverVisitor visitor); | 44 typedef StaticTypeAnalyzer StaticTypeAnalyzerFactory(ResolverVisitor visitor); |
43 | 45 |
44 typedef TypeResolverVisitor TypeResolverVisitorFactory( | 46 typedef TypeResolverVisitor TypeResolverVisitorFactory( |
45 Library library, Source source, TypeProvider typeProvider); | 47 Library library, Source source, TypeProvider typeProvider); |
46 | 48 |
47 typedef void VoidFunction(); | 49 typedef void VoidFunction(); |
48 | 50 |
49 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); | |
50 | |
51 typedef bool _SubtypeChecker<T>(T t1, T t2); | |
52 | |
53 /** | 51 /** |
54 * Instances of the class `BestPracticesVerifier` traverse an AST structure look
ing for | 52 * Instances of the class `BestPracticesVerifier` traverse an AST structure look
ing for |
55 * violations of Dart best practices. | 53 * violations of Dart best practices. |
56 */ | 54 */ |
57 class BestPracticesVerifier extends RecursiveAstVisitor<Object> { | 55 class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
58 // static String _HASHCODE_GETTER_NAME = "hashCode"; | 56 // static String _HASHCODE_GETTER_NAME = "hashCode"; |
59 | 57 |
60 static String _NULL_TYPE_NAME = "Null"; | 58 static String _NULL_TYPE_NAME = "Null"; |
61 | 59 |
62 static String _TO_INT_METHOD_NAME = "toInt"; | 60 static String _TO_INT_METHOD_NAME = "toInt"; |
(...skipping 12736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12799 } | 12797 } |
12800 } else if (statement is FunctionDeclarationStatement) { | 12798 } else if (statement is FunctionDeclarationStatement) { |
12801 FunctionDeclarationStatement fds = statement; | 12799 FunctionDeclarationStatement fds = statement; |
12802 scope.hide(fds.functionDeclaration.element); | 12800 scope.hide(fds.functionDeclaration.element); |
12803 } | 12801 } |
12804 } | 12802 } |
12805 } | 12803 } |
12806 } | 12804 } |
12807 | 12805 |
12808 /** | 12806 /** |
12809 * Implementation of [TypeSystem] using the strong mode rules. | |
12810 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md | |
12811 */ | |
12812 class StrongTypeSystemImpl implements TypeSystem { | |
12813 final _specTypeSystem = new TypeSystemImpl(); | |
12814 | |
12815 StrongTypeSystemImpl(); | |
12816 | |
12817 @override | |
12818 DartType getLeastUpperBound( | |
12819 TypeProvider typeProvider, DartType type1, DartType type2) { | |
12820 // TODO(leafp): Implement a strong mode version of this. | |
12821 return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2); | |
12822 } | |
12823 | |
12824 // TODO(leafp): Document the rules in play here | |
12825 @override | |
12826 bool isAssignableTo(DartType fromType, DartType toType) { | |
12827 // An actual subtype | |
12828 if (isSubtypeOf(fromType, toType)) { | |
12829 return true; | |
12830 } | |
12831 | |
12832 // Don't allow implicit downcasts between function types | |
12833 // and call method objects, as these will almost always fail. | |
12834 if ((fromType is FunctionType && _getCallMethodType(toType) != null) || | |
12835 (toType is FunctionType && _getCallMethodType(fromType) != null)) { | |
12836 return false; | |
12837 } | |
12838 | |
12839 // If the subtype relation goes the other way, allow the implicit downcast. | |
12840 // TODO(leafp): Emit warnings and hints for these in some way. | |
12841 // TODO(leafp): Consider adding a flag to disable these? Or just rely on | |
12842 // --warnings-as-errors? | |
12843 if (isSubtypeOf(toType, fromType) || | |
12844 _specTypeSystem.isAssignableTo(toType, fromType)) { | |
12845 // TODO(leafp): error if type is known to be exact (literal, | |
12846 // instance creation). | |
12847 // TODO(leafp): Warn on composite downcast. | |
12848 // TODO(leafp): hint on object/dynamic downcast. | |
12849 // TODO(leafp): Consider allowing assignment casts. | |
12850 return true; | |
12851 } | |
12852 | |
12853 return false; | |
12854 } | |
12855 | |
12856 @override | |
12857 bool isSubtypeOf(DartType leftType, DartType rightType) { | |
12858 return _isSubtypeOf(leftType, rightType, null); | |
12859 } | |
12860 | |
12861 FunctionType _getCallMethodType(DartType t) { | |
12862 if (t is InterfaceType) { | |
12863 return t.lookUpInheritedMethod("call")?.type; | |
12864 } | |
12865 return null; | |
12866 } | |
12867 | |
12868 // Given a type t, if t is an interface type with a call method | |
12869 // defined, return the function type for the call method, otherwise | |
12870 // return null. | |
12871 _GuardedSubtypeChecker<DartType> _guard( | |
12872 _GuardedSubtypeChecker<DartType> check) { | |
12873 return (DartType t1, DartType t2, Set<Element> visited) { | |
12874 Element element = t1.element; | |
12875 if (visited == null) { | |
12876 visited = new HashSet<Element>(); | |
12877 } | |
12878 if (element == null || !visited.add(element)) { | |
12879 return false; | |
12880 } | |
12881 try { | |
12882 return check(t1, t2, visited); | |
12883 } finally { | |
12884 visited.remove(element); | |
12885 } | |
12886 }; | |
12887 } | |
12888 | |
12889 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { | |
12890 return (t.isDynamic && dynamicIsBottom) || t.isBottom; | |
12891 } | |
12892 | |
12893 // Guard against loops in the class hierarchy | |
12894 /** | |
12895 * Check that [f1] is a subtype of [f2]. | |
12896 * [fuzzyArrows] indicates whether or not the f1 and f2 should be | |
12897 * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated | |
12898 * as bottom). | |
12899 */ | |
12900 bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2, | |
12901 {bool fuzzyArrows: true}) { | |
12902 final r1s = f1.normalParameterTypes; | |
12903 final o1s = f1.optionalParameterTypes; | |
12904 final n1s = f1.namedParameterTypes; | |
12905 final r2s = f2.normalParameterTypes; | |
12906 final o2s = f2.optionalParameterTypes; | |
12907 final n2s = f2.namedParameterTypes; | |
12908 final ret1 = f1.returnType; | |
12909 final ret2 = f2.returnType; | |
12910 | |
12911 // A -> B <: C -> D if C <: A and | |
12912 // either D is void or B <: D | |
12913 if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) { | |
12914 return false; | |
12915 } | |
12916 | |
12917 // Reject if one has named and the other has optional | |
12918 if (n1s.length > 0 && o2s.length > 0) { | |
12919 return false; | |
12920 } | |
12921 if (n2s.length > 0 && o1s.length > 0) { | |
12922 return false; | |
12923 } | |
12924 | |
12925 // Rebind _isSubtypeOf for convenience | |
12926 _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) => | |
12927 _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows); | |
12928 | |
12929 // f2 has named parameters | |
12930 if (n2s.length > 0) { | |
12931 // Check that every named parameter in f2 has a match in f1 | |
12932 for (String k2 in n2s.keys) { | |
12933 if (!n1s.containsKey(k2)) { | |
12934 return false; | |
12935 } | |
12936 if (!parameterSubtype(n2s[k2], n1s[k2])) { | |
12937 return false; | |
12938 } | |
12939 } | |
12940 } | |
12941 // If we get here, we either have no named parameters, | |
12942 // or else the named parameters match and we have no optional | |
12943 // parameters | |
12944 | |
12945 // If f1 has more required parameters, reject | |
12946 if (r1s.length > r2s.length) { | |
12947 return false; | |
12948 } | |
12949 | |
12950 // If f2 has more required + optional parameters, reject | |
12951 if (r2s.length + o2s.length > r1s.length + o1s.length) { | |
12952 return false; | |
12953 } | |
12954 | |
12955 // The parameter lists must look like the following at this point | |
12956 // where rrr is a region of required, and ooo is a region of optionals. | |
12957 // f1: rrr ooo ooo ooo | |
12958 // f2: rrr rrr ooo | |
12959 int rr = r1s.length; // required in both | |
12960 int or = r2s.length - r1s.length; // optional in f1, required in f2 | |
12961 int oo = o2s.length; // optional in both | |
12962 | |
12963 for (int i = 0; i < rr; ++i) { | |
12964 if (!parameterSubtype(r2s[i], r1s[i])) { | |
12965 return false; | |
12966 } | |
12967 } | |
12968 for (int i = 0, j = rr; i < or; ++i, ++j) { | |
12969 if (!parameterSubtype(r2s[j], o1s[i])) { | |
12970 return false; | |
12971 } | |
12972 } | |
12973 for (int i = or, j = 0; i < oo; ++i, ++j) { | |
12974 if (!parameterSubtype(o2s[j], o1s[i])) { | |
12975 return false; | |
12976 } | |
12977 } | |
12978 return true; | |
12979 } | |
12980 | |
12981 bool _isInterfaceSubtypeOf( | |
12982 InterfaceType i1, InterfaceType i2, Set<Element> visited) { | |
12983 // Guard recursive calls | |
12984 _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype = | |
12985 _guard(_isInterfaceSubtypeOf); | |
12986 | |
12987 if (i1 == i2) { | |
12988 return true; | |
12989 } | |
12990 | |
12991 if (i1.element == i2.element) { | |
12992 List<DartType> tArgs1 = i1.typeArguments; | |
12993 List<DartType> tArgs2 = i2.typeArguments; | |
12994 | |
12995 assert(tArgs1.length == tArgs2.length); | |
12996 | |
12997 for (int i = 0; i < tArgs1.length; i++) { | |
12998 DartType t1 = tArgs1[i]; | |
12999 DartType t2 = tArgs2[i]; | |
13000 if (!isSubtypeOf(t1, t2)) { | |
13001 return false; | |
13002 } | |
13003 } | |
13004 return true; | |
13005 } | |
13006 | |
13007 if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) { | |
13008 return true; | |
13009 } | |
13010 | |
13011 if (i1.isObject) { | |
13012 return false; | |
13013 } | |
13014 | |
13015 if (guardedInterfaceSubtype(i1.superclass, i2, visited)) { | |
13016 return true; | |
13017 } | |
13018 | |
13019 for (final parent in i1.interfaces) { | |
13020 if (guardedInterfaceSubtype(parent, i2, visited)) { | |
13021 return true; | |
13022 } | |
13023 } | |
13024 | |
13025 for (final parent in i1.mixins) { | |
13026 if (guardedInterfaceSubtype(parent, i2, visited)) { | |
13027 return true; | |
13028 } | |
13029 } | |
13030 | |
13031 return false; | |
13032 } | |
13033 | |
13034 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, | |
13035 {bool dynamicIsBottom: false}) { | |
13036 // Guard recursive calls | |
13037 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); | |
13038 | |
13039 if (t1 == t2) { | |
13040 return true; | |
13041 } | |
13042 | |
13043 // The types are void, dynamic, bottom, interface types, function types | |
13044 // and type parameters. We proceed by eliminating these different classes | |
13045 // from consideration. | |
13046 | |
13047 // Trivially true. | |
13048 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || | |
13049 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { | |
13050 return true; | |
13051 } | |
13052 | |
13053 // Trivially false. | |
13054 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || | |
13055 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { | |
13056 return false; | |
13057 } | |
13058 | |
13059 // S <: T where S is a type variable | |
13060 // T is not dynamic or object (handled above) | |
13061 // S != T (handled above) | |
13062 // So only true if bound of S is S' and | |
13063 // S' <: T | |
13064 if (t1 is TypeParameterType) { | |
13065 DartType bound = t1.element.bound; | |
13066 if (bound == null) return false; | |
13067 return guardedSubtype(bound, t2, visited); | |
13068 } | |
13069 | |
13070 if (t2 is TypeParameterType) { | |
13071 return false; | |
13072 } | |
13073 | |
13074 if (t1.isVoid || t2.isVoid) { | |
13075 return false; | |
13076 } | |
13077 | |
13078 // We've eliminated void, dynamic, bottom, and type parameters. The only | |
13079 // cases are the combinations of interface type and function type. | |
13080 | |
13081 // A function type can only subtype an interface type if | |
13082 // the interface type is Function | |
13083 if (t1 is FunctionType && t2 is InterfaceType) { | |
13084 return t2.isDartCoreFunction; | |
13085 } | |
13086 | |
13087 // An interface type can only subtype a function type if | |
13088 // the interface type declares a call method with a type | |
13089 // which is a super type of the function type. | |
13090 if (t1 is InterfaceType && t2 is FunctionType) { | |
13091 var callType = _getCallMethodType(t1); | |
13092 return (callType != null) && _isFunctionSubtypeOf(callType, t2); | |
13093 } | |
13094 | |
13095 // Two interface types | |
13096 if (t1 is InterfaceType && t2 is InterfaceType) { | |
13097 return _isInterfaceSubtypeOf(t1, t2, visited); | |
13098 } | |
13099 | |
13100 return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType); | |
13101 } | |
13102 | |
13103 // TODO(leafp): Document the rules in play here | |
13104 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { | |
13105 return (t.isDynamic && !dynamicIsBottom) || t.isObject; | |
13106 } | |
13107 } | |
13108 | |
13109 /** | |
13110 * Instances of this class manage the knowledge of what the set of subtypes are
for a given type. | 12807 * Instances of this class manage the knowledge of what the set of subtypes are
for a given type. |
13111 */ | 12808 */ |
13112 class SubtypeManager { | 12809 class SubtypeManager { |
13113 /** | 12810 /** |
13114 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype
s of the | 12811 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype
s of the |
13115 * key. | 12812 * key. |
13116 */ | 12813 */ |
13117 HashMap<ClassElement, HashSet<ClassElement>> _subtypeMap = | 12814 HashMap<ClassElement, HashSet<ClassElement>> _subtypeMap = |
13118 new HashMap<ClassElement, HashSet<ClassElement>>(); | 12815 new HashMap<ClassElement, HashSet<ClassElement>>(); |
13119 | 12816 |
(...skipping 2205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15325 return identical(parent.type, node); | 15022 return identical(parent.type, node); |
15326 } | 15023 } |
15327 if (parent is SimpleFormalParameter) { | 15024 if (parent is SimpleFormalParameter) { |
15328 return identical(parent.type, node); | 15025 return identical(parent.type, node); |
15329 } | 15026 } |
15330 return false; | 15027 return false; |
15331 } | 15028 } |
15332 } | 15029 } |
15333 | 15030 |
15334 /** | 15031 /** |
15335 * The interface `TypeSystem` defines the behavior of an object representing | |
15336 * the type system. This provides a common location to put methods that act on | |
15337 * types but may need access to more global data structures, and it paves the | |
15338 * way for a possible future where we may wish to make the type system | |
15339 * pluggable. | |
15340 */ | |
15341 abstract class TypeSystem { | |
15342 /** | |
15343 * Compute the least upper bound of two types. | |
15344 */ | |
15345 DartType getLeastUpperBound( | |
15346 TypeProvider typeProvider, DartType type1, DartType type2); | |
15347 | |
15348 /** | |
15349 * Return `true` if the [leftType] is assignable to the [rightType] (that is, | |
15350 * if leftType <==> rightType). | |
15351 */ | |
15352 bool isAssignableTo(DartType leftType, DartType rightType); | |
15353 | |
15354 /** | |
15355 * Return `true` if the [leftType] is a subtype of the [rightType] (that is, | |
15356 * if leftType <: rightType). | |
15357 */ | |
15358 bool isSubtypeOf(DartType leftType, DartType rightType); | |
15359 | |
15360 /** | |
15361 * Create either a strong mode or regular type system based on context. | |
15362 */ | |
15363 static TypeSystem create(AnalysisContext context) { | |
15364 return (context.analysisOptions.strongMode) | |
15365 ? new StrongTypeSystemImpl() | |
15366 : new TypeSystemImpl(); | |
15367 } | |
15368 } | |
15369 | |
15370 /** | |
15371 * Implementation of [TypeSystem] using the rules in the Dart specification. | |
15372 */ | |
15373 class TypeSystemImpl implements TypeSystem { | |
15374 TypeSystemImpl(); | |
15375 | |
15376 @override | |
15377 DartType getLeastUpperBound( | |
15378 TypeProvider typeProvider, DartType type1, DartType type2) { | |
15379 // The least upper bound relation is reflexive. | |
15380 if (identical(type1, type2)) { | |
15381 return type1; | |
15382 } | |
15383 // The least upper bound of dynamic and any type T is dynamic. | |
15384 if (type1.isDynamic) { | |
15385 return type1; | |
15386 } | |
15387 if (type2.isDynamic) { | |
15388 return type2; | |
15389 } | |
15390 // The least upper bound of void and any type T != dynamic is void. | |
15391 if (type1.isVoid) { | |
15392 return type1; | |
15393 } | |
15394 if (type2.isVoid) { | |
15395 return type2; | |
15396 } | |
15397 // The least upper bound of bottom and any type T is T. | |
15398 if (type1.isBottom) { | |
15399 return type2; | |
15400 } | |
15401 if (type2.isBottom) { | |
15402 return type1; | |
15403 } | |
15404 // Let U be a type variable with upper bound B. The least upper bound of U | |
15405 // and a type T is the least upper bound of B and T. | |
15406 while (type1 is TypeParameterType) { | |
15407 // TODO(paulberry): is this correct in the complex of F-bounded | |
15408 // polymorphism? | |
15409 DartType bound = (type1 as TypeParameterType).element.bound; | |
15410 if (bound == null) { | |
15411 bound = typeProvider.objectType; | |
15412 } | |
15413 type1 = bound; | |
15414 } | |
15415 while (type2 is TypeParameterType) { | |
15416 // TODO(paulberry): is this correct in the context of F-bounded | |
15417 // polymorphism? | |
15418 DartType bound = (type2 as TypeParameterType).element.bound; | |
15419 if (bound == null) { | |
15420 bound = typeProvider.objectType; | |
15421 } | |
15422 type2 = bound; | |
15423 } | |
15424 // The least upper bound of a function type and an interface type T is the | |
15425 // least upper bound of Function and T. | |
15426 if (type1 is FunctionType && type2 is InterfaceType) { | |
15427 type1 = typeProvider.functionType; | |
15428 } | |
15429 if (type2 is FunctionType && type1 is InterfaceType) { | |
15430 type2 = typeProvider.functionType; | |
15431 } | |
15432 | |
15433 // At this point type1 and type2 should both either be interface types or | |
15434 // function types. | |
15435 if (type1 is InterfaceType && type2 is InterfaceType) { | |
15436 InterfaceType result = | |
15437 InterfaceTypeImpl.computeLeastUpperBound(type1, type2); | |
15438 if (result == null) { | |
15439 return typeProvider.dynamicType; | |
15440 } | |
15441 return result; | |
15442 } else if (type1 is FunctionType && type2 is FunctionType) { | |
15443 FunctionType result = | |
15444 FunctionTypeImpl.computeLeastUpperBound(type1, type2); | |
15445 if (result == null) { | |
15446 return typeProvider.functionType; | |
15447 } | |
15448 return result; | |
15449 } else { | |
15450 // Should never happen. As a defensive measure, return the dynamic type. | |
15451 assert(false); | |
15452 return typeProvider.dynamicType; | |
15453 } | |
15454 } | |
15455 | |
15456 @override | |
15457 bool isAssignableTo(DartType leftType, DartType rightType) { | |
15458 return leftType.isAssignableTo(rightType); | |
15459 } | |
15460 | |
15461 @override | |
15462 bool isSubtypeOf(DartType leftType, DartType rightType) { | |
15463 return leftType.isSubtypeOf(rightType); | |
15464 } | |
15465 } | |
15466 | |
15467 /** | |
15468 * Instances of the class [UnusedLocalElementsVerifier] traverse an element | 15032 * Instances of the class [UnusedLocalElementsVerifier] traverse an element |
15469 * structure looking for cases of [HintCode.UNUSED_ELEMENT], | 15033 * structure looking for cases of [HintCode.UNUSED_ELEMENT], |
15470 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc. | 15034 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc. |
15471 */ | 15035 */ |
15472 class UnusedLocalElementsVerifier extends RecursiveElementVisitor { | 15036 class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
15473 /** | 15037 /** |
15474 * The error listener to which errors will be reported. | 15038 * The error listener to which errors will be reported. |
15475 */ | 15039 */ |
15476 final AnalysisErrorListener _errorListener; | 15040 final AnalysisErrorListener _errorListener; |
15477 | 15041 |
(...skipping 562 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16040 nonFields.add(node); | 15604 nonFields.add(node); |
16041 return null; | 15605 return null; |
16042 } | 15606 } |
16043 | 15607 |
16044 @override | 15608 @override |
16045 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); | 15609 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); |
16046 | 15610 |
16047 @override | 15611 @override |
16048 Object visitWithClause(WithClause node) => null; | 15612 Object visitWithClause(WithClause node) => null; |
16049 } | 15613 } |
OLD | NEW |