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 Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-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.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.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
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 & 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,
        "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 = (MethodBinding)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.loadObject(closureIndex);
   
    // build the Object[]

    codeStream.generateInlinedValue(nargs-1);
    codeStream.newArray(
        new ArrayBinding(
            classScope.getType(TypeBinding.JAVA_LANG_OBJECT,
                TypeBinding.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);
   
    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.