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

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

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 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.*;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.weaver.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
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.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;

/**
 * An inter-type constructor declaration.
 * 
 * This will generate two implementation methods in the aspect, the main one for the body
 * of the constructor, and an additional preMethod for the code that 
 * runs before the super constructor is called.
 * 
 * @author Jim Hugunin
 */
public class InterTypeConstructorDeclaration extends InterTypeDeclaration {	
	private static final String SUPPRESSAJWARNINGS = "Lorg/aspectj/lang/annotation/SuppressAjWarnings;";
	private static final String NOEXPLICITCONSTRUCTORCALL = "noExplicitConstructorCall";
	private MethodDeclaration preMethod;
	private ExplicitConstructorCall explicitConstructorCall = null;
	
	public InterTypeConstructorDeclaration(CompilationResult result, TypeReference onType) {
		super(result, onType);
	}
	
	public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
		if (ignoreFurtherInvestigation)
			return;
	    parser.parse(this, unit); 
	}
	
	protected char[] getPrefix() {
		return (NameMangler.ITD_PREFIX + "interConstructor$").toCharArray();
	}

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

		explicitConstructorCall = null;
		if (statements != null && statements.length > 0 && 
			statements[0] instanceof ExplicitConstructorCall)
		{
			explicitConstructorCall = (ExplicitConstructorCall) statements[0];
			statements = AstUtil.remove(0, statements);
		}
		
		preMethod = makePreMethod(upperScope, explicitConstructorCall);
		
		binding.parameters  = AstUtil.insert(onTypeBinding, binding.parameters);
		this.arguments = AstUtil.insert(
			AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding),
			this.arguments);
			
		super.resolve(upperScope);
		
		// after annotations have been resolved...
		if (explicitConstructorCall == null) {
			raiseNoFieldInitializersWarning();
		}
	}

	/**
	 * Warning added in response to PR 62606 - if an ITD constructor does not make an explicit constructor
	 * call then field initializers in the target class will not be executed leading to unexpected behaviour.
	 */
	private void raiseNoFieldInitializersWarning() {
		if (suppressingNoExplicitConstructorCall()) return;
		EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
		ISourceLocation location =
			new EclipseSourceLocation(scope.problemReporter().referenceContext.compilationResult(),
									sourceStart(),sourceEnd());
		world.getWorld().getLint().noExplicitConstructorCall.signal(null, location);
	}
	
	/**
	 * true iff constructor has @SuppressAjWarnings or @SuppressAjWarnings("xyz,noExplicitConstructorCall,def,...")
	 * @return
	 */
	private boolean suppressingNoExplicitConstructorCall() {
		if (this.annotations == null) return false;
		for (int i = 0; i < this.annotations.length; i++) {
			if (new String(this.annotations[i].resolvedType.signature()).equals(SUPPRESSAJWARNINGS)) {
				if (this.annotations[i] instanceof MarkerAnnotation) {
					return true;
				} else if (this.annotations[i] instanceof SingleMemberAnnotation){
					SingleMemberAnnotation sma = (SingleMemberAnnotation) this.annotations[i];
					if (sma.memberValue instanceof ArrayInitializer) {
						ArrayInitializer memberValue = (ArrayInitializer) sma.memberValue;
						for (int j = 0; j < memberValue.expressions.length; j++) {
							if (memberValue.expressions[j] instanceof StringLiteral) {
								StringLiteral val = (StringLiteral) memberValue.expressions[j];
								if (new String(val.source()).equals(NOEXPLICITCONSTRUCTORCALL)) return true;
							}
						}
					}
				}
			}
		}
		return false;
	}
	
	private MethodDeclaration makePreMethod(ClassScope scope, 
											ExplicitConstructorCall explicitConstructorCall)
	{
		EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
		
		UnresolvedType aspectTypeX = world.fromBinding(binding.declaringClass);
		UnresolvedType targetTypeX = world.fromBinding(onTypeBinding);
		
		ArrayBinding objectArrayBinding = scope.createArrayType(scope.getJavaLangObject(), 1);
		
		
		MethodDeclaration pre = new MethodDeclaration(compilationResult);
		pre.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic;
		pre.returnType = AstUtil.makeTypeReference(objectArrayBinding);
		pre.selector = NameMangler.postIntroducedConstructor(aspectTypeX, targetTypeX).toCharArray();
		
		
		pre.arguments = AstUtil.copyArguments(this.arguments);
		
		//XXX should do exceptions
		
		pre.scope = new MethodScope(scope, pre, true);
		//??? do we need to do anything with scope???
		
		

        // Use the factory to build a semi-correct resolvedmember - then patch it up with
        // reset calls.  This is SAFE	
		ResolvedMember preIntroducedConstructorRM = world.makeResolvedMember(binding);
		preIntroducedConstructorRM.resetName(NameMangler.preIntroducedConstructor(aspectTypeX, targetTypeX));
		preIntroducedConstructorRM.resetModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
		preIntroducedConstructorRM.resetReturnTypeToObjectArray();
		
		pre.binding = world.makeMethodBinding(preIntroducedConstructorRM);
		
		pre.bindArguments();
		pre.bindThrownExceptions();
		
		
		if (explicitConstructorCall == null) {
			pre.statements = new Statement[] {};
		} else {
			pre.statements = new Statement[] {
				explicitConstructorCall
			};
		}
		
		InterTypeScope newParent =
			new InterTypeScope(scope, onTypeBinding);
		pre.scope.parent = newParent;

		pre.resolveStatements(); //newParent);
		
		
		
		int nParams = pre.arguments.length;
		MethodBinding explicitConstructor = null;
		if (explicitConstructorCall != null) {
			explicitConstructor = explicitConstructorCall.binding;
			// If it is null then we are going to report something else is wrong with this code!
			if (explicitConstructor!=null && explicitConstructor.alwaysNeedsAccessMethod()) {
				explicitConstructor = explicitConstructor.getAccessMethod(true);
			}
		}
		
		int nExprs;
		if (explicitConstructor == null) nExprs = 0;
		else nExprs = explicitConstructor.parameters.length;
		
		
		ArrayInitializer init = new ArrayInitializer();
		init.expressions = new Expression[nExprs + nParams];
		int index = 0;
		for (int i=0; i < nExprs; i++) {
			if (i >= explicitConstructorCall.arguments.length) {
				init.expressions[index++] = new NullLiteral(0, 0);
				continue;
			}
			
			
			Expression arg = explicitConstructorCall.arguments[i];
			ResolvedMember conversionMethod = 
				AjcMemberMaker.toObjectConversionMethod(world.fromBinding(explicitConstructorCall.binding.parameters[i]));
			if (conversionMethod != null) {
				arg = new KnownMessageSend(world.makeMethodBindingForCall(conversionMethod),
					new CastExpression(new NullLiteral(0, 0), 
						AstUtil.makeTypeReference(world.makeTypeBinding(AjcMemberMaker.CONVERSIONS_TYPE))),
				    new Expression[] {arg });
			}
			init.expressions[index++] = arg;
		}
		
		for (int i=0; i < nParams; i++) {
			LocalVariableBinding binding = pre.arguments[i].binding;
			Expression arg = AstUtil.makeResolvedLocalVariableReference(binding);
			ResolvedMember conversionMethod = 
				AjcMemberMaker.toObjectConversionMethod(world.fromBinding(binding.type));
			if (conversionMethod != null) {
				arg = new KnownMessageSend(world.makeMethodBindingForCall(conversionMethod),
					new CastExpression(new NullLiteral(0, 0), 
						AstUtil.makeTypeReference(world.makeTypeBinding(AjcMemberMaker.CONVERSIONS_TYPE))),
				    new Expression[] {arg });
			}
			init.expressions[index++] = arg;
		}
		
		init.binding =objectArrayBinding;
		
		ArrayAllocationExpression newArray = new ArrayAllocationExpression();
		newArray.initializer = init;
		newArray.type = AstUtil.makeTypeReference(scope.getJavaLangObject());
		newArray.dimensions = new Expression[1];
		newArray.constant = Constant.NotAConstant;
		

		
		
		pre.statements = new Statement[] {
			new ReturnStatement(newArray, 0, 0),
		};
		return pre;
	}





	  
	public EclipseTypeMunger build(ClassScope classScope) {
		EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
		
		resolveOnType(classScope);
		if (ignoreFurtherInvestigation) return null;
		
		binding = classScope.referenceContext.binding.resolveTypesFor(binding);
				
		if (isTargetAnnotation(classScope,"constructor")) return null; // Error message output in isTargetAnnotation
		if (isTargetEnum(classScope,"constructor")) return null;       // Error message output in isTargetEnum
		
		if (onTypeBinding.isInterface()) {
			classScope.problemReporter().signalError(sourceStart, sourceEnd,
							"can't define constructors on interfaces");
			ignoreFurtherInvestigation = true;
			return null;
		}
		
		if (onTypeBinding.isNestedType()) {
			classScope.problemReporter().signalError(sourceStart, sourceEnd,
				"can't define constructors on nested types (compiler limitation)");
			ignoreFurtherInvestigation = true;
			return null;
		}	
		
		ResolvedType declaringTypeX = world.fromEclipse(onTypeBinding);
		ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding);
		
		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'
		ResolvedMember signature = world.makeResolvedMemberForITD(binding,onTypeBinding,interTypeScope.getRecoveryAliases());
		signature.resetKind(Member.CONSTRUCTOR);
		signature.resetName("");
		int resetModifiers = declaredModifiers;
		if (binding.isVarargs())  resetModifiers = resetModifiers | Constants.ACC_VARARGS;
		signature.resetModifiers(resetModifiers);
		
		ResolvedMember syntheticInterMember =
			AjcMemberMaker.interConstructor(declaringTypeX,  signature, aspectType);
		
		NewConstructorTypeMunger myMunger = 
			new NewConstructorTypeMunger(signature, syntheticInterMember, null, null,typeVariableAliases);
		setMunger(myMunger);
		myMunger.check(world.getWorld());
		
		this.selector = binding.selector =
			NameMangler.postIntroducedConstructor(
				world.fromBinding(binding.declaringClass),
				declaringTypeX).toCharArray();
		
		return new EclipseTypeMunger(world, myMunger, aspectType, this);
	}
	
	
	private AjAttribute makeAttribute(EclipseFactory world) {
		if (explicitConstructorCall != null && (explicitConstructorCall.binding!=null) && !(explicitConstructorCall.binding instanceof ProblemMethodBinding)) {
			MethodBinding explicitConstructor = explicitConstructorCall.binding;
			if (explicitConstructor.alwaysNeedsAccessMethod()) {
				explicitConstructor = explicitConstructor.getAccessMethod(true);
			}
			if (explicitConstructor instanceof ParameterizedMethodBinding) {
				explicitConstructor = explicitConstructor.original();
			}
			((NewConstructorTypeMunger)munger).setExplicitConstructor(
				world.makeResolvedMember(explicitConstructor));
		} else {
			((NewConstructorTypeMunger)munger).setExplicitConstructor(
				new ResolvedMemberImpl(Member.CONSTRUCTOR, 
					world.fromBinding(onTypeBinding.superclass()),
					0, ResolvedType.VOID, "", UnresolvedType.NONE));
		}
		return new AjAttribute.TypeMunger(munger);
	}
	
	
	public void generateCode(ClassScope classScope, ClassFile classFile) {
		if (ignoreFurtherInvestigation) return;
		EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
		classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute(world)));
		super.generateCode(classScope, classFile);
//		classFile.codeStream.generateAttributes &= ~ClassFileConstants.ATTR_VARS;
		preMethod.generateCode(classScope, classFile);
	}
	protected Shadow.Kind getShadowKindForBody() {
		return Shadow.ConstructorExecution;
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy