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

org.aspectj.ajdt.internal.compiler.ast.IntertypeMemberClassDeclaration 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) 2010 Contributors
 * 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:
 *     Andy Clement - SpringSource
 * ******************************************************************/
package org.aspectj.ajdt.internal.compiler.ast;

import java.lang.reflect.Modifier;
import java.util.Collections;

import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceLocation;
import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger;
import org.aspectj.ajdt.internal.compiler.lookup.InterTypeScope;
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.TypeDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.NewMemberClassTypeMunger;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ResolvedTypeMunger;

/**
 * Represents an intertype member class declaration.
 *
 * @author Andy Clement
 * @since 1.6.9
 */
public class IntertypeMemberClassDeclaration extends TypeDeclaration {

	// The target type for this inner class
	private TypeReference onType;
	private ReferenceBinding onTypeResolvedBinding;
	private NewMemberClassTypeMunger newMemberClassTypeMunger;
	protected InterTypeScope interTypeScope;
	// When set to true, the scope hierarchy for the field/method declaration has been correctly modified to include an intertype
	// scope which resolves things relative to the targeted type.
	private boolean scopeSetup = false;

	public IntertypeMemberClassDeclaration(CompilationResult compilationResult) {
		super(compilationResult);
	}

	public ResolvedTypeMunger getMunger() {
		return newMemberClassTypeMunger;
	}

	@Override
	public void resolve(ClassScope aspectScope) {
		resolveOnType(aspectScope);
		ensureScopeSetup();
		super.resolve(aspectScope);
	}

	/**
	 * Bytecode generation for a member inner type
	 */
	/*
	 * public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) { if ((this.bits & ASTNode.HasBeenGenerated) !=
	 * 0) { return; } try { Field f = ReferenceBinding.class.getDeclaredField("constantPoolName"); char[] name =
	 * CharOperation.concat(onTypeResolvedBinding.constantPoolName(), binding.sourceName, '$'); f.setAccessible(true);
	 * f.set(this.binding, name); } catch (Exception e) { e.printStackTrace(); } if (this.binding != null) { ((NestedTypeBinding)
	 * this.binding).computeSyntheticArgumentSlotSizes(); } generateCode(enclosingClassFile); }
	 */
	@Override
	public void resolve() {
		super.resolve();
	}

	@Override
	public void resolve(BlockScope blockScope) {
		throw new IllegalStateException();
	}

