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

InterTypeFieldDeclaration.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.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.ArrayAllocationExpression;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.AjcMemberMaker;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.NewFieldTypeMunger;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.UnresolvedType;

/**
 * An inter-type field declaration.
 * 
 * returnType encodes the type of the field selector encodes the name statements is null until resolution when it is filled in from
 * the initializer
 * 
 * @author Jim Hugunin
 */
00055 public class InterTypeFieldDeclaration extends InterTypeDeclaration {
      public Expression initialization;
      private TypeBinding realFieldType;

      // public InterTypeFieldBinding interBinding;

      public InterTypeFieldDeclaration(CompilationResult result, TypeReference onType) {
            super(result, onType);
      }

      public TypeBinding getRealFieldType() {
            return realFieldType;
      }

      public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
            // we don't have a body to parse
      }

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

      public void resolveOnType(ClassScope classScope) {
            super.resolveOnType(classScope);
            if (ignoreFurtherInvestigation)
                  return;
            if (Modifier.isStatic(declaredModifiers) && onTypeBinding.isInterface()) {
                  scope.problemReporter().signalError(sourceStart, sourceEnd, "static inter-type field on interface not supported");
                  ignoreFurtherInvestigation = true;
            }
            if (Modifier.isStatic(declaredModifiers) && typeVariableAliases != null && typeVariableAliases.size() > 0
                        && onTypeBinding.isGenericType()) {
                  scope.problemReporter().signalError(sourceStart, sourceEnd,
                              "static intertype field declarations cannot refer to type variables from the target generic type");
            }

      }

      public void resolve(ClassScope upperScope) {
            if (munger == null)
                  ignoreFurtherInvestigation = true;
            if (ignoreFurtherInvestigation)
                  return;

            EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(upperScope);
            ResolvedMember sig = munger.getSignature();
            UnresolvedType aspectType = world.fromBinding(upperScope.referenceContext.binding);

            if (sig.getReturnType() == ResolvedType.VOID
                        || (sig.getReturnType().isArray() && (sig.getReturnType().getComponentType() == ResolvedType.VOID))) {
                  upperScope.problemReporter().signalError(sourceStart, sourceEnd, "field type can not be void");
            }

            //
            // System.err.println("sig: " + sig);
            // System.err.println("field: " + world.makeFieldBinding(
            // AjcMemberMaker.interFieldClassField(sig, aspectType)));

            if (initialization != null && initialization instanceof ArrayInitializer) {
                  // System.err.println("got initializer: " + initialization);
                  ArrayAllocationExpression aae = new ArrayAllocationExpression();
                  aae.initializer = (ArrayInitializer) initialization;
                  ArrayBinding arrayType = (ArrayBinding) world.makeTypeBinding(sig.getReturnType());
                  aae.type = AstUtil.makeTypeReference(arrayType.leafComponentType());
                  aae.sourceStart = initialization.sourceStart;
                  aae.sourceEnd = initialization.sourceEnd;
                  aae.dimensions = new Expression[arrayType.dimensions];
                  initialization = aae;
            } /*
             * else if (initialization!=null) { MethodScope initializationScope = this.scope; TypeBinding fieldType = realFieldType;
             * TypeBinding initializationType; this.initialization.setExpectedType(fieldType); // needed in case of generic method
             * invocation if (this.initialization instanceof ArrayInitializer) {
             * 
             * if ((initializationType = this.initialization.resolveTypeExpecting(initializationScope, fieldType)) != null) {
             * ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationType;
             * this.initialization.computeConversion(initializationScope, fieldType, initializationType); } } //
             * System.err.println("i=>"+initialization); // System.err.println("sasuages=>"+initialization.resolvedType); //
             * //initializationType = initialization.resolveType(initializationScope); //
             * System.err.println("scope=>"+initializationScope);
             * 
             * else if ((initializationType = this.initialization.resolveType(initializationScope)) != null) {
             * 
             * if (fieldType != initializationType) // must call before computeConversion() and typeMismatchError()
             * initializationScope.compilationUnitScope().recordTypeConversion(fieldType, initializationType); if
             * (this.initialization.isConstantValueOfTypeAssignableToType(initializationType, fieldType) || (fieldType.isBaseType() &&
             * BaseTypeBinding.isWidening(fieldType.id, initializationType.id)) || initializationType.isCompatibleWith(fieldType)) {
             * initialization.computeConversion(initializationScope, fieldType, initializationType); if
             * (initializationType.needsUncheckedConversion(fieldType)) {
             * initializationScope.problemReporter().unsafeTypeConversion(this.initialization, initializationType, fieldType); } } else
             * if (initializationScope.isBoxingCompatibleWith(initializationType, fieldType) || (initializationType.isBaseType() //
             * narrowing then boxing ? && initializationScope.compilerOptions().sourceLevel >= JDK1_5 // autoboxing &&
             * !fieldType.isBaseType() && initialization.isConstantValueOfTypeAssignableToType(initializationType,
             * initializationScope.environment().computeBoxingType(fieldType)))) {
             * this.initialization.computeConversion(initializationScope, fieldType, initializationType); } else {
             * initializationScope.problemReporter().typeMismatchError(initializationType, fieldType, this); } // if
             * (this.binding.isFinal()){ // cast from constant actual type to variable type //
             * this.binding.setConstant(this.initialization.constant.castTo((this.binding.returnType.id << 4) +
             * this.initialization.constant.typeID())); // } // } else { // this.binding.setConstant(NotAConstant); } // }
             */

            // ////////////////////

            if (initialization == null) {
                  this.statements = new Statement[] { new ReturnStatement(null, 0, 0), };
            } else if (!onTypeBinding.isInterface()) {
                  MethodBinding writeMethod = world.makeMethodBinding(AjcMemberMaker.interFieldSetDispatcher(sig, aspectType), munger
                              .getTypeVariableAliases());
                  // For the body of an intertype field initalizer, generate a call to the inter field set dispatcher
                  // method as that casts the shadow of a field set join point.
                  if (Modifier.isStatic(declaredModifiers)) {
                        this.statements = new Statement[] { new KnownMessageSend(writeMethod, AstUtil
                                    .makeNameReference(writeMethod.declaringClass), new Expression[] { initialization }), };
                  } else {
                        this.statements = new Statement[] { new KnownMessageSend(writeMethod, AstUtil
                                    .makeNameReference(writeMethod.declaringClass), new Expression[] {
                                    AstUtil.makeLocalVariableReference(arguments[0].binding), initialization }), };
                  }
            } else {
                  // XXX something is broken about this logic. Can we write to static interface fields?
                  MethodBinding writeMethod = world.makeMethodBinding(AjcMemberMaker.interFieldInterfaceSetter(sig, sig
                              .getDeclaringType().resolve(world.getWorld()), aspectType), munger.getTypeVariableAliases());
                  if (Modifier.isStatic(declaredModifiers)) {
                        this.statements = new Statement[] { new KnownMessageSend(writeMethod, AstUtil
                                    .makeNameReference(writeMethod.declaringClass), new Expression[] { initialization }), };
                  } else {
                        this.statements = new Statement[] { new KnownMessageSend(writeMethod, AstUtil
                                    .makeLocalVariableReference(arguments[0].binding), new Expression[] { initialization }), };
                  }
            }

            super.resolve(upperScope);
      }

      public void setInitialization(Expression initialization) {
            this.initialization = initialization;

      }

      /*
       * public void resolveStatements() { super.resolveStatements();
       * 
       * // if (initialization!=null) { // MethodScope initializationScope = this.scope; // TypeBinding fieldType = realFieldType; //
       * TypeBinding initializationType; // this.initialization.setExpectedType(fieldType); // needed in case of generic method
       * invocation // if (this.initialization instanceof ArrayInitializer) { // // if ((initializationType =
       * this.initialization.resolveTypeExpecting(initializationScope, fieldType)) != null) { // ((ArrayInitializer)
       * this.initialization).binding = (ArrayBinding) initializationType; //
       * this.initialization.computeConversion(initializationScope, fieldType, initializationType); // } // } ////
       * System.err.println("i=>"+initialization); //// System.err.println("sasuages=>"+initialization.resolvedType); ////
       * //initializationType = initialization.resolveType(initializationScope); ////
       * System.err.println("scope=>"+initializationScope); // // else if ((initializationType =
       * this.initialization.resolveType(initializationScope)) != null) { // // if (fieldType != initializationType) // must call
       * before computeConversion() and typeMismatchError() //
       * initializationScope.compilationUnitScope().recordTypeConversion(fieldType, initializationType); // if
       * (this.initialization.isConstantValueOfTypeAssignableToType(initializationType, fieldType) // || (fieldType.isBaseType() &&
       * BaseTypeBinding.isWidening(fieldType.id, initializationType.id)) // || initializationType.isCompatibleWith(fieldType)) { //
       * initialization.computeConversion(initializationScope, fieldType, initializationType); // if
       * (initializationType.needsUncheckedConversion(fieldType)) { //
       * initializationScope.problemReporter().unsafeTypeConversion(this.initialization, initializationType, fieldType); // } // }
       * else if (initializationScope.isBoxingCompatibleWith(initializationType, fieldType) // || (initializationType.isBaseType() //
       * narrowing then boxing ? // && initializationScope.compilerOptions().sourceLevel >= JDK1_5 // autoboxing // &&
       * !fieldType.isBaseType() // && initialization.isConstantValueOfTypeAssignableToType(initializationType,
       * initializationScope.environment().computeBoxingType(fieldType)))) { //
       * this.initialization.computeConversion(initializationScope, fieldType, initializationType); // } else { //
       * initializationScope.problemReporter().typeMismatchError(initializationType, fieldType, this); // } // // if
       * (this.binding.isFinal()){ // cast from constant actual type to variable type // //
       * this.binding.setConstant(this.initialization.constant.castTo((this.binding.returnType.id << 4) +
       * this.initialization.constant.typeID())); // // } // // } else { // // this.binding.setConstant(NotAConstant); // }}
       * 
       * }
       */
