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 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.lookup.PrivilegedFieldBinding;
import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedHandler;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
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.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
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 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); // }}
   *
   * }
   */
  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);

    NewFieldTypeMunger fieldMunger = (NewFieldTypeMunger) munger;

        // Force use of version 1 if there is a field with that name on the type already
    if (world.getItdVersion() == 1) {
      fieldMunger.version = NewFieldTypeMunger.VersionOne;
    } else {
      if (!onTypeBinding.isInterface()) {
        FieldBinding[] existingFields = onTypeBinding.fields();
        for (int f = 0; f < existingFields.length; f++) {
          FieldBinding fieldBinding = existingFields[f];
          if (CharOperation.equals(fieldBinding.name, sig.getName().toCharArray())) {
            fieldMunger.version = NewFieldTypeMunger.VersionOne;
          }
        }
      }
    }

    FieldBinding classField = world.makeFieldBinding(AjcMemberMaker.interFieldClassField(sig, aspectType,
        fieldMunger.version == NewFieldTypeMunger.VersionTwo), 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.isPrivate() || !field.canBeSeenBy(binding.declaringClass.fPackage)) {

      PrivilegedHandler handler = (PrivilegedHandler) Scope.findPrivilegedHandler(binding.declaringClass);
      if (handler == null) {
        // one is now required!
        ReferenceBinding typebinding = binding.declaringClass;
        if (typebinding instanceof ReferenceBinding) {
          SourceTypeBinding sourceBinding = (SourceTypeBinding) typebinding;
          handler = new PrivilegedHandler((AspectDeclaration) sourceBinding.scope.referenceContext);
          sourceBinding.privilegedHandler = handler;
        }
      }
      PrivilegedFieldBinding fBinding = (PrivilegedFieldBinding) handler.getPrivilegedAccessField(field, null);

      if (field.isStatic()) {
        codeStream.invokestatic(fBinding.reader);
      } else {
        codeStream.aload_0();
        codeStream.invokestatic(fBinding.reader);
      }
      return;
    }
    if (field.isStatic()) {
      codeStream.getstatic(field);
    } else {
      codeStream.aload_0();
      codeStream.getfield(field);
    }
  }

  private void generateClassWriteBody(MethodBinding binding, FieldBinding field, CodeStream codeStream) {
    if (field.isPrivate() || !field.canBeSeenBy(binding.declaringClass.fPackage)) {
      PrivilegedFieldBinding fBinding = (PrivilegedFieldBinding) Scope.findPrivilegedHandler(binding.declaringClass)
          .getPrivilegedAccessField(field, null);

      if (field.isStatic()) {
        codeStream.load(field.type, 0);
        codeStream.invokestatic(fBinding.writer);
      } else {
        codeStream.aload_0();
        codeStream.load(field.type, 1);
        codeStream.invokestatic(fBinding.writer);
      }
      return;
    }
    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.