| 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 4540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4551 _generateForCompilationUnit(_compilationUnits[i], element.source); | 4551 _generateForCompilationUnit(_compilationUnits[i], element.source); |
| 4552 } | 4552 } |
| 4553 } | 4553 } |
| 4554 } | 4554 } |
| 4555 ErrorReporter definingCompilationUnitErrorReporter = new ErrorReporter( | 4555 ErrorReporter definingCompilationUnitErrorReporter = new ErrorReporter( |
| 4556 _errorListener, _compilationUnits[0].element.source); | 4556 _errorListener, _compilationUnits[0].element.source); |
| 4557 _importsVerifier | 4557 _importsVerifier |
| 4558 .generateDuplicateImportHints(definingCompilationUnitErrorReporter); | 4558 .generateDuplicateImportHints(definingCompilationUnitErrorReporter); |
| 4559 _importsVerifier | 4559 _importsVerifier |
| 4560 .generateUnusedImportHints(definingCompilationUnitErrorReporter); | 4560 .generateUnusedImportHints(definingCompilationUnitErrorReporter); |
| 4561 _library.accept(new _UnusedElementsVerifier( | 4561 _library.accept(new UnusedElementsVerifier( |
| 4562 _errorListener, _usedElementsVisitor.usedElements)); | 4562 _errorListener, _usedElementsVisitor.usedElements)); |
| 4563 }); | 4563 }); |
| 4564 } | 4564 } |
| 4565 | 4565 |
| 4566 void _generateForCompilationUnit(CompilationUnit unit, Source source) { | 4566 void _generateForCompilationUnit(CompilationUnit unit, Source source) { |
| 4567 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); | 4567 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); |
| 4568 unit.accept(_importsVerifier); | 4568 unit.accept(_importsVerifier); |
| 4569 // dead code analysis | 4569 // dead code analysis |
| 4570 unit.accept(new DeadCodeVerifier(errorReporter)); | 4570 unit.accept(new DeadCodeVerifier(errorReporter)); |
| 4571 unit.accept(_usedElementsVisitor); | 4571 unit.accept(_usedElementsVisitor); |
| (...skipping 10373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14945 return identical(parent.type, node); | 14945 return identical(parent.type, node); |
| 14946 } | 14946 } |
| 14947 if (parent is SimpleFormalParameter) { | 14947 if (parent is SimpleFormalParameter) { |
| 14948 return identical(parent.type, node); | 14948 return identical(parent.type, node); |
| 14949 } | 14949 } |
| 14950 return false; | 14950 return false; |
| 14951 } | 14951 } |
| 14952 } | 14952 } |
| 14953 | 14953 |
| 14954 /** | 14954 /** |
| 14955 * Instances of the class [UnusedElementsVerifier] traverse an element |
| 14956 * structure looking for cases of [HintCode.UNUSED_ELEMENT] and |
| 14957 * [HintCode.UNUSED_LOCAL_VARIABLE]. |
| 14958 */ |
| 14959 class UnusedElementsVerifier extends RecursiveElementVisitor { |
| 14960 /** |
| 14961 * The error listener to which errors will be reported. |
| 14962 */ |
| 14963 final AnalysisErrorListener _errorListener; |
| 14964 |
| 14965 /** |
| 14966 * The elements know to be used. |
| 14967 */ |
| 14968 final UsedElements _usedElements; |
| 14969 |
| 14970 /** |
| 14971 * Create a new instance of the [UnusedElementsVerifier]. |
| 14972 */ |
| 14973 UnusedElementsVerifier(this._errorListener, this._usedElements); |
| 14974 |
| 14975 @override |
| 14976 visitClassElement(ClassElement element) { |
| 14977 if (!_isUsedElement(element)) { |
| 14978 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
| 14979 element.kind.displayName, |
| 14980 element.displayName |
| 14981 ]); |
| 14982 } |
| 14983 super.visitClassElement(element); |
| 14984 } |
| 14985 |
| 14986 @override |
| 14987 visitFieldElement(FieldElement element) { |
| 14988 if (!_isReadMember(element)) { |
| 14989 _reportErrorForElement( |
| 14990 HintCode.UNUSED_FIELD, element, [element.displayName]); |
| 14991 } |
| 14992 super.visitFieldElement(element); |
| 14993 } |
| 14994 |
| 14995 @override |
| 14996 visitFunctionElement(FunctionElement element) { |
| 14997 if (!_isUsedElement(element)) { |
| 14998 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
| 14999 element.kind.displayName, |
| 15000 element.displayName |
| 15001 ]); |
| 15002 } |
| 15003 super.visitFunctionElement(element); |
| 15004 } |
| 15005 |
| 15006 @override |
| 15007 visitLocalVariableElement(LocalVariableElement element) { |
| 15008 if (!_isUsedElement(element) && !_isNamedUnderscore(element)) { |
| 15009 HintCode errorCode; |
| 15010 if (_usedElements.isCatchException(element)) { |
| 15011 errorCode = HintCode.UNUSED_CATCH_CLAUSE; |
| 15012 } else if (_usedElements.isCatchStackTrace(element)) { |
| 15013 errorCode = HintCode.UNUSED_CATCH_STACK; |
| 15014 } else { |
| 15015 errorCode = HintCode.UNUSED_LOCAL_VARIABLE; |
| 15016 } |
| 15017 _reportErrorForElement(errorCode, element, [element.displayName]); |
| 15018 } |
| 15019 } |
| 15020 |
| 15021 @override |
| 15022 visitMethodElement(MethodElement element) { |
| 15023 if (!_isUsedMember(element)) { |
| 15024 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
| 15025 element.kind.displayName, |
| 15026 element.displayName |
| 15027 ]); |
| 15028 } |
| 15029 super.visitMethodElement(element); |
| 15030 } |
| 15031 |
| 15032 @override |
| 15033 visitPropertyAccessorElement(PropertyAccessorElement element) { |
| 15034 if (!_isUsedMember(element)) { |
| 15035 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
| 15036 element.kind.displayName, |
| 15037 element.displayName |
| 15038 ]); |
| 15039 } |
| 15040 super.visitPropertyAccessorElement(element); |
| 15041 } |
| 15042 |
| 15043 bool _isNamedUnderscore(LocalVariableElement element) { |
| 15044 String name = element.name; |
| 15045 if (name != null) { |
| 15046 for (int index = name.length - 1; index >= 0; --index) { |
| 15047 if (name.codeUnitAt(index) != 0x5F) { |
| 15048 // 0x5F => '_' |
| 15049 return false; |
| 15050 } |
| 15051 } |
| 15052 return true; |
| 15053 } |
| 15054 return false; |
| 15055 } |
| 15056 |
| 15057 bool _isReadMember(Element element) { |
| 15058 if (element.isPublic) { |
| 15059 return true; |
| 15060 } |
| 15061 if (element.isSynthetic) { |
| 15062 return true; |
| 15063 } |
| 15064 return _usedElements.readMembers.contains(element.displayName); |
| 15065 } |
| 15066 |
| 15067 bool _isUsedElement(Element element) { |
| 15068 if (element.isSynthetic) { |
| 15069 return true; |
| 15070 } |
| 15071 if (element is LocalVariableElement || |
| 15072 element is FunctionElement && !element.isStatic) { |
| 15073 // local variable or function |
| 15074 } else { |
| 15075 if (element.isPublic) { |
| 15076 return true; |
| 15077 } |
| 15078 } |
| 15079 return _usedElements.elements.contains(element); |
| 15080 } |
| 15081 |
| 15082 bool _isUsedMember(Element element) { |
| 15083 if (element.isPublic) { |
| 15084 return true; |
| 15085 } |
| 15086 if (element.isSynthetic) { |
| 15087 return true; |
| 15088 } |
| 15089 if (_usedElements.members.contains(element.displayName)) { |
| 15090 return true; |
| 15091 } |
| 15092 return _usedElements.elements.contains(element); |
| 15093 } |
| 15094 |
| 15095 void _reportErrorForElement( |
| 15096 ErrorCode errorCode, Element element, List<Object> arguments) { |
| 15097 if (element != null) { |
| 15098 _errorListener.onError(new AnalysisError.con2(element.source, |
| 15099 element.nameOffset, element.displayName.length, errorCode, |
| 15100 arguments)); |
| 15101 } |
| 15102 } |
| 15103 } |
| 15104 |
| 15105 /** |
| 14955 * A container with sets of used [Element]s. | 15106 * A container with sets of used [Element]s. |
| 14956 */ | 15107 */ |
| 14957 class UsedElements { | 15108 class UsedElements { |
| 14958 /** | 15109 /** |
| 14959 * Resolved, locally defined elements that are used or potentially can be | 15110 * Resolved, locally defined elements that are used or potentially can be |
| 14960 * used. | 15111 * used. |
| 14961 */ | 15112 */ |
| 14962 final HashSet<Element> elements = new HashSet<Element>(); | 15113 final HashSet<Element> elements = new HashSet<Element>(); |
| 14963 | 15114 |
| 14964 /** | 15115 /** |
| (...skipping 13 matching lines...) Expand all Loading... |
| 14978 * library. | 15129 * library. |
| 14979 */ | 15130 */ |
| 14980 final HashSet<String> members = new HashSet<String>(); | 15131 final HashSet<String> members = new HashSet<String>(); |
| 14981 | 15132 |
| 14982 /** | 15133 /** |
| 14983 * Names of resolved or unresolved class members that are read in the | 15134 * Names of resolved or unresolved class members that are read in the |
| 14984 * library. | 15135 * library. |
| 14985 */ | 15136 */ |
| 14986 final HashSet<String> readMembers = new HashSet<String>(); | 15137 final HashSet<String> readMembers = new HashSet<String>(); |
| 14987 | 15138 |
| 15139 UsedElements(); |
| 15140 |
| 15141 factory UsedElements.merge(List<UsedElements> parts) { |
| 15142 UsedElements result = new UsedElements(); |
| 15143 for (UsedElements part in parts) { |
| 15144 result.elements.addAll(part.elements); |
| 15145 result.catchExceptionElements.addAll(part.catchExceptionElements); |
| 15146 result.catchStackTraceElements.addAll(part.catchStackTraceElements); |
| 15147 result.members.addAll(part.members); |
| 15148 result.readMembers.addAll(part.readMembers); |
| 15149 } |
| 15150 return result; |
| 15151 } |
| 15152 |
| 14988 void addCatchException(LocalVariableElement element) { | 15153 void addCatchException(LocalVariableElement element) { |
| 14989 if (element != null) { | 15154 if (element != null) { |
| 14990 catchExceptionElements.add(element); | 15155 catchExceptionElements.add(element); |
| 14991 } | 15156 } |
| 14992 } | 15157 } |
| 14993 | 15158 |
| 14994 void addCatchStackTrace(LocalVariableElement element) { | 15159 void addCatchStackTrace(LocalVariableElement element) { |
| 14995 if (element != null) { | 15160 if (element != null) { |
| 14996 catchStackTraceElements.add(element); | 15161 catchStackTraceElements.add(element); |
| 14997 } | 15162 } |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 15320 nonFields.add(node); | 15485 nonFields.add(node); |
| 15321 return null; | 15486 return null; |
| 15322 } | 15487 } |
| 15323 | 15488 |
| 15324 @override | 15489 @override |
| 15325 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); | 15490 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); |
| 15326 | 15491 |
| 15327 @override | 15492 @override |
| 15328 Object visitWithClause(WithClause node) => null; | 15493 Object visitWithClause(WithClause node) => null; |
| 15329 } | 15494 } |
| 15330 | |
| 15331 /** | |
| 15332 * Instances of the class [_UnusedElementsVerifier] traverse an element | |
| 15333 * structure looking for cases of [HintCode.UNUSED_ELEMENT] and | |
| 15334 * [HintCode.UNUSED_LOCAL_VARIABLE]. | |
| 15335 */ | |
| 15336 class _UnusedElementsVerifier extends RecursiveElementVisitor { | |
| 15337 /** | |
| 15338 * The error listener to which errors will be reported. | |
| 15339 */ | |
| 15340 final AnalysisErrorListener _errorListener; | |
| 15341 | |
| 15342 /** | |
| 15343 * The elements know to be used. | |
| 15344 */ | |
| 15345 final UsedElements _usedElements; | |
| 15346 | |
| 15347 /** | |
| 15348 * Create a new instance of the [_UnusedElementsVerifier]. | |
| 15349 */ | |
| 15350 _UnusedElementsVerifier(this._errorListener, this._usedElements); | |
| 15351 | |
| 15352 @override | |
| 15353 visitClassElement(ClassElement element) { | |
| 15354 if (!_isUsedElement(element)) { | |
| 15355 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ | |
| 15356 element.kind.displayName, | |
| 15357 element.displayName | |
| 15358 ]); | |
| 15359 } | |
| 15360 super.visitClassElement(element); | |
| 15361 } | |
| 15362 | |
| 15363 @override | |
| 15364 visitFieldElement(FieldElement element) { | |
| 15365 if (!_isReadMember(element)) { | |
| 15366 _reportErrorForElement( | |
| 15367 HintCode.UNUSED_FIELD, element, [element.displayName]); | |
| 15368 } | |
| 15369 super.visitFieldElement(element); | |
| 15370 } | |
| 15371 | |
| 15372 @override | |
| 15373 visitFunctionElement(FunctionElement element) { | |
| 15374 if (!_isUsedElement(element)) { | |
| 15375 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ | |
| 15376 element.kind.displayName, | |
| 15377 element.displayName | |
| 15378 ]); | |
| 15379 } | |
| 15380 super.visitFunctionElement(element); | |
| 15381 } | |
| 15382 | |
| 15383 @override | |
| 15384 visitLocalVariableElement(LocalVariableElement element) { | |
| 15385 if (!_isUsedElement(element) && !_isNamedUnderscore(element)) { | |
| 15386 HintCode errorCode; | |
| 15387 if (_usedElements.isCatchException(element)) { | |
| 15388 errorCode = HintCode.UNUSED_CATCH_CLAUSE; | |
| 15389 } else if (_usedElements.isCatchStackTrace(element)) { | |
| 15390 errorCode = HintCode.UNUSED_CATCH_STACK; | |
| 15391 } else { | |
| 15392 errorCode = HintCode.UNUSED_LOCAL_VARIABLE; | |
| 15393 } | |
| 15394 _reportErrorForElement(errorCode, element, [element.displayName]); | |
| 15395 } | |
| 15396 } | |
| 15397 | |
| 15398 @override | |
| 15399 visitMethodElement(MethodElement element) { | |
| 15400 if (!_isUsedMember(element)) { | |
| 15401 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ | |
| 15402 element.kind.displayName, | |
| 15403 element.displayName | |
| 15404 ]); | |
| 15405 } | |
| 15406 super.visitMethodElement(element); | |
| 15407 } | |
| 15408 | |
| 15409 @override | |
| 15410 visitPropertyAccessorElement(PropertyAccessorElement element) { | |
| 15411 if (!_isUsedMember(element)) { | |
| 15412 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ | |
| 15413 element.kind.displayName, | |
| 15414 element.displayName | |
| 15415 ]); | |
| 15416 } | |
| 15417 super.visitPropertyAccessorElement(element); | |
| 15418 } | |
| 15419 | |
| 15420 bool _isNamedUnderscore(LocalVariableElement element) { | |
| 15421 String name = element.name; | |
| 15422 if (name != null) { | |
| 15423 for (int index = name.length - 1; index >= 0; --index) { | |
| 15424 if (name.codeUnitAt(index) != 0x5F) { | |
| 15425 // 0x5F => '_' | |
| 15426 return false; | |
| 15427 } | |
| 15428 } | |
| 15429 return true; | |
| 15430 } | |
| 15431 return false; | |
| 15432 } | |
| 15433 | |
| 15434 bool _isReadMember(Element element) { | |
| 15435 if (element.isPublic) { | |
| 15436 return true; | |
| 15437 } | |
| 15438 if (element.isSynthetic) { | |
| 15439 return true; | |
| 15440 } | |
| 15441 return _usedElements.readMembers.contains(element.displayName); | |
| 15442 } | |
| 15443 | |
| 15444 bool _isUsedElement(Element element) { | |
| 15445 if (element.isSynthetic) { | |
| 15446 return true; | |
| 15447 } | |
| 15448 if (element is LocalVariableElement || | |
| 15449 element is FunctionElement && !element.isStatic) { | |
| 15450 // local variable or function | |
| 15451 } else { | |
| 15452 if (element.isPublic) { | |
| 15453 return true; | |
| 15454 } | |
| 15455 } | |
| 15456 return _usedElements.elements.contains(element); | |
| 15457 } | |
| 15458 | |
| 15459 bool _isUsedMember(Element element) { | |
| 15460 if (element.isPublic) { | |
| 15461 return true; | |
| 15462 } | |
| 15463 if (element.isSynthetic) { | |
| 15464 return true; | |
| 15465 } | |
| 15466 if (_usedElements.members.contains(element.displayName)) { | |
| 15467 return true; | |
| 15468 } | |
| 15469 return _usedElements.elements.contains(element); | |
| 15470 } | |
| 15471 | |
| 15472 void _reportErrorForElement( | |
| 15473 ErrorCode errorCode, Element element, List<Object> arguments) { | |
| 15474 if (element != null) { | |
| 15475 _errorListener.onError(new AnalysisError.con2(element.source, | |
| 15476 element.nameOffset, element.displayName.length, errorCode, | |
| 15477 arguments)); | |
| 15478 } | |
| 15479 } | |
| 15480 } | |
| OLD | NEW |