All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/* *******************************************************************
 * 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 v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * 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.codegen.Opcodes;
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().equals(UnresolvedType.VOID)
				|| (sig.getReturnType().isArray() && (sig.getReturnType().getComponentType().equals(UnresolvedType.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);
		if (world.getItdVersion() == 1) {
			myMunger.version = NewFieldTypeMunger.VersionOne;
		}
		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.generateMethodInfoAttributes(binding, 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 (FieldBinding fieldBinding : existingFields) {
					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,scope);
		attributeNumber++;
		classFile.completeMethodInfo(binding,methodAttributeOffset, attributeNumber);
	}

	private void generateInterfaceReadBody(MethodBinding binding, MethodBinding readMethod, CodeStream codeStream) {
		codeStream.aload_0();
		codeStream.invoke(Opcodes.OPC_invokeinterface,readMethod,null);
	}

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

	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.invoke(Opcodes.OPC_invokestatic,fBinding.reader,null);
			} else {
				codeStream.aload_0();
				codeStream.invoke(Opcodes.OPC_invokestatic,fBinding.reader,null);
			}
			return;
		}
		if (field.isStatic()) {
			codeStream.fieldAccess(Opcodes.OPC_getstatic,field,null);
		} else {
			codeStream.aload_0();
			codeStream.fieldAccess(Opcodes.OPC_getfield,field,null);
		}
	}

	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.invoke(Opcodes.OPC_invokestatic,fBinding.writer,null);
			} else {
				codeStream.aload_0();
				codeStream.load(field.type, 1);
				codeStream.invoke(Opcodes.OPC_invokestatic,fBinding.writer,null);
			}
			return;
		}
		if (field.isStatic()) {
			codeStream.load(field.type, 0);
			codeStream.fieldAccess(Opcodes.OPC_putstatic,field,null);
		} else {
			codeStream.aload_0();
			codeStream.load(field.type, 1);
			codeStream.fieldAccess(Opcodes.OPC_putfield,field,null);
		}
	}

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

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy