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

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

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

Powered by Google App Engine
This is Rietveld 408576698