View | Details | Raw Unified | Return to bug 288658 | Differences between
and this patch

Collapse All | Expand All

(-)compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java (+14 lines)
Lines 394-399 Link Here
394
				inherited[i].original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
394
				inherited[i].original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
395
			}
395
			}
396
		}
396
		}
397
		if (current == null && this.type.isPublic()) {
398
			int length = inherited.length;
399
			for (int i = 0; i < length; i++) {
400
				MethodBinding inheritedMethod = inherited[i];
401
				if (inheritedMethod.isPublic() && !inheritedMethod.declaringClass.isPublic())
402
					this.type.addSyntheticBridgeMethod(inheritedMethod);
403
			}
404
		}
397
405
398
		if (current == null && skipInheritedMethods)
406
		if (current == null && skipInheritedMethods)
399
			continue nextSelector;
407
			continue nextSelector;
Lines 444-449 Link Here
444
		boolean[] skip = new boolean[inheritedLength];
452
		boolean[] skip = new boolean[inheritedLength];
445
		for (int i = 0; i < inheritedLength; i++) {
453
		for (int i = 0; i < inheritedLength; i++) {
446
			MethodBinding matchMethod = foundMatch[i];
454
			MethodBinding matchMethod = foundMatch[i];
455
			if (matchMethod == null && current != null && this.type.isPublic()) { // current == null case handled already.
456
				MethodBinding inheritedMethod = inherited[i];
457
				if (inheritedMethod.isPublic() && !inheritedMethod.declaringClass.isPublic()) {
458
					this.type.addSyntheticBridgeMethod(inheritedMethod);
459
				}
460
			}
447
			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=296660, if current type is exposed,
461
			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=296660, if current type is exposed,
448
			// inherited methods of super classes are too. current == null case handled already.
462
			// inherited methods of super classes are too. current == null case handled already.
449
			if (!isOrEnclosedByPrivateType && matchMethod == null && current != null) {
463
			if (!isOrEnclosedByPrivateType && matchMethod == null && current != null) {
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java (+46 lines)
Lines 537-542 Link Here
537
	}
537
	}
538
	return accessMethod;
538
	return accessMethod;
539
}
539
}
540
/*
541
 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=288658. Generate a bridge method if a public method is inherited
542
 * from a non-public class into a public class (only in 1.6 or greater)
543
 */
544
public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge) {
545
	if (this.scope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_5) {
546
		return null;
547
	}
548
	if (isInterface()) return null;
549
	if (inheritedMethodToBridge.isAbstract() || inheritedMethodToBridge.isFinal() || inheritedMethodToBridge.isStatic()) {
550
		return null;
551
	}
552
	if (this.synthetics == null)
553
		this.synthetics = new HashMap[MAX_SYNTHETICS];
554
	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) {
555
		this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap(5);
556
	} else {
557
		// check to see if there is another equivalent inheritedMethod already added
558
		Iterator synthMethods = this.synthetics[SourceTypeBinding.METHOD_EMUL].keySet().iterator();
559
		while (synthMethods.hasNext()) {
560
			Object synthetic = synthMethods.next();
561
			if (synthetic instanceof MethodBinding) {
562
				MethodBinding method = (MethodBinding) synthetic;
563
				if (CharOperation.equals(inheritedMethodToBridge.selector, method.selector)
564
					&& inheritedMethodToBridge.returnType.erasure() == method.returnType.erasure()
565
					&& inheritedMethodToBridge.areParameterErasuresEqual(method)) {
566
						return null;
567
				}
568
			}
569
		}
570
	}
571
572
	SyntheticMethodBinding accessMethod = null;
573
	SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(inheritedMethodToBridge);
574
	if (accessors == null) {
575
		accessMethod = new SyntheticMethodBinding(inheritedMethodToBridge, this);
576
		this.synthetics[SourceTypeBinding.METHOD_EMUL].put(inheritedMethodToBridge, accessors = new SyntheticMethodBinding[2]);
577
		accessors[0] = accessMethod;
578
	} else {
579
		if ((accessMethod = accessors[0]) == null) {
580
			accessMethod = new SyntheticMethodBinding(inheritedMethodToBridge, this);
581
			accessors[0] = accessMethod;
582
		}
583
	}
584
	return accessMethod;
585
}
540
boolean areFieldsInitialized() {
586
boolean areFieldsInitialized() {
541
	return this.fields != Binding.UNINITIALIZED_FIELDS;
587
	return this.fields != Binding.UNINITIALIZED_FIELDS;
542
}
588
}
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java (-1 / +22 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 264-269 Link Here
264
			this.modifiers |= ClassFileConstants.AccStrictfp;
264
			this.modifiers |= ClassFileConstants.AccStrictfp;
265
		}
265
		}
266
	}
266
	}
267
	
268
	// Create a synthetic method that will simply call the super classes method.
269
	// Used when a public method is inherited from a non-public class into a public class.
270
	// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=288658
271
	public SyntheticMethodBinding(MethodBinding overridenMethodToBridge, SourceTypeBinding declaringClass) {
272
273
	    this.declaringClass = declaringClass;
274
	    this.selector = overridenMethodToBridge.selector;
275
	    // amongst other, clear the AccGenericSignature, so as to ensure no remains of original inherited persist (101794)
276
	    // also use the modifiers from the target method, as opposed to inherited one (147690)
277
	    this.modifiers = (overridenMethodToBridge.modifiers | ClassFileConstants.AccBridge | ClassFileConstants.AccSynthetic) & ~(ClassFileConstants.AccAbstract | ClassFileConstants.AccNative  | ClassFileConstants.AccFinal | ExtraCompilerModifiers.AccGenericSignature);
278
		this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
279
	    this.returnType = overridenMethodToBridge.returnType;
280
	    this.parameters = overridenMethodToBridge.parameters;
281
	    this.thrownExceptions = overridenMethodToBridge.thrownExceptions;
282
	    this.targetMethod = overridenMethodToBridge;
283
	    this.purpose = SyntheticMethodBinding.SuperMethodAccess;
284
		SyntheticMethodBinding[] knownAccessMethods = declaringClass.syntheticMethods();
285
		int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
286
		this.index = methodId;
287
	}
