Chromium Code Reviews

Side by Side Diff: mojo/public/dart/third_party/analyzer/lib/src/task/strong_mode.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer.src.task.strong_mode;
6
7 import 'dart:collection';
8
9 import 'package:analyzer/src/generated/ast.dart';
10 import 'package:analyzer/src/generated/element.dart';
11 import 'package:analyzer/src/generated/resolver.dart';
12 import 'package:analyzer/src/generated/utilities_dart.dart';
13
14 /**
15 * Set the type of the sole parameter of the given [element] to the given [type] .
16 */
17 void setParameterType(PropertyAccessorElement element, DartType type) {
18 if (element is PropertyAccessorElementImpl) {
19 ParameterElement parameter = _getParameter(element);
20 if (parameter is ParameterElementImpl) {
21 //
22 // Update the type of the parameter.
23 //
24 parameter.type = type;
25 //
26 // Update the type of the setter to reflect the new parameter type.
27 //
28 FunctionType functionType = element.type;
29 if (functionType is FunctionTypeImpl) {
30 element.type =
31 new FunctionTypeImpl(element, functionType.prunedTypedefs);
32 } else {
33 assert(false);
34 }
35 } else {
36 assert(false);
37 }
38 } else {
39 throw new StateError('element is an instance of ${element.runtimeType}');
40 assert(false);
41 }
42 }
43
44 /**
45 * Set the return type of the given [element] to the given [type].
46 */
47 void setReturnType(ExecutableElement element, DartType type) {
48 if (element is ExecutableElementImpl) {
49 //
50 // Update the return type of the element, which is stored in two places:
51 // directly in the element and indirectly in the type of the element.
52 //
53 element.returnType = type;
54 FunctionType functionType = element.type;
55 if (functionType is FunctionTypeImpl) {
56 element.type = new FunctionTypeImpl(element, functionType.prunedTypedefs);
57 } else {
58 assert(false);
59 }
60 } else {
61 assert(false);
62 }
63 }
64
65 /**
66 * Return the element for the single parameter of the given [setter], or `null`
67 * if the executable element is not a setter or does not have a single
68 * parameter.
69 */
70 ParameterElement _getParameter(ExecutableElement setter) {
71 if (setter is PropertyAccessorElement && setter.isSetter) {
72 List<ParameterElement> parameters = setter.parameters;
73 if (parameters.length == 1) {
74 return parameters[0];
75 }
76 }
77 return null;
78 }
79
80 /**
81 * A function that returns `true` if the given [variable] passes the filter.
82 */
83 typedef bool VariableFilter(VariableElement element);
84
85 /**
86 * An object used to find static variables whose types should be inferred and
87 * classes whose members should have types inferred. Clients are expected to
88 * visit a [CompilationUnit].
89 */
90 class InferrenceFinder extends SimpleAstVisitor {
91 /**
92 * The static variables that should have types inferred for them.
93 */
94 final List<VariableElement> staticVariables = <VariableElement>[];
95
96 /**
97 * The classes defined in the unit.
98 *
99 * TODO(brianwilkerson) We don't currently remove classes whose members do not
100 * need to be processed, but we potentially could.
101 */
102 final List<ClassElement> classes = <ClassElement>[];
103
104 /**
105 * Initialize a newly created finder.
106 */
107 InferrenceFinder();
108
109 @override
110 void visitClassDeclaration(ClassDeclaration node) {
111 classes.add(node.element);
112 for (ClassMember member in node.members) {
113 member.accept(this);
114 }
115 }
116
117 @override
118 void visitClassTypeAlias(ClassTypeAlias node) {
119 classes.add(node.element);
120 }
121
122 @override
123 void visitCompilationUnit(CompilationUnit node) {
124 for (CompilationUnitMember declaration in node.declarations) {
125 declaration.accept(this);
126 }
127 }
128
129 @override
130 void visitFieldDeclaration(FieldDeclaration node) {
131 if (node.isStatic && node.fields.type == null) {
132 _addVariables(node.fields.variables);
133 }
134 }
135
136 @override
137 void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
138 if (node.variables.type == null) {
139 _addVariables(node.variables.variables);
140 }
141 }
142
143 /**
144 * Add all of the [variables] with initializers to the list of variables whose
145 * type can be inferred. Technically, we only infer the types of variables
146 * that do not have a static type, but all variables with initializers
147 * potentially need to be re-resolved after inference because they might
148 * refer to fields whose type was inferred.
149 */
150 void _addVariables(NodeList<VariableDeclaration> variables) {
151 for (VariableDeclaration variable in variables) {
152 if (variable.initializer != null) {
153 VariableElement element = variable.element;
154 if (element.hasImplicitType) {
155 staticVariables.add(element);
156 }
157 }
158 }
159 }
160 }
161
162 /**
163 * An object used to infer the type of instance fields and the return types of
164 * instance methods within a single compilation unit.
165 */
166 class InstanceMemberInferrer {
167 /**
168 * The type provider used to look up types.
169 */
170 final TypeProvider typeProvider;
171
172 /**
173 * The type system used to compute the least upper bound of types.
174 */
175 TypeSystem typeSystem;
176
177 /**
178 * The inheritance manager used to find overridden method.
179 */
180 InheritanceManager inheritanceManager;
181
182 /**
183 * The classes that have been visited while attempting to infer the types of
184 * instance members of some base class.
185 */
186 HashSet<ClassElementImpl> elementsBeingInferred =
187 new HashSet<ClassElementImpl>();
188
189 /**
190 * Initialize a newly create inferrer.
191 */
192 InstanceMemberInferrer(this.typeProvider) {
193 typeSystem = new TypeSystemImpl(typeProvider);
194 }
195
196 /**
197 * Infer type information for all of the instance members in the given
198 * compilation [unit].
199 */
200 void inferCompilationUnit(CompilationUnitElement unit) {
201 inheritanceManager = new InheritanceManager(unit.library);
202 unit.types.forEach((ClassElement classElement) {
203 try {
204 _inferClass(classElement);
205 } on _CycleException {
206 // This is a short circuit return to prevent types that inherit from
207 // types containing a circular reference from being inferred.
208 }
209 });
210 }
211
212 /**
213 * Compute the best type for the [parameter] at the given [index] that must be
214 * compatible with the types of the corresponding parameters of the given
215 * [overriddenMethods].
216 *
217 * At the moment, this method will only return a type other than 'dynamic' if
218 * the types of all of the parameters are the same. In the future we might
219 * want to be smarter about it, such as by returning the least upper bound of
220 * the parameter types.
221 */
222 DartType _computeParameterType(ParameterElement parameter, int index,
223 List<ExecutableElement> overriddenMethods) {
224 DartType parameterType = null;
225 int length = overriddenMethods.length;
226 for (int i = 0; i < length; i++) {
227 DartType type = _getTypeOfCorrespondingParameter(
228 parameter, index, overriddenMethods[i]);
229 if (parameterType == null) {
230 parameterType = type;
231 } else if (parameterType != type) {
232 return typeProvider.dynamicType;
233 }
234 }
235 return parameterType == null ? typeProvider.dynamicType : parameterType;
236 }
237
238 /**
239 * Compute the best return type for a method that must be compatible with the
240 * return types of each of the given [overriddenMethods].
241 *
242 * At the moment, this method will only return a type other than 'dynamic' if
243 * the return types of all of the methods are the same. In the future we might
244 * want to be smarter about it.
245 */
246 DartType _computeReturnType(List<ExecutableElement> overriddenMethods) {
247 DartType returnType = null;
248 int length = overriddenMethods.length;
249 for (int i = 0; i < length; i++) {
250 DartType type = _getReturnType(overriddenMethods[i]);
251 if (returnType == null) {
252 returnType = type;
253 } else if (returnType != type) {
254 return typeProvider.dynamicType;
255 }
256 }
257 return returnType == null ? typeProvider.dynamicType : returnType;
258 }
259
260 DartType _getReturnType(ExecutableElement element) {
261 DartType returnType = element.returnType;
262 if (returnType == null) {
263 return typeProvider.dynamicType;
264 }
265 return returnType;
266 }
267
268 /**
269 * Given a [method], return the type of the parameter in the method that
270 * corresponds to the given [parameter]. If the parameter is positional, then
271 * it appears at the given [index] in its enclosing element's list of
272 * parameters.
273 */
274 DartType _getTypeOfCorrespondingParameter(
275 ParameterElement parameter, int index, ExecutableElement method) {
276 //
277 // Find the corresponding parameter.
278 //
279 List<ParameterElement> methodParameters = method.parameters;
280 ParameterElement matchingParameter = null;
281 if (parameter.parameterKind == ParameterKind.NAMED) {
282 //
283 // If we're looking for a named parameter, only a named parameter with
284 // the same name will be matched.
285 //
286 matchingParameter = methodParameters.lastWhere(
287 (ParameterElement methodParameter) =>
288 methodParameter.parameterKind == ParameterKind.NAMED &&
289 methodParameter.name == parameter.name,
290 orElse: () => null);
291 } else {
292 //
293 // If we're looking for a positional parameter we ignore the difference
294 // between required and optional parameters.
295 //
296 if (index < methodParameters.length) {
297 matchingParameter = methodParameters[index];
298 if (matchingParameter.parameterKind == ParameterKind.NAMED) {
299 matchingParameter = null;
300 }
301 }
302 }
303 //
304 // Then return the type of the parameter.
305 //
306 return matchingParameter == null
307 ? typeProvider.dynamicType
308 : matchingParameter.type;
309 }
310
311 /**
312 * If the given [accessorElement] represents a non-synthetic instance getter
313 * for which no return type was provided, infer the return type of the getter.
314 */
315 void _inferAccessor(PropertyAccessorElement accessorElement) {
316 if (!accessorElement.isSynthetic &&
317 accessorElement.isGetter &&
318 !accessorElement.isStatic &&
319 accessorElement.hasImplicitReturnType) {
320 List<ExecutableElement> overriddenGetters = inheritanceManager
321 .lookupOverrides(
322 accessorElement.enclosingElement, accessorElement.name);
323 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) {
324 DartType newType = _computeReturnType(overriddenGetters);
325 List<ExecutableElement> overriddenSetters = inheritanceManager
326 .lookupOverrides(
327 accessorElement.enclosingElement, accessorElement.name + '=');
328 PropertyAccessorElement setter = (accessorElement.enclosingElement
329 as ClassElement).getSetter(accessorElement.name);
330 if (setter != null) {
331 overriddenSetters.add(setter);
332 }
333 if (!_isCompatible(newType, overriddenSetters)) {
334 newType = typeProvider.dynamicType;
335 }
336 setReturnType(accessorElement, newType);
337 (accessorElement.variable as FieldElementImpl).type = newType;
338 }
339 }
340 }
341
342 /**
343 * Infer type information for all of the instance members in the given
344 * [classElement].
345 */
346 void _inferClass(ClassElement classElement) {
347 if (classElement is ClassElementImpl) {
348 if (classElement.hasBeenInferred) {
349 return;
350 }
351 if (!elementsBeingInferred.add(classElement)) {
352 // We have found a circularity in the class hierarchy. For now we just
353 // stop trying to infer any type information for any classes that
354 // inherit from any class in the cycle. We could potentially limit the
355 // algorithm to only not inferring types in the classes in the cycle,
356 // but it isn't clear that the results would be significantly better.
357 throw new _CycleException();
358 }
359 try {
360 //
361 // Ensure that all of instance members in the supertypes have had types
362 // inferred for them.
363 //
364 _inferType(classElement.supertype);
365 classElement.mixins.forEach(_inferType);
366 classElement.interfaces.forEach(_inferType);
367 //
368 // Then infer the types for the members.
369 //
370 classElement.fields.forEach(_inferField);
371 classElement.accessors.forEach(_inferAccessor);
372 classElement.methods.forEach(_inferMethod);
373 classElement.hasBeenInferred = true;
374 } finally {
375 elementsBeingInferred.remove(classElement);
376 }
377 }
378 }
379
380 /**
381 * If the given [fieldElement] represents a non-synthetic instance field for
382 * which no type was provided, infer the type of the field.
383 */
384 void _inferField(FieldElement fieldElement) {
385 if (!fieldElement.isSynthetic &&
386 !fieldElement.isStatic &&
387 fieldElement.hasImplicitType) {
388 //
389 // First look for overridden getters with the same name as the field.
390 //
391 List<ExecutableElement> overriddenGetters = inheritanceManager
392 .lookupOverrides(fieldElement.enclosingElement, fieldElement.name);
393 DartType newType = null;
394 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) {
395 newType = _computeReturnType(overriddenGetters);
396 List<ExecutableElement> overriddenSetters = inheritanceManager
397 .lookupOverrides(
398 fieldElement.enclosingElement, fieldElement.name + '=');
399 if (!_isCompatible(newType, overriddenSetters)) {
400 newType = null;
401 }
402 }
403 //
404 // Then, if none was found, infer the type from the initialization
405 // expression.
406 //
407 if (newType == null) {
408 if (fieldElement.initializer != null &&
409 (fieldElement.isFinal || overriddenGetters.isEmpty)) {
410 newType = fieldElement.initializer.returnType;
411 }
412 }
413 if (newType == null || newType.isBottom) {
414 newType = typeProvider.dynamicType;
415 }
416 (fieldElement as FieldElementImpl).type = newType;
417 setReturnType(fieldElement.getter, newType);
418 if (!fieldElement.isFinal && !fieldElement.isConst) {
419 setParameterType(fieldElement.setter, newType);
420 }
421 }
422 }
423
424 /**
425 * If the given [methodElement] represents a non-synthetic instance method
426 * for which no return type was provided, infer the return type of the method.
427 */
428 void _inferMethod(MethodElement methodElement) {
429 if (methodElement.isSynthetic || methodElement.isStatic) {
430 return;
431 }
432 List<ExecutableElement> overriddenMethods = null;
433 //
434 // Infer the return type.
435 //
436 if (methodElement.hasImplicitReturnType) {
437 overriddenMethods = inheritanceManager.lookupOverrides(
438 methodElement.enclosingElement, methodElement.name);
439 if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) {
440 return;
441 }
442 MethodElementImpl element = methodElement as MethodElementImpl;
443 setReturnType(element, _computeReturnType(overriddenMethods));
444 }
445 //
446 // Infer the parameter types.
447 //
448 List<ParameterElement> parameters = methodElement.parameters;
449 int length = parameters.length;
450 for (int i = 0; i < length; ++i) {
451 ParameterElement parameter = parameters[i];
452 if (parameter is ParameterElementImpl && parameter.hasImplicitType) {
453 if (overriddenMethods == null) {
454 overriddenMethods = inheritanceManager.lookupOverrides(
455 methodElement.enclosingElement, methodElement.name);
456 }
457 if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) {
458 return;
459 }
460 parameter.type = _computeParameterType(parameter, i, overriddenMethods);
461 }
462 }
463 }
464
465 /**
466 * Infer type information for all of the instance members in the given
467 * interface [type].
468 */
469 void _inferType(InterfaceType type) {
470 if (type != null) {
471 ClassElement element = type.element;
472 if (element != null) {
473 _inferClass(element);
474 }
475 }
476 }
477
478 /**
479 * Return `true` if the given [type] is compatible with the argument types of
480 * all of the given [setters].
481 */
482 bool _isCompatible(DartType type, List<ExecutableElement> setters) {
483 for (ExecutableElement setter in setters) {
484 ParameterElement parameter = _getParameter(setter);
485 if (parameter != null && !typeSystem.isSubtypeOf(parameter.type, type)) {
486 return false;
487 }
488 }
489 return true;
490 }
491
492 /**
493 * Return `true` if the list of [elements] contains only getters.
494 */
495 bool _onlyGetters(List<ExecutableElement> elements) {
496 for (ExecutableElement element in elements) {
497 if (!(element is PropertyAccessorElement && element.isGetter)) {
498 return false;
499 }
500 }
501 return true;
502 }
503
504 /**
505 * Return `true` if the list of [elements] contains only methods.
506 */
507 bool _onlyMethods(List<ExecutableElement> elements) {
508 for (ExecutableElement element in elements) {
509 if (element is! MethodElement) {
510 return false;
511 }
512 }
513 return true;
514 }
515 }
516
517 /**
518 * A visitor that will gather all of the variables referenced within a given
519 * AST structure. The collection can be restricted to contain only those
520 * variables that pass a specified filter.
521 */
522 class VariableGatherer extends RecursiveAstVisitor {
523 /**
524 * The filter used to limit which variables are gathered, or `null` if no
525 * filtering is to be performed.
526 */
527 final VariableFilter filter;
528
529 /**
530 * The variables that were found.
531 */
532 final Set<VariableElement> results = new HashSet<VariableElement>();
533
534 /**
535 * Initialize a newly created gatherer to gather all of the variables that
536 * pass the given [filter] (or all variables if no filter is provided).
537 */
538 VariableGatherer([this.filter = null]);
539
540 @override
541 void visitSimpleIdentifier(SimpleIdentifier node) {
542 if (!node.inDeclarationContext()) {
543 Element element = node.staticElement;
544 if (element is PropertyAccessorElement && element.isSynthetic) {
545 element = (element as PropertyAccessorElement).variable;
546 }
547 if (element is VariableElement && (filter == null || filter(element))) {
548 results.add(element);
549 }
550 }
551 }
552 }
553
554 /**
555 * A class of exception that is not used anywhere else.
556 */
557 class _CycleException implements Exception {}
OLDNEW

Powered by Google App Engine