Package org.aspectj.ajdt.internal.compiler.ast

Source Code of org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration

/* *******************************************************************
* 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 java.util.ArrayList;
import java.util.List;

import org.aspectj.ajdt.internal.compiler.lookup.AjTypeConstants;
import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedHandler;
import org.aspectj.bridge.context.CompilationAndWeavingContext;
import org.aspectj.bridge.context.ContextToken;
import org.aspectj.org.eclipse.jdt.core.Flags;
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.Annotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
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.codegen.CodeStream;
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.ExtraCompilerModifiers;
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.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.AdviceKind;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.UnresolvedType;

/**
* Represents before, after and around advice in an aspect. Will generate a method corresponding to the body of the advice with an
* attribute including additional information.
*
* @author Jim Hugunin
*/
public class AdviceDeclaration extends AjMethodDeclaration {
  public PointcutDesignator pointcutDesignator; // set during parsing
  int baseArgumentCount; // referenced by IfPseudoToken.makeArguments

  public Argument extraArgument; // set during parsing, referenced by Proceed

  public AdviceKind kind; // set during parsing, referenced by Proceed and AsmElementFormatter
  private int extraArgumentFlags = 0;

  public MethodBinding proceedMethodBinding; // set during this.resolveStaments, referenced by Proceed
  public List proceedCalls = new ArrayList(2); // populated during Proceed.findEnclosingAround

  private boolean proceedInInners;
  private ResolvedMember[] proceedCallSignatures;
  private boolean[] formalsUnchangedToProceed;
  private UnresolvedType[] declaredExceptions;

  public AdviceDeclaration(CompilationResult result, AdviceKind kind) {
    super(result);
    this.returnType = TypeReference.baseTypeReference(T_void, 0);
    this.kind = kind;
  }

  // override
  protected int generateInfoAttributes(ClassFile classFile) {
    List l = new ArrayList(1);
    l.add(new EclipseAttributeAdapter(makeAttribute()));
    addDeclarationStartLineAttribute(l, classFile);

    return classFile.generateMethodInfoAttribute(binding, false, l);
  }

