diff options
author | Keigo Imai | 2013-05-16 07:53:54 +0000 |
---|---|---|
committer | Jayaprakash Arthanareeswaran | 2013-05-16 10:59:10 +0000 |
commit | a4f4cf398b9c048885f33786fe40b8704243b93a (patch) | |
tree | 76d2f4445ce36cd85b34db8954759c821b819087 | |
parent | f9a29367ea8f3c4c9489072b937e0b301d28ae36 (diff) | |
download | eclipse.jdt.core-a4f4cf398b9c048885f33786fe40b8704243b93a.tar.gz eclipse.jdt.core-a4f4cf398b9c048885f33786fe40b8704243b93a.tar.xz eclipse.jdt.core-a4f4cf398b9c048885f33786fe40b8704243b93a.zip |
[388903] Cannot extend inner class as an anonymous class when it extends
the outer class
Thanks, Keigo!
4 files changed, 88 insertions, 12 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerEmulationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerEmulationTest.java index bbb9c35a56..b177c9c467 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerEmulationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerEmulationTest.java @@ -13,6 +13,8 @@ * IBM Corporation - initial API and implementation * Stephan Herrmann - Contribution for * Bug 388800 - [1.8] adjust tests to 1.8 JRE + * Keigo Imai - Contribution for bug 388903 - Cannot extend inner class as an anonymous class when it extends the outer class +>>>>>>> 11dd8a9 [388903] Cannot extend inner class as an anonymous class when it extends the outer class *******************************************************************************/ package org.eclipse.jdt.core.tests.compiler.regression; @@ -6899,6 +6901,53 @@ public void test174() throws Exception { }, "SUCCESS"); } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=388903 +public void test175() throws Exception { + this.runConformTest( + new String[] { + "X.java",//======================= + "public class X {\n" + + " class Inner extends X {\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " new X().new Inner(){};\n" + + " System.out.println(\"SUCCESS\");\n" + + " }\n" + + "}", + }, + "SUCCESS"); + this.runConformTest( + new String[] { + "X.java",//======================= + "public class X {\n" + + " String which;\n" + + " X(String s) {\n" + + " this.which = s;\n" + + " }\n" + + " class Inner extends X {\n" + + " Inner() {\n" + + " super(\"Inner\");\n" + + " System.out.print( X.this.which + \",\" ); // will output 'Enclosing,'\n" + + " }\n" + + " }\n" + + " void check() {\n" + + " new X(\"Enclosing\").new Inner() {\n" + + " {\n" + + " System.out.print( X.this.which + \",\" ); // will output 'Context,'\n" + + " }\n" + + " void f() {\n" + + " System.out.println( X.this.which ); // will output 'Context'\n" + + " }\n" + + " }.f();\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " new X(\"Context\").check();\n" + + " }\n" + + "}", + }, + "Enclosing,Context,Context"); +} + public static Class testClass() { return InnerEmulationTest.class; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java index 34ae4bfce5..b1aa52695e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java @@ -14,6 +14,7 @@ * Stephan Herrmann - Contributions for * Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop) * Bug 388630 - @NonNull diagnostics at line 0 + * Keigo Imai - Contribution for bug 388903 - Cannot extend inner class as an anonymous class when it extends the outer class *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -796,7 +797,7 @@ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, Fl if (enclosing.isNestedType()) { NestedTypeBinding nestedEnclosing = (NestedTypeBinding)enclosing; // if (nestedEnclosing.findSuperTypeErasingTo(nestedEnclosing.enclosingType()) == null) { // only if not inheriting - SyntheticArgumentBinding syntheticEnclosingInstanceArgument = nestedEnclosing.getSyntheticArgument(nestedEnclosing.enclosingType(), true); + SyntheticArgumentBinding syntheticEnclosingInstanceArgument = nestedEnclosing.getSyntheticArgument(nestedEnclosing.enclosingType(), true, false); if (syntheticEnclosingInstanceArgument != null) { nestedType.addSyntheticArgumentAndField(syntheticEnclosingInstanceArgument); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java index e80e2533c9..83bed12349 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java @@ -23,6 +23,7 @@ * bug 404649 - [1.8][compiler] detect illegal reference to indirect or redundant super * Jesper S Moller <jesper@selskabet.org> - Contributions for * bug 378674 - "The method can be declared as static" is wrong + * Keigo Imai - Contribution for bug 388903 - Cannot extend inner class as an anonymous class when it extends the outer class *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -809,10 +810,13 @@ public Object[] getEmulationPath(ReferenceBinding targetEnclosingType, boolean o // use synthetic constructor arguments if possible if (insideConstructor) { SyntheticArgumentBinding syntheticArg; - if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, onlyExactMatch)) != null) { + if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, onlyExactMatch, currentMethodScope.isConstructorCall)) != null) { + boolean isAnonymousAndHasEnclosing = sourceType.isAnonymousType() + && sourceType.scope.referenceContext.allocation.enclosingInstance != null; // reject allocation and super constructor call if (denyEnclosingArgInConstructorCall && currentMethodScope.isConstructorCall + && !isAnonymousAndHasEnclosing && (sourceType == targetEnclosingType || (!onlyExactMatch && sourceType.findSuperTypeOriginatingFrom(targetEnclosingType) != null))) { return BlockScope.NoEnclosingInstanceInConstructorCall; } @@ -828,7 +832,7 @@ public Object[] getEmulationPath(ReferenceBinding targetEnclosingType, boolean o ReferenceBinding enclosingType = sourceType.enclosingType(); if (enclosingType.isNestedType()) { NestedTypeBinding nestedEnclosingType = (NestedTypeBinding) enclosingType; - SyntheticArgumentBinding enclosingArgument = nestedEnclosingType.getSyntheticArgument(nestedEnclosingType.enclosingType(), onlyExactMatch); + SyntheticArgumentBinding enclosingArgument = nestedEnclosingType.getSyntheticArgument(nestedEnclosingType.enclosingType(), onlyExactMatch, currentMethodScope.isConstructorCall); if (enclosingArgument != null) { FieldBinding syntheticField = sourceType.getSyntheticField(enclosingArgument); if (syntheticField != null) { @@ -850,7 +854,7 @@ public Object[] getEmulationPath(ReferenceBinding targetEnclosingType, boolean o Object[] path = new Object[2]; // probably at least 2 of them ReferenceBinding currentType = sourceType.enclosingType(); if (insideConstructor) { - path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument(currentType, onlyExactMatch); + path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument(currentType, onlyExactMatch, currentMethodScope.isConstructorCall); } else { if (currentMethodScope.isConstructorCall){ return BlockScope.NoEnclosingInstanceInConstructorCall; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java index af25174cfa..d101e138a5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Stephan Herrmann - Contribution for bug 365662 - [compiler][null] warn on contradictory and redundant null annotations + * Keigo Imai - Contribution for bug 388903 - Cannot extend inner class as an anonymous class when it extends the outer class *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -70,12 +71,13 @@ public SyntheticArgumentBinding addSyntheticArgument(ReferenceBinding targetEncl } else { int size = this.enclosingInstances.length; int newArgIndex = size; - for (int i = size; --i >= 0;) { - if (this.enclosingInstances[i].type == targetEnclosingType) - return this.enclosingInstances[i]; // already exists - if (enclosingType() == targetEnclosingType) - newArgIndex = 0; - } + if (enclosingType() == targetEnclosingType) + newArgIndex = 0; + // do not cache things! there can be two instances of same type! + // for (int i = size; --i >= 0;) { + //if (this.enclosingInstances[i].type == targetEnclosingType) + // return this.enclosingInstances[i]; // already exists + // } SyntheticArgumentBinding[] newInstances = new SyntheticArgumentBinding[size + 1]; System.arraycopy(this.enclosingInstances, 0, newInstances, newArgIndex == 0 ? 1 : 0, size); newInstances[newArgIndex] = synthLocal = new SyntheticArgumentBinding(targetEnclosingType); @@ -170,9 +172,29 @@ public SyntheticArgumentBinding getSyntheticArgument(LocalVariableBinding actual /* Answer the synthetic argument for <targetEnclosingType> or null if one does not exist. */ -public SyntheticArgumentBinding getSyntheticArgument(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) { +/* Answer the synthetic argument for <targetEnclosingType> or null if one does not exist. +*/ +public SyntheticArgumentBinding getSyntheticArgument(ReferenceBinding targetEnclosingType, boolean onlyExactMatch, boolean scopeIsConstructorCall) { if (this.enclosingInstances == null) return null; // is null if no enclosing instances are known + // exact match + + // firstly, during allocation, check and use the leftmost one (if possible) + // to handle cases involving two instances of same type, such as + // class X { + // class Inner extends X {} + // void f(){ + // new X().new Inner(){} + // // here the result of (new X()) is passed as the first (synthetic) arg for ctor of new Inner(){} + // // (and (this) as the second, of course) + // } + // } + if (scopeIsConstructorCall && this.enclosingInstances.length > 0) + if (this.enclosingInstances[0].type == targetEnclosingType) + if (this.enclosingInstances[0].actualOuterLocalVariable == null) + return this.enclosingInstances[0]; + + // then check other possibility for (int i = this.enclosingInstances.length; --i >= 0;) if (this.enclosingInstances[i].type == targetEnclosingType) if (this.enclosingInstances[i].actualOuterLocalVariable == null) |