aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhugunin <jhugunin>2003-04-22 21:58:02 +0000
committerjhugunin <jhugunin>2003-04-22 21:58:02 +0000
commit6c9118bfa40d75467085d23a3b0d103199e137b2 (patch)
tree1ed9f725110d254582163a1eddcc54b60fb40bdc
parent0a8dbdeed13fe79ddfd7a291e2b45b50b9a90579 (diff)
downloadaspectj-6c9118bfa40d75467085d23a3b0d103199e137b2.tar.gz
aspectj-6c9118bfa40d75467085d23a3b0d103199e137b2.zip
tests and fixes for
Bugzilla Bug 29665 Inconsistant stack height
-rw-r--r--tests/ajcTests.xml17
-rw-r--r--tests/bugs/StackError.java46
-rw-r--r--tests/bugs/messyAround/DebugTrace.aj34
-rw-r--r--tests/bugs/messyAround/aspects/Trace.aj490
-rw-r--r--tests/bugs/messyAround/cap/OptionList.java138
-rw-r--r--tests/jimTests.xml18
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelShadow.java7
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java5
8 files changed, 754 insertions, 1 deletions
diff --git a/tests/ajcTests.xml b/tests/ajcTests.xml
index 845d21687..8785b0b8a 100644
--- a/tests/ajcTests.xml
+++ b/tests/ajcTests.xml
@@ -5834,4 +5834,21 @@
<run class="tjpStaticPart.Test"/>
</ajc-test>
+ <ajc-test dir="bugs" pr="29665"
+ title="Inconsistant stack height with around">
+ <compile files="StackError.java"/>
+ <run class="StackError"/>
+ </ajc-test>
+
+
+ <ajc-test dir="bugs/messyAround" pr="36056"
+ title="Ajc 1.1 rc1 java.lang.VerifyError with messy arounds">
+ <compile files="aspects/Trace.aj,cap/OptionList.java,DebugTrace.aj">
+ <message kind="warning" line="102"/>
+ <message kind="warning" line="124"/>
+ <message kind="warning" line="138"/>
+ </compile>
+ <run class="cap.OptionList"/>
+ </ajc-test>
+
</suite>
diff --git a/tests/bugs/StackError.java b/tests/bugs/StackError.java
new file mode 100644
index 000000000..2b3a04a09
--- /dev/null
+++ b/tests/bugs/StackError.java
@@ -0,0 +1,46 @@
+import java.lang.reflect.Method;
+
+public class StackError {
+ public static void main(String args[]) {
+ new StackError().testEqualsNull();
+ }
+
+ void assertTrue(String msg, boolean b) {}
+
+ public void testEqualsNull() {
+ StackError one = new StackError();
+ StackError two = new StackError();
+ assertTrue("equal", one.equals(two)); // does not work
+ //boolean yes = one.equals(two); // works
+ }
+
+ public boolean equals(Object other) {
+ return true;
+ }
+}
+
+aspect EqualsContract {
+ pointcut equalsCall(Object thisOne, Object otherOne):
+ target(Object+) &&
+
+ target(thisOne) &&
+ call(public boolean equals(Object+)) &&
+ args(otherOne) &&
+ !within(EqualsContract);
+
+ boolean around(Object thisOne, Object otherOne):
+ equalsCall(thisOne, otherOne) {
+ boolean result = proceed(thisOne, otherOne);
+ Class cls = thisOne.getClass();
+ String name = cls.getName();
+ boolean hasHashCode = false;
+ try {
+ Method m = cls.getDeclaredMethod("hashCode", null);
+ String lookFor = "public int " + name + ".hashCode()";
+ hasHashCode = lookFor.equals(m.toString());
+ }
+ catch (NoSuchMethodException nsme) {
+ }
+ return result;
+ }
+}
diff --git a/tests/bugs/messyAround/DebugTrace.aj b/tests/bugs/messyAround/DebugTrace.aj
new file mode 100644
index 000000000..7e8c55432
--- /dev/null
+++ b/tests/bugs/messyAround/DebugTrace.aj
@@ -0,0 +1,34 @@
+import aspects.*;
+//import org.apache.log4j.*;
+//import com.checkfree.common.util.*;
+import java.lang.reflect.*;
+import java.util.*;
+import org.aspectj.lang.reflect.*;
+/**
+* This concrete trace aspect specifies what we should trace.
+ */
+
+privileged aspect DebugTrace extends Trace
+
+{
+ declare precedence: DebugTrace, *;
+
+ //private static Logger _log = null;
+
+ static
+ {
+ //String log4jPath = GlobalPaths.getPath("properties_dir")+"log4j.properties";
+ //PropertyConfigurator.configure(log4jPath);
+ //_log = Logger.getLogger(TestLog.class);
+ }
+
+ /** define the pointcut for what we trace */
+ protected pointcut lexicalScope() :within(cap.OptionList);
+
+ protected void log(String data)
+ {
+ System.err.println("data: " + data);
+ //_log.debug(data);
+ }
+
+}
diff --git a/tests/bugs/messyAround/aspects/Trace.aj b/tests/bugs/messyAround/aspects/Trace.aj
new file mode 100644
index 000000000..780ba6651
--- /dev/null
+++ b/tests/bugs/messyAround/aspects/Trace.aj
@@ -0,0 +1,490 @@
+package aspects;
+
+import java.io.*;
+import java.util.*;
+import org.aspectj.runtime.*;
+import org.aspectj.lang.*;
+import org.aspectj.lang.reflect.*;
+import java.lang.reflect.*;
+
+/** Trace is an aspect that traces execution through code.
+ *
+ */
+public abstract aspect Trace issingleton()
+{
+ // our internal instance
+ private static Trace _trace;
+
+ // Call depth on trace
+ private static final ThreadLocal traceDepths = new ThreadLocal();
+
+ // An object to synchronize on
+ protected static final Object lock = new Object();
+
+ private static final String NL = System.getProperty("line.separator");
+
+ // Space indentation increment
+ private static final int INDENT = 4;
+
+ // Used for indentation
+ private static final byte[] SPACES = new byte[100];
+
+ private static boolean traceActive = true;
+
+ static
+ {
+ Arrays.fill(SPACES,(byte)' ');
+ }
+
+
+ /** Trace constructor. Since this aspect is a singleton, we can be
+ * assured that only a single instance exists.
+ */
+ protected Trace() {_trace = this;}
+
+ /**
+ * This abstract pointcut indicates what classes we should trace. Typically
+ * you will define this using a within() PCD. We leave that up to concrete aspects.
+ */
+ protected abstract pointcut lexicalScope();
+
+ /**
+ * Common scope for all traces - includes lexicalScope
+ */
+ final pointcut scope() : if(_trace != null && _trace.canTraceJoinpoint(thisJoinPoint)) && lexicalScope() && !within(Trace+);
+
+ /**
+ * This pointcut designates tracing constructors within lexicalScope()
+ */
+ protected final pointcut constructorTrace() : scope() && (call( new(..) ) || execution( new(..)));
+ /**
+ * This pointcut designates tracing method executions within lexicalScope()
+ */
+ protected final pointcut methodTrace() : scope() && (call(* *(..)) || execution(* *(..)));
+
+ /**
+ * This pointcut designates tracing exception handlers within lexicalScope()
+ */
+ protected final pointcut handlerTrace(Exception e) : scope() && args(e) && handler(Exception+);
+
+
+ /**
+ * This pointcut picks out joinpoints within this aspect that implement
+ * the actual tracing. Since parameters and return values are printed
+ * out via implicit or explicit call to Object.toString(), there is the possibility
+ * of an execution joinpoint on toString() causing the trace logic
+ * to be re-entered. This is undesireable because it makes the trace output
+ * difficult to read and adds unecessary overhead. <p>
+ * This pointcut is used within a cflowbelow pointcut to prevent recursive
+ * trace calls.
+ */
+ private pointcut internalMethods() :
+ execution( void Trace.trace*(..,(JoinPoint||JoinPoint.StaticPart),..) );
+
+ /**
+ * For methods, we use around() advice to capture calls/executions.
+ */
+ Object around() : methodTrace() && !cflowbelow(internalMethods())
+ {
+ traceEnter(thisJoinPoint);
+ try
+ {
+ Object result = proceed();
+ traceResult(result,thisJoinPoint);
+ return result;
+ }
+ finally
+ {
+ traceExit(thisJoinPoint);
+ }
+ }
+
+ /**
+ * For Constructors, we use around() advice to capture calls/executions.
+ */
+ Object around() : constructorTrace() && !cflowbelow(internalMethods())
+ {
+ traceEnter(thisJoinPoint);
+ try
+ {
+ return proceed();
+ }
+ finally
+ {
+ traceExit(thisJoinPoint);
+ }
+ }
+
+
+ /**
+ * Trace Exceptions that may occur with constructors or methods
+ */
+ after() throwing(Throwable e): (constructorTrace() || methodTrace()) && !cflowbelow(internalMethods())
+ {
+ traceThrowable(e,thisJoinPoint);
+ }
+
+
+ /**
+ * Trace Exception handlers entry
+ */
+ before(Exception e) : handlerTrace(e) && !cflowbelow(internalMethods())
+ {
+ traceHandlerEntry(e,thisJoinPointStaticPart);
+ }
+ /**
+ * Trace Exception handlers exit
+ */
+ after(Exception e) : handlerTrace(e) && !cflowbelow(internalMethods())
+ {
+ traceHandlerExit();
+ }
+
+
+ /**
+ * Subaspects can override this method to log the data as needed. The default
+ * mechanism is to log to System.out
+ *
+ * Clients should be aware that this method is not synchronized.
+ */
+ protected void log(String data) {System.out.println(data);}
+
+ /**
+ * Can be overridden by subaspects to filter what constructors/methods should be
+ * traced at runtime. This method is always called prior to the log()
+ * method. The default always returns true.<p> Note that exceptions thrown
+ * by constructors/methods are filtered through this method.
+ * @param currentlyExecutingClass The Class that is currently executing.
+ * @param signature The signature of the member being traced
+ * @param traceType The type of trace entry (see AspectJ doc for the available types)
+ */
+ protected boolean isTraceable(Class currentlyExecutingClass, CodeSignature signature,String traceType) {return true;}
+
+ /**
+ * Can be overridden by subaspects to filter what exception handlers should be
+ * traced at runtime. This method is always called prior to the log()
+ * method. The default always returns false.<p>
+ * Note that exception handlers are catch(...){} blocks and are filtered
+ * independently from constructor/method calls and execution.
+ * @param currentlyExecutingClass The Class that is currently executing.
+ * @param signature The signature of the member being traced
+ */
+ protected boolean isTraceable(Class currentlyExecutingClass, CatchClauseSignature signature) {return false;}
+
+ /**
+ * Retrieves the signature of the joinpoint and asks if it can be traced
+ */
+ private boolean canTraceJoinpoint(JoinPoint jp)
+ {
+ if ( !traceActive ) return false;
+ final Signature sig = jp.getSignature();
+ final Object o = jp.getThis(); // current object
+ Class currentType;
+ if ( o == null ) // must be a static
+ currentType = jp.getStaticPart().getSourceLocation().getWithinType();
+ else
+ currentType = o.getClass();
+
+ // dispatch the correct filter method
+ if ( sig instanceof CodeSignature )
+ return isTraceable(currentType,(CodeSignature)sig,jp.getKind());
+ else
+ return isTraceable(currentType,(CatchClauseSignature)sig);
+ }
+
+
+ /**
+ * This method creates a trace entry line based on information in the
+ * supplied join point.
+ */
+ private void traceEnter(JoinPoint thisJoinPoint)
+ {
+
+ // Get the indent level (call depth for current thread * 4).
+ int depth = getTraceDepth(INDENT);
+
+ Class[] parameterTypes = ((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes();
+ String[] parameterNames = ((CodeSignature)thisJoinPoint.getSignature()).getParameterNames();
+
+ boolean isCall = thisJoinPoint.getKind().endsWith("call");
+
+ StringBuffer enterPhrase = new StringBuffer(100);
+ enterPhrase.append(getSpaces(depth));
+ if ( isCall )
+ enterPhrase.append("Call ");
+ else
+ enterPhrase.append("Entering ");
+ enterPhrase.append(methodSignature(parameterNames,parameterTypes,thisJoinPoint));
+
+// if ( isCall )
+// enterPhrase.append(" From: ").append(thisJoinPoint.getSourceLocation().getWithinType());
+
+ // Prepare the methods parameter list
+ String parmStr = null;
+ Object[] parameters = thisJoinPoint.getArgs();
+ if (parameters.length > 0)
+ {
+ String spaces = getSpaces(depth + 6);
+ StringBuffer parms = new StringBuffer();
+ for (int i = 0; i < parameters.length; i++)
+ {
+ if (parameters[i] != null && parameters[i].getClass().isArray())
+ {
+ // arrays can be huge...limit to first 100 elements
+ final int len = Math.min(Array.getLength(parameters[i]),100);
+ if ( len == 0 )
+ {
+ parms.append(spaces);
+ parms.append(parameterNames[i]);
+ parms.append(": 0 length array");
+ parms.append(NL);
+ }
+ else
+ {
+ Object o = null;
+ for ( int x = 0; x < len; x++ )
+ {
+ parms.append(spaces);
+ parms.append(parameterNames[i]);
+ parms.append("[");
+ parms.append(x);
+ parms.append("]:");
+ o = Array.get(parameters[i],x);
+ try{parms.append(" " + (o != null?o:"null"));} // implicit toString()
+ catch(Throwable t) {parms.append(" " + parameters[i]);}
+ parms.append(NL);
+ }
+ }
+ }
+ else
+ {
+ // Not an array.
+ parms.append(spaces);
+ parms.append(parameterNames[i]);
+ parms.append(": ");
+ try
+ {
+ parms.append("" + parameters[i]);
+ }
+ catch (Throwable t ) {parms.append("" + parameters[i].getClass().getName());}
+ }
+
+ parmStr = parms.toString();
+
+ }
+
+ }
+
+ if (parmStr != null)
+ enterPhrase.append(NL).append(parmStr);
+ log(enterPhrase.toString());
+ }
+
+ /**
+ * This method creates an exception handler trace entry based on a Throwable
+ * and information contained in the join point.
+ */
+ private void traceHandlerEntry(Throwable t, JoinPoint.StaticPart thisJoinPoint)
+ {
+
+ int depth = getTraceDepth(INDENT);
+ String phrase = getSpaces(depth) +
+ "Exception caught at: " +
+ thisJoinPoint;
+ log(printStackTrace(phrase,t));
+
+ }
+ /**
+ * This method simply adjusts the trace depth - no other information printed.
+ */
+ private void traceHandlerExit()
+ {
+ getTraceDepth(-INDENT);
+ }
+ /**
+ * This method creates a stack trace entry based on a Throwable and
+ * information contained in the join point.
+ */
+ private void traceThrowable(Throwable t, JoinPoint thisJoinPoint)
+ {
+
+ int depth = getTraceDepth(0);
+ String phrase = getSpaces(depth+4) +
+ "Throwing Exception at: " +
+ thisJoinPoint;
+ log(printStackTrace(phrase,t));
+ }
+
+
+ private String printStackTrace(String phrase, Throwable t)
+ {
+ try {
+ StringWriter sw = new StringWriter(4096);
+ PrintWriter pw = new PrintWriter(sw,true);
+
+ pw.println(phrase);
+
+ pw.println();
+
+ pw.println("Exception Stack Trace:");
+
+ pw.println();
+
+ t.printStackTrace(pw);
+
+ pw.println();
+
+ pw.flush();
+ sw.flush();
+
+ pw.close();
+ sw.close();
+ return sw.toString();
+ }
+ catch(IOException IOE) {
+ log(IOE.toString());
+ return IOE.getMessage();
+ }
+ }
+
+ /**
+ * This method creates a trace exit entry based on the join point
+ * information.
+ */
+ private void traceExit(JoinPoint thisJoinPoint)
+ {
+
+ int depth = getTraceDepth(-INDENT);
+
+ // Assemble the method's signature.
+ Class[] parameterTypes = ((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes();
+ String[] parameterNames = ((CodeSignature)thisJoinPoint.getSignature()).getParameterNames();
+
+ boolean isCall = thisJoinPoint.getKind().endsWith("call");
+
+ StringBuffer exitPhrase = new StringBuffer(100);
+ exitPhrase.append(getSpaces(depth));
+ if ( isCall )
+ exitPhrase.append("Return ");
+ else
+ exitPhrase.append("Exiting ");
+ exitPhrase.append(methodSignature(parameterNames,parameterTypes,thisJoinPoint)).append(NL);
+
+
+ log(exitPhrase.toString());
+
+ }
+
+ /**
+ * This method creates a trace result entry based on a result and the
+ * join point.
+ */
+ private void traceResult(Object thisResult, JoinPoint thisJoinPoint)
+ {
+
+ Class returnType = ((MethodSignature)thisJoinPoint.getSignature()).getReturnType();
+ if ( returnType.toString().equals("void") )
+ return;
+
+ int depth = getTraceDepth(0);
+ if ( thisResult == null )
+ thisResult = "null";
+
+ if ( thisResult.getClass().isArray() )
+ {
+ // arrays can be Oprah-sized - limit to 100 elements
+ final int len = Math.min(Array.getLength(thisResult),100);
+ StringBuffer buf = new StringBuffer();
+ if ( len == 0 )
+ buf.append(">>>zero-length array<<<");
+ else
+ {
+ Object o;
+ for ( int i = 0; i < len; i++ )
+ {
+ o = Array.get(thisResult,i);
+ buf.append("data[").append(i).append("] ");
+ try{buf.append(o != null?o:"null");} // implicit toString()
+ catch(Throwable t) {buf.append(thisResult);}
+ buf.append(NL);
+ }
+ }
+ thisResult = buf.toString();
+ }
+ thisResult = thisResult.toString();
+
+ StringBuffer returnPhrase = new StringBuffer(100);
+ returnPhrase.append(getSpaces(depth+2)).append(thisJoinPoint);
+ returnPhrase.append(" returned >>>>>>> ").append(thisResult);
+
+ log(returnPhrase.toString());
+ }
+
+ /**
+ * This method returns the current trace line indentation for the
+ * thread.
+ */
+ private int getTraceDepth(int incr)
+ {
+ int rc = 0;
+ Integer depth = (Integer) traceDepths.get();
+ if (depth == null)
+ {
+ if ( incr > 0 )
+ {
+ traceDepths.set(new Integer(incr));
+ return incr;
+ }
+ else return rc;
+ }
+
+ rc = depth.intValue();
+
+ if ( incr > 0 )
+ {
+ depth = new Integer(rc += incr);
+ traceDepths.set(depth);
+ }
+ else if ( incr < 0 )
+ {
+ depth = new Integer(rc + incr);
+ traceDepths.set(depth);
+ }
+
+ return rc;
+ }
+
+ /**
+ * This method returns a String containing the number of spaces desired to
+ * be used as padding for formatting trace log entries.
+ */
+ private String getSpaces(int num)
+ {
+ return new String(SPACES,0,Math.min(num,SPACES.length));
+ }
+
+ /**
+ * Create a method signature
+ */
+ private String methodSignature(String[] parameterNames,
+ Class[] parameterTypes,
+ JoinPoint thisJoinPoint)
+ {
+ // Assemble the method's signature.
+ StringBuffer signature = new StringBuffer("(");
+ for (int i = 0; i < parameterTypes.length; i++)
+ {
+ signature.append(parameterTypes[i].getName());
+ signature.append(" ");
+ signature.append(parameterNames[i]);
+ if (i < (parameterTypes.length-1))
+ signature.append(", ");
+ }
+ signature.append(")");
+
+ return thisJoinPoint.getSignature().getDeclaringType().getName() + "." +
+ thisJoinPoint.getSignature().getName() +
+ signature;
+ }
+
+} \ No newline at end of file
diff --git a/tests/bugs/messyAround/cap/OptionList.java b/tests/bugs/messyAround/cap/OptionList.java
new file mode 100644
index 000000000..1e4a9349c
--- /dev/null
+++ b/tests/bugs/messyAround/cap/OptionList.java
@@ -0,0 +1,138 @@
+package cap;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.net.*;
+import java.text.*;
+
+/**
+ * This class builds a list of &lt;option&gt; HTML elements given a data object,
+ * typically a GAPI output object, and a list of accessor method names.
+ * <p>
+ * <b>Usage:</b><pre>
+ * // Create the bank account list select
+ * RBBankAcctList2Input acctIn = new RBBankAcctList2Input();
+ * initApiHeader(acctIn.getHeader(),sessInfo);
+ * ArrayList accts = new ArrayList();
+ * getBankAccounts(acctIn,accts);
+ *
+ * String ol = OptionList.createListHtmlFromApi(accts.toArray(),
+ * new String[]{"getBankAcctNbr","getBankRtgNbr","getBankAcctTyp"},
+ * new String[]{"getBankAcctNbr"},
+ * new MessageFormat("{0}"),
+ * Integer.parseInt(acctIndex));
+ *
+ * </pre>
+ * @author Rich Price
+ */
+class OptionList
+{
+ private static final String OPTION_PATTERN = "<option value=\"{0}\" {1}>{2}</option>";
+ private static final Object[] GETTER_ARGS = new Object[0];
+ private static final Class[] GETTER_ARG_TYPES = new Class[0];
+ private static final String DELIM = "&";
+
+ /**
+ * Parses the value string and returns a HashMap of name/value pairs
+ * @return A HashMap of name/value pairs.
+ * @see createListHtmlFromApi
+ */
+ public static HashMap getSelectedValues(String optionListValueString)
+ {
+ HashMap map = new HashMap();
+ if ( optionListValueString != null )
+ {
+ StringTokenizer lex = new StringTokenizer(optionListValueString,DELIM + "=",false);
+ while ( lex.hasMoreTokens() )
+ map.put(lex.nextToken(),lex.nextToken());
+ }
+ return map;
+ }
+
+ /**
+ * This method creates a String of HTML &lt;option&gt; elements in the following
+ * format:<p>
+ * <pre>
+ * &lt;option value="valueName1=value1^valueName2=value2"&gt; optionValues &lt;option&gt;
+ * </pre>
+ * @param api An array of Objects, typically a GAPI output object, from which data
+ * will be retrieved by name(s).
+ * @param valueNames An array of method names declared in <code>api</code>. Only
+ * public methods taking zero arguments can be used. Each non-null value
+ * is used to create a value string for the particular HTML option element in the form:
+ * valueName1=value1^valueName2=value2...where valueName[n] is the method name.
+ * For convenience, the getValues() method will return a HashMap of these name/value
+ * pairs.
+ * @param optionNames An array of method names declared in <code>api</code>. Only
+ * public methods taking zero arguments can be listed. Each non-null value
+ * is used to create a parameter list to pass to a supplied MessageFormat object.
+ * Each value retrieved from the api object will be substituted using the MessageFormat
+ * object, the resulting String is used to create the optionValues string that is
+ * displayed to the user.
+ * @param selectedIndex The index of the option that should be selected. If -1, nothing
+ * will be selected.
+ *
+ */
+ public static String createListHtmlFromApi(Object[] api,
+ String[] valueNames,
+ String[] optionNames,
+ MessageFormat optionFormat,
+ int selectedIndex )
+ {
+ StringBuffer html = new StringBuffer();
+ for ( int apiIndex = 0; apiIndex < api.length; apiIndex++ )
+ {
+ final String[] messageArgs = new String[3];
+ // for each valueName, use reflection to look up data from the api
+ StringBuffer buf = new StringBuffer();
+ for ( int i = 0; i < valueNames.length; i++ )
+ {
+ try
+ {
+ Method m = api[apiIndex].getClass().getMethod(valueNames[i], GETTER_ARG_TYPES);
+ String value = m.invoke(api[apiIndex],GETTER_ARGS).toString();
+
+ if ( value != null && value.length() > 0 )
+ {
+ if ( buf.length() > 0 )
+ buf.append(DELIM);
+ buf.append(valueNames[i]).append("=").append(value);
+ }
+ }
+ catch (Exception e) {}
+ }
+ // set the first and second value arguments for the pattern
+ messageArgs[0] = buf.toString();
+ if ( apiIndex == selectedIndex )
+ messageArgs[1] = "selected";
+ else
+ messageArgs[1] = "";
+
+ // now, handle the option part
+ buf.setLength(0);
+ String[] optionFormatArgs = new String[optionNames.length];
+ for ( int i = 0; i < optionNames.length; i++ )
+ {
+ try
+ {
+ optionFormatArgs[i] = "";
+ Method m = api[apiIndex].getClass().getMethod(optionNames[i],GETTER_ARG_TYPES);
+ String value = m.invoke(api[apiIndex],GETTER_ARGS).toString();
+ if ( value != null )
+ optionFormatArgs[i] = value;
+ }
+ catch(Exception e) {}
+ }
+
+ messageArgs[2] = optionFormat.format(optionFormatArgs,buf,new FieldPosition(0)).toString();
+ html.append(MessageFormat.format(OPTION_PATTERN,messageArgs));
+ }
+ return html.toString();
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ OptionList.createListHtmlFromApi(new Object[]{new String()},new String[]{"getFoo"},new String[]{"getFoo"},new MessageFormat("{0}"),-1);
+ }
+
+} \ No newline at end of file
diff --git a/tests/jimTests.xml b/tests/jimTests.xml
index 7664c3799..a58aef5fa 100644
--- a/tests/jimTests.xml
+++ b/tests/jimTests.xml
@@ -1,8 +1,26 @@
<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd">
<suite>
+ <ajc-test dir="bugs" pr="29665"
+ title="Inconsistant stack height with around">
+ <compile files="StackError.java"/>
+ <run class="StackError"/>
+ </ajc-test>
+
+ <ajc-test dir="bugs/messyAround" pr="36056"
+ title="Ajc 1.1 rc1 java.lang.VerifyError with messy arounds">
+ <compile files="aspects/Trace.aj,cap/OptionList.java,DebugTrace.aj">
+ <message kind="warning" line="102"/>
+ <message kind="warning" line="124"/>
+ <message kind="warning" line="138"/>
+ </compile>
+ <run class="cap.OptionList"/>
+ </ajc-test>
<!--
+
+
+
<ajc-test dir="new" pr="885"
title="source locations within expressions">
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
index 6059e7d9f..30f5b263f 100644
--- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
+++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
@@ -1201,7 +1201,12 @@ public class BcelShadow extends Shadow {
BcelObjectType ot = BcelWorld.getBcelObjectType(declaringType);
LazyMethodGen adviceMethod = ot.getLazyClassGen().getLazyMethodGen(mungerSig);
- if (!adviceMethod.getCanInline()) {
+ //TODO handle the second part of this if by creating a method for the around
+ // advice rather than going to a full-on closure
+ if (!adviceMethod.getCanInline() ||
+ isFallsThrough() && adviceMethod.hasExceptionHandlers() // fix for Bug 29665
+ )
+ {
weaveAroundClosure(munger, hasDynamicTest);
return;
}
diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java
index adf0c953a..9c7f3dc42 100644
--- a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java
+++ b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java
@@ -81,6 +81,7 @@ public final class LazyMethodGen {
private int maxLocals;
private boolean canInline = true;
+ private boolean hasExceptionHandlers;
/**
* only used by {@link BcelClassWeaver}
@@ -167,6 +168,7 @@ public final class LazyMethodGen {
CodeExceptionGen[] exns = gen.getExceptionHandlers();
if (exns != null) {
int len = exns.length;
+ if (len > 0) hasExceptionHandlers = true;
int priority = len - 1;
for (int i = 0; i < len; i++, priority--) {
CodeExceptionGen exn = exns[i];
@@ -1145,5 +1147,8 @@ public final class LazyMethodGen {
public void setCanInline(boolean canInline) {
this.canInline = canInline;
}
+ public boolean hasExceptionHandlers() {
+ return hasExceptionHandlers;
+ }
}