| /* ******************************************************************* |
| * 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.lookup; |
| |
| import org.aspectj.ajdt.internal.compiler.ast.InterTypeMethodDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.IPrivilegedHandler; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.InvocationSite; |
| 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.weaver.AjcMemberMaker; |
| import org.aspectj.weaver.Member; |
| import org.aspectj.weaver.ResolvedMember; |
| import org.aspectj.weaver.ResolvedTypeMunger; |
| import org.aspectj.weaver.UnresolvedType; |
| |
| /** |
| * A special method binding representing an ITD that pretends to be a member in some target type for matching purposes. |
| */ |
| public class InterTypeMethodBinding extends MethodBinding { |
| |
| /** The target type upon which the ITD is declared */ |
| private ReferenceBinding targetType; |
| |
| /** |
| * This is the 'pretend' method that should be the target of any attempt to call the ITD'd method. |
| */ |
| private MethodBinding syntheticMethod; |
| |
| public MethodBinding postDispatchMethod; |
| |
| public AbstractMethodDeclaration sourceMethod; |
| |
| public InterTypeMethodBinding(EclipseFactory world, ResolvedTypeMunger munger, UnresolvedType withinType, |
| AbstractMethodDeclaration sourceMethod) { |
| super(); |
| ResolvedMember signature = munger.getSignature(); |
| MethodBinding mb = world.makeMethodBinding(signature, munger.getTypeVariableAliases()); |
| this.modifiers = mb.modifiers; |
| this.selector = mb.selector; |
| this.returnType = mb.returnType; |
| this.parameters = mb.parameters; |
| this.thrownExceptions = mb.thrownExceptions; |
| this.typeVariables = mb.typeVariables; |
| this.sourceMethod = sourceMethod; |
| this.targetType = (ReferenceBinding) world.makeTypeBinding(signature.getDeclaringType()); |
| this.declaringClass = (ReferenceBinding) world.makeTypeBinding(withinType); |
| |
| // Ok, we need to set the typevariable declaring elements |
| // 1st set: |
| // If the typevariable is one declared on the source method, then we know we are the declaring element |
| for (int i = 0; i < typeVariables.length; i++) { |
| typeVariables[i].declaringElement = this; |
| } |
| for (int i = 0; i < typeVariables.length; i++) { |
| if (typeVariables[i].declaringElement == null) |
| throw new RuntimeException("Declaring element not set"); |
| |
| } |
| // typeVariables[0].declaringElement=this; |
| // if (tVar.getDeclaringElement() instanceof Member) { |
| // declaringElement = makeMethodBinding((ResolvedMember)tVar.getDeclaringElement()); |
| // } else { |
| // declaringElement = makeTypeBinding((UnresolvedType)tVar.getDeclaringElement()); |
| // } |
| if (signature.getKind() == Member.METHOD) { |
| syntheticMethod = world.makeMethodBinding(AjcMemberMaker.interMethodDispatcher(signature, withinType)); |
| postDispatchMethod = world.makeMethodBinding(AjcMemberMaker.interMethodBody(signature, withinType)); |
| } else { |
| syntheticMethod = world.makeMethodBinding(AjcMemberMaker.interConstructor(world.getWorld().resolve( |
| signature.getDeclaringType()), signature, withinType)); |
| postDispatchMethod = syntheticMethod; |
| } |
| |
| } |
| |
| // XXX this is identical to InterTypeFieldBinding |
| public boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) { |
| scope.compilationUnitScope().recordTypeReference(declaringClass); |
| |
| if (isPublic()) |
| return true; |
| |
| SourceTypeBinding invocationType = scope.invocationType(); |
| // System.out.println("receiver: " + receiverType + ", " + invocationType); |
| |
| if (invocationType == declaringClass) |
| return true; |
| |
| if (invocationType.privilegedHandler != null) { |
| // it is a privileged aspect |
| return true; |
| } |
| |
| if (isProtected()) { |
| throw new RuntimeException("unimplemented"); |
| } |
| |
| // XXX make sure this walks correctly |
| if (isPrivate()) { |
| // Possibly the call is made from an inner type within the privileged aspect |
| // TODO should check the first outer aspect we come across and stop at that point? |
| if (invocationType.isNestedType()) { |
| TypeBinding enclosingType = invocationType.enclosingType(); |
| while (enclosingType != null) { |
| if ((enclosingType instanceof SourceTypeBinding) && ((SourceTypeBinding)enclosingType).privilegedHandler != null) { |
| return true; |
| } |
| enclosingType = enclosingType.enclosingType(); |
| } |
| } |
| |
| // answer true if the receiverType is the declaringClass |
| // AND the invocationType and the declaringClass have a common enclosingType |
| // if (receiverType != declaringClass) return false; |
| |
| if (invocationType != declaringClass) { |
| ReferenceBinding outerInvocationType = invocationType; |
| ReferenceBinding temp = outerInvocationType.enclosingType(); |
| while (temp != null) { |
| outerInvocationType = temp; |
| temp = temp.enclosingType(); |
| } |
| |
| ReferenceBinding outerDeclaringClass = declaringClass; |
| temp = outerDeclaringClass.enclosingType(); |
| while (temp != null) { |
| outerDeclaringClass = temp; |
| temp = temp.enclosingType(); |
| } |
| |
| // System.err.println("outer dec: " + |
| if (outerInvocationType != outerDeclaringClass) |
| return false; |
| } |
| return true; |
| } |
| |
| // isDefault() |
| if (invocationType.fPackage == declaringClass.fPackage) |
| return true; |
| return false; |
| } |
| |
| public boolean isFinal() { |
| if (sourceMethod == null || !(sourceMethod instanceof InterTypeMethodDeclaration)) |
| return super.isFinal(); |
| return ((InterTypeMethodDeclaration) sourceMethod).isFinal(); |
| } |
| |
| public MethodBinding getAccessMethod(boolean staticReference) { |
| if (staticReference) |
| return postDispatchMethod; |
| else |
| return syntheticMethod; |
| } |
| |
| public boolean alwaysNeedsAccessMethod() { |
| return true; |
| } |
| |
| public AbstractMethodDeclaration sourceMethod() { |
| return sourceMethod; |
| } |
| |
| public ReferenceBinding getTargetType() { |
| return targetType; |
| } |
| |
| // override method in MethodBinding to ensure correct behaviour in some of JDTs generics checks. |
| public ReferenceBinding getOwningClass() { |
| return targetType; |
| } |
| |
| public String toString() { |
| return "InterTypeMethodBinding(" + super.toString() + ", " + getTargetType() + ")"; |
| } |
| } |