| 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 engine.resolver; | 5 library engine.resolver; |
| 6 | 6 |
| 7 import "dart:math" as math; | 7 import "dart:math" as math; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 | 9 |
| 10 import 'package:analyzer/src/generated/utilities_collection.dart'; | 10 import 'package:analyzer/src/generated/utilities_collection.dart'; |
| (...skipping 4332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4343 */ | 4343 */ |
| 4344 void _defineTypeParameters() { | 4344 void _defineTypeParameters() { |
| 4345 Scope typeParameterScope = enclosingScope; | 4345 Scope typeParameterScope = enclosingScope; |
| 4346 for (TypeParameterElement typeParameter in _typeElement.typeParameters) { | 4346 for (TypeParameterElement typeParameter in _typeElement.typeParameters) { |
| 4347 typeParameterScope.define(typeParameter); | 4347 typeParameterScope.define(typeParameter); |
| 4348 } | 4348 } |
| 4349 } | 4349 } |
| 4350 } | 4350 } |
| 4351 | 4351 |
| 4352 /** | 4352 /** |
| 4353 * A visitor that visits ASTs and fills [UsedImportedElements]. |
| 4354 */ |
| 4355 class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor { |
| 4356 final LibraryElement library; |
| 4357 final UsedImportedElements usedElements = new UsedImportedElements(); |
| 4358 |
| 4359 GatherUsedImportedElementsVisitor(this.library); |
| 4360 |
| 4361 @override |
| 4362 void visitExportDirective(ExportDirective node) { |
| 4363 _visitMetadata(node.metadata); |
| 4364 } |
| 4365 |
| 4366 @override |
| 4367 void visitImportDirective(ImportDirective node) { |
| 4368 _visitMetadata(node.metadata); |
| 4369 } |
| 4370 |
| 4371 @override |
| 4372 void visitLibraryDirective(LibraryDirective node) { |
| 4373 _visitMetadata(node.metadata); |
| 4374 } |
| 4375 |
| 4376 @override |
| 4377 void visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 4378 // If the prefixed identifier references some A.B, where A is a library |
| 4379 // prefix, then we can lookup the associated ImportDirective in |
| 4380 // prefixElementMap and remove it from the unusedImports list. |
| 4381 SimpleIdentifier prefixIdentifier = node.prefix; |
| 4382 Element element = prefixIdentifier.staticElement; |
| 4383 if (element is PrefixElement) { |
| 4384 usedElements.prefixes.add(element); |
| 4385 return; |
| 4386 } |
| 4387 // Otherwise, pass the prefixed identifier element and name onto |
| 4388 // visitIdentifier. |
| 4389 _visitIdentifier(element, prefixIdentifier.name); |
| 4390 } |
| 4391 |
| 4392 @override |
| 4393 void visitSimpleIdentifier(SimpleIdentifier node) { |
| 4394 _visitIdentifier(node.staticElement, node.name); |
| 4395 } |
| 4396 |
| 4397 void _visitIdentifier(Element element, String name) { |
| 4398 if (element == null) { |
| 4399 return; |
| 4400 } |
| 4401 // If the element is multiply defined then call this method recursively for |
| 4402 // each of the conflicting elements. |
| 4403 if (element is MultiplyDefinedElement) { |
| 4404 MultiplyDefinedElement multiplyDefinedElement = element; |
| 4405 for (Element elt in multiplyDefinedElement.conflictingElements) { |
| 4406 _visitIdentifier(elt, name); |
| 4407 } |
| 4408 return; |
| 4409 } else if (element is PrefixElement) { |
| 4410 usedElements.prefixes.add(element); |
| 4411 return; |
| 4412 } else if (element.enclosingElement is! CompilationUnitElement) { |
| 4413 // Identifiers that aren't a prefix element and whose enclosing element |
| 4414 // isn't a CompilationUnit are ignored- this covers the case the |
| 4415 // identifier is a relative-reference, a reference to an identifier not |
| 4416 // imported by this library. |
| 4417 return; |
| 4418 } |
| 4419 // Ignore if an unknown library. |
| 4420 LibraryElement containingLibrary = element.library; |
| 4421 if (containingLibrary == null) { |
| 4422 return; |
| 4423 } |
| 4424 // Ignore if a local element. |
| 4425 if (library == containingLibrary) { |
| 4426 return; |
| 4427 } |
| 4428 // Remember the element. |
| 4429 usedElements.elements.add(element); |
| 4430 } |
| 4431 |
| 4432 /** |
| 4433 * Given some [NodeList] of [Annotation]s, ensure that the identifiers are vis
ited by |
| 4434 * this visitor. Specifically, this covers the cases where AST nodes don't hav
e their identifiers |
| 4435 * visited by this visitor, but still need their annotations visited. |
| 4436 * |
| 4437 * @param annotations the list of annotations to visit |
| 4438 */ |
| 4439 void _visitMetadata(NodeList<Annotation> annotations) { |
| 4440 int count = annotations.length; |
| 4441 for (int i = 0; i < count; i++) { |
| 4442 annotations[i].accept(this); |
| 4443 } |
| 4444 } |
| 4445 } |
| 4446 |
| 4447 /** |
| 4353 * An [AstVisitor] that fills [UsedLocalElements]. | 4448 * An [AstVisitor] that fills [UsedLocalElements]. |
| 4354 */ | 4449 */ |
| 4355 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor { | 4450 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor { |
| 4356 final UsedLocalElements usedElements = new UsedLocalElements(); | 4451 final UsedLocalElements usedElements = new UsedLocalElements(); |
| 4357 | 4452 |
| 4358 final LibraryElement _enclosingLibrary; | 4453 final LibraryElement _enclosingLibrary; |
| 4359 ClassElement _enclosingClass; | 4454 ClassElement _enclosingClass; |
| 4360 ExecutableElement _enclosingExec; | 4455 ExecutableElement _enclosingExec; |
| 4361 | 4456 |
| 4362 GatherUsedLocalElementsVisitor(this._enclosingLibrary); | 4457 GatherUsedLocalElementsVisitor(this._enclosingLibrary); |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4510 */ | 4605 */ |
| 4511 class HintGenerator { | 4606 class HintGenerator { |
| 4512 final List<CompilationUnit> _compilationUnits; | 4607 final List<CompilationUnit> _compilationUnits; |
| 4513 | 4608 |
| 4514 final InternalAnalysisContext _context; | 4609 final InternalAnalysisContext _context; |
| 4515 | 4610 |
| 4516 final AnalysisErrorListener _errorListener; | 4611 final AnalysisErrorListener _errorListener; |
| 4517 | 4612 |
| 4518 LibraryElement _library; | 4613 LibraryElement _library; |
| 4519 | 4614 |
| 4520 ImportsVerifier _importsVerifier; | 4615 GatherUsedImportedElementsVisitor _usedImportedElementsVisitor; |
| 4521 | 4616 |
| 4522 bool _enableDart2JSHints = false; | 4617 bool _enableDart2JSHints = false; |
| 4523 | 4618 |
| 4524 /** | 4619 /** |
| 4525 * The inheritance manager used to find overridden methods. | 4620 * The inheritance manager used to find overridden methods. |
| 4526 */ | 4621 */ |
| 4527 InheritanceManager _manager; | 4622 InheritanceManager _manager; |
| 4528 | 4623 |
| 4529 GatherUsedLocalElementsVisitor _usedElementsVisitor; | 4624 GatherUsedLocalElementsVisitor _usedLocalElementsVisitor; |
| 4530 | 4625 |
| 4531 HintGenerator(this._compilationUnits, this._context, this._errorListener) { | 4626 HintGenerator(this._compilationUnits, this._context, this._errorListener) { |
| 4532 _library = _compilationUnits[0].element.library; | 4627 _library = _compilationUnits[0].element.library; |
| 4533 _importsVerifier = new ImportsVerifier(_library); | 4628 _usedImportedElementsVisitor = |
| 4629 new GatherUsedImportedElementsVisitor(_library); |
| 4534 _enableDart2JSHints = _context.analysisOptions.dart2jsHint; | 4630 _enableDart2JSHints = _context.analysisOptions.dart2jsHint; |
| 4535 _manager = new InheritanceManager(_compilationUnits[0].element.library); | 4631 _manager = new InheritanceManager(_compilationUnits[0].element.library); |
| 4536 _usedElementsVisitor = new GatherUsedLocalElementsVisitor(_library); | 4632 _usedLocalElementsVisitor = new GatherUsedLocalElementsVisitor(_library); |
| 4537 } | 4633 } |
| 4538 | 4634 |
| 4539 void generateForLibrary() { | 4635 void generateForLibrary() { |
| 4540 PerformanceStatistics.hints.makeCurrentWhile(() { | 4636 PerformanceStatistics.hints.makeCurrentWhile(() { |
| 4541 for (int i = 0; i < _compilationUnits.length; i++) { | 4637 for (CompilationUnit unit in _compilationUnits) { |
| 4542 CompilationUnitElement element = _compilationUnits[i].element; | 4638 CompilationUnitElement element = unit.element; |
| 4543 if (element != null) { | 4639 if (element != null) { |
| 4544 if (i == 0) { | 4640 _generateForCompilationUnit(unit, element.source); |
| 4545 _importsVerifier.inDefiningCompilationUnit = true; | |
| 4546 _generateForCompilationUnit(_compilationUnits[i], element.source); | |
| 4547 _importsVerifier.inDefiningCompilationUnit = false; | |
| 4548 } else { | |
| 4549 _generateForCompilationUnit(_compilationUnits[i], element.source); | |
| 4550 } | |
| 4551 } | 4641 } |
| 4552 } | 4642 } |
| 4553 ErrorReporter definingCompilationUnitErrorReporter = new ErrorReporter( | 4643 CompilationUnit definingUnit = _compilationUnits[0]; |
| 4554 _errorListener, _compilationUnits[0].element.source); | 4644 ErrorReporter definingUnitErrorReporter = |
| 4555 _importsVerifier | 4645 new ErrorReporter(_errorListener, definingUnit.element.source); |
| 4556 .generateDuplicateImportHints(definingCompilationUnitErrorReporter); | 4646 { |
| 4557 _importsVerifier | 4647 ImportsVerifier importsVerifier = new ImportsVerifier(); |
| 4558 .generateUnusedImportHints(definingCompilationUnitErrorReporter); | 4648 importsVerifier.addImports(definingUnit); |
| 4649 importsVerifier |
| 4650 .removeUsedElements(_usedImportedElementsVisitor.usedElements); |
| 4651 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter); |
| 4652 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter); |
| 4653 } |
| 4559 _library.accept(new UnusedLocalElementsVerifier( | 4654 _library.accept(new UnusedLocalElementsVerifier( |
| 4560 _errorListener, _usedElementsVisitor.usedElements)); | 4655 _errorListener, _usedLocalElementsVisitor.usedElements)); |
| 4561 }); | 4656 }); |
| 4562 } | 4657 } |
| 4563 | 4658 |
| 4564 void _generateForCompilationUnit(CompilationUnit unit, Source source) { | 4659 void _generateForCompilationUnit(CompilationUnit unit, Source source) { |
| 4565 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); | 4660 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); |
| 4566 unit.accept(_importsVerifier); | 4661 unit.accept(_usedImportedElementsVisitor); |
| 4567 // dead code analysis | 4662 // dead code analysis |
| 4568 unit.accept(new DeadCodeVerifier(errorReporter)); | 4663 unit.accept(new DeadCodeVerifier(errorReporter)); |
| 4569 unit.accept(_usedElementsVisitor); | 4664 unit.accept(_usedLocalElementsVisitor); |
| 4570 // dart2js analysis | 4665 // dart2js analysis |
| 4571 if (_enableDart2JSHints) { | 4666 if (_enableDart2JSHints) { |
| 4572 unit.accept(new Dart2JSVerifier(errorReporter)); | 4667 unit.accept(new Dart2JSVerifier(errorReporter)); |
| 4573 } | 4668 } |
| 4574 // Dart best practices | 4669 // Dart best practices |
| 4575 unit.accept( | 4670 unit.accept( |
| 4576 new BestPracticesVerifier(errorReporter, _context.typeProvider)); | 4671 new BestPracticesVerifier(errorReporter, _context.typeProvider)); |
| 4577 unit.accept(new OverrideVerifier(errorReporter, _manager)); | 4672 unit.accept(new OverrideVerifier(errorReporter, _manager)); |
| 4578 // Find to-do comments | 4673 // Find to-do comments |
| 4579 new ToDoFinder(errorReporter).findIn(unit); | 4674 new ToDoFinder(errorReporter).findIn(unit); |
| (...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5343 | 5438 |
| 5344 /** | 5439 /** |
| 5345 * Instances of the class `ImportsVerifier` visit all of the referenced librarie
s in the | 5440 * Instances of the class `ImportsVerifier` visit all of the referenced librarie
s in the |
| 5346 * source code verifying that all of the imports are used, otherwise a | 5441 * source code verifying that all of the imports are used, otherwise a |
| 5347 * [HintCode.UNUSED_IMPORT] is generated with | 5442 * [HintCode.UNUSED_IMPORT] is generated with |
| 5348 * [generateUnusedImportHints]. | 5443 * [generateUnusedImportHints]. |
| 5349 * | 5444 * |
| 5350 * While this class does not yet have support for an "Organize Imports" action,
this logic built up | 5445 * While this class does not yet have support for an "Organize Imports" action,
this logic built up |
| 5351 * in this class could be used for such an action in the future. | 5446 * in this class could be used for such an action in the future. |
| 5352 */ | 5447 */ |
| 5353 class ImportsVerifier extends RecursiveAstVisitor<Object> { | 5448 class ImportsVerifier /*extends RecursiveAstVisitor<Object>*/ { |
| 5354 /** | |
| 5355 * This is set to `true` if the current compilation unit which is being visite
d is the | |
| 5356 * defining compilation unit for the library, its value can be set with | |
| 5357 * [setInDefiningCompilationUnit]. | |
| 5358 */ | |
| 5359 bool _inDefiningCompilationUnit = false; | |
| 5360 | |
| 5361 /** | |
| 5362 * The current library. | |
| 5363 */ | |
| 5364 LibraryElement _currentLibrary; | |
| 5365 | |
| 5366 /** | 5449 /** |
| 5367 * A list of [ImportDirective]s that the current library imports, as identifie
rs are visited | 5450 * A list of [ImportDirective]s that the current library imports, as identifie
rs are visited |
| 5368 * by this visitor and an import has been identified as being used by the libr
ary, the | 5451 * by this visitor and an import has been identified as being used by the libr
ary, the |
| 5369 * [ImportDirective] is removed from this list. After all the sources in the l
ibrary have | 5452 * [ImportDirective] is removed from this list. After all the sources in the l
ibrary have |
| 5370 * been evaluated, this list represents the set of unused imports. | 5453 * been evaluated, this list represents the set of unused imports. |
| 5371 * | 5454 * |
| 5372 * See [ImportsVerifier.generateUnusedImportErrors]. | 5455 * See [ImportsVerifier.generateUnusedImportErrors]. |
| 5373 */ | 5456 */ |
| 5374 List<ImportDirective> _unusedImports; | 5457 final List<ImportDirective> _unusedImports = <ImportDirective>[]; |
| 5375 | 5458 |
| 5376 /** | 5459 /** |
| 5377 * After the list of [unusedImports] has been computed, this list is a proper
subset of the | 5460 * After the list of [unusedImports] has been computed, this list is a proper
subset of the |
| 5378 * unused imports that are listed more than once. | 5461 * unused imports that are listed more than once. |
| 5379 */ | 5462 */ |
| 5380 List<ImportDirective> _duplicateImports; | 5463 final List<ImportDirective> _duplicateImports = <ImportDirective>[]; |
| 5381 | 5464 |
| 5382 /** | 5465 /** |
| 5383 * This is a map between the set of [LibraryElement]s that the current library
imports, and | 5466 * This is a map between the set of [LibraryElement]s that the current library
imports, and |
| 5384 * a list of [ImportDirective]s that imports the library. In cases where the c
urrent library | 5467 * a list of [ImportDirective]s that imports the library. In cases where the c
urrent library |
| 5385 * imports a library with a single directive (such as `import lib1.dart;`), th
e library | 5468 * imports a library with a single directive (such as `import lib1.dart;`), th
e library |
| 5386 * element will map to a list of one [ImportDirective], which will then be rem
oved from the | 5469 * element will map to a list of one [ImportDirective], which will then be rem
oved from the |
| 5387 * [unusedImports] list. In cases where the current library imports a library
with multiple | 5470 * [unusedImports] list. In cases where the current library imports a library
with multiple |
| 5388 * directives (such as `import lib1.dart; import lib1.dart show C;`), the | 5471 * directives (such as `import lib1.dart; import lib1.dart show C;`), the |
| 5389 * [LibraryElement] will be mapped to a list of the import directives, and the
namespace | 5472 * [LibraryElement] will be mapped to a list of the import directives, and the
namespace |
| 5390 * will need to be used to compute the correct [ImportDirective] being used, s
ee | 5473 * will need to be used to compute the correct [ImportDirective] being used, s
ee |
| 5391 * [namespaceMap]. | 5474 * [namespaceMap]. |
| 5392 */ | 5475 */ |
| 5393 HashMap<LibraryElement, List<ImportDirective>> _libraryMap; | 5476 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap = |
| 5477 new HashMap<LibraryElement, List<ImportDirective>>(); |
| 5394 | 5478 |
| 5395 /** | 5479 /** |
| 5396 * In cases where there is more than one import directive per library element,
this mapping is | 5480 * In cases where there is more than one import directive per library element,
this mapping is |
| 5397 * used to determine which of the multiple import directives are used by gener
ating a | 5481 * used to determine which of the multiple import directives are used by gener
ating a |
| 5398 * [Namespace] for each of the imports to do lookups in the same way that they
are done from | 5482 * [Namespace] for each of the imports to do lookups in the same way that they
are done from |
| 5399 * the [ElementResolver]. | 5483 * the [ElementResolver]. |
| 5400 */ | 5484 */ |
| 5401 HashMap<ImportDirective, Namespace> _namespaceMap; | 5485 final HashMap<ImportDirective, Namespace> _namespaceMap = |
| 5486 new HashMap<ImportDirective, Namespace>(); |
| 5402 | 5487 |
| 5403 /** | 5488 /** |
| 5404 * This is a map between prefix elements and the import directives from which
they are derived. In | 5489 * This is a map between prefix elements and the import directives from which
they are derived. In |
| 5405 * cases where a type is referenced via a prefix element, the import directive
can be marked as | 5490 * cases where a type is referenced via a prefix element, the import directive
can be marked as |
| 5406 * used (removed from the unusedImports) by looking at the resolved `lib` in `
lib.X`, | 5491 * used (removed from the unusedImports) by looking at the resolved `lib` in `
lib.X`, |
| 5407 * instead of looking at which library the `lib.X` resolves. | 5492 * instead of looking at which library the `lib.X` resolves. |
| 5408 * | 5493 * |
| 5409 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl
ement], | 5494 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl
ement], |
| 5410 * it is possible to have an unreported unused import in situations where two
imports use the same | 5495 * it is possible to have an unreported unused import in situations where two
imports use the same |
| 5411 * prefix and at least one import directive is used. | 5496 * prefix and at least one import directive is used. |
| 5412 */ | 5497 */ |
| 5413 HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap; | 5498 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap = |
| 5499 new HashMap<PrefixElement, List<ImportDirective>>(); |
| 5414 | 5500 |
| 5415 /** | 5501 void addImports(CompilationUnit node) { |
| 5416 * Create a new instance of the [ImportsVerifier]. | 5502 for (Directive directive in node.directives) { |
| 5417 * | 5503 if (directive is ImportDirective) { |
| 5418 * @param errorReporter the error reporter | 5504 ImportDirective importDirective = directive; |
| 5419 */ | 5505 LibraryElement libraryElement = importDirective.uriElement; |
| 5420 ImportsVerifier(LibraryElement library) { | 5506 if (libraryElement != null) { |
| 5421 this._currentLibrary = library; | 5507 _unusedImports.add(importDirective); |
| 5422 this._unusedImports = new List<ImportDirective>(); | 5508 // |
| 5423 this._duplicateImports = new List<ImportDirective>(); | 5509 // Initialize prefixElementMap |
| 5424 this._libraryMap = new HashMap<LibraryElement, List<ImportDirective>>(); | 5510 // |
| 5425 this._namespaceMap = new HashMap<ImportDirective, Namespace>(); | 5511 if (importDirective.asKeyword != null) { |
| 5426 this._prefixElementMap = | 5512 SimpleIdentifier prefixIdentifier = importDirective.prefix; |
| 5427 new HashMap<PrefixElement, List<ImportDirective>>(); | 5513 if (prefixIdentifier != null) { |
| 5428 } | 5514 Element element = prefixIdentifier.staticElement; |
| 5429 | 5515 if (element is PrefixElement) { |
| 5430 void set inDefiningCompilationUnit(bool inDefiningCompilationUnit) { | 5516 PrefixElement prefixElementKey = element; |
| 5431 this._inDefiningCompilationUnit = inDefiningCompilationUnit; | 5517 List<ImportDirective> list = |
| 5518 _prefixElementMap[prefixElementKey]; |
| 5519 if (list == null) { |
| 5520 list = new List<ImportDirective>(); |
| 5521 _prefixElementMap[prefixElementKey] = list; |
| 5522 } |
| 5523 list.add(importDirective); |
| 5524 } |
| 5525 // TODO (jwren) Can the element ever not be a PrefixElement? |
| 5526 } |
| 5527 } |
| 5528 // |
| 5529 // Initialize libraryMap: libraryElement -> importDirective |
| 5530 // |
| 5531 _putIntoLibraryMap(libraryElement, importDirective); |
| 5532 // |
| 5533 // For this new addition to the libraryMap, also recursively add any |
| 5534 // exports from the libraryElement. |
| 5535 // |
| 5536 _addAdditionalLibrariesForExports( |
| 5537 libraryElement, importDirective, new List<LibraryElement>()); |
| 5538 } |
| 5539 } |
| 5540 } |
| 5541 if (_unusedImports.length > 1) { |
| 5542 // order the list of unusedImports to find duplicates in faster than |
| 5543 // O(n^2) time |
| 5544 List<ImportDirective> importDirectiveArray = |
| 5545 new List<ImportDirective>.from(_unusedImports); |
| 5546 importDirectiveArray.sort(ImportDirective.COMPARATOR); |
| 5547 ImportDirective currentDirective = importDirectiveArray[0]; |
| 5548 for (int i = 1; i < importDirectiveArray.length; i++) { |
| 5549 ImportDirective nextDirective = importDirectiveArray[i]; |
| 5550 if (ImportDirective.COMPARATOR(currentDirective, nextDirective) == 0) { |
| 5551 // Add either the currentDirective or nextDirective depending on which |
| 5552 // comes second, this guarantees that the first of the duplicates |
| 5553 // won't be highlighted. |
| 5554 if (currentDirective.offset < nextDirective.offset) { |
| 5555 _duplicateImports.add(nextDirective); |
| 5556 } else { |
| 5557 _duplicateImports.add(currentDirective); |
| 5558 } |
| 5559 } |
| 5560 currentDirective = nextDirective; |
| 5561 } |
| 5562 } |
| 5432 } | 5563 } |
| 5433 | 5564 |
| 5434 /** | 5565 /** |
| 5435 * Any time after the defining compilation unit has been visited by this visit
or, this method can | 5566 * Any time after the defining compilation unit has been visited by this visit
or, this method can |
| 5436 * be called to report an [HintCode.DUPLICATE_IMPORT] hint for each of the imp
ort directives | 5567 * be called to report an [HintCode.DUPLICATE_IMPORT] hint for each of the imp
ort directives |
| 5437 * in the [duplicateImports] list. | 5568 * in the [duplicateImports] list. |
| 5438 * | 5569 * |
| 5439 * @param errorReporter the error reporter to report the set of [HintCode.DUPL
ICATE_IMPORT] | 5570 * @param errorReporter the error reporter to report the set of [HintCode.DUPL
ICATE_IMPORT] |
| 5440 * hints to | 5571 * hints to |
| 5441 */ | 5572 */ |
| (...skipping 20 matching lines...) Expand all Loading... |
| 5462 LibraryElement libraryElement = importElement.importedLibrary; | 5593 LibraryElement libraryElement = importElement.importedLibrary; |
| 5463 if (libraryElement != null && libraryElement.isDartCore) { | 5594 if (libraryElement != null && libraryElement.isDartCore) { |
| 5464 continue; | 5595 continue; |
| 5465 } | 5596 } |
| 5466 } | 5597 } |
| 5467 errorReporter.reportErrorForNode( | 5598 errorReporter.reportErrorForNode( |
| 5468 HintCode.UNUSED_IMPORT, unusedImport.uri); | 5599 HintCode.UNUSED_IMPORT, unusedImport.uri); |
| 5469 } | 5600 } |
| 5470 } | 5601 } |
| 5471 | 5602 |
| 5472 @override | 5603 /** |
| 5473 Object visitCompilationUnit(CompilationUnit node) { | 5604 * Remove elements from [_unusedImports] using the given [usedElements]. |
| 5474 if (_inDefiningCompilationUnit) { | 5605 */ |
| 5475 NodeList<Directive> directives = node.directives; | 5606 void removeUsedElements(UsedImportedElements usedElements) { |
| 5476 for (Directive directive in directives) { | 5607 // Stop if all the imports are known to be used. |
| 5477 if (directive is ImportDirective) { | 5608 if (_unusedImports.isEmpty) { |
| 5478 ImportDirective importDirective = directive; | 5609 return; |
| 5479 LibraryElement libraryElement = importDirective.uriElement; | |
| 5480 if (libraryElement != null) { | |
| 5481 _unusedImports.add(importDirective); | |
| 5482 // | |
| 5483 // Initialize prefixElementMap | |
| 5484 // | |
| 5485 if (importDirective.asKeyword != null) { | |
| 5486 SimpleIdentifier prefixIdentifier = importDirective.prefix; | |
| 5487 if (prefixIdentifier != null) { | |
| 5488 Element element = prefixIdentifier.staticElement; | |
| 5489 if (element is PrefixElement) { | |
| 5490 PrefixElement prefixElementKey = element; | |
| 5491 List<ImportDirective> list = | |
| 5492 _prefixElementMap[prefixElementKey]; | |
| 5493 if (list == null) { | |
| 5494 list = new List<ImportDirective>(); | |
| 5495 _prefixElementMap[prefixElementKey] = list; | |
| 5496 } | |
| 5497 list.add(importDirective); | |
| 5498 } | |
| 5499 // TODO (jwren) Can the element ever not be a PrefixElement? | |
| 5500 } | |
| 5501 } | |
| 5502 // | |
| 5503 // Initialize libraryMap: libraryElement -> importDirective | |
| 5504 // | |
| 5505 _putIntoLibraryMap(libraryElement, importDirective); | |
| 5506 // | |
| 5507 // For this new addition to the libraryMap, also recursively add any | |
| 5508 // exports from the libraryElement. | |
| 5509 // | |
| 5510 _addAdditionalLibrariesForExports( | |
| 5511 libraryElement, importDirective, new List<LibraryElement>()); | |
| 5512 } | |
| 5513 } | |
| 5514 } | |
| 5515 } | 5610 } |
| 5516 // If there are no imports in this library, don't visit the identifiers in | 5611 // Process import prefixes. |
| 5517 // the library- there can be no unused imports. | 5612 for (PrefixElement prefix in usedElements.prefixes) { |
| 5518 if (_unusedImports.isEmpty) { | 5613 List<ImportDirective> importDirectives = _prefixElementMap[prefix]; |
| 5519 return null; | |
| 5520 } | |
| 5521 if (_unusedImports.length > 1) { | |
| 5522 // order the list of unusedImports to find duplicates in faster than | |
| 5523 // O(n^2) time | |
| 5524 List<ImportDirective> importDirectiveArray = | |
| 5525 new List.from(_unusedImports); | |
| 5526 importDirectiveArray.sort(ImportDirective.COMPARATOR); | |
| 5527 ImportDirective currentDirective = importDirectiveArray[0]; | |
| 5528 for (int i = 1; i < importDirectiveArray.length; i++) { | |
| 5529 ImportDirective nextDirective = importDirectiveArray[i]; | |
| 5530 if (ImportDirective.COMPARATOR(currentDirective, nextDirective) == 0) { | |
| 5531 // Add either the currentDirective or nextDirective depending on which | |
| 5532 // comes second, this guarantees that the first of the duplicates | |
| 5533 // won't be highlighted. | |
| 5534 if (currentDirective.offset < nextDirective.offset) { | |
| 5535 _duplicateImports.add(nextDirective); | |
| 5536 } else { | |
| 5537 _duplicateImports.add(currentDirective); | |
| 5538 } | |
| 5539 } | |
| 5540 currentDirective = nextDirective; | |
| 5541 } | |
| 5542 } | |
| 5543 return super.visitCompilationUnit(node); | |
| 5544 } | |
| 5545 | |
| 5546 @override | |
| 5547 Object visitExportDirective(ExportDirective node) { | |
| 5548 _visitMetadata(node.metadata); | |
| 5549 return null; | |
| 5550 } | |
| 5551 | |
| 5552 @override | |
| 5553 Object visitImportDirective(ImportDirective node) { | |
| 5554 _visitMetadata(node.metadata); | |
| 5555 return null; | |
| 5556 } | |
| 5557 | |
| 5558 @override | |
| 5559 Object visitLibraryDirective(LibraryDirective node) { | |
| 5560 _visitMetadata(node.metadata); | |
| 5561 return null; | |
| 5562 } | |
| 5563 | |
| 5564 @override | |
| 5565 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 5566 if (_unusedImports.isEmpty) { | |
| 5567 return null; | |
| 5568 } | |
| 5569 // If the prefixed identifier references some A.B, where A is a library | |
| 5570 // prefix, then we can lookup the associated ImportDirective in | |
| 5571 // prefixElementMap and remove it from the unusedImports list. | |
| 5572 SimpleIdentifier prefixIdentifier = node.prefix; | |
| 5573 Element element = prefixIdentifier.staticElement; | |
| 5574 if (element is PrefixElement) { | |
| 5575 List<ImportDirective> importDirectives = _prefixElementMap[element]; | |
| 5576 if (importDirectives != null) { | 5614 if (importDirectives != null) { |
| 5577 for (ImportDirective importDirective in importDirectives) { | 5615 for (ImportDirective importDirective in importDirectives) { |
| 5578 _unusedImports.remove(importDirective); | 5616 _unusedImports.remove(importDirective); |
| 5579 } | 5617 } |
| 5580 } | 5618 } |
| 5581 return null; | |
| 5582 } | 5619 } |
| 5583 // Otherwise, pass the prefixed identifier element and name onto | 5620 // Process top-level elements. |
| 5584 // visitIdentifier. | 5621 for (Element element in usedElements.elements) { |
| 5585 return _visitIdentifier(element, prefixIdentifier.name); | 5622 // Stop if all the imports are known to be used. |
| 5586 } | 5623 if (_unusedImports.isEmpty) { |
| 5587 | 5624 return; |
| 5588 @override | 5625 } |
| 5589 Object visitSimpleIdentifier(SimpleIdentifier node) { | 5626 // Prepare import directives for this library. |
| 5590 if (_unusedImports.isEmpty) { | 5627 LibraryElement library = element.library; |
| 5591 return null; | 5628 List<ImportDirective> importsLibrary = _libraryMap[library]; |
| 5629 if (importsLibrary == null) { |
| 5630 continue; |
| 5631 } |
| 5632 // If there is only one import directive for this library, then it must be |
| 5633 // the directive that this element is imported with, remove it from the |
| 5634 // unusedImports list. |
| 5635 if (importsLibrary.length == 1) { |
| 5636 ImportDirective usedImportDirective = importsLibrary[0]; |
| 5637 _unusedImports.remove(usedImportDirective); |
| 5638 continue; |
| 5639 } |
| 5640 // Otherwise, find import directives using namespaces. |
| 5641 String name = element.displayName; |
| 5642 for (ImportDirective importDirective in importsLibrary) { |
| 5643 Namespace namespace = _computeNamespace(importDirective); |
| 5644 if (namespace != null && namespace.get(name) != null) { |
| 5645 _unusedImports.remove(importDirective); |
| 5646 } |
| 5647 } |
| 5592 } | 5648 } |
| 5593 return _visitIdentifier(node.staticElement, node.name); | |
| 5594 } | 5649 } |
| 5595 | 5650 |
| 5596 /** | 5651 /** |
| 5597 * Recursively add any exported library elements into the [libraryMap]. | 5652 * Recursively add any exported library elements into the [libraryMap]. |
| 5598 */ | 5653 */ |
| 5599 void _addAdditionalLibrariesForExports(LibraryElement library, | 5654 void _addAdditionalLibrariesForExports(LibraryElement library, |
| 5600 ImportDirective importDirective, List<LibraryElement> exportPath) { | 5655 ImportDirective importDirective, List<LibraryElement> exportPath) { |
| 5601 if (exportPath.contains(library)) { | 5656 if (exportPath.contains(library)) { |
| 5602 return; | 5657 return; |
| 5603 } | 5658 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5640 */ | 5695 */ |
| 5641 void _putIntoLibraryMap( | 5696 void _putIntoLibraryMap( |
| 5642 LibraryElement libraryElement, ImportDirective importDirective) { | 5697 LibraryElement libraryElement, ImportDirective importDirective) { |
| 5643 List<ImportDirective> importList = _libraryMap[libraryElement]; | 5698 List<ImportDirective> importList = _libraryMap[libraryElement]; |
| 5644 if (importList == null) { | 5699 if (importList == null) { |
| 5645 importList = new List<ImportDirective>(); | 5700 importList = new List<ImportDirective>(); |
| 5646 _libraryMap[libraryElement] = importList; | 5701 _libraryMap[libraryElement] = importList; |
| 5647 } | 5702 } |
| 5648 importList.add(importDirective); | 5703 importList.add(importDirective); |
| 5649 } | 5704 } |
| 5650 | |
| 5651 Object _visitIdentifier(Element element, String name) { | |
| 5652 if (element == null) { | |
| 5653 return null; | |
| 5654 } | |
| 5655 // If the element is multiply defined then call this method recursively for | |
| 5656 // each of the conflicting elements. | |
| 5657 if (element is MultiplyDefinedElement) { | |
| 5658 MultiplyDefinedElement multiplyDefinedElement = element; | |
| 5659 for (Element elt in multiplyDefinedElement.conflictingElements) { | |
| 5660 _visitIdentifier(elt, name); | |
| 5661 } | |
| 5662 return null; | |
| 5663 } else if (element is PrefixElement) { | |
| 5664 List<ImportDirective> importDirectives = _prefixElementMap[element]; | |
| 5665 if (importDirectives != null) { | |
| 5666 for (ImportDirective importDirective in importDirectives) { | |
| 5667 _unusedImports.remove(importDirective); | |
| 5668 } | |
| 5669 } | |
| 5670 return null; | |
| 5671 } else if (element.enclosingElement is! CompilationUnitElement) { | |
| 5672 // Identifiers that aren't a prefix element and whose enclosing element | |
| 5673 // isn't a CompilationUnit are ignored- this covers the case the | |
| 5674 // identifier is a relative-reference, a reference to an identifier not | |
| 5675 // imported by this library. | |
| 5676 return null; | |
| 5677 } | |
| 5678 LibraryElement containingLibrary = element.library; | |
| 5679 if (containingLibrary == null) { | |
| 5680 return null; | |
| 5681 } | |
| 5682 // If the element is declared in the current library, return. | |
| 5683 if (_currentLibrary == containingLibrary) { | |
| 5684 return null; | |
| 5685 } | |
| 5686 List<ImportDirective> importsFromSameLibrary = | |
| 5687 _libraryMap[containingLibrary]; | |
| 5688 if (importsFromSameLibrary == null) { | |
| 5689 return null; | |
| 5690 } | |
| 5691 if (importsFromSameLibrary.length == 1) { | |
| 5692 // If there is only one import directive for this library, then it must be | |
| 5693 // the directive that this element is imported with, remove it from the | |
| 5694 // unusedImports list. | |
| 5695 ImportDirective usedImportDirective = importsFromSameLibrary[0]; | |
| 5696 _unusedImports.remove(usedImportDirective); | |
| 5697 } else { | |
| 5698 // Otherwise, for each of the imported directives, use the namespaceMap to | |
| 5699 for (ImportDirective importDirective in importsFromSameLibrary) { | |
| 5700 // Get the namespace for this import | |
| 5701 Namespace namespace = _computeNamespace(importDirective); | |
| 5702 if (namespace != null && namespace.get(name) != null) { | |
| 5703 _unusedImports.remove(importDirective); | |
| 5704 } | |
| 5705 } | |
| 5706 } | |
| 5707 return null; | |
| 5708 } | |
| 5709 | |
| 5710 /** | |
| 5711 * Given some [NodeList] of [Annotation]s, ensure that the identifiers are vis
ited by | |
| 5712 * this visitor. Specifically, this covers the cases where AST nodes don't hav
e their identifiers | |
| 5713 * visited by this visitor, but still need their annotations visited. | |
| 5714 * | |
| 5715 * @param annotations the list of annotations to visit | |
| 5716 */ | |
| 5717 void _visitMetadata(NodeList<Annotation> annotations) { | |
| 5718 int count = annotations.length; | |
| 5719 for (int i = 0; i < count; i++) { | |
| 5720 annotations[i].accept(this); | |
| 5721 } | |
| 5722 } | |
| 5723 } | 5705 } |
| 5724 | 5706 |
| 5725 /** | 5707 /** |
| 5726 * Instances of the class `InheritanceManager` manage the knowledge of where cla
ss members | 5708 * Instances of the class `InheritanceManager` manage the knowledge of where cla
ss members |
| 5727 * (methods, getters & setters) are inherited from. | 5709 * (methods, getters & setters) are inherited from. |
| 5728 */ | 5710 */ |
| 5729 class InheritanceManager { | 5711 class InheritanceManager { |
| 5730 /** | 5712 /** |
| 5731 * The [LibraryElement] that is managed by this manager. | 5713 * The [LibraryElement] that is managed by this manager. |
| 5732 */ | 5714 */ |
| (...skipping 9361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 15094 ErrorCode errorCode, Element element, List<Object> arguments) { | 15076 ErrorCode errorCode, Element element, List<Object> arguments) { |
| 15095 if (element != null) { | 15077 if (element != null) { |
| 15096 _errorListener.onError(new AnalysisError.con2(element.source, | 15078 _errorListener.onError(new AnalysisError.con2(element.source, |
| 15097 element.nameOffset, element.displayName.length, errorCode, | 15079 element.nameOffset, element.displayName.length, errorCode, |
| 15098 arguments)); | 15080 arguments)); |
| 15099 } | 15081 } |
| 15100 } | 15082 } |
| 15101 } | 15083 } |
| 15102 | 15084 |
| 15103 /** | 15085 /** |
| 15086 * A container with information about used imports prefixes and used imported |
| 15087 * elements. |
| 15088 */ |
| 15089 class UsedImportedElements { |
| 15090 /** |
| 15091 * The set of referenced [PrefixElement]s. |
| 15092 */ |
| 15093 final Set<PrefixElement> prefixes = new HashSet<PrefixElement>(); |
| 15094 |
| 15095 /** |
| 15096 * The set of referenced top-level [Element]s. |
| 15097 */ |
| 15098 final Set<Element> elements = new HashSet<Element>(); |
| 15099 } |
| 15100 |
| 15101 /** |
| 15104 * A container with sets of used [Element]s. | 15102 * A container with sets of used [Element]s. |
| 15105 * All these elements are defined in a single compilation unit or a library. | 15103 * All these elements are defined in a single compilation unit or a library. |
| 15106 */ | 15104 */ |
| 15107 class UsedLocalElements { | 15105 class UsedLocalElements { |
| 15108 /** | 15106 /** |
| 15109 * Resolved, locally defined elements that are used or potentially can be | 15107 * Resolved, locally defined elements that are used or potentially can be |
| 15110 * used. | 15108 * used. |
| 15111 */ | 15109 */ |
| 15112 final HashSet<Element> elements = new HashSet<Element>(); | 15110 final HashSet<Element> elements = new HashSet<Element>(); |
| 15113 | 15111 |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 15484 nonFields.add(node); | 15482 nonFields.add(node); |
| 15485 return null; | 15483 return null; |
| 15486 } | 15484 } |
| 15487 | 15485 |
| 15488 @override | 15486 @override |
| 15489 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); | 15487 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); |
| 15490 | 15488 |
| 15491 @override | 15489 @override |
| 15492 Object visitWithClause(WithClause node) => null; | 15490 Object visitWithClause(WithClause node) => null; |
| 15493 } | 15491 } |
| OLD | NEW |