|
57 | 57 | import org.eclipse.jdt.core.dom.SimpleType; |
58 | 58 | import org.eclipse.jdt.core.dom.Statement; |
59 | 59 | import org.eclipse.jdt.core.dom.StringLiteral; |
| 60 | +import org.eclipse.jdt.core.dom.SuperFieldAccess; |
60 | 61 | import org.eclipse.jdt.core.dom.ThisExpression; |
61 | 62 | import org.eclipse.jdt.core.dom.Type; |
62 | 63 | import org.eclipse.jdt.core.dom.TypeLiteral; |
@@ -113,7 +114,17 @@ private static final String getPrimitiveTYPE(String name) { |
113 | 114 | private boolean isArray = false; |
114 | 115 | protected int blockLevel = 0; |
115 | 116 | protected int currentBlockForVisit = -1; |
| 117 | + |
| 118 | + public String parentClassName; |
| 119 | + |
| 120 | + |
| 121 | + /** |
| 122 | + * used in case we are applying a private outer class method |
| 123 | + * |
| 124 | + */ |
116 | 125 | protected String b$name; |
| 126 | + |
| 127 | + |
117 | 128 | protected Stack<String> methodDeclareNameStack = new Stack<String>(); |
118 | 129 |
|
119 | 130 | /** |
@@ -979,8 +990,8 @@ private String simpleNameInMethodBinding(SimpleName node, boolean isQualified, I |
979 | 990 | ASTNode parent = node.getParent(); |
980 | 991 | boolean checkNameViolation = false; |
981 | 992 | if (parent != null && !(parent instanceof FieldAccess)) { |
982 | | - IMethodBinding variableDeclaration = mBinding.getMethodDeclaration(); |
983 | | - ITypeBinding declaringClass = variableDeclaration.getDeclaringClass(); |
| 993 | + IMethodBinding methodDeclaration = mBinding.getMethodDeclaration(); |
| 994 | + ITypeBinding declaringClass = methodDeclaration.getDeclaringClass(); |
984 | 995 | if (!isQualified && declaringClass != null && getUnqualifiedClassName() != null) { |
985 | 996 | String className = declaringClass.getQualifiedName(); |
986 | 997 | checkNameViolation = !("java.lang.String".equals(className) && "valueOf".equals(name)); |
@@ -1015,15 +1026,15 @@ private String simpleNameInVarBinding(SimpleName node, char ch, IVariableBinding |
1015 | 1026 | name = assureQualifiedName(name); |
1016 | 1027 | if (name.length() != 0) { |
1017 | 1028 | ret = getQualifiedStaticName(null, name, true, true, false) + "."; |
1018 | | - ch = '.'; |
| 1029 | + //ch = '.'; |
1019 | 1030 | } |
1020 | 1031 | } |
1021 | 1032 | } else { |
1022 | 1033 | ASTNode parent = node.getParent(); |
1023 | 1034 | if (parent != null && !(parent instanceof FieldAccess)) { |
1024 | 1035 | if (declaringClass != null && getUnqualifiedClassName() != null && ch != '.') { |
1025 | 1036 | ret = getClassNameAndDot(parent, declaringClass, false); |
1026 | | - ch = '.'; |
| 1037 | + //ch = '.'; |
1027 | 1038 | } |
1028 | 1039 | } |
1029 | 1040 | String fieldVar = null; |
@@ -1068,6 +1079,53 @@ public boolean visit(StringLiteral node) { |
1068 | 1079 | return false; |
1069 | 1080 | } |
1070 | 1081 |
|
| 1082 | + /** |
| 1083 | + * SuperFieldAccess: |
| 1084 | + * |
| 1085 | + *[ ClassName . ] super . Identifier |
| 1086 | + * |
| 1087 | + */ |
| 1088 | + public boolean visit(SuperFieldAccess node) { |
| 1089 | + ITypeBinding classBinding = resolveAbstractOrAnonymousBinding(node); |
| 1090 | + String fieldName = J2SMapAdapter.getJ2SName(node.getName()); |
| 1091 | + buffer.append("this."); |
| 1092 | + if (isInheritedFieldName(classBinding, fieldName)) { |
| 1093 | + if (classBinding != null) { |
| 1094 | + IVariableBinding[] declaredFields = classBinding.getDeclaredFields(); |
| 1095 | + for (int i = 0; i < declaredFields.length; i++) { |
| 1096 | + String superFieldName = J2SMapAdapter.getJ2SName(declaredFields[i]); |
| 1097 | + if (fieldName.equals(superFieldName)) { |
| 1098 | + buffer.append(getValidFieldName$Qualifier(fieldName, false)); |
| 1099 | + buffer.append(J2SMapAdapter.getFieldName$Appended(classBinding.getSuperclass(), fieldName)); |
| 1100 | + return false; |
| 1101 | + } |
| 1102 | + } |
| 1103 | + } |
| 1104 | + } |
| 1105 | + buffer.append(getValidFieldName$Qualifier(fieldName, true)); |
| 1106 | + return false; |
| 1107 | + } |
| 1108 | + |
| 1109 | + /** |
| 1110 | + * this or ClassName.this |
| 1111 | + * |
| 1112 | + */ |
| 1113 | + public boolean visit(ThisExpression node) { |
| 1114 | + Name className = node.getQualifier(); |
| 1115 | + if (className != null) { |
| 1116 | + ASTNode classNode = getAbstractOrAnonymousParentForNode(node); |
| 1117 | + if (classNode != null && classNode.getParent() != null // CompilationUnit |
| 1118 | + && classNode.getParent().getParent() != null) { |
| 1119 | + // just checking for top level? |
| 1120 | + buffer.append(getSyntheticReference(node.resolveTypeBinding().getQualifiedName())); |
| 1121 | + return false; |
| 1122 | + } |
| 1123 | + } |
| 1124 | + buffer.append("this"); |
| 1125 | + return false; |
| 1126 | + } |
| 1127 | + |
| 1128 | + |
1071 | 1129 | public boolean visit(TypeLiteral node) { |
1072 | 1130 | // Class x = Foo.class |
1073 | 1131 | Type type = node.getType(); |
@@ -1670,35 +1728,49 @@ protected void addVariable(FinalVariable f, String identifier, IBinding binding) |
1670 | 1728 | finalVars.add(f); |
1671 | 1729 | } |
1672 | 1730 |
|
1673 | | - protected String getClassNameAndDot(ASTNode parent, ITypeBinding declaringClass, boolean isPrivate) { |
| 1731 | + /** |
| 1732 | + * Determine the qualifier for a method or variable. |
| 1733 | + * |
| 1734 | + * In the case of private methods, this is "p$."; |
| 1735 | + * for general fields, this will be "this."; for fields in outer classes, we need a synthetic |
| 1736 | + * references, this.b$[className] that points to the outer object, which may be one or more levels |
| 1737 | + * higher than this one. |
| 1738 | + * |
| 1739 | + * Anonymous inner classes may reference either a superclass method/field or one in its declaring class |
| 1740 | + * stack. |
| 1741 | + * |
| 1742 | + * @param node either a method or field or local variable |
| 1743 | + * @param declaringClass the class that declares this variable |
| 1744 | + * @param isPrivate |
| 1745 | + * @return qualifier for method or variable |
| 1746 | + */ |
| 1747 | + protected String getClassNameAndDot(ASTNode node, ITypeBinding declaringClass, boolean isPrivate) { |
| 1748 | + |
1674 | 1749 | String name = declaringClass.getQualifiedName(); |
1675 | 1750 | String ret = ""; |
1676 | 1751 | int superLevel = 0; |
1677 | | - ITypeBinding originalType = null; |
1678 | 1752 | boolean isThis = false; |
1679 | | - while (parent != null) { |
1680 | | - boolean isAnonymous = (parent instanceof AnonymousClassDeclaration); |
1681 | | - ITypeBinding typeBinding = (isAnonymous ? ((AnonymousClassDeclaration) parent).resolveBinding() |
1682 | | - : parent instanceof AbstractTypeDeclaration ? ((AbstractTypeDeclaration) parent).resolveBinding() |
| 1753 | + |
| 1754 | + // Search parents of this node for an anonymous or abstract class declaration |
| 1755 | + while (node != null) { |
| 1756 | + boolean isAnonymous = (node instanceof AnonymousClassDeclaration); |
| 1757 | + ITypeBinding typeBinding = (isAnonymous ? ((AnonymousClassDeclaration) node).resolveBinding() |
| 1758 | + : node instanceof AbstractTypeDeclaration ? ((AbstractTypeDeclaration) node).resolveBinding() |
1683 | 1759 | : null); |
1684 | 1760 | if (typeBinding != null) { |
1685 | | - if (originalType == null) { |
1686 | | - originalType = typeBinding; |
1687 | | - } |
1688 | 1761 | superLevel++; |
1689 | 1762 | if (Bindings.isSuperType(declaringClass, typeBinding)) { |
1690 | 1763 | if (superLevel == 1) { |
1691 | 1764 | ret = (isPrivate ? "p$." : "this."); |
1692 | 1765 | isThis = true; |
1693 | 1766 | } |
1694 | 1767 | name = typeBinding.getQualifiedName(); |
1695 | | - if (!isAnonymous) |
1696 | | - break; |
1697 | | - name = ensureNameIfLocal(name, typeBinding, parent); |
| 1768 | + if (isAnonymous) |
| 1769 | + name = ensureNameIfLocal(name, typeBinding, node); |
1698 | 1770 | break; |
1699 | 1771 | } |
1700 | 1772 | } |
1701 | | - parent = parent.getParent(); |
| 1773 | + node = node.getParent(); |
1702 | 1774 | } |
1703 | 1775 | return (isThis ? ret : getSyntheticReference(name) + "."); |
1704 | 1776 | } |
@@ -1757,8 +1829,8 @@ protected void appendShortenedQualifiedName(String packageName, String name, boo |
1757 | 1829 | } |
1758 | 1830 | } |
1759 | 1831 |
|
1760 | | - protected String getSyntheticReference(String name) { |
1761 | | - b$name = ".b$['" + assureQualifiedNameNoC$(null, name) + "']"; |
| 1832 | + protected String getSyntheticReference(String className) { |
| 1833 | + b$name = (className.equals(parentClassName) ? ".this$0" : ".b$['" + assureQualifiedNameNoC$(null, className) + "']"); |
1762 | 1834 | return "this" + b$name; |
1763 | 1835 | } |
1764 | 1836 |
|
@@ -2040,6 +2112,22 @@ private static void checkMethodsWithGenericParams(String topClassKey, ITypeBindi |
2040 | 2112 |
|
2041 | 2113 | } |
2042 | 2114 |
|
| 2115 | + private static ASTNode getAbstractOrAnonymousParentForNode(ASTNode node) { |
| 2116 | + ASTNode parent = node.getParent(); |
| 2117 | + while (parent != null && !(parent instanceof AbstractTypeDeclaration) |
| 2118 | + && !(parent instanceof AnonymousClassDeclaration)) { |
| 2119 | + parent = parent.getParent(); |
| 2120 | + } |
| 2121 | + return parent; |
| 2122 | + } |
| 2123 | + |
| 2124 | + protected static ITypeBinding resolveAbstractOrAnonymousBinding(ASTNode node) { |
| 2125 | + node = getAbstractOrAnonymousParentForNode(node); |
| 2126 | + return (node instanceof AbstractTypeDeclaration ? ((AbstractTypeDeclaration) node).resolveBinding() |
| 2127 | + : node instanceof AnonymousClassDeclaration ? ((AnonymousClassDeclaration) node).resolveBinding() |
| 2128 | + : null); |
| 2129 | + } |
| 2130 | + |
2043 | 2131 | /** |
2044 | 2132 | * Create a map of the class type arguments for an implemented generic class |
2045 | 2133 | * |
|
0 commit comments