| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library analyzer.src.generated.resolver; | 5 library analyzer.src.generated.resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
| (...skipping 4093 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4104 } | 4104 } |
| 4105 | 4105 |
| 4106 @override | 4106 @override |
| 4107 void visitPrefixedIdentifier(PrefixedIdentifier node) { | 4107 void visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 4108 // If the prefixed identifier references some A.B, where A is a library | 4108 // If the prefixed identifier references some A.B, where A is a library |
| 4109 // prefix, then we can lookup the associated ImportDirective in | 4109 // prefix, then we can lookup the associated ImportDirective in |
| 4110 // prefixElementMap and remove it from the unusedImports list. | 4110 // prefixElementMap and remove it from the unusedImports list. |
| 4111 SimpleIdentifier prefixIdentifier = node.prefix; | 4111 SimpleIdentifier prefixIdentifier = node.prefix; |
| 4112 Element element = prefixIdentifier.staticElement; | 4112 Element element = prefixIdentifier.staticElement; |
| 4113 if (element is PrefixElement) { | 4113 if (element is PrefixElement) { |
| 4114 usedElements.prefixes.add(element); | 4114 List<Element> prefixedElements = |
| 4115 usedElements.prefixMap.putIfAbsent(element, () => <Element>[]); |
| 4116 prefixedElements.add(node.identifier.staticElement); |
| 4115 return; | 4117 return; |
| 4116 } | 4118 } |
| 4117 // Otherwise, pass the prefixed identifier element and name onto | 4119 // Otherwise, pass the prefixed identifier element and name onto |
| 4118 // visitIdentifier. | 4120 // visitIdentifier. |
| 4119 _visitIdentifier(element, prefixIdentifier.name); | 4121 _visitIdentifier(element, prefixIdentifier.name); |
| 4120 } | 4122 } |
| 4121 | 4123 |
| 4122 @override | 4124 @override |
| 4123 void visitSimpleIdentifier(SimpleIdentifier node) { | 4125 void visitSimpleIdentifier(SimpleIdentifier node) { |
| 4124 _visitIdentifier(node.staticElement, node.name); | 4126 _visitIdentifier(node.staticElement, node.name); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4138 } | 4140 } |
| 4139 // If the element is multiply defined then call this method recursively for | 4141 // If the element is multiply defined then call this method recursively for |
| 4140 // each of the conflicting elements. | 4142 // each of the conflicting elements. |
| 4141 if (element is MultiplyDefinedElement) { | 4143 if (element is MultiplyDefinedElement) { |
| 4142 MultiplyDefinedElement multiplyDefinedElement = element; | 4144 MultiplyDefinedElement multiplyDefinedElement = element; |
| 4143 for (Element elt in multiplyDefinedElement.conflictingElements) { | 4145 for (Element elt in multiplyDefinedElement.conflictingElements) { |
| 4144 _visitIdentifier(elt, name); | 4146 _visitIdentifier(elt, name); |
| 4145 } | 4147 } |
| 4146 return; | 4148 return; |
| 4147 } else if (element is PrefixElement) { | 4149 } else if (element is PrefixElement) { |
| 4148 usedElements.prefixes.add(element); | 4150 usedElements.prefixMap.putIfAbsent(element, () => <Element>[]); |
| 4149 return; | 4151 return; |
| 4150 } else if (element.enclosingElement is! CompilationUnitElement) { | 4152 } else if (element.enclosingElement is! CompilationUnitElement) { |
| 4151 // Identifiers that aren't a prefix element and whose enclosing element | 4153 // Identifiers that aren't a prefix element and whose enclosing element |
| 4152 // isn't a CompilationUnit are ignored- this covers the case the | 4154 // isn't a CompilationUnit are ignored- this covers the case the |
| 4153 // identifier is a relative-reference, a reference to an identifier not | 4155 // identifier is a relative-reference, a reference to an identifier not |
| 4154 // imported by this library. | 4156 // imported by this library. |
| 4155 return; | 4157 return; |
| 4156 } | 4158 } |
| 4157 // Ignore if an unknown library. | 4159 // Ignore if an unknown library. |
| 4158 LibraryElement containingLibrary = element.library; | 4160 LibraryElement containingLibrary = element.library; |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4368 CompilationUnit definingUnit = _compilationUnits[0]; | 4370 CompilationUnit definingUnit = _compilationUnits[0]; |
| 4369 ErrorReporter definingUnitErrorReporter = | 4371 ErrorReporter definingUnitErrorReporter = |
| 4370 new ErrorReporter(_errorListener, definingUnit.element.source); | 4372 new ErrorReporter(_errorListener, definingUnit.element.source); |
| 4371 { | 4373 { |
| 4372 ImportsVerifier importsVerifier = new ImportsVerifier(); | 4374 ImportsVerifier importsVerifier = new ImportsVerifier(); |
| 4373 importsVerifier.addImports(definingUnit); | 4375 importsVerifier.addImports(definingUnit); |
| 4374 importsVerifier | 4376 importsVerifier |
| 4375 .removeUsedElements(_usedImportedElementsVisitor.usedElements); | 4377 .removeUsedElements(_usedImportedElementsVisitor.usedElements); |
| 4376 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter); | 4378 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter); |
| 4377 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter); | 4379 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter); |
| 4380 importsVerifier.generateUnusedShownNameHints(definingUnitErrorReporter); |
| 4378 } | 4381 } |
| 4379 _library.accept(new UnusedLocalElementsVerifier( | 4382 _library.accept(new UnusedLocalElementsVerifier( |
| 4380 _errorListener, _usedLocalElementsVisitor.usedElements)); | 4383 _errorListener, _usedLocalElementsVisitor.usedElements)); |
| 4381 }); | 4384 }); |
| 4382 } | 4385 } |
| 4383 | 4386 |
| 4384 void _generateForCompilationUnit(CompilationUnit unit, Source source) { | 4387 void _generateForCompilationUnit(CompilationUnit unit, Source source) { |
| 4385 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); | 4388 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); |
| 4386 unit.accept(_usedImportedElementsVisitor); | 4389 unit.accept(_usedImportedElementsVisitor); |
| 4387 // dead code analysis | 4390 // dead code analysis |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4450 /** | 4453 /** |
| 4451 * Initialize a newly created scope to represent a switch statement or loop | 4454 * Initialize a newly created scope to represent a switch statement or loop |
| 4452 * nested within the current scope. [statement] is the statement associated | 4455 * nested within the current scope. [statement] is the statement associated |
| 4453 * with the newly created scope. | 4456 * with the newly created scope. |
| 4454 */ | 4457 */ |
| 4455 ImplicitLabelScope nest(Statement statement) => | 4458 ImplicitLabelScope nest(Statement statement) => |
| 4456 new ImplicitLabelScope._(this, statement); | 4459 new ImplicitLabelScope._(this, statement); |
| 4457 } | 4460 } |
| 4458 | 4461 |
| 4459 /** | 4462 /** |
| 4460 * Instances of the class `ImportsVerifier` visit all of the referenced librarie
s in the | 4463 * Instances of the class `ImportsVerifier` visit all of the referenced librarie
s in the source code |
| 4461 * source code verifying that all of the imports are used, otherwise a | 4464 * verifying that all of the imports are used, otherwise a [HintCode.UNUSED_IMPO
RT] hint is |
| 4462 * [HintCode.UNUSED_IMPORT] is generated with | 4465 * generated with [generateUnusedImportHints]. |
| 4463 * [generateUnusedImportHints]. | 4466 * |
| 4467 * Additionally, [generateDuplicateImportHints] generates [HintCode.DUPLICATE_IM
PORT] hints and |
| 4468 * [HintCode.UNUSED_SHOWN_NAME] hints. |
| 4464 * | 4469 * |
| 4465 * While this class does not yet have support for an "Organize Imports" action,
this logic built up | 4470 * While this class does not yet have support for an "Organize Imports" action,
this logic built up |
| 4466 * in this class could be used for such an action in the future. | 4471 * in this class could be used for such an action in the future. |
| 4467 */ | 4472 */ |
| 4468 class ImportsVerifier { | 4473 class ImportsVerifier { |
| 4469 /** | 4474 /** |
| 4470 * A list of [ImportDirective]s that the current library imports, as identifie
rs are visited | 4475 * A list of [ImportDirective]s that the current library imports, but does not
use. |
| 4471 * by this visitor and an import has been identified as being used by the libr
ary, the | 4476 * |
| 4472 * [ImportDirective] is removed from this list. After all the sources in the l
ibrary have | 4477 * As identifiers are visited by this visitor and an import has been identifie
d as being used |
| 4473 * been evaluated, this list represents the set of unused imports. | 4478 * by the library, the [ImportDirective] is removed from this list. After all
the sources in the |
| 4479 * library have been evaluated, this list represents the set of unused imports
. |
| 4474 * | 4480 * |
| 4475 * See [ImportsVerifier.generateUnusedImportErrors]. | 4481 * See [ImportsVerifier.generateUnusedImportErrors]. |
| 4476 */ | 4482 */ |
| 4477 final List<ImportDirective> _unusedImports = <ImportDirective>[]; | 4483 final List<ImportDirective> _unusedImports = <ImportDirective>[]; |
| 4478 | 4484 |
| 4479 /** | 4485 /** |
| 4480 * After the list of [unusedImports] has been computed, this list is a proper
subset of the | 4486 * After the list of [unusedImports] has been computed, this list is a proper
subset of the |
| 4481 * unused imports that are listed more than once. | 4487 * unused imports that are listed more than once. |
| 4482 */ | 4488 */ |
| 4483 final List<ImportDirective> _duplicateImports = <ImportDirective>[]; | 4489 final List<ImportDirective> _duplicateImports = <ImportDirective>[]; |
| 4484 | 4490 |
| 4485 /** | 4491 /** |
| 4486 * This is a map between the set of [LibraryElement]s that the current library
imports, and | 4492 * This is a map between the set of [LibraryElement]s that the current library
imports, and the |
| 4487 * a list of [ImportDirective]s that imports the library. In cases where the c
urrent library | 4493 * list of [ImportDirective]s that import each [LibraryElement]. In cases wher
e the current |
| 4488 * imports a library with a single directive (such as `import lib1.dart;`), th
e library | 4494 * library imports a library with a single directive (such as `import lib1.dar
t;`), the library |
| 4489 * element will map to a list of one [ImportDirective], which will then be rem
oved from the | 4495 * element will map to a list of one [ImportDirective], which will then be rem
oved from the |
| 4490 * [unusedImports] list. In cases where the current library imports a library
with multiple | 4496 * [unusedImports] list. In cases where the current library imports a library
with multiple |
| 4491 * directives (such as `import lib1.dart; import lib1.dart show C;`), the | 4497 * directives (such as `import lib1.dart; import lib1.dart show C;`), the [Lib
raryElement] will |
| 4492 * [LibraryElement] will be mapped to a list of the import directives, and the
namespace | 4498 * be mapped to a list of the import directives, and the namespace will need t
o be used to |
| 4493 * will need to be used to compute the correct [ImportDirective] being used, s
ee | 4499 * compute the correct [ImportDirective] being used; see [_namespaceMap]. |
| 4494 * [namespaceMap]. | |
| 4495 */ | 4500 */ |
| 4496 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap = | 4501 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap = |
| 4497 new HashMap<LibraryElement, List<ImportDirective>>(); | 4502 new HashMap<LibraryElement, List<ImportDirective>>(); |
| 4498 | 4503 |
| 4499 /** | 4504 /** |
| 4500 * In cases where there is more than one import directive per library element,
this mapping is | 4505 * In cases where there is more than one import directive per library element,
this mapping is |
| 4501 * used to determine which of the multiple import directives are used by gener
ating a | 4506 * used to determine which of the multiple import directives are used by gener
ating a |
| 4502 * [Namespace] for each of the imports to do lookups in the same way that they
are done from | 4507 * [Namespace] for each of the imports to do lookups in the same way that they
are done from |
| 4503 * the [ElementResolver]. | 4508 * the [ElementResolver]. |
| 4504 */ | 4509 */ |
| 4505 final HashMap<ImportDirective, Namespace> _namespaceMap = | 4510 final HashMap<ImportDirective, Namespace> _namespaceMap = |
| 4506 new HashMap<ImportDirective, Namespace>(); | 4511 new HashMap<ImportDirective, Namespace>(); |
| 4507 | 4512 |
| 4508 /** | 4513 /** |
| 4509 * This is a map between prefix elements and the import directives from which
they are derived. In | 4514 * This is a map between prefix elements and the import directives from which
they are derived. In |
| 4510 * cases where a type is referenced via a prefix element, the import directive
can be marked as | 4515 * cases where a type is referenced via a prefix element, the import directive
can be marked as |
| 4511 * used (removed from the unusedImports) by looking at the resolved `lib` in `
lib.X`, | 4516 * used (removed from the unusedImports) by looking at the resolved `lib` in `
lib.X`, |
| 4512 * instead of looking at which library the `lib.X` resolves. | 4517 * instead of looking at which library the `lib.X` resolves. |
| 4513 * | 4518 * |
| 4514 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl
ement], | 4519 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl
ement], |
| 4515 * it is possible to have an unreported unused import in situations where two
imports use the same | 4520 * it is possible to have an unreported unused import in situations where two
imports use the same |
| 4516 * prefix and at least one import directive is used. | 4521 * prefix and at least one import directive is used. |
| 4517 */ | 4522 */ |
| 4518 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap = | 4523 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap = |
| 4519 new HashMap<PrefixElement, List<ImportDirective>>(); | 4524 new HashMap<PrefixElement, List<ImportDirective>>(); |
| 4520 | 4525 |
| 4526 /** |
| 4527 * A map of identifiers that the current library's imports show, but that the
library does not |
| 4528 * use. |
| 4529 * |
| 4530 * Each import directive maps to a list of the identifiers that are imported v
ia the "show" |
| 4531 * keyword. |
| 4532 * |
| 4533 * As each identifier is visited by this visitor, it is identified as being us
ed by the library, |
| 4534 * and the identifier is removed from this map (under the import that imported
it). After all the |
| 4535 * sources in the library have been evaluated, each list in this map's values
present the set of |
| 4536 * unused shown elements. |
| 4537 * |
| 4538 * See [ImportsVerifier.generateUnusedShownNameHints]. |
| 4539 */ |
| 4540 final HashMap<ImportDirective, List<SimpleIdentifier>> _unusedShownNamesMap = |
| 4541 new HashMap<ImportDirective, List<SimpleIdentifier>>(); |
| 4542 |
| 4521 void addImports(CompilationUnit node) { | 4543 void addImports(CompilationUnit node) { |
| 4522 for (Directive directive in node.directives) { | 4544 for (Directive directive in node.directives) { |
| 4523 if (directive is ImportDirective) { | 4545 if (directive is ImportDirective) { |
| 4524 ImportDirective importDirective = directive; | 4546 ImportDirective importDirective = directive; |
| 4525 LibraryElement libraryElement = importDirective.uriElement; | 4547 LibraryElement libraryElement = importDirective.uriElement; |
| 4526 if (libraryElement != null) { | 4548 if (libraryElement == null) { |
| 4527 _unusedImports.add(importDirective); | 4549 continue; |
| 4528 // | 4550 } |
| 4529 // Initialize prefixElementMap | 4551 _unusedImports.add(importDirective); |
| 4530 // | 4552 // |
| 4531 if (importDirective.asKeyword != null) { | 4553 // Initialize prefixElementMap |
| 4532 SimpleIdentifier prefixIdentifier = importDirective.prefix; | 4554 // |
| 4533 if (prefixIdentifier != null) { | 4555 if (importDirective.asKeyword != null) { |
| 4534 Element element = prefixIdentifier.staticElement; | 4556 SimpleIdentifier prefixIdentifier = importDirective.prefix; |
| 4535 if (element is PrefixElement) { | 4557 if (prefixIdentifier != null) { |
| 4536 PrefixElement prefixElementKey = element; | 4558 Element element = prefixIdentifier.staticElement; |
| 4537 List<ImportDirective> list = | 4559 if (element is PrefixElement) { |
| 4538 _prefixElementMap[prefixElementKey]; | 4560 PrefixElement prefixElementKey = element; |
| 4539 if (list == null) { | 4561 List<ImportDirective> list = _prefixElementMap[prefixElementKey]; |
| 4540 list = new List<ImportDirective>(); | 4562 if (list == null) { |
| 4541 _prefixElementMap[prefixElementKey] = list; | 4563 list = new List<ImportDirective>(); |
| 4542 } | 4564 _prefixElementMap[prefixElementKey] = list; |
| 4543 list.add(importDirective); | |
| 4544 } | 4565 } |
| 4545 // TODO (jwren) Can the element ever not be a PrefixElement? | 4566 list.add(importDirective); |
| 4546 } | 4567 } |
| 4568 // TODO (jwren) Can the element ever not be a PrefixElement? |
| 4547 } | 4569 } |
| 4548 // | |
| 4549 // Initialize libraryMap: libraryElement -> importDirective | |
| 4550 // | |
| 4551 _putIntoLibraryMap(libraryElement, importDirective); | |
| 4552 // | |
| 4553 // For this new addition to the libraryMap, also recursively add any | |
| 4554 // exports from the libraryElement. | |
| 4555 // | |
| 4556 _addAdditionalLibrariesForExports( | |
| 4557 libraryElement, importDirective, new List<LibraryElement>()); | |
| 4558 } | 4570 } |
| 4571 // |
| 4572 // Initialize libraryMap: libraryElement -> importDirective |
| 4573 // |
| 4574 _putIntoLibraryMap(libraryElement, importDirective); |
| 4575 // |
| 4576 // For this new addition to the libraryMap, also recursively add any |
| 4577 // exports from the libraryElement. |
| 4578 // |
| 4579 _addAdditionalLibrariesForExports( |
| 4580 libraryElement, importDirective, new List<LibraryElement>()); |
| 4581 _addShownNames(importDirective); |
| 4559 } | 4582 } |
| 4560 } | 4583 } |
| 4561 if (_unusedImports.length > 1) { | 4584 if (_unusedImports.length > 1) { |
| 4562 // order the list of unusedImports to find duplicates in faster than | 4585 // order the list of unusedImports to find duplicates in faster than |
| 4563 // O(n^2) time | 4586 // O(n^2) time |
| 4564 List<ImportDirective> importDirectiveArray = | 4587 List<ImportDirective> importDirectiveArray = |
| 4565 new List<ImportDirective>.from(_unusedImports); | 4588 new List<ImportDirective>.from(_unusedImports); |
| 4566 importDirectiveArray.sort(ImportDirective.COMPARATOR); | 4589 importDirectiveArray.sort(ImportDirective.COMPARATOR); |
| 4567 ImportDirective currentDirective = importDirectiveArray[0]; | 4590 ImportDirective currentDirective = importDirectiveArray[0]; |
| 4568 for (int i = 1; i < importDirectiveArray.length; i++) { | 4591 for (int i = 1; i < importDirectiveArray.length; i++) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 4591 * hints to | 4614 * hints to |
| 4592 */ | 4615 */ |
| 4593 void generateDuplicateImportHints(ErrorReporter errorReporter) { | 4616 void generateDuplicateImportHints(ErrorReporter errorReporter) { |
| 4594 for (ImportDirective duplicateImport in _duplicateImports) { | 4617 for (ImportDirective duplicateImport in _duplicateImports) { |
| 4595 errorReporter.reportErrorForNode( | 4618 errorReporter.reportErrorForNode( |
| 4596 HintCode.DUPLICATE_IMPORT, duplicateImport.uri); | 4619 HintCode.DUPLICATE_IMPORT, duplicateImport.uri); |
| 4597 } | 4620 } |
| 4598 } | 4621 } |
| 4599 | 4622 |
| 4600 /** | 4623 /** |
| 4601 * After all of the compilation units have been visited by this visitor, this
method can be called | 4624 * Report an [HintCode.UNUSED_IMPORT] hint for each unused import. |
| 4602 * to report an [HintCode.UNUSED_IMPORT] hint for each of the import directive
s in the | |
| 4603 * [unusedImports] list. | |
| 4604 * | 4625 * |
| 4605 * @param errorReporter the error reporter to report the set of [HintCode.UNUS
ED_IMPORT] | 4626 * Only call this method after all of the compilation units have been visited
by this visitor. |
| 4606 * hints to | 4627 * |
| 4628 * @param errorReporter the error reporter used to report the set of [HintCode
.UNUSED_IMPORT] |
| 4629 * hints |
| 4607 */ | 4630 */ |
| 4608 void generateUnusedImportHints(ErrorReporter errorReporter) { | 4631 void generateUnusedImportHints(ErrorReporter errorReporter) { |
| 4609 for (ImportDirective unusedImport in _unusedImports) { | 4632 for (ImportDirective unusedImport in _unusedImports) { |
| 4610 // Check that the import isn't dart:core | 4633 // Check that the import isn't dart:core |
| 4611 ImportElement importElement = unusedImport.element; | 4634 ImportElement importElement = unusedImport.element; |
| 4612 if (importElement != null) { | 4635 if (importElement != null) { |
| 4613 LibraryElement libraryElement = importElement.importedLibrary; | 4636 LibraryElement libraryElement = importElement.importedLibrary; |
| 4614 if (libraryElement != null && libraryElement.isDartCore) { | 4637 if (libraryElement != null && libraryElement.isDartCore) { |
| 4615 continue; | 4638 continue; |
| 4616 } | 4639 } |
| 4617 } | 4640 } |
| 4618 errorReporter.reportErrorForNode( | 4641 errorReporter.reportErrorForNode( |
| 4619 HintCode.UNUSED_IMPORT, unusedImport.uri); | 4642 HintCode.UNUSED_IMPORT, unusedImport.uri); |
| 4620 } | 4643 } |
| 4621 } | 4644 } |
| 4622 | 4645 |
| 4623 /** | 4646 /** |
| 4647 * Report an [HintCode.UNUSED_SHOWN_NAME] hint for each unused shown name. |
| 4648 * |
| 4649 * Only call this method after all of the compilation units have been visited
by this visitor. |
| 4650 * |
| 4651 * @param errorReporter the error reporter used to report the set of [HintCode
.UNUSED_SHOWN_NAME] |
| 4652 * hints |
| 4653 */ |
| 4654 void generateUnusedShownNameHints(ErrorReporter reporter) { |
| 4655 _unusedShownNamesMap.forEach((ImportDirective importDirective, |
| 4656 List<SimpleIdentifier> identifiers) { |
| 4657 if (_unusedImports.contains(importDirective)) { |
| 4658 // This import is actually wholly unused, not just one or more shown nam
es from it. |
| 4659 // This is then an "unused import", rather than unused shown names. |
| 4660 return; |
| 4661 } |
| 4662 for (Identifier identifier in identifiers) { |
| 4663 reporter.reportErrorForNode(HintCode.UNUSED_SHOWN_NAME, identifier, [ide
ntifier.name]); |
| 4664 } |
| 4665 }); |
| 4666 } |
| 4667 |
| 4668 /** |
| 4624 * Remove elements from [_unusedImports] using the given [usedElements]. | 4669 * Remove elements from [_unusedImports] using the given [usedElements]. |
| 4625 */ | 4670 */ |
| 4626 void removeUsedElements(UsedImportedElements usedElements) { | 4671 void removeUsedElements(UsedImportedElements usedElements) { |
| 4627 // Stop if all the imports are known to be used. | 4672 // Stop if all the imports and shown names are known to be used. |
| 4628 if (_unusedImports.isEmpty) { | 4673 if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) { |
| 4629 return; | 4674 return; |
| 4630 } | 4675 } |
| 4631 // Process import prefixes. | 4676 // Process import prefixes. |
| 4632 for (PrefixElement prefix in usedElements.prefixes) { | 4677 usedElements.prefixMap.forEach((PrefixElement prefix, List<Element> elements
) { |
| 4633 List<ImportDirective> importDirectives = _prefixElementMap[prefix]; | 4678 List<ImportDirective> importDirectives = _prefixElementMap[prefix]; |
| 4634 if (importDirectives != null) { | 4679 if (importDirectives != null) { |
| 4635 for (ImportDirective importDirective in importDirectives) { | 4680 for (ImportDirective importDirective in importDirectives) { |
| 4636 _unusedImports.remove(importDirective); | 4681 _unusedImports.remove(importDirective); |
| 4682 for (Element element in elements) { |
| 4683 _removeFromUnusedShownNamesMap(element, importDirective); |
| 4684 } |
| 4637 } | 4685 } |
| 4638 } | 4686 } |
| 4639 } | 4687 }); |
| 4640 // Process top-level elements. | 4688 // Process top-level elements. |
| 4641 for (Element element in usedElements.elements) { | 4689 for (Element element in usedElements.elements) { |
| 4642 // Stop if all the imports are known to be used. | 4690 // Stop if all the imports and shown names are known to be used. |
| 4643 if (_unusedImports.isEmpty) { | 4691 if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) { |
| 4644 return; | 4692 return; |
| 4645 } | 4693 } |
| 4646 // Prepare import directives for this library. | 4694 // Prepare import directives for this element's library. |
| 4647 LibraryElement library = element.library; | 4695 LibraryElement library = element.library; |
| 4648 List<ImportDirective> importsLibrary = _libraryMap[library]; | 4696 List<ImportDirective> importsLibrary = _libraryMap[library]; |
| 4649 if (importsLibrary == null) { | 4697 if (importsLibrary == null) { |
| 4698 // element's library is not imported. Must be the current library. |
| 4650 continue; | 4699 continue; |
| 4651 } | 4700 } |
| 4652 // If there is only one import directive for this library, then it must be | 4701 // If there is only one import directive for this library, then it must be |
| 4653 // the directive that this element is imported with, remove it from the | 4702 // the directive that this element is imported with, remove it from the |
| 4654 // unusedImports list. | 4703 // unusedImports list. |
| 4655 if (importsLibrary.length == 1) { | 4704 if (importsLibrary.length == 1) { |
| 4656 ImportDirective usedImportDirective = importsLibrary[0]; | 4705 ImportDirective usedImportDirective = importsLibrary[0]; |
| 4657 _unusedImports.remove(usedImportDirective); | 4706 _unusedImports.remove(usedImportDirective); |
| 4707 _removeFromUnusedShownNamesMap(element, usedImportDirective); |
| 4658 continue; | 4708 continue; |
| 4659 } | 4709 } |
| 4660 // Otherwise, find import directives using namespaces. | 4710 // Otherwise, find import directives using namespaces. |
| 4661 String name = element.displayName; | 4711 String name = element.displayName; |
| 4662 for (ImportDirective importDirective in importsLibrary) { | 4712 for (ImportDirective importDirective in importsLibrary) { |
| 4663 Namespace namespace = _computeNamespace(importDirective); | 4713 Namespace namespace = _computeNamespace(importDirective); |
| 4664 if (namespace != null && namespace.get(name) != null) { | 4714 if (namespace != null && namespace.get(name) != null) { |
| 4665 _unusedImports.remove(importDirective); | 4715 _unusedImports.remove(importDirective); |
| 4716 _removeFromUnusedShownNamesMap(element, importDirective); |
| 4666 } | 4717 } |
| 4667 } | 4718 } |
| 4668 } | 4719 } |
| 4669 } | 4720 } |
| 4670 | 4721 |
| 4671 /** | 4722 /** |
| 4723 * Remove [element] from the list of names shown by [importDirective]. |
| 4724 */ |
| 4725 void _removeFromUnusedShownNamesMap(Element element, |
| 4726 ImportDirective importDirective) { |
| 4727 List<SimpleIdentifier> identifiers = _unusedShownNamesMap[importDirective]; |
| 4728 if (identifiers == null) { |
| 4729 return; |
| 4730 } |
| 4731 for (Identifier identifier in identifiers) { |
| 4732 if (element is PropertyAccessorElement) { |
| 4733 // If the getter or setter of a variable is used, then the variable (the |
| 4734 // shown name) is used. |
| 4735 if (identifier.staticElement == element.variable) { |
| 4736 identifiers.remove(identifier); |
| 4737 break; |
| 4738 } |
| 4739 } else { |
| 4740 if (identifier.staticElement == element) { |
| 4741 identifiers.remove(identifier); |
| 4742 break; |
| 4743 } |
| 4744 } |
| 4745 } |
| 4746 if (identifiers.isEmpty) { |
| 4747 _unusedShownNamesMap.remove(importDirective); |
| 4748 } |
| 4749 } |
| 4750 |
| 4751 /** |
| 4672 * Recursively add any exported library elements into the [libraryMap]. | 4752 * Recursively add any exported library elements into the [libraryMap]. |
| 4673 */ | 4753 */ |
| 4674 void _addAdditionalLibrariesForExports(LibraryElement library, | 4754 void _addAdditionalLibrariesForExports(LibraryElement library, |
| 4675 ImportDirective importDirective, List<LibraryElement> exportPath) { | 4755 ImportDirective importDirective, List<LibraryElement> exportPath) { |
| 4676 if (exportPath.contains(library)) { | 4756 if (exportPath.contains(library)) { |
| 4677 return; | 4757 return; |
| 4678 } | 4758 } |
| 4679 exportPath.add(library); | 4759 exportPath.add(library); |
| 4680 for (LibraryElement exportedLibraryElt in library.exportedLibraries) { | 4760 for (LibraryElement exportedLibraryElt in library.exportedLibraries) { |
| 4681 _putIntoLibraryMap(exportedLibraryElt, importDirective); | 4761 _putIntoLibraryMap(exportedLibraryElt, importDirective); |
| 4682 _addAdditionalLibrariesForExports( | 4762 _addAdditionalLibrariesForExports( |
| 4683 exportedLibraryElt, importDirective, exportPath); | 4763 exportedLibraryElt, importDirective, exportPath); |
| 4684 } | 4764 } |
| 4685 } | 4765 } |
| 4686 | 4766 |
| 4687 /** | 4767 /** |
| 4688 * Lookup and return the [Namespace] from the [namespaceMap], if the map does
not | 4768 * Lookup and return the [Namespace] from the [_namespaceMap]. |
| 4689 * have the computed namespace, compute it and cache it in the map. If the imp
ort directive is not | 4769 * |
| 4690 * resolved or is not resolvable, `null` is returned. | 4770 * If the map does not have the computed namespace, compute it and cache it in
the map. If |
| 4771 * [importDirective] is not resolved or is not resolvable, `null` is returned. |
| 4691 * | 4772 * |
| 4692 * @param importDirective the import directive used to compute the returned na
mespace | 4773 * @param importDirective the import directive used to compute the returned na
mespace |
| 4693 * @return the computed or looked up [Namespace] | 4774 * @return the computed or looked up [Namespace] |
| 4694 */ | 4775 */ |
| 4695 Namespace _computeNamespace(ImportDirective importDirective) { | 4776 Namespace _computeNamespace(ImportDirective importDirective) { |
| 4696 Namespace namespace = _namespaceMap[importDirective]; | 4777 Namespace namespace = _namespaceMap[importDirective]; |
| 4697 if (namespace == null) { | 4778 if (namespace == null) { |
| 4698 // If the namespace isn't in the namespaceMap, then compute and put it in | 4779 // If the namespace isn't in the namespaceMap, then compute and put it in |
| 4699 // the map. | 4780 // the map. |
| 4700 ImportElement importElement = importDirective.element; | 4781 ImportElement importElement = importDirective.element; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4715 */ | 4796 */ |
| 4716 void _putIntoLibraryMap( | 4797 void _putIntoLibraryMap( |
| 4717 LibraryElement libraryElement, ImportDirective importDirective) { | 4798 LibraryElement libraryElement, ImportDirective importDirective) { |
| 4718 List<ImportDirective> importList = _libraryMap[libraryElement]; | 4799 List<ImportDirective> importList = _libraryMap[libraryElement]; |
| 4719 if (importList == null) { | 4800 if (importList == null) { |
| 4720 importList = new List<ImportDirective>(); | 4801 importList = new List<ImportDirective>(); |
| 4721 _libraryMap[libraryElement] = importList; | 4802 _libraryMap[libraryElement] = importList; |
| 4722 } | 4803 } |
| 4723 importList.add(importDirective); | 4804 importList.add(importDirective); |
| 4724 } | 4805 } |
| 4806 |
| 4807 /** |
| 4808 * Add every shown name from [importDirective] into [_unusedShownNamesMap]. |
| 4809 */ |
| 4810 void _addShownNames(ImportDirective importDirective) { |
| 4811 if (importDirective.combinators == null) { |
| 4812 return; |
| 4813 } |
| 4814 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); |
| 4815 _unusedShownNamesMap[importDirective] = identifiers; |
| 4816 for (Combinator combinator in importDirective.combinators) { |
| 4817 if (combinator is ShowCombinator) { |
| 4818 for (SimpleIdentifier name in combinator.shownNames) { |
| 4819 identifiers.add(name); |
| 4820 } |
| 4821 } |
| 4822 } |
| 4823 } |
| 4725 } | 4824 } |
| 4726 | 4825 |
| 4727 /** | 4826 /** |
| 4728 * Maintains and manages contextual type information used for | 4827 * Maintains and manages contextual type information used for |
| 4729 * inferring types. | 4828 * inferring types. |
| 4730 */ | 4829 */ |
| 4731 class InferenceContext { | 4830 class InferenceContext { |
| 4732 // TODO(leafp): Consider replacing these node properties with a | 4831 // TODO(leafp): Consider replacing these node properties with a |
| 4733 // hash table help in an instance of this class. | 4832 // hash table help in an instance of this class. |
| 4734 static const String _typeProperty = | 4833 static const String _typeProperty = |
| (...skipping 7824 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12559 } | 12658 } |
| 12560 } | 12659 } |
| 12561 } | 12660 } |
| 12562 | 12661 |
| 12563 /** | 12662 /** |
| 12564 * A container with information about used imports prefixes and used imported | 12663 * A container with information about used imports prefixes and used imported |
| 12565 * elements. | 12664 * elements. |
| 12566 */ | 12665 */ |
| 12567 class UsedImportedElements { | 12666 class UsedImportedElements { |
| 12568 /** | 12667 /** |
| 12569 * The set of referenced [PrefixElement]s. | 12668 * The map of referenced [PrefixElement]s and the [Element]s that they prefix. |
| 12570 */ | 12669 */ |
| 12571 final Set<PrefixElement> prefixes = new HashSet<PrefixElement>(); | 12670 final Map<PrefixElement, List<Element>> prefixMap = |
| 12671 new HashMap<PrefixElement, List<Element>>(); |
| 12572 | 12672 |
| 12573 /** | 12673 /** |
| 12574 * The set of referenced top-level [Element]s. | 12674 * The set of referenced top-level [Element]s. |
| 12575 */ | 12675 */ |
| 12576 final Set<Element> elements = new HashSet<Element>(); | 12676 final Set<Element> elements = new HashSet<Element>(); |
| 12577 } | 12677 } |
| 12578 | 12678 |
| 12579 /** | 12679 /** |
| 12580 * A container with sets of used [Element]s. | 12680 * A container with sets of used [Element]s. |
| 12581 * All these elements are defined in a single compilation unit or a library. | 12681 * All these elements are defined in a single compilation unit or a library. |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12977 nonFields.add(node); | 13077 nonFields.add(node); |
| 12978 return null; | 13078 return null; |
| 12979 } | 13079 } |
| 12980 | 13080 |
| 12981 @override | 13081 @override |
| 12982 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); | 13082 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); |
| 12983 | 13083 |
| 12984 @override | 13084 @override |
| 12985 Object visitWithClause(WithClause node) => null; | 13085 Object visitWithClause(WithClause node) => null; |
| 12986 } | 13086 } |
| OLD | NEW |