diff options
author | acolyer <acolyer> | 2005-09-26 15:05:01 +0000 |
---|---|---|
committer | acolyer <acolyer> | 2005-09-26 15:05:01 +0000 |
commit | d485f9bcc4df37aef60863fceb88654bbd32b680 (patch) | |
tree | 1341f68a69f16d1a6b0f86d840ee8a5553c8d091 /bridge | |
parent | 4afdcf2612e94ce3c07ab0db5b20ea73134ac632 (diff) | |
download | aspectj-d485f9bcc4df37aef60863fceb88654bbd32b680.tar.gz aspectj-d485f9bcc4df37aef60863fceb88654bbd32b680.zip |
fix for pr108123 and pr106500 - better diagnostics and exceptions, plus support for -Xdev:Pinpoint
Diffstat (limited to 'bridge')
6 files changed, 457 insertions, 0 deletions
diff --git a/bridge/src/org/aspectj/bridge/context/CompilationAndWeavingContext.java b/bridge/src/org/aspectj/bridge/context/CompilationAndWeavingContext.java new file mode 100644 index 000000000..208bc696b --- /dev/null +++ b/bridge/src/org/aspectj/bridge/context/CompilationAndWeavingContext.java @@ -0,0 +1,240 @@ +/* ******************************************************************* + * Copyright (c) 2005 Contributors. + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://eclipse.org/legal/epl-v10.html + * + * Contributors: + * Adrian Colyer Initial implementation + * ******************************************************************/ +package org.aspectj.bridge.context; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Stack; + +/** + * @author colyer + * This class is responsible for tracking progress through the various phases of + * compilation and weaving. When an exception occurs (or a message is issued, if + * desired), you can ask this class for a "stack trace" that gives information about + * what the compiler was doing at the time. The trace will say something like: + * + * when matching pointcut xyz + * when matching shadow sss + * when weaving type ABC + * when weaving shadow mungers + * + * Since we can't use ThreadLocal (have to work on 1.3), we use a + * map from Thread -> ContextStack. + */ +public class CompilationAndWeavingContext { + + private static int nextTokenId = 1; + + // unique constants for the different phases that can be registered + + // "FRONT END" + public static final int BATCH_BUILD = 0; + public static final int INCREMENTAL_BUILD = 1; + public static final int PROCESSING_COMPILATION_UNIT = 2; + public static final int RESOLVING_COMPILATION_UNIT = 3; + public static final int ANALYSING_COMPILATION_UNIT = 4; + public static final int GENERATING_UNWOVEN_CODE_FOR_COMPILATION_UNIT = 5; + public static final int COMPLETING_TYPE_BINDINGS = 6; + public static final int PROCESSING_DECLARE_PARENTS = 7; + public static final int CHECK_AND_SET_IMPORTS = 8; + public static final int CONNECTING_TYPE_HIERARCHY = 9; + public static final int BUILDING_FIELDS_AND_METHODS = 10; + public static final int COLLECTING_ITDS_AND_DECLARES = 11; + public static final int PROCESSING_DECLARE_ANNOTATIONS = 12; + public static final int WEAVING_INTERTYPE_DECLARATIONS = 13; + public static final int RESOLVING_POINTCUT_DECLARATIONS = 14; + public static final int ADDING_DECLARE_WARNINGS_AND_ERRORS = 15; + public static final int VALIDATING_AT_ASPECTJ_ANNOTATIONS = 16; + public static final int ACCESS_FOR_INLINE = 17; + public static final int ADDING_AT_ASPECTJ_ANNOTATIONS = 18; + public static final int FIXING_SUPER_CALLS_IN_ITDS = 19; + public static final int FIXING_SUPER_CALLS = 20; + public static final int OPTIMIZING_THIS_JOIN_POINT_CALLS = 21; + + // "BACK END" + + public static final int WEAVING = 22; + public static final int PROCESSING_REWEAVABLE_STATE = 23; + public static final int PROCESSING_TYPE_MUNGERS = 24; + public static final int WEAVING_ASPECTS = 25; + public static final int WEAVING_CLASSES = 26; + public static final int WEAVING_TYPE = 27; + public static final int MATCHING_SHADOW = 28; + public static final int IMPLEMENTING_ON_SHADOW = 29; + public static final int MATCHING_POINTCUT = 30; + public static final int MUNGING_WITH = 31; + + + // phase names + public static final String[] PHASE_NAMES = new String[] { + "batch building", + "incrementally building", + "processing compilation unit", + "resolving types defined in compilation unit", + "analysing types defined in compilation unit", + "generating unwoven code for type defined in compilation unit", + "completing type bindings", + "processing declare parents", + "checking and setting imports", + "connecting type hierarchy", + "building fields and methods", + "collecting itds and declares", + "processing declare annotations", + "weaving intertype declarations", + "resolving pointcut declarations", + "adding declare warning and errors", + "validating @AspectJ annotations", + "creating accessors for inlining", + "adding @AspectJ annotations", + "fixing super calls in ITDs in interface context", + "fixing super calls in ITDs", + "optimizing thisJoinPoint calls", + + // BACK END + + "weaving", + "processing reweavable state", + "processing type mungers", + "weaving aspects", + "weaving classes", + "weaving type", + "matching shadow", + "implementing on shadow", + "matching pointcut", + "type munging with" + }; + + // context stacks, one per thread + private static Map contextMap = new HashMap(); + // formatters, by phase id + private static Map formatterMap = new HashMap(); + + private static ContextFormatter defaultFormatter = new DefaultFormatter(); + + + /** + * this is a static service + */ + private CompilationAndWeavingContext() { + } + + // for testing... + public static void reset() { + contextMap = new HashMap(); + formatterMap = new HashMap(); + nextTokenId = 1; + } + + public static void registerFormatter(int phaseId, ContextFormatter aFormatter) { + formatterMap.put(new Integer(phaseId),aFormatter); + } + + /** + * Returns a string description of what the compiler/weaver is currently doing + */ + public static String getCurrentContext() { + Stack contextStack = getContextStack(); + Stack explanationStack = new Stack(); + for (Iterator iter = contextStack.iterator(); iter.hasNext();) { + ContextStackEntry entry = (ContextStackEntry) iter.next(); + explanationStack.push(getFormatter(entry).formatEntry(entry.phaseId,entry.data)); + } + StringBuffer sb = new StringBuffer(); + for (Iterator iter = explanationStack.iterator(); iter.hasNext();) { + sb.append("when "); + sb.append(iter.next().toString()); + sb.append("\n"); + } + return sb.toString(); + } + + public static ContextToken enteringPhase(int phaseId, Object data) { + Stack contextStack = getContextStack(); + ContextTokenImpl nextToken = nextToken(); + contextStack.push(new ContextStackEntry(nextToken,phaseId,data)); + return nextToken; + } + + /** + * Exit a phase, all stack entries from the one with the given token + * down will be removed. + */ + public static void leavingPhase(ContextToken aToken) { + Stack contextStack = getContextStack(); + while (!contextStack.isEmpty()) { + ContextStackEntry entry = (ContextStackEntry) contextStack.pop(); + if (entry.contextToken == aToken) break; + } + } + + private static Stack getContextStack() { + if (contextMap.containsKey(Thread.currentThread())) { + return (Stack) contextMap.get(Thread.currentThread()); + } else { + Stack contextStack = new Stack(); + contextMap.put(Thread.currentThread(),contextStack); + return contextStack; + } + } + + private static ContextTokenImpl nextToken() { + return new ContextTokenImpl(nextTokenId++); + } + + private static ContextFormatter getFormatter(ContextStackEntry entry) { + Integer key = new Integer(entry.phaseId); + if (formatterMap.containsKey(key)) { + return (ContextFormatter) formatterMap.get(key); + } else { + return defaultFormatter; + } + } + + private static class ContextTokenImpl implements ContextToken { + public int tokenId; + public ContextTokenImpl(int id) { this.tokenId = id; } + } + + // dumb data structure + private static class ContextStackEntry { + public ContextTokenImpl contextToken; + public int phaseId; + public Object data; + public ContextStackEntry(ContextTokenImpl ct, int phase, Object data) { + this.contextToken = ct; + this.phaseId = phase; + this.data = data; + } + } + + private static class DefaultFormatter implements ContextFormatter { + + public String formatEntry(int phaseId, Object data) { + StringBuffer sb = new StringBuffer(); + sb.append(PHASE_NAMES[phaseId]); + sb.append(" "); + if (data instanceof char[]) { + sb.append(new String((char[])data)); + } else { + try { + sb.append(data.toString()); + } catch (RuntimeException ex) { + // don't lose vital info because of bad toString + sb.append("** broken toString in data object **"); + } + } + return sb.toString(); + } + + } +} diff --git a/bridge/src/org/aspectj/bridge/context/ContextFormatter.java b/bridge/src/org/aspectj/bridge/context/ContextFormatter.java new file mode 100644 index 000000000..9f1b591d7 --- /dev/null +++ b/bridge/src/org/aspectj/bridge/context/ContextFormatter.java @@ -0,0 +1,21 @@ +/* ******************************************************************* + * Copyright (c) 2005 Contributors. + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://eclipse.org/legal/epl-v10.html + * + * Contributors: + * Adrian Colyer Initial implementation + * ******************************************************************/ +package org.aspectj.bridge.context; + +/** + * @author colyer + * Implementors of this interface know how to turn the "Object" data and phase id + * associated with a context stack entry into a meaningful string. + */ +public interface ContextFormatter { + String formatEntry(int phaseId, Object data); +} diff --git a/bridge/src/org/aspectj/bridge/context/ContextToken.java b/bridge/src/org/aspectj/bridge/context/ContextToken.java new file mode 100644 index 000000000..2415fa72e --- /dev/null +++ b/bridge/src/org/aspectj/bridge/context/ContextToken.java @@ -0,0 +1,20 @@ +/* ******************************************************************* + * Copyright (c) 2005 Contributors. + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://eclipse.org/legal/epl-v10.html + * + * Contributors: + * Adrian Colyer Initial implementation + * ******************************************************************/ +package org.aspectj.bridge.context; + +/** + * When an entry is added to the CompilationAndWeavingContext stack, + * a ContextToken is returned. + * When leaving a compilation or weaving phase, this token must be supplied. + * The token details are opaque to clients + */ +public interface ContextToken {} diff --git a/bridge/src/org/aspectj/bridge/context/PinpointingMessageHandler.java b/bridge/src/org/aspectj/bridge/context/PinpointingMessageHandler.java new file mode 100644 index 000000000..8f7852eb0 --- /dev/null +++ b/bridge/src/org/aspectj/bridge/context/PinpointingMessageHandler.java @@ -0,0 +1,106 @@ +/* ******************************************************************* + * Copyright (c) 2005 Contributors. + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://eclipse.org/legal/epl-v10.html + * + * Contributors: + * Adrian Colyer Initial implementation + * ******************************************************************/ +package org.aspectj.bridge.context; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; + +import org.aspectj.bridge.AbortException; +import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.IMessageHandler; +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.bridge.IMessage.Kind; + +/** + * @author colyer + * Facade for an IMessageHandler + * Extends message with details of exactly what the compiler / weaver was doing at the + * time. Use the -Xdev:Pinpoint option to turn this facility on. + */ +public class PinpointingMessageHandler implements IMessageHandler { + + private IMessageHandler delegate; + + public PinpointingMessageHandler(IMessageHandler delegate) { + this.delegate = delegate; + } + + /* (non-Javadoc) + * @see org.aspectj.bridge.IMessageHandler#handleMessage(org.aspectj.bridge.IMessage) + */ + public boolean handleMessage(IMessage message) throws AbortException { + if (!isIgnoring(message.getKind())) { + MessageIssued ex = new MessageIssued(); + ex.fillInStackTrace(); + StringWriter sw = new StringWriter(); + ex.printStackTrace(new PrintWriter(sw)); + StringBuffer sb = new StringBuffer(); + sb.append(CompilationAndWeavingContext.getCurrentContext()); + sb.append(sw.toString()); + IMessage pinpointedMessage = new PinpointedMessage(message,sb.toString()); + return delegate.handleMessage(pinpointedMessage); + } else { + return delegate.handleMessage(message); + } + } + + /* (non-Javadoc) + * @see org.aspectj.bridge.IMessageHandler#isIgnoring(org.aspectj.bridge.IMessage.Kind) + */ + public boolean isIgnoring(Kind kind) { + return delegate.isIgnoring(kind); + } + + /* (non-Javadoc) + * @see org.aspectj.bridge.IMessageHandler#dontIgnore(org.aspectj.bridge.IMessage.Kind) + */ + public void dontIgnore(Kind kind) { + delegate.dontIgnore(kind); + } + + private static class PinpointedMessage implements IMessage { + + private IMessage delegate; + private String message; + + public PinpointedMessage(IMessage delegate, String pinpoint) { + this.delegate = delegate; + this.message = delegate.getMessage() + "\n" + pinpoint; + } + + public String getMessage() { return this.message; } + public Kind getKind() { return delegate.getKind();} + public boolean isError() { return delegate.isError(); } + public boolean isWarning() { return delegate.isWarning();} + public boolean isDebug() { return delegate.isDebug();} + public boolean isInfo() { return delegate.isInfo();} + public boolean isAbort() { return delegate.isAbort();} + public boolean isTaskTag() { return delegate.isTaskTag();} + public boolean isFailed() { return delegate.isFailed();} + public boolean getDeclared() { return delegate.getDeclared(); } + public int getID() { return delegate.getID();} + public int getSourceStart() { return delegate.getSourceStart();} + public int getSourceEnd() { return delegate.getSourceEnd();} + public Throwable getThrown() { return delegate.getThrown();} + public ISourceLocation getSourceLocation() { return delegate.getSourceLocation();} + public String getDetails() { return delegate.getDetails();} + public List getExtraSourceLocations() { return delegate.getExtraSourceLocations();} + } + + private static class MessageIssued extends RuntimeException { + public String getMessage() { + return "message issued..."; + } + } + +} diff --git a/bridge/testsrc/BridgeModuleTests.java b/bridge/testsrc/BridgeModuleTests.java index e0049f863..23e28ea60 100644 --- a/bridge/testsrc/BridgeModuleTests.java +++ b/bridge/testsrc/BridgeModuleTests.java @@ -14,6 +14,8 @@ // default package +import org.aspectj.bridge.context.CompilationAndWeavingContextTest; + import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -23,6 +25,7 @@ public class BridgeModuleTests extends TestCase { public static Test suite() { TestSuite suite = new TestSuite(BridgeModuleTests.class.getName()); suite.addTest(org.aspectj.bridge.BridgeTests.suite()); + suite.addTestSuite(CompilationAndWeavingContextTest.class); return suite; } diff --git a/bridge/testsrc/org/aspectj/bridge/context/CompilationAndWeavingContextTest.java b/bridge/testsrc/org/aspectj/bridge/context/CompilationAndWeavingContextTest.java new file mode 100644 index 000000000..6e8c73e22 --- /dev/null +++ b/bridge/testsrc/org/aspectj/bridge/context/CompilationAndWeavingContextTest.java @@ -0,0 +1,67 @@ +/* ******************************************************************* + * Copyright (c) 2005 Contributors. + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://eclipse.org/legal/epl-v10.html + * + * Contributors: + * Adrian Colyer Initial implementation + * ******************************************************************/ +package org.aspectj.bridge.context; + +import junit.framework.TestCase; + +/** + * @author colyer + * + */ +public class CompilationAndWeavingContextTest extends TestCase { + + public void testEnteringPhase() { + CompilationAndWeavingContext.enteringPhase(1,"XYZ"); + assertEquals("when fiddling XYZ\n",CompilationAndWeavingContext.getCurrentContext()); + } + + public void testDoubleEntry() { + CompilationAndWeavingContext.enteringPhase(1,"XYZ"); + CompilationAndWeavingContext.enteringPhase(2, "ABC"); + assertEquals("when fiddling XYZ\nwhen mucking about with ABC\n",CompilationAndWeavingContext.getCurrentContext()); + } + + public void testEntryEntryExit() { + CompilationAndWeavingContext.enteringPhase(1,"XYZ"); + ContextToken ct = CompilationAndWeavingContext.enteringPhase(2, "ABC"); + CompilationAndWeavingContext.leavingPhase(ct); + assertEquals("when fiddling XYZ\n",CompilationAndWeavingContext.getCurrentContext()); + } + + public void testEntryExitTop() { + ContextToken ct = CompilationAndWeavingContext.enteringPhase(1,"XYZ"); + CompilationAndWeavingContext.enteringPhase(2, "ABC"); + CompilationAndWeavingContext.leavingPhase(ct); + assertEquals("",CompilationAndWeavingContext.getCurrentContext()); + } + + + protected void setUp() throws Exception { + CompilationAndWeavingContext.reset(); + CompilationAndWeavingContext.registerFormatter(1, new MyContextFormatter("fiddling ")); + CompilationAndWeavingContext.registerFormatter(2, new MyContextFormatter("mucking about with ")); + } + + private static class MyContextFormatter implements ContextFormatter { + + private String prefix; + + public MyContextFormatter(String prefix) { + this.prefix = prefix; + } + + public String formatEntry(int phaseId, Object data) { + return prefix + data.toString(); + } + + } +} |