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

Side by Side Diff: pkg/kernel/lib/analyzer/loader.dart

Issue 2756593004: Start unraveling circularities between analyzer and front_end/kernel. (Closed)
Patch Set: Created 3 years, 9 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
« no previous file with comments | « pkg/kernel/lib/analyzer/ast_from_analyzer.dart ('k') | pkg/kernel/test/baseline_tester.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016, 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 library kernel.analyzer.loader;
5
6 import 'dart:async';
7 import 'dart:convert';
8 import 'dart:io' as io;
9
10 import 'package:analyzer/analyzer.dart';
11 import 'package:analyzer/file_system/file_system.dart';
12 import 'package:analyzer/file_system/physical_file_system.dart';
13 import 'package:analyzer/source/package_map_resolver.dart';
14 import 'package:analyzer/src/dart/scanner/scanner.dart';
15 import 'package:analyzer/src/dart/sdk/sdk.dart';
16 import 'package:analyzer/src/generated/engine.dart';
17 import 'package:analyzer/src/generated/parser.dart';
18 import 'package:analyzer/src/generated/sdk.dart';
19 import 'package:analyzer/src/generated/source_io.dart';
20 import 'package:analyzer/src/summary/summary_sdk.dart';
21 import 'package:kernel/application_root.dart';
22 import 'package:package_config/discovery.dart';
23 import 'package:package_config/packages.dart';
24
25 import '../ast.dart' as ast;
26 import '../target/targets.dart' show Target;
27 import '../type_algebra.dart';
28 import 'analyzer.dart';
29 import 'ast_from_analyzer.dart';
30
31 /// Options passed to the Dart frontend.
32 class DartOptions {
33 /// True if user code should be loaded in strong mode.
34 bool strongMode;
35
36 /// True if the Dart SDK should be loaded in strong mode.
37 bool strongModeSdk;
38
39 /// Path to the sdk sources, ignored if sdkSummary is provided.
40 String sdk;
41
42 /// Path to a summary of the sdk sources.
43 String sdkSummary;
44
45 /// Path to the `.packages` file.
46 String packagePath;
47
48 /// Root used to relativize app file-urls, making them machine agnostic.
49 ApplicationRoot applicationRoot;
50
51 Map<Uri, Uri> customUriMappings;
52
53 /// Environment definitions provided via `-Dkey=value`.
54 Map<String, String> declaredVariables;
55
56 DartOptions(
57 {bool strongMode: false,
58 bool strongModeSdk,
59 this.sdk,
60 this.sdkSummary,
61 this.packagePath,
62 ApplicationRoot applicationRoot,
63 Map<Uri, Uri> customUriMappings,
64 Map<String, String> declaredVariables})
65 : this.customUriMappings = customUriMappings ?? <Uri, Uri>{},
66 this.declaredVariables = declaredVariables ?? <String, String>{},
67 this.strongMode = strongMode,
68 this.strongModeSdk = strongModeSdk ?? strongMode,
69 this.applicationRoot = applicationRoot ?? new ApplicationRoot.none();
70 }
71
72 abstract class ReferenceLevelLoader {
73 ast.Library getLibraryReference(LibraryElement element);
74 ast.Class getClassReference(ClassElement element);
75 ast.Member getMemberReference(Element element);
76 ast.Class getRootClassReference();
77 ast.Constructor getRootClassConstructorReference();
78 ast.Class getCoreClassReference(String className);
79 ast.Constructor getCoreClassConstructorReference(String className,
80 {String constructorName, String library});
81 ast.TypeParameter tryGetClassTypeParameter(TypeParameterElement element);
82 ast.Class getSharedMixinApplicationClass(
83 ast.Library library, ast.Class supertype, ast.Class mixin);
84 bool get strongMode;
85
86 /// Whether or not to include redirecting factories in the output.
87 bool get ignoreRedirectingFactories;
88 }
89
90 class DartLoader implements ReferenceLevelLoader {
91 final ast.Program program;
92 final ApplicationRoot applicationRoot;
93 final Bimap<ClassElement, ast.Class> _classes =
94 new Bimap<ClassElement, ast.Class>();
95 final Bimap<Element, ast.Member> _members = new Bimap<Element, ast.Member>();
96 final Map<TypeParameterElement, ast.TypeParameter> _classTypeParameters =
97 <TypeParameterElement, ast.TypeParameter>{};
98 final Map<ast.Library, Map<String, ast.Class>> _mixinApplications =
99 <ast.Library, Map<String, ast.Class>>{};
100 final Map<LibraryElement, ast.Library> _libraries =
101 <LibraryElement, ast.Library>{};
102 final AnalysisContext context;
103 LibraryElement _dartCoreLibrary;
104 final List errors = [];
105 final List libraryElements = [];
106
107 /// Classes that have been referenced, and must be promoted to type level
108 /// so as not to expose partially initialized classes.
109 final List<ast.Class> temporaryClassWorklist = [];
110
111 final Map<LibraryElement, List<ClassElement>> mixinLibraryWorklist = {};
112
113 final bool ignoreRedirectingFactories;
114
115 LibraryElement _libraryBeingLoaded = null;
116 ClassElement _classBeingPromotedToMixin = null;
117
118 bool get strongMode => context.analysisOptions.strongMode;
119
120 DartLoader(this.program, DartOptions options, Packages packages,
121 {DartSdk dartSdk,
122 AnalysisContext context,
123 this.ignoreRedirectingFactories: true})
124 : this.context =
125 context ?? createContext(options, packages, dartSdk: dartSdk),
126 this.applicationRoot = options.applicationRoot;
127
128 String getLibraryName(LibraryElement element) {
129 return element.name.isEmpty ? null : element.name;
130 }
131
132 LibraryElement getLibraryElementFromUri(Uri uri) {
133 var source = context.sourceFactory.forUri2(uri);
134 if (source == null) return null;
135 return context.computeLibraryElement(source);
136 }
137
138 ast.Library getLibraryReference(LibraryElement element) {
139 var uri = applicationRoot.relativeUri(element.source.uri);
140 var library = _libraries[element];
141 if (library == null) {
142 library = new ast.Library(uri)
143 ..isExternal = true
144 ..name = getLibraryName(element)
145 ..fileUri = '${element.source.uri}';
146 program.libraries.add(library..parent = program);
147 _libraries[element] = library;
148 }
149 return library;
150 }
151
152 ast.Library getLibraryReferenceFromUri(Uri uri) {
153 return getLibraryReference(getLibraryElementFromUri(uri));
154 }
155
156 void _buildTopLevelMember(
157 ast.Member member, Element element, Declaration astNode) {
158 assert(member.parent != null);
159 new MemberBodyBuilder(this, member, element).build(astNode);
160 }
161
162 /// True if [element] is in the process of being loaded by
163 /// [_buildLibraryBody].
164 ///
165 /// If this is the case, we should avoid adding new members to the classes
166 /// in the library, since the AST builder will rebuild the member lists.
167 bool isLibraryBeingLoaded(LibraryElement element) {
168 return _libraryBeingLoaded == element;
169 }
170
171 bool isClassBeingPromotedToMixin(ClassElement element) {
172 return _classBeingPromotedToMixin == element;
173 }
174
175 void _buildLibraryBody(LibraryElement element, ast.Library library,
176 List<CompilationUnit> units) {
177 assert(_libraryBeingLoaded == null);
178 _libraryBeingLoaded = element;
179 var classes = <ast.Class>[];
180 var procedures = <ast.Procedure>[];
181 var fields = <ast.Field>[];
182
183 void loadClass(NamedCompilationUnitMember declaration) {
184 // [declaration] can be a ClassDeclaration, EnumDeclaration, or a
185 // ClassTypeAlias.
186 ClassElement element = declaration.element;
187 var node = getClassReference(element);
188 promoteToBodyLevel(node, element, declaration);
189 classes.add(node);
190 }
191
192 void loadProcedure(FunctionDeclaration declaration) {
193 var element = declaration.element;
194 var node = getMemberReference(element);
195 _buildTopLevelMember(node, element, declaration);
196 procedures.add(node);
197 }
198
199 void loadField(TopLevelVariableDeclaration declaration) {
200 for (var field in declaration.variables.variables) {
201 var element = field.element;
202 // Ignore fields inserted through error recovery.
203 if (element.name == '') continue;
204 var node = getMemberReference(element);
205 _buildTopLevelMember(node, element, field);
206 fields.add(node);
207 }
208 }
209
210 for (var unit in units) {
211 for (CompilationUnitMember declaration in unit.declarations) {
212 if (declaration is ClassDeclaration ||
213 declaration is EnumDeclaration ||
214 declaration is ClassTypeAlias) {
215 loadClass(declaration);
216 } else if (declaration is FunctionDeclaration) {
217 loadProcedure(declaration);
218 } else if (declaration is TopLevelVariableDeclaration) {
219 loadField(declaration);
220 } else if (declaration is FunctionTypeAlias) {
221 // Nothing to do. Typedefs are handled lazily while constructing type
222 // references.
223 } else {
224 throw "unexpected node: ${declaration.runtimeType} $declaration";
225 }
226 }
227 }
228 libraryElements.add(element);
229 _iterateTemporaryClassWorklist();
230 // Ensure everything is stored in the original declaration order.
231 library.classes
232 ..clear()
233 ..addAll(classes)
234 ..addAll(_mixinApplications[library]?.values ?? const []);
235 library.fields
236 ..clear()
237 ..addAll(fields);
238 library.procedures
239 ..clear()
240 ..addAll(procedures);
241 _libraryBeingLoaded = null;
242 }
243
244 LibraryElement getDartCoreLibrary() {
245 return _dartCoreLibrary ??= _findLibraryElement('dart:core');
246 }
247
248 LibraryElement _findLibraryElement(String uri) {
249 var source = context.sourceFactory.forUri(uri);
250 if (source == null) return null;
251 return context.computeLibraryElement(source);
252 }
253
254 ast.Class getRootClassReference() {
255 return getCoreClassReference('Object');
256 }
257
258 ast.Constructor getRootClassConstructorReference() {
259 var element = getDartCoreLibrary().getType('Object').constructors[0];
260 return getMemberReference(element);
261 }
262
263 ast.Class getCoreClassReference(String className) {
264 return getClassReference(getDartCoreLibrary().getType(className));
265 }
266
267 ast.Constructor getCoreClassConstructorReference(String className,
268 {String constructorName, String library}) {
269 LibraryElement libraryElement =
270 library != null ? _findLibraryElement(library) : getDartCoreLibrary();
271 ClassElement element = libraryElement.getType(className);
272 if (element == null) {
273 throw 'Missing core class $className from ${libraryElement.name}';
274 }
275 var constructor = element.constructors.firstWhere((constructor) {
276 return (constructorName == null)
277 ? (constructor.nameLength == 0)
278 : (constructor.name == constructorName);
279 });
280 return getMemberReference(constructor);
281 }
282
283 ClassElement getClassElement(ast.Class node) {
284 return _classes.inverse[node];
285 }
286
287 void addMixinClassToLibrary(ast.Class class_, ast.Library library) {
288 assert(class_.parent == null);
289 library.addClass(class_);
290 var map =
291 _mixinApplications.putIfAbsent(library, () => <String, ast.Class>{});
292 map[class_.name] = class_;
293 }
294
295 /// Returns the IR for a class, at a temporary loading level.
296 ///
297 /// The returned class has the correct name, flags, type parameter arity,
298 /// and enclosing library.
299 ast.Class getClassReference(ClassElement element) {
300 var classNode = _classes[element];
301 if (classNode != null) return classNode;
302 _classes[element] = classNode = new ast.Class(
303 name: element.name,
304 isAbstract: element.isAbstract,
305 fileUri: '${element.source.uri}')..fileOffset = element.nameOffset;
306 classNode.level = ast.ClassLevel.Temporary;
307 var library = getLibraryReference(element.library);
308 library.addClass(classNode);
309 // Initialize type parameter list without bounds.
310 for (var parameter in element.typeParameters) {
311 var parameterNode = new ast.TypeParameter(parameter.name);
312 _classTypeParameters[parameter] = parameterNode;
313 classNode.typeParameters.add(parameterNode);
314 parameterNode.parent = classNode;
315 }
316 // Ensure the class is at least promoted to type level before exposing it
317 // to kernel consumers.
318 temporaryClassWorklist.add(classNode);
319 return classNode;
320 }
321
322 /// Ensures the supertypes and type parameter bounds have been generated for
323 /// the given class.
324 void promoteToTypeLevel(ast.Class classNode) {
325 if (classNode.level.index >= ast.ClassLevel.Type.index) return;
326 classNode.level = ast.ClassLevel.Type;
327 var element = getClassElement(classNode);
328 assert(element != null);
329 var library = getLibraryReference(element.library);
330 var scope = new ClassScope(this, library);
331 // Initialize bounds on type parameters.
332 for (int i = 0; i < classNode.typeParameters.length; ++i) {
333 var parameter = element.typeParameters[i];
334 var parameterNode = classNode.typeParameters[i];
335 parameterNode.bound = parameter.bound == null
336 ? scope.defaultTypeParameterBound
337 : scope.buildType(parameter.bound);
338 }
339 // Initialize supertypes.
340 Iterable<InterfaceType> mixins = element.mixins;
341 if (element.isMixinApplication && mixins.isNotEmpty) {
342 classNode.mixedInType = scope.buildSupertype(mixins.last);
343 mixins = mixins.take(mixins.length - 1);
344 }
345 if (element.supertype != null) {
346 ast.Supertype supertype = scope.buildSupertype(element.supertype);
347 bool useSharedMixin = true;
348 for (var mixin in mixins) {
349 var mixinType = scope.buildSupertype(mixin);
350 if (useSharedMixin &&
351 areDistinctUnboundTypeVariables(supertype, mixinType)) {
352 // Use a shared mixin application class for this library.
353 var mixinClass = getSharedMixinApplicationClass(
354 scope.currentLibrary, supertype.classNode, mixinType.classNode);
355 if (mixinClass.fileOffset < 0) {
356 mixinClass.fileOffset = element.nameOffset;
357 }
358 supertype = new ast.Supertype(
359 mixinClass,
360 supertype.typeArguments.length > mixinType.typeArguments.length
361 ? supertype.typeArguments
362 : mixinType.typeArguments);
363 } else {
364 // Generate a new class specific for this mixin application.
365 var freshParameters =
366 getFreshTypeParameters(classNode.typeParameters);
367 var mixinClass = new ast.Class(
368 name: '${classNode.name}^${mixinType.classNode.name}',
369 isAbstract: true,
370 typeParameters: freshParameters.freshTypeParameters,
371 supertype: freshParameters.substituteSuper(supertype),
372 mixedInType: freshParameters.substituteSuper(mixinType),
373 fileUri: classNode.fileUri)..fileOffset = element.nameOffset;
374 mixinClass.level = ast.ClassLevel.Type;
375 addMixinClassToLibrary(mixinClass, classNode.enclosingLibrary);
376 supertype = new ast.Supertype(mixinClass,
377 classNode.typeParameters.map(makeTypeParameterType).toList());
378 // This class cannot be used from anywhere else, so don't try to
379 // generate shared mixin applications using it.
380 useSharedMixin = false;
381 }
382 }
383 classNode.supertype = supertype;
384 for (var implementedType in element.interfaces) {
385 classNode.implementedTypes.add(scope.buildSupertype(implementedType));
386 }
387 }
388 }
389
390 void promoteToHierarchyLevel(ast.Class classNode) {
391 if (classNode.level.index >= ast.ClassLevel.Hierarchy.index) return;
392 promoteToTypeLevel(classNode);
393 classNode.level = ast.ClassLevel.Hierarchy;
394 var element = getClassElement(classNode);
395 if (element != null) {
396 // Ensure all instance members are at present.
397 for (var field in element.fields) {
398 if (!field.isStatic && !field.isSynthetic) {
399 getMemberReference(field);
400 }
401 }
402 for (var accessor in element.accessors) {
403 if (!accessor.isStatic && !accessor.isSynthetic) {
404 getMemberReference(accessor);
405 }
406 }
407 for (var method in element.methods) {
408 if (!method.isStatic && !method.isSynthetic) {
409 getMemberReference(method);
410 }
411 }
412 }
413 for (var supertype in classNode.supers) {
414 promoteToHierarchyLevel(supertype.classNode);
415 }
416 }
417
418 void promoteToMixinLevel(ast.Class classNode, ClassElement element,
419 NamedCompilationUnitMember astNode) {
420 if (classNode.level.index >= ast.ClassLevel.Mixin.index) return;
421 _classBeingPromotedToMixin = element;
422 promoteToHierarchyLevel(classNode);
423 classNode.level = ast.ClassLevel.Mixin;
424 // Clear out the member references that were put in the class.
425 // The AST builder will load them all put back in the right order.
426 classNode..fields.clear()..procedures.clear()..constructors.clear();
427 new ClassBodyBuilder(this, classNode, element).build(astNode);
428 _classBeingPromotedToMixin = null;
429
430 // Ensure mixed-in classes are available.
431 for (var mixin in element.mixins) {
432 _ensureMixinBecomesLoaded(mixin.element);
433 }
434 }
435
436 /// Ensures that [element] eventually becomes loaded at least at mixin level.
437 void _ensureMixinBecomesLoaded(ClassElement element) {
438 if (isClassBeingPromotedToMixin(element)) {
439 return;
440 }
441 var class_ = getClassReference(element);
442 if (class_.level.index >= ast.ClassLevel.Mixin.index) {
443 return;
444 }
445 var list = mixinLibraryWorklist[element.library] ??= <ClassElement>[];
446 list.add(element);
447 }
448
449 void promoteToBodyLevel(ast.Class classNode, ClassElement element,
450 NamedCompilationUnitMember astNode) {
451 if (classNode.level == ast.ClassLevel.Body) return;
452 promoteToMixinLevel(classNode, element, astNode);
453 classNode.level = ast.ClassLevel.Body;
454 // This frontend delivers the same contents for classes at body and mixin
455 // levels, even though as specified, the mixin level does not require all
456 // the static members to be present. So no additional work is needed.
457 }
458
459 ast.TypeParameter tryGetClassTypeParameter(TypeParameterElement element) {
460 return _classTypeParameters[element];
461 }
462
463 Element getMemberElement(ast.Member node) {
464 return _members.inverse[node];
465 }
466
467 ast.Member getMemberReference(Element element) {
468 assert(element != null);
469 assert(element is! Member); // Use the "base element".
470 return _members[element] ??= _buildMemberReference(element);
471 }
472
473 ast.Member _buildMemberReference(Element element) {
474 assert(element != null);
475 var member = _buildOrphanedMemberReference(element);
476 // Set the parent pointer and store it in the enclosing class or library.
477 // If the enclosing library is being built from the AST, do not add the
478 // member, since the AST builder will put it in there.
479 var parent = element.enclosingElement;
480 if (parent is ClassElement) {
481 var class_ = getClassReference(parent);
482 member.parent = class_;
483 if (!isLibraryBeingLoaded(element.library)) {
484 class_.addMember(member);
485 }
486 } else {
487 var library = getLibraryReference(element.library);
488 member.parent = library;
489 if (!isLibraryBeingLoaded(element.library)) {
490 library.addMember(member);
491 }
492 }
493 return member;
494 }
495
496 ast.Member _buildOrphanedMemberReference(Element element) {
497 assert(element != null);
498 ClassElement classElement = element.enclosingElement is ClassElement
499 ? element.enclosingElement
500 : null;
501 TypeScope scope = classElement != null
502 ? new ClassScope(this, getLibraryReference(element.library))
503 : new TypeScope(this);
504 if (classElement != null) {
505 getClassReference(classElement);
506 }
507 switch (element.kind) {
508 case ElementKind.CONSTRUCTOR:
509 ConstructorElement constructor = element;
510 if (constructor.isFactory) {
511 return new ast.Procedure(
512 _nameOfMember(constructor),
513 ast.ProcedureKind.Factory,
514 scope.buildFunctionInterface(constructor),
515 isAbstract: false,
516 isStatic: true,
517 isExternal: constructor.isExternal,
518 isConst: constructor.isConst,
519 fileUri: '${element.source.uri}')
520 ..fileOffset = element.nameOffset;
521 }
522 return new ast.Constructor(scope.buildFunctionInterface(constructor),
523 name: _nameOfMember(element),
524 isConst: constructor.isConst,
525 isExternal: constructor.isExternal)
526 ..fileOffset = element.nameOffset;
527
528 case ElementKind.FIELD:
529 case ElementKind.TOP_LEVEL_VARIABLE:
530 VariableElement variable = element;
531 return new ast.Field(_nameOfMember(variable),
532 isStatic: variable.isStatic,
533 isFinal: variable.isFinal,
534 isConst: variable.isConst,
535 type: scope.buildType(variable.type),
536 fileUri: '${element.source.uri}')..fileOffset = element.nameOffset;
537
538 case ElementKind.METHOD:
539 case ElementKind.GETTER:
540 case ElementKind.SETTER:
541 case ElementKind.FUNCTION:
542 if (element is FunctionElement &&
543 element.enclosingElement is! CompilationUnitElement) {
544 throw 'Function $element is nested in ${element.enclosingElement} '
545 'and hence is not a member';
546 }
547 ExecutableElement executable = element;
548 return new ast.Procedure(
549 _nameOfMember(element),
550 _procedureKindOf(executable),
551 scope.buildFunctionInterface(executable),
552 isAbstract: executable.isAbstract,
553 isStatic: executable.isStatic,
554 isExternal: executable.isExternal,
555 fileUri: '${element.source.uri}')..fileOffset = element.nameOffset;
556
557 default:
558 throw 'Unexpected member kind: $element';
559 }
560 }
561
562 ast.ProcedureKind _procedureKindOf(ExecutableElement element) {
563 if (element is PropertyAccessorElement) {
564 return element.isGetter
565 ? ast.ProcedureKind.Getter
566 : ast.ProcedureKind.Setter;
567 }
568 if (element is MethodElement) {
569 if (element.isOperator) return ast.ProcedureKind.Operator;
570 return ast.ProcedureKind.Method;
571 }
572 if (element is FunctionElement) {
573 return ast.ProcedureKind.Method;
574 }
575 if (element is ConstructorElement) {
576 assert(element.isFactory);
577 return ast.ProcedureKind.Factory;
578 }
579 throw 'Unexpected procedure: $element';
580 }
581
582 ast.Name _nameOfMember(Element element) {
583 // Use 'displayName' to avoid a trailing '=' for setters and 'name' to
584 // ensure unary minus is called 'unary-'.
585 String name =
586 element is PropertyAccessorElement ? element.displayName : element.name;
587 return new ast.Name(name, getLibraryReference(element.library));
588 }
589
590 /// True if the two types have form `C<T1 ... Tm>` and `D<T1 ... Tn>`, and
591 /// `T1 ... TN` are distinct type variables with no upper bound, where
592 /// `N = max(m,n)`.
593 bool areDistinctUnboundTypeVariables(
594 ast.Supertype first, ast.Supertype second) {
595 var seen = new Set<ast.TypeParameter>();
596 if (first.typeArguments.length < second.typeArguments.length) {
597 var tmp = first;
598 first = second;
599 second = tmp;
600 }
601 for (int i = 0; i < first.typeArguments.length; ++i) {
602 var firstArg = first.typeArguments[i];
603 if (!(firstArg is ast.TypeParameterType &&
604 seen.add(firstArg.parameter) &&
605 firstArg.parameter.bound is ast.DynamicType)) {
606 return false;
607 }
608 if (i < second.typeArguments.length &&
609 firstArg != second.typeArguments[i]) {
610 return false;
611 }
612 }
613 return true;
614 }
615
616 /// Returns the canonical mixin application of two classes, instantiated with
617 /// the same list of unbound type variables.
618 ///
619 /// Given two classes:
620 /// class C<C1 ... Cm>
621 /// class D<D1 ... Dn>
622 ///
623 /// This creates or reuses a mixin application class in the library of form:
624 ///
625 /// abstract class C&D<T1 ... TN> = C<T1 ... Tm> with D<T1 ... Tn>
626 ///
627 /// where `N = max(m,n)`.
628 ///
629 /// Such a class can in general contain type errors due to incompatible
630 /// inheritance from `C` and `D`. This method therefore should only be called
631 /// if a mixin application `C<S1 ... Sm> with D<S1 ... Sn>` is seen, where
632 /// `S1 ... SN` are distinct, unbound type variables.
633 ast.Class getSharedMixinApplicationClass(
634 ast.Library library, ast.Class superclass, ast.Class mixedInClass) {
635 // TODO(asgerf): Avoid potential name clash due to associativity.
636 // As it is, these mixins get the same name:
637 // (A with B) with C
638 // A with (B with C)
639 String name = '${superclass.name}&${mixedInClass.name}';
640 return _mixinApplications
641 .putIfAbsent(library, () => <String, ast.Class>{})
642 .putIfAbsent(name, () {
643 var fresh =
644 superclass.typeParameters.length >= mixedInClass.typeParameters.length
645 ? getFreshTypeParameters(superclass.typeParameters)
646 : getFreshTypeParameters(mixedInClass.typeParameters);
647 var typeArguments =
648 fresh.freshTypeParameters.map(makeTypeParameterType).toList();
649 var superArgs = typeArguments.length != superclass.typeParameters.length
650 ? typeArguments.sublist(0, superclass.typeParameters.length)
651 : typeArguments;
652 var mixinArgs = typeArguments.length != mixedInClass.typeParameters.length
653 ? typeArguments.sublist(0, mixedInClass.typeParameters.length)
654 : typeArguments;
655 var result = new ast.Class(
656 name: name,
657 isAbstract: true,
658 typeParameters: fresh.freshTypeParameters,
659 supertype: new ast.Supertype(superclass, superArgs),
660 mixedInType: new ast.Supertype(mixedInClass, mixinArgs),
661 fileUri: library.fileUri);
662 result.level = ast.ClassLevel.Type;
663 library.addClass(result);
664 return result;
665 });
666 }
667
668 String formatErrorMessage(
669 AnalysisError error, String filename, LineInfo lines) {
670 var location = lines.getLocation(error.offset);
671 return '[error] ${error.message} ($filename, '
672 'line ${location.lineNumber}, '
673 'col ${location.columnNumber})';
674 }
675
676 void ensureLibraryIsLoaded(ast.Library node) {
677 _ensureLibraryIsLoaded(node);
678 _iterateMixinLibraryWorklist();
679 }
680
681 void _ensureLibraryIsLoaded(ast.Library node) {
682 if (!node.isExternal) return;
683 node.isExternal = false;
684 var source = context.sourceFactory
685 .forUri2(applicationRoot.absoluteUri(node.importUri));
686 assert(source != null);
687 var element = context.computeLibraryElement(source);
688 var units = <CompilationUnit>[];
689 bool reportErrors = node.importUri.scheme != 'dart';
690 var tree = context.resolveCompilationUnit(source, element);
691 units.add(tree);
692 if (reportErrors) _processErrors(source);
693 for (var part in element.parts) {
694 var source = part.source;
695 units.add(context.resolveCompilationUnit(source, element));
696 if (reportErrors) _processErrors(source);
697 }
698 _buildLibraryBody(element, node, units);
699 }
700
701 void _processErrors(Source source) {
702 LineInfo lines;
703 for (var error in context.computeErrors(source)) {
704 if (error.errorCode is CompileTimeErrorCode ||
705 error.errorCode is ParserErrorCode ||
706 error.errorCode is ScannerErrorCode ||
707 error.errorCode is StrongModeCode) {
708 lines ??= context.computeLineInfo(source);
709 errors.add(formatErrorMessage(error, source.shortName, lines));
710 }
711 }
712 }
713
714 void loadSdkInterface(ast.Program program, Target target) {
715 var requiredSdkMembers = target.requiredSdkClasses;
716 for (var libraryUri in requiredSdkMembers.keys) {
717 var source = context.sourceFactory.forUri2(Uri.parse(libraryUri));
718 var libraryElement = context.computeLibraryElement(source);
719 for (var member in requiredSdkMembers[libraryUri]) {
720 var type = libraryElement.getType(member);
721 if (type == null) {
722 throw 'Could not find $member in $libraryUri';
723 }
724 promoteToTypeLevel(getClassReference(type));
725 }
726 }
727 _iterateTemporaryClassWorklist();
728 _iterateMixinLibraryWorklist();
729 }
730
731 void loadEverything({Target target, bool compileSdk}) {
732 compileSdk ??= true;
733 if (compileSdk) {
734 ensureLibraryIsLoaded(getLibraryReference(getDartCoreLibrary()));
735 if (target != null) {
736 for (var uri in target.extraRequiredLibraries) {
737 var library = _findLibraryElement(uri);
738 if (library == null) {
739 errors.add('Could not find required library $uri');
740 continue;
741 }
742 ensureLibraryIsLoaded(getLibraryReference(library));
743 }
744 }
745 }
746 for (int i = 0; i < program.libraries.length; ++i) {
747 var library = program.libraries[i];
748 if (compileSdk || library.importUri.scheme != 'dart') {
749 ensureLibraryIsLoaded(library);
750 }
751 }
752 }
753
754 /// Builds a list of sources that have been loaded.
755 ///
756 /// This operation may be expensive and should only be used for diagnostics.
757 List<String> getLoadedFileNames() {
758 var list = <String>[];
759 for (var library in program.libraries) {
760 LibraryElement element = context.computeLibraryElement(context
761 .sourceFactory
762 .forUri2(applicationRoot.absoluteUri(library.importUri)));
763 for (var unit in element.units) {
764 list.add(unit.source.fullName);
765 }
766 }
767 return list;
768 }
769
770 void _iterateTemporaryClassWorklist() {
771 while (temporaryClassWorklist.isNotEmpty) {
772 var element = temporaryClassWorklist.removeLast();
773 promoteToTypeLevel(element);
774 }
775 }
776
777 void _iterateMixinLibraryWorklist() {
778 // The worklist groups classes in the same library together so that we
779 // request resolved ASTs for each library only once.
780 while (mixinLibraryWorklist.isNotEmpty) {
781 LibraryElement library = mixinLibraryWorklist.keys.first;
782 _libraryBeingLoaded = library;
783 List<ClassElement> classes = mixinLibraryWorklist.remove(library);
784 for (var class_ in classes) {
785 var classNode = getClassReference(class_);
786 promoteToMixinLevel(classNode, class_, class_.computeNode());
787 }
788 _libraryBeingLoaded = null;
789 }
790 _iterateTemporaryClassWorklist();
791 }
792
793 ast.Procedure _getMainMethod(Uri uri) {
794 Source source = context.sourceFactory.forUri2(uri);
795 LibraryElement library = context.computeLibraryElement(source);
796 var mainElement = library.entryPoint;
797 if (mainElement == null) return null;
798 var mainMember = getMemberReference(mainElement);
799 if (mainMember is ast.Procedure && !mainMember.isAccessor) {
800 return mainMember;
801 }
802 // Top-level 'main' getters are not supported at the moment.
803 return null;
804 }
805
806 ast.Procedure _makeMissingMainMethod(ast.Library library) {
807 var main = new ast.Procedure(
808 new ast.Name('main'),
809 ast.ProcedureKind.Method,
810 new ast.FunctionNode(new ast.ExpressionStatement(new ast.Throw(
811 new ast.StringLiteral('Program has no main method')))),
812 isStatic: true)..fileUri = library.fileUri;
813 library.addMember(main);
814 return main;
815 }
816
817 void loadProgram(Uri mainLibrary, {Target target, bool compileSdk}) {
818 ast.Library library = getLibraryReferenceFromUri(mainLibrary);
819 ensureLibraryIsLoaded(library);
820 var mainMethod = _getMainMethod(mainLibrary);
821 loadEverything(target: target, compileSdk: compileSdk);
822 if (mainMethod == null) {
823 mainMethod = _makeMissingMainMethod(library);
824 }
825 program.mainMethod = mainMethod;
826 for (LibraryElement libraryElement in libraryElements) {
827 for (CompilationUnitElement compilationUnitElement
828 in libraryElement.units) {
829 var source = compilationUnitElement.source;
830 LineInfo lineInfo = context.computeLineInfo(source);
831 List<int> sourceCode;
832 try {
833 sourceCode =
834 const Utf8Encoder().convert(context.getContents(source).data);
835 } catch (e) {
836 // The source's contents could not be accessed.
837 sourceCode = const <int>[];
838 }
839 program.uriToSource['${source.uri}'] =
840 new ast.Source(lineInfo.lineStarts, sourceCode);
841 }
842 }
843 }
844
845 ast.Library loadLibrary(Uri uri) {
846 ast.Library library = getLibraryReferenceFromUri(uri);
847 ensureLibraryIsLoaded(library);
848 return library;
849 }
850 }
851
852 class Bimap<K, V> {
853 final Map<K, V> nodeMap = <K, V>{};
854 final Map<V, K> inverse = <V, K>{};
855
856 bool containsKey(K key) => nodeMap.containsKey(key);
857
858 V operator [](K key) => nodeMap[key];
859
860 void operator []=(K key, V value) {
861 assert(!nodeMap.containsKey(key));
862 nodeMap[key] = value;
863 inverse[value] = key;
864 }
865 }
866
867 /// Creates [DartLoader]s for a given configuration, while reusing the
868 /// [DartSdk] and [Packages] object if possible.
869 class DartLoaderBatch {
870 Packages packages;
871 DartSdk dartSdk;
872
873 String lastSdk;
874 String lastPackagePath;
875 bool lastStrongMode;
876
877 Future<DartLoader> getLoader(ast.Program program, DartOptions options,
878 {String packageDiscoveryPath}) async {
879 if (dartSdk == null ||
880 lastSdk != options.sdk ||
881 lastStrongMode != options.strongMode) {
882 lastSdk = options.sdk;
883 lastStrongMode = options.strongMode;
884 dartSdk = createDartSdk(options.sdk, strongMode: options.strongModeSdk);
885 }
886 if (packages == null ||
887 lastPackagePath != options.packagePath ||
888 packageDiscoveryPath != null) {
889 lastPackagePath = options.packagePath;
890 packages = await createPackages(options.packagePath,
891 discoveryPath: packageDiscoveryPath);
892 }
893 return new DartLoader(program, options, packages, dartSdk: dartSdk);
894 }
895 }
896
897 Future<Packages> createPackages(String packagePath,
898 {String discoveryPath}) async {
899 if (packagePath != null) {
900 var absolutePath = new io.File(packagePath).absolute.path;
901 if (await new io.Directory(packagePath).exists()) {
902 return getPackagesDirectory(new Uri.file(absolutePath));
903 } else if (await new io.File(packagePath).exists()) {
904 return loadPackagesFile(new Uri.file(absolutePath));
905 } else {
906 throw 'Packages not found: $packagePath';
907 }
908 }
909 if (discoveryPath != null) {
910 return findPackagesFromFile(Uri.parse(discoveryPath));
911 }
912 return Packages.noPackages;
913 }
914
915 AnalysisOptions createAnalysisOptions(bool strongMode) {
916 return new AnalysisOptionsImpl()
917 ..strongMode = strongMode
918 ..generateImplicitErrors = false
919 ..generateSdkErrors = false
920 ..preserveComments = false
921 ..hint = false
922 ..enableSuperMixins = true;
923 }
924
925 DartSdk createDartSdk(String path, {bool strongMode, bool isSummary}) {
926 if (isSummary ?? false) {
927 return new SummaryBasedDartSdk(path, strongMode);
928 }
929 var resources = PhysicalResourceProvider.INSTANCE;
930 return new FolderBasedDartSdk(resources, resources.getFolder(path))
931 ..context
932 .analysisOptions
933 .setCrossContextOptionsFrom(createAnalysisOptions(strongMode));
934 }
935
936 class CustomUriResolver extends UriResolver {
937 final ResourceUriResolver _resourceUriResolver;
938 final Map<Uri, Uri> _customUrlMappings;
939
940 CustomUriResolver(this._resourceUriResolver, this._customUrlMappings);
941
942 Source resolveAbsolute(Uri uri, [Uri actualUri]) {
943 // TODO(kustermann): Once dartk supports configurable imports we should be
944 // able to get rid of this.
945 if (uri.toString() == 'package:mojo/src/internal_contract.dart') {
946 uri = actualUri = Uri.parse('dart:mojo.internal');
947 }
948
949 Uri baseUri = uri;
950 String relative;
951 String path = uri.path;
952 int index = path.indexOf('/');
953 if (index > 0) {
954 baseUri = uri.replace(path: path.substring(0, index));
955 relative = path.substring(index + 1);
956 }
957 Uri baseMapped = _customUrlMappings[baseUri];
958 if (baseMapped == null) return null;
959
960 Uri mapped = relative != null ? baseMapped.resolve(relative) : baseMapped;
961 return _resourceUriResolver.resolveAbsolute(mapped, actualUri);
962 }
963
964 Uri restoreAbsolute(Source source) {
965 return _resourceUriResolver.restoreAbsolute(source);
966 }
967 }
968
969 AnalysisContext createContext(DartOptions options, Packages packages,
970 {DartSdk dartSdk}) {
971 bool fromSummary = options.sdkSummary != null;
972 dartSdk ??= createDartSdk(fromSummary ? options.sdkSummary : options.sdk,
973 strongMode: options.strongModeSdk, isSummary: fromSummary);
974
975 var resourceProvider = PhysicalResourceProvider.INSTANCE;
976 var resourceUriResolver = new ResourceUriResolver(resourceProvider);
977 List<UriResolver> resolvers = [];
978 var customUriMappings = options.customUriMappings;
979 if (customUriMappings != null && customUriMappings.length > 0) {
980 resolvers
981 .add(new CustomUriResolver(resourceUriResolver, customUriMappings));
982 }
983 resolvers.add(new DartUriResolver(dartSdk));
984 resolvers.add(resourceUriResolver);
985
986 if (packages != null) {
987 var folderMap = <String, List<Folder>>{};
988 packages.asMap().forEach((String packagePath, Uri uri) {
989 String path = resourceProvider.pathContext.fromUri(uri);
990 folderMap[packagePath] = [resourceProvider.getFolder(path)];
991 });
992 resolvers.add(new PackageMapUriResolver(resourceProvider, folderMap));
993 }
994
995 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext()
996 ..sourceFactory = new SourceFactory(resolvers)
997 ..analysisOptions = createAnalysisOptions(options.strongMode);
998
999 options.declaredVariables.forEach((String name, String value) {
1000 context.declaredVariables.define(name, value);
1001 });
1002
1003 return context;
1004 }
OLDNEW
« no previous file with comments | « pkg/kernel/lib/analyzer/ast_from_analyzer.dart ('k') | pkg/kernel/test/baseline_tester.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698