From 5adbb9cab3648180111a362dab7e5fd15d2ee7db Mon Sep 17 00:00:00 2001 From: aclement Date: Mon, 7 Jun 2010 18:28:40 +0000 Subject: [PATCH] PushIn --- .../internal/compiler/AjCompilerAdapter.java | 30 +- .../compiler/AjPipeliningCompilerAdapter.java | 93 +- .../ajdt/internal/compiler/CommonPrinter.java | 1227 +++++++++++++++++ .../compiler/DeclareAnnotationsPrinter.java | 50 + .../compiler/ITDConstructorPrinter.java | 101 ++ .../internal/compiler/ITDFieldPrinter.java | 77 ++ .../internal/compiler/ITDMethodPrinter.java | 95 ++ .../compiler/InterimCompilationResult.java | 94 +- .../compiler/lookup/AjLookupEnvironment.java | 24 +- .../compiler/lookup/EclipseFactory.java | 3 + .../compiler/lookup/EclipseTypeMunger.java | 2 +- .../compiler/lookup/PushinCollector.java | 368 +++++ 12 files changed, 2085 insertions(+), 79 deletions(-) create mode 100644 org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/CommonPrinter.java create mode 100644 org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/DeclareAnnotationsPrinter.java create mode 100644 org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDConstructorPrinter.java create mode 100644 org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDFieldPrinter.java create mode 100644 org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDMethodPrinter.java create mode 100644 org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/PushinCollector.java diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java index 2537c0356..a23eb05f0 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java @@ -85,8 +85,7 @@ public class AjCompilerAdapter extends AbstractCompilerAdapter { EclipseFactory eFactory, IIntermediateResultsRequestor intRequestor, IProgressListener progressListener, IOutputClassFileNameProvider outputFileNameProvider, IBinarySourceProvider binarySourceProvider, Map fullBinarySourceEntries, /* fileName |-> List */ - 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); + } } } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjPipeliningCompilerAdapter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjPipeliningCompilerAdapter.java index 29fcf45bc..00f7f8d8c 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjPipeliningCompilerAdapter.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjPipeliningCompilerAdapter.java @@ -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 */binarySourceSetForFullWeave = new HashMap(); + private Map> binarySourceSetForFullWeave = new HashMap>(); 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 resultsPendingWeave = new ArrayList(); // 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 aspects = new ArrayList(); + List nonaspects = new ArrayList(); 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(); 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 getBinarySourcesFrom(Map> binarySourceEntries) { // Map is fileName |-> List - List ret = new ArrayList(); - for (Iterator binIter = binarySourceEntries.keySet().iterator(); binIter.hasNext();) { - String sourceFileName = (String) binIter.next(); - List unwovenClassFiles = (List) binarySourceEntries.get(sourceFileName); + List ret = new ArrayList(); + for (Iterator binIter = binarySourceEntries.keySet().iterator(); binIter.hasNext();) { + String sourceFileName = binIter.next(); + List 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 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 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 index 000000000..cfdc9da0a --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/CommonPrinter.java @@ -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 index 000000000..7e087ae0b --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/DeclareAnnotationsPrinter.java @@ -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 index 000000000..0a5ca697a --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDConstructorPrinter.java @@ -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 index 000000000..cf1f5249f --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDFieldPrinter.java @@ -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 index 000000000..55b1eb725 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ITDMethodPrinter.java @@ -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 diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java index 8111238c7..7236237a1 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java @@ -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 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(); + } + } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java index 826f0fb5e..855e8f736 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java @@ -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; } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java index 3d746402e..706bcfa21 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java @@ -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; } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java index c180a4bd9..010b52e7c 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java @@ -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 index 000000000..d289f74f4 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/PushinCollector.java @@ -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: + *
    + *
  • declare at_type + *
  • itd method + *
  • itd field + *
  • itd ctor + *
  • declare parents + *
+ * + * @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 codeRepresentation = new HashMap(); + + // This stores the new annotations + private Map> additionalAnnotations = new HashMap>(); + + // This stores the new parents + private Map> additionalParents = new HashMap>(); + + // This indicates which types are affected by which intertype declarations + private Map> newDeclarations = new HashMap>(); + + 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 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 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 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 amds = newDeclarations.get(sourceType); + if (amds == null) { + amds = new ArrayList(); + newDeclarations.put(sourceType, amds); + } + amds.add(sourceMethod); + } + + public void tagAsMunged(SourceTypeBinding sourceType, String annotationString) { + List annos = additionalAnnotations.get(sourceType); + if (annos == null) { + annos = new ArrayList(); + 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 annos = additionalParents.get(sourceType); + if (annos == null) { + annos = new ArrayList(); + 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: + *
    + *
  • dir=XXXX - to set the output directory for the pushed in files + *
  • suffix=XXX - to set the suffix, can be blank to get just '.java' + *
+ */ + 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; + } +} -- 2.39.5