* This field goes on top-most implementers of the interface the field is declared onto | * This field goes on top-most implementers of the interface the field is declared onto | ||||
*/ | */ | ||||
public static ResolvedMember interFieldInterfaceField(ResolvedMember field, UnresolvedType onClass, UnresolvedType aspectType) { | public static ResolvedMember interFieldInterfaceField(ResolvedMember field, UnresolvedType onClass, UnresolvedType aspectType) { | ||||
return new ResolvedMemberImpl(Member.FIELD, onClass, makePublicNonFinal(field.getModifiers()), field.getReturnType(), | |||||
NameMangler.interFieldInterfaceField(aspectType, field.getDeclaringType(), field.getName()), UnresolvedType.NONE, | |||||
UnresolvedType.NONE); | |||||
// return new ResolvedMemberImpl(Member.FIELD, onClass, makePublicNonFinal(field.getModifiers()), field.getReturnType(), | |||||
// NameMangler.interFieldInterfaceField(aspectType, field.getDeclaringType(), field.getName()), UnresolvedType.NONE, | |||||
// UnresolvedType.NONE); | |||||
// TODO what about non public fields, can you have those? | |||||
return interFieldClassField(field,aspectType,true); | |||||
} | } | ||||
/** | /** |
return false; | return false; | ||||
} | } | ||||
if (m1.getKind() == Member.FIELD) { | |||||
return m1.getDeclaringType().equals(m2.getDeclaringType()); | |||||
if (m1.getKind() == Member.FIELD && m1.getDeclaringType().equals(m2.getDeclaringType())) { | |||||
return true ; | |||||
} else if (m1.getKind() == Member.POINTCUT) { | } else if (m1.getKind() == Member.POINTCUT) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
boolean needsAdding = true; | |||||
boolean needsToBeAddedEarlier = false; | |||||
// now compare to existingMungers | // now compare to existingMungers | ||||
for (Iterator<ConcreteTypeMunger> i = interTypeMungers.iterator(); i.hasNext();) { | for (Iterator<ConcreteTypeMunger> i = interTypeMungers.iterator(); i.hasNext();) { | ||||
ConcreteTypeMunger existingMunger = i.next(); | ConcreteTypeMunger existingMunger = i.next(); | ||||
if (conflictingSignature(existingMunger.getSignature(), munger.getSignature())) { | if (conflictingSignature(existingMunger.getSignature(), munger.getSignature())) { | ||||
// System.err.println("match " + munger + " with " + | |||||
// existingMunger); | |||||
// System.err.println("match " + munger + " with " + existingMunger); | |||||
if (isVisible(munger.getSignature().getModifiers(), munger.getAspectType(), existingMunger.getAspectType())) { | if (isVisible(munger.getSignature().getModifiers(), munger.getAspectType(), existingMunger.getAspectType())) { | ||||
// System.err.println(" is visible"); | // System.err.println(" is visible"); | ||||
int c = compareMemberPrecedence(sig, existingMunger.getSignature()); | int c = compareMemberPrecedence(sig, existingMunger.getSignature()); | ||||
if (c < 0) { | if (c < 0) { | ||||
// the existing munger dominates the new munger | // the existing munger dominates the new munger | ||||
checkLegalOverride(munger.getSignature(), existingMunger.getSignature(), 0x11, null); | checkLegalOverride(munger.getSignature(), existingMunger.getSignature(), 0x11, null); | ||||
return; | |||||
needsAdding = false; | |||||
// return; | |||||
if (munger.getSignature().getKind()==Member.FIELD && | |||||
munger.getSignature().getDeclaringType().resolve(world).isInterface()) { | |||||
needsAdding=true; | |||||
} | |||||
break; | |||||
} else if (c > 0) { | } else if (c > 0) { | ||||
// the new munger dominates the existing one | // the new munger dominates the existing one | ||||
checkLegalOverride(existingMunger.getSignature(), munger.getSignature(), 0x11, null); | checkLegalOverride(existingMunger.getSignature(), munger.getSignature(), 0x11, null); | ||||
i.remove(); | |||||
if (munger.getSignature().getKind()==Member.FIELD && | |||||
munger.getSignature().getDeclaringType().resolve(world).isInterface()) { | |||||
needsToBeAddedEarlier = true; | |||||
} else { | |||||
i.remove(); | |||||
} | |||||
break; | break; | ||||
} else { | } else { | ||||
interTypeConflictError(munger, existingMunger); | interTypeConflictError(munger, existingMunger); | ||||
// we are adding the parameterized form of the ITD to the list of | // we are adding the parameterized form of the ITD to the list of | ||||
// mungers. Within it, the munger knows the original declared | // mungers. Within it, the munger knows the original declared | ||||
// signature for the ITD so it can be retrieved. | // signature for the ITD so it can be retrieved. | ||||
interTypeMungers.add(munger); | |||||
if (needsAdding) { | |||||
if (!needsToBeAddedEarlier) { | |||||
interTypeMungers.add(munger); | |||||
} else { | |||||
interTypeMungers.add(0,munger); | |||||
} | |||||
} | |||||
} | } | ||||
/** | /** |
import java.lang.reflect.*; | |||||
interface I { | |||||
} | |||||
class C implements I { | |||||
} | |||||
public aspect Case1 { | |||||
public int I.i; | |||||
public static void main(String []argv) throws Exception { | |||||
Field f = C.class.getField("i"); | |||||
if (f==null) System.out.println("Couldn't find a field called i"); | |||||
else System.out.println("Found a field called i"); | |||||
} | |||||
} |
import java.lang.reflect.*; | |||||
interface I { | |||||
} | |||||
class C implements I { | |||||
public int i = 1; | |||||
} | |||||
public aspect Case2 { | |||||
public int I.i = 5; | |||||
public static void main(String []argv) { | |||||
System.out.println("Value of C.i is "+new C().i); | |||||
} | |||||
} |
import java.lang.reflect.*; | |||||
interface I { | |||||
} | |||||
class C implements I { | |||||
} | |||||
public aspect Case3 { | |||||
// one order | |||||
public int C.i = 1; | |||||
public int I.i = 5; | |||||
// the other order ;) | |||||
public int I.j = 5; | |||||
public int C.j = 1; | |||||
public static void main(String []argv) { | |||||
System.out.println("Value of C.i is "+new C().i); | |||||
System.out.println("Value of C.j is "+new C().j); | |||||
System.out.println("Value of I.i is "+((I)new C()).i); | |||||
System.out.println("Value of I.j is "+((I)new C()).j); | |||||
} | |||||
} |
import java.lang.reflect.*; | |||||
interface I { | |||||
} | |||||
class C implements I { | |||||
public int i = 1; | |||||
} | |||||
public aspect Case4 { | |||||
public String I.i = "hello"; | |||||
public static void main(String []argv) { | |||||
} | |||||
} |
*/ | */ | ||||
public class Ajc170Tests extends org.aspectj.testing.XMLBasedAjcTestCase { | public class Ajc170Tests extends org.aspectj.testing.XMLBasedAjcTestCase { | ||||
public void testPublicITDFs_pr73507_1() { | |||||
runTest("public ITDfs - 1"); | |||||
} | |||||
public void testPublicITDFs_pr73507_2() { | |||||
runTest("public ITDfs - 2"); | |||||
} | |||||
public void testPublicITDFs_pr73507_3() { | |||||
runTest("public ITDfs - 3"); | |||||
} | |||||
public void testPublicITDFs_pr73507_4() { | |||||
runTest("public ITDfs - 4"); | |||||
} | |||||
public void testBCExceptionAnnoDecp_371998() { | public void testBCExceptionAnnoDecp_371998() { | ||||
runTest("BCException anno decp"); | runTest("BCException anno decp"); | ||||
} | } |
<suite> | <suite> | ||||
<ajc-test dir="bugs170/pr73507" title="public ITDfs - 1"> | |||||
<compile files="Case1.java" options="-1.5"/> | |||||
<run class="Case1"> | |||||
<stdout> | |||||
<line text="Found a field called i"/> | |||||
</stdout> | |||||
</run> | |||||
</ajc-test> | |||||
<ajc-test dir="bugs170/pr73507" title="public ITDfs - 2"> | |||||
<compile files="Case2.java" options="-1.5"/> | |||||
<run class="Case2"> | |||||
<stdout> | |||||
<line text="Value of C.i is 1"/> | |||||
</stdout> | |||||
</run> | |||||
</ajc-test> | |||||
<ajc-test dir="bugs170/pr73507" title="public ITDfs - 3"> | |||||
<compile files="Case3.java" options="-1.5"/> | |||||
<run class="Case3"> | |||||
<stdout> | |||||
<line text="Value of C.i is 1"/> | |||||
<line text="Value of C.j is 1"/> | |||||
</stdout> | |||||
</run> | |||||
</ajc-test> | |||||
<ajc-test dir="bugs170/pr73507" title="public ITDfs - 4"> | |||||
<compile files="Case4.java" options="-1.5"> | |||||
<message kind="error" line="13" text="can't override java.lang.String I.i with int C.i return types don't match"/> | |||||
</compile> | |||||
</ajc-test> | |||||
<ajc-test dir="bugs170/pr371998" title="BCException anno decp"> | <ajc-test dir="bugs170/pr371998" title="BCException anno decp"> | ||||
<compile files="AspectTest.java" options="-1.5 -showWeaveInfo"> | <compile files="AspectTest.java" options="-1.5 -showWeaveInfo"> | ||||
<message kind="weave" text="Extending interface set for type 'Foo' (AspectTest.java) to include 'X' (AspectTest.java)"/> | <message kind="weave" text="Extending interface set for type 'Foo' (AspectTest.java) to include 'X' (AspectTest.java)"/> |
ResolvedMember[] methods = typeToCheck.getDeclaredMethods(); | ResolvedMember[] methods = typeToCheck.getDeclaredMethods(); | ||||
for (int ii = 0; ii < methods.length; ii++) { | for (int ii = 0; ii < methods.length; ii++) { | ||||
ResolvedMember methodThatMightBeGettingOverridden = methods[ii]; // the | |||||
// method | |||||
// we | |||||
// are | |||||
// going | |||||
// to | |||||
// check | |||||
// the method we are going to check | |||||
ResolvedMember methodThatMightBeGettingOverridden = methods[ii]; | |||||
ResolvedMember isOverriding = isOverriding(typeToCheck, methodThatMightBeGettingOverridden, mname, mrettype, mmods, | ResolvedMember isOverriding = isOverriding(typeToCheck, methodThatMightBeGettingOverridden, mname, mrettype, mmods, | ||||
inSamePackage, methodParamsArray); | inSamePackage, methodParamsArray); | ||||
if (isOverriding != null) { | if (isOverriding != null) { |
import org.aspectj.apache.bcel.Constants; | import org.aspectj.apache.bcel.Constants; | ||||
import org.aspectj.apache.bcel.classfile.ConstantPool; | import org.aspectj.apache.bcel.classfile.ConstantPool; | ||||
import org.aspectj.apache.bcel.classfile.Field; | |||||
import org.aspectj.apache.bcel.classfile.Signature; | import org.aspectj.apache.bcel.classfile.Signature; | ||||
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; | import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; | ||||
import org.aspectj.apache.bcel.generic.FieldGen; | import org.aspectj.apache.bcel.generic.FieldGen; | ||||
LazyMethodGen mg1 = makeMethodGen(gen, AjcMemberMaker.interFieldInterfaceSetter(field, onType, aspectType)); | LazyMethodGen mg1 = makeMethodGen(gen, AjcMemberMaker.interFieldInterfaceSetter(field, onType, aspectType)); | ||||
gen.addMethodGen(mg1); | gen.addMethodGen(mg1); | ||||
} else { | } else { | ||||
if (gen.fieldExists(field.getName())) return false; | |||||
weaver.addInitializer(this); | weaver.addInitializer(this); | ||||
ResolvedMember newField = AjcMemberMaker.interFieldClassField(field, aspectType, | ResolvedMember newField = AjcMemberMaker.interFieldClassField(field, aspectType, | ||||
munger.version == NewFieldTypeMunger.VersionTwo); | munger.version == NewFieldTypeMunger.VersionTwo); | ||||
} | } | ||||
return true; | return true; | ||||
} else if (onInterface && gen.getType().isTopmostImplementor(onType)) { | } else if (onInterface && gen.getType().isTopmostImplementor(onType)) { | ||||
// wew know that we can't be static since we don't allow statics on | |||||
// interfaces | |||||
// we know that we can't be static since we don't allow statics on interfaces | |||||
if (Modifier.isStatic(field.getModifiers())) { | if (Modifier.isStatic(field.getModifiers())) { | ||||
throw new RuntimeException("unimplemented"); | throw new RuntimeException("unimplemented"); | ||||
} | } | ||||
weaver.addInitializer(this); | |||||
// System.err.println("impl body on " + gen.getType() + " for " + | |||||
// munger); | |||||
Type fieldType = BcelWorld.makeBcelType(field.getType()); | Type fieldType = BcelWorld.makeBcelType(field.getType()); | ||||
FieldGen fg = makeFieldGen(gen, AjcMemberMaker.interFieldInterfaceField(field, onType, aspectType)); | |||||
if (annotationsOnRealMember != null) { | |||||
for (int i = 0; i < annotationsOnRealMember.length; i++) { | |||||
AnnotationAJ annotationX = annotationsOnRealMember[i]; | |||||
AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation(); | |||||
AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true); | |||||
fg.addAnnotation(ag); | |||||
String fieldname = field.getName(); | |||||
if (!gen.fieldExists(fieldname)) { | |||||
weaver.addInitializer(this); | |||||
// System.err.println("impl body on " + gen.getType() + " for " + | |||||
// munger); | |||||
FieldGen fg = makeFieldGen(gen, AjcMemberMaker.interFieldInterfaceField(field, onType, aspectType)); | |||||
if (annotationsOnRealMember != null) { | |||||
for (int i = 0; i < annotationsOnRealMember.length; i++) { | |||||
AnnotationAJ annotationX = annotationsOnRealMember[i]; | |||||
AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation(); | |||||
AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true); | |||||
fg.addAnnotation(ag); | |||||
} | |||||
} | } | ||||
fieldname = fg.getName(); | |||||
gen.addField(fg, getSourceLocation()); | |||||
} | } | ||||
gen.addField(fg, getSourceLocation()); | |||||
// this uses a shadow munger to add init method to constructors | // this uses a shadow munger to add init method to constructors | ||||
// weaver.getShadowMungers().add(makeInitCallShadowMunger(initMethod) | // weaver.getShadowMungers().add(makeInitCallShadowMunger(initMethod) | ||||
// ); | // ); | ||||
InstructionList il = new InstructionList(); | InstructionList il = new InstructionList(); | ||||
InstructionFactory fact = gen.getFactory(); | InstructionFactory fact = gen.getFactory(); | ||||
if (Modifier.isStatic(field.getModifiers())) { | if (Modifier.isStatic(field.getModifiers())) { | ||||
il.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.GETSTATIC)); | |||||
il.append(fact.createFieldAccess(gen.getClassName(), fieldname, fieldType, Constants.GETSTATIC)); | |||||
} else { | } else { | ||||
il.append(InstructionConstants.ALOAD_0); | il.append(InstructionConstants.ALOAD_0); | ||||
il.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.GETFIELD)); | |||||
il.append(fact.createFieldAccess(gen.getClassName(), fieldname, fieldType, Constants.GETFIELD)); | |||||
} | } | ||||
il.append(InstructionFactory.createReturn(fieldType)); | il.append(InstructionFactory.createReturn(fieldType)); | ||||
mg.getBody().insert(il); | mg.getBody().insert(il); | ||||
InstructionList il1 = new InstructionList(); | InstructionList il1 = new InstructionList(); | ||||
if (Modifier.isStatic(field.getModifiers())) { | if (Modifier.isStatic(field.getModifiers())) { | ||||
il1.append(InstructionFactory.createLoad(fieldType, 0)); | il1.append(InstructionFactory.createLoad(fieldType, 0)); | ||||
il1.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.PUTSTATIC)); | |||||
il1.append(fact.createFieldAccess(gen.getClassName(), fieldname, fieldType, Constants.PUTSTATIC)); | |||||
} else { | } else { | ||||
il1.append(InstructionConstants.ALOAD_0); | il1.append(InstructionConstants.ALOAD_0); | ||||
il1.append(InstructionFactory.createLoad(fieldType, 1)); | il1.append(InstructionFactory.createLoad(fieldType, 1)); | ||||
il1.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.PUTFIELD)); | |||||
il1.append(fact.createFieldAccess(gen.getClassName(), fieldname, fieldType, Constants.PUTFIELD)); | |||||
} | } | ||||
il1.append(InstructionFactory.createReturn(Type.VOID)); | il1.append(InstructionFactory.createReturn(Type.VOID)); | ||||
mg1.getBody().insert(il1); | mg1.getBody().insert(il1); |
public List<BcelField> getFieldGens() { | public List<BcelField> getFieldGens() { | ||||
return fields; | return fields; | ||||
} | } | ||||
public boolean fieldExists(String name) { | |||||
// Field[] allFields = myGen.getFields(); | |||||
// if (allFields!=null) { | |||||
// for (int i=0;i<allFields.length;i++) { | |||||
// Field f = allFields[i]; | |||||
// if (f.getName().equals(name)) { | |||||
// return f; | |||||
// } | |||||
// } | |||||
// } | |||||
for (BcelField f: fields) { | |||||
if (f.getName().equals(name)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
private void writeBack(BcelWorld world) { | private void writeBack(BcelWorld world) { | ||||
if (getConstantPool().getSize() > Short.MAX_VALUE) { | if (getConstantPool().getSize() > Short.MAX_VALUE) { |