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

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

Issue 1058153005: Separate imported elements gathering and imports validation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698