Package org.aspectj.ajdt.internal.compiler.ast

Source Code of org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration

/* *******************************************************************
* 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 Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-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
*/
public class InterTypeFieldDeclaration extends InterTypeDeclaration {
  public Expression initialization;
  private TypeBinding realFieldType;
  //public InterTypeFieldBinding interBinding;
 
  public InterTypeFieldDeclaration(CompilationResult result, TypeReference onType) {
    super(result, onType);
  }
 
 
  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);
//    }}
   
  }*/
  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());
    ResolvedMember sig = new ResolvedMemberImpl(Member.FIELD,declaringType,declaredModifiers,
                          sigtemp.getReturnType(),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.VoidBinding;
    //??? 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;
  }

}
TOP

Related Classes of org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.