From: aclement Date: Fri, 10 Dec 2004 13:34:42 +0000 (+0000) Subject: Autoboxing and decp restrictions X-Git-Tag: Root_AspectJ5_Development~141 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b1111a9826f2734fd770183138bc0d74fad40579;p=aspectj.git Autoboxing and decp restrictions --- diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java index f3aad9214..e383fb458 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java @@ -612,6 +612,21 @@ public class BuildArgParser extends Main { buildConfig.setProceedOnError(true); } else if (new File(arg).isDirectory()) { showError("dir arg not permitted: " + arg); + } else if (arg.equals("-1.5")) { + buildConfig.setBehaveInJava5Way(true); +// this would enable the '-source 1.5' to do the same as '-1.5' but doesnt sound quite right as +// as an option right now as it doesnt mean we support 1.5 source code - people will get confused... +// } else if (arg.equals("-source")) { +// if (args.size() > nextArgIndex) { +// String level = ((ConfigParser.Arg)args.get(nextArgIndex)).getValue(); +// if (!level.equals("1.5")) { +// unparsedArgs.add("-source"); +// unparsedArgs.add(level); +// } else { +// buildConfig.setJava5Behaviour(true); +// } +// args.remove(args.get(nextArgIndex)); +// } } else { // argfile, @file parsed by superclass // no eclipse options parsed: diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties index 0dd92150a..061417143 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties @@ -55,6 +55,7 @@ Standard Eclipse compiler options:\n\ \ Compliance options:\n\ \ -1.3 use 1.3 compliance level (implicit -source 1.3 -target 1.1)\n\ \ -1.4 + use 1.4 compliance level (implicit -source 1.3 -target 1.2)\n\ +\ -1.5 set behaviour of the weaver to 1.5 mode\n\ \ -source set source level (1.3 or 1.4)\n\ \ -target set classfile target (1.1 to 1.4)\n\ \ \n\ diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java index da778a54e..8306dd120 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java @@ -416,7 +416,7 @@ public class AjLookupEnvironment extends LookupEnvironment { } private void doDeclareParents(DeclareParents declareParents, SourceTypeBinding sourceType) { - List newParents = declareParents.findMatchingNewParents(factory.fromEclipse(sourceType)); + List newParents = declareParents.findMatchingNewParents(factory.fromEclipse(sourceType),false); if (!newParents.isEmpty()) { for (Iterator i = newParents.iterator(); i.hasNext(); ) { ResolvedTypeX parent = (ResolvedTypeX)i.next(); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java index 562a5951b..12ca5f606 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java @@ -524,4 +524,12 @@ public class AjBuildConfig { public boolean getProceedOnError() { return options.proceedOnError; } + + public void setBehaveInJava5Way(boolean b) { + options.behaveInJava5Way = b; + } + + public boolean getBehaveInJava5Way() { + return options.behaveInJava5Way; + } } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java index a08d1c0ef..d0701d190 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java @@ -489,6 +489,7 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc List cp = buildConfig.getBootclasspath(); cp.addAll(buildConfig.getClasspath()); bcelWorld = new BcelWorld(cp, handler, null); + bcelWorld.setBehaveInJava5Way(buildConfig.getBehaveInJava5Way()); bcelWorld.setXnoInline(buildConfig.isXnoInline()); bcelWorld.setXlazyTjp(buildConfig.isXlazyTjp()); bcelWeaver = new BcelWeaver(bcelWorld); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java index 904954721..8553ed9df 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java @@ -66,6 +66,9 @@ public class AjCompilerOptions extends CompilerOptions { public boolean xReweavableCompress = false; public boolean showWeavingInformation = false; + // If true - autoboxing behaves differently ... + public boolean behaveInJava5Way = false; + // these next three not exposed by IDEs public boolean generateModel = false; public boolean generateJavaDocsInModel = false; diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AspectJBuilder.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AspectJBuilder.java index a1e066b79..b91aed439 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AspectJBuilder.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AspectJBuilder.java @@ -154,6 +154,7 @@ public class AspectJBuilder extends JavaBuilder implements ICompilerAdapterFacto private void initWorldAndWeaver(AjCompilerOptions options) { cpManager = new EclipseClassPathManager(nameEnvironment); myBcelWorld = new BcelWorld(cpManager,new UnhandledMessageHandler(getProject()),null /*(xrefHandler)*/); + myBcelWorld.setBehaveInJava5Way(options.behaveInJava5Way); myBcelWorld.setXnoInline(options.xNoInline); myBcelWorld.setXlazyTjp(options.xLazyThisJoinPoint); setLintProperties(myBcelWorld,options); diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/ajc/BuildArgParserTestCase.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/ajc/BuildArgParserTestCase.java index 238879e71..a020afe9f 100644 --- a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/ajc/BuildArgParserTestCase.java +++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/ajc/BuildArgParserTestCase.java @@ -422,6 +422,28 @@ public class BuildArgParserTestCase extends TestCase { assertTrue(new File(lintFile).exists()); assertEquals(getCanonicalPath(new File(lintFile)),config.getLintSpecFile().getAbsolutePath()); } + + /** + * The option '-1.5' are currently eaten by the AspectJ argument parser - since + * the JDT compiler upon which we are based doesn't understand them - *this should change* when we + * switch to a 1.5 compiler base. They are currently used to determine whether the weaver should + * behave in a '1.5' way - for example autoboxing behaves differently when the 1.5 flag is specified. + * Under 1.4 Integer != int + * Under 1.5 Integer == int + * (this applies to all primitive types) + */ + public void testSource15() throws InvalidInputException { +// AjBuildConfig config = genBuildConfig(new String[]{"-source","1.5"},messageWriter); +// assertTrue("should be in 1.5 mode",config.getJave5Behaviour()); + AjBuildConfig config = genBuildConfig(new String[]{"-1.5"},messageWriter); + assertTrue("should be in 1.5 mode",config.getBehaveInJava5Way()); + config = genBuildConfig(new String[]{"-source","1.4"},messageWriter); + assertTrue("should not be in 1.5 mode",!config.getBehaveInJava5Way()); + assertTrue("should be in 1.4 mode",config.getOptions().sourceLevel == CompilerOptions.JDK1_4); + config = genBuildConfig(new String[]{"-source","1.3"},messageWriter); + assertTrue("should not be in 1.5 mode",!config.getBehaveInJava5Way()); + assertTrue("should be in 1.3 mode",config.getOptions().sourceLevel == CompilerOptions.JDK1_3); + } public void testOptions() throws InvalidInputException { // AjdtCommand command = new AjdtCommand(); diff --git a/weaver/src/org/aspectj/weaver/Lint.java b/weaver/src/org/aspectj/weaver/Lint.java index 466cf9b5b..942aab182 100644 --- a/weaver/src/org/aspectj/weaver/Lint.java +++ b/weaver/src/org/aspectj/weaver/Lint.java @@ -65,6 +65,12 @@ public class Lint { public final Kind noJoinpointsForBridgeMethods = new Kind("noJoinpointsForBridgeMethods","pointcut did not match on the method call to a bridge method. Bridge methods are generated by the compiler and have no join points"); + public final Kind enumAsTargetForDecpIgnored = + new Kind("enumAsTargetForDecpIgnored","enum type {0} matches a declare parents type pattern but is being ignored"); + + public final Kind annotationAsTargetForDecpIgnored = + new Kind("annotationAsTargetForDecpIgnored","annotation type {0} matches a declare parents type pattern but is being ignored"); + public final Kind cantMatchArrayTypeOnVarargs = new Kind("cantMatchArrayTypeOnVarargs","an array type as the last parameter in a signature does not match on the varargs declared method: {0}"); diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java index f324affae..b2a0b116c 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java @@ -18,8 +18,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.aspectj.bridge.IMessage; import org.aspectj.bridge.ISourceLocation; @@ -99,11 +101,42 @@ public abstract class ResolvedTypeX extends TypeX implements AnnotatedElement { public boolean needsNoConversionFrom(TypeX other, World world) { return needsNoConversionFrom(other); } + + // This set contains pairs of types whose signatures are concatenated + // together, this means with a fast lookup we can tell if two types + // are equivalent. + private static Set validBoxing = new HashSet(); + + static { + validBoxing.add("Ljava/lang/Byte;B"); + validBoxing.add("Ljava/lang/Character;C"); + validBoxing.add("Ljava/lang/Double;D"); + validBoxing.add("Ljava/lang/Float;F"); + validBoxing.add("Ljava/lang/Integer;I"); + validBoxing.add("Ljava/lang/Long;J"); + validBoxing.add("Ljava/lang/Short;S"); + validBoxing.add("Ljava/lang/Boolean;Z"); + validBoxing.add("BLjava/lang/Byte;"); + validBoxing.add("CLjava/lang/Character;"); + validBoxing.add("DLjava/lang/Double;"); + validBoxing.add("FLjava/lang/Float;"); + validBoxing.add("ILjava/lang/Integer;"); + validBoxing.add("JLjava/lang/Long;"); + validBoxing.add("SLjava/lang/Short;"); + validBoxing.add("ZLjava/lang/Boolean;"); + } + public final boolean isConvertableFrom(TypeX other) { if (this.equals(OBJECT) || other.equals(OBJECT)) return true; + if (world.behaveInJava5Way) { + if (this.isPrimitive()^other.isPrimitive()) { // If one is primitive and the other isnt + if (validBoxing.contains(this.getSignature()+other.getSignature())) return true; + } + } return this.isCoerceableFrom(other); } + // utilities public ResolvedTypeX getResolvedComponentType() { return null; @@ -595,7 +628,10 @@ public abstract class ResolvedTypeX extends TypeX implements AnnotatedElement { } public final boolean isAssignableFrom(TypeX o) { - if (o.isPrimitive()) return false; + if (o.isPrimitive()) { + if (!world.behaveInJava5Way) return false; + if (validBoxing.contains(this.getSignature()+o.getSignature())) return true; + } ResolvedTypeX other = o.resolve(world); return isAssignableFrom(other); @@ -879,7 +915,10 @@ public abstract class ResolvedTypeX extends TypeX implements AnnotatedElement { return false; } public final boolean isAssignableFrom(TypeX other) { - if (! other.isPrimitive()) return false; + if (!other.isPrimitive()) { + if (!world.behaveInJava5Way) return false; + return validBoxing.contains(this.getSignature()+other.getSignature()); + } return assignTable[((Primitive)other).index][index]; } public final boolean isCoerceableFrom(TypeX other) { diff --git a/weaver/src/org/aspectj/weaver/TypeX.java b/weaver/src/org/aspectj/weaver/TypeX.java index 6a44d338c..c13349eb3 100644 --- a/weaver/src/org/aspectj/weaver/TypeX.java +++ b/weaver/src/org/aspectj/weaver/TypeX.java @@ -368,7 +368,7 @@ public class TypeX implements AnnotatedElement { public boolean isAssignableFrom(TypeX other, World world) { // primitives override this method, so we know we're not primitive. // So if the other is primitive, don't bother asking the world anything. - if (other.isPrimitive()) return false; + if (other.isPrimitive() && !world.behaveInJava5Way) return false; return world.isAssignableFrom(this, other); } @@ -582,6 +582,9 @@ public class TypeX implements AnnotatedElement { public static final TypeX ERROR = forSignature("Ljava/lang/Error;"); public static final TypeX AT_INHERITED = forSignature("Ljava/lang/annotation/Inherited;"); public static final TypeX AT_RETENTION = forSignature("Ljava/lang/annotation/Retention;"); + public static final TypeX ENUM = forSignature("Ljava/lang/Enum;"); + public static final TypeX ANNOTATION = forSignature("Ljava/lang/annotation/Annotation;"); + // ---- helpers diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java index 74a083053..228eeb3f1 100644 --- a/weaver/src/org/aspectj/weaver/World.java +++ b/weaver/src/org/aspectj/weaver/World.java @@ -44,7 +44,10 @@ public abstract class World implements Dump.INode { protected boolean XnoInline; protected boolean XlazyTjp; + + public boolean behaveInJava5Way = false; + private List dumpState_cantFindTypeExceptions = null; protected World() { @@ -118,7 +121,7 @@ public abstract class World implements Dump.INode { //System.out.println("resolve: " + ty + " world " + typeMap.keySet()); String signature = ty.getSignature(); ResolvedTypeX ret = typeMap.get(signature); - if (ret != null) return ret; + if (ret != null) { ret.world = this; return ret; } // Set the world for the RTX if (ty.isArray()) { ret = new ResolvedTypeX.Array(signature, this, resolve(ty.getComponentType(), allowMissing)); @@ -158,7 +161,7 @@ public abstract class World implements Dump.INode { } protected final boolean isAssignableFrom(TypeX type, TypeX other) { - return resolve(type).isAssignableFrom(other); + return resolve(type).isAssignableFrom(resolve(other)); } public boolean needsNoConversionFrom(TypeX type, TypeX other) { @@ -519,4 +522,8 @@ public abstract class World implements Dump.INode { ); } } + + public void setBehaveInJava5Way(boolean b) { + behaveInJava5Way = b; + } } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java index 3e497642d..1f850999e 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -673,7 +673,7 @@ public class BcelWeaver implements IWeaver { // need to do any declare parents before the matching below for (Iterator i = declareParentsList.iterator(); i.hasNext(); ) { DeclareParents p = (DeclareParents)i.next(); - List newParents = p.findMatchingNewParents(onType); + List newParents = p.findMatchingNewParents(onType,true); if (!newParents.isEmpty()) { BcelObjectType classType = BcelWorld.getBcelObjectType(onType); //System.err.println("need to do declare parents for: " + onType); diff --git a/weaver/src/org/aspectj/weaver/bcel/Utility.java b/weaver/src/org/aspectj/weaver/bcel/Utility.java index 0a98a0985..64c512f91 100644 --- a/weaver/src/org/aspectj/weaver/bcel/Utility.java +++ b/weaver/src/org/aspectj/weaver/bcel/Utility.java @@ -18,6 +18,9 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.ClassParser; @@ -206,6 +209,29 @@ public class Utility { return ret; } + // Lookup table, for converting between pairs of types, it gives + // us the method name in the Conversions class + private static Hashtable validBoxing = new Hashtable(); + + static { + validBoxing.put("Ljava/lang/Byte;B","byteObject"); + validBoxing.put("Ljava/lang/Character;C","charObject"); + validBoxing.put("Ljava/lang/Double;D","doubleObject"); + validBoxing.put("Ljava/lang/Float;F","floatObject"); + validBoxing.put("Ljava/lang/Integer;I","intObject"); + validBoxing.put("Ljava/lang/Long;J","longObject"); + validBoxing.put("Ljava/lang/Short;S","shortObject"); + validBoxing.put("Ljava/lang/Boolean;Z","booleanObject"); + validBoxing.put("BLjava/lang/Byte;","byteValue"); + validBoxing.put("CLjava/lang/Character;","charValue"); + validBoxing.put("DLjava/lang/Double;","doubleValue"); + validBoxing.put("FLjava/lang/Float;","floatValue"); + validBoxing.put("ILjava/lang/Integer;","intValue"); + validBoxing.put("JLjava/lang/Long;","longValue"); + validBoxing.put("SLjava/lang/Short;","shortValue"); + validBoxing.put("ZLjava/lang/Boolean;","booleanValue"); + } + public static void appendConversion( InstructionList il, InstructionFactory fact, @@ -215,8 +241,12 @@ public class Utility { if (! toType.isConvertableFrom(fromType)) { throw new BCException("can't convert from " + fromType + " to " + toType); } - if (toType.needsNoConversionFrom(fromType)) return; - + // XXX I'm sure this test can be simpler but my brain hurts and this works + if (!toType.getWorld().behaveInJava5Way) { + if (toType.needsNoConversionFrom(fromType)) return; + } else { + if (toType.needsNoConversionFrom(fromType) && !(toType.isPrimitive()^fromType.isPrimitive())) return; + } if (toType.equals(ResolvedTypeX.VOID)) { // assert fromType.equals(TypeX.OBJECT) il.append(InstructionFactory.createPop(fromType.getSize())); @@ -249,6 +279,29 @@ public class Utility { Type.OBJECT, new Type[] { from }, Constants.INVOKESTATIC)); + } else if (toType.getWorld().behaveInJava5Way && validBoxing.get(toType.getSignature()+fromType.getSignature())!=null) { + // XXX could optimize by using any java boxing code that may be just before the call... + Type from = BcelWorld.makeBcelType(fromType); + Type to = BcelWorld.makeBcelType(toType); + String name = (String)validBoxing.get(toType.getSignature()+fromType.getSignature()); + if (toType.isPrimitive()) { + il.append( + fact.createInvoke( + "org.aspectj.runtime.internal.Conversions", + name, + to, + new Type[]{Type.OBJECT}, + Constants.INVOKESTATIC)); + } else { + il.append( + fact.createInvoke( + "org.aspectj.runtime.internal.Conversions", + name, + Type.OBJECT, + new Type[] { from }, + Constants.INVOKESTATIC)); + il.append(fact.createCheckCast((ReferenceType) to)); + } } else if (fromType.isPrimitive()) { // assert toType.isPrimitive() Type from = BcelWorld.makeBcelType(fromType); diff --git a/weaver/src/org/aspectj/weaver/patterns/DeclareParents.java b/weaver/src/org/aspectj/weaver/patterns/DeclareParents.java index a5ece09bd..3adcd722a 100644 --- a/weaver/src/org/aspectj/weaver/patterns/DeclareParents.java +++ b/weaver/src/org/aspectj/weaver/patterns/DeclareParents.java @@ -30,6 +30,7 @@ import org.aspectj.weaver.World; public class DeclareParents extends Declare { private TypePattern child; private TypePatternList parents; + private boolean isWildChild = false; public DeclareParents(TypePattern child, List parents) { @@ -39,6 +40,7 @@ public class DeclareParents extends Declare { private DeclareParents(TypePattern child, TypePatternList parents) { this.child = child; this.parents = parents; + if (child instanceof WildTypePattern) isWildChild = true; } public boolean match(ResolvedTypeX typeX) { @@ -90,12 +92,27 @@ public class DeclareParents extends Declare { return ret; } + public boolean parentsIncludeInterface(World w) { + for (int i = 0; i < parents.size(); i++) { + if (parents.get(i).getExactType().isInterface(w)) return true; + } + return false; + } + public boolean parentsIncludeClass(World w) { + for (int i = 0; i < parents.size(); i++) { + if (parents.get(i).getExactType().isClass(w)) return true; + } + return false; + } + public void resolve(IScope scope) { child = child.resolveBindings(scope, Bindings.NONE, false, false); parents = parents.resolveBindings(scope, Bindings.NONE, false, true); -// for (int i=0; i < parents.size(); i++) { -// parents.get(i).assertExactType(scope.getMessageHandler()); -// } + +// Could assert this ... +// for (int i=0; i < parents.size(); i++) { +// parents.get(i).assertExactType(scope.getMessageHandler()); +// } } public TypePatternList getParents() { @@ -110,7 +127,7 @@ public class DeclareParents extends Declare { return false; } - private ResolvedTypeX maybeGetNewParent(ResolvedTypeX targetType, TypePattern typePattern, World world) { + private ResolvedTypeX maybeGetNewParent(ResolvedTypeX targetType, TypePattern typePattern, World world,boolean reportErrors) { if (typePattern == TypePattern.NO) return null; // already had an error here TypeX iType = typePattern.getExactType(); ResolvedTypeX parentType = iType.resolve(world); @@ -121,8 +138,64 @@ public class DeclareParents extends Declare { this.getSourceLocation(), null); return null; } - + if (parentType.isAssignableFrom(targetType)) return null; // already a parent + + // Enum types that are targetted for decp through a wild type pattern get linted + if (reportErrors && isWildChild && targetType.isEnum()) { + world.getLint().enumAsTargetForDecpIgnored.signal(targetType.toString(),getSourceLocation()); + } + + // Annotation types that are targetted for decp through a wild type pattern get linted + if (reportErrors && isWildChild && targetType.isAnnotation()) { + world.getLint().annotationAsTargetForDecpIgnored.signal(targetType.toString(),getSourceLocation()); + } + + // 1. Can't use decp to make an enum/annotation type implement an interface + if (targetType.isEnum() && parentType.isInterface()) { + if (reportErrors && !isWildChild) { + world.showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.CANT_DECP_ON_ENUM_TO_IMPL_INTERFACE,targetType),getSourceLocation(),null); + } + return null; + } + if (targetType.isAnnotation() && parentType.isInterface()) { + if (reportErrors && !isWildChild) { + world.showMessage(IMessage.ERROR,WeaverMessages.format(WeaverMessages.CANT_DECP_ON_ANNOTATION_TO_IMPL_INTERFACE,targetType),getSourceLocation(),null); + } + return null; + } + + // 2. Can't use decp to change supertype of an enum/annotation + if (targetType.isEnum() && parentType.isClass()) { + if (reportErrors && !isWildChild) { + world.showMessage(IMessage.ERROR,WeaverMessages.format(WeaverMessages.CANT_DECP_ON_ENUM_TO_EXTEND_CLASS,targetType),getSourceLocation(),null); + } + return null; + } + if (targetType.isAnnotation() && parentType.isClass()) { + if (reportErrors && !isWildChild) { + world.showMessage(IMessage.ERROR,WeaverMessages.format(WeaverMessages.CANT_DECP_ON_ANNOTATION_TO_EXTEND_CLASS,targetType),getSourceLocation(),null); + } + return null; + } + + // 3. Can't use decp to declare java.lang.Enum/java.lang.annotation.Annotation as the parent of a type + if (parentType.getSignature().equals(TypeX.ENUM.getSignature())) { + if (reportErrors && !isWildChild) { + world.showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.CANT_DECP_TO_MAKE_ENUM_SUPERTYPE,targetType),getSourceLocation(),null); + } + return null; + } + if (parentType.getSignature().equals(TypeX.ANNOTATION.getSignature())) { + if (reportErrors && !isWildChild) { + world.showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.CANT_DECP_TO_MAKE_ANNOTATION_SUPERTYPE,targetType),getSourceLocation(),null); + } + return null; + } + if (targetType.isAssignableFrom(parentType)) { world.showMessage(IMessage.ERROR, @@ -159,12 +232,12 @@ public class DeclareParents extends Declare { } - public List/**/ findMatchingNewParents(ResolvedTypeX onType) { + public List/**/ findMatchingNewParents(ResolvedTypeX onType,boolean reportErrors) { if (!match(onType)) return Collections.EMPTY_LIST; List ret = new ArrayList(); for (int i=0; i < parents.size(); i++) { - ResolvedTypeX t = maybeGetNewParent(onType, parents.get(i), onType.getWorld()); + ResolvedTypeX t = maybeGetNewParent(onType, parents.get(i), onType.getWorld(),reportErrors); if (t != null) ret.add(t); }