Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(718)

Side by Side Diff: pkg/analyzer/lib/src/task/strong/info.dart

Issue 2054443002: Add analysis option that will be used to fix #26583 (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 /// Defines static information collected by the type checker and used later by 5 /// Defines static information collected by the type checker and used later by
6 /// emitters to generate code. 6 /// emitters to generate code.
7 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be 7 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
8 // refactored to fit into analyzer. 8 // refactored to fit into analyzer.
9 library analyzer.src.task.strong.info; 9 library analyzer.src.task.strong.info;
10 10
11 import 'package:analyzer/dart/ast/ast.dart'; 11 import 'package:analyzer/dart/ast/ast.dart';
12 import 'package:analyzer/dart/element/element.dart'; 12 import 'package:analyzer/dart/element/element.dart';
13 import 'package:analyzer/dart/element/type.dart'; 13 import 'package:analyzer/dart/element/type.dart';
14 import 'package:analyzer/src/dart/element/type.dart'; 14 import 'package:analyzer/src/dart/element/type.dart';
15 import 'package:analyzer/src/generated/error.dart'; 15 import 'package:analyzer/src/generated/error.dart';
16 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
16 import 'package:analyzer/src/generated/type_system.dart'; 17 import 'package:analyzer/src/generated/type_system.dart';
17 18
18 /// A down cast due to a variable declaration to a ground type:
19 ///
20 /// T x = expr;
21 ///
22 /// where `T` is ground. We exclude non-ground types as these behave
23 /// differently compared to standard Dart.
24 class AssignmentCast extends DownCast {
25 AssignmentCast(TypeSystem rules, Expression expression, DartType fromType,
26 DartType toType)
27 : super._internal(rules, expression, fromType, toType);
28
29 @override
30 String get name => 'STRONG_MODE_ASSIGNMENT_CAST';
31
32 toErrorCode() => new HintCode(name, message);
33 }
34
35 /// Implicitly injected expression conversion. 19 /// Implicitly injected expression conversion.
36 abstract class CoercionInfo extends StaticInfo { 20 abstract class CoercionInfo extends StaticInfo {
37 static const String _propertyName = 'dev_compiler.src.info.CoercionInfo'; 21 static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
38 22
39 final TypeSystem rules;
40
41 final Expression node; 23 final Expression node;
42 24
43 CoercionInfo(this.rules, this.node); 25 CoercionInfo(this.node);
44 26
45 DartType get baseType => node.staticType ?? DynamicTypeImpl.instance; 27 DartType get baseType => node.staticType ?? DynamicTypeImpl.instance;
46 DartType get convertedType; 28 DartType get convertedType;
47 29
48 String get message; 30 String get message;
49 DartType get staticType => convertedType; 31 DartType get staticType => convertedType;
50 32
51 toErrorCode() => new HintCode(name, message); 33 toErrorCode() => new HintCode(name, message);
52 34
53 /// Gets the coercion info associated with this node. 35 /// Gets the coercion info associated with this node.
54 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName); 36 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
55 37
56 /// Sets the coercion info associated with this node. 38 /// Sets the coercion info associated with this node.
57 static CoercionInfo set(AstNode node, CoercionInfo info) { 39 static CoercionInfo set(AstNode node, CoercionInfo info) {
58 node.setProperty(_propertyName, info); 40 node.setProperty(_propertyName, info);
59 return info; 41 return info;
60 } 42 }
61 } 43 }
62 44
63 /// Base class for all casts from base type to sub type. 45 /// Implicit casts from base type to sub type.
64 abstract class DownCast extends CoercionInfo { 46 class DownCast extends CoercionInfo {
65 final DartType _fromType; 47 final DartType _fromType;
66 final DartType _toType; 48 final DartType _toType;
49 ErrorCode _errorCode;
67 50
68 DownCast._internal( 51 DownCast._(
69 TypeSystem rules, Expression expression, this._fromType, this._toType) 52 Expression expression, this._fromType, this._toType, this._errorCode)
70 : super(rules, expression); 53 : super(expression);
71 54
72 @override 55 @override
73 List<Object> get arguments => [baseType, convertedType]; 56 List<Object> get arguments => [baseType, convertedType];
74 57
75 /// The type being cast from. 58 /// The type being cast from.
76 /// 59 ///
77 /// This is usually the static type of the associated expression, but may not 60 /// This is usually the static type of the associated expression, but may not
78 /// be if the cast is attached to a variable in a for-in loop. 61 /// be if the cast is attached to a variable in a for-in loop.
79 @override 62 @override
80 DartType get baseType => _fromType; 63 DartType get baseType => _fromType;
81 64
65 @override
82 DartType get convertedType => _toType; 66 DartType get convertedType => _toType;
83 67
84 @override 68 @override
85 String get message => 'Unsound implicit cast from {0} to {1}'; 69 String get message => _message;
70
71 @override
72 String get name => _errorCode.name;
73
74 @override
75 toErrorCode() => _errorCode;
76
77 static const String _message = 'Unsound implicit cast from {0} to {1}';
86 78
87 /// Factory to create correct DownCast variant. 79 /// Factory to create correct DownCast variant.
88 static StaticInfo create(StrongTypeSystemImpl rules, Expression expression, 80 static StaticInfo create(StrongTypeSystemImpl rules, Expression expression,
89 DartType fromType, DartType toType) { 81 DartType fromType, DartType toType, AnalysisOptionsImpl options) {
90 // toT <:_R fromT => to <: fromT 82 // toT <:_R fromT => to <: fromT
91 // NB: classes with call methods are subtypes of function 83 // NB: classes with call methods are subtypes of function
92 // types, but the function type is not assignable to the class 84 // types, but the function type is not assignable to the class
93 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); 85 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
94 86
95 // Inference "casts": 87 // Inference "casts":
96 if (expression is Literal || expression is FunctionExpression) { 88 if (expression is Literal || expression is FunctionExpression) {
97 // fromT should be an exact type - this will almost certainly fail at 89 // fromT should be an exact type - this will almost certainly fail at
98 // runtime. 90 // runtime.
99 return new StaticTypeError(rules, expression, toType); 91 return new StaticTypeError(expression, toType);
100 } 92 }
101 93
102 if (expression is InstanceCreationExpression) { 94 if (expression is InstanceCreationExpression) {
103 ConstructorElement e = expression.staticElement; 95 ConstructorElement e = expression.staticElement;
104 if (e == null || !e.isFactory) { 96 if (e == null || !e.isFactory) {
105 // fromT should be an exact type - this will almost certainly fail at 97 // fromT should be an exact type - this will almost certainly fail at
106 // runtime. 98 // runtime.
107 return new StaticTypeError(rules, expression, toType); 99 return new StaticTypeError(expression, toType);
108 } 100 }
109 } 101 }
110 102
111 if (StaticInfo.isKnownFunction(expression)) { 103 if (StaticInfo.isKnownFunction(expression)) {
112 return new StaticTypeError(rules, expression, toType); 104 return new StaticTypeError(expression, toType);
113 } 105 }
114 106
115 // TODO(vsm): Change this to an assert when we have generic methods and 107 // TODO(vsm): Change this to an assert when we have generic methods and
116 // fix TypeRules._coerceTo to disallow implicit sideways casts. 108 // fix TypeRules._coerceTo to disallow implicit sideways casts.
109 bool downCastComposite = false;
117 if (!rules.isSubtypeOf(toType, fromType)) { 110 if (!rules.isSubtypeOf(toType, fromType)) {
118 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); 111 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
119 return new DownCastComposite(rules, expression, fromType, toType); 112 downCastComposite = true;
120 } 113 }
121 114
122 // Composite cast: these are more likely to fail. 115 // Composite cast: these are more likely to fail.
123 if (!rules.isGroundType(toType)) { 116 if (!rules.isGroundType(toType)) {
124 // This cast is (probably) due to our different treatment of dynamic. 117 // This cast is (probably) due to our different treatment of dynamic.
125 // It may be more likely to fail at runtime. 118 // It may be more likely to fail at runtime.
126 if (fromType is InterfaceType) { 119 if (fromType is InterfaceType) {
127 // For class types, we'd like to allow non-generic down casts, e.g., 120 // For class types, we'd like to allow non-generic down casts, e.g.,
128 // Iterable<T> to List<T>. The intuition here is that raw (generic) 121 // Iterable<T> to List<T>. The intuition here is that raw (generic)
129 // casts are problematic, and we should complain about those. 122 // casts are problematic, and we should complain about those.
130 var typeArgs = fromType.typeArguments; 123 var typeArgs = fromType.typeArguments;
131 if (typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic)) { 124 downCastComposite =
132 return new DownCastComposite(rules, expression, fromType, toType); 125 typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic);
133 }
134 } else { 126 } else {
135 return new DownCastComposite(rules, expression, fromType, toType); 127 downCastComposite = true;
136 } 128 }
137 } 129 }
138 130
139 // Dynamic cast 131 var parent = expression.parent;
140 if (fromType.isDynamic) { 132 String name;
141 return new DynamicCast(rules, expression, fromType, toType); 133 if (downCastComposite) {
134 name = 'STRONG_MODE_DOWN_CAST_COMPOSITE';
135 } else if (fromType.isDynamic) {
136 name = 'STRONG_MODE_DYNAMIC_CAST';
137 } else if (parent is VariableDeclaration &&
138 parent.initializer == expression) {
139 name = 'STRONG_MODE_ASSIGNMENT_CAST';
140 } else {
141 name = 'STRONG_MODE_DOWN_CAST_IMPLICIT';
142 } 142 }
143 143
144 // Assignment cast 144 // For the remaining cases, we allow implicit casts by default.
145 var parent = expression.parent; 145 // However this can be disabled with an option.
146 if (parent is VariableDeclaration && (parent.initializer == expression)) { 146 ErrorCode errorCode;
Brian Wilkerson 2016/06/08 18:31:35 Creating a new ErrorCode for each error is really
Jennifer Messerly 2016/06/08 19:01:52 You're 100% right! It is super weird. I can't thin
Brian Wilkerson 2016/06/08 19:06:07 Having multiple error codes would be useful if (a)
147 return new AssignmentCast(rules, expression, fromType, toType); 147 if (downCastComposite || !options.implicitCasts) {
148 errorCode = new StaticWarningCode(name, _message);
149 } else {
150 errorCode = new HintCode(name, _message);
148 } 151 }
149 152 return new DownCast._(expression, fromType, toType, errorCode);
150 // Other casts
151 return new DownCastImplicit(rules, expression, fromType, toType);
152 } 153 }
153 } 154 }
154 155
155 /// Implicit down casts. These are only injected by the compiler by flag.
156 ///
157 /// A down cast to a non-ground type. These behave differently from standard
158 /// Dart and may be more likely to fail at runtime.
159 class DownCastComposite extends DownCast {
160 DownCastComposite(TypeSystem rules, Expression expression, DartType fromType,
161 DartType toType)
162 : super._internal(rules, expression, fromType, toType);
163
164 @override
165 String get name => 'STRONG_MODE_DOWN_CAST_COMPOSITE';
166
167 toErrorCode() => new StaticWarningCode(name, message);
168 }
169
170 /// A down cast to a non-ground type. These behave differently from standard
171 /// Dart and may be more likely to fail at runtime.
172 class DownCastImplicit extends DownCast {
173 DownCastImplicit(TypeSystem rules, Expression expression, DartType fromType,
174 DartType toType)
175 : super._internal(rules, expression, fromType, toType);
176
177 @override
178 String get name => 'STRONG_MODE_DOWN_CAST_IMPLICIT';
179
180 toErrorCode() => new HintCode(name, message);
181 }
182
183 /// A down cast from dynamic to T.
184 class DynamicCast extends DownCast {
185 DynamicCast(TypeSystem rules, Expression expression, DartType fromType,
186 DartType toType)
187 : super._internal(rules, expression, fromType, toType);
188
189 @override
190 String get name => 'STRONG_MODE_DYNAMIC_CAST';
191
192 toErrorCode() => new HintCode(name, message);
193 }
194
195 class DynamicInvoke extends CoercionInfo { 156 class DynamicInvoke extends CoercionInfo {
196 static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke'; 157 static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
197 158
198 DynamicInvoke(TypeSystem rules, Expression expression) 159 DynamicInvoke(Expression expression) : super(expression);
199 : super(rules, expression);
200 DartType get convertedType => DynamicTypeImpl.instance; 160 DartType get convertedType => DynamicTypeImpl.instance;
201 String get message => '{0} requires dynamic invoke'; 161 String get message => '{0} requires dynamic invoke';
202 162
203 @override 163 @override
204 String get name => 'STRONG_MODE_DYNAMIC_INVOKE'; 164 String get name => 'STRONG_MODE_DYNAMIC_INVOKE';
205 165
206 toErrorCode() => new HintCode(name, message); 166 toErrorCode() => new HintCode(name, message);
207 167
208 /// Whether this [node] is the target of a dynamic operation. 168 /// Whether this [node] is the target of a dynamic operation.
209 static bool get(AstNode node) => node.getProperty(_propertyName) ?? false; 169 static bool get(AstNode node) => node.getProperty(_propertyName) ?? false;
210 170
211 /// Sets whether this node is the target of a dynamic operation. 171 /// Sets whether this node is the target of a dynamic operation.
212 static bool set(AstNode node, bool value) { 172 static bool set(AstNode node, bool value) {
213 // Free the storage for things that aren't dynamic. 173 // Free the storage for things that aren't dynamic.
214 if (value == false) value = null; 174 if (value == false) value = null;
215 node.setProperty(_propertyName, value); 175 node.setProperty(_propertyName, value);
216 return value; 176 return value;
217 } 177 }
218 } 178 }
219 179
220 /// Standard / unspecialized inferred type. 180 /// A marker for an inferred type.
221 class InferredType extends InferredTypeBase { 181 class InferredType extends CoercionInfo {
222 InferredType(TypeSystem rules, Expression expression, DartType type) 182 @override
223 : super._internal(rules, expression, type); 183 final String name;
224 184
225 @override 185 final DartType type;
226 String get name => 'STRONG_MODE_INFERRED_TYPE'; 186
187 InferredType(Expression expression, this.type, this.name) : super(expression);
227 188
228 /// Factory to create correct InferredType variant. 189 /// Factory to create correct InferredType variant.
229 static InferredTypeBase create( 190 static InferredType create(
230 TypeSystem rules, Expression expression, DartType type) { 191 TypeSystem rules, Expression expression, DartType type) {
231 // Specialized inference: 192 // Specialized inference:
193 String name;
232 if (expression is Literal) { 194 if (expression is Literal) {
233 return new InferredTypeLiteral(rules, expression, type); 195 name = 'STRONG_MODE_INFERRED_TYPE_LITERAL';
196 } else if (expression is InstanceCreationExpression) {
197 name = 'STRONG_MODE_INFERRED_TYPE_ALLOCATION';
198 } else if (expression is FunctionExpression) {
199 name = 'STRONG_MODE_INFERRED_TYPE_CLOSURE';
200 } else {
201 name = 'STRONG_MODE_INFERRED_TYPE';
234 } 202 }
235 if (expression is InstanceCreationExpression) { 203 return new InferredType(expression, type, name);
236 return new InferredTypeAllocation(rules, expression, type);
237 }
238 if (expression is FunctionExpression) {
239 return new InferredTypeClosure(rules, expression, type);
240 }
241 return new InferredType(rules, expression, type);
242 } 204 }
243 }
244
245 /// An inferred type for a non-literal allocation site.
246 class InferredTypeAllocation extends InferredTypeBase {
247 InferredTypeAllocation(TypeSystem rules, Expression expression, DartType type)
248 : super._internal(rules, expression, type);
249
250 @override
251 String get name => 'STRONG_MODE_INFERRED_TYPE_ALLOCATION';
252 }
253
254 /// An inferred type for the wrapped expression, which may need to be
255 /// reified into the term.
256 abstract class InferredTypeBase extends CoercionInfo {
257 final DartType _type;
258
259 InferredTypeBase._internal(
260 TypeSystem rules, Expression expression, this._type)
261 : super(rules, expression);
262 205
263 @override 206 @override
264 List get arguments => [node, type]; 207 List get arguments => [node, type];
208
265 DartType get convertedType => type; 209 DartType get convertedType => type;
210
266 @override 211 @override
267 String get message => '{0} has inferred type {1}'; 212 String get message => '{0} has inferred type {1}';
268 DartType get type => _type;
269 213
270 toErrorCode() => new HintCode(name, message); 214 toErrorCode() => new HintCode(name, message);
271 } 215 }
272 216
273 /// An inferred type for a closure expression.
274 class InferredTypeClosure extends InferredTypeBase {
275 InferredTypeClosure(TypeSystem rules, Expression expression, DartType type)
276 : super._internal(rules, expression, type);
277
278 @override
279 String get name => 'STRONG_MODE_INFERRED_TYPE_CLOSURE';
280 }
281
282 /// An inferred type for a literal expression.
283 class InferredTypeLiteral extends InferredTypeBase {
284 InferredTypeLiteral(TypeSystem rules, Expression expression, DartType type)
285 : super._internal(rules, expression, type);
286
287 @override
288 String get name => 'STRONG_MODE_INFERRED_TYPE_LITERAL';
289 }
290
291 class InvalidFieldOverride extends InvalidOverride { 217 class InvalidFieldOverride extends InvalidOverride {
292 InvalidFieldOverride(AstNode node, ExecutableElement element, 218 InvalidFieldOverride(AstNode node, ExecutableElement element,
293 InterfaceType base, DartType subType, DartType baseType) 219 InterfaceType base, DartType subType, DartType baseType)
294 : super(node, element, base, subType, baseType); 220 : super(node, element, base, subType, baseType);
295 221
296 String get message => 'Field declaration {3}.{1} cannot be ' 222 String get message => 'Field declaration {3}.{1} cannot be '
297 'overridden in {0}.'; 223 'overridden in {0}.';
298 224
299 @override 225 @override
300 String get name => 'STRONG_MODE_INVALID_FIELD_OVERRIDE'; 226 String get name => 'STRONG_MODE_INVALID_FIELD_OVERRIDE';
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 // Analyzer instead has template strings, and replaces '{0}' with the first 387 // Analyzer instead has template strings, and replaces '{0}' with the first
462 // argument. 388 // argument.
463 abstract class StaticInfo { 389 abstract class StaticInfo {
464 /// Strong-mode error code names. 390 /// Strong-mode error code names.
465 /// 391 ///
466 /// Used for error code configuration validation in an analysis options file. 392 /// Used for error code configuration validation in an analysis options file.
467 static const List<String> names = const [ 393 static const List<String> names = const [
468 // 394 //
469 // Manually populated. 395 // Manually populated.
470 // 396 //
471 'STRONG_MODE_ASSIGNMENT_CAST', 397 'STRONG_MODE_ASSIGNMENT_CAST',
Jennifer Messerly 2016/06/08 17:50:47 do we need all of these? I started to consolidate
472 'STRONG_MODE_DOWN_CAST_COMPOSITE', 398 'STRONG_MODE_DOWN_CAST_COMPOSITE',
473 'STRONG_MODE_DOWN_CAST_IMPLICIT', 399 'STRONG_MODE_DOWN_CAST_IMPLICIT',
474 'STRONG_MODE_DYNAMIC_CAST', 400 'STRONG_MODE_DYNAMIC_CAST',
475 'STRONG_MODE_DYNAMIC_INVOKE', 401 'STRONG_MODE_DYNAMIC_INVOKE',
476 'STRONG_MODE_INFERRED_TYPE', 402 'STRONG_MODE_INFERRED_TYPE',
477 'STRONG_MODE_INFERRED_TYPE_ALLOCATION', 403 'STRONG_MODE_INFERRED_TYPE_ALLOCATION',
478 'STRONG_MODE_INFERRED_TYPE_CLOSURE', 404 'STRONG_MODE_INFERRED_TYPE_CLOSURE',
479 'STRONG_MODE_INFERRED_TYPE_LITERAL', 405 'STRONG_MODE_INFERRED_TYPE_LITERAL',
480 'STRONG_MODE_INVALID_FIELD_OVERRIDE', 406 'STRONG_MODE_INVALID_FIELD_OVERRIDE',
481 'STRONG_MODE_INVALID_METHOD_OVERRIDE', 407 'STRONG_MODE_INVALID_METHOD_OVERRIDE',
482 'STRONG_MODE_INVALID_PARAMETER_DECLARATION', 408 'STRONG_MODE_INVALID_PARAMETER_DECLARATION',
483 'STRONG_MODE_INVALID_SUPER_INVOCATION', 409 'STRONG_MODE_INVALID_SUPER_INVOCATION',
484 'STRONG_MODE_INVALID_VARIABLE_DECLARATION', 410 'STRONG_MODE_INVALID_VARIABLE_DECLARATION',
485 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO', 411 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO',
486 'STRONG_MODE_STATIC_TYPE_ERROR', 412 'STRONG_MODE_STATIC_TYPE_ERROR',
487 'STRONG_MODE_UNINFERRED_CLOSURE',
488 ]; 413 ];
489 414
490 List<Object> get arguments => [node]; 415 List<Object> get arguments => [node];
491 416
492 String get name; 417 String get name;
493 418
494 /// AST Node this info is attached to. 419 /// AST Node this info is attached to.
495 AstNode get node; 420 AstNode get node;
496 421
497 AnalysisError toAnalysisError() { 422 AnalysisError toAnalysisError() {
(...skipping 22 matching lines...) Expand all
520 // declaration, will have an exact type, so we know a downcast will fail. 445 // declaration, will have an exact type, so we know a downcast will fail.
521 return element is FunctionElement || 446 return element is FunctionElement ||
522 element is MethodElement && element.isStatic; 447 element is MethodElement && element.isStatic;
523 } 448 }
524 } 449 }
525 450
526 class StaticTypeError extends StaticError { 451 class StaticTypeError extends StaticError {
527 final DartType baseType; 452 final DartType baseType;
528 final DartType expectedType; 453 final DartType expectedType;
529 454
530 StaticTypeError(TypeSystem rules, Expression expression, this.expectedType) 455 StaticTypeError(Expression expression, this.expectedType)
531 : baseType = expression.staticType ?? DynamicTypeImpl.instance, 456 : baseType = expression.staticType ?? DynamicTypeImpl.instance,
532 super(expression); 457 super(expression);
533 458
534 @override 459 @override
535 List<Object> get arguments => [node, baseType, expectedType]; 460 List<Object> get arguments => [node, baseType, expectedType];
536 @override 461 @override
537 String get message => 'Type check failed: {0} ({1}) is not of type {2}'; 462 String get message => 'Type check failed: {0} ({1}) is not of type {2}';
538 463
539 @override 464 @override
540 String get name => 'STRONG_MODE_STATIC_TYPE_ERROR'; 465 String get name => 'STRONG_MODE_STATIC_TYPE_ERROR';
541 } 466 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/task/strong/checker.dart ('k') | pkg/analyzer/test/src/task/strong/checker_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698