  private AjAttribute makeAttribute() {
    if (kind == AdviceKind.Around) {
      return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(), extraArgumentFlags, sourceStart,
          sourceEnd, null, proceedInInners, proceedCallSignatures, formalsUnchangedToProceed, declaredExceptions);
    } else {
      return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(), extraArgumentFlags, sourceStart,
          sourceEnd, null);
    }
  }

  // override
  public void resolveStatements() {
    if (binding == null || ignoreFurtherInvestigation)
      return;

    ClassScope upperScope = (ClassScope) scope.parent; // !!! safety

    modifiers = checkAndSetModifiers(modifiers, upperScope);
    int bindingModifiers = (modifiers | (binding.modifiers & ExtraCompilerModifiers.AccGenericSignature));
    binding.modifiers = bindingModifiers;

    if (kind == AdviceKind.AfterThrowing && extraArgument != null) {
      TypeBinding argTb = extraArgument.binding.type;
      TypeBinding expectedTb = upperScope.getJavaLangThrowable();
      if (!argTb.isCompatibleWith(expectedTb)) {
        scope.problemReporter().typeMismatchError(argTb, expectedTb, extraArgument);
        ignoreFurtherInvestigation = true;
        return;
      }
    }

    pointcutDesignator.finishResolveTypes(this, this.binding, baseArgumentCount, upperScope.referenceContext.binding);

    if (binding == null || ignoreFurtherInvestigation)
      return;

    if (kind == AdviceKind.Around) {
      ReferenceBinding[] exceptions = new ReferenceBinding[] { upperScope.getJavaLangThrowable() };
      proceedMethodBinding = new MethodBinding(Modifier.STATIC | Flags.AccSynthetic, "proceed".toCharArray(),
          binding.returnType, resize(baseArgumentCount + 1, binding.parameters), exceptions, binding.declaringClass);
      proceedMethodBinding.selector = CharOperation.concat(selector, proceedMethodBinding.selector);
    }

    super.resolveStatements(); // upperScope);
    if (binding != null)
      determineExtraArgumentFlags();

    if (kind == AdviceKind.Around) {
      int n = proceedCalls.size();
      // EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(upperScope);

      // System.err.println("access to: " + Arrays.asList(handler.getMembers()));

      // XXX set these correctly
      formalsUnchangedToProceed = new boolean[baseArgumentCount];
      proceedCallSignatures = new ResolvedMember[0];
      proceedInInners = false;
      declaredExceptions = new UnresolvedType[0];

      for (int i = 0; i < n; i++) {
        Proceed call = (Proceed) proceedCalls.get(i);
        if (call.inInner) {
          // System.err.println("proceed in inner: " + call);
          proceedInInners = true;
          // XXX wrong
          // proceedCallSignatures[i] = world.makeResolvedMember(call.binding);
        }
      }

      // ??? should reorganize into AspectDeclaration
      // if we have proceed in inners we won't ever be inlined so the code below is unneeded
      if (!proceedInInners) {
        PrivilegedHandler handler = (PrivilegedHandler) upperScope.referenceContext.binding.privilegedHandler;
        if (handler == null) {
          handler = new PrivilegedHandler((AspectDeclaration) upperScope.referenceContext);
          // upperScope.referenceContext.binding.privilegedHandler = handler;
        }

        this.traverse(new MakeDeclsPublicVisitor(), (ClassScope) null);

        AccessForInlineVisitor v = new AccessForInlineVisitor((AspectDeclaration) upperScope.referenceContext, handler);
        ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.ACCESS_FOR_INLINE,
            selector);
        this.traverse(v, (ClassScope) null);
        CompilationAndWeavingContext.leavingPhase(tok);

        // ??? if we found a construct that we can't inline, set
        // proceedInInners so that we won't try to inline this body
        if (!v.isInlinable)
          proceedInInners = true;
      }
    }
  }

  // called by Proceed.resolveType
  public int getDeclaredParameterCount() {
    // this only works before code generation
    return this.arguments.length - 3 - ((extraArgument == null) ? 0 : 1);
    // Advice.countOnes(extraArgumentFlags);
  }

  private void generateProceedMethod(ClassScope classScope, ClassFile classFile) {
    MethodBinding binding = proceedMethodBinding;

    classFile.generateMethodInfoHeader(binding);
    int methodAttributeOffset = classFile.contentsOffset;
    int attributeNumber = classFile.generateMethodInfoAttribute(binding, false, AstUtil.getAjSyntheticAttribute());
    int codeAttributeOffset = classFile.contentsOffset;
    classFile.generateCodeAttributeHeader();
    CodeStream codeStream = classFile.codeStream;
    codeStream.reset(this, classFile);

    // push the closure
    int nargs = binding.parameters.length;
    int closureIndex = 0;
    for (int i = 0; i < nargs - 1; i++) {
      closureIndex += AstUtil.slotsNeeded(binding.parameters[i]);
    }

    codeStream.aload(closureIndex);

    // build the Object[]

    codeStream.generateInlinedValue(nargs - 1);
    codeStream.newArray(new ArrayBinding(classScope.getType(TypeConstants.JAVA_LANG_OBJECT,
        TypeConstants.JAVA_LANG_OBJECT.length), 1, classScope.environment()));

    int index = 0;
    for (int i = 0; i < nargs - 1; i++) {
      TypeBinding type = binding.parameters[i];
      codeStream.dup();
      codeStream.generateInlinedValue(i);
      codeStream.load(type, index);
      index += AstUtil.slotsNeeded(type);
      if (type.isBaseType()) {
        codeStream.invokestatic(AjTypeConstants.getConversionMethodToObject(classScope, type));
      }

      codeStream.aastore();
    }

    // call run
    ReferenceBinding closureType = (ReferenceBinding) binding.parameters[nargs - 1];
    MethodBinding runMethod = closureType.getMethods("run".toCharArray())[0];
    codeStream.invokevirtual(runMethod);

    TypeBinding returnType = binding.returnType;
    if (returnType.isBaseType()) {
      codeStream.invokestatic(AjTypeConstants.getConversionMethodFromObject(classScope, returnType));
    } else {
      codeStream.checkcast(returnType);
    }
    AstUtil.generateReturn(returnType, codeStream);
    codeStream.recordPositionsFrom(0, 1);
    classFile.completeCodeAttribute(codeAttributeOffset);
    attributeNumber++;
    classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
  }

  // override
  public void generateCode(ClassScope classScope, ClassFile classFile) {
    if (ignoreFurtherInvestigation)
      return;

    super.generateCode(classScope, classFile);
    if (proceedMethodBinding != null) {
      generateProceedMethod(classScope, classFile);
    }
  }

  private void determineExtraArgumentFlags() {
    if (extraArgument != null)
      extraArgumentFlags |= Advice.ExtraArgument;

    ThisJoinPointVisitor tjp = new ThisJoinPointVisitor(this);
    extraArgumentFlags |= tjp.removeUnusedExtraArguments();
  }

  private static TypeBinding[] resize(int newSize, TypeBinding[] bindings) {
    int len = bindings.length;
    TypeBinding[] ret = new TypeBinding[newSize];
    System.arraycopy(bindings, 0, ret, 0, Math.min(newSize, len));
    return ret;
  }

  /**
   * Add either the @Before, @After, @Around, @AfterReturning or @AfterThrowing annotation
   */
  public void addAtAspectJAnnotations() {
    Annotation adviceAnnotation = null;
    String pointcutExpression = pointcutDesignator.getPointcut().toString();
    String extraArgumentName = "";
    if (extraArgument != null) {
      extraArgumentName = new String(extraArgument.name);
    }
    String argNames = buildArgNameRepresentation();

    if (kind == AdviceKind.Before) {
      adviceAnnotation = AtAspectJAnnotationFactory.createBeforeAnnotation(pointcutExpression, argNames,
          declarationSourceStart);
    } else if (kind == AdviceKind.After) {
      adviceAnnotation = AtAspectJAnnotationFactory.createAfterAnnotation(pointcutExpression, argNames,
          declarationSourceStart);
    } else if (kind == AdviceKind.AfterReturning) {
      adviceAnnotation = AtAspectJAnnotationFactory.createAfterReturningAnnotation(pointcutExpression, argNames,
          extraArgumentName, declarationSourceStart);
    } else if (kind == AdviceKind.AfterThrowing) {
      adviceAnnotation = AtAspectJAnnotationFactory.createAfterThrowingAnnotation(pointcutExpression, argNames,
          extraArgumentName, declarationSourceStart);
    } else if (kind == AdviceKind.Around) {
      adviceAnnotation = AtAspectJAnnotationFactory.createAroundAnnotation(pointcutExpression, argNames,
          declarationSourceStart);
    }
    AtAspectJAnnotationFactory.addAnnotation(this, adviceAnnotation, this.scope);
  }

  private String buildArgNameRepresentation() {
    StringBuffer args = new StringBuffer();
    int numArgsWeCareAbout = getDeclaredParameterCount();
    if (this.arguments != null) {
      for (int i = 0; i < numArgsWeCareAbout; i++) {
        if (i != 0)
          args.append(",");
        args.append(new String(this.arguments[i].name));
      }
    }
    if (extraArgument != null) {
      if (numArgsWeCareAbout > 0) {
        args.append(",");
      }
      args.append(new String(extraArgument.name));
    }
    return args.toString();
  }

  // override, Called by ClassScope.postParse
  public void postParse(TypeDeclaration typeDec) {
    AspectDeclaration aspectDecl = (AspectDeclaration) typeDec;
    int adviceSequenceNumberInType = aspectDecl.adviceCounter++;

    StringBuffer stringifiedPointcut = new StringBuffer(30);
    pointcutDesignator.print(0, stringifiedPointcut);
    this.selector = NameMangler.adviceName(EclipseFactory.getName(typeDec.binding).replace('.', '_'), kind,
        adviceSequenceNumberInType, stringifiedPointcut.toString().hashCode()).toCharArray();
    if (arguments != null) {
      baseArgumentCount = arguments.length;
    }

    if (kind == AdviceKind.Around) {
      extraArgument = makeFinalArgument("ajc$aroundClosure", AjTypeConstants.getAroundClosureType());
    }

    int addedArguments = 3;
    if (extraArgument != null) {
      addedArguments += 1;
    }

    arguments = extendArgumentsLength(arguments, addedArguments);

    int index = baseArgumentCount;
    if (extraArgument != null) {
      arguments[index++] = extraArgument;
    }

    arguments[index++] = makeFinalArgument("thisJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
    arguments[index++] = makeFinalArgument("thisJoinPoint", AjTypeConstants.getJoinPointType());
    arguments[index++] = makeFinalArgument("thisEnclosingJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());

    if (pointcutDesignator.isError()) {
      this.ignoreFurtherInvestigation = true;
    }
    pointcutDesignator.postParse(typeDec, this);
  }

  private int checkAndSetModifiers(int modifiers, ClassScope scope) {
    if (modifiers == 0)
      return Modifier.PUBLIC;
    else if (modifiers == Modifier.STRICT)
      return Modifier.PUBLIC | Modifier.STRICT;
    else {
      tagAsHavingErrors();
      scope.problemReporter().signalError(declarationSourceStart, sourceStart - 1,
          "illegal modifier on advice, only strictfp is allowed");
      return Modifier.PUBLIC;
    }
  }

  // called by IfPseudoToken
  public static Argument[] addTjpArguments(Argument[] arguments) {
    int index = arguments.length;
    arguments = extendArgumentsLength(arguments, 3);

    arguments[index++] = makeFinalArgument("thisJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
    arguments[index++] = makeFinalArgument("thisJoinPoint", AjTypeConstants.getJoinPointType());
    arguments[index++] = makeFinalArgument("thisEnclosingJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());

    return arguments;
  }

  private static Argument makeFinalArgument(String name, TypeReference typeRef) {
    long pos = 0; // XXX encode start and end location
    return new Argument(name.toCharArray(), pos, typeRef, Modifier.FINAL);
  }

  private static Argument[] extendArgumentsLength(Argument[] args, int addedArguments) {
    if (args == null) {
      return new Argument[addedArguments];
    }
    int len = args.length;
    Argument[] ret = new Argument[len + addedArguments];
    System.arraycopy(args, 0, ret, 0, len);
    return ret;
  }

  // public String toString(int tab) {
  // String s = tabString(tab);
  // if (modifiers != AccDefault) {
  // s += modifiersString(modifiers);
  // }
  //
  // if (kind == AdviceKind.Around) {
  // s += returnTypeToString(0);
  // }
  //
  //    s += new String(selector) + "("; //$NON-NLS-1$
  // if (arguments != null) {
  // for (int i = 0; i < arguments.length; i++) {
  // s += arguments[i].toString(0);
  // if (i != (arguments.length - 1))
  //          s = s + ", "; //$NON-NLS-1$
  // };
  // };
  //    s += ")"; //$NON-NLS-1$
  //   
  // if (extraArgument != null) {
  // s += "(" + extraArgument.toString(0) + ")";
  // }
  //   
  //   
  //   
  // if (thrownExceptions != null) {
  //      s += " throws "; //$NON-NLS-1$
  // for (int i = 0; i < thrownExceptions.length; i++) {
  // s += thrownExceptions[i].toString(0);
  // if (i != (thrownExceptions.length - 1))
  //          s = s + ", "; //$NON-NLS-1$
  // };
  // };
  //   
  // s += ": ";
  // if (pointcutDesignator != null) {
  // s += pointcutDesignator.toString(0);
  // }
  //
  // s += toStringStatements(tab + 1);
  // return s;
  // }

  public StringBuffer printBody(int indent, StringBuffer output) {
    output.append(": ");
    if (pointcutDesignator != null) {
      output.append(pointcutDesignator.toString());
    }
    return super.printBody(indent, output);
  }

  public StringBuffer printReturnType(int indent, StringBuffer output) {
    if (this.kind == AdviceKind.Around) {
      return super.printReturnType(indent, output);
    }
    return output;
  }
}
TOP

Related Classes of org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.