aboutsummaryrefslogtreecommitdiffstats
path: root/bridge
diff options
context:
space:
mode:
authoracolyer <acolyer>2005-09-26 15:05:01 +0000
committeracolyer <acolyer>2005-09-26 15:05:01 +0000
commitd485f9bcc4df37aef60863fceb88654bbd32b680 (patch)
tree1341f68a69f16d1a6b0f86d840ee8a5553c8d091 /bridge
parent4afdcf2612e94ce3c07ab0db5b20ea73134ac632 (diff)
downloadaspectj-d485f9bcc4df37aef60863fceb88654bbd32b680.tar.gz
aspectj-d485f9bcc4df37aef60863fceb88654bbd32b680.zip
fix for pr108123 and pr106500 - better diagnostics and exceptions, plus support for -Xdev:Pinpoint
Diffstat (limited to 'bridge')
-rw-r--r--bridge/src/org/aspectj/bridge/context/CompilationAndWeavingContext.java240
-rw-r--r--bridge/src/org/aspectj/bridge/context/ContextFormatter.java21
-rw-r--r--bridge/src/org/aspectj/bridge/context/ContextToken.java20
-rw-r--r--bridge/src/org/aspectj/bridge/context/PinpointingMessageHandler.java106
-rw-r--r--bridge/testsrc/BridgeModuleTests.java3
-rw-r--r--bridge/testsrc/org/aspectj/bridge/context/CompilationAndWeavingContextTest.java67
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();
+ }
+
+ }
+}