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

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

Issue 725473005: During resolution, record the target of break/continue statements. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library engine.resolver.element_resolver; 5 library engine.resolver.element_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';
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 if (operator.isUserDefinableOperator) { 169 if (operator.isUserDefinableOperator) {
170 _resolveBinaryExpression(node, operator.lexeme); 170 _resolveBinaryExpression(node, operator.lexeme);
171 } else if (operator.type == sc.TokenType.BANG_EQ) { 171 } else if (operator.type == sc.TokenType.BANG_EQ) {
172 _resolveBinaryExpression(node, sc.TokenType.EQ_EQ.lexeme); 172 _resolveBinaryExpression(node, sc.TokenType.EQ_EQ.lexeme);
173 } 173 }
174 return null; 174 return null;
175 } 175 }
176 176
177 @override 177 @override
178 Object visitBreakStatement(BreakStatement node) { 178 Object visitBreakStatement(BreakStatement node) {
179 _lookupLabel(node, node.label); 179 node.target = _lookupBreakOrContinueTarget(node, node.label, false);
180 return null; 180 return null;
181 } 181 }
182 182
183 @override 183 @override
184 Object visitClassDeclaration(ClassDeclaration node) { 184 Object visitClassDeclaration(ClassDeclaration node) {
185 _setMetadata(node.element, node); 185 _setMetadata(node.element, node);
186 return null; 186 return null;
187 } 187 }
188 188
189 @override 189 @override
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 constructor = 360 constructor =
361 interfaceType.lookUpConstructor(name.name, _definingLibrary); 361 interfaceType.lookUpConstructor(name.name, _definingLibrary);
362 name.staticElement = constructor; 362 name.staticElement = constructor;
363 } 363 }
364 node.staticElement = constructor; 364 node.staticElement = constructor;
365 return null; 365 return null;
366 } 366 }
367 367
368 @override 368 @override
369 Object visitContinueStatement(ContinueStatement node) { 369 Object visitContinueStatement(ContinueStatement node) {
370 _lookupLabel(node, node.label); 370 node.target = _lookupBreakOrContinueTarget(node, node.label, true);
371 return null; 371 return null;
372 } 372 }
373 373
374 @override 374 @override
375 Object visitDeclaredIdentifier(DeclaredIdentifier node) { 375 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
376 _setMetadata(node.element, node); 376 _setMetadata(node.element, node);
377 return null; 377 return null;
378 } 378 }
379 379
380 @override 380 @override
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 _recordUndefinedToken( 795 _recordUndefinedToken(
796 propagatedType.element, 796 propagatedType.element,
797 HintCode.UNDEFINED_OPERATOR, 797 HintCode.UNDEFINED_OPERATOR,
798 node.operator, 798 node.operator,
799 [methodName, propagatedType.displayName]); 799 [methodName, propagatedType.displayName]);
800 } 800 }
801 return null; 801 return null;
802 } 802 }
803 803
804 @override 804 @override
805 Object visitPrefixExpression(PrefixExpression node) {
806 sc.Token operator = node.operator;
807 sc.TokenType operatorType = operator.type;
808 if (operatorType.isUserDefinableOperator ||
809 operatorType == sc.TokenType.PLUS_PLUS ||
810 operatorType == sc.TokenType.MINUS_MINUS) {
811 Expression operand = node.operand;
812 String methodName = _getPrefixOperator(node);
813 DartType staticType = _getStaticType(operand);
814 MethodElement staticMethod =
815 _lookUpMethod(operand, staticType, methodName);
816 node.staticElement = staticMethod;
817 DartType propagatedType = _getPropagatedType(operand);
818 MethodElement propagatedMethod =
819 _lookUpMethod(operand, propagatedType, methodName);
820 node.propagatedElement = propagatedMethod;
821 if (_shouldReportMissingMember(staticType, staticMethod)) {
822 _recordUndefinedToken(
823 staticType.element,
824 StaticTypeWarningCode.UNDEFINED_OPERATOR,
825 operator,
826 [methodName, staticType.displayName]);
827 } else if (_enableHints &&
828 _shouldReportMissingMember(propagatedType, propagatedMethod) &&
829 !_memberFoundInSubclass(propagatedType.element, methodName, true, fals e)) {
830 _recordUndefinedToken(
831 propagatedType.element,
832 HintCode.UNDEFINED_OPERATOR,
833 operator,
834 [methodName, propagatedType.displayName]);
835 }
836 }
837 return null;
838 }
839
840 @override
841 Object visitPrefixedIdentifier(PrefixedIdentifier node) { 805 Object visitPrefixedIdentifier(PrefixedIdentifier node) {
842 SimpleIdentifier prefix = node.prefix; 806 SimpleIdentifier prefix = node.prefix;
843 SimpleIdentifier identifier = node.identifier; 807 SimpleIdentifier identifier = node.identifier;
844 // 808 //
845 // First, check the "lib.loadLibrary" case 809 // First, check the "lib.loadLibrary" case
846 // 810 //
847 if (identifier.name == FunctionElement.LOAD_LIBRARY_NAME && 811 if (identifier.name == FunctionElement.LOAD_LIBRARY_NAME &&
848 _isDeferredPrefix(prefix)) { 812 _isDeferredPrefix(prefix)) {
849 LibraryElement importedLibrary = _getImportedLibrary(prefix); 813 LibraryElement importedLibrary = _getImportedLibrary(prefix);
850 identifier.staticElement = importedLibrary.loadLibraryFunction; 814 identifier.staticElement = importedLibrary.loadLibraryFunction;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 } 873 }
910 // 874 //
911 // Otherwise, the prefix is really an expression that happens to be a simple 875 // Otherwise, the prefix is really an expression that happens to be a simple
912 // identifier and this is really equivalent to a property access node. 876 // identifier and this is really equivalent to a property access node.
913 // 877 //
914 _resolvePropertyAccess(prefix, identifier); 878 _resolvePropertyAccess(prefix, identifier);
915 return null; 879 return null;
916 } 880 }
917 881
918 @override 882 @override
883 Object visitPrefixExpression(PrefixExpression node) {
884 sc.Token operator = node.operator;
885 sc.TokenType operatorType = operator.type;
886 if (operatorType.isUserDefinableOperator ||
887 operatorType == sc.TokenType.PLUS_PLUS ||
888 operatorType == sc.TokenType.MINUS_MINUS) {
889 Expression operand = node.operand;
890 String methodName = _getPrefixOperator(node);
891 DartType staticType = _getStaticType(operand);
892 MethodElement staticMethod =
893 _lookUpMethod(operand, staticType, methodName);
894 node.staticElement = staticMethod;
895 DartType propagatedType = _getPropagatedType(operand);
896 MethodElement propagatedMethod =
897 _lookUpMethod(operand, propagatedType, methodName);
898 node.propagatedElement = propagatedMethod;
899 if (_shouldReportMissingMember(staticType, staticMethod)) {
900 _recordUndefinedToken(
901 staticType.element,
902 StaticTypeWarningCode.UNDEFINED_OPERATOR,
903 operator,
904 [methodName, staticType.displayName]);
905 } else if (_enableHints &&
906 _shouldReportMissingMember(propagatedType, propagatedMethod) &&
907 !_memberFoundInSubclass(propagatedType.element, methodName, true, fals e)) {
908 _recordUndefinedToken(
909 propagatedType.element,
910 HintCode.UNDEFINED_OPERATOR,
911 operator,
912 [methodName, propagatedType.displayName]);
913 }
914 }
915 return null;
916 }
917
918 @override
919 Object visitPropertyAccess(PropertyAccess node) { 919 Object visitPropertyAccess(PropertyAccess node) {
920 Expression target = node.realTarget; 920 Expression target = node.realTarget;
921 if (target is SuperExpression && !_isSuperInValidContext(target)) { 921 if (target is SuperExpression && !_isSuperInValidContext(target)) {
922 return null; 922 return null;
923 } 923 }
924 SimpleIdentifier propertyName = node.propertyName; 924 SimpleIdentifier propertyName = node.propertyName;
925 _resolvePropertyAccess(target, propertyName); 925 _resolvePropertyAccess(target, propertyName);
926 return null; 926 return null;
927 } 927 }
928 928
(...skipping 638 matching lines...) Expand 10 before | Expand all | Expand 10 after
1567 return identical(parent.prefix, node); 1567 return identical(parent.prefix, node);
1568 } else if (parent is PrefixedIdentifier) { 1568 } else if (parent is PrefixedIdentifier) {
1569 return true; 1569 return true;
1570 } else if (parent is MethodInvocation) { 1570 } else if (parent is MethodInvocation) {
1571 return identical(parent.target, node); 1571 return identical(parent.target, node);
1572 } 1572 }
1573 return false; 1573 return false;
1574 } 1574 }
1575 1575
1576 /** 1576 /**
1577 * Return the target of a break or continue statement, and update the static
1578 * element of its label (if any). [parentNode] is the AST node of the break
1579 * or continue statement, [labelNode] is the label contained in that
1580 * statement (if any), and [isContinue] is true if the node being visited is
1581 * a continue statement.
1582 */
1583 AstNode _lookupBreakOrContinueTarget(AstNode parentNode,
1584 SimpleIdentifier labelNode, bool isContinue) {
1585 if (labelNode == null) {
1586 return _resolver.getUnlabeledBreakOrContinueTarget(isContinue);
1587 } else {
1588 LabelScope labelScope = _resolver.labelScope;
1589 if (labelScope == null) {
1590 // There are no labels in scope, so by definition the label is
1591 // undefined.
1592 _resolver.reportErrorForNode(
1593 CompileTimeErrorCode.LABEL_UNDEFINED,
1594 labelNode,
1595 [labelNode.name]);
1596 return null;
1597 }
1598 LabelScope definingScope = labelScope.lookup(labelNode.name);
1599 if (definingScope == null) {
1600 // No definition of the given label name could be found in any
1601 // enclosing scope.
1602 _resolver.reportErrorForNode(
1603 CompileTimeErrorCode.LABEL_UNDEFINED,
1604 labelNode,
1605 [labelNode.name]);
1606 return null;
1607 }
1608 // The target has been found.
1609 labelNode.staticElement = definingScope.element;
1610 ExecutableElement labelContainer =
1611 definingScope.element.getAncestor((element) => element is ExecutableEl ement);
1612 if (!identical(labelContainer, _resolver.enclosingFunction)) {
1613 _resolver.reportErrorForNode(
1614 CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE,
1615 labelNode,
1616 [labelNode.name]);
1617 }
1618 return definingScope.node;
1619 }
1620 }
1621
1622 /**
1577 * Look up the getter with the given name in the given type. Return the elemen t representing the 1623 * Look up the getter with the given name in the given type. Return the elemen t representing the
1578 * getter that was found, or `null` if there is no getter with the given name. 1624 * getter that was found, or `null` if there is no getter with the given name.
1579 * 1625 *
1580 * @param target the target of the invocation, or `null` if there is no target 1626 * @param target the target of the invocation, or `null` if there is no target
1581 * @param type the type in which the getter is defined 1627 * @param type the type in which the getter is defined
1582 * @param getterName the name of the getter being looked up 1628 * @param getterName the name of the getter being looked up
1583 * @return the element representing the getter that was found 1629 * @return the element representing the getter that was found
1584 */ 1630 */
1585 PropertyAccessorElement _lookUpGetter(Expression target, DartType type, 1631 PropertyAccessorElement _lookUpGetter(Expression target, DartType type,
1586 String getterName) { 1632 String getterName) {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1655 return null; 1701 return null;
1656 } 1702 }
1657 return _lookUpGetterInInterfaces( 1703 return _lookUpGetterInInterfaces(
1658 superclass, 1704 superclass,
1659 true, 1705 true,
1660 getterName, 1706 getterName,
1661 visitedInterfaces); 1707 visitedInterfaces);
1662 } 1708 }
1663 1709
1664 /** 1710 /**
1711 * Look up the method or getter with the given name in the given type. Return the element
1712 * representing the method or getter that was found, or `null` if there is no method or
1713 * getter with the given name.
1714 *
1715 * @param type the type in which the method or getter is defined
1716 * @param memberName the name of the method or getter being looked up
1717 * @return the element representing the method or getter that was found
1718 */
1719 ExecutableElement _lookupGetterOrMethod(DartType type, String memberName) {
1720 type = _resolveTypeParameter(type);
1721 if (type is InterfaceType) {
1722 InterfaceType interfaceType = type;
1723 ExecutableElement member =
1724 interfaceType.lookUpMethod(memberName, _definingLibrary);
1725 if (member != null) {
1726 return member;
1727 }
1728 member = interfaceType.lookUpGetter(memberName, _definingLibrary);
1729 if (member != null) {
1730 return member;
1731 }
1732 return _lookUpGetterOrMethodInInterfaces(
1733 interfaceType,
1734 false,
1735 memberName,
1736 new HashSet<ClassElement>());
1737 }
1738 return null;
1739 }
1740
1741 /**
1665 * Look up the method or getter with the given name in the interfaces implemen ted by the given 1742 * Look up the method or getter with the given name in the interfaces implemen ted by the given
1666 * type, either directly or indirectly. Return the element representing the me thod or getter that 1743 * type, either directly or indirectly. Return the element representing the me thod or getter that
1667 * was found, or `null` if there is no method or getter with the given name. 1744 * was found, or `null` if there is no method or getter with the given name.
1668 * 1745 *
1669 * @param targetType the type in which the method or getter might be defined 1746 * @param targetType the type in which the method or getter might be defined
1670 * @param includeTargetType `true` if the search should include the target typ e 1747 * @param includeTargetType `true` if the search should include the target typ e
1671 * @param memberName the name of the method or getter being looked up 1748 * @param memberName the name of the method or getter being looked up
1672 * @param visitedInterfaces a set containing all of the interfaces that have b een examined, used 1749 * @param visitedInterfaces a set containing all of the interfaces that have b een examined, used
1673 * to prevent infinite recursion and to optimize the search 1750 * to prevent infinite recursion and to optimize the search
1674 * @return the element representing the method or getter that was found 1751 * @return the element representing the method or getter that was found
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
1815 return null; 1892 return null;
1816 } 1893 }
1817 return _lookUpMethodInInterfaces( 1894 return _lookUpMethodInInterfaces(
1818 superclass, 1895 superclass,
1819 true, 1896 true,
1820 methodName, 1897 methodName,
1821 visitedInterfaces); 1898 visitedInterfaces);
1822 } 1899 }
1823 1900
1824 /** 1901 /**
1902 * Look up all methods of a given name defined on a union type.
1903 *
1904 * @param target
1905 * @param type
1906 * @param methodName
1907 * @return all methods named `methodName` defined on the union type `type`.
1908 */
1909 Set<ExecutableElement> _lookupMethods(Expression target, UnionType type,
1910 String methodName) {
1911 Set<ExecutableElement> methods = new HashSet<ExecutableElement>();
1912 bool allElementsHaveMethod = true;
1913 for (DartType t in type.elements) {
1914 MethodElement m = _lookUpMethod(target, t, methodName);
1915 if (m != null) {
1916 methods.add(m);
1917 } else {
1918 allElementsHaveMethod = false;
1919 }
1920 }
1921 // For strict union types we require that all types in the union define the
1922 // method.
1923 if (AnalysisEngine.instance.strictUnionTypes) {
1924 if (allElementsHaveMethod) {
1925 return methods;
1926 } else {
1927 return new Set<ExecutableElement>();
1928 }
1929 } else {
1930 return methods;
1931 }
1932 }
1933
1934 /**
1825 * Look up the setter with the given name in the given type. Return the elemen t representing the 1935 * Look up the setter with the given name in the given type. Return the elemen t representing the
1826 * setter that was found, or `null` if there is no setter with the given name. 1936 * setter that was found, or `null` if there is no setter with the given name.
1827 * 1937 *
1828 * @param target the target of the invocation, or `null` if there is no target 1938 * @param target the target of the invocation, or `null` if there is no target
1829 * @param type the type in which the setter is defined 1939 * @param type the type in which the setter is defined
1830 * @param setterName the name of the setter being looked up 1940 * @param setterName the name of the setter being looked up
1831 * @return the element representing the setter that was found 1941 * @return the element representing the setter that was found
1832 */ 1942 */
1833 PropertyAccessorElement _lookUpSetter(Expression target, DartType type, 1943 PropertyAccessorElement _lookUpSetter(Expression target, DartType type,
1834 String setterName) { 1944 String setterName) {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1903 return null; 2013 return null;
1904 } 2014 }
1905 return _lookUpSetterInInterfaces( 2015 return _lookUpSetterInInterfaces(
1906 superclass, 2016 superclass,
1907 true, 2017 true,
1908 setterName, 2018 setterName,
1909 visitedInterfaces); 2019 visitedInterfaces);
1910 } 2020 }
1911 2021
1912 /** 2022 /**
1913 * Look up the method or getter with the given name in the given type. Return the element
1914 * representing the method or getter that was found, or `null` if there is no method or
1915 * getter with the given name.
1916 *
1917 * @param type the type in which the method or getter is defined
1918 * @param memberName the name of the method or getter being looked up
1919 * @return the element representing the method or getter that was found
1920 */
1921 ExecutableElement _lookupGetterOrMethod(DartType type, String memberName) {
1922 type = _resolveTypeParameter(type);
1923 if (type is InterfaceType) {
1924 InterfaceType interfaceType = type;
1925 ExecutableElement member =
1926 interfaceType.lookUpMethod(memberName, _definingLibrary);
1927 if (member != null) {
1928 return member;
1929 }
1930 member = interfaceType.lookUpGetter(memberName, _definingLibrary);
1931 if (member != null) {
1932 return member;
1933 }
1934 return _lookUpGetterOrMethodInInterfaces(
1935 interfaceType,
1936 false,
1937 memberName,
1938 new HashSet<ClassElement>());
1939 }
1940 return null;
1941 }
1942
1943 /**
1944 * Find the element corresponding to the given label node in the current label scope.
1945 *
1946 * @param parentNode the node containing the given label
1947 * @param labelNode the node representing the label being looked up
1948 * @return the element corresponding to the given label node in the current sc ope
1949 */
1950 LabelElementImpl _lookupLabel(AstNode parentNode,
1951 SimpleIdentifier labelNode) {
1952 LabelScope labelScope = _resolver.labelScope;
1953 LabelElementImpl labelElement = null;
1954 if (labelNode == null) {
1955 if (labelScope == null) {
1956 // TODO(brianwilkerson) Do we need to report this error, or is this
1957 // condition always caught in the parser?
1958 // reportError(ResolverErrorCode.BREAK_OUTSIDE_LOOP);
1959 } else {
1960 labelElement =
1961 labelScope.lookup(LabelScope.EMPTY_LABEL) as LabelElementImpl;
1962 if (labelElement == null) {
1963 // TODO(brianwilkerson) Do we need to report this error, or is this
1964 // condition always caught in the parser?
1965 // reportError(ResolverErrorCode.BREAK_OUTSIDE_LOOP);
1966 }
1967 //
1968 // The label element that was returned was a marker for look-up and
1969 // isn't stored in the element model.
1970 //
1971 labelElement = null;
1972 }
1973 } else {
1974 if (labelScope == null) {
1975 _resolver.reportErrorForNode(
1976 CompileTimeErrorCode.LABEL_UNDEFINED,
1977 labelNode,
1978 [labelNode.name]);
1979 } else {
1980 labelElement = labelScope.lookup(labelNode.name) as LabelElementImpl;
1981 if (labelElement == null) {
1982 _resolver.reportErrorForNode(
1983 CompileTimeErrorCode.LABEL_UNDEFINED,
1984 labelNode,
1985 [labelNode.name]);
1986 } else {
1987 labelNode.staticElement = labelElement;
1988 }
1989 }
1990 }
1991 if (labelElement != null) {
1992 ExecutableElement labelContainer =
1993 labelElement.getAncestor((element) => element is ExecutableElement);
1994 if (!identical(labelContainer, _resolver.enclosingFunction)) {
1995 _resolver.reportErrorForNode(
1996 CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE,
1997 labelNode,
1998 [labelNode.name]);
1999 labelElement = null;
2000 }
2001 }
2002 return labelElement;
2003 }
2004
2005 /**
2006 * Look up all methods of a given name defined on a union type.
2007 *
2008 * @param target
2009 * @param type
2010 * @param methodName
2011 * @return all methods named `methodName` defined on the union type `type`.
2012 */
2013 Set<ExecutableElement> _lookupMethods(Expression target, UnionType type,
2014 String methodName) {
2015 Set<ExecutableElement> methods = new HashSet<ExecutableElement>();
2016 bool allElementsHaveMethod = true;
2017 for (DartType t in type.elements) {
2018 MethodElement m = _lookUpMethod(target, t, methodName);
2019 if (m != null) {
2020 methods.add(m);
2021 } else {
2022 allElementsHaveMethod = false;
2023 }
2024 }
2025 // For strict union types we require that all types in the union define the
2026 // method.
2027 if (AnalysisEngine.instance.strictUnionTypes) {
2028 if (allElementsHaveMethod) {
2029 return methods;
2030 } else {
2031 return new Set<ExecutableElement>();
2032 }
2033 } else {
2034 return methods;
2035 }
2036 }
2037
2038 /**
2039 * Given some class element, this method uses [subtypeManager] to find the set of all 2023 * Given some class element, this method uses [subtypeManager] to find the set of all
2040 * subtypes; the subtypes are then searched for a member (method, getter, or s etter), that matches 2024 * subtypes; the subtypes are then searched for a member (method, getter, or s etter), that matches
2041 * a passed 2025 * a passed
2042 * 2026 *
2043 * @param element the class element to search the subtypes of, if a non-ClassE lement element is 2027 * @param element the class element to search the subtypes of, if a non-ClassE lement element is
2044 * passed, then `false` is returned 2028 * passed, then `false` is returned
2045 * @param memberName the member name to search for 2029 * @param memberName the member name to search for
2046 * @param asMethod `true` if the methods should be searched for in the subtype s 2030 * @param asMethod `true` if the methods should be searched for in the subtype s
2047 * @param asAccessor `true` if the accessors (getters and setters) should be s earched for in 2031 * @param asAccessor `true` if the accessors (getters and setters) should be s earched for in
2048 * the subtypes 2032 * the subtypes
(...skipping 1030 matching lines...) Expand 10 before | Expand all | Expand 10 after
3079 @override 3063 @override
3080 Element get staticElement => null; 3064 Element get staticElement => null;
3081 3065
3082 @override 3066 @override
3083 accept(AstVisitor visitor) => null; 3067 accept(AstVisitor visitor) => null;
3084 3068
3085 @override 3069 @override
3086 void visitChildren(AstVisitor visitor) { 3070 void visitChildren(AstVisitor visitor) {
3087 } 3071 }
3088 } 3072 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698