Logo Search packages:      
Sourcecode: aspectj version File versions  Download package

InterTypeMethodDeclaration.java

/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * 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: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.ajdt.internal.compiler.ast;

import java.lang.reflect.Modifier;

import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger;
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.codegen.CodeStream;
import org.aspectj.org.eclipse.jdt.internal.compiler.flow.FlowInfo;
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;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.AjcMemberMaker;
import org.aspectj.weaver.Constants;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.NewMethodTypeMunger;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.UnresolvedType;

/**
 * An inter-type method declaration.
 * 
 * @author Jim Hugunin
 */
00054 public class InterTypeMethodDeclaration extends InterTypeDeclaration {
      public InterTypeMethodDeclaration(CompilationResult result, TypeReference onType) {
            super(result, onType);
      }

      public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
            if (ignoreFurtherInvestigation)
                  return;
            if (!Modifier.isAbstract(declaredModifiers)) {
                  parser.parse(this, unit);
            }
      }

      protected char[] getPrefix() {
            return (NameMangler.ITD_PREFIX + "interMethod$").toCharArray();
      }

      public boolean isFinal() {
            return (declaredModifiers & ClassFileConstants.AccFinal) != 0;
      }

      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 (binding == null)
                  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);
            }

            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()) {
                        EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
                        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;
                  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;
                        // Go up the hierarchy, looking for something we override
                        ReferenceBinding supertype = onTypeBinding.superclass();
                        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;
                                    else {
                                          for (int j = 0; j < mb.parameters.length && couldBeMatch; j++) {
                                                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;
                              }
                              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 (!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");
                  }
            }
      }

00175       public EclipseTypeMunger build(ClassScope classScope) {
            EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(classScope);

            resolveOnType(classScope);
            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);
            }

            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());
            sig.resetName(new String(declaredSelector));
            int resetModifiers = declaredModifiers;
            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);
            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);
                  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
            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());

            classFile.generateMethodInfoHeader(dispatchBinding);
            int methodAttributeOffset = classFile.contentsOffset;

            // 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 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;
            int resolvedPosition;
            if (methodBinding.isStatic())
                  resolvedPosition = 0;
            else {
                  codeStream.aload_0();
                  resolvedPosition = 1;
            }
            for (int i = 0; i < length; i++) {
                  codeStream.load(parameters[i], resolvedPosition);
                  if ((parameters[i] == TypeBinding.DOUBLE) || (parameters[i] == TypeBinding.LONG))
                        resolvedPosition += 2;
                  else
                        resolvedPosition++;
            }
            // TypeBinding type;
            if (methodBinding.isStatic())
                  codeStream.invokestatic(methodBinding);
            else {
                  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 && codeStream.locals != null) {
                  for (int a = 0; a < itdArgs.length; a++) {
                        if (codeStream.locals[a] != null) {
                              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);

            // after this point, tests on the 16 bits reserved.
            int realModifiers = declaredModifiers & ExtraCompilerModifiers.AccJustFlag;

            // check for abnormal modifiers
            int unexpectedModifiers = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected
                        | 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);
            if ((accessorBits & (accessorBits - 1)) != 0) {
                  scope.problemReporter().illegalVisibilityModifierCombinationForMethod(onTypeBinding, this);

                  // need to keep the less restrictive so disable Protected/Private as necessary
                  if ((accessorBits & ClassFileConstants.AccPublic) != 0) {
                        if ((accessorBits & ClassFileConstants.AccProtected) != 0)
                              declaredModifiers &= ~ClassFileConstants.AccProtected;
                        if ((accessorBits & ClassFileConstants.AccPrivate) != 0)
                              declaredModifiers &= ~ClassFileConstants.AccPrivate;
                  } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) {
                        declaredModifiers &= ~ClassFileConstants.AccPrivate;
                  }
            }

            // check for modifiers incompatible with abstract modifier
            if ((declaredModifiers & ClassFileConstants.AccAbstract) != 0) {
                  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;
             */
            // native methods cannot also be tagged as strictfp
            if ((declaredModifiers & ClassFileConstants.AccNative) != 0 && (declaredModifiers & ClassFileConstants.AccStrictfp) != 0)
                  scope.problemReporter().nativeMethodsCannotBeStrictfp(onTypeBinding, this);

            // static members are only authorized in a static member or top level type
            if (((realModifiers & ClassFileConstants.AccStatic) != 0) && declaringClass.isNestedType() && !declaringClass.isStatic())
                  scope.problemReporter().unexpectedStaticModifierForMethod(onTypeBinding, this);

            // restore the true selector now that any problems have been reported
            this.selector = realSelector;
      }
}

Generated by  Doxygen 1.6.0   Back to index