| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library analyzer.src.generated.declaration_resolver; | 5 library analyzer.src.generated.declaration_resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | |
| 8 | |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 7 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart'; | 8 import 'package:analyzer/dart/ast/token.dart'; |
| 11 import 'package:analyzer/dart/ast/visitor.dart'; | 9 import 'package:analyzer/dart/ast/visitor.dart'; |
| 12 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
| 13 import 'package:analyzer/dart/element/visitor.dart'; | |
| 14 import 'package:analyzer/exception/exception.dart'; | 11 import 'package:analyzer/exception/exception.dart'; |
| 15 import 'package:analyzer/src/dart/element/element.dart'; | 12 import 'package:analyzer/src/dart/element/element.dart'; |
| 16 | 13 |
| 17 /** | 14 /** |
| 18 * A visitor that resolves declarations in an AST structure to already built | 15 * A visitor that resolves declarations in an AST structure to already built |
| 19 * elements. | 16 * elements. |
| 20 * | 17 * |
| 21 * The resulting AST must have everything resolved that would have been resolved | 18 * The resulting AST must have everything resolved that would have been resolved |
| 22 * by a [CompilationUnitBuilder] (that is, must be a valid [RESOLVED_UNIT1]). | 19 * by a [CompilationUnitBuilder] (that is, must be a valid [RESOLVED_UNIT1]). |
| 23 * This class must not assume that the [CompilationUnitElement] passed to it is | 20 * This class must not assume that the [CompilationUnitElement] passed to it is |
| 24 * any more complete than a [COMPILATION_UNIT_ELEMENT]. | 21 * any more complete than a [COMPILATION_UNIT_ELEMENT]. |
| 25 */ | 22 */ |
| 26 class DeclarationResolver extends RecursiveAstVisitor<Object> | 23 class DeclarationResolver extends RecursiveAstVisitor<Object> { |
| 27 with _ExistingElementResolver { | |
| 28 /** | 24 /** |
| 29 * The elements that are reachable from the compilation unit element. When a | 25 * The compilation unit containing the AST nodes being visited. |
| 30 * compilation unit has been resolved, this set should be empty. | |
| 31 */ | 26 */ |
| 32 Set<Element> _expectedElements; | 27 CompilationUnitElementImpl _enclosingUnit; |
| 33 | 28 |
| 34 /** | 29 /** |
| 35 * The function type alias containing the AST nodes being visited, or `null` | 30 * The [ElementWalker] we are using to keep track of progress through the |
| 36 * if we are not in the scope of a function type alias. | 31 * element model. |
| 37 */ | 32 */ |
| 38 FunctionTypeAliasElement _enclosingAlias; | 33 ElementWalker _walker; |
| 39 | |
| 40 /** | |
| 41 * The class containing the AST nodes being visited, or `null` if we are not | |
| 42 * in the scope of a class. | |
| 43 */ | |
| 44 ClassElement _enclosingClass; | |
| 45 | |
| 46 /** | |
| 47 * The method or function containing the AST nodes being visited, or `null` if | |
| 48 * we are not in the scope of a method or function. | |
| 49 */ | |
| 50 ExecutableElement _enclosingExecutable; | |
| 51 | |
| 52 /** | |
| 53 * The parameter containing the AST nodes being visited, or `null` if we are | |
| 54 * not in the scope of a parameter. | |
| 55 */ | |
| 56 ParameterElement _enclosingParameter; | |
| 57 | 34 |
| 58 /** | 35 /** |
| 59 * Resolve the declarations within the given compilation [unit] to the | 36 * Resolve the declarations within the given compilation [unit] to the |
| 60 * elements rooted at the given [element]. Throw an [ElementMismatchException] | 37 * elements rooted at the given [element]. Throw an [ElementMismatchException] |
| 61 * if the element model and compilation unit do not match each other. | 38 * if the element model and compilation unit do not match each other. |
| 62 */ | 39 */ |
| 63 void resolve(CompilationUnit unit, CompilationUnitElement element) { | 40 void resolve(CompilationUnit unit, CompilationUnitElement element) { |
| 64 _ElementGatherer gatherer = new _ElementGatherer(); | |
| 65 element.accept(gatherer); | |
| 66 _expectedElements = gatherer.elements; | |
| 67 _enclosingUnit = element; | 41 _enclosingUnit = element; |
| 68 _expectedElements.remove(element); | 42 _walker = new ElementWalker.forCompilationUnit(element); |
| 69 unit.element = element; | 43 unit.element = element; |
| 70 unit.accept(this); | 44 try { |
| 71 _validateResolution(); | 45 unit.accept(this); |
| 46 _walker.validate(); |
| 47 } on Error catch (e, st) { |
| 48 throw new _ElementMismatchException( |
| 49 element, _walker.element, new CaughtException(e, st)); |
| 50 } |
| 72 } | 51 } |
| 73 | 52 |
| 74 @override | 53 @override |
| 75 Object visitCatchClause(CatchClause node) { | 54 Object visitCatchClause(CatchClause node) { |
| 76 SimpleIdentifier exceptionParameter = node.exceptionParameter; | 55 SimpleIdentifier exceptionParameter = node.exceptionParameter; |
| 77 if (exceptionParameter != null) { | 56 if (exceptionParameter != null) { |
| 78 List<LocalVariableElement> localVariables = | 57 _match(exceptionParameter, _walker.getVariable()); |
| 79 _enclosingExecutable.localVariables; | |
| 80 _findIdentifier(localVariables, exceptionParameter); | |
| 81 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; | 58 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; |
| 82 if (stackTraceParameter != null) { | 59 if (stackTraceParameter != null) { |
| 83 _findIdentifier(localVariables, stackTraceParameter); | 60 _match(stackTraceParameter, _walker.getVariable()); |
| 84 } | 61 } |
| 85 } | 62 } |
| 86 return super.visitCatchClause(node); | 63 return super.visitCatchClause(node); |
| 87 } | 64 } |
| 88 | 65 |
| 89 @override | 66 @override |
| 90 Object visitClassDeclaration(ClassDeclaration node) { | 67 Object visitClassDeclaration(ClassDeclaration node) { |
| 91 ClassElement outerClass = _enclosingClass; | 68 ClassElement element = _match(node.name, _walker.getClass()); |
| 92 try { | 69 _walk(new ElementWalker.forClass(element), () { |
| 93 SimpleIdentifier className = node.name; | |
| 94 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); | |
| 95 super.visitClassDeclaration(node); | 70 super.visitClassDeclaration(node); |
| 96 _resolveMetadata(node, node.metadata, _enclosingClass); | 71 }); |
| 97 return null; | 72 _resolveMetadata(node, node.metadata, element); |
| 98 } finally { | 73 return null; |
| 99 _enclosingClass = outerClass; | |
| 100 } | |
| 101 } | 74 } |
| 102 | 75 |
| 103 @override | 76 @override |
| 104 Object visitClassTypeAlias(ClassTypeAlias node) { | 77 Object visitClassTypeAlias(ClassTypeAlias node) { |
| 105 ClassElement outerClass = _enclosingClass; | 78 ClassElement element = _match(node.name, _walker.getClass()); |
| 106 try { | 79 _walk(new ElementWalker.forClass(element), () { |
| 107 SimpleIdentifier className = node.name; | |
| 108 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); | |
| 109 super.visitClassTypeAlias(node); | 80 super.visitClassTypeAlias(node); |
| 110 _resolveMetadata(node, node.metadata, _enclosingClass); | 81 }); |
| 111 return null; | 82 _resolveMetadata(node, node.metadata, element); |
| 112 } finally { | 83 return null; |
| 113 _enclosingClass = outerClass; | |
| 114 } | |
| 115 } | 84 } |
| 116 | 85 |
| 117 @override | 86 @override |
| 118 Object visitConstructorDeclaration(ConstructorDeclaration node) { | 87 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 119 ExecutableElement outerExecutable = _enclosingExecutable; | 88 ConstructorElement element = _match(node.name, _walker.getConstructor()); |
| 120 try { | 89 _walk(new ElementWalker.forExecutable(element), () { |
| 121 SimpleIdentifier constructorName = node.name; | 90 node.element = element; |
| 122 if (constructorName == null) { | |
| 123 _enclosingExecutable = _enclosingClass.unnamedConstructor; | |
| 124 if (_enclosingExecutable == null) { | |
| 125 _mismatch('Could not find default constructor', node); | |
| 126 } | |
| 127 } else { | |
| 128 _enclosingExecutable = | |
| 129 _enclosingClass.getNamedConstructor(constructorName.name); | |
| 130 if (_enclosingExecutable == null) { | |
| 131 _mismatch( | |
| 132 'Could not find constructor element with name "${constructorName.n
ame}', | |
| 133 node); | |
| 134 } | |
| 135 constructorName.staticElement = _enclosingExecutable; | |
| 136 } | |
| 137 _expectedElements.remove(_enclosingExecutable); | |
| 138 node.element = _enclosingExecutable as ConstructorElement; | |
| 139 super.visitConstructorDeclaration(node); | 91 super.visitConstructorDeclaration(node); |
| 140 _resolveMetadata(node, node.metadata, _enclosingExecutable); | 92 }); |
| 141 return null; | 93 _resolveMetadata(node, node.metadata, element); |
| 142 } finally { | 94 return null; |
| 143 _enclosingExecutable = outerExecutable; | |
| 144 } | |
| 145 } | 95 } |
| 146 | 96 |
| 147 @override | 97 @override |
| 148 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | 98 Object visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 149 SimpleIdentifier variableName = node.identifier; | 99 VariableElement element = _match(node.identifier, _walker.getVariable()); |
| 150 Element element = | |
| 151 _findIdentifier(_enclosingExecutable.localVariables, variableName); | |
| 152 super.visitDeclaredIdentifier(node); | 100 super.visitDeclaredIdentifier(node); |
| 153 _resolveMetadata(node, node.metadata, element); | 101 _resolveMetadata(node, node.metadata, element); |
| 154 return null; | 102 return null; |
| 155 } | 103 } |
| 156 | 104 |
| 157 @override | 105 @override |
| 158 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | 106 Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 159 SimpleIdentifier parameterName = node.parameter.identifier; | 107 ParameterElement element = |
| 160 ParameterElement element = _getElementForParameter(node, parameterName); | 108 _match(node.parameter.identifier, _walker.getParameter()); |
| 161 Expression defaultValue = node.defaultValue; | 109 Expression defaultValue = node.defaultValue; |
| 162 if (defaultValue != null) { | 110 if (defaultValue != null) { |
| 163 ExecutableElement outerExecutable = _enclosingExecutable; | 111 _walk(new ElementWalker.forExecutable(element.initializer), () { |
| 164 try { | |
| 165 _enclosingExecutable = element.initializer; | |
| 166 defaultValue.accept(this); | 112 defaultValue.accept(this); |
| 167 } finally { | 113 }); |
| 168 _enclosingExecutable = outerExecutable; | |
| 169 } | |
| 170 } | 114 } |
| 171 ParameterElement outerParameter = _enclosingParameter; | 115 _walk(new ElementWalker.forParameter(element), () { |
| 172 try { | |
| 173 _enclosingParameter = element; | |
| 174 super.visitDefaultFormalParameter(node); | 116 super.visitDefaultFormalParameter(node); |
| 175 _resolveMetadata(node, node.metadata, element); | 117 }); |
| 176 return null; | 118 _resolveMetadata(node, node.metadata, element); |
| 177 } finally { | 119 return null; |
| 178 _enclosingParameter = outerParameter; | |
| 179 } | |
| 180 } | 120 } |
| 181 | 121 |
| 182 @override | 122 @override |
| 183 Object visitEnumDeclaration(EnumDeclaration node) { | 123 Object visitEnumDeclaration(EnumDeclaration node) { |
| 184 ClassElement enclosingEnum = | 124 ClassElement element = _match(node.name, _walker.getEnum()); |
| 185 _findIdentifier(_enclosingUnit.enums, node.name); | 125 _walk(new ElementWalker.forClass(element), () { |
| 186 List<FieldElement> constants = enclosingEnum.fields; | 126 for (EnumConstantDeclaration constant in node.constants) { |
| 187 for (EnumConstantDeclaration constant in node.constants) { | 127 _match(constant.name, _walker.getVariable()); |
| 188 _findIdentifier(constants, constant.name); | 128 } |
| 189 } | 129 super.visitEnumDeclaration(node); |
| 190 super.visitEnumDeclaration(node); | 130 }); |
| 191 _resolveMetadata(node, node.metadata, enclosingEnum); | 131 _resolveMetadata(node, node.metadata, element); |
| 192 return null; | 132 return null; |
| 193 } | 133 } |
| 194 | 134 |
| 195 @override | 135 @override |
| 196 Object visitExportDirective(ExportDirective node) { | 136 Object visitExportDirective(ExportDirective node) { |
| 197 super.visitExportDirective(node); | 137 super.visitExportDirective(node); |
| 198 _resolveAnnotations( | 138 _resolveAnnotations( |
| 199 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); | 139 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 200 return null; | 140 return null; |
| 201 } | 141 } |
| 202 | 142 |
| 203 @override | 143 @override |
| 204 Object visitFieldDeclaration(FieldDeclaration node) { | 144 Object visitFieldDeclaration(FieldDeclaration node) { |
| 205 super.visitFieldDeclaration(node); | 145 super.visitFieldDeclaration(node); |
| 206 _resolveMetadata(node, node.metadata, node.fields.variables[0].element); | 146 _resolveMetadata(node, node.metadata, node.fields.variables[0].element); |
| 207 return null; | 147 return null; |
| 208 } | 148 } |
| 209 | 149 |
| 210 @override | 150 @override |
| 211 Object visitFieldFormalParameter(FieldFormalParameter node) { | 151 Object visitFieldFormalParameter(FieldFormalParameter node) { |
| 212 if (node.parent is! DefaultFormalParameter) { | 152 if (node.parent is! DefaultFormalParameter) { |
| 213 SimpleIdentifier parameterName = node.identifier; | 153 ParameterElement element = |
| 214 ParameterElement element = _getElementForParameter(node, parameterName); | 154 _match(node.identifier, _walker.getParameter()); |
| 215 ParameterElement outerParameter = _enclosingParameter; | 155 _walk(new ElementWalker.forParameter(element), () { |
| 216 try { | |
| 217 _enclosingParameter = element; | |
| 218 super.visitFieldFormalParameter(node); | 156 super.visitFieldFormalParameter(node); |
| 219 _resolveMetadata(node, node.metadata, element); | 157 }); |
| 220 return null; | 158 _resolveMetadata(node, node.metadata, element); |
| 221 } finally { | 159 return null; |
| 222 _enclosingParameter = outerParameter; | |
| 223 } | |
| 224 } else { | 160 } else { |
| 225 return super.visitFieldFormalParameter(node); | 161 return super.visitFieldFormalParameter(node); |
| 226 } | 162 } |
| 227 } | 163 } |
| 228 | 164 |
| 229 @override | 165 @override |
| 230 Object visitFunctionDeclaration(FunctionDeclaration node) { | 166 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 231 ExecutableElement outerExecutable = _enclosingExecutable; | 167 SimpleIdentifier functionName = node.name; |
| 232 try { | 168 Token property = node.propertyKeyword; |
| 233 SimpleIdentifier functionName = node.name; | 169 ExecutableElement element; |
| 234 Token property = node.propertyKeyword; | 170 if (property == null) { |
| 235 if (property == null) { | 171 element = _match(functionName, _walker.getFunction()); |
| 236 if (_enclosingExecutable != null) { | 172 } else { |
| 237 _enclosingExecutable = | 173 if (_walker.element is ExecutableElement) { |
| 238 _findIdentifier(_enclosingExecutable.functions, functionName); | 174 element = _match(functionName, _walker.getFunction()); |
| 239 } else { | 175 } else if (property.keyword == Keyword.GET) { |
| 240 _enclosingExecutable = | 176 element = _match(functionName, _walker.getAccessor()); |
| 241 _findIdentifier(_enclosingUnit.functions, functionName); | |
| 242 } | |
| 243 } else { | 177 } else { |
| 244 if (_enclosingExecutable != null) { | 178 assert(property.keyword == Keyword.SET); |
| 245 _enclosingExecutable = | 179 element = _match(functionName, _walker.getAccessor(), |
| 246 _findIdentifier(_enclosingExecutable.functions, functionName); | 180 elementName: functionName.name + '='); |
| 247 } else { | |
| 248 List<PropertyAccessorElement> accessors; | |
| 249 if (_enclosingClass != null) { | |
| 250 accessors = _enclosingClass.accessors; | |
| 251 } else { | |
| 252 accessors = _enclosingUnit.accessors; | |
| 253 } | |
| 254 PropertyAccessorElement accessor; | |
| 255 if (property.keyword == Keyword.GET) { | |
| 256 accessor = _findIdentifier(accessors, functionName); | |
| 257 } else if (property.keyword == Keyword.SET) { | |
| 258 accessor = _findWithNameAndOffset(accessors, functionName, | |
| 259 functionName.name + '=', functionName.offset); | |
| 260 _expectedElements.remove(accessor); | |
| 261 functionName.staticElement = accessor; | |
| 262 } | |
| 263 _enclosingExecutable = accessor; | |
| 264 } | |
| 265 } | 181 } |
| 266 node.functionExpression.element = _enclosingExecutable; | 182 } |
| 183 node.functionExpression.element = element; |
| 184 _walk(new ElementWalker.forExecutable(element), () { |
| 267 super.visitFunctionDeclaration(node); | 185 super.visitFunctionDeclaration(node); |
| 268 _resolveMetadata(node, node.metadata, _enclosingExecutable); | 186 }); |
| 269 return null; | 187 _resolveMetadata(node, node.metadata, element); |
| 270 } finally { | 188 return null; |
| 271 _enclosingExecutable = outerExecutable; | |
| 272 } | |
| 273 } | 189 } |
| 274 | 190 |
| 275 @override | 191 @override |
| 276 Object visitFunctionExpression(FunctionExpression node) { | 192 Object visitFunctionExpression(FunctionExpression node) { |
| 277 if (node.parent is! FunctionDeclaration) { | 193 if (node.parent is! FunctionDeclaration) { |
| 278 FunctionElement element = _findAtOffset( | 194 FunctionElement element = _walker.getFunction(); |
| 279 _enclosingExecutable.functions, node, node.beginToken.offset); | |
| 280 _expectedElements.remove(element); | |
| 281 node.element = element; | 195 node.element = element; |
| 282 } | 196 _walk(new ElementWalker.forExecutable(element), () { |
| 283 ExecutableElement outerExecutable = _enclosingExecutable; | 197 super.visitFunctionExpression(node); |
| 284 try { | 198 }); |
| 285 _enclosingExecutable = node.element; | 199 return null; |
| 200 } else { |
| 286 return super.visitFunctionExpression(node); | 201 return super.visitFunctionExpression(node); |
| 287 } finally { | |
| 288 _enclosingExecutable = outerExecutable; | |
| 289 } | 202 } |
| 290 } | 203 } |
| 291 | 204 |
| 292 @override | 205 @override |
| 293 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | 206 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 294 FunctionTypeAliasElement outerAlias = _enclosingAlias; | 207 FunctionTypeAliasElement element = _match(node.name, _walker.getTypedef()); |
| 295 try { | 208 _walk(new ElementWalker.forTypedef(element), () { |
| 296 SimpleIdentifier aliasName = node.name; | |
| 297 _enclosingAlias = | |
| 298 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName); | |
| 299 super.visitFunctionTypeAlias(node); | 209 super.visitFunctionTypeAlias(node); |
| 300 _resolveMetadata(node, node.metadata, _enclosingAlias); | 210 }); |
| 301 return null; | 211 _resolveMetadata(node, node.metadata, element); |
| 302 } finally { | 212 return null; |
| 303 _enclosingAlias = outerAlias; | |
| 304 } | |
| 305 } | 213 } |
| 306 | 214 |
| 307 @override | 215 @override |
| 308 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | 216 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
| 309 if (node.parent is! DefaultFormalParameter) { | 217 if (node.parent is! DefaultFormalParameter) { |
| 310 SimpleIdentifier parameterName = node.identifier; | 218 ParameterElement element = |
| 311 ParameterElement element = _getElementForParameter(node, parameterName); | 219 _match(node.identifier, _walker.getParameter()); |
| 312 ParameterElement outerParameter = _enclosingParameter; | 220 _walk(new ElementWalker.forParameter(element), () { |
| 313 try { | |
| 314 _enclosingParameter = element; | |
| 315 super.visitFunctionTypedFormalParameter(node); | 221 super.visitFunctionTypedFormalParameter(node); |
| 316 _resolveMetadata(node, node.metadata, _enclosingParameter); | 222 }); |
| 317 return null; | 223 _resolveMetadata(node, node.metadata, element); |
| 318 } finally { | 224 return null; |
| 319 _enclosingParameter = outerParameter; | |
| 320 } | |
| 321 } else { | 225 } else { |
| 322 return super.visitFunctionTypedFormalParameter(node); | 226 return super.visitFunctionTypedFormalParameter(node); |
| 323 } | 227 } |
| 324 } | 228 } |
| 325 | 229 |
| 326 @override | 230 @override |
| 327 Object visitImportDirective(ImportDirective node) { | 231 Object visitImportDirective(ImportDirective node) { |
| 328 super.visitImportDirective(node); | 232 super.visitImportDirective(node); |
| 329 _resolveAnnotations( | 233 _resolveAnnotations( |
| 330 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); | 234 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 331 return null; | 235 return null; |
| 332 } | 236 } |
| 333 | 237 |
| 334 @override | 238 @override |
| 335 Object visitLabeledStatement(LabeledStatement node) { | 239 Object visitLabeledStatement(LabeledStatement node) { |
| 336 for (Label label in node.labels) { | 240 for (Label label in node.labels) { |
| 337 SimpleIdentifier labelName = label.label; | 241 _match(label.label, _walker.getLabel()); |
| 338 _findIdentifier(_enclosingExecutable.labels, labelName); | |
| 339 } | 242 } |
| 340 return super.visitLabeledStatement(node); | 243 return super.visitLabeledStatement(node); |
| 341 } | 244 } |
| 342 | 245 |
| 343 @override | 246 @override |
| 344 Object visitLibraryDirective(LibraryDirective node) { | 247 Object visitLibraryDirective(LibraryDirective node) { |
| 345 super.visitLibraryDirective(node); | 248 super.visitLibraryDirective(node); |
| 346 _resolveAnnotations( | 249 _resolveAnnotations( |
| 347 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); | 250 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 348 return null; | 251 return null; |
| 349 } | 252 } |
| 350 | 253 |
| 351 @override | 254 @override |
| 352 Object visitMethodDeclaration(MethodDeclaration node) { | 255 Object visitMethodDeclaration(MethodDeclaration node) { |
| 353 ExecutableElement outerExecutable = _enclosingExecutable; | 256 Token property = node.propertyKeyword; |
| 354 try { | 257 SimpleIdentifier methodName = node.name; |
| 355 Token property = node.propertyKeyword; | 258 String nameOfMethod = methodName.name; |
| 356 SimpleIdentifier methodName = node.name; | 259 ExecutableElement element; |
| 357 String nameOfMethod = methodName.name; | 260 if (property == null) { |
| 358 if (property == null) { | 261 String elementName = nameOfMethod == '-' && |
| 359 String elementName = nameOfMethod == '-' && | 262 node.parameters != null && |
| 360 node.parameters != null && | 263 node.parameters.parameters.isEmpty |
| 361 node.parameters.parameters.isEmpty | 264 ? 'unary-' |
| 362 ? 'unary-' | 265 : nameOfMethod; |
| 363 : nameOfMethod; | 266 element = |
| 364 _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods, | 267 _match(methodName, _walker.getFunction(), elementName: elementName); |
| 365 methodName, elementName, methodName.offset); | 268 } else { |
| 366 _expectedElements.remove(_enclosingExecutable); | 269 if (property.keyword == Keyword.GET) { |
| 367 methodName.staticElement = _enclosingExecutable; | 270 element = _match(methodName, _walker.getAccessor()); |
| 368 } else { | 271 } else { |
| 369 PropertyAccessorElement accessor; | 272 assert(property.keyword == Keyword.SET); |
| 370 if (property.keyword == Keyword.GET) { | 273 element = _match(methodName, _walker.getAccessor(), |
| 371 accessor = _findIdentifier(_enclosingClass.accessors, methodName); | 274 elementName: nameOfMethod + '='); |
| 372 } else if (property.keyword == Keyword.SET) { | |
| 373 accessor = _findWithNameAndOffset(_enclosingClass.accessors, | |
| 374 methodName, nameOfMethod + '=', methodName.offset); | |
| 375 _expectedElements.remove(accessor); | |
| 376 methodName.staticElement = accessor; | |
| 377 } | |
| 378 _enclosingExecutable = accessor; | |
| 379 } | 275 } |
| 276 } |
| 277 _walk(new ElementWalker.forExecutable(element), () { |
| 380 super.visitMethodDeclaration(node); | 278 super.visitMethodDeclaration(node); |
| 381 _resolveMetadata(node, node.metadata, _enclosingExecutable); | 279 }); |
| 382 return null; | 280 _resolveMetadata(node, node.metadata, element); |
| 383 } finally { | 281 return null; |
| 384 _enclosingExecutable = outerExecutable; | |
| 385 } | |
| 386 } | 282 } |
| 387 | 283 |
| 388 @override | 284 @override |
| 389 Object visitPartDirective(PartDirective node) { | 285 Object visitPartDirective(PartDirective node) { |
| 390 super.visitPartDirective(node); | 286 super.visitPartDirective(node); |
| 391 _resolveAnnotations( | 287 _resolveAnnotations( |
| 392 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); | 288 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 393 return null; | 289 return null; |
| 394 } | 290 } |
| 395 | 291 |
| 396 @override | 292 @override |
| 397 Object visitPartOfDirective(PartOfDirective node) { | 293 Object visitPartOfDirective(PartOfDirective node) { |
| 398 node.element = _enclosingUnit.library; | 294 node.element = _enclosingUnit.library; |
| 399 return super.visitPartOfDirective(node); | 295 return super.visitPartOfDirective(node); |
| 400 } | 296 } |
| 401 | 297 |
| 402 @override | 298 @override |
| 403 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | 299 Object visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 404 if (node.parent is! DefaultFormalParameter) { | 300 if (node.parent is! DefaultFormalParameter) { |
| 405 SimpleIdentifier parameterName = node.identifier; | 301 ParameterElement element = |
| 406 ParameterElement element = _getElementForParameter(node, parameterName); | 302 _match(node.identifier, _walker.getParameter()); |
| 407 ParameterElement outerParameter = _enclosingParameter; | 303 _walk(new ElementWalker.forParameter(element), () { |
| 408 try { | |
| 409 _enclosingParameter = element; | |
| 410 super.visitSimpleFormalParameter(node); | 304 super.visitSimpleFormalParameter(node); |
| 411 _resolveMetadata(node, node.metadata, element); | 305 }); |
| 412 return null; | 306 _resolveMetadata(node, node.metadata, element); |
| 413 } finally { | 307 return null; |
| 414 _enclosingParameter = outerParameter; | 308 } else { |
| 415 } | 309 return super.visitSimpleFormalParameter(node); |
| 416 } else {} | 310 } |
| 417 return super.visitSimpleFormalParameter(node); | |
| 418 } | 311 } |
| 419 | 312 |
| 420 @override | 313 @override |
| 421 Object visitSwitchCase(SwitchCase node) { | 314 Object visitSwitchCase(SwitchCase node) { |
| 422 for (Label label in node.labels) { | 315 for (Label label in node.labels) { |
| 423 SimpleIdentifier labelName = label.label; | 316 _match(label.label, _walker.getLabel()); |
| 424 _findIdentifier(_enclosingExecutable.labels, labelName); | |
| 425 } | 317 } |
| 426 return super.visitSwitchCase(node); | 318 return super.visitSwitchCase(node); |
| 427 } | 319 } |
| 428 | 320 |
| 429 @override | 321 @override |
| 430 Object visitSwitchDefault(SwitchDefault node) { | 322 Object visitSwitchDefault(SwitchDefault node) { |
| 431 for (Label label in node.labels) { | 323 for (Label label in node.labels) { |
| 432 SimpleIdentifier labelName = label.label; | 324 _match(label.label, _walker.getLabel()); |
| 433 _findIdentifier(_enclosingExecutable.labels, labelName); | |
| 434 } | 325 } |
| 435 return super.visitSwitchDefault(node); | 326 return super.visitSwitchDefault(node); |
| 436 } | 327 } |
| 437 | 328 |
| 438 @override | 329 @override |
| 439 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | 330 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 440 super.visitTopLevelVariableDeclaration(node); | 331 super.visitTopLevelVariableDeclaration(node); |
| 441 _resolveMetadata(node, node.metadata, node.variables.variables[0].element); | 332 _resolveMetadata(node, node.metadata, node.variables.variables[0].element); |
| 442 return null; | 333 return null; |
| 443 } | 334 } |
| 444 | 335 |
| 445 @override | 336 @override |
| 446 Object visitTypeParameter(TypeParameter node) { | 337 Object visitTypeParameter(TypeParameter node) { |
| 447 SimpleIdentifier parameterName = node.name; | 338 Element element = _match(node.name, _walker.getTypeParameter()); |
| 448 Element element = null; | |
| 449 if (_enclosingExecutable != null) { | |
| 450 element = _findIdentifier( | |
| 451 _enclosingExecutable.typeParameters, parameterName, | |
| 452 required: false); | |
| 453 } | |
| 454 if (element == null) { | |
| 455 if (_enclosingClass != null) { | |
| 456 element = | |
| 457 _findIdentifier(_enclosingClass.typeParameters, parameterName); | |
| 458 } else if (_enclosingAlias != null) { | |
| 459 element = | |
| 460 _findIdentifier(_enclosingAlias.typeParameters, parameterName); | |
| 461 } | |
| 462 } | |
| 463 if (element == null) { | |
| 464 String name = parameterName.name; | |
| 465 int offset = parameterName.offset; | |
| 466 _mismatch( | |
| 467 'Could not find type parameter with name "$name" at $offset', node); | |
| 468 } | |
| 469 super.visitTypeParameter(node); | 339 super.visitTypeParameter(node); |
| 470 _resolveMetadata(node, node.metadata, element); | 340 _resolveMetadata(node, node.metadata, element); |
| 471 return null; | 341 return null; |
| 472 } | 342 } |
| 473 | 343 |
| 474 @override | 344 @override |
| 475 Object visitVariableDeclaration(VariableDeclaration node) { | 345 Object visitVariableDeclaration(VariableDeclaration node) { |
| 476 VariableElement element = null; | 346 VariableElement element = _match(node.name, _walker.getVariable()); |
| 477 SimpleIdentifier variableName = node.name; | |
| 478 if (_enclosingExecutable != null) { | |
| 479 element = _findIdentifier( | |
| 480 _enclosingExecutable.localVariables, variableName, | |
| 481 required: false); | |
| 482 } | |
| 483 if (element == null && _enclosingClass != null) { | |
| 484 element = _findIdentifier(_enclosingClass.fields, variableName, | |
| 485 required: false); | |
| 486 } | |
| 487 if (element == null && _enclosingUnit != null) { | |
| 488 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName); | |
| 489 } | |
| 490 Expression initializer = node.initializer; | 347 Expression initializer = node.initializer; |
| 491 if (initializer != null) { | 348 if (initializer != null) { |
| 492 ExecutableElement outerExecutable = _enclosingExecutable; | 349 _walk(new ElementWalker.forExecutable(element.initializer), () { |
| 493 try { | 350 super.visitVariableDeclaration(node); |
| 494 _enclosingExecutable = element.initializer; | 351 }); |
| 495 return super.visitVariableDeclaration(node); | 352 return null; |
| 496 } finally { | 353 } else { |
| 497 _enclosingExecutable = outerExecutable; | 354 return super.visitVariableDeclaration(node); |
| 498 } | |
| 499 } | 355 } |
| 500 return super.visitVariableDeclaration(node); | |
| 501 } | 356 } |
| 502 | 357 |
| 503 @override | 358 @override |
| 504 Object visitVariableDeclarationList(VariableDeclarationList node) { | 359 Object visitVariableDeclarationList(VariableDeclarationList node) { |
| 505 super.visitVariableDeclarationList(node); | 360 super.visitVariableDeclarationList(node); |
| 506 if (node.parent is! FieldDeclaration && | 361 if (node.parent is! FieldDeclaration && |
| 507 node.parent is! TopLevelVariableDeclaration) { | 362 node.parent is! TopLevelVariableDeclaration) { |
| 508 _resolveMetadata(node, node.metadata, node.variables[0].element); | 363 _resolveMetadata(node, node.metadata, node.variables[0].element); |
| 509 } | 364 } |
| 510 return null; | 365 return null; |
| 511 } | 366 } |
| 512 | 367 |
| 513 /** | 368 /** |
| 514 * Return the element in the given list of [elements] that was created for the | 369 * Updates [identifier] to point to [element], after ensuring that the |
| 515 * declaration at the given [offset]. Throw an [ElementMismatchException] if | 370 * element has the expected name. |
| 516 * an element at that offset cannot be found. | |
| 517 * | 371 * |
| 518 * This method should only be used when there is no name associated with the | 372 * If no [elementName] is given, it defaults to the name of the [identifier] |
| 519 * node. | 373 * (or the empty string if [identifier] is `null`). |
| 374 * |
| 375 * If [identifier] is `null`, nothing is updated, but the element name is |
| 376 * still checked. |
| 520 */ | 377 */ |
| 521 Element _findAtOffset(List<Element> elements, AstNode node, int offset) => | 378 Element/*=E*/ _match/*<E extends Element>*/( |
| 522 _findWithNameAndOffset(elements, node, '', offset); | 379 SimpleIdentifier identifier, Element/*=E*/ element, |
| 523 | 380 {String elementName}) { |
| 524 /** | 381 elementName ??= identifier?.name ?? ''; |
| 525 * Return the element in the given list of [elements] that was created for the | 382 if (element.name != elementName) { |
| 526 * declaration with the given [identifier]. As a side-effect, associate the | 383 throw new StateError( |
| 527 * returned element with the identifier. Throw an [ElementMismatchException] | 384 'Expected an element matching `$elementName`, got `${element.name}`'); |
| 528 * if an element corresponding to the identifier cannot be found unless | 385 } |
| 529 * [required] is `false`, in which case return `null`. | 386 identifier?.staticElement = element; |
| 530 */ | |
| 531 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier, | |
| 532 {bool required: true}) { | |
| 533 Element element = _findWithNameAndOffset( | |
| 534 elements, identifier, identifier.name, identifier.offset, | |
| 535 required: required); | |
| 536 _expectedElements.remove(element); | |
| 537 identifier.staticElement = element; | |
| 538 return element; | 387 return element; |
| 539 } | 388 } |
| 540 | 389 |
| 541 /** | 390 /** |
| 542 * Return the element in the given list of [elements] that was created for the | |
| 543 * declaration with the given [name] at the given [offset]. Throw an | |
| 544 * [ElementMismatchException] if an element corresponding to the identifier | |
| 545 * cannot be found unless [required] is `false`, in which case return `null`. | |
| 546 */ | |
| 547 Element _findWithNameAndOffset( | |
| 548 List<Element> elements, AstNode node, String name, int offset, | |
| 549 {bool required: true}) { | |
| 550 int length = elements.length; | |
| 551 for (int i = 0; i < length; i++) { | |
| 552 Element element = elements[i]; | |
| 553 if (element.nameOffset == offset && element.name == name) { | |
| 554 return element; | |
| 555 } | |
| 556 } | |
| 557 if (!required) { | |
| 558 return null; | |
| 559 } | |
| 560 for (int i = 0; i < length; i++) { | |
| 561 Element element = elements[i]; | |
| 562 if (element.name == name) { | |
| 563 _mismatch( | |
| 564 'Found element with name "$name" at ${element.nameOffset}, ' | |
| 565 'but expected offset of $offset', | |
| 566 node); | |
| 567 } | |
| 568 if (element.nameOffset == offset) { | |
| 569 _mismatch( | |
| 570 'Found element with name "${element.name}" at $offset, ' | |
| 571 'but expected element with name "$name"', | |
| 572 node); | |
| 573 } | |
| 574 } | |
| 575 _mismatch('Could not find element with name "$name" at $offset', node); | |
| 576 return null; // Never reached | |
| 577 } | |
| 578 | |
| 579 /** | |
| 580 * Search the most closely enclosing list of parameter elements for a | |
| 581 * parameter, defined by the given [node], with the given [parameterName]. | |
| 582 * Return the element that was found, or throw an [ElementMismatchException] | |
| 583 * if an element corresponding to the identifier cannot be found. | |
| 584 */ | |
| 585 ParameterElement _getElementForParameter( | |
| 586 FormalParameter node, SimpleIdentifier parameterName) { | |
| 587 List<ParameterElement> parameters = null; | |
| 588 if (_enclosingParameter != null) { | |
| 589 parameters = _enclosingParameter.parameters; | |
| 590 } | |
| 591 if (parameters == null && _enclosingExecutable != null) { | |
| 592 parameters = _enclosingExecutable.parameters; | |
| 593 } | |
| 594 if (parameters == null && _enclosingAlias != null) { | |
| 595 parameters = _enclosingAlias.parameters; | |
| 596 } | |
| 597 if (parameters == null) { | |
| 598 StringBuffer buffer = new StringBuffer(); | |
| 599 buffer.writeln('Could not find parameter in enclosing scope'); | |
| 600 buffer.writeln( | |
| 601 '(_enclosingParameter == null) == ${_enclosingParameter == null}'); | |
| 602 buffer.writeln( | |
| 603 '(_enclosingExecutable == null) == ${_enclosingExecutable == null}'); | |
| 604 buffer.writeln('(_enclosingAlias == null) == ${_enclosingAlias == null}'); | |
| 605 _mismatch(buffer.toString(), parameterName); | |
| 606 } | |
| 607 return _findIdentifier(parameters, parameterName); | |
| 608 } | |
| 609 | |
| 610 /** | |
| 611 * Associate each of the annotation [nodes] with the corresponding | 391 * Associate each of the annotation [nodes] with the corresponding |
| 612 * [ElementAnnotation] in [annotations]. If there is a problem, report it | 392 * [ElementAnnotation] in [annotations]. If there is a problem, report it |
| 613 * against the given [parent] node. | 393 * against the given [parent] node. |
| 614 */ | 394 */ |
| 615 void _resolveAnnotations(AstNode parent, NodeList<Annotation> nodes, | 395 void _resolveAnnotations(AstNode parent, NodeList<Annotation> nodes, |
| 616 List<ElementAnnotation> annotations) { | 396 List<ElementAnnotation> annotations) { |
| 617 int nodeCount = nodes.length; | 397 int nodeCount = nodes.length; |
| 618 if (nodeCount != annotations.length) { | 398 if (nodeCount != annotations.length) { |
| 619 _mismatch( | 399 throw new StateError('Found $nodeCount annotation nodes and ' |
| 620 'Found $nodeCount annotation nodes and ' | 400 '${annotations.length} element annotations'); |
| 621 '${annotations.length} element annotations', | |
| 622 parent); | |
| 623 } | 401 } |
| 624 for (int i = 0; i < nodeCount; i++) { | 402 for (int i = 0; i < nodeCount; i++) { |
| 625 nodes[i].elementAnnotation = annotations[i]; | 403 nodes[i].elementAnnotation = annotations[i]; |
| 626 } | 404 } |
| 627 } | 405 } |
| 628 | 406 |
| 629 /** | 407 /** |
| 630 * If [element] is not `null`, associate each of the annotation [nodes] with | 408 * If [element] is not `null`, associate each of the annotation [nodes] with |
| 631 * the corresponding [ElementAnnotation] in [element.metadata]. If there is a | 409 * the corresponding [ElementAnnotation] in [element.metadata]. If there is a |
| 632 * problem, report it against the given [parent] node. | 410 * problem, report it against the given [parent] node. |
| 633 * | 411 * |
| 634 * If [element] is `null`, do nothing--this allows us to be robust in the | 412 * If [element] is `null`, do nothing--this allows us to be robust in the |
| 635 * case where we are operating on an element model that hasn't been fully | 413 * case where we are operating on an element model that hasn't been fully |
| 636 * built. | 414 * built. |
| 637 */ | 415 */ |
| 638 void _resolveMetadata( | 416 void _resolveMetadata( |
| 639 AstNode parent, NodeList<Annotation> nodes, Element element) { | 417 AstNode parent, NodeList<Annotation> nodes, Element element) { |
| 640 if (element != null) { | 418 if (element != null) { |
| 641 _resolveAnnotations(parent, nodes, element.metadata); | 419 _resolveAnnotations(parent, nodes, element.metadata); |
| 642 } | 420 } |
| 643 } | 421 } |
| 644 | 422 |
| 645 /** | 423 /** |
| 646 * Throw an exception if there are non-synthetic elements in the element model | 424 * Recurses through the element model and AST, verifying that all elements are |
| 647 * that were not associated with an AST node. | 425 * matched. |
| 648 */ | 426 * |
| 649 void _validateResolution() { | 427 * Executes [callback] with [_walker] pointing to the given [walker] (which |
| 650 if (_expectedElements.isNotEmpty) { | 428 * should be a new instance of [ElementWalker]). Once [callback] returns, |
| 651 StringBuffer buffer = new StringBuffer(); | 429 * uses [ElementWalker.validate] to verify that all expected elements have |
| 652 buffer.write(_expectedElements.length); | 430 * been matched. |
| 653 buffer.writeln(' unmatched elements found:'); | 431 */ |
| 654 for (Element element in _expectedElements) { | 432 void _walk(ElementWalker walker, void callback()) { |
| 655 buffer.write(' '); | 433 ElementWalker outerWalker = _walker; |
| 656 buffer.writeln(element); | 434 _walker = walker; |
| 657 } | 435 callback(); |
| 658 throw new _ElementMismatchException(buffer.toString()); | 436 walker.validate(); |
| 659 } | 437 _walker = outerWalker; |
| 660 } | 438 } |
| 661 } | 439 } |
| 662 | 440 |
| 663 /** | 441 /** |
| 664 * A visitor that can be used to collect all of the non-synthetic elements in an | 442 * Keeps track of the set of non-synthetic child elements of an element, |
| 665 * element model. | 443 * yielding them one at a time in response to "get" method calls. |
| 666 */ | 444 */ |
| 667 class _ElementGatherer extends GeneralizingElementVisitor { | 445 class ElementWalker { |
| 668 /** | 446 /** |
| 669 * The set in which the elements are collected. | 447 * The element whose child elements are being walked. |
| 670 */ | 448 */ |
| 671 final Set<Element> elements = new HashSet<Element>(); | 449 final Element element; |
| 672 | 450 |
| 673 /** | 451 List<PropertyAccessorElement> _accessors; |
| 674 * Initialize the visitor. | 452 int _accessorIndex = 0; |
| 675 */ | 453 List<ClassElement> _classes; |
| 676 _ElementGatherer(); | 454 int _classIndex = 0; |
| 677 | 455 List<ConstructorElement> _constructors; |
| 678 @override | 456 int _constructorIndex = 0; |
| 679 void visitElement(Element element) { | 457 List<ClassElement> _enums; |
| 680 if (!element.isSynthetic) { | 458 int _enumIndex = 0; |
| 681 elements.add(element); | 459 List<ExecutableElement> _functions; |
| 460 int _functionIndex = 0; |
| 461 List<LabelElement> _labels; |
| 462 int _labelIndex = 0; |
| 463 List<ParameterElement> _parameters; |
| 464 int _parameterIndex = 0; |
| 465 List<FunctionTypeAliasElement> _typedefs; |
| 466 int _typedefIndex = 0; |
| 467 List<TypeParameterElement> _typeParameters; |
| 468 int _typeParameterIndex = 0; |
| 469 List<VariableElement> _variables; |
| 470 int _variableIndex = 0; |
| 471 |
| 472 /** |
| 473 * Creates an [ElementWalker] which walks the child elements of a class |
| 474 * element. |
| 475 */ |
| 476 ElementWalker.forClass(ClassElement element) |
| 477 : element = element, |
| 478 _accessors = element.accessors.where(_isNotSynthetic).toList(), |
| 479 _constructors = element.isMixinApplication |
| 480 ? null |
| 481 : element.constructors.where(_isNotSynthetic).toList(), |
| 482 _functions = element.methods, |
| 483 _typeParameters = element.typeParameters, |
| 484 _variables = element.fields.where(_isNotSynthetic).toList(); |
| 485 |
| 486 /** |
| 487 * Creates an [ElementWalker] which walks the child elements of a compilation |
| 488 * unit element. |
| 489 */ |
| 490 ElementWalker.forCompilationUnit(CompilationUnitElement compilationUnit) |
| 491 : element = compilationUnit, |
| 492 _accessors = compilationUnit.accessors.where(_isNotSynthetic).toList(), |
| 493 _classes = compilationUnit.types, |
| 494 _enums = compilationUnit.enums, |
| 495 _functions = compilationUnit.functions, |
| 496 _typedefs = compilationUnit.functionTypeAliases, |
| 497 _variables = |
| 498 compilationUnit.topLevelVariables.where(_isNotSynthetic).toList(); |
| 499 |
| 500 /** |
| 501 * Creates an [ElementWalker] which walks the child elements of a compilation |
| 502 * unit element. |
| 503 */ |
| 504 ElementWalker.forExecutable(ExecutableElement element) |
| 505 : element = element, |
| 506 _functions = element.functions, |
| 507 _labels = element.labels, |
| 508 _parameters = element.parameters, |
| 509 _typeParameters = element.typeParameters, |
| 510 _variables = element.localVariables; |
| 511 |
| 512 /** |
| 513 * Creates an [ElementWalker] which walks the child elements of a parameter |
| 514 * element. |
| 515 */ |
| 516 ElementWalker.forParameter(ParameterElement element) |
| 517 : element = element, |
| 518 _parameters = element.parameters; |
| 519 |
| 520 /** |
| 521 * Creates an [ElementWalker] which walks the child elements of a typedef |
| 522 * element. |
| 523 */ |
| 524 ElementWalker.forTypedef(FunctionTypeAliasElement element) |
| 525 : element = element, |
| 526 _parameters = element.parameters, |
| 527 _typeParameters = element.typeParameters; |
| 528 |
| 529 /** |
| 530 * Returns the next non-synthetic child of [element] which is an accessor; |
| 531 * throws an [IndexError] if there are no more. |
| 532 */ |
| 533 PropertyAccessorElement getAccessor() => _accessors[_accessorIndex++]; |
| 534 |
| 535 /** |
| 536 * Returns the next non-synthetic child of [element] which is a class; throws |
| 537 * an [IndexError] if there are no more. |
| 538 */ |
| 539 ClassElement getClass() => _classes[_classIndex++]; |
| 540 |
| 541 /** |
| 542 * Returns the next non-synthetic child of [element] which is a constructor; |
| 543 * throws an [IndexError] if there are no more. |
| 544 */ |
| 545 ConstructorElement getConstructor() => _constructors[_constructorIndex++]; |
| 546 |
| 547 /** |
| 548 * Returns the next non-synthetic child of [element] which is an enum; throws |
| 549 * an [IndexError] if there are no more. |
| 550 */ |
| 551 ClassElement getEnum() => _enums[_enumIndex++]; |
| 552 |
| 553 /** |
| 554 * Returns the next non-synthetic child of [element] which is a top level |
| 555 * function, method, or local function; throws an [IndexError] if there are no |
| 556 * more. |
| 557 */ |
| 558 ExecutableElement getFunction() => _functions[_functionIndex++]; |
| 559 |
| 560 /** |
| 561 * Returns the next non-synthetic child of [element] which is a label; throws |
| 562 * an [IndexError] if there are no more. |
| 563 */ |
| 564 LabelElement getLabel() => _labels[_labelIndex++]; |
| 565 |
| 566 /** |
| 567 * Returns the next non-synthetic child of [element] which is a parameter; |
| 568 * throws an [IndexError] if there are no more. |
| 569 */ |
| 570 ParameterElement getParameter() => _parameters[_parameterIndex++]; |
| 571 |
| 572 /** |
| 573 * Returns the next non-synthetic child of [element] which is a typedef; |
| 574 * throws an [IndexError] if there are no more. |
| 575 */ |
| 576 FunctionTypeAliasElement getTypedef() => _typedefs[_typedefIndex++]; |
| 577 |
| 578 /** |
| 579 * Returns the next non-synthetic child of [element] which is a type |
| 580 * parameter; throws an [IndexError] if there are no more. |
| 581 */ |
| 582 TypeParameterElement getTypeParameter() => |
| 583 _typeParameters[_typeParameterIndex++]; |
| 584 |
| 585 /** |
| 586 * Returns the next non-synthetic child of [element] which is a top level |
| 587 * variable, field, or local variable; throws an [IndexError] if there are no |
| 588 * more. |
| 589 */ |
| 590 VariableElement getVariable() => _variables[_variableIndex++]; |
| 591 |
| 592 /** |
| 593 * Verifies that all non-synthetic children of [element] have been obtained |
| 594 * from their corresponding "get" method calls; if not, throws a [StateError]. |
| 595 */ |
| 596 void validate() { |
| 597 void check(List<Element> elements, int index) { |
| 598 if (elements != null && elements.length != index) { |
| 599 throw new StateError( |
| 600 'Unmatched ${elements[index].runtimeType} ${elements[index]}'); |
| 601 } |
| 682 } | 602 } |
| 683 super.visitElement(element); | 603 |
| 604 check(_accessors, _accessorIndex); |
| 605 check(_classes, _classIndex); |
| 606 check(_constructors, _constructorIndex); |
| 607 check(_enums, _enumIndex); |
| 608 check(_functions, _functionIndex); |
| 609 check(_labels, _labelIndex); |
| 610 check(_parameters, _parameterIndex); |
| 611 check(_typedefs, _typedefIndex); |
| 612 check(_typeParameters, _typeParameterIndex); |
| 613 check(_variables, _variableIndex); |
| 684 } | 614 } |
| 615 |
| 616 static bool _isNotSynthetic(Element e) => !e.isSynthetic; |
| 685 } | 617 } |
| 686 | 618 |
| 687 class _ElementMismatchException extends AnalysisException { | 619 class _ElementMismatchException extends AnalysisException { |
| 688 /** | 620 /** |
| 689 * Initialize a newly created exception to have the given [message] and | 621 * Creates an exception to refer to the given [compilationUnit], [element], |
| 690 * [cause]. | 622 * and [cause]. |
| 691 */ | 623 */ |
| 692 _ElementMismatchException(String message, [CaughtException cause = null]) | 624 _ElementMismatchException( |
| 693 : super(message, cause); | 625 CompilationUnitElement compilationUnit, Element element, |
| 626 [CaughtException cause = null]) |
| 627 : super('Element mismatch in $compilationUnit at $element', cause); |
| 694 } | 628 } |
| 695 | |
| 696 /** | |
| 697 * A mixin for classes that use an existing element model to resolve a portion | |
| 698 * of an AST structure. | |
| 699 */ | |
| 700 class _ExistingElementResolver { | |
| 701 /** | |
| 702 * The compilation unit containing the AST nodes being visited. | |
| 703 */ | |
| 704 CompilationUnitElementImpl _enclosingUnit; | |
| 705 | |
| 706 /** | |
| 707 * Throw an [ElementMismatchException] to report that the element model and th
e | |
| 708 * AST do not match. The [message] will have the path to the given [node] | |
| 709 * appended to it. | |
| 710 */ | |
| 711 void _mismatch(String message, AstNode node) { | |
| 712 StringBuffer buffer = new StringBuffer(); | |
| 713 buffer.write('Mismatch in '); | |
| 714 buffer.write(runtimeType); | |
| 715 buffer.write(' while resolving '); | |
| 716 buffer.writeln(_enclosingUnit?.source?.fullName); | |
| 717 buffer.writeln(message); | |
| 718 buffer.write('Path to root:'); | |
| 719 String separator = ' '; | |
| 720 AstNode parent = node; | |
| 721 while (parent != null) { | |
| 722 buffer.write(separator); | |
| 723 buffer.write(parent.runtimeType.toString()); | |
| 724 separator = ', '; | |
| 725 parent = parent.parent; | |
| 726 } | |
| 727 throw new _ElementMismatchException(buffer.toString()); | |
| 728 } | |
| 729 } | |
| OLD | NEW |