267
288
268
	/**
289
	/**
269
	 * An constructor accessor is a constructor with an extra argument (declaringClass), in case of
290
	 * An constructor accessor is a constructor with an extra argument (declaringClass), in case of
(-)src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java (+75 lines)
Lines 10832-10835 Link Here
10832
		},
10832
		},
10833
		"class java.lang.Object");
10833
		"class java.lang.Object");
10834
}
10834
}
10835
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=288658, make sure a bridge method
10836
// is generated when a public method is inherited from a non-public class into a
10837
// public class.
10838
public void test208() {
10839
	this.runConformTest(
10840
		new String[] {
10841
			"Test.java",
10842
			"import java.lang.annotation.Annotation;\n"+ 
10843
			"import java.lang.annotation.Retention;\n"+ 
10844
			"import java.lang.annotation.RetentionPolicy;\n"+ 
10845
			"import java.lang.reflect.Method;\n"+ 
10846
			"\n"+ 
10847
			"public class Test extends Super {\n"+ 
10848
			"    public static void main(String[] args) {\n"+ 
10849
			"        try {\n"+ 
10850
			"            Method m = Test.class.getMethod(\"setFoo\", String.class);\n"+
10851
			"            Annotation a = m.getAnnotation(Anno.class);\n"+ 
10852
			"            System.out.println(\"Annotation was \" + (a == null ? \"not \" : \"\") +\n"+ 
10853
			"\"found\");\n"+ 
10854
			"        } catch (Exception e) {\n"+ 
10855
			"            e.printStackTrace();\n"+ 
10856
			"        }\n"+ 
10857
			"    }\n"+ 
10858
			"}\n"+ 
10859
			"\n"+ 
10860
			"class Super {\n"+ 
10861
			"    @Anno\n"+ 
10862
			"    public void setFoo(String foo) {}\n"+ 
10863
			"}\n"+ 
10864
			"\n"+ 
10865
			"@Retention(RetentionPolicy.RUNTIME)\n"+ 
10866
			"@interface Anno {\n"+ 
10867
			"\n"+ 
10868
			"}\n"
10869
		},
10870
		this.complianceLevel <= ClassFileConstants.JDK1_5 ? "Annotation was found" : "Annotation was not found");
10871
}
10872
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=288658, make sure a bridge method
10873
// is generated when a public method is inherited from a non-public class into a
10874
// public class.
10875
public void test208a() {
10876
	this.runConformTest(
10877
		new String[] {
10878
			"Test.java",
10879
			"import java.lang.annotation.Annotation;\n"+ 
10880
			"import java.lang.annotation.Retention;\n"+ 
10881
			"import java.lang.annotation.RetentionPolicy;\n"+ 
10882
			"import java.lang.reflect.Method;\n"+ 
10883
			"\n"+ 
10884
			"public class Test extends Super {\n"+
10885
			"    public void setFoo() {}\n" +
10886
			"    public static void main(String[] args) {\n"+ 
10887
			"        try {\n"+ 
10888
			"            Method m = Test.class.getMethod(\"setFoo\", String.class);\n"+
10889
			"            Annotation a = m.getAnnotation(Anno.class);\n"+ 
10890
			"            System.out.println(\"Annotation was \" + (a == null ? \"not \" : \"\") +\n"+ 
10891
			"\"found\");\n"+ 
10892
			"        } catch (Exception e) {\n"+ 
10893
			"            e.printStackTrace();\n"+ 
10894
			"        }\n"+ 
10895
			"    }\n"+ 
10896
			"}\n"+ 
10897
			"\n"+ 
10898
			"class Super {\n"+ 
10899
			"    @Anno\n"+ 
10900
			"    public void setFoo(String foo) {}\n"+ 
10901
			"}\n"+ 
10902
			"\n"+ 
10903
			"@Retention(RetentionPolicy.RUNTIME)\n"+ 
10904
			"@interface Anno {\n"+ 
10905
			"\n"+ 
10906
			"}\n"
10907
		},
10908
		this.complianceLevel <= ClassFileConstants.JDK1_5 ? "Annotation was found" : "Annotation was not found");
10909
}
10835
}
10910
}
(-)src/org/eclipse/jdt/core/tests/compiler/regression/RuntimeTests.java (-2 / +1 lines)
Lines 176-183 Link Here
176
			"  }\n" +
176
			"  }\n" +
177
			"}\n"},
177
			"}\n"},
178
		"",
178
		"",
179
		"SUCCESS\n" +
179
		this.complianceLevel <= ClassFileConstants.JDK1_5 ? "SUCCESS\n" + "FAILURE: IllegalAccessException" : "SUCCESS\n" + "SUCCESS",
180
		"FAILURE: IllegalAccessException",
181
		"",
180
		"",
182
		JavacTestOptions.EclipseJustification.EclipseBug126712
181
		JavacTestOptions.EclipseJustification.EclipseBug126712
183
	);
182
	);

Return to bug 288658