Chromium Code Reviews| 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.incremental_resolver; | 5 library engine.incremental_resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'ast.dart'; | 9 import 'ast.dart'; |
| 10 import 'element.dart'; | 10 import 'element.dart'; |
| 11 import 'error.dart'; | 11 import 'error.dart'; |
| 12 import 'java_engine.dart'; | 12 import 'java_engine.dart'; |
| 13 import 'resolver.dart'; | 13 import 'resolver.dart'; |
| 14 import 'scanner.dart'; | 14 import 'scanner.dart'; |
| 15 import 'source.dart'; | 15 import 'source.dart'; |
| 16 | 16 |
| 17 | 17 |
| 18 /** | 18 /** |
| 19 * Instances of the class [DeclarationMatcher] determine whether the element | 19 * Instances of the class [DeclarationMatcher] determine whether the element |
| 20 * model defined by a given AST structure matches an existing element model. | 20 * model defined by a given AST structure matches an existing element model. |
| 21 */ | 21 */ |
| 22 class DeclarationMatcher extends RecursiveAstVisitor { | 22 class DeclarationMatcher extends RecursiveAstVisitor { |
| 23 /** | 23 /** |
| 24 * The libary containing the AST nodes being visited. | |
| 25 */ | |
| 26 LibraryElement _enclosingLibrary; | |
| 27 | |
| 28 /** | |
| 24 * The compilation unit containing the AST nodes being visited. | 29 * The compilation unit containing the AST nodes being visited. |
| 25 */ | 30 */ |
| 26 CompilationUnitElement _enclosingUnit; | 31 CompilationUnitElement _enclosingUnit; |
| 27 | 32 |
| 28 /** | 33 /** |
| 29 * The function type alias containing the AST nodes being visited, or `null` i f we are not | 34 * The function type alias containing the AST nodes being visited, or `null` i f we are not |
| 30 * in the scope of a function type alias. | 35 * in the scope of a function type alias. |
| 31 */ | 36 */ |
| 32 FunctionTypeAliasElement _enclosingAlias; | 37 FunctionTypeAliasElement _enclosingAlias; |
| 33 | 38 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 _hasConstructor = true; | 144 _hasConstructor = true; |
| 140 SimpleIdentifier constructorName = node.name; | 145 SimpleIdentifier constructorName = node.name; |
| 141 ConstructorElement element = constructorName == null ? | 146 ConstructorElement element = constructorName == null ? |
| 142 _enclosingClass.unnamedConstructor : | 147 _enclosingClass.unnamedConstructor : |
| 143 _enclosingClass.getNamedConstructor(constructorName.name); | 148 _enclosingClass.getNamedConstructor(constructorName.name); |
| 144 _processElement(element); | 149 _processElement(element); |
| 145 _assertCompatibleParameters(node.parameters, element.parameters); | 150 _assertCompatibleParameters(node.parameters, element.parameters); |
| 146 } | 151 } |
| 147 | 152 |
| 148 @override | 153 @override |
| 154 visitEnumConstantDeclaration(EnumConstantDeclaration node) { | |
| 155 String name = node.name.name; | |
| 156 FieldElement element = _findElement(_enclosingClass.fields, name); | |
| 157 _processElement(element); | |
| 158 } | |
| 159 | |
| 160 @override | |
| 149 visitEnumDeclaration(EnumDeclaration node) { | 161 visitEnumDeclaration(EnumDeclaration node) { |
| 150 String name = node.name.name; | 162 String name = node.name.name; |
| 151 ClassElement element = _findElement(_enclosingUnit.enums, name); | 163 ClassElement element = _findElement(_enclosingUnit.enums, name); |
| 152 _enclosingClass = element; | 164 _enclosingClass = element; |
| 153 _processElement(element); | 165 _processElement(element); |
| 154 _assertTrue(element.isEnum); | 166 _assertTrue(element.isEnum); |
| 155 super.visitEnumDeclaration(node); | 167 super.visitEnumDeclaration(node); |
| 156 } | 168 } |
| 157 | 169 |
| 158 @override | 170 @override |
| 159 visitEnumConstantDeclaration(EnumConstantDeclaration node) { | 171 visitExportDirective(ExportDirective node) { |
|
Brian Wilkerson
2014/11/21 19:50:41
Export directives also have combinators. Do we nee
scheglov
2014/11/21 20:07:17
Done.
| |
| 160 String name = node.name.name; | 172 String uri = _getStringValue(node.uri); |
| 161 FieldElement element = _findElement(_enclosingClass.fields, name); | 173 if (uri != null) { |
| 162 _processElement(element); | 174 ExportElement element = |
| 175 _findUriReferencedElement(_enclosingLibrary.exports, uri); | |
| 176 _processElement(element); | |
| 177 } | |
| 163 } | 178 } |
| 164 | 179 |
| 165 @override | 180 @override |
| 166 visitExportDirective(ExportDirective node) { | |
| 167 String uri = _getStringValue(node.uri); | |
| 168 if (uri != null) { | |
| 169 LibraryElement library = _enclosingUnit.library; | |
| 170 ExportElement exportElement = _findExport( | |
| 171 library.exports, | |
| 172 _enclosingUnit.context.sourceFactory.resolveUri(_enclosingUnit.source, uri)); | |
| 173 _processElement(exportElement); | |
| 174 } | |
| 175 super.visitExportDirective(node); | |
| 176 } | |
| 177 | |
| 178 @override | |
| 179 visitExpressionFunctionBody(ExpressionFunctionBody node) { | 181 visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 180 // ignore bodies | 182 // ignore bodies |
| 181 } | 183 } |
| 182 | 184 |
| 183 @override | 185 @override |
| 184 visitExtendsClause(ExtendsClause node) { | 186 visitExtendsClause(ExtendsClause node) { |
| 185 _assertSameType(node.superclass, _enclosingClass.supertype); | 187 _assertSameType(node.superclass, _enclosingClass.supertype); |
| 186 } | 188 } |
| 187 | 189 |
| 188 @override | 190 @override |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 visitImplementsClause(ImplementsClause node) { | 240 visitImplementsClause(ImplementsClause node) { |
| 239 List<TypeName> nodes = node.interfaces; | 241 List<TypeName> nodes = node.interfaces; |
| 240 List<InterfaceType> types = _enclosingClass.interfaces; | 242 List<InterfaceType> types = _enclosingClass.interfaces; |
| 241 _assertSameTypes(nodes, types); | 243 _assertSameTypes(nodes, types); |
| 242 } | 244 } |
| 243 | 245 |
| 244 @override | 246 @override |
| 245 visitImportDirective(ImportDirective node) { | 247 visitImportDirective(ImportDirective node) { |
| 246 String uri = _getStringValue(node.uri); | 248 String uri = _getStringValue(node.uri); |
| 247 if (uri != null) { | 249 if (uri != null) { |
| 248 LibraryElement library = _enclosingUnit.library; | 250 ImportElement element = |
| 249 ImportElement importElement = _findImport( | 251 _findUriReferencedElement(_enclosingLibrary.imports, uri); |
| 250 library.imports, | 252 _processElement(element); |
| 251 _enclosingUnit.context.sourceFactory.resolveUri(_enclosingUnit.source, uri), | 253 // match the prefix |
| 252 node.prefix); | 254 SimpleIdentifier prefixNode = node.prefix; |
| 253 _processElement(importElement); | 255 PrefixElement prefixElement = element.prefix; |
| 256 if (prefixNode == null) { | |
| 257 _assertNull(prefixElement); | |
| 258 } else { | |
| 259 _assertNotNull(prefixElement); | |
| 260 _assertEquals(prefixNode.name, prefixElement.name); | |
| 261 } | |
| 262 // prepare shown/hidden names in the element | |
| 263 Set<String> showNames = new Set<String>(); | |
| 264 Set<String> hideNames = new Set<String>(); | |
| 265 for (NamespaceCombinator combinator in element.combinators) { | |
| 266 if (combinator is ShowElementCombinator) { | |
| 267 showNames.addAll(combinator.shownNames); | |
| 268 } else if (combinator is HideElementCombinator) { | |
| 269 hideNames.addAll(combinator.hiddenNames); | |
| 270 } | |
| 271 } | |
| 272 // match combinators with the node | |
| 273 for (Combinator combinator in node.combinators) { | |
| 274 if (combinator is ShowCombinator) { | |
| 275 for (SimpleIdentifier nameNode in combinator.shownNames) { | |
| 276 String name = nameNode.name; | |
| 277 _assertTrue(showNames.remove(name)); | |
| 278 } | |
| 279 _assertTrue(showNames.isEmpty); | |
| 280 } else if (combinator is HideCombinator) { | |
| 281 for (SimpleIdentifier nameNode in combinator.hiddenNames) { | |
| 282 String name = nameNode.name; | |
| 283 _assertTrue(hideNames.remove(name)); | |
| 284 } | |
| 285 _assertTrue(hideNames.isEmpty); | |
| 286 } | |
| 287 } | |
| 254 } | 288 } |
| 255 super.visitImportDirective(node); | |
| 256 } | 289 } |
| 257 | 290 |
| 258 @override | 291 @override |
| 259 visitMethodDeclaration(MethodDeclaration node) { | 292 visitMethodDeclaration(MethodDeclaration node) { |
| 260 // prepare element name | 293 // prepare element name |
| 261 String name = node.name.name; | 294 String name = node.name.name; |
| 262 if (name == TokenType.MINUS.lexeme && | 295 if (name == TokenType.MINUS.lexeme && |
| 263 node.parameters.parameters.length == 0) { | 296 node.parameters.parameters.length == 0) { |
| 264 name = "unary-"; | 297 name = "unary-"; |
| 265 } | 298 } |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 281 _processElement(element); | 314 _processElement(element); |
| 282 // TODO(scheglov) test returnType | 315 // TODO(scheglov) test returnType |
| 283 _assertSameType(node.returnType, element.returnType); | 316 _assertSameType(node.returnType, element.returnType); |
| 284 _assertCompatibleParameters(node.parameters, element.parameters); | 317 _assertCompatibleParameters(node.parameters, element.parameters); |
| 285 } | 318 } |
| 286 | 319 |
| 287 @override | 320 @override |
| 288 visitPartDirective(PartDirective node) { | 321 visitPartDirective(PartDirective node) { |
| 289 String uri = _getStringValue(node.uri); | 322 String uri = _getStringValue(node.uri); |
| 290 if (uri != null) { | 323 if (uri != null) { |
| 291 Source partSource = | |
| 292 _enclosingUnit.context.sourceFactory.resolveUri(_enclosingUnit.source, uri); | |
| 293 CompilationUnitElement element = | 324 CompilationUnitElement element = |
| 294 _findPart(_enclosingUnit.library.parts, partSource); | 325 _findUriReferencedElement(_enclosingLibrary.parts, uri); |
| 295 _processElement(element); | 326 _processElement(element); |
| 296 } | 327 } |
| 297 super.visitPartDirective(node); | 328 super.visitPartDirective(node); |
| 298 } | 329 } |
| 299 | 330 |
| 300 @override | 331 @override |
| 301 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | 332 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 302 _inTopLevelVariableDeclaration = true; | 333 _inTopLevelVariableDeclaration = true; |
| 303 try { | 334 try { |
| 304 super.visitTopLevelVariableDeclaration(node); | 335 super.visitTopLevelVariableDeclaration(node); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 throw new _DeclarationMismatchException(); | 413 throw new _DeclarationMismatchException(); |
| 383 } | 414 } |
| 384 } | 415 } |
| 385 | 416 |
| 386 void _assertNotNull(Element element) { | 417 void _assertNotNull(Element element) { |
| 387 if (element == null) { | 418 if (element == null) { |
| 388 throw new _DeclarationMismatchException(); | 419 throw new _DeclarationMismatchException(); |
| 389 } | 420 } |
| 390 } | 421 } |
| 391 | 422 |
| 423 void _assertNull(Element element) { | |
| 424 if (element != null) { | |
| 425 throw new _DeclarationMismatchException(); | |
| 426 } | |
| 427 } | |
| 428 | |
| 392 void _assertSameType(TypeName node, DartType type) { | 429 void _assertSameType(TypeName node, DartType type) { |
| 393 // no return type == dynamic | 430 // no return type == dynamic |
| 394 if (node == null) { | 431 if (node == null) { |
| 395 return _assertTrue(type == null || type.isDynamic); | 432 return _assertTrue(type == null || type.isDynamic); |
| 396 } | 433 } |
| 397 // check specific type kinds | 434 // check specific type kinds |
| 398 String nodeName = node.name.name; | 435 String nodeName = node.name.name; |
| 399 if (type is InterfaceType) { | 436 if (type is InterfaceType) { |
| 400 _assertEquals(nodeName, type.name); | 437 _assertEquals(nodeName, type.name); |
| 401 // check arguments | 438 // check arguments |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 424 } | 461 } |
| 425 } | 462 } |
| 426 | 463 |
| 427 void _assertTrue(bool condition) { | 464 void _assertTrue(bool condition) { |
| 428 if (!condition) { | 465 if (!condition) { |
| 429 throw new _DeclarationMismatchException(); | 466 throw new _DeclarationMismatchException(); |
| 430 } | 467 } |
| 431 } | 468 } |
| 432 | 469 |
| 433 /** | 470 /** |
| 434 * Given that the comparison is to begin with the given element, capture the e nclosing elements | 471 * Given that the comparison is to begin with the given [element], capture |
| 435 * that might be used while performing the comparison. | 472 * the enclosing elements that might be used while performing the comparison. |
| 436 * | |
| 437 * @param element the element corresponding to the AST structure to be compare d | |
| 438 */ | 473 */ |
| 439 void _captureEnclosingElements(Element element) { | 474 void _captureEnclosingElements(Element element) { |
| 440 Element parent = | 475 Element parent = |
| 441 element is CompilationUnitElement ? element : element.enclosingElement; | 476 element is CompilationUnitElement ? element : element.enclosingElement; |
| 442 while (parent != null) { | 477 while (parent != null) { |
| 443 if (parent is CompilationUnitElement) { | 478 if (parent is CompilationUnitElement) { |
| 444 _enclosingUnit = parent as CompilationUnitElement; | 479 _enclosingUnit = parent as CompilationUnitElement; |
| 480 _enclosingLibrary = element.library; | |
| 445 } else if (parent is ClassElement) { | 481 } else if (parent is ClassElement) { |
| 446 if (_enclosingClass == null) { | 482 if (_enclosingClass == null) { |
| 447 _enclosingClass = parent as ClassElement; | 483 _enclosingClass = parent as ClassElement; |
| 448 } | 484 } |
| 449 } else if (parent is FunctionTypeAliasElement) { | 485 } else if (parent is FunctionTypeAliasElement) { |
| 450 if (_enclosingAlias == null) { | 486 if (_enclosingAlias == null) { |
| 451 _enclosingAlias = parent as FunctionTypeAliasElement; | 487 _enclosingAlias = parent as FunctionTypeAliasElement; |
| 452 } | 488 } |
| 453 } else if (parent is ParameterElement) { | 489 } else if (parent is ParameterElement) { |
| 454 if (_enclosingParameter == null) { | 490 if (_enclosingParameter == null) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 465 Element _findElement(List<Element> elements, String name) { | 501 Element _findElement(List<Element> elements, String name) { |
| 466 for (Element element in elements) { | 502 for (Element element in elements) { |
| 467 if (element.displayName == name) { | 503 if (element.displayName == name) { |
| 468 return element; | 504 return element; |
| 469 } | 505 } |
| 470 } | 506 } |
| 471 return null; | 507 return null; |
| 472 } | 508 } |
| 473 | 509 |
| 474 /** | 510 /** |
| 475 * Return the export element from the given array whose library has the given source, or | |
| 476 * `null` if there is no such export. | |
| 477 * | |
| 478 * @param exports the export elements being searched | |
| 479 * @param source the source of the library associated with the export element to being searched | |
| 480 * for | |
| 481 * @return the export element whose library has the given source | |
| 482 */ | |
| 483 ExportElement _findExport(List<ExportElement> exports, Source source) { | |
| 484 for (ExportElement export in exports) { | |
| 485 if (export.exportedLibrary.source == source) { | |
| 486 return export; | |
| 487 } | |
| 488 } | |
| 489 return null; | |
| 490 } | |
| 491 | |
| 492 /** | |
| 493 * Return the element in the given array of elements that was created for the declaration with the | 511 * Return the element in the given array of elements that was created for the declaration with the |
| 494 * given name. | 512 * given name. |
| 495 * | 513 * |
| 496 * @param elements the elements of the appropriate kind that exist in the curr ent context | 514 * @param elements the elements of the appropriate kind that exist in the curr ent context |
| 497 * @param identifier the name node in the declaration of the element to be ret urned | 515 * @param identifier the name node in the declaration of the element to be ret urned |
| 498 * @return the element created for the declaration with the given name | 516 * @return the element created for the declaration with the given name |
| 499 */ | 517 */ |
| 500 Element _findIdentifier(List<Element> elements, | 518 Element _findIdentifier(List<Element> elements, |
| 501 SimpleIdentifier identifier) => | 519 SimpleIdentifier identifier) => |
| 502 _findWithNameAndOffset(elements, identifier.name, identifier.offset); | 520 _findWithNameAndOffset(elements, identifier.name, identifier.offset); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 562 int offset) { | 580 int offset) { |
| 563 for (Element element in elements) { | 581 for (Element element in elements) { |
| 564 if (element.displayName == name && element.nameOffset == offset) { | 582 if (element.displayName == name && element.nameOffset == offset) { |
| 565 return element; | 583 return element; |
| 566 } | 584 } |
| 567 } | 585 } |
| 568 return null; | 586 return null; |
| 569 } | 587 } |
| 570 | 588 |
| 571 void _gatherElements(Element element) { | 589 void _gatherElements(Element element) { |
| 572 element.accept(new _ElementsGatherer(this)); | 590 _ElementsGatherer gatherer = new _ElementsGatherer(this); |
| 591 element.accept(gatherer); | |
| 592 // TODO(scheglov) push into CompilationUnitElement | |
| 593 if (identical(_enclosingUnit, _enclosingLibrary.definingCompilationUnit)) { | |
| 594 gatherer.addElements(_enclosingLibrary.imports); | |
| 595 gatherer.addElements(_enclosingLibrary.exports); | |
| 596 gatherer.addElements(_enclosingLibrary.parts); | |
| 597 } | |
| 573 } | 598 } |
| 574 | 599 |
| 575 /** | 600 /** |
| 576 * Return the value of the given string literal, or `null` if the string is no t a constant | 601 * Return the value of the given string literal, or `null` if the string is no t a constant |
| 577 * string without any string interpolation. | 602 * string without any string interpolation. |
| 578 * | 603 * |
| 579 * @param literal the string literal whose value is to be returned | 604 * @param literal the string literal whose value is to be returned |
| 580 * @return the value of the given string literal | 605 * @return the value of the given string literal |
| 581 */ | 606 */ |
| 582 String _getStringValue(StringLiteral literal) { | 607 String _getStringValue(StringLiteral literal) { |
| 583 if (literal is StringInterpolation) { | 608 if (literal is StringInterpolation) { |
| 584 return null; | 609 return null; |
| 585 } | 610 } |
| 586 return literal.stringValue; | 611 return literal.stringValue; |
| 587 } | 612 } |
| 588 | 613 |
| 589 void _processElement(Element element) { | 614 void _processElement(Element element) { |
| 590 _assertNotNull(element); | 615 _assertNotNull(element); |
| 591 if (!_allElements.contains(element)) { | 616 if (!_allElements.contains(element)) { |
| 592 throw new _DeclarationMismatchException(); | 617 throw new _DeclarationMismatchException(); |
| 593 } | 618 } |
| 594 _unmatchedElements.remove(element); | 619 _unmatchedElements.remove(element); |
| 595 } | 620 } |
| 621 | |
| 622 /** | |
| 623 * Return the [UriReferencedElement] from [elements] with the given [uri], or | |
| 624 * `null` if there is no such element. | |
| 625 */ | |
| 626 static UriReferencedElement | |
| 627 _findUriReferencedElement(List<UriReferencedElement> elements, String uri) { | |
| 628 for (UriReferencedElement element in elements) { | |
| 629 if (element.uri == uri) { | |
| 630 return element; | |
| 631 } | |
| 632 } | |
| 633 return null; | |
| 634 } | |
| 596 } | 635 } |
| 597 | 636 |
| 598 | 637 |
| 599 /** | 638 /** |
| 600 * Instances of the class [IncrementalResolver] resolve the smallest portion of | 639 * Instances of the class [IncrementalResolver] resolve the smallest portion of |
| 601 * an AST structure that we currently know how to resolve. | 640 * an AST structure that we currently know how to resolve. |
| 602 */ | 641 */ |
| 603 class IncrementalResolver { | 642 class IncrementalResolver { |
| 604 /** | 643 /** |
| 605 * The error listener that will be informed of any errors that are found | 644 * The error listener that will be informed of any errors that are found |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 926 super.visitElement(element); | 965 super.visitElement(element); |
| 927 } | 966 } |
| 928 } | 967 } |
| 929 | 968 |
| 930 | 969 |
| 931 class _ElementsGatherer extends GeneralizingElementVisitor { | 970 class _ElementsGatherer extends GeneralizingElementVisitor { |
| 932 final DeclarationMatcher matcher; | 971 final DeclarationMatcher matcher; |
| 933 | 972 |
| 934 _ElementsGatherer(this.matcher); | 973 _ElementsGatherer(this.matcher); |
| 935 | 974 |
| 975 void addElements(List<Element> elements) { | |
| 976 for (Element element in elements) { | |
| 977 if (!element.isSynthetic) { | |
| 978 _addElement(element); | |
| 979 } | |
| 980 } | |
| 981 } | |
| 982 | |
| 936 @override | 983 @override |
| 937 visitElement(Element element) { | 984 visitElement(Element element) { |
| 938 _addElement(element); | 985 _addElement(element); |
| 939 super.visitElement(element); | 986 super.visitElement(element); |
| 940 } | 987 } |
| 941 | 988 |
| 942 @override | 989 @override |
| 943 visitExecutableElement(ExecutableElement element) { | 990 visitExecutableElement(ExecutableElement element) { |
| 944 _addElement(element); | 991 _addElement(element); |
| 945 } | 992 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 960 // Don't visit children (such as property accessors). | 1007 // Don't visit children (such as property accessors). |
| 961 } | 1008 } |
| 962 | 1009 |
| 963 void _addElement(Element element) { | 1010 void _addElement(Element element) { |
| 964 if (element != null) { | 1011 if (element != null) { |
| 965 matcher._allElements.add(element); | 1012 matcher._allElements.add(element); |
| 966 matcher._unmatchedElements.add(element); | 1013 matcher._unmatchedElements.add(element); |
| 967 } | 1014 } |
| 968 } | 1015 } |
| 969 } | 1016 } |
| OLD | NEW |