00225       public EclipseTypeMunger build(ClassScope classScope) {
            EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
            resolveOnType(classScope);

            if (ignoreFurtherInvestigation)
                  return null;

            binding = classScope.referenceContext.binding.resolveTypesFor(binding);
            if (ignoreFurtherInvestigation)
                  return null;

            if (isTargetAnnotation(classScope, "field"))
                  return null; // Error message output in isTargetAnnotation
            if (isTargetEnum(classScope, "field"))
                  return null; // Error message output in isTargetEnum

            if (!Modifier.isStatic(declaredModifiers)) {
                  super.binding.parameters = new TypeBinding[] { onTypeBinding, };
                  this.arguments = new Argument[] { AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding), };
            }

            // System.err.println("type: " + binding.returnType + ", " + returnType);
            ResolvedType declaringType = world.fromBinding(onTypeBinding).resolve(world.getWorld());
            if (declaringType.isRawType() || declaringType.isParameterizedType()) {
                  declaringType = declaringType.getGenericType();
            }

            if (interTypeScope == null)
                  return null; // We encountered a problem building the scope, don't continue - error already reported

            // Build a half correct resolvedmember (makeResolvedMember understands tvars) then build a fully correct sig from it
            ResolvedMember sigtemp = world.makeResolvedMemberForITD(binding, onTypeBinding, interTypeScope.getRecoveryAliases());
            UnresolvedType returnType = sigtemp.getReturnType();
            // if (returnType.isParameterizedType() || returnType.isGenericType()) returnType = returnType.getRawType();
            ResolvedMember sig = new ResolvedMemberImpl(Member.FIELD, declaringType, declaredModifiers, returnType, new String(
                        declaredSelector), UnresolvedType.NONE);
            sig.setTypeVariables(sigtemp.getTypeVariables());

            NewFieldTypeMunger myMunger = new NewFieldTypeMunger(sig, null, typeVariableAliases);
            setMunger(myMunger);
            ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding);
            ResolvedMember me = myMunger.getInitMethod(aspectType);
            this.selector = binding.selector = me.getName().toCharArray();
            this.realFieldType = this.binding.returnType;
            this.binding.returnType = TypeBinding.VOID;
            // ??? all other pieces should already match

            return new EclipseTypeMunger(world, myMunger, aspectType, this);
      }

      private AjAttribute makeAttribute() {
            return new AjAttribute.TypeMunger(munger);
      }

      public void generateCode(ClassScope classScope, ClassFile classFile) {
            if (ignoreFurtherInvestigation)
                  return;

            classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute()));
            super.generateCode(classScope, classFile);
            generateDispatchMethods(classScope, classFile);
            // interBinding.reader.generateMethod(this, classScope, classFile);
            // interBinding.writer.generateMethod(this, classScope, classFile);
      }

      private void generateDispatchMethods(ClassScope classScope, ClassFile classFile) {
            EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
            ResolvedMember sig = munger.getSignature();
            UnresolvedType aspectType = world.fromBinding(classScope.referenceContext.binding);
            generateDispatchMethod(world, sig, aspectType, classScope, classFile, true);
            generateDispatchMethod(world, sig, aspectType, classScope, classFile, false);
      }

      private void generateDispatchMethod(EclipseFactory world, ResolvedMember sig, UnresolvedType aspectType, ClassScope classScope,
                  ClassFile classFile, boolean isGetter) {
            MethodBinding binding;
            if (isGetter) {
                  binding = world.makeMethodBinding(AjcMemberMaker.interFieldGetDispatcher(sig, aspectType), munger
                              .getTypeVariableAliases(), munger.getSignature().getDeclaringType());
            } else {
                  binding = world.makeMethodBinding(AjcMemberMaker.interFieldSetDispatcher(sig, aspectType), munger
                              .getTypeVariableAliases(), munger.getSignature().getDeclaringType());
            }
            classFile.generateMethodInfoHeader(binding);
            int methodAttributeOffset = classFile.contentsOffset;
            int attributeNumber = classFile.generateMethodInfoAttribute(binding, false, makeEffectiveSignatureAttribute(sig,
                        isGetter ? Shadow.FieldGet : Shadow.FieldSet, false));
            int codeAttributeOffset = classFile.contentsOffset;
            classFile.generateCodeAttributeHeader();
            CodeStream codeStream = classFile.codeStream;
            codeStream.reset(this, classFile);

            FieldBinding classField = world.makeFieldBinding(AjcMemberMaker.interFieldClassField(sig, aspectType), munger
                        .getTypeVariableAliases());

            codeStream.initializeMaxLocals(binding);
            if (isGetter) {
                  if (onTypeBinding.isInterface()) {
                        UnresolvedType declaringTX = sig.getDeclaringType();
                        ResolvedType declaringRTX = world.getWorld().resolve(declaringTX, munger.getSourceLocation());
                        MethodBinding readMethod = world.makeMethodBinding(AjcMemberMaker.interFieldInterfaceGetter(sig, declaringRTX,
                                    aspectType), munger.getTypeVariableAliases());
                        generateInterfaceReadBody(binding, readMethod, codeStream);
                  } else {
                        generateClassReadBody(binding, classField, codeStream);
                  }
            } else {
                  if (onTypeBinding.isInterface()) {
                        MethodBinding writeMethod = world.makeMethodBinding(AjcMemberMaker.interFieldInterfaceSetter(sig, world.getWorld()
                                    .resolve(sig.getDeclaringType(), munger.getSourceLocation()), aspectType), munger.getTypeVariableAliases());
                        generateInterfaceWriteBody(binding, writeMethod, codeStream);
                  } else {
                        generateClassWriteBody(binding, classField, codeStream);
                  }
            }
            AstUtil.generateReturn(binding.returnType, codeStream);

            classFile.completeCodeAttribute(codeAttributeOffset);
            attributeNumber++;
            classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
      }

      private void generateInterfaceReadBody(MethodBinding binding, MethodBinding readMethod, CodeStream codeStream) {
            codeStream.aload_0();
            codeStream.invokeinterface(readMethod);
      }

      private void generateInterfaceWriteBody(MethodBinding binding, MethodBinding writeMethod, CodeStream codeStream) {
            codeStream.aload_0();
            codeStream.load(writeMethod.parameters[0], 1);
            codeStream.invokeinterface(writeMethod);
      }

      private void generateClassReadBody(MethodBinding binding, FieldBinding field, CodeStream codeStream) {
            if (field.isStatic()) {
                  codeStream.getstatic(field);
            } else {
                  codeStream.aload_0();
                  codeStream.getfield(field);
            }
      }

      private void generateClassWriteBody(MethodBinding binding, FieldBinding field, CodeStream codeStream) {
            if (field.isStatic()) {
                  codeStream.load(field.type, 0);
                  codeStream.putstatic(field);
            } else {
                  codeStream.aload_0();
                  codeStream.load(field.type, 1);
                  codeStream.putfield(field);
            }
      }

      protected Shadow.Kind getShadowKindForBody() {
            return null;
      }

}

Generated by  Doxygen 1.6.0   Back to index