	@Override
	public void resolve(CompilationUnitScope upperScope) {
		throw new IllegalStateException();
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void generateAttributes(ClassFile classFile) {
		// classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute()));
		super.generateAttributes(classFile);
	}

	public AjAttribute getAttribute() {
		// if there were problems then there is nothing to return
		if (newMemberClassTypeMunger == null) {
			return null;
		}
		return new AjAttribute.TypeMunger(newMemberClassTypeMunger);
	}

	/**
	 * Called just before the compiler is going to start resolving elements of a declaration, this method adds an intertype scope so
	 * that elements of the type targeted by the ITD can be resolved. For example, if type variables are referred to in the ontype
	 * for the ITD, they have to be resolved against the ontype, not the aspect containing the ITD.
	 */
	public void ensureScopeSetup() {
		if (scopeSetup) {
			return; // don't do it again
		}
		ClassScope scope = this.scope;

		// TODO [inner] ton of stuff related to parameterization support

		// if (ot instanceof ParameterizedQualifiedTypeReference) { // pr132349
		// ParameterizedQualifiedTypeReference pref = (ParameterizedQualifiedTypeReference) ot;
		// if (pref.typeArguments != null && pref.typeArguments.length != 0) {
		// boolean usingNonTypeVariableInITD = false;
		// // Check if any of them are not type variables
		// for (int i = 0; i < pref.typeArguments.length; i++) {
		// TypeReference[] refs = pref.typeArguments[i];
		// for (int j = 0; refs != null && j < refs.length; j++) {
		// TypeBinding tb = refs[j].getTypeBindingPublic(scope.parent);
		// if (!tb.isTypeVariable() && !(tb instanceof ProblemReferenceBinding)) {
		// usingNonTypeVariableInITD = true;
		// }
		//
		// }
		// }
		// if (usingNonTypeVariableInITD) {
		// scope.problemReporter().signalError(sourceStart, sourceEnd,
		// "Cannot make inter-type declarations on parameterized types");
		// // to prevent disgusting cascading errors after this problem - lets null out what leads to them (pr105038)
		// this.arguments = null;
		// this.returnType = new SingleTypeReference(TypeReference.VOID, 0L);
		//
		// this.ignoreFurtherInvestigation = true;
		// ReferenceBinding closestMatch = null;
		// rb = new ProblemReferenceBinding(ot.getParameterizedTypeName(), closestMatch, 0);
		// onType = null;
		// }
		// }
		//
		// }

		// // Work out the real base type
		// if (onType instanceof ParameterizedSingleTypeReference) {
		// ParameterizedSingleTypeReference pref = (ParameterizedSingleTypeReference) ot;
		// long pos = (((long) pref.sourceStart) << 32) | pref.sourceEnd;
		// ot = new SingleTypeReference(pref.token, pos);
		// } else if (ot instanceof ParameterizedQualifiedTypeReference) {
		// ParameterizedQualifiedTypeReference pref = (ParameterizedQualifiedTypeReference) ot;
		// long pos = (((long) pref.sourceStart) << 32) | pref.sourceEnd;
		// ot = new QualifiedTypeReference(pref.tokens, new long[] { pos });// SingleTypeReference(pref.Quatoken,pos);
		// }

		// resolve it
		// if (rb == null) {
		// rb = (ReferenceBinding) ot.getTypeBindingPublic(scope.parent);
		// }

		// pr203646 - if we have ended up with the raw type, get back to the underlying generic one.
		// if (rb.isRawType() && rb.isMemberType()) {
		// // if the real target type used a type variable alias then we can do this OK, but need to switch things around, we want
		// // the generic type
		// rb = ((RawTypeBinding) rb).type;
		// }

		// if (rb instanceof TypeVariableBinding) {
		// scope.problemReporter().signalError(sourceStart, sourceEnd,
		// "Cannot make inter-type declarations on type variables, use an interface and declare parents");
		// // to prevent disgusting cascading errors after this problem - lets null out what leads to them (pr105038)
		// this.arguments = null;
		// this.returnType = new SingleTypeReference(TypeReference.VOID, 0L);
		//
		// this.ignoreFurtherInvestigation = true;
		// ReferenceBinding closestMatch = null;
		// if (((TypeVariableBinding) rb).firstBound != null) {
		// closestMatch = ((TypeVariableBinding) rb).firstBound.enclosingType();
		// }
		// rb = new ProblemReferenceBinding(rb.compoundName, closestMatch, 0);
		// }

		// if resolution failed, give up - someone else is going to report an error
		// if (rb instanceof ProblemReferenceBinding) {
		// return;
		// }
		if (scope != null) {
			interTypeScope = new InterTypeScope(scope.parent, onTypeResolvedBinding, Collections.emptyList());
			// FIXME asc verify the choice of lines here...
			// Two versions of this next line.
			// First one tricks the JDT variable processing code so that it won't complain if
			// you refer to a type variable from a static ITD - it *is* a problem and it *will* be caught, but later and
			// by the AJDT code so we can put out a much nicer message.
			// scope.isStatic = (typeVariableAliases != null ? false : Modifier.isStatic(declaredModifiers));
			// this is the original version in case tricking the JDT causes grief (if you reinstate this variant, you
			// will need to change the expected messages output for some of the generic ITD tests)
			// scope.isStatic = Modifier.isStatic(declaredModifiers);
			// Use setter in order to also update member 'compilationUnitScope'
			scope.setParent(interTypeScope);
		}
		scopeSetup = true;
	}

	public void setOnType(TypeReference onType) {
		this.onType = onType;
	}

	private void resolveOnType(ClassScope cuScope) {
		if (onType == null || onTypeResolvedBinding != null) {
			return;
		} // error reported elsewhere.

		onTypeResolvedBinding = (ReferenceBinding) onType.getTypeBindingPublic(cuScope);
		if (!onTypeResolvedBinding.isValidBinding()) {
			cuScope.problemReporter().invalidType(onType, onTypeResolvedBinding);
			ignoreFurtherInvestigation = true;
		} else {
			// fix up the ITD'd type?
			if (this.binding != null) {
				((NestedTypeBinding) this.binding).enclosingType = (SourceTypeBinding) onTypeResolvedBinding;
			}
			// this done at build type for the nested type now:
			// ((NestedTypeBinding) this.binding).compoundName = CharOperation.splitOn('.', "Basic$_".toCharArray());
		}
	}

	public EclipseTypeMunger build(ClassScope classScope) {
		EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
		resolveOnType(classScope);
		ensureScopeSetup();

		if (ignoreFurtherInvestigation) {
			return null;
		}

		if (onTypeResolvedBinding.isInterface() || onTypeResolvedBinding.isEnum() || onTypeResolvedBinding.isAnnotationType()) {
			scope.problemReporter().signalError(
					sourceStart,
					sourceEnd,
					"Cannot declare new member type on '" + onType.toString()
							+ "'. New member types can only be specified on classes (compiler limitation)");
			return null;
		}

		if (!Modifier.isStatic(modifiers)) {
			scope.problemReporter().signalError(sourceStart, sourceEnd,
					"Intertype declared member types can only be static (compiler limitation)");
			return null;
		}

		ResolvedType declaringType = world.fromBinding(onTypeResolvedBinding).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
		}

		// TODO [inner] use the interTypeScope.getRecoveryAliases
		// TODO [inner] should mark it in the aspect as unreachable - it is not to be considered part of the aspect
		newMemberClassTypeMunger = new NewMemberClassTypeMunger(declaringType, new String(this.name));
		newMemberClassTypeMunger.setSourceLocation(new EclipseSourceLocation(compilationResult, sourceStart, sourceEnd));
		ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding);
		return new EclipseTypeMunger(world, newMemberClassTypeMunger, aspectType, null);
	}

	public char[] alternativeName() {
		return CharOperation.concatWith(onType.getTypeName(),'.');//onType.getLastToken();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy