<compile files="CflowCycles.java"/>
<run class="CflowCycles"/>
</ajc-test>
+
+ <ajc-test dir="new"
+ title="incompatible advice throws clause are a compile-time error"
+ keywords="from-resolved_10x">
+ <compile files="AdviceThrowsCf.java">
+ <message kind="error" line="13"/>
+ <message kind="error" line="28"/>
+ <message kind="error" line="47"/>
+ <message kind="error" line="48"/>
+ <message kind="error" line="50"/>
+
+ <message kind="error" line="70"/>
+ <message kind="error" line="74"/>
+ <message kind="error" line="76"/>
+ <message kind="error" line="78"/>
+
+ <message kind="error" line="85"/>
+ </compile>
+ </ajc-test>
</suite>
<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd">
<suite>
-
- <ajc-test dir="new"
- title="incompatible advice throws clause are a compile-time error"
- keywords="from-resolved_10x">
- <compile files="AdviceThrowsCf.java">
- <message kind="error" line="70"/>
- <message kind="error" line="74"/>
- <message kind="error" line="76"/>
- <message kind="error" line="78"/>
- </compile>
- </ajc-test>
-
<ajc-test dir="new" pr="660" title="illegal name binding in around cflow"
keywords="from-resolved_104">
<compile files="ArgsInCflowCf.java">
<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd">
<suite>
- <ajc-test dir="new" pr="29934"
- title="can't apply around advice to the execution of around advice"
- keywords="from-resolved_10x">
- <compile files="CflowCycles.java"/>
- <run class="CflowCycles"/>
- </ajc-test>
+
+
+
<!--
-
+ <ajc-test dir="new" pr="885"
+ title="source locations within expressions">
+ <compile files="SourceLocationWithinExpr.java" options="-1.4"/>
+ <run class="SourceLocationWithinExpr"/>
+ </ajc-test>
-->
</suite>
\ No newline at end of file
}
before() throws CheckedExc: staticinitialization(C) { //ERR: can't throw
}
+
+ void around() throws CheckedExc: canThrowChecked() {
+ proceed();
+ }
+
+ void around() throws CheckedExc: canThrowUnchecked() { // ERR: can't throw
+ proceed();
+ }
+
+ void around() throws UncheckedExc: canThrowUnchecked() || set(int C.x) {
+ proceed();
+ }
+
}
package org.aspectj.weaver;
+import java.util.Collection;
+import java.util.Collections;
+
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.Message;
import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
public int compareTo(Object other) {
return 0;
}
+
+ public Collection getThrownExceptions() { return Collections.EMPTY_LIST; }
}
}
}
+ protected boolean checkMunger(ShadowMunger munger) {
+ for (Iterator i = munger.getThrownExceptions().iterator(); i.hasNext(); ) {
+ if (!checkCanThrow(munger, (ResolvedTypeX)i.next() )) return false;
+ }
+ return true;
+ }
+
+ protected boolean checkCanThrow(ShadowMunger munger, ResolvedTypeX resolvedTypeX) {
+ if (getKind() == ExceptionHandler) {
+ //XXX much too lenient rules here, need to walk up exception handlers
+ return true;
+ }
+
+ if (!isDeclaredException(resolvedTypeX, getSignature())) {
+ getIWorld().showMessage(IMessage.ERROR, "can't throw checked exception \'" + resolvedTypeX +
+ "\' at this join point \'" + this +"\'", // from advice in \'" + munger. + "\'",
+ getSourceLocation(), munger.getSourceLocation());
+ }
+
+ return true;
+ }
+
+ private boolean isDeclaredException(
+ ResolvedTypeX resolvedTypeX,
+ Member member)
+ {
+ ResolvedTypeX[] excs = getIWorld().resolve(member.getExceptions(getIWorld()));
+ for (int i=0, len=excs.length; i < len; i++) {
+ if (excs[i].isAssignableFrom(resolvedTypeX)) return true;
+ }
+ return false;
+ }
+
+
public void addMunger(ShadowMunger munger) {
- this.mungers.add(munger);
+ if (checkMunger(munger)) this.mungers.add(munger);
}
public final void implement() {
public String toString() {
return getKind() + "(" + getSignature() + ")"; // + getSourceLines();
}
-
-
-
-
-
-
-
-
- // ---- type access methods
-
-
-
}
package org.aspectj.weaver;
+import java.util.Collection;
+
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.util.PartialOrder;
import org.aspectj.weaver.patterns.PerClause;
return pointcut;
}
+
+ /**
+ * @return a Collection of ResolvedTypeX for all checked exceptions that
+ * might be thrown by this munger
+ */
+ public abstract Collection getThrownExceptions();
}
public static final TypeX CLONEABLE = forSignature("Ljava/lang/Cloneable;");
public static final TypeX SERIALIZABLE = forSignature("Ljava/io/Serializable;");
public static final TypeX THROWABLE = forSignature("Ljava/lang/Throwable;");
+ public static final TypeX RUNTIME_EXCEPTION = forSignature("Ljava/lang/RuntimeException;");
+ public static final TypeX ERROR = forSignature("Ljava/lang/Error;");
// ---- helpers
package org.aspectj.weaver.bcel;
-import org.apache.bcel.generic.InstructionFactory;
-import org.apache.bcel.generic.InstructionHandle;
-import org.apache.bcel.generic.InstructionList;
-import org.aspectj.weaver.Advice;
-import org.aspectj.weaver.AdviceKind;
-import org.aspectj.weaver.AjAttribute;
-import org.aspectj.weaver.BCException;
-import org.aspectj.weaver.ISourceContext;
-import org.aspectj.weaver.Member;
-import org.aspectj.weaver.ResolvedTypeX;
-import org.aspectj.weaver.Shadow;
-import org.aspectj.weaver.TypeX;
-import org.aspectj.weaver.WeaverStateKind;
-import org.aspectj.weaver.World;
+import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.bcel.generic.*;
+import org.aspectj.weaver.*;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;
-import org.aspectj.weaver.patterns.ExactTypePattern;
-import org.aspectj.weaver.patterns.ExposedState;
-import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.*;
/**
* Advice implemented for bcel.
this.concreteAspect = concreteAspect;
}
- // !!! only used for testing
+ // !!! must only be used for testing
public BcelAdvice(AdviceKind kind, Pointcut pointcut, Member signature,
int extraArgumentFlags,
int start, int end, ISourceContext sourceContext, ResolvedTypeX concreteAspect)
{
this(new AjAttribute.AdviceAttribute(kind, pointcut, extraArgumentFlags, start, end, sourceContext),
pointcut, signature, concreteAspect);
+ thrownExceptions = Collections.EMPTY_LIST; //!!! interaction with unit tests
}
// ---- implementations of ShadowMunger's methods
}
// ---- implementations
+
+ private Collection collectCheckedExceptions(TypeX[] excs) {
+ if (excs == null || excs.length == 0) return Collections.EMPTY_LIST;
+
+ Collection ret = new ArrayList();
+ World world = concreteAspect.getWorld();
+ ResolvedTypeX runtimeException = world.resolve(TypeX.RUNTIME_EXCEPTION);
+ ResolvedTypeX error = world.resolve(TypeX.ERROR);
+
+ for (int i=0, len=excs.length; i < len; i++) {
+ ResolvedTypeX t = world.resolve(excs[i]);
+ if (!(runtimeException.isAssignableFrom(t) || error.isAssignableFrom(t))) {
+ ret.add(t);
+ }
+ }
+
+ return ret;
+ }
+
+ private Collection thrownExceptions = null;
+ public Collection getThrownExceptions() {
+ if (thrownExceptions == null) {
+ //??? can we really lump in Around here, how does this interact with Throwable
+ if (concreteAspect != null && concreteAspect.getWorld() != null && // null tests for test harness
+ (getKind().isAfter() || getKind() == AdviceKind.Before || getKind() == AdviceKind.Around))
+ {
+ World world = concreteAspect.getWorld();
+ ResolvedMember m = world.resolve(signature);
+ if (m == null) {
+ thrownExceptions = Collections.EMPTY_LIST;
+ } else {
+ thrownExceptions = collectCheckedExceptions(m.getExceptions());
+ }
+ } else {
+ thrownExceptions = Collections.EMPTY_LIST;
+ }
+ }
+ return thrownExceptions;
+ }
+
// only call me after prepare has been called
public boolean hasDynamicTests() {