}
private void doDeclareParents(DeclareParents declareParents, SourceTypeBinding sourceType) {
- if (declareParents.match(factory.fromEclipse(sourceType))) {
- TypePatternList l = declareParents.getParents();
- for (int i=0, len=l.size(); i < len; i++) {
- addParent(declareParents, sourceType, l.get(i));
+ List newParents = declareParents.findMatchingNewParents(factory.fromEclipse(sourceType));
+ if (!newParents.isEmpty()) {
+ for (Iterator i = newParents.iterator(); i.hasNext(); ) {
+ ResolvedTypeX parent = (ResolvedTypeX)i.next();
+ addParent(sourceType, parent);
}
}
}
- private void addParent(DeclareParents declareParents, SourceTypeBinding sourceType, TypePattern typePattern) {
- if (typePattern == TypePattern.NO) return; // already had an error here
- TypeX iType = typePattern.getExactType();
- ReferenceBinding b = (ReferenceBinding)factory.makeTypeBinding(iType); //"
-
- if (b.isClass()) {
- if (sourceType.isInterface()) {
- factory.showMessage(IMessage.ERROR,
- "interface can not extend a class",
- declareParents.getSourceLocation(), null
- );
- // how to handle xcutting errors???
- }
-
- if (sourceType == b || sourceType.isSuperclassOf(b)) {
- factory.showMessage(IMessage.ERROR,
- "class can not extend itself", declareParents.getSourceLocation(), null
- );
- return;
- }
- sourceType.superclass = b;
+ private void addParent(SourceTypeBinding sourceType, ResolvedTypeX parent) {
+ ReferenceBinding parentBinding = (ReferenceBinding)factory.makeTypeBinding(parent);
+ if (parentBinding.isClass()) {
+ sourceType.superclass = parentBinding;
} else {
- //??? it's not considered an error to extend yourself, nothing happens
- if (sourceType.equals(b)) {
- return;
- }
-
- if (sourceType.isInterface() && b.implementsInterface(sourceType, true)) {
- factory.showMessage(IMessage.ERROR,
- "interface can not extend itself", declareParents.getSourceLocation(), null
- );
- return;
- }
- if (sourceType == b || b.isSuperclassOf(sourceType)) return;
ReferenceBinding[] oldI = sourceType.superInterfaces;
ReferenceBinding[] newI;
if (oldI == null) {
newI = new ReferenceBinding[1];
- newI[0] = b;
+ newI[0] = parentBinding;
} else {
int n = oldI.length;
newI = new ReferenceBinding[n+1];
System.arraycopy(oldI, 0, newI, 0, n);
- newI[n] = b;
+ newI[n] = parentBinding;
}
sourceType.superInterfaces = newI;
}
declare parents: C2 implements I; // CE can't implement
declare parents: C2 extends C3; // CE circular
- declare parents: C1 extends C1; // CE self
+ declare parents: C1 extends C1; // not considered a CE, just does nothing
}
\ No newline at end of file
}
public void testDeclareParentsFail() throws IOException {
- CommandTestCase.checkCompile("src1/ParentsFail.java", new int[] {3, 11, 19, 21});
+ CommandTestCase.checkCompile("src1/ParentsFail.java", new int[] {3, 11, 19});
}
public void testDeclareParents() throws IOException {
<run class="b_impl.BImpl"/>
</ajc-test>
+ <ajc-test dir="new/declareParents"
+ title="Declare parents with intermediate ancestor"
+ keywords="from-new">
+ <compile files="Driver.java"/>
+ <run class="Driver"/>
+ </ajc-test>
+
+ <ajc-test dir="new/declareParents"
+ title="Declare parents removing ancestor"
+ keywords="from-new">
+ <compile files="IllegalAdoption.java">
+ <message kind="error" line="13"/>
+ </compile>
+ </ajc-test>
+
+
+ <ajc-test dir="options/injars/simple" pr="35865"
+ title="options -injars checking declare parents interactions">
+ <compile files="DecParents.java,main.jar"
+ options="!eclipse"/>
+ <run class="DecParents"/>
+ </ajc-test>
</suite>
<!-- contains valid tests that the compiler has never passed -->
<suite>
- <ajc-test dir="new/declareParents"
- title="Declare parents with intermediate ancestor"
- keywords="from-new">
- <compile files="Driver.java"/>
- <run class="Driver"/>
- </ajc-test>
-
- <ajc-test dir="new/declareParents"
- title="Declare parents removing ancestor"
- keywords="from-new">
- <compile files="IllegalAdoption.java">
- <message kind="error" line="13"/>
- </compile>
- </ajc-test>
+
</suite>
<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd">
<suite>
-
<!--
<ajc-test dir="new" pr="885"
--- /dev/null
+
+
+import org.aspectj.testing.Tester;
+
+public aspect DecParents {
+ private interface I {
+ public abstract String doit();
+ }
+
+ public String I.doit() {
+ return "foo";
+ }
+
+ declare parents: Main implements I;
+
+ before(): execution(void Main.main(..)) {
+ }
+
+ public static void main(String[] args) {
+ I i = new Main();
+ System.out.println("Main: " + i.doit());
+ }
+}
\ No newline at end of file
--- /dev/null
+/* *******************************************************************
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Set;
+
+public class NewParentTypeMunger extends ResolvedTypeMunger {
+ ResolvedTypeX newParent;
+
+ public NewParentTypeMunger(ResolvedTypeX newParent) {
+ super(Parent, null);
+ this.newParent = newParent;
+ }
+
+ public void write(DataOutputStream s) throws IOException {
+ throw new RuntimeException("unimplemented");
+ }
+
+
+ public ResolvedTypeX getNewParent() {
+ return newParent;
+ }
+
+
+}
// not serialized, only created during concretization of aspects
public static final Kind PerObjectInterface = new Kind("PerObjectInterface", 3);
public static final Kind PrivilegedAccess = new Kind("PrivilegedAccess", 4);
+
+ public static final Kind Parent = new Kind("Parent", 6);
public static final String SUPER_DISPATCH_NAME = "superDispatch";
if (ret == null) {
//System.err.println("creating lazy class gen for: " + this);
ret = new LazyClassGen(this);
+ //ret.print(System.err);
+ //System.err.println("made LCG from : " + this.getJavaClass().getSuperclassName() );
if (isAspect()) {
lazyClassGen = ret;
}
public ISourceLocation getSourceLocation() {
return getResolvedTypeX().getSourceContext().makeSourceLocation(0); //FIXME, we can do better than this
}
+
+ public void addParent(ResolvedTypeX newParent) {
+ if (newParent.isClass()) {
+ superClass = newParent;
+ } else {
+ ResolvedTypeX[] oldInterfaceNames = getDeclaredInterfaces();
+ int len = oldInterfaceNames.length;
+ ResolvedTypeX[] newInterfaceNames = new ResolvedTypeX[len+1];
+ System.arraycopy(oldInterfaceNames, 0, newInterfaceNames, 0, len);
+ newInterfaceNames[len] = newParent;
+
+ interfaces = newInterfaceNames;
+ }
+ //System.err.println("javaClass: " + Arrays.asList(javaClass.getInterfaceNames()) + " super " + javaClass.getSuperclassName());
+ //if (lazyClassGen != null) lazyClassGen.print();
+ }
}
import org.aspectj.weaver.NewConstructorTypeMunger;
import org.aspectj.weaver.NewFieldTypeMunger;
import org.aspectj.weaver.NewMethodTypeMunger;
+import org.aspectj.weaver.NewParentTypeMunger;
import org.aspectj.weaver.PerObjectInterfaceTypeMunger;
import org.aspectj.weaver.PrivilegedAccessMunger;
import org.aspectj.weaver.ResolvedMember;
return mungePrivilegedAccess(weaver, (PrivilegedAccessMunger)munger);
} else if (munger.getKind() == ResolvedTypeMunger.Constructor) {
return mungeNewConstructor(weaver, (NewConstructorTypeMunger)munger);
+ } else if (munger.getKind() == ResolvedTypeMunger.Parent) {
+ return mungeNewParent(weaver, (NewParentTypeMunger)munger);
} else {
throw new RuntimeException("unimplemented");
}
}
-
+ private boolean mungeNewParent(BcelClassWeaver weaver, NewParentTypeMunger munger) {
+ LazyClassGen gen = weaver.getLazyClassGen();
+ ResolvedTypeX newParent = munger.getNewParent();
+ if (newParent.isClass()) {
+ //gen.setSuperClass(newParent);
+ } else {
+ gen.addInterface(newParent);
+ }
+ return true;
+ }
+
private boolean mungePrivilegedAccess(
BcelClassWeaver weaver,
PrivilegedAccessMunger munger)
import org.aspectj.bridge.IMessage;
import org.aspectj.util.FileUtil;
import org.aspectj.weaver.*;
+import org.aspectj.weaver.patterns.DeclareParents;
import org.aspectj.weaver.patterns.Pointcut;
public class BcelWeaver implements IWeaver {
private boolean needToReweaveWorld = false;
private List shadowMungerList = null; // setup by prepareForWeave
- private List typeMungerList = null; // setup by prepareForWeave
+ private List typeMungerList = null; // setup by prepareForWeave
+ private List declareParentsList = null; // setup by prepareForWeave
private ZipOutputStream zipOutputStream;
shadowMungerList = xcutSet.getShadowMungers();
typeMungerList = xcutSet.getTypeMungers();
+ declareParentsList = xcutSet.getDeclareParents();
//XXX this gets us a stable (but completely meaningless) order
Collections.sort(
public void weave(ResolvedTypeX onType) {
onType.clearInterTypeMungers();
+
+ // 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);
+ if (!newParents.isEmpty()) {
+ //???
+ BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(onType.getClassName()));
+ //System.err.println("need to do declare parents for: " + onType);
+ for (Iterator j = newParents.iterator(); j.hasNext(); ) {
+ ResolvedTypeX newParent = (ResolvedTypeX)j.next();
+ if (newParent.isClass()) {
+ world.showMessage(IMessage.ERROR,
+ "can't use declare parents to change superclass of binary form \'" +
+ onType.getClassName() + "\' (implementation limitation)",
+ p.getSourceLocation(), null);
+ continue;
+ }
+
+ classType.addParent(newParent);
+ ResolvedTypeMunger newParentMunger = new NewParentTypeMunger(newParent);
+ onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, null));
+ }
+ }
+ }
+
for (Iterator i = typeMungerList.iterator(); i.hasNext(); ) {
ConcreteTypeMunger m = (ConcreteTypeMunger)i.next();
if (m.matches(onType)) {
}
}
+
// exposed for ClassLoader dynamic weaving
public LazyClassGen weaveWithoutDump(UnwovenClassFile classFile, BcelObjectType classType) throws IOException {
return weave(classFile, classType, false);
public void addInterface(TypeX typeX) {
myGen.addInterface(typeX.getName());
}
+
+ public void setSuperClass(TypeX typeX) {
+ myGen.setSuperclassName(typeX.getName());
+ }
+
// non-recursive, may be a bug, ha ha.
private List getClassGens() {
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import org.aspectj.bridge.IMessage;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.ResolvedTypeX;
+import org.aspectj.weaver.TypeX;
+import org.aspectj.weaver.World;
public class DeclareParents extends Declare {
private TypePattern child;
public boolean isAdviceLike() {
return false;
}
+
+ private ResolvedTypeX maybeGetNewParent(ResolvedTypeX targetType, TypePattern typePattern, World world) {
+ if (typePattern == TypePattern.NO) return null; // already had an error here
+ TypeX iType = typePattern.getExactType();
+ ResolvedTypeX parentType = iType.resolve(world);
+
+ if (parentType.isAssignableFrom(targetType)) return null; // already a parent
+
+ if (targetType.isAssignableFrom(parentType)) {
+ world.showMessage(IMessage.ERROR,
+ "type can not extend itself", this.getSourceLocation(), null
+ );
+ return null;
+ }
+
+ if (parentType.isClass()) {
+ if (targetType.isInterface()) {
+ world.showMessage(IMessage.ERROR,
+ "interface can not extend a class",
+ this.getSourceLocation(), null
+ );
+ return null;
+ // how to handle xcutting errors???
+ }
+
+ if (!targetType.getSuperclass().isAssignableFrom(parentType)) {
+ world.showMessage(IMessage.ERROR,
+ "can only insert a class into hierarchy, but "
+ + iType.getName() + " is not a subtype of " +
+ targetType.getSuperclass().getName(),
+ this.getSourceLocation(), null
+ );
+ return null;
+ } else {
+ return parentType;
+ }
+ } else {
+ return parentType;
+ }
+ }
+
+
+ public List/*<ResolvedTypeX>*/ findMatchingNewParents(ResolvedTypeX onType) {
+ 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());
+ if (t != null) ret.add(t);
+ }
+
+ return ret;
+ }
}