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

Side by Side Diff: packages/analyzer/lib/src/dart/resolver/scope.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer.src.dart.resolver.scope;
6
7 import 'dart:collection';
8
9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/element/element.dart';
11 import 'package:analyzer/error/error.dart';
12 import 'package:analyzer/src/dart/element/element.dart';
13 import 'package:analyzer/src/error/codes.dart';
14 import 'package:analyzer/src/generated/engine.dart';
15 import 'package:analyzer/src/generated/java_engine.dart';
16 import 'package:analyzer/src/generated/source.dart';
17
18 /**
19 * The scope defined by a block.
20 */
21 class BlockScope extends EnclosedScope {
22 /**
23 * Initialize a newly created scope, enclosed within the [enclosingScope],
24 * based on the given [block].
25 */
26 BlockScope(Scope enclosingScope, Block block) : super(enclosingScope) {
27 if (block == null) {
28 throw new ArgumentError("block cannot be null");
29 }
30 _defineElements(block);
31 }
32
33 void _defineElements(Block block) {
34 for (Element element in elementsInBlock(block)) {
35 define(element);
36 }
37 }
38
39 /**
40 * Return the elements that are declared directly in the given [block]. This
41 * does not include elements declared in nested blocks.
42 */
43 static Iterable<Element> elementsInBlock(Block block) sync* {
44 NodeList<Statement> statements = block.statements;
45 int statementCount = statements.length;
46 for (int i = 0; i < statementCount; i++) {
47 Statement statement = statements[i];
48 if (statement is VariableDeclarationStatement) {
49 NodeList<VariableDeclaration> variables = statement.variables.variables;
50 int variableCount = variables.length;
51 for (int j = 0; j < variableCount; j++) {
52 yield variables[j].element;
53 }
54 } else if (statement is FunctionDeclarationStatement) {
55 yield statement.functionDeclaration.element;
56 }
57 }
58 }
59 }
60
61 /**
62 * The scope defined by a class.
63 */
64 class ClassScope extends EnclosedScope {
65 /**
66 * Initialize a newly created scope, enclosed within the [enclosingScope],
67 * based on the given [classElement].
68 */
69 ClassScope(Scope enclosingScope, ClassElement classElement)
70 : super(enclosingScope) {
71 if (classElement == null) {
72 throw new ArgumentError("class element cannot be null");
73 }
74 _defineMembers(classElement);
75 }
76
77 @override
78 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
79 if (existing is PropertyAccessorElement && duplicate is MethodElement) {
80 if (existing.nameOffset < duplicate.nameOffset) {
81 return new AnalysisError(
82 duplicate.source,
83 duplicate.nameOffset,
84 duplicate.nameLength,
85 CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME,
86 [existing.displayName]);
87 } else {
88 return new AnalysisError(
89 existing.source,
90 existing.nameOffset,
91 existing.nameLength,
92 CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
93 [existing.displayName]);
94 }
95 }
96 return super.getErrorForDuplicate(existing, duplicate);
97 }
98
99 /**
100 * Define the instance members defined by the given [classElement].
101 */
102 void _defineMembers(ClassElement classElement) {
103 List<PropertyAccessorElement> accessors = classElement.accessors;
104 int accessorLength = accessors.length;
105 for (int i = 0; i < accessorLength; i++) {
106 define(accessors[i]);
107 }
108 List<MethodElement> methods = classElement.methods;
109 int methodLength = methods.length;
110 for (int i = 0; i < methodLength; i++) {
111 define(methods[i]);
112 }
113 }
114 }
115
116 /**
117 * The scope defined for the initializers in a constructor.
118 */
119 class ConstructorInitializerScope extends EnclosedScope {
120 /**
121 * Initialize a newly created scope, enclosed within the [enclosingScope].
122 */
123 ConstructorInitializerScope(Scope enclosingScope, ConstructorElement element)
124 : super(enclosingScope) {
125 _initializeFieldFormalParameters(element);
126 }
127
128 /**
129 * Initialize the local scope with all of the field formal parameters.
130 */
131 void _initializeFieldFormalParameters(ConstructorElement element) {
132 for (ParameterElement parameter in element.parameters) {
133 if (parameter is FieldFormalParameterElement) {
134 define(parameter);
135 }
136 }
137 }
138 }
139
140 /**
141 * A scope that is lexically enclosed in another scope.
142 */
143 class EnclosedScope extends Scope {
144 /**
145 * The scope in which this scope is lexically enclosed.
146 */
147 @override
148 final Scope enclosingScope;
149
150 /**
151 * Initialize a newly created scope, enclosed within the [enclosingScope].
152 */
153 EnclosedScope(this.enclosingScope);
154
155 @override
156 Element internalLookup(
157 Identifier identifier, String name, LibraryElement referencingLibrary) {
158 Element element = localLookup(name, referencingLibrary);
159 if (element != null) {
160 return element;
161 }
162 // Check enclosing scope.
163 return enclosingScope.internalLookup(identifier, name, referencingLibrary);
164 }
165
166 @override
167 Element _internalLookupPrefixed(PrefixedIdentifier identifier, String prefix,
168 String name, LibraryElement referencingLibrary) {
169 return enclosingScope._internalLookupPrefixed(
170 identifier, prefix, name, referencingLibrary);
171 }
172 }
173
174 /**
175 * The scope defined by a function.
176 */
177 class FunctionScope extends EnclosedScope {
178 /**
179 * The element representing the function that defines this scope.
180 */
181 final ExecutableElement _functionElement;
182
183 /**
184 * A flag indicating whether the parameters have already been defined, used to
185 * prevent the parameters from being defined multiple times.
186 */
187 bool _parametersDefined = false;
188
189 /**
190 * Initialize a newly created scope, enclosed within the [enclosingScope],
191 * that represents the given [_functionElement].
192 */
193 FunctionScope(Scope enclosingScope, this._functionElement)
194 : super(new EnclosedScope(new EnclosedScope(enclosingScope))) {
195 if (_functionElement == null) {
196 throw new ArgumentError("function element cannot be null");
197 }
198 _defineTypeParameters();
199 }
200
201 /**
202 * Define the parameters for the given function in the scope that encloses
203 * this function.
204 */
205 void defineParameters() {
206 if (_parametersDefined) {
207 return;
208 }
209 _parametersDefined = true;
210 Scope parameterScope = enclosingScope;
211 List<ParameterElement> parameters = _functionElement.parameters;
212 int length = parameters.length;
213 for (int i = 0; i < length; i++) {
214 ParameterElement parameter = parameters[i];
215 if (!parameter.isInitializingFormal) {
216 parameterScope.define(parameter);
217 }
218 }
219 }
220
221 /**
222 * Define the type parameters for the function.
223 */
224 void _defineTypeParameters() {
225 Scope typeParameterScope = enclosingScope.enclosingScope;
226 List<TypeParameterElement> typeParameters = _functionElement.typeParameters;
227 int length = typeParameters.length;
228 for (int i = 0; i < length; i++) {
229 TypeParameterElement typeParameter = typeParameters[i];
230 typeParameterScope.define(typeParameter);
231 }
232 }
233 }
234
235 /**
236 * The scope defined by a function type alias.
237 */
238 class FunctionTypeScope extends EnclosedScope {
239 final FunctionTypeAliasElement _typeElement;
240
241 bool _parametersDefined = false;
242
243 /**
244 * Initialize a newly created scope, enclosed within the [enclosingScope],
245 * that represents the given [_typeElement].
246 */
247 FunctionTypeScope(Scope enclosingScope, this._typeElement)
248 : super(new EnclosedScope(enclosingScope)) {
249 _defineTypeParameters();
250 }
251
252 /**
253 * Define the parameters for the function type alias.
254 */
255 void defineParameters() {
256 if (_parametersDefined) {
257 return;
258 }
259 _parametersDefined = true;
260 for (ParameterElement parameter in _typeElement.parameters) {
261 define(parameter);
262 }
263 }
264
265 /**
266 * Define the type parameters for the function type alias.
267 */
268 void _defineTypeParameters() {
269 Scope typeParameterScope = enclosingScope;
270 for (TypeParameterElement typeParameter in _typeElement.typeParameters) {
271 typeParameterScope.define(typeParameter);
272 }
273 }
274 }
275
276 /**
277 * The scope statements that can be the target of unlabeled `break` and
278 * `continue` statements.
279 */
280 class ImplicitLabelScope {
281 /**
282 * The implicit label scope associated with the top level of a function.
283 */
284 static const ImplicitLabelScope ROOT = const ImplicitLabelScope._(null, null);
285
286 /**
287 * The implicit label scope enclosing this implicit label scope.
288 */
289 final ImplicitLabelScope outerScope;
290
291 /**
292 * The statement that acts as a target for break and/or continue statements
293 * at this scoping level.
294 */
295 final Statement statement;
296
297 /**
298 * Initialize a newly created scope, enclosed within the [outerScope],
299 * representing the given [statement].
300 */
301 const ImplicitLabelScope._(this.outerScope, this.statement);
302
303 /**
304 * Return the statement which should be the target of an unlabeled `break` or
305 * `continue` statement, or `null` if there is no appropriate target.
306 */
307 Statement getTarget(bool isContinue) {
308 if (outerScope == null) {
309 // This scope represents the toplevel of a function body, so it doesn't
310 // match either break or continue.
311 return null;
312 }
313 if (isContinue && statement is SwitchStatement) {
314 return outerScope.getTarget(isContinue);
315 }
316 return statement;
317 }
318
319 /**
320 * Initialize a newly created scope to represent a switch statement or loop
321 * nested within the current scope. [statement] is the statement associated
322 * with the newly created scope.
323 */
324 ImplicitLabelScope nest(Statement statement) =>
325 new ImplicitLabelScope._(this, statement);
326 }
327
328 /**
329 * A scope in which a single label is defined.
330 */
331 class LabelScope {
332 /**
333 * The label scope enclosing this label scope.
334 */
335 final LabelScope _outerScope;
336
337 /**
338 * The label defined in this scope.
339 */
340 final String _label;
341
342 /**
343 * The element to which the label resolves.
344 */
345 final LabelElement element;
346
347 /**
348 * The AST node to which the label resolves.
349 */
350 final AstNode node;
351
352 /**
353 * Initialize a newly created scope, enclosed within the [_outerScope],
354 * representing the label [_label]. The [node] is the AST node the label
355 * resolves to. The [element] is the element the label resolves to.
356 */
357 LabelScope(this._outerScope, this._label, this.node, this.element);
358
359 /**
360 * Return the LabelScope which defines [targetLabel], or `null` if it is not
361 * defined in this scope.
362 */
363 LabelScope lookup(String targetLabel) {
364 if (_label == targetLabel) {
365 return this;
366 }
367 return _outerScope?.lookup(targetLabel);
368 }
369 }
370
371 /**
372 * The scope containing all of the names available from imported libraries.
373 */
374 class LibraryImportScope extends Scope {
375 /**
376 * The name of the property containing a list of the elements from the SDK
377 * that conflict with the single name imported from non-SDK libraries. The
378 * value of the property is always of type `List<Element>`.
379 */
380 static const String conflictingSdkElements = 'conflictingSdkElements';
381
382 /**
383 * The element representing the library in which this scope is enclosed.
384 */
385 final LibraryElement _definingLibrary;
386
387 /**
388 * A list of the namespaces representing the names that are available in this scope from imported
389 * libraries.
390 */
391 List<Namespace> _importedNamespaces;
392
393 /**
394 * A table mapping prefixes that have been referenced to a map from the names
395 * that have been referenced to the element associated with the prefixed name.
396 */
397 Map<String, Map<String, Element>> _definedPrefixedNames;
398
399 /**
400 * Initialize a newly created scope representing the names imported into the
401 * [_definingLibrary].
402 */
403 LibraryImportScope(this._definingLibrary) {
404 _createImportedNamespaces();
405 }
406
407 @override
408 void define(Element element) {
409 if (!Scope.isPrivateName(element.displayName)) {
410 super.define(element);
411 }
412 }
413
414 @override
415 Source getSource(AstNode node) {
416 Source source = super.getSource(node);
417 if (source == null) {
418 source = _definingLibrary.definingCompilationUnit.source;
419 }
420 return source;
421 }
422
423 @override
424 Element internalLookup(
425 Identifier identifier, String name, LibraryElement referencingLibrary) {
426 Element element = localLookup(name, referencingLibrary);
427 if (element != null) {
428 return element;
429 }
430 element = _lookupInImportedNamespaces(
431 identifier, (Namespace namespace) => namespace.get(name));
432 if (element != null) {
433 defineNameWithoutChecking(name, element);
434 }
435 return element;
436 }
437
438 @override
439 bool shouldIgnoreUndefined(Identifier node) {
440 Iterable<NamespaceCombinator> getShowCombinators(
441 ImportElement importElement) =>
442 importElement.combinators.where((NamespaceCombinator combinator) =>
443 combinator is ShowElementCombinator);
444 if (node is PrefixedIdentifier) {
445 String prefix = node.prefix.name;
446 String name = node.identifier.name;
447 List<ImportElement> imports = _definingLibrary.imports;
448 int count = imports.length;
449 for (int i = 0; i < count; i++) {
450 ImportElement importElement = imports[i];
451 if (importElement.prefix?.name == prefix &&
452 importElement.importedLibrary?.isSynthetic != false) {
453 Iterable<NamespaceCombinator> showCombinators =
454 getShowCombinators(importElement);
455 if (showCombinators.isEmpty) {
456 return true;
457 }
458 for (ShowElementCombinator combinator in showCombinators) {
459 if (combinator.shownNames.contains(name)) {
460 return true;
461 }
462 }
463 }
464 }
465 } else if (node is SimpleIdentifier) {
466 String name = node.name;
467 List<ImportElement> imports = _definingLibrary.imports;
468 int count = imports.length;
469 for (int i = 0; i < count; i++) {
470 ImportElement importElement = imports[i];
471 if (importElement.prefix == null &&
472 importElement.importedLibrary?.isSynthetic != false) {
473 for (ShowElementCombinator combinator
474 in getShowCombinators(importElement)) {
475 if (combinator.shownNames.contains(name)) {
476 return true;
477 }
478 }
479 }
480 }
481 }
482 return false;
483 }
484
485 /**
486 * Create all of the namespaces associated with the libraries imported into
487 * this library. The names are not added to this scope, but are stored for
488 * later reference.
489 */
490 void _createImportedNamespaces() {
491 NamespaceBuilder builder = new NamespaceBuilder();
492 List<ImportElement> imports = _definingLibrary.imports;
493 int count = imports.length;
494 _importedNamespaces = new List<Namespace>(count);
495 for (int i = 0; i < count; i++) {
496 _importedNamespaces[i] =
497 builder.createImportNamespaceForDirective(imports[i]);
498 }
499 }
500
501 /**
502 * Add the given [element] to this scope without checking for duplication or
503 * hiding.
504 */
505 void _definePrefixedNameWithoutChecking(
506 String prefix, String name, Element element) {
507 _definedPrefixedNames ??= new HashMap<String, Map<String, Element>>();
508 Map<String, Element> unprefixedNames = _definedPrefixedNames.putIfAbsent(
509 prefix, () => new HashMap<String, Element>());
510 unprefixedNames[name] = element;
511 }
512
513 @override
514 Element _internalLookupPrefixed(PrefixedIdentifier identifier, String prefix,
515 String name, LibraryElement referencingLibrary) {
516 Element element = _localPrefixedLookup(prefix, name);
517 if (element != null) {
518 return element;
519 }
520 element = _lookupInImportedNamespaces(identifier.identifier,
521 (Namespace namespace) => namespace.getPrefixed(prefix, name));
522 if (element != null) {
523 _definePrefixedNameWithoutChecking(prefix, name, element);
524 }
525 return element;
526 }
527
528 /**
529 * Return the element with which the given [prefix] and [name] are associated,
530 * or `null` if the name is not defined within this scope.
531 */
532 Element _localPrefixedLookup(String prefix, String name) {
533 if (_definedPrefixedNames != null) {
534 Map<String, Element> unprefixedNames = _definedPrefixedNames[prefix];
535 if (unprefixedNames != null) {
536 return unprefixedNames[name];
537 }
538 }
539 return null;
540 }
541
542 Element _lookupInImportedNamespaces(
543 Identifier identifier, Element lookup(Namespace namespace)) {
544 Set<Element> sdkElements = new HashSet<Element>();
545 Set<Element> nonSdkElements = new HashSet<Element>();
546 for (int i = 0; i < _importedNamespaces.length; i++) {
547 Element element = lookup(_importedNamespaces[i]);
548 if (element != null) {
549 if (element.library.isInSdk) {
550 sdkElements.add(element);
551 } else {
552 nonSdkElements.add(element);
553 }
554 }
555 }
556 int nonSdkCount = nonSdkElements.length;
557 int sdkCount = sdkElements.length;
558 if (nonSdkCount == 0) {
559 if (sdkCount == 0) {
560 return null;
561 } else if (sdkCount == 1) {
562 return sdkElements.first;
563 }
564 }
565 if (nonSdkCount == 1) {
566 if (sdkCount > 0) {
567 identifier.setProperty(
568 conflictingSdkElements, sdkElements.toList(growable: false));
569 }
570 return nonSdkElements.first;
571 }
572 return new MultiplyDefinedElementImpl(
573 _definingLibrary.context,
574 sdkElements.toList(growable: false),
575 nonSdkElements.toList(growable: false));
576 }
577 }
578
579 /**
580 * A scope containing all of the names defined in a given library.
581 */
582 class LibraryScope extends EnclosedScope {
583 /**
584 * Initialize a newly created scope representing the names defined in the
585 * [definingLibrary].
586 */
587 LibraryScope(LibraryElement definingLibrary)
588 : super(new LibraryImportScope(definingLibrary)) {
589 _defineTopLevelNames(definingLibrary);
590 }
591
592 @override
593 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
594 if (existing is PrefixElement) {
595 // TODO(scheglov) consider providing actual 'nameOffset' from the
596 // synthetic accessor
597 int offset = duplicate.nameOffset;
598 if (duplicate is PropertyAccessorElement) {
599 PropertyAccessorElement accessor = duplicate;
600 if (accessor.isSynthetic) {
601 offset = accessor.variable.nameOffset;
602 }
603 }
604 return new AnalysisError(
605 duplicate.source,
606 offset,
607 duplicate.nameLength,
608 CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
609 [existing.displayName]);
610 }
611 return super.getErrorForDuplicate(existing, duplicate);
612 }
613
614 /**
615 * Add to this scope all of the public top-level names that are defined in the
616 * given [compilationUnit].
617 */
618 void _defineLocalNames(CompilationUnitElement compilationUnit) {
619 for (PropertyAccessorElement element in compilationUnit.accessors) {
620 define(element);
621 }
622 for (ClassElement element in compilationUnit.enums) {
623 define(element);
624 }
625 for (FunctionElement element in compilationUnit.functions) {
626 define(element);
627 }
628 for (FunctionTypeAliasElement element
629 in compilationUnit.functionTypeAliases) {
630 define(element);
631 }
632 for (ClassElement element in compilationUnit.types) {
633 define(element);
634 }
635 }
636
637 /**
638 * Add to this scope all of the names that are explicitly defined in the
639 * [definingLibrary].
640 */
641 void _defineTopLevelNames(LibraryElement definingLibrary) {
642 for (PrefixElement prefix in definingLibrary.prefixes) {
643 define(prefix);
644 }
645 _defineLocalNames(definingLibrary.definingCompilationUnit);
646 for (CompilationUnitElement compilationUnit in definingLibrary.parts) {
647 _defineLocalNames(compilationUnit);
648 }
649 }
650 }
651
652 /**
653 * A mapping of identifiers to the elements represented by those identifiers.
654 * Namespaces are the building blocks for scopes.
655 */
656 class Namespace {
657 /**
658 * An empty namespace.
659 */
660 static Namespace EMPTY = new Namespace(new HashMap<String, Element>());
661
662 /**
663 * A table mapping names that are defined in this namespace to the element
664 * representing the thing declared with that name.
665 */
666 final HashMap<String, Element> _definedNames;
667
668 /**
669 * Initialize a newly created namespace to have the [_definedNames].
670 */
671 Namespace(this._definedNames);
672
673 /**
674 * Return a table containing the same mappings as those defined by this
675 * namespace.
676 */
677 Map<String, Element> get definedNames => _definedNames;
678
679 /**
680 * Return the element in this namespace that is available to the containing
681 * scope using the given name, or `null` if there is no such element.
682 */
683 Element get(String name) => _definedNames[name];
684
685 /**
686 * Return the element in this namespace whose name is the result of combining
687 * the [prefix] and the [name], separated by a period, or `null` if there is
688 * no such element.
689 */
690 Element getPrefixed(String prefix, String name) => null;
691 }
692
693 /**
694 * The builder used to build a namespace. Namespace builders are thread-safe and
695 * re-usable.
696 */
697 class NamespaceBuilder {
698 /**
699 * Create a namespace representing the export namespace of the given [element] .
700 */
701 Namespace createExportNamespaceForDirective(ExportElement element) {
702 LibraryElement exportedLibrary = element.exportedLibrary;
703 if (exportedLibrary == null) {
704 //
705 // The exported library will be null if the URI does not reference a valid
706 // library.
707 //
708 return Namespace.EMPTY;
709 }
710 HashMap<String, Element> exportedNames = _getExportMapping(exportedLibrary);
711 exportedNames = _applyCombinators(exportedNames, element.combinators);
712 return new Namespace(exportedNames);
713 }
714
715 /**
716 * Create a namespace representing the export namespace of the given [library] .
717 */
718 Namespace createExportNamespaceForLibrary(LibraryElement library) {
719 HashMap<String, Element> exportedNames = _getExportMapping(library);
720 return new Namespace(exportedNames);
721 }
722
723 /**
724 * Create a namespace representing the import namespace of the given [element] .
725 */
726 Namespace createImportNamespaceForDirective(ImportElement element) {
727 LibraryElement importedLibrary = element.importedLibrary;
728 if (importedLibrary == null) {
729 //
730 // The imported library will be null if the URI does not reference a valid
731 // library.
732 //
733 return Namespace.EMPTY;
734 }
735 HashMap<String, Element> exportedNames = _getExportMapping(importedLibrary);
736 exportedNames = _applyCombinators(exportedNames, element.combinators);
737 PrefixElement prefix = element.prefix;
738 if (prefix != null) {
739 return new PrefixedNamespace(prefix.name, exportedNames);
740 }
741 return new Namespace(exportedNames);
742 }
743
744 /**
745 * Create a namespace representing the public namespace of the given
746 * [library].
747 */
748 Namespace createPublicNamespaceForLibrary(LibraryElement library) {
749 HashMap<String, Element> definedNames = new HashMap<String, Element>();
750 _addPublicNames(definedNames, library.definingCompilationUnit);
751 for (CompilationUnitElement compilationUnit in library.parts) {
752 _addPublicNames(definedNames, compilationUnit);
753 }
754 return new Namespace(definedNames);
755 }
756
757 /**
758 * Add all of the names in the given [namespace] to the table of
759 * [definedNames].
760 */
761 void _addAllFromNamespace(
762 Map<String, Element> definedNames, Namespace namespace) {
763 if (namespace != null) {
764 definedNames.addAll(namespace.definedNames);
765 }
766 }
767
768 /**
769 * Add the given [element] to the table of [definedNames] if it has a
770 * publicly visible name.
771 */
772 void _addIfPublic(Map<String, Element> definedNames, Element element) {
773 String name = element.name;
774 if (name != null && !Scope.isPrivateName(name)) {
775 definedNames[name] = element;
776 }
777 }
778
779 /**
780 * Add to the table of [definedNames] all of the public top-level names that
781 * are defined in the given [compilationUnit].
782 * namespace
783 */
784 void _addPublicNames(Map<String, Element> definedNames,
785 CompilationUnitElement compilationUnit) {
786 for (PropertyAccessorElement element in compilationUnit.accessors) {
787 _addIfPublic(definedNames, element);
788 }
789 for (ClassElement element in compilationUnit.enums) {
790 _addIfPublic(definedNames, element);
791 }
792 for (FunctionElement element in compilationUnit.functions) {
793 _addIfPublic(definedNames, element);
794 }
795 for (FunctionTypeAliasElement element
796 in compilationUnit.functionTypeAliases) {
797 _addIfPublic(definedNames, element);
798 }
799 for (ClassElement element in compilationUnit.types) {
800 _addIfPublic(definedNames, element);
801 }
802 }
803
804 /**
805 * Apply the given [combinators] to all of the names in the given table of
806 * [definedNames].
807 */
808 HashMap<String, Element> _applyCombinators(
809 HashMap<String, Element> definedNames,
810 List<NamespaceCombinator> combinators) {
811 for (NamespaceCombinator combinator in combinators) {
812 if (combinator is HideElementCombinator) {
813 definedNames = _hide(definedNames, combinator.hiddenNames);
814 } else if (combinator is ShowElementCombinator) {
815 definedNames = _show(definedNames, combinator.shownNames);
816 } else {
817 // Internal error.
818 AnalysisEngine.instance.logger
819 .logError("Unknown type of combinator: ${combinator.runtimeType}");
820 }
821 }
822 return definedNames;
823 }
824
825 /**
826 * Create a mapping table representing the export namespace of the given
827 * [library]. The set of [visitedElements] contains the libraries that do not
828 * need to be visited when processing the export directives of the given
829 * library because all of the names defined by them will be added by another
830 * library.
831 */
832 HashMap<String, Element> _computeExportMapping(
833 LibraryElement library, HashSet<LibraryElement> visitedElements) {
834 visitedElements.add(library);
835 try {
836 HashMap<String, Element> definedNames = new HashMap<String, Element>();
837 for (ExportElement element in library.exports) {
838 LibraryElement exportedLibrary = element.exportedLibrary;
839 if (exportedLibrary != null &&
840 !visitedElements.contains(exportedLibrary)) {
841 //
842 // The exported library will be null if the URI does not reference a
843 // valid library.
844 //
845 HashMap<String, Element> exportedNames =
846 _computeExportMapping(exportedLibrary, visitedElements);
847 exportedNames = _applyCombinators(exportedNames, element.combinators);
848 definedNames.addAll(exportedNames);
849 }
850 }
851 _addAllFromNamespace(
852 definedNames,
853 (library.context as InternalAnalysisContext)
854 .getPublicNamespace(library));
855 return definedNames;
856 } finally {
857 visitedElements.remove(library);
858 }
859 }
860
861 HashMap<String, Element> _getExportMapping(LibraryElement library) {
862 if (library is LibraryElementImpl) {
863 if (library.exportNamespace != null) {
864 return library.exportNamespace.definedNames;
865 } else {
866 HashMap<String, Element> exportMapping =
867 _computeExportMapping(library, new HashSet<LibraryElement>());
868 library.exportNamespace = new Namespace(exportMapping);
869 return exportMapping;
870 }
871 }
872 return _computeExportMapping(library, new HashSet<LibraryElement>());
873 }
874
875 /**
876 * Return a new map of names which has all the names from [definedNames]
877 * with exception of [hiddenNames].
878 */
879 Map<String, Element> _hide(
880 HashMap<String, Element> definedNames, List<String> hiddenNames) {
881 HashMap<String, Element> newNames =
882 new HashMap<String, Element>.from(definedNames);
883 for (String name in hiddenNames) {
884 newNames.remove(name);
885 newNames.remove("$name=");
886 }
887 return newNames;
888 }
889
890 /**
891 * Return a new map of names which has only [shownNames] from [definedNames].
892 */
893 HashMap<String, Element> _show(
894 HashMap<String, Element> definedNames, List<String> shownNames) {
895 HashMap<String, Element> newNames = new HashMap<String, Element>();
896 for (String name in shownNames) {
897 Element element = definedNames[name];
898 if (element != null) {
899 newNames[name] = element;
900 }
901 String setterName = "$name=";
902 element = definedNames[setterName];
903 if (element != null) {
904 newNames[setterName] = element;
905 }
906 }
907 return newNames;
908 }
909 }
910
911 /**
912 * A mapping of identifiers to the elements represented by those identifiers.
913 * Namespaces are the building blocks for scopes.
914 */
915 class PrefixedNamespace implements Namespace {
916 /**
917 * The prefix that is prepended to each of the defined names.
918 */
919 final String _prefix;
920
921 /**
922 * The length of the prefix.
923 */
924 final int _length;
925
926 /**
927 * A table mapping names that are defined in this namespace to the element
928 * representing the thing declared with that name.
929 */
930 final HashMap<String, Element> _definedNames;
931
932 /**
933 * Initialize a newly created namespace to have the names resulting from
934 * prefixing each of the [_definedNames] with the given [_prefix] (and a
935 * period).
936 */
937 PrefixedNamespace(String prefix, this._definedNames)
938 : _prefix = prefix,
939 _length = prefix.length;
940
941 @override
942 Map<String, Element> get definedNames {
943 Map<String, Element> definedNames = <String, Element>{};
944 _definedNames.forEach((String name, Element element) {
945 definedNames["$_prefix.$name"] = element;
946 });
947 return definedNames;
948 }
949
950 @override
951 Element get(String name) {
952 if (name.length > _length && name.startsWith(_prefix)) {
953 if (name.codeUnitAt(_length) == '.'.codeUnitAt(0)) {
954 return _definedNames[name.substring(_length + 1)];
955 }
956 }
957 return null;
958 }
959
960 @override
961 Element getPrefixed(String prefix, String name) {
962 if (prefix == _prefix) {
963 return _definedNames[name];
964 }
965 return null;
966 }
967 }
968
969 /**
970 * A name scope used by the resolver to determine which names are visible at any
971 * given point in the code.
972 */
973 abstract class Scope {
974 /**
975 * The prefix used to mark an identifier as being private to its library.
976 */
977 static int PRIVATE_NAME_PREFIX = 0x5F;
978
979 /**
980 * The suffix added to the declared name of a setter when looking up the
981 * setter. Used to disambiguate between a getter and a setter that have the
982 * same name.
983 */
984 static String SETTER_SUFFIX = "=";
985
986 /**
987 * The name used to look up the method used to implement the unary minus
988 * operator. Used to disambiguate between the unary and binary operators.
989 */
990 static String UNARY_MINUS = "unary-";
991
992 /**
993 * A table mapping names that are defined in this scope to the element
994 * representing the thing declared with that name.
995 */
996 HashMap<String, Element> _definedNames = null;
997
998 /**
999 * Return the scope in which this scope is lexically enclosed.
1000 */
1001 Scope get enclosingScope => null;
1002
1003 /**
1004 * Add the given [element] to this scope. If there is already an element with
1005 * the given name defined in this scope, then the original element will
1006 * continue to be mapped to the name.
1007 */
1008 void define(Element element) {
1009 String name = _getName(element);
1010 if (name != null && !name.isEmpty) {
1011 _definedNames ??= new HashMap<String, Element>();
1012 _definedNames.putIfAbsent(name, () => element);
1013 }
1014 }
1015
1016 /**
1017 * Add the given [element] to this scope without checking for duplication or
1018 * hiding.
1019 */
1020 void defineNameWithoutChecking(String name, Element element) {
1021 _definedNames ??= new HashMap<String, Element>();
1022 _definedNames[name] = element;
1023 }
1024
1025 /**
1026 * Add the given [element] to this scope without checking for duplication or
1027 * hiding.
1028 */
1029 void defineWithoutChecking(Element element) {
1030 _definedNames ??= new HashMap<String, Element>();
1031 _definedNames[_getName(element)] = element;
1032 }
1033
1034 /**
1035 * Return the error code to be used when reporting that a name being defined
1036 * locally conflicts with another element of the same name in the local scope.
1037 * [existing] is the first element to be declared with the conflicting name,
1038 * while [duplicate] another element declared with the conflicting name.
1039 */
1040 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
1041 // TODO(brianwilkerson) Customize the error message based on the types of
1042 // elements that share the same name.
1043 // TODO(jwren) There are 4 error codes for duplicate, but only 1 is being
1044 // generated.
1045 Source source = duplicate.source;
1046 return new AnalysisError(source, duplicate.nameOffset, duplicate.nameLength,
1047 CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]);
1048 }
1049
1050 /**
1051 * Return the source that contains the given [identifier], or the source
1052 * associated with this scope if the source containing the identifier could
1053 * not be determined.
1054 */
1055 Source getSource(AstNode identifier) {
1056 CompilationUnit unit =
1057 identifier.getAncestor((node) => node is CompilationUnit);
1058 if (unit != null) {
1059 CompilationUnitElement unitElement = unit.element;
1060 if (unitElement != null) {
1061 return unitElement.source;
1062 }
1063 }
1064 return null;
1065 }
1066
1067 /**
1068 * Return the element with which the given [name] is associated, or `null` if
1069 * the name is not defined within this scope. The [identifier] is the
1070 * identifier node to lookup element for, used to report correct kind of a
1071 * problem and associate problem with. The [referencingLibrary] is the library
1072 * that contains the reference to the name, used to implement library-level
1073 * privacy.
1074 */
1075 Element internalLookup(
1076 Identifier identifier, String name, LibraryElement referencingLibrary);
1077
1078 /**
1079 * Return the element with which the given [name] is associated, or `null` if
1080 * the name is not defined within this scope. This method only returns
1081 * elements that are directly defined within this scope, not elements that are
1082 * defined in an enclosing scope. The [referencingLibrary] is the library that
1083 * contains the reference to the name, used to implement library-level privacy .
1084 */
1085 Element localLookup(String name, LibraryElement referencingLibrary) {
1086 if (_definedNames != null) {
1087 return _definedNames[name];
1088 }
1089 return null;
1090 }
1091
1092 /**
1093 * Return the element with which the given [identifier] is associated, or
1094 * `null` if the name is not defined within this scope. The
1095 * [referencingLibrary] is the library that contains the reference to the
1096 * name, used to implement library-level privacy.
1097 */
1098 Element lookup(Identifier identifier, LibraryElement referencingLibrary) {
1099 if (identifier is PrefixedIdentifier) {
1100 return _internalLookupPrefixed(identifier, identifier.prefix.name,
1101 identifier.identifier.name, referencingLibrary);
1102 }
1103 return internalLookup(identifier, identifier.name, referencingLibrary);
1104 }
1105
1106 /**
1107 * Return `true` if the fact that the given [node] is not defined should be
1108 * ignored (from the perspective of error reporting). This will be the case if
1109 * there is at least one import that defines the node's prefix, and if that
1110 * import either has no show combinators or has a show combinator that
1111 * explicitly lists the node's name.
1112 */
1113 bool shouldIgnoreUndefined(Identifier node) {
1114 if (enclosingScope != null) {
1115 return enclosingScope.shouldIgnoreUndefined(node);
1116 }
1117 return false;
1118 }
1119
1120 /**
1121 * Return the name that will be used to look up the given [element].
1122 */
1123 String _getName(Element element) {
1124 if (element is MethodElement) {
1125 MethodElement method = element;
1126 if (method.name == "-" && method.parameters.length == 0) {
1127 return UNARY_MINUS;
1128 }
1129 }
1130 return element.name;
1131 }
1132
1133 /**
1134 * Return the element with which the given [prefix] and [name] are associated,
1135 * or `null` if the name is not defined within this scope. The [identifier] is
1136 * the identifier node to lookup element for, used to report correct kind of a
1137 * problem and associate problem with. The [referencingLibrary] is the library
1138 * that contains the reference to the name, used to implement library-level
1139 * privacy.
1140 */
1141 Element _internalLookupPrefixed(PrefixedIdentifier identifier, String prefix,
1142 String name, LibraryElement referencingLibrary);
1143
1144 /**
1145 * Return `true` if the given [name] is a library-private name.
1146 */
1147 static bool isPrivateName(String name) =>
1148 name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX);
1149 }
1150
1151 /**
1152 * The scope defined by the type parameters in a class.
1153 */
1154 class TypeParameterScope extends EnclosedScope {
1155 /**
1156 * Initialize a newly created scope, enclosed within the [enclosingScope],
1157 * that defined the type parameters from the given [classElement].
1158 */
1159 TypeParameterScope(Scope enclosingScope, ClassElement classElement)
1160 : super(enclosingScope) {
1161 if (classElement == null) {
1162 throw new ArgumentError("class element cannot be null");
1163 }
1164 _defineTypeParameters(classElement);
1165 }
1166
1167 /**
1168 * Define the type parameters declared by the [classElement].
1169 */
1170 void _defineTypeParameters(ClassElement classElement) {
1171 for (TypeParameterElement typeParameter in classElement.typeParameters) {
1172 define(typeParameter);
1173 }
1174 }
1175 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/dart/resolver/inheritance_manager.dart ('k') | packages/analyzer/lib/src/dart/scanner/reader.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698