* PARC initial implementation
* ******************************************************************/
-
package org.aspectj.ajdt.internal.compiler.ast;
import java.lang.reflect.Modifier;
import org.aspectj.ajdt.internal.compiler.problem.AjProblemReporter;
import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
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.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
/**
* An inter-type method declaration.
- *
+ *
* @author Jim Hugunin
*/
public class InterTypeMethodDeclaration extends InterTypeDeclaration {
parser.parse(this, unit);
}
}
-
+
protected char[] getPrefix() {
return (NameMangler.ITD_PREFIX + "interMethod$").toCharArray();
}
-
+
public boolean isFinal() {
- return (declaredModifiers & ClassFileConstants.AccFinal) != 0;
+ return (declaredModifiers & ClassFileConstants.AccFinal) != 0;
}
- public void analyseCode(
- ClassScope currentScope,
- InitializationFlowContext flowContext,
- FlowInfo flowInfo)
- {
- if (Modifier.isAbstract(declaredModifiers)) return;
-
+ public void analyseCode(ClassScope currentScope, InitializationFlowContext flowContext, FlowInfo flowInfo) {
+ if (Modifier.isAbstract(declaredModifiers))
+ return;
+
super.analyseCode(currentScope, flowContext, flowInfo);
}
-
+
public void resolve(ClassScope upperScope) {
- if (munger == null) ignoreFurtherInvestigation = true;
+ if (munger == null)
+ ignoreFurtherInvestigation = true;
if (binding == null)
- ignoreFurtherInvestigation = true;
- if (ignoreFurtherInvestigation) return;
-
+ ignoreFurtherInvestigation = true;
+ if (ignoreFurtherInvestigation)
+ return;
+
if (!Modifier.isStatic(declaredModifiers)) {
- this.arguments = AstUtil.insert(
- AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding),
- this.arguments);
- binding.parameters = AstUtil.insert(onTypeBinding, binding.parameters);
+ this.arguments = AstUtil.insert(AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding), this.arguments);
+ binding.parameters = AstUtil.insert(onTypeBinding, binding.parameters);
}
-
+
super.resolve(upperScope);
}
-
-
+
public void resolveStatements() {
checkAndSetModifiersForMethod();
- if ((modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
- if ((declaredModifiers & ClassFileConstants.AccAbstract) == 0)
- scope.problemReporter().methodNeedBody(this);
- } else {
- // the method HAS a body --> abstract native modifiers are forbiden
- if (((declaredModifiers & ClassFileConstants.AccAbstract) != 0))
- scope.problemReporter().methodNeedingNoBody(this);
- }
-
- // XXX AMC we need to do this, but I'm not 100% comfortable as I don't
- // know why the return type is wrong in this case. Also, we don't seem to need
- // to do it for args...
- if (munger.getSignature().getReturnType().isRawType()) {
- if (!binding.returnType.isRawType()) {
+ if ((modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
+ if ((declaredModifiers & ClassFileConstants.AccAbstract) == 0)
+ scope.problemReporter().methodNeedBody(this);
+ } else {
+ // the method HAS a body --> abstract native modifiers are forbiden
+ if (((declaredModifiers & ClassFileConstants.AccAbstract) != 0))
+ scope.problemReporter().methodNeedingNoBody(this);
+ }
+
+ // XXX AMC we need to do this, but I'm not 100% comfortable as I don't
+ // know why the return type is wrong in this case. Also, we don't seem to need
+ // to do it for args...
+ if (munger.getSignature().getReturnType().isRawType()) {
+ if (!binding.returnType.isRawType()) {
EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
- binding.returnType = world.makeTypeBinding(munger.getSignature().getReturnType());
- }
- }
-
- // check @Override annotation - based on MethodDeclaration.resolveStatements() @Override processing
+ binding.returnType = world.makeTypeBinding(munger.getSignature().getReturnType());
+ }
+ }
+
+ // check @Override annotation - based on MethodDeclaration.resolveStatements() @Override processing
checkOverride: {
- if (this.binding == null) break checkOverride;
- if (this.scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5) break checkOverride;
+ if (this.binding == null)
+ break checkOverride;
+ if (this.scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5)
+ break checkOverride;
boolean hasOverrideAnnotation = (this.binding.tagBits & TagBits.AnnotationOverride) != 0;
-
+
// Need to verify
if (hasOverrideAnnotation) {
-
+
// Work out the real method binding that we can use for comparison
EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
- MethodBinding realthing = world.makeMethodBinding(munger.getSignature(),munger.getTypeVariableAliases());
-
- boolean reportError = true;
+ MethodBinding realthing = world.makeMethodBinding(munger.getSignature(), munger.getTypeVariableAliases());
+
+ boolean reportError = true;
// Go up the hierarchy, looking for something we override
ReferenceBinding supertype = onTypeBinding.superclass();
- while (supertype!=null && reportError) {
+ while (supertype != null && reportError) {
MethodBinding[] possibles = supertype.getMethods(declaredSelector);
for (int i = 0; i < possibles.length; i++) {
MethodBinding mb = possibles[i];
boolean couldBeMatch = true;
- if (mb.parameters.length!=realthing.parameters.length) couldBeMatch=false;
+ if (mb.parameters.length != realthing.parameters.length)
+ couldBeMatch = false;
else {
for (int j = 0; j < mb.parameters.length && couldBeMatch; j++) {
- if (!mb.parameters[j].equals(realthing.parameters[j])) couldBeMatch=false;
+ if (!mb.parameters[j].equals(realthing.parameters[j]))
+ couldBeMatch = false;
}
}
// return types compatible? (allow for covariance)
- if (couldBeMatch && !returnType.resolvedType.isCompatibleWith(mb.returnType)) couldBeMatch=false;
- if (couldBeMatch) reportError = false;
+ if (couldBeMatch && !returnType.resolvedType.isCompatibleWith(mb.returnType))
+ couldBeMatch = false;
+ if (couldBeMatch)
+ reportError = false;
}
supertype = supertype.superclass(); // superclass of object is null
}
// If we couldn't find something we override, report the error
- if (reportError) ((AjProblemReporter)this.scope.problemReporter()).itdMethodMustOverride(this,realthing);
+ if (reportError)
+ ((AjProblemReporter) this.scope.problemReporter()).itdMethodMustOverride(this, realthing);
}
}
-
- if (!Modifier.isAbstract(declaredModifiers)) super.resolveStatements();
+
+ if (!Modifier.isAbstract(declaredModifiers))
+ super.resolveStatements();
if (Modifier.isStatic(declaredModifiers)) {
// Check the target for ITD is not an interface
if (onTypeBinding.isInterface()) {
- scope.problemReporter().signalError(sourceStart, sourceEnd,
- "methods in interfaces cannot be declared static");
+ scope.problemReporter().signalError(sourceStart, sourceEnd, "methods in interfaces cannot be declared static");
}
}
}
-
-
public EclipseTypeMunger build(ClassScope classScope) {
EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(classScope);
-
+
resolveOnType(classScope);
- if (ignoreFurtherInvestigation) return null;
+ if (ignoreFurtherInvestigation)
+ return null;
binding = classScope.referenceContext.binding.resolveTypesFor(binding);
if (binding == null) {
// if binding is null, we failed to find a type used in the method params, this error
// has already been reported.
this.ignoreFurtherInvestigation = true;
- //return null;
- throw new AbortCompilationUnit(compilationResult,null);
+ // return null;
+ throw new AbortCompilationUnit(compilationResult, null);
}
- if (isTargetAnnotation(classScope,"method")) return null; // Error message output in isTargetAnnotation
- if (isTargetEnum(classScope,"method")) return null; // Error message output in isTargetEnum
-
- if (interTypeScope==null) return null; // We encountered a problem building the scope, don't continue - error already reported
-
+ if (isTargetAnnotation(classScope, "method"))
+ return null; // Error message output in isTargetAnnotation
+ if (isTargetEnum(classScope, "method"))
+ return null; // Error message output in isTargetEnum
+
+ if (interTypeScope == null)
+ return null; // We encountered a problem building the scope, don't continue - error already reported
+
// This signature represents what we want consumers of the targetted type to 'see'
// must use the factory method to build it since there may be typevariables from the binding
// referred to in the parameters/returntype
- ResolvedMember sig = factory.makeResolvedMemberForITD(binding,onTypeBinding,interTypeScope.getRecoveryAliases());
+ ResolvedMember sig = factory.makeResolvedMemberForITD(binding, onTypeBinding, interTypeScope.getRecoveryAliases());
sig.resetName(new String(declaredSelector));
int resetModifiers = declaredModifiers;
- if (binding.isVarargs()) resetModifiers = resetModifiers | Constants.ACC_VARARGS;
- sig.resetModifiers(resetModifiers);
+ if (binding.isVarargs())
+ resetModifiers = resetModifiers | Constants.ACC_VARARGS;
+ sig.resetModifiers(resetModifiers);
NewMethodTypeMunger myMunger = new NewMethodTypeMunger(sig, null, typeVariableAliases);
setMunger(myMunger);
ResolvedType aspectType = factory.fromEclipse(classScope.referenceContext.binding);
- ResolvedMember me =
- myMunger.getInterMethodBody(aspectType);
+ ResolvedMember me = myMunger.getInterMethodBody(aspectType);
this.selector = binding.selector = me.getName().toCharArray();
return new EclipseTypeMunger(factory, myMunger, aspectType, this);
}
-
-
+
private AjAttribute makeAttribute() {
return new AjAttribute.TypeMunger(munger);
}
-
-
+
public void generateCode(ClassScope classScope, ClassFile classFile) {
if (ignoreFurtherInvestigation) {
- //System.err.println("no code for " + this);
+ // System.err.println("no code for " + this);
return;
}
-
+
classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute()));
-
+
if (!Modifier.isAbstract(declaredModifiers)) {
super.generateCode(classScope, classFile); // this makes the interMethodBody
}
-
- // annotations on the ITD declaration get put on this method
+
+ // annotations on the ITD declaration get put on this method
generateDispatchMethod(classScope, classFile);
}
-
+
public void generateDispatchMethod(ClassScope classScope, ClassFile classFile) {
EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
-
+
UnresolvedType aspectType = world.fromBinding(classScope.referenceContext.binding);
ResolvedMember signature = munger.getSignature();
-
- ResolvedMember dispatchMember =
- AjcMemberMaker.interMethodDispatcher(signature, aspectType);
- MethodBinding dispatchBinding = world.makeMethodBinding(dispatchMember,munger.getTypeVariableAliases(),munger.getSignature().getDeclaringType());
- MethodBinding introducedMethod =
- world.makeMethodBinding(AjcMemberMaker.interMethod(signature, aspectType, onTypeBinding.isInterface()),munger.getTypeVariableAliases());
-
+
+ ResolvedMember dispatchMember = AjcMemberMaker.interMethodDispatcher(signature, aspectType);
+ MethodBinding dispatchBinding = world.makeMethodBinding(dispatchMember, munger.getTypeVariableAliases(), munger
+ .getSignature().getDeclaringType());
+ MethodBinding introducedMethod = world.makeMethodBinding(AjcMemberMaker.interMethod(signature, aspectType, onTypeBinding
+ .isInterface()), munger.getTypeVariableAliases());
+
classFile.generateMethodInfoHeader(dispatchBinding);
int methodAttributeOffset = classFile.contentsOffset;
-
-
- // Watch out! We are passing in 'binding' here (instead of dispatchBinding) so that
+
+ // Watch out! We are passing in 'binding' here (instead of dispatchBinding) so that
// the dispatch binding attributes will include the annotations from the 'binding'.
// There is a chance that something else on the binding (e.g. throws clause) might
// damage the attributes generated for the dispatch binding.
- int attributeNumber = classFile.generateMethodInfoAttribute(binding,
- false,
- makeEffectiveSignatureAttribute(signature, Shadow.MethodCall, false));
+ int attributeNumber = classFile.generateMethodInfoAttribute(binding, false, makeEffectiveSignatureAttribute(signature,
+ Shadow.MethodCall, false));
int codeAttributeOffset = classFile.contentsOffset;
classFile.generateCodeAttributeHeader();
CodeStream codeStream = classFile.codeStream;
codeStream.reset(this, classFile);
-
codeStream.initializeMaxLocals(dispatchBinding);
-
+
+ Argument[] itdArgs = this.arguments;
+ if (itdArgs != null) {
+ for (int a = 0; a < itdArgs.length; a++) {
+ LocalVariableBinding lvb = itdArgs[a].binding;
+ LocalVariableBinding lvbCopy = new LocalVariableBinding(lvb.name, lvb.type, lvb.modifiers, true);
+ codeStream.record(lvbCopy);
+ lvbCopy.recordInitializationStartPC(0);
+ lvbCopy.resolvedPosition = lvb.resolvedPosition;
+ }
+ }
+
MethodBinding methodBinding = introducedMethod;
TypeBinding[] parameters = methodBinding.parameters;
int length = parameters.length;
else
resolvedPosition++;
}
-// TypeBinding type;
+ // TypeBinding type;
if (methodBinding.isStatic())
codeStream.invokestatic(methodBinding);
else {
- if (methodBinding.declaringClass.isInterface()){
+ if (methodBinding.declaringClass.isInterface()) {
codeStream.invokeinterface(methodBinding);
} else {
codeStream.invokevirtual(methodBinding);
}
AstUtil.generateReturn(dispatchBinding.returnType, codeStream);
+ // tag the local variables as used throughout the method
+ if (itdArgs != null) {
+ for (int a = 0; a < itdArgs.length; a++) {
+ codeStream.locals[a].recordInitializationEndPC(codeStream.position);
+ }
+ }
classFile.completeCodeAttribute(codeAttributeOffset);
attributeNumber++;
classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
}
-
protected Shadow.Kind getShadowKindForBody() {
return Shadow.MethodExecution;
}
-
+
// XXX this code is copied from MethodScope, with a few adjustments for ITDs...
private void checkAndSetModifiersForMethod() {
-
+
// for reported problems, we want the user to see the declared selector
char[] realSelector = this.selector;
this.selector = declaredSelector;
-
+
final ReferenceBinding declaringClass = this.binding.declaringClass;
if ((declaredModifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0)
scope.problemReporter().duplicateModifierForMethod(onTypeBinding, this);
// check for abnormal modifiers
int unexpectedModifiers = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected
- | ClassFileConstants.AccAbstract | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp);
+ | ClassFileConstants.AccAbstract | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal
+ | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp);
if ((realModifiers & unexpectedModifiers) != 0) {
scope.problemReporter().illegalModifierForMethod(this);
declaredModifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~unexpectedModifiers;
}
// check for incompatible modifiers in the visibility bits, isolate the visibility bits
- int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate);
+ int accessorBits = realModifiers
+ & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate);
if ((accessorBits & (accessorBits - 1)) != 0) {
scope.problemReporter().illegalVisibilityModifierCombinationForMethod(onTypeBinding, this);
// check for modifiers incompatible with abstract modifier
if ((declaredModifiers & ClassFileConstants.AccAbstract) != 0) {
- int incompatibleWithAbstract = ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp;
+ int incompatibleWithAbstract = ClassFileConstants.AccStatic | ClassFileConstants.AccFinal
+ | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp;
if ((declaredModifiers & incompatibleWithAbstract) != 0)
scope.problemReporter().illegalAbstractModifierCombinationForMethod(onTypeBinding, this);
if (!onTypeBinding.isAbstract())
scope.problemReporter().abstractMethodInAbstractClass((SourceTypeBinding) onTypeBinding, this);
}
- /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final)
- // methods from a final class are final : 8.4.3.3
- if (methodBinding.declaringClass.isFinal())
- modifiers |= AccFinal;
- */
+ /*
+ * DISABLED for backward compatibility with javac (if enabled should also mark private methods as final) // methods from a
+ * final class are final : 8.4.3.3 if (methodBinding.declaringClass.isFinal()) modifiers |= AccFinal;
+ */
// native methods cannot also be tagged as strictfp
if ((declaredModifiers & ClassFileConstants.AccNative) != 0 && (declaredModifiers & ClassFileConstants.AccStrictfp) != 0)
scope.problemReporter().nativeMethodsCannotBeStrictfp(onTypeBinding, this);
scope.problemReporter().unexpectedStaticModifierForMethod(onTypeBinding, this);
// restore the true selector now that any problems have been reported
- this.selector = realSelector;
+ this.selector = realSelector;
}
}