| 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 computer.overrides; | 5 library computer.overrides; |
| 6 | 6 |
| 7 import 'package:analysis_server/src/collections.dart'; | 7 import 'package:analysis_server/src/collections.dart'; |
| 8 import 'package:analysis_server/src/protocol_server.dart'; | 8 import 'package:analysis_server/src/protocol_server.dart' as proto; |
| 9 import 'package:analyzer/dart/element/element.dart' as engine; | 9 import 'package:analyzer/dart/element/element.dart'; |
| 10 import 'package:analyzer/dart/element/type.dart' as engine; | 10 import 'package:analyzer/dart/element/type.dart'; |
| 11 import 'package:analyzer/src/generated/ast.dart'; | 11 import 'package:analyzer/src/generated/ast.dart'; |
| 12 | 12 |
| 13 /** | 13 /** |
| 14 * Return the elements that the given [element] overrides. |
| 15 */ |
| 16 OverriddenElements findOverriddenElements(Element element) { |
| 17 if (element?.enclosingElement is ClassElement) { |
| 18 return new _OverriddenElementsFinder(element).find(); |
| 19 } |
| 20 return new OverriddenElements(element, <Element>[], <Element>[]); |
| 21 } |
| 22 |
| 23 /** |
| 14 * A computer for class member overrides in a Dart [CompilationUnit]. | 24 * A computer for class member overrides in a Dart [CompilationUnit]. |
| 15 */ | 25 */ |
| 16 class DartUnitOverridesComputer { | 26 class DartUnitOverridesComputer { |
| 17 static const List<ElementKind> FIELD_KINDS = const <ElementKind>[ | |
| 18 ElementKind.FIELD, | |
| 19 ElementKind.GETTER, | |
| 20 ElementKind.SETTER | |
| 21 ]; | |
| 22 | |
| 23 static const List<ElementKind> GETTER_KINDS = const <ElementKind>[ | |
| 24 ElementKind.FIELD, | |
| 25 ElementKind.GETTER | |
| 26 ]; | |
| 27 | |
| 28 static const List<ElementKind> METHOD_KINDS = const <ElementKind>[ | |
| 29 ElementKind.METHOD | |
| 30 ]; | |
| 31 | |
| 32 static const List<ElementKind> SETTER_KINDS = const <ElementKind>[ | |
| 33 ElementKind.FIELD, | |
| 34 ElementKind.SETTER | |
| 35 ]; | |
| 36 | |
| 37 final CompilationUnit _unit; | 27 final CompilationUnit _unit; |
| 38 | 28 final List<proto.Override> _overrides = <proto.Override>[]; |
| 39 final List<Override> _overrides = <Override>[]; | |
| 40 engine.ClassElement _currentClass; | |
| 41 | 29 |
| 42 DartUnitOverridesComputer(this._unit); | 30 DartUnitOverridesComputer(this._unit); |
| 43 | 31 |
| 44 /** | 32 /** |
| 45 * Returns the computed occurrences, not `null`. | 33 * Returns the computed occurrences, not `null`. |
| 46 */ | 34 */ |
| 47 List<Override> compute() { | 35 List<proto.Override> compute() { |
| 48 for (CompilationUnitMember unitMember in _unit.declarations) { | 36 for (CompilationUnitMember unitMember in _unit.declarations) { |
| 49 if (unitMember is ClassDeclaration) { | 37 if (unitMember is ClassDeclaration) { |
| 50 _currentClass = unitMember.element; | |
| 51 for (ClassMember classMember in unitMember.members) { | 38 for (ClassMember classMember in unitMember.members) { |
| 52 if (classMember is MethodDeclaration) { | 39 if (classMember is MethodDeclaration) { |
| 53 if (classMember.isStatic) { | 40 if (classMember.isStatic) { |
| 54 continue; | 41 continue; |
| 55 } | 42 } |
| 56 SimpleIdentifier name = classMember.name; | 43 _addOverride(classMember.name); |
| 57 List<ElementKind> kinds; | |
| 58 if (classMember.isGetter) { | |
| 59 kinds = GETTER_KINDS; | |
| 60 } else if (classMember.isSetter) { | |
| 61 kinds = SETTER_KINDS; | |
| 62 } else { | |
| 63 kinds = METHOD_KINDS; | |
| 64 } | |
| 65 new _SingleOverrideComputer(_currentClass, name, kinds) | |
| 66 .addOverrideTo(_overrides); | |
| 67 } | 44 } |
| 68 if (classMember is FieldDeclaration) { | 45 if (classMember is FieldDeclaration) { |
| 69 if (classMember.isStatic) { | 46 if (classMember.isStatic) { |
| 70 continue; | 47 continue; |
| 71 } | 48 } |
| 72 List<VariableDeclaration> fields = classMember.fields.variables; | 49 List<VariableDeclaration> fields = classMember.fields.variables; |
| 73 for (VariableDeclaration field in fields) { | 50 for (VariableDeclaration field in fields) { |
| 74 SimpleIdentifier name = field.name; | 51 _addOverride(field.name); |
| 75 new _SingleOverrideComputer(_currentClass, name, FIELD_KINDS) | |
| 76 .addOverrideTo(_overrides); | |
| 77 } | 52 } |
| 78 } | 53 } |
| 79 } | 54 } |
| 80 } | 55 } |
| 81 } | 56 } |
| 82 return _overrides; | 57 return _overrides; |
| 83 } | 58 } |
| 59 |
| 60 /** |
| 61 * Add a new [Override] for the declaration with the given name [node]. |
| 62 */ |
| 63 void _addOverride(SimpleIdentifier node) { |
| 64 Element element = node.staticElement; |
| 65 OverriddenElements overridesResult = |
| 66 new _OverriddenElementsFinder(element).find(); |
| 67 List<Element> superElements = overridesResult.superElements; |
| 68 List<Element> interfaceElements = overridesResult.interfaceElements; |
| 69 if (superElements.isNotEmpty || interfaceElements.isNotEmpty) { |
| 70 proto.OverriddenMember superMember = superElements.isNotEmpty |
| 71 ? proto.newOverriddenMember_fromEngine(superElements.first) |
| 72 : null; |
| 73 List<proto.OverriddenMember> interfaceMembers = interfaceElements |
| 74 .map((member) => proto.newOverriddenMember_fromEngine(member)) |
| 75 .toList(); |
| 76 _overrides.add(new proto.Override(node.offset, node.length, |
| 77 superclassMember: superMember, |
| 78 interfaceMembers: nullIfEmpty(interfaceMembers))); |
| 79 } |
| 80 } |
| 84 } | 81 } |
| 85 | 82 |
| 86 /** | 83 /** |
| 87 * Computer for [Override] for a single declaration. | 84 * The container with elements that a class member overrides. |
| 88 */ | 85 */ |
| 89 class _SingleOverrideComputer { | 86 class OverriddenElements { |
| 90 final engine.LibraryElement currentLibrary; | 87 /** |
| 91 final engine.ClassElement currentClass; | 88 * The element that overrides other class members. |
| 92 final SimpleIdentifier node; | 89 */ |
| 93 final String name; | 90 final Element element; |
| 94 final List<ElementKind> kinds; | |
| 95 | |
| 96 _SingleOverrideComputer( | |
| 97 engine.ClassElement currentClass, SimpleIdentifier node, this.kinds) | |
| 98 : currentClass = currentClass, | |
| 99 currentLibrary = currentClass.library, | |
| 100 node = node, | |
| 101 name = node.name; | |
| 102 | 91 |
| 103 /** | 92 /** |
| 104 * Add a new [Override] for this declaration to the given [overrides]. | 93 * The elements that [element] overrides and which is defined in a class that |
| 94 * is a superclass of the class that defines [element]. |
| 105 */ | 95 */ |
| 106 void addOverrideTo(List<Override> overrides) { | 96 final List<Element> superElements; |
| 107 // super | 97 |
| 108 engine.Element superEngineElement; | 98 /** |
| 109 { | 99 * The elements that [element] overrides and which is defined in a class that |
| 110 engine.InterfaceType superType = currentClass.supertype; | 100 * which is implemented by the class that defines [element]. |
| 111 if (superType != null) { | 101 */ |
| 112 superEngineElement = _lookupMember(superType.element); | 102 final List<Element> interfaceElements; |
| 103 |
| 104 OverriddenElements(this.element, this.superElements, this.interfaceElements); |
| 105 } |
| 106 |
| 107 class _OverriddenElementsFinder { |
| 108 static const List<ElementKind> FIELD_KINDS = const <ElementKind>[ |
| 109 ElementKind.FIELD, |
| 110 ElementKind.GETTER, |
| 111 ElementKind.SETTER |
| 112 ]; |
| 113 |
| 114 static const List<ElementKind> GETTER_KINDS = const <ElementKind>[ |
| 115 ElementKind.FIELD, |
| 116 ElementKind.GETTER |
| 117 ]; |
| 118 |
| 119 static const List<ElementKind> METHOD_KINDS = const <ElementKind>[ |
| 120 ElementKind.METHOD |
| 121 ]; |
| 122 |
| 123 static const List<ElementKind> SETTER_KINDS = const <ElementKind>[ |
| 124 ElementKind.FIELD, |
| 125 ElementKind.SETTER |
| 126 ]; |
| 127 |
| 128 Element _seed; |
| 129 LibraryElement _library; |
| 130 ClassElement _class; |
| 131 String _name; |
| 132 List<ElementKind> _kinds; |
| 133 |
| 134 List<Element> _superElements = <Element>[]; |
| 135 List<Element> _interfaceElements = <Element>[]; |
| 136 Set<InterfaceType> _visited = new Set<InterfaceType>(); |
| 137 |
| 138 _OverriddenElementsFinder(Element seed) { |
| 139 _seed = seed; |
| 140 _class = seed.enclosingElement; |
| 141 _library = _class.library; |
| 142 _name = seed.displayName; |
| 143 if (seed is MethodElement) { |
| 144 _kinds = METHOD_KINDS; |
| 145 } else if (seed is PropertyAccessorElement) { |
| 146 _kinds = seed.isGetter ? GETTER_KINDS : SETTER_KINDS; |
| 147 } else { |
| 148 _kinds = FIELD_KINDS; |
| 149 } |
| 150 } |
| 151 |
| 152 /** |
| 153 * Add the [OverriddenElements] for this element. |
| 154 */ |
| 155 OverriddenElements find() { |
| 156 _visited.clear(); |
| 157 _addSuperOverrides(_class.supertype); |
| 158 _visited.clear(); |
| 159 _addInterfaceOverrides(_class.type, false); |
| 160 _superElements.forEach(_interfaceElements.remove); |
| 161 return new OverriddenElements(_seed, _superElements, _interfaceElements); |
| 162 } |
| 163 |
| 164 void _addInterfaceOverrides(InterfaceType type, bool checkType) { |
| 165 if (type == null) { |
| 166 return; |
| 167 } |
| 168 if (!_visited.add(type)) { |
| 169 return; |
| 170 } |
| 171 // this type |
| 172 if (checkType) { |
| 173 Element element = _lookupMember(type.element); |
| 174 if (element != null && !_interfaceElements.contains(element)) { |
| 175 _interfaceElements.add(element); |
| 113 } | 176 } |
| 114 } | 177 } |
| 115 // interfaces | 178 // interfaces |
| 116 Set<engine.Element> interfaceEngineElements = new Set<engine.Element>(); | 179 for (InterfaceType interfaceType in type.interfaces) { |
| 117 _addInterfaceOverrides(interfaceEngineElements, currentClass.type, false, | 180 _addInterfaceOverrides(interfaceType, true); |
| 118 new Set<engine.InterfaceType>()); | |
| 119 interfaceEngineElements.remove(superEngineElement); | |
| 120 // is there any override? | |
| 121 if (superEngineElement != null || interfaceEngineElements.isNotEmpty) { | |
| 122 OverriddenMember superMember = superEngineElement != null | |
| 123 ? newOverriddenMember_fromEngine(superEngineElement) | |
| 124 : null; | |
| 125 List<OverriddenMember> interfaceMembers = interfaceEngineElements | |
| 126 .map((member) => newOverriddenMember_fromEngine(member)) | |
| 127 .toList(); | |
| 128 overrides.add(new Override(node.offset, node.length, | |
| 129 superclassMember: superMember, | |
| 130 interfaceMembers: nullIfEmpty(interfaceMembers))); | |
| 131 } | 181 } |
| 182 // super |
| 183 _addInterfaceOverrides(type.superclass, checkType); |
| 132 } | 184 } |
| 133 | 185 |
| 134 void _addInterfaceOverrides( | 186 void _addSuperOverrides(InterfaceType type) { |
| 135 Set<engine.Element> elements, | |
| 136 engine.InterfaceType type, | |
| 137 bool checkType, | |
| 138 Set<engine.InterfaceType> visited) { | |
| 139 if (type == null) { | 187 if (type == null) { |
| 140 return; | 188 return; |
| 141 } | 189 } |
| 142 if (!visited.add(type)) { | 190 if (!_visited.add(type)) { |
| 143 return; | 191 return; |
| 144 } | 192 } |
| 145 // check type | 193 // this type |
| 146 if (checkType) { | 194 Element element = _lookupMember(type.element); |
| 147 engine.Element element = _lookupMember(type.element); | 195 if (element != null && !_superElements.contains(element)) { |
| 148 if (element != null) { | 196 _superElements.add(element); |
| 149 elements.add(element); | |
| 150 return; | |
| 151 } | |
| 152 } | 197 } |
| 153 // check interfaces | 198 // super |
| 154 for (engine.InterfaceType interfaceType in type.interfaces) { | 199 _addSuperOverrides(type.superclass); |
| 155 _addInterfaceOverrides(elements, interfaceType, true, visited); | |
| 156 } | |
| 157 // check super | |
| 158 _addInterfaceOverrides(elements, type.superclass, checkType, visited); | |
| 159 } | 200 } |
| 160 | 201 |
| 161 engine.Element _lookupMember(engine.ClassElement classElement) { | 202 Element _lookupMember(ClassElement classElement) { |
| 162 if (classElement == null) { | 203 if (classElement == null) { |
| 163 return null; | 204 return null; |
| 164 } | 205 } |
| 165 engine.Element member; | 206 Element member; |
| 166 // method | 207 // method |
| 167 if (kinds.contains(ElementKind.METHOD)) { | 208 if (_kinds.contains(ElementKind.METHOD)) { |
| 168 member = classElement.lookUpMethod(name, currentLibrary); | 209 member = classElement.lookUpMethod(_name, _library); |
| 169 if (member != null) { | 210 if (member != null) { |
| 170 return member; | 211 return member; |
| 171 } | 212 } |
| 172 } | 213 } |
| 173 // getter | 214 // getter |
| 174 if (kinds.contains(ElementKind.GETTER)) { | 215 if (_kinds.contains(ElementKind.GETTER)) { |
| 175 member = classElement.lookUpGetter(name, currentLibrary); | 216 member = classElement.lookUpGetter(_name, _library); |
| 176 if (member != null) { | 217 if (member != null) { |
| 177 return member; | 218 return member; |
| 178 } | 219 } |
| 179 } | 220 } |
| 180 // setter | 221 // setter |
| 181 if (kinds.contains(ElementKind.SETTER)) { | 222 if (_kinds.contains(ElementKind.SETTER)) { |
| 182 member = classElement.lookUpSetter(name + '=', currentLibrary); | 223 member = classElement.lookUpSetter(_name + '=', _library); |
| 183 if (member != null) { | 224 if (member != null) { |
| 184 return member; | 225 return member; |
| 185 } | 226 } |
| 186 } | 227 } |
| 187 // not found | 228 // not found |
| 188 return null; | 229 return null; |
| 189 } | 230 } |
| 190 } | 231 } |
| OLD | NEW |