]> source.dussan.org Git - aspectj.git/commitdiff
PushIn
authoraclement <aclement>
Mon, 7 Jun 2010 18:28:40 +0000 (18:28 +0000)
committeraclement <aclement>
Mon, 7 Jun 2010 18:28:40 +0000 (18:28 +0000)
12 files changed:
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjPipeliningCompilerAdapter.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/CommonPrinter.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/DeclareAnnotationsPrinter.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDConstructorPrinter.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDFieldPrinter.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDMethodPrinter.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/PushinCollector.java [new file with mode: 0644]

index 2537c0356e14f8d0bd1c9184f914ca4f6f87d86e..a23eb05f09050426a700e89c70eb55b0a0df670d 100644 (file)
@@ -85,8 +85,7 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
                        EclipseFactory eFactory, IIntermediateResultsRequestor intRequestor, IProgressListener progressListener,
                        IOutputClassFileNameProvider outputFileNameProvider, IBinarySourceProvider binarySourceProvider,
                        Map fullBinarySourceEntries, /* fileName |-> List<UnwovenClassFile> */
-                       boolean isXterminateAfterCompilation, boolean proceedOnError, boolean noAtAspectJProcessing,
-                       boolean reflectable,
+                       boolean isXterminateAfterCompilation, boolean proceedOnError, boolean noAtAspectJProcessing, boolean reflectable,
                        AjState incrementalCompilationState) {
                this.compiler = compiler;
                this.isBatchCompile = isBatchCompile;
@@ -99,13 +98,14 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
                this.proceedOnError = proceedOnError;
                this.binarySourceSetForFullWeave = fullBinarySourceEntries;
                this.eWorld = eFactory;
-               this.reflectable= reflectable;
+               this.reflectable = reflectable;
                this.inJava5Mode = false;
                this.noAtAspectJAnnotationProcessing = noAtAspectJProcessing;
                this.incrementalCompilationState = incrementalCompilationState;
 
-               if (compiler.options.complianceLevel >= ClassFileConstants.JDK1_5)
+               if (compiler.options.complianceLevel >= ClassFileConstants.JDK1_5) {
                        inJava5Mode = true;
+               }
 
                IMessageHandler msgHandler = world.getMessageHandler();
                // Do we need to reset the message handler or create a new one? (This saves a ton of memory lost on incremental compiles...)
@@ -132,7 +132,7 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
                if (inJava5Mode && !noAtAspectJAnnotationProcessing) {
                        ContextToken tok = CompilationAndWeavingContext.enteringPhase(
                                        CompilationAndWeavingContext.ADDING_AT_ASPECTJ_ANNOTATIONS, unit.getFileName());
-                       AddAtAspectJAnnotationsVisitor atAspectJVisitor = new AddAtAspectJAnnotationsVisitor(unit,reflectable);
+                       AddAtAspectJAnnotationsVisitor atAspectJVisitor = new AddAtAspectJAnnotationsVisitor(unit, reflectable);
                        unit.traverse(atAspectJVisitor, unit.scope);
                        CompilationAndWeavingContext.leavingPhase(tok);
                }
@@ -144,8 +144,9 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
        }
 
        public void afterResolving(CompilationUnitDeclaration unit) {
-               if (resolvingToken != null)
+               if (resolvingToken != null) {
                        CompilationAndWeavingContext.leavingPhase(resolvingToken);
+               }
        }
 
        public void beforeAnalysing(CompilationUnitDeclaration unit) {
@@ -158,8 +159,9 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
        }
 
        public void afterAnalysing(CompilationUnitDeclaration unit) {
-               if (analysingToken != null)
+               if (analysingToken != null) {
                        CompilationAndWeavingContext.leavingPhase(analysingToken);
+               }
        }
 
        public void beforeGenerating(CompilationUnitDeclaration unit) {
@@ -168,8 +170,9 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
        }
 
        public void afterGenerating(CompilationUnitDeclaration unit) {
-               if (generatingToken != null)
+               if (generatingToken != null) {
                        CompilationAndWeavingContext.leavingPhase(generatingToken);
+               }
        }
 
        public void afterCompiling(CompilationUnitDeclaration[] units) {
@@ -195,8 +198,9 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
                        AbortCompilation ac = new AbortCompilation(null, ex);
                        throw ac;
                } catch (RuntimeException rEx) {
-                       if (rEx instanceof AbortCompilation)
+                       if (rEx instanceof AbortCompilation) {
                                throw rEx; // Don't wrap AbortCompilation exceptions!
+                       }
 
                        // This will be unwrapped in Compiler.handleInternalException() and the nested
                        // RuntimeException thrown back to the original caller - which is AspectJ
@@ -209,8 +213,9 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
                CompilationAndWeavingContext.leavingPhase(processingToken);
                eWorld.finishedCompilationUnit(unit);
                InterimCompilationResult intRes = new InterimCompilationResult(unit.compilationResult, outputFileNameProvider);
-               if (unit.compilationResult.hasErrors())
+               if (unit.compilationResult.hasErrors()) {
                        reportedErrors = true;
+               }
 
                if (intermediateResultsRequestor != null) {
                        intermediateResultsRequestor.acceptResult(intRes);
@@ -292,7 +297,7 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
                for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) {
                        InterimCompilationResult iresult = (InterimCompilationResult) iter.next();
                        for (int i = 0; i < iresult.unwovenClassFiles().length; i++) {
-                               weaver.addClassFile(iresult.unwovenClassFiles()[i],false);
+                               weaver.addClassFile(iresult.unwovenClassFiles()[i], false);
                        }
                }
 
@@ -326,8 +331,9 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter {
                        weaver.allWeavingComplete();
                        weaver.tidyUp();
                        IMessageHandler imh = weaver.getWorld().getMessageHandler();
-                       if (imh instanceof WeaverMessageHandler)
+                       if (imh instanceof WeaverMessageHandler) {
                                ((WeaverMessageHandler) imh).resetCompiler(null);
+                       }
                }
        }
 
index 29fcf45bc07e445b01a9268ed186e21682aa6cda..00f7f8d8c7da1e3edc42c3d3d9da04d425f3b4a3 100644 (file)
@@ -20,6 +20,9 @@ import java.util.Map;
 
 import org.aspectj.ajdt.internal.compiler.ast.AddAtAspectJAnnotationsVisitor;
 import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeConstructorDeclaration;
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration;
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeMethodDeclaration;
 import org.aspectj.ajdt.internal.compiler.ast.ValidateAtAspectJAnnotationsVisitor;
 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
 import org.aspectj.ajdt.internal.core.builder.AjState;
@@ -31,6 +34,7 @@ import org.aspectj.bridge.context.CompilationAndWeavingContext;
 import org.aspectj.bridge.context.ContextToken;
 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.aspectj.org.eclipse.jdt.internal.compiler.Compiler;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
@@ -39,6 +43,7 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.aspectj.weaver.bcel.BcelWeaver;
 import org.aspectj.weaver.bcel.BcelWorld;
+import org.aspectj.weaver.bcel.UnwovenClassFile;
 
 /**
  * Adapts standard JDT Compiler to add in AspectJ specific behaviours. This version implements pipelining - where files are compiled
@@ -103,7 +108,7 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
        private IOutputClassFileNameProvider outputFileNameProvider;
        private IBinarySourceProvider binarySourceProvider;
        private WeaverMessageHandler weaverMessageHandler;
-       private Map /* fileName > List<UnwovenClassFile> */binarySourceSetForFullWeave = new HashMap();
+       private Map<String, List<UnwovenClassFile>> binarySourceSetForFullWeave = new HashMap<String, List<UnwovenClassFile>>();
 
        private ContextToken processingToken = null;
        private ContextToken resolvingToken = null;
@@ -113,7 +118,7 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
        private AjState incrementalCompilationState;
 
        // Maintains a list of whats weaving - whilst the pipeline is stalled, this accumulates aspects.
-       List /* InterimResult */resultsPendingWeave = new ArrayList();
+       List<InterimCompilationResult> resultsPendingWeave = new ArrayList<InterimCompilationResult>();
 
        // pipelining info
        private boolean pipelineStalled = true;
@@ -195,8 +200,8 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
                }
 
                // Break the units into two lists...
