| /* ******************************************************************* |
| * Copyright (c) 2002-2014 Palo Alto Research Center, Incorporated (PARC) |
| * and Contributors |
| * 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 |
| * IBM ongoing maintenance |
| * ******************************************************************/ |
| |
| |
| package org.aspectj.ajdt.internal.compiler.ast; |
| |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CastExpression; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MessageSend; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.impl.ReferenceContext; |
| 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.MethodScope; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; |
| import org.aspectj.weaver.AdviceKind; |
| |
| /** |
| * Used to represent any method call to a method named <code>proceed</code>. During |
| * <code>resolvedType</code> it will be determined if this is actually in the body |
| * of an <code>around</code> advice and has no receiver (must be a bare proceed call, |
| * see pr 53981), and if not this will be treated like any other |
| * MessageSend. |
| * |
| * @author Jim Hugunin |
| */ |
| public class Proceed extends MessageSend { |
| public boolean inInner = false; |
| |
| public Proceed(MessageSend parent) { |
| super(); |
| |
| this.receiver = parent.receiver; |
| this.selector = parent.selector; |
| this.arguments = parent.arguments; |
| this.binding = parent.binding; |
| //this.codegenBinding = parent.codegenBinding; |
| this.syntheticAccessor = parent.syntheticAccessor; |
| this.expectedType = parent.expectedType; |
| |
| this.nameSourcePosition = parent.nameSourcePosition; |
| this.actualReceiverType = parent.actualReceiverType; |
| //this.qualifyingType = parent.qualifyingType; |
| |
| this.valueCast = parent.valueCast; |
| this.typeArguments = parent.typeArguments; |
| this.genericTypeArguments = parent.genericTypeArguments; |
| |
| this.sourceStart = parent.sourceStart; |
| this.sourceEnd = parent.sourceEnd; |
| } |
| |
| public TypeBinding resolveType(BlockScope scope) { |
| // find out if I'm really in an around body or not |
| //??? this could in theory be done by the parser, but that appears to be hard |
| AdviceDeclaration aroundDecl = findEnclosingAround(scope); |
| |
| if (aroundDecl == null) { |
| return super.resolveType(scope); |
| } |
| |
| constant = Constant.NotAConstant; |
| binding =/* codegenBinding = */aroundDecl.proceedMethodBinding; |
| |
| this.actualReceiverType = binding.declaringClass; |
| |
| int baseArgCount = 0; |
| if (arguments != null) { |
| baseArgCount = arguments.length; |
| Expression[] newArguments = new Expression[baseArgCount + 1]; |
| System.arraycopy(arguments, 0, newArguments, 0, baseArgCount); |
| arguments = newArguments; |
| } else { |
| arguments = new Expression[1]; |
| } |
| |
| arguments[baseArgCount] = AstUtil.makeLocalVariableReference(aroundDecl.extraArgument.binding); |
| |
| int declaredParameterCount = aroundDecl.getDeclaredParameterCount(); |
| if (baseArgCount < declaredParameterCount) { |
| scope.problemReporter().signalError(this.sourceStart, this.sourceEnd, |
| "too few arguments to proceed, expected " + declaredParameterCount); |
| aroundDecl.ignoreFurtherInvestigation = true; |
| return null; //binding.returnType; |
| } |
| |
| if (baseArgCount > declaredParameterCount) { |
| scope.problemReporter().signalError(this.sourceStart, this.sourceEnd, |
| "too many arguments to proceed, expected " + declaredParameterCount); |
| aroundDecl.ignoreFurtherInvestigation = true; |
| return null; //binding.returnType; |
| } |
| |
| boolean argsContainCast = false; |
| for (int i=0; i<arguments.length;i++) { |
| if (arguments[i] instanceof CastExpression) argsContainCast = true; |
| // if (arguments[i].constant==null) arguments[i].constant=Constant.NotAConstant; |
| } |
| // TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; |
| // if (this.arguments != null) { |
| // boolean argHasError = false; // typeChecks all arguments |
| // int length = this.arguments.length; |
| // argumentTypes = new TypeBinding[length]; |
| // for (int i = 0; i < length; i++){ |
| // Expression argument = this.arguments[i]; |
| // if (argument instanceof CastExpression) { |
| // argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on |
| // argsContainCast = true; |
| // } |
| // if ((argumentTypes[i] = argument.resolveType(scope)) == null){ |
| // argHasError = true; |
| // } |
| // } |
| // if (argHasError) { |
| // if (this.actualReceiverType instanceof ReferenceBinding) { |
| // // record a best guess, for clients who need hint about possible method match |
| // TypeBinding[] pseudoArgs = new TypeBinding[length]; |
| // for (int i = length; --i >= 0;) |
| // pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL : argumentTypes[i]; // replace args with errors with null type |
| // this.binding = |
| // this.receiver.isImplicitThis() |
| // ? scope.getImplicitMethod(this.selector, pseudoArgs, this) |
| // : scope.findMethod((ReferenceBinding) this.actualReceiverType, this.selector, pseudoArgs, this); |
| // if (this.binding != null && !this.binding.isValidBinding()) { |
| // MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; |
| // // record the closest match, for clients who may still need hint about possible method match |
| // if (closestMatch != null) { |
| // if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method |
| // // shouldn't return generic method outside its context, rather convert it to raw method (175409) |
| // closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null); |
| // } |
| // this.binding = closestMatch; |
| // MethodBinding closestMatchOriginal = closestMatch.original(); |
| // if ((closestMatchOriginal.isPrivate() || closestMatchOriginal.declaringClass.isLocalType()) && !scope.isDefinedInMethod(closestMatchOriginal)) { |
| // // ignore cases where method is used from within inside itself (e.g. direct recursions) |
| // closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; |
| // } |
| // } |
| // } |
| // } |
| // return null; |
| // } |
| // } |
| // |
| |
| |
| // checkInvocationArguments(scope, this.receiver, this.actualReceiverType, this.binding, this.arguments, argumentTypes, argsContainCast, this); |
| for (int i=0, len=arguments.length; i < len; i++) { |
| Expression arg = arguments[i]; |
| TypeBinding argType = arg.resolveType(scope); |
| if (argType != null) { |
| TypeBinding paramType = binding.parameters[i]; |
| if (!argType.isCompatibleWith(paramType)) { |
| scope.problemReporter().typeMismatchError(argType, paramType, arg,null); |
| } |
| } |
| } |
| checkInvocationArguments(scope,null,this.actualReceiverType,binding, |
| this.arguments,binding.parameters,argsContainCast,this); |
| |
| this.resolvedType = binding.returnType; |
| return binding.returnType; |
| } |
| |
| private AdviceDeclaration findEnclosingAround(Scope scope) { |
| if (scope == null) return null; |
| |
| if (scope instanceof MethodScope) { |
| MethodScope methodScope = (MethodScope)scope; |
| ReferenceContext context = methodScope.referenceContext; |
| if (context instanceof AdviceDeclaration) { |
| AdviceDeclaration adviceDecl = (AdviceDeclaration)context; |
| if (adviceDecl.kind == AdviceKind.Around) { |
| // pr 53981 only match "bare" calls to proceed |
| if((receiver != null) && (!receiver.isThis())) { return null; } |
| adviceDecl.proceedCalls.add(this); |
| return adviceDecl; |
| } else { |
| return null; |
| } |
| } |
| } else if (scope instanceof ClassScope) { |
| inInner = true; |
| } |
| |
| return findEnclosingAround(scope.parent); |
| } |
| } |