-               List aspects = new ArrayList();
-               List nonaspects = new ArrayList();
+               List<CompilationUnitDeclaration> aspects = new ArrayList<CompilationUnitDeclaration>();
+               List<CompilationUnitDeclaration> nonaspects = new ArrayList<CompilationUnitDeclaration>();
                for (int i = 0; i < units.length; i++) {
                        if (containsAnAspect(units[i])) {
                                aspects.add(units[i]);
@@ -207,11 +212,11 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
 
                // ...and put them back together, aspects first
                int posn = 0;
-               for (Iterator iter = aspects.iterator(); iter.hasNext();) {
-                       units[posn++] = (CompilationUnitDeclaration) iter.next();
+               for (CompilationUnitDeclaration aspect : aspects) {
+                       units[posn++] = aspect;
                }
-               for (Iterator iter = nonaspects.iterator(); iter.hasNext();) {
-                       units[posn++] = (CompilationUnitDeclaration) iter.next();
+               for (CompilationUnitDeclaration nonaspect : nonaspects) {
+                       units[posn++] = nonaspect;
                }
 
                // Work out how long to stall the pipeline
@@ -250,7 +255,7 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
        }
 
        public void beforeCompiling(ICompilationUnit[] sourceUnits) {
-               resultsPendingWeave = new ArrayList();
+               resultsPendingWeave = new ArrayList<InterimCompilationResult>();
                reportedErrors = false;
                droppingBackToFullBuild = false;
        }
@@ -265,7 +270,7 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
                if (inJava5Mode && !noAtAspectJAnnotationProcessing) {
                        ContextToken tok = CompilationAndWeavingContext.enteringPhase(
                                        CompilationAndWeavingContext.ADDING_AT_ASPECTJ_ANNOTATIONS, unit.getFileName());
-                       AddAtAspectJAnnotationsVisitor atAspectJVisitor = new AddAtAspectJAnnotationsVisitor(unit,makeReflectable);
+                       AddAtAspectJAnnotationsVisitor atAspectJVisitor = new AddAtAspectJAnnotationsVisitor(unit, makeReflectable);
                        unit.traverse(atAspectJVisitor, unit.scope);
                        CompilationAndWeavingContext.leavingPhase(tok);
                }
@@ -300,12 +305,64 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
        public void beforeGenerating(CompilationUnitDeclaration unit) {
                generatingToken = CompilationAndWeavingContext.enteringPhase(
                                CompilationAndWeavingContext.GENERATING_UNWOVEN_CODE_FOR_COMPILATION_UNIT, unit.getFileName());
+               if (eWorld.pushinCollector != null) {
+                       if (unit.types != null && unit.types.length > 0) {
+                               for (int t = 0; t < unit.types.length; t++) {
+                                       TypeDeclaration type = unit.types[t];
+                                       if (type.methods != null) {
+                                               for (int m = 0; m < type.methods.length; m++) {
+                                                       AbstractMethodDeclaration md = type.methods[m];
+                                                       if (md instanceof InterTypeMethodDeclaration) {
+                                                               InterTypeMethodDeclaration itmd = ((InterTypeMethodDeclaration) md);
+                                                               ITDMethodPrinter printer = new ITDMethodPrinter(itmd, md.scope);
+                                                               String s = printer.print();
+                                                               eWorld.pushinCollector.recordInterTypeMethodDeclarationCode(md, s, getDeclarationLineNumber(md));
+                                                       } else if (md instanceof InterTypeFieldDeclaration) {
+                                                               ITDFieldPrinter printer = new ITDFieldPrinter(((InterTypeFieldDeclaration) md), md.scope);
+                                                               String s = printer.print();
+                                                               eWorld.pushinCollector.recordInterTypeFieldDeclarationCode(md, s, getDeclarationLineNumber(md));
+                                                       } else if (md instanceof InterTypeConstructorDeclaration) {
+                                                               ITDConstructorPrinter printer = new ITDConstructorPrinter(((InterTypeConstructorDeclaration) md),
+                                                                               md.scope);
+                                                               String s = printer.print();
+                                                               eWorld.pushinCollector.recordInterTypeConstructorDeclarationCode(md, s,
+                                                                               getDeclarationLineNumber(md));
+                                                               // } else if (md instanceof DeclareAnnotationDeclaration) {
+                                                               // DeclareAnnotationDeclaration dad = (DeclareAnnotationDeclaration) md;
+                                                               // String value = new DeclareAnnotationsPrinter(dad, dad.scope).print();
+                                                               // eWorld.pushinCollector.recordDeclareAnnotationDeclarationCode(md, value);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       eWorld.pushinCollector.setOutputFileNameProvider(outputFileNameProvider);
+               }
+       }
+
+       /**
+        * @return the line number for this declaration in the source code
+        */
+       private int getDeclarationLineNumber(AbstractMethodDeclaration md) {
+               int sourceStart = md.sourceStart;
+               int[] separators = md.compilationResult.lineSeparatorPositions;
+               int declarationStartLine = 1;
+               for (int i = 0; i < separators.length; i++) {
+                       if (sourceStart < separators[i]) {
+                               break;
+                       }
+                       declarationStartLine++;
+               }
+               return declarationStartLine;
        }
 
        public void afterGenerating(CompilationUnitDeclaration unit) {
                if (generatingToken != null) {
                        CompilationAndWeavingContext.leavingPhase(generatingToken);
                }
+               if (eWorld.pushinCollector != null) {
+                       eWorld.pushinCollector.dump(unit);
+               }
        }
 
        public void afterCompiling(CompilationUnitDeclaration[] units) {
@@ -416,12 +473,12 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
        // helper methods...
        // ==================================================================================
 
-       private List getBinarySourcesFrom(Map binarySourceEntries) {
+       private List<InterimCompilationResult> getBinarySourcesFrom(Map<String, List<UnwovenClassFile>> binarySourceEntries) {
                // Map is fileName |-> List<UnwovenClassFile>
-               List ret = new ArrayList();
-               for (Iterator binIter = binarySourceEntries.keySet().iterator(); binIter.hasNext();) {
-                       String sourceFileName = (String) binIter.next();
-                       List unwovenClassFiles = (List) binarySourceEntries.get(sourceFileName);
+               List<InterimCompilationResult> ret = new ArrayList<InterimCompilationResult>();
+               for (Iterator<String> binIter = binarySourceEntries.keySet().iterator(); binIter.hasNext();) {
+                       String sourceFileName = binIter.next();
+                       List<UnwovenClassFile> unwovenClassFiles = binarySourceEntries.get(sourceFileName);
                        // XXX - see bugs 57432,58679 - final parameter on next call should be "compiler.options.maxProblemsPerUnit"
                        CompilationResult result = new CompilationResult(sourceFileName.toCharArray(), 0, 0, Integer.MAX_VALUE);
                        result.noSourceAvailable();
@@ -610,7 +667,7 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
         * SECRET: FOR TESTING - this can be used to collect information that tests can verify.
         */
        public static boolean pipelineTesting = false;
-       public static Hashtable pipelineOutput = null;
+       public static Hashtable<String, String> pipelineOutput = null;
 
        // Keys into pipelineOutput:
        // compileOrder "[XXX,YYY]" a list of the order in which files will be woven (aspects should be first)
@@ -621,12 +678,12 @@ public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
                if (pipelineOutput == null) {
                        return "";
                }
-               return (String) pipelineOutput.get(key);
+               return pipelineOutput.get(key);
        }
 
        private final static boolean debugPipeline = false;
 
-       public List getResultsPendingWeave() {
+       public List<InterimCompilationResult> getResultsPendingWeave() {
                return resultsPendingWeave;
        }
 
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/CommonPrinter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/CommonPrinter.java
new file mode 100644 (file)
index 0000000..cfdc9da
--- /dev/null
@@ -0,0 +1,1227 @@
+/* *******************************************************************
+ * Copyright (c) 2010 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://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import org.aspectj.asm.internal.CharOperation;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AssertStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Assignment;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Block;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.BreakStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CaseStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CastExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CharLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.DoubleLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FloatLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ForStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.IfStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.IntLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.LongLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NullLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.PostfixExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.PrefixExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ThisReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TryStatement;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.UnaryExpression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedFieldBinding;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+
+public class CommonPrinter {
+
+       StringBuilder output;
+       private int tab = 0;
+       MethodScope mscope;
+       AbstractMethodDeclaration declaration;
+       protected int expressionLevel = 0;
+
+       public CommonPrinter(MethodScope mscope) {
+               output = new StringBuilder();
+               this.mscope = mscope;
+       }
+
+       protected StringBuilder printTypeReference(TypeReference tr) {
+               if (tr instanceof Wildcard) {
+                       Wildcard w = (Wildcard) tr;
+                       output.append('?');
+                       if (w.bound != null) {
+                               if (w.kind == Wildcard.EXTENDS) {
+                                       output.append(" extends ");
+                               } else if (w.kind == Wildcard.SUPER) {
+                                       output.append(" super ");
+                               }
+                               printTypeReference(w.bound);
+                       }
+                       return output;
+               } else if (tr instanceof ParameterizedSingleTypeReference) {
+                       ParameterizedSingleTypeReference pstr = (ParameterizedSingleTypeReference) tr;
+                       ReferenceBinding tb = (ReferenceBinding) mscope.getType(pstr.token);
+                       output.append(CharOperation.concatWith(tb.compoundName, '.'));
+                       output.append('<');
+                       TypeReference[] typeArguments = pstr.typeArguments;
+                       for (int i = 0; i < typeArguments.length; i++) {
+                               if (i > 0) {
+                                       output.append(',');
+                               }
+                               printTypeReference(typeArguments[i]);
+                       }
+                       output.append('>');
+                       for (int i = 0; i < pstr.dimensions; i++) {
+                               output.append("[]"); //$NON-NLS-1$
+                       }
+                       return output;
+               } else if (tr instanceof ParameterizedQualifiedTypeReference) {
+                       ParameterizedQualifiedTypeReference pqtr = (ParameterizedQualifiedTypeReference) tr;
+                       output.append(CharOperation.concatWith(pqtr.tokens, '.'));
+                       output.append('<');
+                       TypeReference[][] typeArguments = pqtr.typeArguments;
+                       // TODO don't support parameterized interim name components
+                       TypeReference[] ofInterest = typeArguments[typeArguments.length - 1];
+                       for (int i = 0; i < ofInterest.length; i++) {
+                               if (i > 0) {
+                                       output.append(',');
+                               }
+                               printTypeReference(ofInterest[i]);
+                       }
+                       output.append('>');
+                       for (int i = 0; i < pqtr.dimensions(); i++) {
+                               output.append("[]"); //$NON-NLS-1$
+                       }
+                       return output;
+               } else if (tr instanceof SingleTypeReference) {
+                       SingleTypeReference str = (SingleTypeReference) tr;
+                       TypeBinding tb = mscope.getType(str.token);
+                       output.append(tb.debugName()); // fq name
+                       for (int i = 0; i < str.dimensions(); i++) {
+                               output.append("[]"); //$NON-NLS-1$
+                       }
+                       return output;
+               } else if (tr instanceof QualifiedTypeReference) {
+                       QualifiedTypeReference qtr = (QualifiedTypeReference) tr;
+                       output.append(CharOperation.concatWith(qtr.tokens, '.'));
+                       for (int i = 0; i < qtr.dimensions(); i++) {
+                               output.append("[]"); //$NON-NLS-1$
+                       }
+                       return output;
+               }
+               throwit(tr);
+               return output;
+       }
+
+       protected StringBuilder printMemberValuePair(MemberValuePair mvp) {
+               output.append(mvp.name).append(" = "); //$NON-NLS-1$
+               printExpression(mvp.value);
+               return output;
+       }
+
+       protected StringBuilder printAnnotations(Annotation[] annotations) {
+               int length = annotations.length;
+               for (int i = 0; i < length; i++) {
+                       printAnnotation(annotations[i]);
+                       output.append(" "); //$NON-NLS-1$
+               }
+               return output;
+       }
+
+       public StringBuilder printAnnotation(Annotation annotation) {
+               output.append('@');
+               printExpression(annotation.type);
+               MemberValuePair[] mvps = annotation.memberValuePairs();
+               if (mvps != null && mvps.length > 0) {
+                       output.append('(');
+                       for (int m = 0; m < mvps.length; m++) {
+                               if (m > 0) {
+                                       output.append(',');
+                               }
+                               printMemberValuePair(mvps[m]);
+                       }
+                       output.append(')');
+               }
+               return output;
+       }
+
+       public String toString() {
+               return output.toString();
+       }
+
+       protected StringBuilder printBody(int indent) {
+
+               if (declaration.isAbstract()) { // || (md.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
+                       return output.append(';');
+               }
+
+               output.append(" {"); //$NON-NLS-1$
+               if (declaration.statements != null) {
+                       for (int i = 0; i < declaration.statements.length; i++) {
+                               output.append('\n');
+                               printStatement(declaration.statements[i], indent);
+                       }
+               }
+               output.append('\n');
+               printIndent(indent == 0 ? 0 : indent - 1).append('}');
+               return output;
+       }
+
+       protected StringBuilder printBody(AbstractMethodDeclaration amd, int indent) {
+
+               if (amd.isAbstract()) { // || (md.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
+                       return output.append(';');
+               }
+
+               output.append(" {"); //$NON-NLS-1$
+               if (amd.statements != null) {
+                       for (int i = 0; i < amd.statements.length; i++) {
+                               output.append('\n');
+                               printStatement(amd.statements[i], indent);
+                       }
+               }
+               output.append('\n');
+               printIndent(indent == 0 ? 0 : indent - 1).append('}');
+               return output;
+       }
+
+       protected StringBuilder printArgument(Argument argument) {
+               // printIndent(indent, output);
+               printModifiers(argument.modifiers);
+               if (argument.annotations != null) {
+                       printAnnotations(argument.annotations);
+               }
+               printTypeReference(argument.type).append(' ');
+               return output.append(argument.name);
+       }
+
+       void throwit(Object o) {
+               if (true) {
+                       System.out.println("so far:" + output.toString());
+                       throw new IllegalStateException(o == null ? "" : o.getClass().getName() + ":" + o);
+               }
+       }
+
+       void throwit() {
+               if (true) {
+                       throw new IllegalStateException();
+               }
+       }
+
+       public StringBuilder printIndent(int indent) {
+               for (int i = indent; i > 0; i--) {
+                       output.append("  "); //$NON-NLS-1$
+               }
+               return output;
+       }
+
+       public StringBuilder printModifiers(int modifiers) {
+
+               if ((modifiers & ClassFileConstants.AccPublic) != 0) {
+                       output.append("public "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccPrivate) != 0) {
+                       output.append("private "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccProtected) != 0) {
+                       output.append("protected "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccStatic) != 0) {
+                       output.append("static "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccFinal) != 0) {
+                       output.append("final "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccSynchronized) != 0) {
+                       output.append("synchronized "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccVolatile) != 0) {
+                       output.append("volatile "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccTransient) != 0) {
+                       output.append("transient "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccNative) != 0) {
+                       output.append("native "); //$NON-NLS-1$
+               }
+               if ((modifiers & ClassFileConstants.AccAbstract) != 0) {
+                       output.append("abstract "); //$NON-NLS-1$
+               }
+               return output;
+       }
+
+       public StringBuilder printExpression(Expression e) {
+               // TODO other literals
+               try {
+                       expressionLevel++;
+                       if (e instanceof TypeReference) {
+                               return printTypeReference((TypeReference) e);
+                       } else if (e instanceof IntLiteral) {
+                               return output.append(((IntLiteral) e).value);
+                       } else if (e instanceof CharLiteral) {
+                               return output.append(((CharLiteral) e).source());
+                       } else if (e instanceof DoubleLiteral) {
+                               return output.append(((DoubleLiteral) e).source());
+                       } else if (e instanceof LongLiteral) {
+                               return output.append(((LongLiteral) e).source());
+                       } else if (e instanceof FloatLiteral) {
+                               return output.append(((FloatLiteral) e).source());
+                       } else if (e instanceof TrueLiteral) {
+                               return output.append(((TrueLiteral) e).source());
+                       } else if (e instanceof FalseLiteral) {
+                               return output.append(((FalseLiteral) e).source());
+                       } else if (e instanceof ClassLiteralAccess) {
+                               printTypeReference(((ClassLiteralAccess) e).type);
+                               return output.append(".class");
+                       } else if (e instanceof StringLiteral) {
+                               return printStringLiteral((StringLiteral) e);
+                       } else if (e instanceof SingleNameReference) {
+                               SingleNameReference snr = (SingleNameReference) e;
+                               if (snr.binding instanceof ReferenceBinding) {
+                                       output.append(CharOperation.concatWith(((ReferenceBinding) snr.binding).compoundName, '.'));
+                               } else if (snr.binding instanceof ParameterizedFieldBinding) {
+                                       ParameterizedFieldBinding pfb = (ParameterizedFieldBinding) snr.binding;
+                                       output.append(pfb.name);
+                               } else if (snr.binding instanceof LocalVariableBinding) {
+                                       LocalVariableBinding lvb = (LocalVariableBinding) snr.binding;
+                                       output.append(lvb.name);
+                               } else if (snr.binding instanceof FieldBinding) {
+                                       FieldBinding fb = (FieldBinding) snr.binding;
+                                       ReferenceBinding rb = fb.declaringClass;
+                                       if (fb.isStatic()) {
+                                               // qualify it
+                                               output.append(CharOperation.concatWith(rb.compoundName, '.'));
+                                               output.append('.');
+                                               output.append(fb.name);
+                                       } else {
+                                               output.append(snr.token);
+                                       }
+                                       int stop = 1;
+                               } else {
+                                       throwit(snr.binding);
+                               }
+                               return output;
+                       } else if (e instanceof QualifiedNameReference) {
+                               QualifiedNameReference qnr = (QualifiedNameReference) e;
+                               if (qnr.binding instanceof FieldBinding) {
+                                       FieldBinding fb = (FieldBinding) qnr.binding;
+                                       ReferenceBinding rb = fb.declaringClass;
+                                       if (fb.isStatic()) {
+                                               output.append(CharOperation.concatWith(rb.compoundName, '.'));
+                                               output.append('.');
+                                               output.append(fb.name);
+                                       } else {
+                                               output.append(CharOperation.concatWith(qnr.tokens, '.'));// ((ReferenceBinding) qnr.binding).compoundName,
+                                       }
+                               } else if (qnr.binding instanceof ReferenceBinding) {
+                                       output.append(CharOperation.concatWith(qnr.tokens, '.'));// ((ReferenceBinding) qnr.binding).compoundName,
+                                       // '.'));
+                               } else if (qnr.binding instanceof LocalVariableBinding) {
+                                       output.append(CharOperation.concatWith(qnr.tokens, '.'));// oncatWith(((LocalVariableBinding)
+                                       // qnr.binding).compoundName, '.'));
+                                       // LocalVariableBinding lvb = (LocalVariableBinding) qnr.binding;
+                                       // output.append(lvb.name);
+                               } else {
+                                       throwit(qnr.binding);
+                               }
+                               // output.append(qnr.actualReceiverType.debugName());
+                               // output.append('.');
+                               // output.append(qnr.tokens[qnr.tokens.length - 1]);
+                               return output;
+                       } else if (e instanceof ArrayReference) {
+                               ArrayReference ar = (ArrayReference) e;
+                               printExpression(ar.receiver).append('[');
+                               return printExpression(ar.position).append(']');
+                       } else if (e instanceof MessageSend) {
+                               return printMessageSendStatement((MessageSend) e);
+                       } else if (e instanceof ThisReference) {
+                               ThisReference tr = (ThisReference) e;
+                               if (tr.isImplicitThis()) {
+                                       return output;
+                               }
+                               return output.append("this"); //$NON-NLS-1$
+                       } else if (e instanceof CastExpression) {
+                               return printCastExpression((CastExpression) e);
+                       } else if (e instanceof BinaryExpression) {
+                               if (expressionLevel != 0) {
+                                       output.append('(');
+                               }
+                               expressionLevel++;
+                               BinaryExpression be = (BinaryExpression) e;
+                               printExpression(be.left).append(' ').append(be.operatorToString()).append(' ');
+                               printExpression(be.right);
+                               expressionLevel--;
+                               if (expressionLevel != 0) {
+                                       output.append(')');
+                               }
+                               return output;
+                       } else if (e instanceof NullLiteral) {
+                               return output.append("null");
+                       } else if (e instanceof QualifiedAllocationExpression) {
+                               return printQualifiedAllocationExpression((QualifiedAllocationExpression) e, 0);
+                       } else if (e instanceof AllocationExpression) {
+                               return printAllocationExpression((AllocationExpression) e);
+                       } else if (e instanceof ArrayInitializer) {
+                               return printArrayInitialized((ArrayInitializer) e);
+                       } else if (e instanceof FieldReference) {
+                               return printFieldReference((FieldReference) e);
+                       } else if (e instanceof UnaryExpression) {
+                               return printUnaryExpression((UnaryExpression) e);
+                       } else if (e instanceof InstanceOfExpression) {
+                               return printInstanceOfExpression((InstanceOfExpression) e);
+                       } else if (e instanceof Assignment) {
+                               return printAssignment((Assignment) e, false);
+                       } else if (e instanceof ArrayAllocationExpression) {
+                               return printArrayAllocationExpression((ArrayAllocationExpression) e);
+                       } else if (e instanceof ConditionalExpression) {
+                               return printConditionalExpression((ConditionalExpression) e);
+                       }
+                       throwit(e);
+                       return output;
+               } finally {
+                       expressionLevel--;
+               }
+       }
+
+       private StringBuilder printConditionalExpression(ConditionalExpression e) {
+               if (expressionLevel != 0) {
+                       output.append('(');
+               }
+               expressionLevel++;
+               printExpression(e.condition).append(" ? ");
+               printExpression(e.valueIfTrue).append(" : ");
+               printExpression(e.valueIfFalse);
+               expressionLevel--;
+               if (expressionLevel != 0) {
+                       output.append(')');
+               }
+               return output;
+       }
+
+       private StringBuilder printArrayAllocationExpression(ArrayAllocationExpression aae) {
+               output.append("new "); //$NON-NLS-1$
+               printTypeReference(aae.type);
+               for (int i = 0; i < aae.dimensions.length; i++) {
+                       if (aae.dimensions[i] == null) {
+                               output.append("[]"); //$NON-NLS-1$
+                       } else {
+                               output.append('[');
+                               printExpression(aae.dimensions[i]);
+                               output.append(']');
+                       }
+               }
+               if (aae.initializer != null) {
+                       printExpression(aae.initializer);
+               }
+               return output;
+       }
+
+       private StringBuilder printInstanceOfExpression(InstanceOfExpression e) {
+               if (expressionLevel != 0) {
+                       output.append('(');
+               }
+               expressionLevel++;
+               printExpression(e.expression).append(" instanceof "); //$NON-NLS-1$
+               printTypeReference(e.type);
+               expressionLevel--;
+               if (expressionLevel != 0) {
+                       output.append(')');
+               }
+               return output;
+       }
+
+       private StringBuilder printUnaryExpression(UnaryExpression e) {
+               if (expressionLevel != 0) {
+                       output.append('(');
+               }
+               expressionLevel++;
+               output.append(e.operatorToString()).append(' ');
+               printExpression(e.expression);
+               expressionLevel--;
+               if (expressionLevel != 0) {
+                       output.append(')');
+               }
+               return output;
+       }
+
+       private StringBuilder printFieldReference(FieldReference fr) {
+               printExpression(fr.receiver).append('.').append(fr.token);
+               return output;
+       }
+
+       private StringBuilder printArrayInitialized(ArrayInitializer e) {
+
+               output.append('{');
+               if (e.expressions != null) {
+                       // int j = 20;
+                       for (int i = 0; i < e.expressions.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printExpression(e.expressions[i]);
+                               // expressions[i].printExpression(0, output);
+                               // j--;
+                               // if (j == 0) {
+                               // output.append('\n');
+                               // printIndent(indent + 1, output);
+                               // j = 20;
+                               // }
+                       }
+               }
+               return output.append('}');
+       }
+
+       private StringBuilder printCastExpression(CastExpression e) {
+               output.append('(');
+               output.append('(');
+               printExpression(e.type).append(") "); //$NON-NLS-1$
+               printExpression(e.expression);
+               output.append(')');
+               return output;
+       }
+
+       private StringBuilder printStringLiteral(StringLiteral e) {
+               output.append('\"');
+               for (int i = 0; i < e.source().length; i++) {
+                       switch (e.source()[i]) {
+                       case '\b':
+                               output.append("\\b"); //$NON-NLS-1$
+                               break;
+                       case '\t':
+                               output.append("\\t"); //$NON-NLS-1$
+                               break;
+                       case '\n':
+                               output.append("\\n"); //$NON-NLS-1$
+                               break;
+                       case '\f':
+                               output.append("\\f"); //$NON-NLS-1$
+                               break;
+                       case '\r':
+                               output.append("\\r"); //$NON-NLS-1$
+                               break;
+                       case '\"':
+                               output.append("\\\""); //$NON-NLS-1$
+                               break;
+                       case '\'':
+                               output.append("\\'"); //$NON-NLS-1$
+                               break;
+                       case '\\': // take care not to display the escape as a potential real char
+                               output.append("\\\\"); //$NON-NLS-1$
+                               break;
+                       default:
+                               output.append(e.source()[i]);
+                       }
+               }
+               output.append('\"');
+               return output;
+       }
+
+       public StringBuilder printExpression(SingleTypeReference str) {
+               output.append(str.token);
+               return output;
+       }
+
+       protected StringBuilder printStatement(Statement statement, int indent) {
+               return printStatement(statement, indent, true);
+       }
+
+       protected StringBuilder printStatement(Statement statement, int indent, boolean applyIndent) {
+               if (statement instanceof ReturnStatement) {
+                       printIndent(indent).append("return "); //$NON-NLS-1$
+                       if (((ReturnStatement) statement).expression != null) {
+                               printExpression(((ReturnStatement) statement).expression);
+                       }
+                       return output.append(';');
+               } else if (statement instanceof PostfixExpression) {
+                       return printPostfixExpression((PostfixExpression) statement);
+               } else if (statement instanceof PrefixExpression) {
+                       return printPrefixExpression((PrefixExpression) statement);
+               } else if (statement instanceof MessageSend) {
+                       printIndent(indent);
+                       MessageSend ms = (MessageSend) statement;
+                       printMessageSendStatement(ms);
+                       return output.append(';');
+               } else if (statement instanceof QualifiedAllocationExpression) {
+                       printIndent(indent);
+                       printQualifiedAllocationExpression((QualifiedAllocationExpression) statement, indent);
+                       return output.append(';');
+               } else if (statement instanceof Assignment) {
+                       printIndent(indent);
+                       printAssignment((Assignment) statement);
+                       return output.append(';');
+               } else if (statement instanceof TryStatement) {
+                       printTryStatement((TryStatement) statement, indent);
+                       return output;
+               } else if (statement instanceof IfStatement) {
+                       printIndent(indent);
+                       IfStatement is = (IfStatement) statement;
+                       printIndent(indent).append("if ("); //$NON-NLS-1$
+                       printExpression(is.condition).append(")\n"); //$NON-NLS-1$ 
+                       printStatement(is.thenStatement, indent + 2);
+                       if (is.elseStatement != null) {
+                               output.append('\n');
+                               printIndent(indent);
+                               output.append("else\n"); //$NON-NLS-1$
+                               printStatement(is.elseStatement, indent + 2);
+                       }
+                       return output;
+               } else if (statement instanceof Block) {
+                       printBlock((Block) statement, indent, applyIndent);
+                       return output;
+               } else if (statement instanceof LocalDeclaration) {
+                       return printLocalDeclaration((LocalDeclaration) statement, indent);
+               } else if (statement instanceof SwitchStatement) {
+                       return printSwitchStatement((SwitchStatement) statement, indent);
+               } else if (statement instanceof CaseStatement) {
+                       return printCaseStatement((CaseStatement) statement, indent);
+               } else if (statement instanceof BreakStatement) {
+                       return printBreakStatement((BreakStatement) statement, indent);
+               } else if (statement instanceof ThrowStatement) {
+                       return printThrowStatement((ThrowStatement) statement, indent);
+               } else if (statement instanceof TypeDeclaration) {
+                       return printTypeDeclaration((TypeDeclaration) statement, indent, false).append(';');
+               } else if (statement instanceof AssertStatement) {
+                       return printAssertStatement((AssertStatement) statement, indent);
+               } else if (statement instanceof ForStatement) {
+                       return printForStatement((ForStatement) statement, indent);
+               } else if (statement instanceof ForeachStatement) {
+                       return printForeachStatement((ForeachStatement) statement, indent);
+               }
+               System.err.println(statement);
+               System.err.println(statement.getClass().getName());
+               throwit(statement);
+
+               return output;
+       }
+
+       private StringBuilder printPostfixExpression(PostfixExpression pe) {
+               printExpression(pe.lhs);
+               output.append(' ');
+               output.append(pe.operatorToString());
+               return output;
+       }
+
+       private StringBuilder printPrefixExpression(PrefixExpression pe) {
+               output.append(pe.operatorToString());
+               output.append(' ');
+               printExpression(pe.lhs);
+               return output;
+       }
+
+       public StringBuilder printAsExpression(LocalDeclaration ld, int indent) {
+               // printIndent(indent);
+               printModifiers(ld.modifiers);
+               if (ld.annotations != null) {
+                       printAnnotations(ld.annotations);
+               }
+
+               if (ld.type != null) {
+                       printTypeReference(ld.type).append(' ');
+               }
+               output.append(ld.name);
+               switch (ld.getKind()) {
+               case AbstractVariableDeclaration.ENUM_CONSTANT:
+                       if (ld.initialization != null) {
+                               printExpression(ld.initialization);
+                       }
+                       break;
+               default:
+                       if (ld.initialization != null) {
+                               output.append(" = "); //$NON-NLS-1$
+                               printExpression(ld.initialization);
+                       }
+               }
+               return output;
+       }
+
+       private StringBuilder printForeachStatement(ForeachStatement statement, int indent) {
+               printIndent(indent).append("for ("); //$NON-NLS-1$
+               printAsExpression(statement.elementVariable, indent);
+               output.append(" : ");//$NON-NLS-1$
+               printExpression(statement.collection).append(") "); //$NON-NLS-1$
+               // block
+               if (statement.action == null) {
+                       output.append(';');
+               } else {
+                       printStatement(statement.action, indent + 1);
+               }
+               return output;
+       }
+
+       private StringBuilder printForStatement(ForStatement fs, int indent) {
+               printIndent(indent).append("for ("); //$NON-NLS-1$
+
+               // inits
+               if (fs.initializations != null) {
+                       for (int i = 0; i < fs.initializations.length; i++) {
+                               // nice only with expressions
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printStatement(fs.initializations[i], 0);
+                       }
+               }
+               if (!output.toString().endsWith(";")) {
+                       output.append("; "); //$NON-NLS-1$
+               }
+               // cond
+               if (fs.condition != null) {
+                       printExpression(fs.condition);
+               }
+               output.append("; "); //$NON-NLS-1$
+               // updates
+               if (fs.increments != null) {
+                       for (int i = 0; i < fs.increments.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printStatement(fs.increments[i], 0);
+                       }
+               }
+               output.append(") "); //$NON-NLS-1$
+               // block
+               if (fs.action == null) {
+                       output.append(';');
+               } else {
+                       // output.append('\n');
+                       printStatement(fs.action, indent + 1, false);
+               }
+               return output;
+       }
+
+       private StringBuilder printAssertStatement(AssertStatement as, int indent) {
+               printIndent(indent);
+               output.append("assert "); //$NON-NLS-1$
+               printExpression(as.assertExpression);
+               if (as.exceptionArgument != null) {
+                       output.append(": "); //$NON-NLS-1$
+                       printExpression(as.exceptionArgument);
+               }
+               return output.append(';');
+       }
+
+       private StringBuilder printThrowStatement(ThrowStatement ts, int indent) {
+               printIndent(indent).append("throw "); //$NON-NLS-1$
+               printExpression(ts.exception);
+               return output.append(';');
+       }
+
+       private StringBuilder printBreakStatement(BreakStatement statement, int indent) {
+               printIndent(indent).append("break "); //$NON-NLS-1$
+               if (statement.label != null) {
+                       output.append(statement.label);
+               }
+               return output.append(';');
+       }
+
+       private StringBuilder printCaseStatement(CaseStatement statement, int indent) {
+               printIndent(indent);
+               if (statement.constantExpression == null) {
+                       output.append("default : "); //$NON-NLS-1$
+               } else {
+                       output.append("case "); //$NON-NLS-1$
+                       printExpression(statement.constantExpression).append(" : "); //$NON-NLS-1$
+               }
+               return output;// output.append(';');
+       }
+
+       private StringBuilder printSwitchStatement(SwitchStatement statement, int indent) {
+               printIndent(indent).append("switch ("); //$NON-NLS-1$
+               printExpression(statement.expression).append(") {"); //$NON-NLS-1$
+               if (statement.statements != null) {
+                       for (int i = 0; i < statement.statements.length; i++) {
+                               output.append('\n');
+                               if (statement.statements[i] instanceof CaseStatement) {
+                                       printStatement(statement.statements[i], indent);
+                               } else {
+                                       printStatement(statement.statements[i], indent + 2);
+                               }
+                       }
+               }
+               output.append("\n"); //$NON-NLS-1$
+               return printIndent(indent).append('}');
+       }
+
+       private StringBuilder printLocalDeclaration(LocalDeclaration statement, int indent) {
+               printAbstractVariableDeclarationAsExpression(statement, indent);
+               switch (statement.getKind()) {
+               case AbstractVariableDeclaration.ENUM_CONSTANT:
+                       return output.append(',');
+               default:
+                       return output.append(';');
+               }
+       }
+
+       private StringBuilder printAbstractVariableDeclarationAsExpression(AbstractVariableDeclaration avd, int indent) {
+               printIndent(indent);
+               printModifiers(avd.modifiers);
+               if (avd.annotations != null) {
+                       printAnnotations(avd.annotations);
+               }
+
+               if (avd.type != null) {
+                       printTypeReference(avd.type).append(' ');
+               }
+               output.append(avd.name);
+               switch (avd.getKind()) {
+               case AbstractVariableDeclaration.ENUM_CONSTANT:
+                       if (avd.initialization != null) {
+                               printExpression(avd.initialization);
+                       }
+                       break;
+               default:
+                       if (avd.initialization != null) {
+                               output.append(" = "); //$NON-NLS-1$
+                               printExpression(avd.initialization);
+                       }
+               }
+               return output;
+       }
+
+       private StringBuilder printBlock(Block b, int indent, boolean applyIndent) {
+               if (applyIndent) {
+                       printIndent(indent);
+               }
+               output.append("{\n"); //$NON-NLS-1$
+               printBody(b, indent);
+               printIndent(indent);
+               return output.append('}');
+       }
+
+       public StringBuilder printBody(Block b, int indent) {
+               if (b.statements == null) {
+                       return output;
+               }
+               for (int i = 0; i < b.statements.length; i++) {
+                       printStatement(b.statements[i], indent + 1);
+                       output.append('\n');
+               }
+               return output;
+       }
+
+       private StringBuilder printTryStatement(TryStatement statement, int indent) {
+               printIndent(indent).append("try "); //$NON-NLS-1$
+               printBlock(statement.tryBlock, indent, false);
+               // catches
+               if (statement.catchBlocks != null) {
+                       for (int i = 0; i < statement.catchBlocks.length; i++) {
+                               // output.append('\n');
+                               // printIndent(indent).
+                               output.append(" catch ("); //$NON-NLS-1$
+                               printArgument(statement.catchArguments[i]).append(") "); //$NON-NLS-1$
+                               printBlock(statement.catchBlocks[i], indent, false);
+                               // statement.catchBlocks[i].printStatement(indent + 1, output);
+                       }
+               }
+               // finally
+               if (statement.finallyBlock != null) {
+                       // output.append('\n');
+                       // printIndent(indent).
+                       output.append(" finally "); //$NON-NLS-1$
+                       printBlock(statement.finallyBlock, indent, false);// .printStatement(indent + 1, output);
+               }
+               return output;
+       }
+
+       private StringBuilder printAssignment(Assignment statement) {
+               return printAssignment(statement, expressionLevel != 0);
+       }
+
+       private StringBuilder printAssignment(Assignment statement, boolean parens) {
+               if (parens) {
+                       output.append('(');
+               }
+               printExpression(statement.lhs).append(" = ");
+               printExpression(statement.expression);
+               if (parens) {
+                       output.append(')');
+               }
+               return output;
+       }
+
+       private StringBuilder printMessageSendStatement(MessageSend ms) {
+               if (!ms.receiver.isImplicitThis()) {
+                       printExpression(ms.receiver).append('.');
+               }
+               if (ms.typeArguments != null) {
+                       output.append('<');
+                       int max = ms.typeArguments.length - 1;
+                       for (int j = 0; j < max; j++) {
+                               printTypeReference(ms.typeArguments[j]);
+                               // ms.typeArguments[j].print(0, output);
+                               output.append(", ");//$NON-NLS-1$
+                       }
+                       printTypeReference(ms.typeArguments[max]);
+                       // ms.typeArguments[max].print(0, output);
+                       output.append('>');
+               }
+               output.append(ms.selector).append('(');
+               if (ms.arguments != null) {
+                       for (int i = 0; i < ms.arguments.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printExpression(ms.arguments[i]);
+                       }
+               }
+               return output.append(')');
+       }
+
+       protected StringBuilder printQualifiedAllocationExpression(QualifiedAllocationExpression qae, int indent) {
+               if (qae.enclosingInstance != null) {
+                       printExpression(qae.enclosingInstance).append('.');
+               }
+               printAllocationExpression(qae);
+               if (qae.anonymousType != null) {
+                       printTypeDeclaration(qae.anonymousType, indent, true);
+               }
+               return output;
+       }
+
+       protected StringBuilder printTypeDeclaration(TypeDeclaration td, int indent, boolean isAnonymous) {
+               if (td.javadoc != null) {
+                       throwit(td);
+                       // td.javadoc.print(indent, output);
+               }
+               if ((td.bits & ASTNode.IsAnonymousType) == 0) {
+                       printIndent(tab);
+                       printTypeDeclarationHeader(td);
+               }
+               printTypeDeclarationBody(td, indent, isAnonymous);
+               return output;
+       }
+
+       public StringBuilder printTypeDeclarationBody(TypeDeclaration td, int indent, boolean isAnonymous) {
+               output.append(" {"); //$NON-NLS-1$
+               if (td.memberTypes != null) {
+                       for (int i = 0; i < td.memberTypes.length; i++) {
+                               if (td.memberTypes[i] != null) {
+                                       output.append('\n');
+                                       printTypeDeclaration(td.memberTypes[i], indent + 1, false);
+                               }
+                       }
+               }
+               if (td.fields != null) {
+                       for (int fieldI = 0; fieldI < td.fields.length; fieldI++) {
+                               if (td.fields[fieldI] != null) {
+                                       output.append('\n');
+                                       printFieldDeclaration(td.fields[fieldI], indent + 1);
+                               }
+                       }
+               }
+               if (td.methods != null) {
+                       for (int i = 0; i < td.methods.length; i++) {
+                               if (td.methods[i] != null) {
+                                       AbstractMethodDeclaration amd = td.methods[i];
+                                       if (amd instanceof MethodDeclaration) {
+                                               output.append('\n');
+                                               printMethodDeclaration(((MethodDeclaration) amd), indent + 1);
+                                       } else if (amd instanceof ConstructorDeclaration) {
+                                               if (!isAnonymous) {
+                                                       output.append('\n');
+                                                       // likely to be just a ctor with name 'x' as set in TypeDeclaration.createDefaultConstructorWithBinding
+                                                       printConstructorDeclaration(((ConstructorDeclaration) amd), indent + 1);
+                                               }
+                                       } else {
+                                               throwit(amd);
+                                       }
+                               }
+                       }
+               }
+               output.append('\n');
+               return printIndent(indent).append('}');
+       }
+
+       protected StringBuilder printFieldDeclaration(FieldDeclaration fd, int indent) {
+               printIndent(indent);
+               printModifiers(fd.modifiers);
+               if (fd.annotations != null) {
+                       printAnnotations(fd.annotations);
+               }
+
+               if (fd.type != null) {
+                       printTypeReference(fd.type).append(' ');
+               }
+               output.append(fd.name);
+               switch (fd.getKind()) {
+               case AbstractVariableDeclaration.ENUM_CONSTANT:
+                       if (fd.initialization != null) {
+                               printExpression(fd.initialization);
+                       }
+                       break;
+               default:
+                       if (fd.initialization != null) {
+                               output.append(" = "); //$NON-NLS-1$
+                               printExpression(fd.initialization);
+                       }
+               }
+               output.append(';');
+               return output;
+       }
+
+       protected StringBuilder printConstructorDeclaration(ConstructorDeclaration amd, int tab) {
+               if (amd.javadoc != null) {
+                       throwit();
+                       // amd.javadoc.print(tab, output);
+               }
+               printIndent(tab);
+               if (amd.annotations != null) {
+                       printAnnotations(amd.annotations);
+               }
+               printModifiers(amd.modifiers);
+
+               TypeParameter[] typeParams = amd.typeParameters();
+               if (typeParams != null) {
+                       output.append('<');
+                       int max = typeParams.length - 1;
+                       for (int j = 0; j < max; j++) {
+                               printTypeParameter(typeParams[j]);
+                               // typeParams[j].print(0, output);
+                               output.append(", ");//$NON-NLS-1$
+                       }
+                       printTypeParameter(typeParams[max]);
+                       output.append('>');
+               }
+
+               // TODO confirm selector is right name
+               output.append(amd.selector).append('(');
+               if (amd.arguments != null) {
+                       for (int i = 0; i < amd.arguments.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printArgument(amd.arguments[i]);
+                       }
+               }
+               output.append(')');
+               if (amd.thrownExceptions != null) {
+                       output.append(" throws "); //$NON-NLS-1$
+                       for (int i = 0; i < amd.thrownExceptions.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               throwit();
+                               // this.thrownExceptions[i].print(0, output);
+                       }
+               }
+               printBody(amd, tab + 1);
+               return output;
+       }
+
+       private StringBuilder printMethodDeclaration(MethodDeclaration amd, int tab) {
+
+               if (amd.javadoc != null) {
+                       throwit();
+                       // amd.javadoc.print(tab, output);
+               }
+               printIndent(tab);
+               if (amd.annotations != null) {
+                       printAnnotations(amd.annotations);
+               }
+               printModifiers(amd.modifiers);
+
+               TypeParameter[] typeParams = amd.typeParameters();
+               if (typeParams != null) {
+                       output.append('<');
+                       int max = typeParams.length - 1;
+                       for (int j = 0; j < max; j++) {
+                               printTypeParameter(typeParams[j]);
+                               // typeParams[j].print(0, output);
+                               output.append(", ");//$NON-NLS-1$
+                       }
+                       printTypeParameter(typeParams[max]);
+                       output.append('>');
+               }
+
+               printReturnType(amd.returnType).append(amd.selector).append('(');
+               if (amd.arguments != null) {
+                       for (int i = 0; i < amd.arguments.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printArgument(amd.arguments[i]);
+                       }
+               }
+               output.append(')');
+               if (amd.thrownExceptions != null) {
+                       output.append(" throws "); //$NON-NLS-1$
+                       for (int i = 0; i < amd.thrownExceptions.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               throwit();
+                               // this.thrownExceptions[i].print(0, output);
+                       }
+               }
+               printBody(amd, tab + 1);
+               return output;
+       }
+
+       public StringBuilder printReturnType(TypeReference tr) {
+               if (tr == null) {
+                       return output;
+               }
+               return printExpression(tr).append(' ');
+       }
+
+       public final static int kind(int flags) {
+               switch (flags & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) {
+               case ClassFileConstants.AccInterface:
+                       return TypeDeclaration.INTERFACE_DECL;
+               case ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation:
+                       return TypeDeclaration.ANNOTATION_TYPE_DECL;
+               case ClassFileConstants.AccEnum:
+                       return TypeDeclaration.ENUM_DECL;
+               default:
+                       return TypeDeclaration.CLASS_DECL;
+               }
+       }
+
+       protected StringBuilder printTypeDeclarationHeader(TypeDeclaration td) {
+               printModifiers(td.modifiers);
+               if (td.annotations != null) {
+                       printAnnotations(td.annotations);
+               }
+
+               switch (kind(td.modifiers)) {
+               case TypeDeclaration.CLASS_DECL:
+                       output.append("class "); //$NON-NLS-1$
+                       break;
+               case TypeDeclaration.INTERFACE_DECL:
+                       output.append("interface "); //$NON-NLS-1$
+                       break;
+               case TypeDeclaration.ENUM_DECL:
+                       output.append("enum "); //$NON-NLS-1$
+                       break;
+               case TypeDeclaration.ANNOTATION_TYPE_DECL:
+                       output.append("@interface "); //$NON-NLS-1$
+                       break;
+               }
+               output.append(td.name);
+               if (td.typeParameters != null) {
+                       output.append("<");//$NON-NLS-1$
+                       for (int i = 0; i < td.typeParameters.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printTypeParameter(td.typeParameters[i]);
+                               // this.typeParameters[i].print(0, output);
+                       }
+                       output.append(">");//$NON-NLS-1$
+               }
+               if (td.superclass != null) {
+                       output.append(" extends "); //$NON-NLS-1$
+                       printTypeReference(td.superclass);
+               }
+               if (td.superInterfaces != null && td.superInterfaces.length > 0) {
+                       switch (kind(td.modifiers)) {
+                       case TypeDeclaration.CLASS_DECL:
+                       case TypeDeclaration.ENUM_DECL:
+                               output.append(" implements "); //$NON-NLS-1$
+                               break;
+                       case TypeDeclaration.INTERFACE_DECL:
+                       case TypeDeclaration.ANNOTATION_TYPE_DECL:
+                               output.append(" extends "); //$NON-NLS-1$
+                               break;
+                       }
+                       for (int i = 0; i < td.superInterfaces.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printTypeReference(td.superInterfaces[i]);
+                       }
+               }
+               return output;
+       }
+
+       protected StringBuilder printTypeParameter(TypeParameter tp) {
+               output.append(tp.name);
+               if (tp.type != null) {
+                       output.append(" extends "); //$NON-NLS-1$
+                       printTypeReference(tp.type);
+               }
+               if (tp.bounds != null) {
+                       for (int i = 0; i < tp.bounds.length; i++) {
+                               output.append(" & "); //$NON-NLS-1$
+                               printTypeReference(tp.bounds[i]);
+                       }
+               }
+               return output;
+       }
+
+       protected StringBuilder printAllocationExpression(AllocationExpression ae) {
+               if (ae.type != null) { // type null for enum constant initializations
+                       output.append("new "); //$NON-NLS-1$
+               }
+               if (ae.typeArguments != null) {
+                       output.append('<');
+                       int max = ae.typeArguments.length - 1;
+                       for (int j = 0; j < max; j++) {
+                               printTypeReference(ae.typeArguments[j]);
+                               output.append(", ");//$NON-NLS-1$
+                       }
+                       printTypeReference(ae.typeArguments[max]);
+                       output.append('>');
+               }
+               if (ae.type != null) { // type null for enum constant initializations
+                       printExpression(ae.type);
+               }
+               output.append('(');
+               if (ae.arguments != null) {
+                       for (int i = 0; i < ae.arguments.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printExpression(ae.arguments[i]);
+                       }
+               }
+               return output.append(')');
+       }
+}
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/DeclareAnnotationsPrinter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/DeclareAnnotationsPrinter.java
new file mode 100644 (file)
index 0000000..7e087ae
--- /dev/null
@@ -0,0 +1,50 @@
+/* *******************************************************************
+ * Copyright (c) 2010 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://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement - SpringSource
+ * ******************************************************************/
+//package org.aspectj.ajdt.internal.compiler;
+//
+//import org.aspectj.ajdt.internal.compiler.ast.DeclareAnnotationDeclaration;
+//import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
+//import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+//
+//class DeclareAnnotationsPrinter extends HelperPrinter {
+//
+//     private DeclareAnnotationDeclaration dad;
+//
+//     DeclareAnnotationsPrinter(DeclareAnnotationDeclaration md, MethodScope mscope) {
+//             super(mscope);
+//             output = new StringBuilder();
+//             this.amd = md;
+//             this.dad = md;
+//     }
+//
+//     public String print() {
+//             return print(2);
+//     }
+//
+//     public String print(int tab) {
+//             output = new StringBuilder();
+//             Annotation[] annos = dad.annotations;
+//             int count = 0;
+//             for (int a = 0; a < annos.length; a++) {
+//                     Annotation anno = annos[a];
+//                     String aa = anno.type.toString();
+//                     if (!aa.startsWith("org.aspectj")) {
+//                             if (count > 0) {
+//                                     output.append(' ');
+//                             }
+//                             printAnnotation(anno);
+//                             count++;
+//                     }
+//             }
+//             return output.toString();
+//     }
+// }
\ No newline at end of file
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDConstructorPrinter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDConstructorPrinter.java
new file mode 100644 (file)
index 0000000..0a5ca69
--- /dev/null
@@ -0,0 +1,101 @@
+/* *******************************************************************
+ * Copyright (c) 2010 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://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import java.lang.reflect.Modifier;
+
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeConstructorDeclaration;
+import org.aspectj.asm.internal.CharOperation;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+
+/**
+ * Prints the declaration for an intertype declared constructor.
+ * 
+ * @author Andy Clement
+ */
+class ITDConstructorPrinter extends CommonPrinter {
+
+       private InterTypeConstructorDeclaration constructorDeclaration;
+
+       ITDConstructorPrinter(InterTypeConstructorDeclaration constructorDeclaration, MethodScope mscope) {
+               super(mscope);
+               this.output = new StringBuilder();
+               this.declaration = constructorDeclaration;
+               this.constructorDeclaration = constructorDeclaration;
+       }
+
+       public String print() {
+               return print(2);
+       }
+
+       public String print(int tab) {
+
+               this.output = new StringBuilder();
+
+               if (constructorDeclaration.javadoc != null) {
+                       throwit(null);
+                       // md.javadoc.print(tab, output);
+               }
+               printIndent(tab);
+               if (constructorDeclaration.annotations != null) {
+                       printAnnotations(constructorDeclaration.annotations);
+               }
+               printModifiers(constructorDeclaration.declaredModifiers); // not md.modifiers
+
+               TypeParameter[] typeParams = constructorDeclaration.typeParameters();
+               if (typeParams != null) {
+                       output.append('<');
+                       int max = typeParams.length - 1;
+                       for (int j = 0; j < max; j++) {
+                               printTypeParameter(typeParams[j]);
+                               output.append(", ");//$NON-NLS-1$
+                       }
+                       printTypeParameter(typeParams[max]);
+                       output.append("> ");
+               }
+
+               char[] s = constructorDeclaration.getDeclaredSelector();
+
+               output.append(CharOperation.subarray(s, 0, s.length - 4)).append('(');
+               if (constructorDeclaration.arguments != null) {
+                       for (int i = Modifier.isStatic(constructorDeclaration.declaredModifiers) ? 0 : 1; i < constructorDeclaration.arguments.length; i++) {
+
+                               printArgument(constructorDeclaration.arguments[i]);
+                               if ((i + 1) < constructorDeclaration.arguments.length) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                       }
+               }
+               output.append(')');
+
+               if (constructorDeclaration.thrownExceptions != null) {
+                       output.append(" throws "); //$NON-NLS-1$
+                       for (int i = 0; i < constructorDeclaration.thrownExceptions.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printTypeReference(constructorDeclaration.thrownExceptions[i]);
+                       }
+               }
+               printBody(tab + 1);
+               return output.toString();
+       }
+
+       // TODO better name
+       public StringBuilder printReturnType(int indent) {
+               if (constructorDeclaration.returnType == null) {
+                       return output;
+               }
+               return printExpression(constructorDeclaration.returnType).append(' ');
+       }
+}
\ No newline at end of file
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDFieldPrinter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDFieldPrinter.java
new file mode 100644 (file)
index 0000000..cf1f524
--- /dev/null
@@ -0,0 +1,77 @@
+/* *******************************************************************
+ * Copyright (c) 2010 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://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+
+/**
+ * Prints the declaration for an intertype declared field, including initializer.
+ * 
+ * @author Andy Clement
+ */
+class ITDFieldPrinter extends CommonPrinter {
+
+       private InterTypeFieldDeclaration fieldDeclaration;
+
+       ITDFieldPrinter(InterTypeFieldDeclaration fieldDeclaration, MethodScope methodscope) {
+               super(methodscope);
+               output = new StringBuilder();
+               this.fieldDeclaration = fieldDeclaration;
+       }
+
+       public String print() {
+               return print(2);
+       }
+
+       public String print(int tab) {
+               this.output = new StringBuilder();
+
+               if (fieldDeclaration.javadoc != null) {
+                       // TODO javadoc
+                       // md.javadoc.print(tab, output);
+               }
+               printIndent(tab);
+               if (fieldDeclaration.annotations != null) {
+                       printAnnotations(fieldDeclaration.annotations);
+               }
+               printModifiers(fieldDeclaration.declaredModifiers); // not md.modifiers
+
+               TypeParameter[] typeParams = fieldDeclaration.typeParameters();
+               if (typeParams != null) {
+                       output.append('<');
+                       int max = typeParams.length - 1;
+                       for (int j = 0; j < max; j++) {
+                               printTypeParameter(typeParams[j]);
+                               output.append(", ");//$NON-NLS-1$
+                       }
+                       printTypeParameter(typeParams[max]);
+                       output.append('>');
+               }
+               printReturnType(0).append(fieldDeclaration.getDeclaredSelector());
+               if (fieldDeclaration.initialization != null) {
+                       output.append(" = ");
+                       printExpression(fieldDeclaration.initialization);
+               }
+               output.append(';');
+               return output.toString();
+       }
+
+       // TODO better name
+       public StringBuilder printReturnType(int indent) {
+               if (fieldDeclaration.returnType == null) {
+                       return output;
+               }
+               return printExpression(fieldDeclaration.returnType).append(' ');
+       }
+}
\ No newline at end of file
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDMethodPrinter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDMethodPrinter.java
new file mode 100644 (file)
index 0000000..55b1eb7
--- /dev/null
@@ -0,0 +1,95 @@
+/* *******************************************************************
+ * Copyright (c) 2010 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://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import java.lang.reflect.Modifier;
+
+import org.aspectj.ajdt.internal.compiler.ast.InterTypeMethodDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+
+/**
+ * Prints the declaration for an intertype declared method.
+ * 
+ * @author Andy Clement
+ */
+class ITDMethodPrinter extends CommonPrinter {
+       private InterTypeMethodDeclaration methodDeclaration;
+
+       ITDMethodPrinter(InterTypeMethodDeclaration methodDeclaration, MethodScope methodscope) {
+               super(methodscope);
+               output = new StringBuilder();
+               this.methodDeclaration = methodDeclaration;
+               this.declaration = methodDeclaration;
+       }
+
+       public String print() {
+               return print(2);
+       }
+
+       public StringBuilder printReturnType(int indent) {
+               if (methodDeclaration.returnType == null) {
+                       return output;
+               }
+               return printExpression(methodDeclaration.returnType).append(' ');
+       }
+
+       public String print(int tab) {
+               this.output = new StringBuilder();
+
+               if (methodDeclaration.javadoc != null) {
+                       // TODO javadoc support...
+                       // md.javadoc.print(tab, output);
+               }
+               printIndent(tab);
+               if (methodDeclaration.annotations != null) {
+                       printAnnotations(methodDeclaration.annotations);
+               }
+               printModifiers(methodDeclaration.declaredModifiers); // not md.modifiers
+
+               TypeParameter[] typeParams = methodDeclaration.typeParameters();
+               if (typeParams != null) {
+                       output.append('<');
+                       int max = typeParams.length - 1;
+                       for (int j = 0; j < max; j++) {
+                               printTypeParameter(typeParams[j]);
+                               output.append(", ");//$NON-NLS-1$
+                       }
+                       printTypeParameter(typeParams[max]);
+                       output.append("> ");
+               }
+
+               printReturnType(0).append(methodDeclaration.getDeclaredSelector()).append('(');
+               if (methodDeclaration.arguments != null) {
+                       for (int i = Modifier.isStatic(methodDeclaration.declaredModifiers) ? 0 : 1; i < methodDeclaration.arguments.length; i++) {
+
+                               printArgument(methodDeclaration.arguments[i]);
+                               if ((i + 1) < methodDeclaration.arguments.length) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                       }
+               }
+               output.append(')');
+
+               if (methodDeclaration.thrownExceptions != null) {
+                       output.append(" throws "); //$NON-NLS-1$
+                       for (int i = 0; i < methodDeclaration.thrownExceptions.length; i++) {
+                               if (i > 0) {
+                                       output.append(", "); //$NON-NLS-1$
+                               }
+                               printTypeReference(methodDeclaration.thrownExceptions[i]);
+                       }
+               }
+               printBody(tab + 1);
+               return output.toString();
+       }
+}
\ No newline at end of file
index 8111238c77a598211c78e3d0d7a080acf0dcb3d8..7236237a1880840453e80716f5bf929a9d95b279 100644 (file)
@@ -12,57 +12,59 @@ package org.aspectj.ajdt.internal.compiler;
 
 import java.util.List;
 
-import org.aspectj.weaver.bcel.UnwovenClassFile;
 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.aspectj.weaver.bcel.UnwovenClassFile;
 
 /**
- * Holds a compilation result produced by the Java compilation phase,
- * ready for weaving in the weave phase.
- * NOTE: This class defines equality based solely on the fileName 
- * of the compiled file (not the bytecodes produced for example)
+ * Holds a compilation result produced by the Java compilation phase, ready for weaving in the weave phase. NOTE: This class defines
+ * equality based solely on the fileName of the compiled file (not the bytecodes produced for example)
  */
 public class InterimCompilationResult {
-       
-         private CompilationResult result;
-         private UnwovenClassFile[] unwovenClassFiles;  // longer term would be nice not to have two copies of
-                                                       // the byte codes, one in result.classFiles and another
-                                                       // in unwovenClassFiles;
 
-         public InterimCompilationResult(CompilationResult cr, 
-                                                                         IOutputClassFileNameProvider np) {
-               result = cr;
-               unwovenClassFiles = ClassFileBasedByteCodeProvider.unwovenClassFilesFor(result,np);
-         }
-         
-         public InterimCompilationResult(CompilationResult cr, List ucfList) {
-               result = cr;
-               unwovenClassFiles = new UnwovenClassFile[ucfList.size()];
-               for (int i=0; i < ucfList.size(); i++) {
-                       UnwovenClassFile element = (UnwovenClassFile) ucfList.get(i);
+       private CompilationResult result;
+       private UnwovenClassFile[] unwovenClassFiles; // longer term would be nice not to have two copies of
+
+       // the byte codes, one in result.classFiles and another
+       // in unwovenClassFiles;
+
+       public InterimCompilationResult(CompilationResult cr, IOutputClassFileNameProvider np) {
+               result = cr;
+               unwovenClassFiles = ClassFileBasedByteCodeProvider.unwovenClassFilesFor(result, np);
+       }
+
+       public InterimCompilationResult(CompilationResult cr, List<UnwovenClassFile> ucfList) {
+               result = cr;
+               unwovenClassFiles = new UnwovenClassFile[ucfList.size()];
+               for (int i = 0; i < ucfList.size(); i++) {
+                       UnwovenClassFile element = ucfList.get(i);
                        unwovenClassFiles[i] = element;
-                       AjClassFile ajcf = new AjClassFile(element.getClassNameAsChars(),
-                                                                                          element.getBytes());
-                       result.record(ajcf.fileName(),ajcf); 
-               }               
-         }
-         
-         public CompilationResult result() { return result; }
-         
-         public UnwovenClassFile[] unwovenClassFiles() { return unwovenClassFiles; }
-         
-         public String fileName() {
-               return new String(result.fileName);
-         }
-         
-      public boolean equals(Object other) {
-                       if( other == null || !(other instanceof InterimCompilationResult)) {
-                               return false;
-                       }
-                       InterimCompilationResult ir = (InterimCompilationResult) other;
-                       return fileName().equals(ir.fileName());
-         }
-         public int hashCode() {
-                       return fileName().hashCode();
-         }
-               
+                       AjClassFile ajcf = new AjClassFile(element.getClassNameAsChars(), element.getBytes());
+                       result.record(ajcf.fileName(), ajcf);
+               }
+       }
+
+       public CompilationResult result() {
+               return result;
+       }
+
+       public UnwovenClassFile[] unwovenClassFiles() {
+               return unwovenClassFiles;
+       }
+
+       public String fileName() {
+               return new String(result.fileName);
+       }
+
+       public boolean equals(Object other) {
+               if (other == null || !(other instanceof InterimCompilationResult)) {
+                       return false;
+               }
+               InterimCompilationResult ir = (InterimCompilationResult) other;
+               return fileName().equals(ir.fileName());
+       }
+
+       public int hashCode() {
+               return fileName().hashCode();
+       }
+
 }
index 826f0fb5efb8cd5bcbbad9b33692014aed73730f..855e8f7365460e809ac2af796552cd1c2afa55cf 100644 (file)
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.aspectj.ajdt.internal.compiler.CommonPrinter;
 import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
 import org.aspectj.ajdt.internal.compiler.ast.PointcutDeclaration;
 import org.aspectj.asm.AsmManager;
@@ -643,6 +644,9 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                        if (!decp.isMixin()) {
                                boolean didSomething = doDeclareParents(decp, sourceType);
                                if (didSomething) {
+                                       if (factory.pushinCollector != null) {
+                                               factory.pushinCollector.tagAsMunged(sourceType, decp.getParents().get(0));
+                                       }
                                        anyNewParents = true;
                                } else {
                                        if (!decp.getChild().isStarAnnotation()) {
@@ -656,6 +660,7 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                        DeclareAnnotation deca = (DeclareAnnotation) i.next();
                        boolean didSomething = doDeclareAnnotations(deca, sourceType, true);
                        if (didSomething) {
+
                                anyNewAnnotations = true;
                        } else {
                                if (!deca.getTypePattern().isStar()) {
@@ -672,6 +677,9 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                                DeclareParents decp = (DeclareParents) i.next();
                                boolean didSomething = doDeclareParents(decp, sourceType);
                                if (didSomething) {
+                                       if (factory.pushinCollector != null) {
+                                               factory.pushinCollector.tagAsMunged(sourceType, decp.getParents().get(0));
+                                       }
                                        anyNewParents = true;
                                        forRemoval.add(decp);
                                }
@@ -683,6 +691,9 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                                DeclareAnnotation deca = (DeclareAnnotation) i.next();
                                boolean didSomething = doDeclareAnnotations(deca, sourceType, false);
                                if (didSomething) {
+                                       if (factory.pushinCollector != null) {
+                                               factory.pushinCollector.tagAsMunged(sourceType, deca.getAnnotationString());
+                                       }
                                        anyNewAnnotations = true;
                                        forRemoval.add(deca);
                                }
@@ -705,7 +716,11 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                onType.checkInterTypeMungers();
                for (Iterator i = onType.getInterTypeMungers().iterator(); i.hasNext();) {
                        EclipseTypeMunger munger = (EclipseTypeMunger) i.next();
-                       munger.munge(sourceType, onType);
+                       if (munger.munge(sourceType, onType)) {
+                               if (factory.pushinCollector != null) {
+                                       factory.pushinCollector.tagAsMunged(sourceType, munger.getSourceMethod());
+                               }
+                       }
                }
 
                // Call if you would like to do source weaving of declare
@@ -884,6 +899,7 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                Annotation[] toAdd = null;
                long abits = 0;
 
+               AbstractMethodDeclaration methodDecl = null;
                // Might have to retrieve the annotation through BCEL and construct an
                // eclipse one for it.
                if (stb instanceof BinaryTypeBinding) {
@@ -919,7 +935,7 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                        MethodBinding[] mbs = stb.getMethods(decA.getAnnotationMethod().toCharArray());
                        abits = mbs[0].getAnnotationTagBits(); // ensure resolved
                        TypeDeclaration typeDecl = ((SourceTypeBinding) mbs[0].declaringClass).scope.referenceContext;
-                       AbstractMethodDeclaration methodDecl = typeDecl.declarationOf(mbs[0]);
+                       methodDecl = typeDecl.declarationOf(mbs[0]);
                        toAdd = methodDecl.annotations; // this is what to add
                        toAdd[0] = createAnnotationCopy(toAdd[0]);
                        if (toAdd[0].resolvedType != null) {
@@ -1063,6 +1079,10 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC
                }
                sourceType.scope.referenceContext.annotations = newset;
                CompilationAndWeavingContext.leavingPhase(tok);
+               if (factory.pushinCollector != null) {
+                       factory.pushinCollector.tagAsMunged(sourceType, new CommonPrinter((methodDecl == null ? null : methodDecl.scope))
+                                       .printAnnotation(toAdd[0]).toString());
+               }
                return true;
        }
 
index 3d746402e775ed244d564f799aa3ccfeff9d24a5..706bcfa2152af718abb229a6ee7c9f9d90751285 100644 (file)
@@ -87,6 +87,7 @@ public class EclipseFactory {
        private final LookupEnvironment lookupEnvironment;
        private final boolean xSerializableAspects;
        private final World world;
+       public PushinCollector pushinCollector;
        public Collection finishedTypeMungers = null;
 
        // We can get clashes if we don't treat raw types differently - we end up looking
@@ -110,6 +111,7 @@ public class EclipseFactory {
                this.lookupEnvironment = lookupEnvironment;
                this.buildManager = buildManager;
                this.world = buildManager.getWorld();
+               this.pushinCollector = PushinCollector.createInstance(this.world);
                this.xSerializableAspects = buildManager.buildConfig.isXserializableAspects();
        }
 
@@ -117,6 +119,7 @@ public class EclipseFactory {
                this.lookupEnvironment = lookupEnvironment;
                this.world = world;
                this.xSerializableAspects = xSer;
+               this.pushinCollector = PushinCollector.createInstance(this.world);
                this.buildManager = null;
        }
 
index c180a4bd90b3ecde2d9fa3864e2a4a5963c9bb65..010b52e7c97ffc17a9cad3d231afc873d4021254 100644 (file)
@@ -34,7 +34,7 @@ import org.aspectj.weaver.World;
 public class EclipseTypeMunger extends ConcreteTypeMunger {
        private ResolvedType targetTypeX;
        // protected ReferenceBinding targetBinding = null;
-       private AbstractMethodDeclaration sourceMethod;
+       public AbstractMethodDeclaration sourceMethod;
        private EclipseFactory world;
        private ISourceLocation sourceLocation;
 
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/PushinCollector.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/PushinCollector.java
new file mode 100644 (file)
index 0000000..d289f74
--- /dev/null
@@ -0,0 +1,368 @@
+/* *******************************************************************
+ * Copyright (c) 2010 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://www.eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *     Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.ajdt.internal.compiler.lookup;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.aspectj.ajdt.internal.compiler.IOutputClassFileNameProvider;
+import org.aspectj.asm.internal.CharOperation;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.patterns.ExactTypePattern;
+import org.aspectj.weaver.patterns.TypePattern;
+
+/**
+ * Collects up information about the application of ITDs and relevant declares - it can then output source code as if those ITDs had
+ * been pushed in. Supports the simulated push-in of:
+ * <ul>
+ * <li>declare at_type
+ * <li>itd method
+ * <li>itd field
+ * <li>itd ctor
+ * <li>declare parents
+ * </ul>
+ * 
+ * @author Andy Clement
+ * @since 1.6.9
+ */
+public class PushinCollector {
+
+       private final static String OPTION_SUFFIX = "suffix";
+       private final static String OPTION_DIR = "dir";
+       private final static String OPTION_PKGDIRS = "packageDirs";
+       private final static String OPTION_DEBUG = "debug";
+       private final static String OPTION_LINENUMS = "lineNums";
+
+       private World world;
+       private boolean debug = false;
+       private IOutputClassFileNameProvider outputFileNameProvider;
+       private String specifiedOutputDirectory;
+       private boolean includePackageDirs;
+       private boolean includeLineNumberComments;
+       private String suffix;
+
+       // This first collection stores the 'text' for the declarations.
+       private Map<AbstractMethodDeclaration, RepresentationAndLocation> codeRepresentation = new HashMap<AbstractMethodDeclaration, RepresentationAndLocation>();
+
+       // This stores the new annotations
+       private Map<SourceTypeBinding, List<String>> additionalAnnotations = new HashMap<SourceTypeBinding, List<String>>();
+
+       // This stores the new parents
+       private Map<SourceTypeBinding, List<ExactTypePattern>> additionalParents = new HashMap<SourceTypeBinding, List<ExactTypePattern>>();
+
+       // This indicates which types are affected by which intertype declarations
+       private Map<SourceTypeBinding, List<AbstractMethodDeclaration>> newDeclarations = new HashMap<SourceTypeBinding, List<AbstractMethodDeclaration>>();
+
+       private PushinCollector(World world, Properties configuration) {
+               this.world = world;
+
+               // Configure the instance based on the input properties
+               specifiedOutputDirectory = configuration.getProperty(OPTION_DIR);
+               includePackageDirs = configuration.getProperty(OPTION_PKGDIRS, "true").equalsIgnoreCase("true");
+               includeLineNumberComments = configuration.getProperty(OPTION_LINENUMS, "false").equalsIgnoreCase("true");
+               debug = configuration.getProperty(OPTION_DEBUG, "false").equalsIgnoreCase("true");
+               String specifiedSuffix = configuration.getProperty(OPTION_SUFFIX, "pushedin");
+               if (specifiedSuffix.length() > 0) {
+                       StringBuilder sb = new StringBuilder();
+                       sb.append(".").append(specifiedSuffix);
+                       suffix = sb.toString();
+               } else {
+                       suffix = "";
+               }
+               if (debug) {
+                       System.out.println("Configured to create pushin side files:" + configuration);
+               }
+
+       }
+
+       private String getName(CompilationUnitDeclaration cud) {
+               if (cud == null) {
+                       return "UNKNOWN";
+               }
+               if (cud.scope == null) {
+                       return "UNKNOWN";
+               }
+               if (cud.scope.referenceContext == null) {
+                       return "UNKNOWN";
+               }
+               return new String(cud.scope.referenceContext.getFileName());
+       }
+
+       /**
+        * @return true if the type is affected by something (itd/declare anno/declare parent)
+        */
+       private boolean hasChanged(SourceTypeBinding stb) {
+               return newDeclarations.get(stb) != null || additionalParents.get(stb) != null || additionalAnnotations.get(stb) != null;
+       }
+
+       /**
+        * Produce the modified source that looks like the itds and declares have been applied.
+        */
+       public void dump(CompilationUnitDeclaration compilationUnitDeclaration, String outputFileLocation) {
+               if (compilationUnitDeclaration.scope.topLevelTypes == null || compilationUnitDeclaration.scope.topLevelTypes.length == 0) {
+                       return;
+               }
+               SourceTypeBinding[] types = compilationUnitDeclaration.scope.topLevelTypes;
+               if (types == null || types.length == 0) {
+                       return;
+               }
+
+               // Process all types working from end to start as whatever we do (insert-wise) will affect locations later in the file
+               StringBuffer sourceContents = new StringBuffer();
+               // put the whole original file in the buffer
+               sourceContents.append(compilationUnitDeclaration.compilationResult.compilationUnit.getContents());
+               for (int t = types.length - 1; t >= 0; t--) {
+                       SourceTypeBinding sourceTypeBinding = compilationUnitDeclaration.scope.topLevelTypes[t];
+                       if (!hasChanged(sourceTypeBinding)) {
+                               if (debug) {
+                                       System.out.println(getName(compilationUnitDeclaration) + " has nothing applied");
+                               }
+                               continue;
+                       }
+
+                       int bodyEnd = sourceTypeBinding.scope.referenceContext.bodyEnd; // last '}' of the type
+                       List<AbstractMethodDeclaration> declarations = newDeclarations.get(sourceTypeBinding);
+                       if (declarations != null) {
+                               for (AbstractMethodDeclaration md : declarations) {
+                                       RepresentationAndLocation ral = codeRepresentation.get(md);
+                                       if (ral != null) {
+                                               String s = ral.textualRepresentation;
+                                               sourceContents.insert(bodyEnd, "\n" + s + "\n");
+                                               if (includeLineNumberComments && ral.linenumber != -1) {
+                                                       sourceContents.insert(bodyEnd, "\n    // " + ral.linenumber);
+                                               }
+                                       }
+                               }
+                       }
+
+                       // fix up declare parents - may need to attach them to existing ones
+                       TypeReference sr = sourceTypeBinding.scope.referenceContext.superclass;
+                       TypeReference[] trs = sourceTypeBinding.scope.referenceContext.superInterfaces;
+                       List<ExactTypePattern> newParents = additionalParents.get(sourceTypeBinding);
+                       StringBuffer extendsString = new StringBuffer();
+                       StringBuffer implementsString = new StringBuffer();
+                       if (newParents != null && newParents.size() > 0) {
+                               for (ExactTypePattern newParent : newParents) {
+                                       ResolvedType newParentType = newParent.getExactType().resolve(world);
+                                       if (newParentType.isInterface()) {
+                                               if (implementsString.length() > 0) {
+                                                       implementsString.append(",");
+                                               }
+                                               implementsString.append(newParentType.getName());
+                                       } else {
+                                               extendsString.append(newParentType.getName());
+                                       }
+                               }
+                               if (trs == null && sr == null) {
+                                       // nothing after the class declaration, let's insert what we need to
+                                       // Find the position just before the type opening '{'
+                                       int beforeOpeningCurly = sourceTypeBinding.scope.referenceContext.bodyStart - 1;
+                                       if (implementsString.length() != 0) {
+                                               implementsString.insert(0, "implements ");
+                                               implementsString.append(" ");
+                                               sourceContents.insert(beforeOpeningCurly, implementsString);
+                                       }
+                                       if (extendsString.length() != 0) {
+                                               extendsString.insert(0, "extends ");
+                                               extendsString.append(" ");
+                                               sourceContents.insert(beforeOpeningCurly, extendsString);
+                                       }
+                               }
+                       }
+                       List<String> annos = additionalAnnotations.get(sourceTypeBinding);
+                       if (annos != null && annos.size() > 0) {
+                               for (String anno : annos) {
+                                       sourceContents.insert(sourceTypeBinding.scope.referenceContext.declarationSourceStart, anno + " ");
+                               }
+                       }
+               }
+               try {
+                       if (debug) {
+                               System.out.println("Pushed in output file being written to " + outputFileLocation);
+                               System.out.println(sourceContents);
+                       }
+                       FileWriter fos = new FileWriter(new File(outputFileLocation));
+                       fos.write(sourceContents.toString());
+                       fos.close();
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       /**
+        * Encapsulates a text representation (source code) for a member and the line where it was declared.
+        */
+       private static class RepresentationAndLocation {
+
+               String textualRepresentation;
+               int linenumber;
+
+               public RepresentationAndLocation(String textualRepresentation, int linenumber) {
+                       this.textualRepresentation = textualRepresentation;
+                       this.linenumber = linenumber;
+               }
+       }
+
+       public void recordInterTypeMethodDeclarationCode(AbstractMethodDeclaration md, String s, int line) {
+               codeRepresentation.put(md, new RepresentationAndLocation(s, line));
+       }
+
+       public void recordInterTypeFieldDeclarationCode(AbstractMethodDeclaration md, String s, int line) {
+               codeRepresentation.put(md, new RepresentationAndLocation(s, line));
+       }
+
+       public void recordInterTypeConstructorDeclarationCode(AbstractMethodDeclaration md, String s, int line) {
+               codeRepresentation.put(md, new RepresentationAndLocation(s, line));
+       }
+
+       // public void recordDeclareAnnotationDeclarationCode(AbstractMethodDeclaration md, String value) {
+       // codeRepresentation.put(md, new RepresentationAndLocation(value, -1));
+       // }
+
+       public void tagAsMunged(SourceTypeBinding sourceType, AbstractMethodDeclaration sourceMethod) {
+               if (sourceMethod == null) {
+                       // seen when an ITD field is made onto an interface. It matches, but the sourceMethod is null.
+                       // can be null for binary weave (there is no source method)
+                       return;
+               }
+               List<AbstractMethodDeclaration> amds = newDeclarations.get(sourceType);
+               if (amds == null) {
+                       amds = new ArrayList<AbstractMethodDeclaration>();
+                       newDeclarations.put(sourceType, amds);
+               }
+               amds.add(sourceMethod);
+       }
+
+       public void tagAsMunged(SourceTypeBinding sourceType, String annotationString) {
+               List<String> annos = additionalAnnotations.get(sourceType);
+               if (annos == null) {
+                       annos = new ArrayList<String>();
+                       additionalAnnotations.put(sourceType, annos);
+               }
+               annos.add(annotationString);
+       }
+
+       public void dump(CompilationUnitDeclaration unit) {
+               String outputFile = getOutputFileFor(unit);
+               if (debug) {
+                       System.out
+                                       .println("Output location is " + outputFile + " for " + new String(unit.scope.referenceContext.getFileName()));
+               }
+               dump(unit, outputFile);
+       }
+
+       private String getOutputFileFor(CompilationUnitDeclaration unit) {
+               StringBuffer sb = new StringBuffer();
+
+               // Create the directory portion of the output location
+               if (specifiedOutputDirectory != null) {
+                       sb.append(specifiedOutputDirectory).append(File.separator);
+               } else {
+                       String sss = outputFileNameProvider.getOutputClassFileName("A".toCharArray(), unit.compilationResult);
+                       sb.append(sss, 0, sss.length() - 7);
+               }
+
+               // Create the subdirectory structure matching the package declaration
+               if (includePackageDirs) {
+                       char[][] packageName = unit.compilationResult.packageName;
+                       if (packageName != null) {
+                               sb.append(CharOperation.concatWith(unit.compilationResult.packageName, File.separatorChar));
+                               sb.append(File.separator);
+                       }
+               }
+
+               new File(sb.toString()).mkdirs();
+
+               // Create the filename portion
+               String filename = new String(unit.getFileName()); // gives 'n:\A.java'
+               int index = filename.lastIndexOf('/');
+               int index2 = filename.lastIndexOf('\\');
+               if (index > index2) {
+                       sb.append(filename.substring(index + 1));
+               } else if (index2 > index) {
+                       sb.append(filename.substring(index2 + 1));
+               } else {
+                       sb.append(filename);
+               }
+
+               // Add the suffix (may be an empty string)
+               sb.append(suffix);
+               return sb.toString();
+       }
+
+       public void tagAsMunged(SourceTypeBinding sourceType, TypePattern typePattern) {
+               if (typePattern instanceof ExactTypePattern) {
+                       List<ExactTypePattern> annos = additionalParents.get(sourceType);
+                       if (annos == null) {
+                               annos = new ArrayList<ExactTypePattern>();
+                               additionalParents.put(sourceType, annos);
+                       }
+                       annos.add((ExactTypePattern) typePattern);
+               }
+       }
+
+       /**
+        * Checks if the aspectj.pushin property is set - this is the main condition for triggering the creation of pushed-in source
+        * files. If not set just to 'true', the value of the property is processed as configuration. Configurable options are:
+        * <ul>
+        * <li>dir=XXXX - to set the output directory for the pushed in files
+        * <li>suffix=XXX - to set the suffix, can be blank to get just '.java'
+        * </ul>
+        */
+       public static PushinCollector createInstance(World world) {
+               try {
+                       String property = System.getProperty("aspectj.pushin");
+                       if (property == null) {
+                               return null;
+                       }
+                       Properties configuration = new Properties();
+                       StringTokenizer tokenizer = new StringTokenizer(property, ",");
+                       while (tokenizer.hasMoreElements()) {
+                               String token = tokenizer.nextToken();
+                               // Simplest thing to do is turn it on 'aspectj.pushin=true'
+                               if (token.equalsIgnoreCase("true")) {
+                                       continue;
+                               }
+                               int positionOfEquals = token.indexOf("=");
+                               if (positionOfEquals != -1) {
+                                       // it is an option
+                                       String optionName = token.substring(0, positionOfEquals);
+                                       String optionValue = token.substring(positionOfEquals + 1);
+                                       configuration.put(optionName, optionValue);
+                               } else {
+                                       // it is a flag
+                                       configuration.put(token, "true");
+                               }
+                       }
+                       return new PushinCollector(world, configuration);
+               } catch (Exception e) {
+                       // unable to read system properties...
+               }
+               return null;
+       }
+
+       public void setOutputFileNameProvider(IOutputClassFileNameProvider outputFileNameProvider) {
+               this.outputFileNameProvider = outputFileNameProvider;
+       }
+}