avoid NPE if this member is not declared in a compilation unit (for example, a binary type) (see javadoc of getCompilationUnit)

/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.cfprovider;

import java.util.HashSet;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.search.TypeNameMatch;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.env.ISourceImport;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.core.BinaryType;
import org.eclipse.jdt.internal.core.ClassFile;
import org.eclipse.jdt.internal.core.CompilationUnitElementInfo;
import org.eclipse.jdt.internal.core.ImportDeclaration;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.NameLookup;
import org.eclipse.jdt.internal.core.Openable;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.SourceMapper;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
import org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver;
import org.eclipse.jdt.internal.core.hierarchy.HierarchyType;
import org.eclipse.jdt.internal.core.util.Util;
import org.eclipse.jdt.internal.corext.util.OpenTypeHistory;
import org.eclipse.jdt.internal.ui.filters.InnerClassFilesFilter;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jface.viewers.Viewer;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaClassFile;
import scala.tools.eclipse.contribution.weaving.jdt.IScalaElement;

@SuppressWarnings("restriction")
public privileged aspect ClassFileProviderAspect {

  pointcut classFileCreations(PackageFragment parent, String name) :
    call(protected ClassFile.new(PackageFragment, String)) &&
    within(org.eclipse.jdt..*) &&
    args(parent, name);

  pointcut getTypeName(ClassFile cf) :
    execution(public String ClassFile.getTypeName()) &&
    target(cf);

  pointcut getType(ClassFile cf) :
    call(public IType IClassFile.getType()) &&
    target(cf);

  pointcut mapSource() :
    execution(IBuffer ClassFile.mapSource(SourceMapper, IBinaryType)) &&
    target(IScalaClassFile);

  pointcut mapSource2() :
    execution(void SourceMapper.mapSource(IType, char[], IBinaryType));

  pointcut getSourceFileName(BinaryType bt) :
    execution(String BinaryType.getSourceFileName(IBinaryType)) &&
    target(bt);

  pointcut select(Viewer viewer, Object parentElement, Object element) :
    execution(boolean InnerClassFilesFilter.select(Viewer, Object, Object)) &&
    args(viewer, parentElement, element);

  pointcut getChildren(BinaryType bt) :
    execution(IJavaElement[] BinaryType.getChildren()) &&
    target(bt);

  pointcut getAST(ITypeRoot element, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) :
    execution(CompilationUnit SharedASTProvider.getAST(ITypeRoot, SharedASTProvider.WAIT_FLAG, IProgressMonitor)) &&
    args(element, waitFlag, progressMonitor);

  pointcut resolve(HierarchyResolver hr, IGenericType suppliedType) :
    execution(void HierarchyResolver.resolve(IGenericType)) &&
    target(hr) &&
    args(suppliedType);

  pointcut remember(HierarchyResolver hr, IType type, ReferenceBinding typeBinding) :
    execution(void HierarchyResolver.remember(IType, ReferenceBinding)) &&
    target(hr) &&
    args(type, typeBinding);

  pointcut acceptType(IType type, int acceptFlags, boolean isSourceType) :
    execution(boolean NameLookup.acceptType(IType, int, boolean)) &&
    args(type, acceptFlags, isSourceType);

  pointcut find(SearchableEnvironment se, String typeName, String packageName) :
    execution(NameEnvironmentAnswer find(String, String)) &&
    target(se) &&
    args(typeName, packageName);

  pointcut convert(SourceTypeConverter stc, ISourceType[] sourceTypes, CompilationResult compilationResult) :
    execution(CompilationUnitDeclaration SourceTypeConverter.convert(ISourceType[], CompilationResult)) &&
    target(stc) &&
    args(sourceTypes, compilationResult);

  pointcut getAncestor(JavaElement je, int ancestorType) :
    execution(IJavaElement JavaElement.getAncestor(int)) &&
    target(je) &&
    args(ancestorType);

  pointcut isContainerDirty(TypeNameMatch match) :
    execution(boolean OpenTypeHistory.isContainerDirty(TypeNameMatch)) &&
    args(match);

  ClassFile around(PackageFragment parent, String name) :
    classFileCreations(parent, name) {

    ClassFile javaClassFile = proceed(parent, name);
    byte[] bytes;

    try {
      bytes = javaClassFile.getBytes();
    } catch(Throwable t) {
      return javaClassFile;
    }

    for (IClassFileProvider provider : ClassFileProviderRegistry.getInstance().getProviders()) {
      ClassFile cf = provider.create(bytes, parent, name);
      if (cf != null)
        return cf;
    }

    return javaClassFile;
  }

  void around() :
    mapSource2() &&
    cflow(mapSource()) {
    return;
  }

  IType around(ClassFile cf) :
    getType(cf) &&
    cflow(mapSource()) {
    if (cf.binaryType == null)
      cf.binaryType = new BinaryType(cf, cf.getTypeName());
    return cf.binaryType;
  }

  String around(ClassFile cf) :
    getTypeName(cf) {
    if(cf instanceof IScalaClassFile) {
      int lastDollar = cf.name.lastIndexOf('$');
      return (lastDollar == -1 || lastDollar == cf.name.length()-1) ? cf.name : Util.localTypeName(cf.name, lastDollar, cf.name.length());
    } else
      return proceed(cf);
  }

  boolean around(Viewer viewer, Object parentElement, Object element) :
    select(viewer, parentElement, element) {
    if (element instanceof IScalaClassFile) {
      IClassFile classFile = (IClassFile) element;
      String name = classFile.getElementName();
      int dollarIndex = name.indexOf('$');
      return dollarIndex == -1 || dollarIndex == name.length()-7; // Trailing '$' implies object rather than inner class
    }
    return proceed(viewer, parentElement, element);
  }

  IJavaElement[] around(BinaryType bt) throws JavaModelException :
    getChildren(bt) &&
    target(BinaryType) {
    ClassFile cf = (ClassFile)bt.parent;
    if (cf instanceof IScalaClassFile)
      return cf.getChildren();
    else
      return proceed(bt);
  }

  CompilationUnit around(ITypeRoot element, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) :
    getAST(element, waitFlag, progressMonitor) {
      if (element instanceof IScalaElement)
        return null;
      else
        return proceed(element, waitFlag, progressMonitor);
  }

  void around(HierarchyResolver hr, IGenericType suppliedType) :
    resolve(hr, suppliedType) {
    if (!suppliedType.isBinaryType()) {
      IType tpe = ((SourceTypeElementInfo)suppliedType).getHandle();
      IClassFile cf = tpe.getClassFile();
      if (cf instanceof IScalaClassFile) {
        hr.resolve(new Openable[]{(Openable)cf}, new HashSet(), null);
        return;
      }
    }

    proceed(hr, suppliedType);
  }

  void around(HierarchyResolver hr, IType type, ReferenceBinding typeBinding) :
    remember(hr, type, typeBinding) {
    IOpenable openable = (IOpenable) type.getCompilationUnit();
    if (openable != null && openable.isOpen()) {
      try {
        IGenericType genericType = (IGenericType)((JavaElement)type).getElementInfo();
        hr.remember(genericType, typeBinding);
      } catch (JavaModelException e) {
        // cannot happen since element is open
        return;
      }
    } else {
      if (typeBinding == null) return;

      TypeDeclaration typeDeclaration = ((SourceTypeBinding)typeBinding).scope.referenceType();

      // simple super class name
      char[] superclassName = null;
      TypeReference superclass;
      if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
        superclass = typeDeclaration.allocation.type;
      } else {
        superclass = typeDeclaration.superclass;
      }
      if (superclass != null) {
        char[][] typeName = superclass.getTypeName();
        superclassName = typeName == null ? null : typeName[typeName.length-1];
      }

      // simple super interface names
      char[][] superInterfaceNames = null;
      TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
      if (superInterfaces != null) {
        int length = superInterfaces.length;
        superInterfaceNames = new char[length][];
        for (int i = 0; i < length; i++) {
          TypeReference superInterface = superInterfaces[i];
          char[][] typeName = superInterface.getTypeName();
          superInterfaceNames[i] = typeName[typeName.length-1];
        }
      }

      HierarchyType hierarchyType = new HierarchyType(
        type,
        typeDeclaration.name,
        typeDeclaration.binding.modifiers,
        superclassName,
        superInterfaceNames);
      hr.remember(hierarchyType, typeDeclaration.binding);
    }
  }

  String around(BinaryType bt) :
    getSourceFileName(bt) {
    IJavaElement parent = bt.getParent();
    if (parent instanceof IScalaClassFile)
      return ((IScalaClassFile)parent).getSourceFileName();
    else
      return proceed(bt);
  }

  boolean around(IType type, int acceptFlags, boolean isSourceType) :
    acceptType(type, acceptFlags, isSourceType) {
    if (!isSourceType && (type instanceof SourceType)) {
      IJavaElement parent = type.getParent();
      if (parent instanceof IScalaClassFile)
        return proceed(type, acceptFlags, true);
    }

    return proceed(type, acceptFlags, isSourceType);
  }

  CompilationUnitDeclaration around(SourceTypeConverter stc, ISourceType[] sourceTypes, CompilationResult compilationResult) throws JavaModelException :
    convert(stc, sourceTypes, compilationResult) {
    stc.unit = new CompilationUnitDeclaration(stc.problemReporter, compilationResult, 0);
    // not filled at this point

    if (sourceTypes.length == 0) return stc.unit;
    SourceTypeElementInfo topLevelTypeInfo = (SourceTypeElementInfo) sourceTypes[0];
    org.eclipse.jdt.core.ICompilationUnit cuHandle = topLevelTypeInfo.getHandle().getCompilationUnit();
    stc.cu = (ICompilationUnit) cuHandle;

    CompilationUnitElementInfo cuei = null;
    Object info = ((JavaElement)stc.cu).getElementInfo();
    if (info instanceof CompilationUnitElementInfo)
      cuei = (CompilationUnitElementInfo)info;

    if (stc.has1_5Compliance && cuei != null && cuei.annotationNumber > 10) { // experimental value
      // if more than 10 annotations, diet parse as this is faster
      return new Parser(stc.problemReporter, true).dietParse(stc.cu, compilationResult);
    }

    /* only positions available */
    int start = topLevelTypeInfo.getNameSourceStart();
    int end = topLevelTypeInfo.getNameSourceEnd();

    //cuHanlde could be null if this member is not declared in a compilation unit (for example, a binary type) (see javadoc of getCompilationUnit)
    if (cuHandle != null) {
      /* convert package and imports */
      String[] packageName = ((PackageFragment) cuHandle.getParent()).names;
      if (packageName.length > 0)
        // if its null then it is defined in the default package
        stc.unit.currentPackage =
          stc.createImportReference(packageName, start, end, false, ClassFileConstants.AccDefault);
      IImportDeclaration[] importDeclarations = cuHandle.getImports();
      int importCount = importDeclarations.length;
      stc.unit.imports = new ImportReference[importCount];
      for (int i = 0; i < importCount; i++) {
        ImportDeclaration importDeclaration = (ImportDeclaration) importDeclarations[i];
        ISourceImport sourceImport = (ISourceImport) importDeclaration.getElementInfo();
        String nameWithoutStar = importDeclaration.getNameWithoutStar();
        stc.unit.imports[i] = stc.createImportReference(
          Util.splitOn('.', nameWithoutStar, 0, nameWithoutStar.length()),
          sourceImport.getDeclarationSourceStart(),
          sourceImport.getDeclarationSourceEnd(),
          importDeclaration.isOnDemand(),
          sourceImport.getModifiers());
      }
    }
    /* convert type(s) */
    try {
      int typeCount = sourceTypes.length;
      final TypeDeclaration[] types = new TypeDeclaration[typeCount];
      /*
       * We used a temporary types collection to prevent this.unit.types from being null during a call to
       * convert(...) when the source is syntactically incorrect and the parser is flushing the unit's types.
       * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97466
       */
      for (int i = 0; i < typeCount; i++) {
        SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) sourceTypes[i];
        types[i] = stc.convert((SourceType) typeInfo.getHandle(), compilationResult);
      }
      stc.unit.types = types;
      return stc.unit;
    } catch (SourceTypeConverter.AnonymousMemberFound e) {
      return new Parser(stc.problemReporter, true).parse(stc.cu, compilationResult);
    }
  }

  IJavaElement around(JavaElement je, int ancestorType) :
    getAncestor(je, ancestorType) {
    IJavaElement element = je;
    while (element != null) {
      if (element.getElementType() == ancestorType)
        return element;
      else if (element instanceof IScalaClassFile && ancestorType == IJavaElement.COMPILATION_UNIT)
        return ((JavaElement)element).getCompilationUnit();
      element= element.getParent();
    }
    return null;
  }

  boolean around(TypeNameMatch match) :
    isContainerDirty(match) {
    org.eclipse.jdt.core.ICompilationUnit cu = match.getType().getCompilationUnit();
    if (cu == null) {
      return false;
    }
    IResource resource= cu.getResource();
    if (resource == null)
      return false;

    ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
    ITextFileBuffer textFileBuffer= manager.getTextFileBuffer(resource.getFullPath(), LocationKind.IFILE);
    if (textFileBuffer != null) {
      return textFileBuffer.isDirty();
    }
    return false;
  }
}

/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.cfprovider;

import java.util.HashSet;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.search.TypeNameMatch;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.env.ISourceImport;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.core.BinaryType;
import org.eclipse.jdt.internal.core.ClassFile;
import org.eclipse.jdt.internal.core.CompilationUnitElementInfo;
import org.eclipse.jdt.internal.core.ImportDeclaration;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.NameLookup;
import org.eclipse.jdt.internal.core.Openable;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.SourceMapper;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
import org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver;
import org.eclipse.jdt.internal.core.hierarchy.HierarchyType;
import org.eclipse.jdt.internal.core.util.Util;
import org.eclipse.jdt.internal.corext.util.OpenTypeHistory;
import org.eclipse.jdt.internal.ui.filters.InnerClassFilesFilter;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jface.viewers.Viewer;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaClassFile;
import scala.tools.eclipse.contribution.weaving.jdt.IScalaElement;

@SuppressWarnings("restriction")
public privileged aspect ClassFileProviderAspect {

  pointcut classFileCreations(PackageFragment parent, String name) :
    call(protected ClassFile.new(PackageFragment, String)) &&
    within(org.eclipse.jdt..*) &&
    args(parent, name);

  pointcut getTypeName(ClassFile cf) :
    execution(public String ClassFile.getTypeName()) &&
    target(cf);

  pointcut getType(ClassFile cf) :
    call(public IType IClassFile.getType()) &&
    target(cf);

  pointcut mapSource() :
    execution(IBuffer ClassFile.mapSource(SourceMapper, IBinaryType)) &&
    target(IScalaClassFile);

  pointcut mapSource2() :
    execution(void SourceMapper.mapSource(IType, char[], IBinaryType));

  pointcut getSourceFileName(BinaryType bt) :
    execution(String BinaryType.getSourceFileName(IBinaryType)) &&
    target(bt);

  pointcut select(Viewer viewer, Object parentElement, Object element) :
    execution(boolean InnerClassFilesFilter.select(Viewer, Object, Object)) &&
    args(viewer, parentElement, element);

  pointcut getChildren(BinaryType bt) :
    execution(IJavaElement[] BinaryType.getChildren()) &&
    target(bt);

  pointcut getAST(ITypeRoot element, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) :
    execution(CompilationUnit SharedASTProvider.getAST(ITypeRoot, SharedASTProvider.WAIT_FLAG, IProgressMonitor)) &&
    args(element, waitFlag, progressMonitor);

  pointcut resolve(HierarchyResolver hr, IGenericType suppliedType) :
    execution(void HierarchyResolver.resolve(IGenericType)) &&
    target(hr) &&
    args(suppliedType);

  pointcut remember(HierarchyResolver hr, IType type, ReferenceBinding typeBinding) :
    execution(void HierarchyResolver.remember(IType, ReferenceBinding)) &&
    target(hr) &&
    args(type, typeBinding);

  pointcut acceptType(IType type, int acceptFlags, boolean isSourceType) :
    execution(boolean NameLookup.acceptType(IType, int, boolean)) &&
    args(type, acceptFlags, isSourceType);

  pointcut find(SearchableEnvironment se, String typeName, String packageName) :
    execution(NameEnvironmentAnswer find(String, String)) &&
    target(se) &&
    args(typeName, packageName);

  pointcut convert(SourceTypeConverter stc, ISourceType[] sourceTypes, CompilationResult compilationResult) :
    execution(CompilationUnitDeclaration SourceTypeConverter.convert(ISourceType[], CompilationResult)) &&
    target(stc) &&
    args(sourceTypes, compilationResult);

  pointcut getAncestor(JavaElement je, int ancestorType) :
    execution(IJavaElement JavaElement.getAncestor(int)) &&
    target(je) &&
    args(ancestorType);

  pointcut isContainerDirty(TypeNameMatch match) :
    execution(boolean OpenTypeHistory.isContainerDirty(TypeNameMatch)) &&
    args(match);

  ClassFile around(PackageFragment parent, String name) :
    classFileCreations(parent, name) {

    ClassFile javaClassFile = proceed(parent, name);
    byte[] bytes;

    try {
      bytes = javaClassFile.getBytes();
    } catch(Throwable t) {
      return javaClassFile;
    }

    for (IClassFileProvider provider : ClassFileProviderRegistry.getInstance().getProviders()) {
      ClassFile cf = provider.create(bytes, parent, name);
      if (cf != null)
        return cf;
    }

    return javaClassFile;
  }

  void around() :
    mapSource2() &&
    cflow(mapSource()) {
    return;
  }

  IType around(ClassFile cf) :
    getType(cf) &&
    cflow(mapSource()) {
    if (cf.binaryType == null)
      cf.binaryType = new BinaryType(cf, cf.getTypeName());
    return cf.binaryType;
  }

  String around(ClassFile cf) :
    getTypeName(cf) {
    if(cf instanceof IScalaClassFile) {
      int lastDollar = cf.name.lastIndexOf('$');
      return (lastDollar == -1 || lastDollar == cf.name.length()-1) ? cf.name : Util.localTypeName(cf.name, lastDollar, cf.name.length());
    } else
      return proceed(cf);
  }

  boolean around(Viewer viewer, Object parentElement, Object element) :
    select(viewer, parentElement, element) {
    if (element instanceof IScalaClassFile) {
      IClassFile classFile = (IClassFile) element;
      String name = classFile.getElementName();
      int dollarIndex = name.indexOf('$');
      return dollarIndex == -1 || dollarIndex == name.length()-7; // Trailing '$' implies object rather than inner class
    }
    return proceed(viewer, parentElement, element);
  }

  IJavaElement[] around(BinaryType bt) throws JavaModelException :
    getChildren(bt) &&
    target(BinaryType) {
    ClassFile cf = (ClassFile)bt.parent;
    if (cf instanceof IScalaClassFile)
      return cf.getChildren();
    else
      return proceed(bt);
  }

  CompilationUnit around(ITypeRoot element, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) :
    getAST(element, waitFlag, progressMonitor) {
      if (element instanceof IScalaElement)
        return null;
      else
        return proceed(element, waitFlag, progressMonitor);
  }

  void around(HierarchyResolver hr, IGenericType suppliedType) :
    resolve(hr, suppliedType) {
    if (!suppliedType.isBinaryType()) {
      IType tpe = ((SourceTypeElementInfo)suppliedType).getHandle();
      IClassFile cf = tpe.getClassFile();
      if (cf instanceof IScalaClassFile) {
        hr.resolve(new Openable[]{(Openable)cf}, new HashSet(), null);
        return;
      }
    }

    proceed(hr, suppliedType);
  }

  void around(HierarchyResolver hr, IType type, ReferenceBinding typeBinding) :
    remember(hr, type, typeBinding) {
    if (((IOpenable)type.getCompilationUnit()).isOpen()) {
      try {
        IGenericType genericType = (IGenericType)((JavaElement)type).getElementInfo();
        hr.remember(genericType, typeBinding);
      } catch (JavaModelException e) {
        // cannot happen since element is open
        return;
      }
    } else {
      if (typeBinding == null) return;

      TypeDeclaration typeDeclaration = ((SourceTypeBinding)typeBinding).scope.referenceType();

      // simple super class name
      char[] superclassName = null;
      TypeReference superclass;
      if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
        superclass = typeDeclaration.allocation.type;
      } else {
        superclass = typeDeclaration.superclass;
      }
      if (superclass != null) {
        char[][] typeName = superclass.getTypeName();
        superclassName = typeName == null ? null : typeName[typeName.length-1];
      }

      // simple super interface names
      char[][] superInterfaceNames = null;
      TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
      if (superInterfaces != null) {
        int length = superInterfaces.length;
        superInterfaceNames = new char[length][];
        for (int i = 0; i < length; i++) {
          TypeReference superInterface = superInterfaces[i];
          char[][] typeName = superInterface.getTypeName();
          superInterfaceNames[i] = typeName[typeName.length-1];
        }
      }

      HierarchyType hierarchyType = new HierarchyType(
        type,
        typeDeclaration.name,
        typeDeclaration.binding.modifiers,
        superclassName,
        superInterfaceNames);
      hr.remember(hierarchyType, typeDeclaration.binding);
    }
  }

  String around(BinaryType bt) :
    getSourceFileName(bt) {
    IJavaElement parent = bt.getParent();
    if (parent instanceof IScalaClassFile)
      return ((IScalaClassFile)parent).getSourceFileName();
    else
      return proceed(bt);
  }

  boolean around(IType type, int acceptFlags, boolean isSourceType) :
    acceptType(type, acceptFlags, isSourceType) {
    if (!isSourceType && (type instanceof SourceType)) {
      IJavaElement parent = type.getParent();
      if (parent instanceof IScalaClassFile)
        return proceed(type, acceptFlags, true);
    }

    return proceed(type, acceptFlags, isSourceType);
  }

  CompilationUnitDeclaration around(SourceTypeConverter stc, ISourceType[] sourceTypes, CompilationResult compilationResult) throws JavaModelException :
    convert(stc, sourceTypes, compilationResult) {
    stc.unit = new CompilationUnitDeclaration(stc.problemReporter, compilationResult, 0);
    // not filled at this point

    if (sourceTypes.length == 0) return stc.unit;
    SourceTypeElementInfo topLevelTypeInfo = (SourceTypeElementInfo) sourceTypes[0];
    org.eclipse.jdt.core.ICompilationUnit cuHandle = topLevelTypeInfo.getHandle().getCompilationUnit();
    stc.cu = (ICompilationUnit) cuHandle;

    CompilationUnitElementInfo cuei = null;
    Object info = ((JavaElement)stc.cu).getElementInfo();
    if (info instanceof CompilationUnitElementInfo)
      cuei = (CompilationUnitElementInfo)info;

    if (stc.has1_5Compliance && cuei != null && cuei.annotationNumber > 10) { // experimental value
      // if more than 10 annotations, diet parse as this is faster
      return new Parser(stc.problemReporter, true).dietParse(stc.cu, compilationResult);
    }

    /* only positions available */
    int start = topLevelTypeInfo.getNameSourceStart();
    int end = topLevelTypeInfo.getNameSourceEnd();

    /* convert package and imports */
    String[] packageName = ((PackageFragment) cuHandle.getParent()).names;
    if (packageName.length > 0)
      // if its null then it is defined in the default package
      stc.unit.currentPackage =
        stc.createImportReference(packageName, start, end, false, ClassFileConstants.AccDefault);
    IImportDeclaration[] importDeclarations = topLevelTypeInfo.getHandle().getCompilationUnit().getImports();
    int importCount = importDeclarations.length;
    stc.unit.imports = new ImportReference[importCount];
    for (int i = 0; i < importCount; i++) {
      ImportDeclaration importDeclaration = (ImportDeclaration) importDeclarations[i];
      ISourceImport sourceImport = (ISourceImport) importDeclaration.getElementInfo();
      String nameWithoutStar = importDeclaration.getNameWithoutStar();
      stc.unit.imports[i] = stc.createImportReference(
        Util.splitOn('.', nameWithoutStar, 0, nameWithoutStar.length()),
        sourceImport.getDeclarationSourceStart(),
        sourceImport.getDeclarationSourceEnd(),
        importDeclaration.isOnDemand(),
        sourceImport.getModifiers());
    }
    /* convert type(s) */
    try {
      int typeCount = sourceTypes.length;
      final TypeDeclaration[] types = new TypeDeclaration[typeCount];
      /*
       * We used a temporary types collection to prevent this.unit.types from being null during a call to
       * convert(...) when the source is syntactically incorrect and the parser is flushing the unit's types.
       * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97466
       */
      for (int i = 0; i < typeCount; i++) {
        SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) sourceTypes[i];
        types[i] = stc.convert((SourceType) typeInfo.getHandle(), compilationResult);
      }
      stc.unit.types = types;
      return stc.unit;
    } catch (SourceTypeConverter.AnonymousMemberFound e) {
      return new Parser(stc.problemReporter, true).parse(stc.cu, compilationResult);
    }
  }

  IJavaElement around(JavaElement je, int ancestorType) :
    getAncestor(je, ancestorType) {
    IJavaElement element = je;
    while (element != null) {
      if (element.getElementType() == ancestorType)
        return element;
      else if (element instanceof IScalaClassFile && ancestorType == IJavaElement.COMPILATION_UNIT)
        return ((JavaElement)element).getCompilationUnit();
      element= element.getParent();
    }
    return null;
  }

  boolean around(TypeNameMatch match) :
    isContainerDirty(match) {
    org.eclipse.jdt.core.ICompilationUnit cu = match.getType().getCompilationUnit();
    if (cu == null) {
      return false;
    }
    IResource resource= cu.getResource();
    if (resource == null)
      return false;

    ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
    ITextFileBuffer textFileBuffer= manager.getTextFileBuffer(resource.getFullPath(), LocationKind.IFILE);
    if (textFileBuffer != null) {
      return textFileBuffer.isDirty();
    }
    return false;
  }
}


NPE: 100% induced by some incorrect AST, but I'm too lazy to dig who is to blame, us or JDT, so fix it here.

/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.core;

import java.util.Locale;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.SourceAnnotationMethodInfo;
import org.eclipse.jdt.internal.core.SourceMethod;
import org.eclipse.jdt.internal.core.SourceMethodElementInfo;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaCompilationUnit;

@SuppressWarnings("restriction")
public privileged aspect DOMAspect {
  pointcut internalCreateAST(ASTParser parser, IProgressMonitor monitor) :
    execution(ASTNode ASTParser.internalCreateAST(IProgressMonitor)) &&
    args(monitor) &&
    target(parser);

  pointcut convert(SourceTypeConverter stc, SourceMethod methodHandle, SourceMethodElementInfo methodInfo, CompilationResult compilationResult) :
    execution(AbstractMethodDeclaration SourceTypeConverter.convert(SourceMethod, SourceMethodElementInfo, CompilationResult)) &&
    args(methodHandle, methodInfo, compilationResult) &&
    target(stc);

  ASTNode around(ASTParser parser, IProgressMonitor monitor) :
    internalCreateAST(parser, monitor) {
    try {
      if (!(parser.typeRoot instanceof IScalaCompilationUnit))
        return proceed(parser, monitor);

      ICompilationUnit cu = (ICompilationUnit)parser.typeRoot;
      org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit)cu;

      IType[] topLevelTypes = cu.getTypes();
      int length = topLevelTypes.length;
      if (length == 0)
        throw new IllegalStateException();

      SourceTypeElementInfo[] topLevelInfos = new SourceTypeElementInfo[length];
      for (int i = 0; i < length; i++) {
        topLevelInfos[i] = (SourceTypeElementInfo) ((SourceType)topLevelTypes[i]).getElementInfo();
      }
      char[] fileName = ((ISourceType)topLevelInfos[0]).getFileName();

      CompilationResult result = new CompilationResult(fileName, 1, 1, 100);

      JavaProject javaProject = (JavaProject)cu.getJavaProject();
      Map compilerOptions0 = javaProject.getOptions(true);
      CompilerOptions compilerOptions = new CompilerOptions(compilerOptions0);
      compilerOptions.storeAnnotations = true;

      ProblemReporter problemReporter =
        new ProblemReporter(
          DefaultErrorHandlingPolicies.proceedWithAllProblems(),
          compilerOptions,
          new DefaultProblemFactory(Locale.getDefault()));

      int flags = SourceTypeConverter.FIELD_AND_METHOD | SourceTypeConverter.MEMBER_TYPE;

      CompilationUnitDeclaration unit =
        SourceTypeConverter.buildCompilationUnit(topLevelInfos, flags, problemReporter, result);

      INameEnvironment ne = javaProject.newSearchableNameEnvironment(DefaultWorkingCopyOwner.PRIMARY);
      final LookupEnvironment le = new LookupEnvironment(null, compilerOptions, problemReporter, ne);
      ITypeRequestor typeRequestor = new ITypeRequestor() {
        public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
          le.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
        }
        public void accept(org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit, AccessRestriction accessRestriction) {}
        public void accept(ISourceType[] sourceType, PackageBinding packageBinding, AccessRestriction accessRestriction) {}
      };
      le.typeRequestor = typeRequestor;

      le.buildTypeBindings(unit, null);
      le.completeTypeBindings();
      fixTypes(unit.types);

      AST ast = AST.newAST(AST.JLS3);
      ast.setFlag(AST.RESOLVED_BINDINGS);
      ast.setDefaultNodeFlag(ASTNode.ORIGINAL);

      org.eclipse.jdt.core.dom.ASTConverter converter =
        new org.eclipse.jdt.core.dom.ASTConverter(compilerOptions0, true, monitor);

      org.eclipse.jdt.core.dom.BindingResolver resolver =
        new org.eclipse.jdt.core.dom.DefaultBindingResolver(
          unit.scope,
          DefaultWorkingCopyOwner.PRIMARY,
          new org.eclipse.jdt.core.dom.DefaultBindingResolver.BindingTables(),
          true);
      ast.setBindingResolver(resolver);
      converter.setAST(ast);

      ASTNode node = converter.convert(unit, sourceUnit.getContents());
      return node;
    } catch (JavaModelException ex) {
      throw new IllegalArgumentException(ex);
    }
  }

  private void fixTypes(TypeDeclaration[] types) {
    for(int i = 0, iLimit = types.length; i < iLimit ; ++i) {
      TypeDeclaration tpe = types[i];
      if (tpe != null) {
        tpe.binding.getAnnotationTagBits();
        tpe.scope.buildFields();
        tpe.scope.buildMethods();
        fixFields(tpe.fields);
        fixMethods(tpe.methods);
        fixTypes(tpe.memberTypes);
      }
    }
  }

  private void fixMethods(AbstractMethodDeclaration[] methods) {
    if (methods == null)
      return;

    for(int i = 0, iLimit = methods.length; i < iLimit; ++i) {
      AbstractMethodDeclaration m = methods[i];
      m.bodyStart = m.declarationSourceStart;
      m.bodyEnd = m.declarationSourceEnd;
      m.binding.getAnnotationTagBits();
    }
  }

  private void fixFields(AbstractVariableDeclaration[] fields) {
    if (fields == null)
      return;

    for(int i = 0, iLimit = fields.length; i < iLimit; ++i) {
      AbstractVariableDeclaration f = fields[i];
      f.declarationEnd = f.declarationSourceEnd;
    }
  }

  AbstractMethodDeclaration around(SourceTypeConverter stc, SourceMethod methodHandle, SourceMethodElementInfo methodInfo, CompilationResult compilationResult) throws JavaModelException :
    convert(stc, methodHandle, methodInfo, compilationResult) {
    AbstractMethodDeclaration method;

    /* only source positions available */
    int start = methodInfo.getNameSourceStart();
    int end = methodInfo.getNameSourceEnd();

    // convert 1.5 specific constructs only if compliance is 1.5 or above
    TypeParameter[] typeParams = null;
    if (stc.has1_5Compliance) {
      /* convert type parameters */
      char[][] typeParameterNames = methodInfo.getTypeParameterNames();
      if (typeParameterNames != null) {
        int parameterCount = typeParameterNames.length;
        if (parameterCount > 0) { // method's type parameters must be null if no type parameter
          char[][][] typeParameterBounds = methodInfo.getTypeParameterBounds();
          typeParams = new TypeParameter[parameterCount];
          for (int i = 0; i < parameterCount; i++) {
            typeParams[i] = stc.createTypeParameter(typeParameterNames[i], typeParameterBounds[i], start, end);
          }
        }
      }
    }

    int modifiers = methodInfo.getModifiers();
    if (methodInfo.isConstructor()) {
      ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult);
      decl.bits &= ~org.eclipse.jdt.internal.compiler.ast.ASTNode.IsDefaultConstructor;
      method = decl;
      decl.typeParameters = typeParams;
    } else {
      MethodDeclaration decl;
      if (methodInfo.isAnnotationMethod()) {
        AnnotationMethodDeclaration annotationMethodDeclaration = new AnnotationMethodDeclaration(compilationResult);

        /* conversion of default value */
        SourceAnnotationMethodInfo annotationMethodInfo = (SourceAnnotationMethodInfo) methodInfo;
        boolean hasDefaultValue = annotationMethodInfo.defaultValueStart != -1 || annotationMethodInfo.defaultValueEnd != -1;
        if ((stc.flags & SourceTypeConverter.FIELD_INITIALIZATION) != 0) {
          if (hasDefaultValue) {
            char[] defaultValueSource = CharOperation.subarray(stc.getSource(), annotationMethodInfo.defaultValueStart, annotationMethodInfo.defaultValueEnd+1);
            if (defaultValueSource != null) {
                Expression expression =  stc.parseMemberValue(defaultValueSource);
                if (expression != null) {
                  annotationMethodDeclaration.defaultValue = expression;
                }
            } else {
              // could not retrieve the default value
              hasDefaultValue = false;
            }
          }
        }
        if (hasDefaultValue)
          modifiers |= ClassFileConstants.AccAnnotationDefault;
        decl = annotationMethodDeclaration;
      } else {
        decl = new MethodDeclaration(compilationResult);
      }

      // convert return type
      decl.returnType = stc.createTypeReference(methodInfo.getReturnTypeName(), start, end);

      // type parameters
      decl.typeParameters = typeParams;

      method = decl;
    }
    method.selector = methodHandle.getElementName().toCharArray();
    boolean isVarargs = (modifiers & ClassFileConstants.AccVarargs) != 0;
    method.modifiers = modifiers & ~ClassFileConstants.AccVarargs;
    method.sourceStart = start;
    method.sourceEnd = end;
    method.declarationSourceStart = methodInfo.getDeclarationSourceStart();
    method.declarationSourceEnd = methodInfo.getDeclarationSourceEnd();

    // convert 1.5 specific constructs only if compliance is 1.5 or above
    if (stc.has1_5Compliance) {
      /* convert annotations */
      method.annotations = stc.convertAnnotations(methodHandle);
    }

    /* convert arguments */
    String[] argumentTypeSignatures = methodHandle.getParameterTypes();
    char[][] argumentNames = methodInfo.getArgumentNames();
    int argumentCount = argumentTypeSignatures == null ? 0 : argumentTypeSignatures.length;
    if (argumentCount > 0) {
      long position = ((long) start << 32) + end;
      method.arguments = new Argument[argumentCount];
      for (int i = 0; i < argumentCount; i++) {
        TypeReference typeReference = stc.createTypeReference(argumentTypeSignatures[i], start, end);
        if (isVarargs && i == argumentCount-1) {
          typeReference.bits |= org.eclipse.jdt.internal.compiler.ast.ASTNode.IsVarArgs;
        }
        method.arguments[i] =
          new Argument(
            argumentNames[i],
            position,
            typeReference,
            ClassFileConstants.AccDefault);
        // do not care whether was final or not
      }
    }

    /* convert thrown exceptions */
    char[][] exceptionTypeNames = methodInfo.getExceptionTypeNames();
    int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length;
    if (exceptionCount > 0) {
      method.thrownExceptions = new TypeReference[exceptionCount];
      for (int i = 0; i < exceptionCount; i++) {
        method.thrownExceptions[i] =
          stc.createTypeReference(exceptionTypeNames[i], start, end);
      }
    }

    /* convert local and anonymous types */
    if ((stc.flags & SourceTypeConverter.LOCAL_TYPE) != 0) {
      IJavaElement[] children = methodInfo.getChildren();
      int typesLength = 0;
      int childrenLength = children.length;
      for (int i = 0; i < childrenLength; ++i)
        if (children[i] instanceof SourceType)
          ++typesLength;

      if (typesLength != 0) {
        Statement[] statements = new Statement[typesLength];
        int typeIndex = 0;
        for (int i = 0; i < childrenLength; i++) {
          if (children[i] instanceof SourceType) {
            SourceType type = (SourceType) children[i];
            TypeDeclaration localType = stc.convert(type, compilationResult);
            if ((localType.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsAnonymousType) != 0) {
              QualifiedAllocationExpression expression = new QualifiedAllocationExpression(localType);
              expression.type = localType.superclass;
              localType.superclass = null;
              localType.superInterfaces = null;
              localType.allocation = expression;
              statements[typeIndex] = expression;
            } else {
              statements[typeIndex] = localType;
            }
            ++typeIndex;
          }
        }
        method.statements = statements;
      }
    }

    return method;
  }
}

/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.core;

import java.util.Locale;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.SourceAnnotationMethodInfo;
import org.eclipse.jdt.internal.core.SourceMethod;
import org.eclipse.jdt.internal.core.SourceMethodElementInfo;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaCompilationUnit;

@SuppressWarnings("restriction")
public privileged aspect DOMAspect {
  pointcut internalCreateAST(ASTParser parser, IProgressMonitor monitor) :
    execution(ASTNode ASTParser.internalCreateAST(IProgressMonitor)) &&
    args(monitor) &&
    target(parser);

  pointcut convert(SourceTypeConverter stc, SourceMethod methodHandle, SourceMethodElementInfo methodInfo, CompilationResult compilationResult) :
    execution(AbstractMethodDeclaration SourceTypeConverter.convert(SourceMethod, SourceMethodElementInfo, CompilationResult)) &&
    args(methodHandle, methodInfo, compilationResult) &&
    target(stc);

  ASTNode around(ASTParser parser, IProgressMonitor monitor) :
    internalCreateAST(parser, monitor) {
    try {
      if (!(parser.typeRoot instanceof IScalaCompilationUnit))
        return proceed(parser, monitor);

      ICompilationUnit cu = (ICompilationUnit)parser.typeRoot;
      org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit)cu;

      IType[] topLevelTypes = cu.getTypes();
      int length = topLevelTypes.length;
      if (length == 0)
        throw new IllegalStateException();

      SourceTypeElementInfo[] topLevelInfos = new SourceTypeElementInfo[length];
      for (int i = 0; i < length; i++) {
        topLevelInfos[i] = (SourceTypeElementInfo) ((SourceType)topLevelTypes[i]).getElementInfo();
      }
      char[] fileName = ((ISourceType)topLevelInfos[0]).getFileName();

      CompilationResult result = new CompilationResult(fileName, 1, 1, 100);

      JavaProject javaProject = (JavaProject)cu.getJavaProject();
      Map compilerOptions0 = javaProject.getOptions(true);
      CompilerOptions compilerOptions = new CompilerOptions(compilerOptions0);
      compilerOptions.storeAnnotations = true;

      ProblemReporter problemReporter =
        new ProblemReporter(
          DefaultErrorHandlingPolicies.proceedWithAllProblems(),
          compilerOptions,
          new DefaultProblemFactory(Locale.getDefault()));

      int flags = SourceTypeConverter.FIELD_AND_METHOD | SourceTypeConverter.MEMBER_TYPE;

      CompilationUnitDeclaration unit =
        SourceTypeConverter.buildCompilationUnit(topLevelInfos, flags, problemReporter, result);

      INameEnvironment ne = javaProject.newSearchableNameEnvironment(DefaultWorkingCopyOwner.PRIMARY);
      final LookupEnvironment le = new LookupEnvironment(null, compilerOptions, problemReporter, ne);
      ITypeRequestor typeRequestor = new ITypeRequestor() {
        public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
          le.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
        }
        public void accept(org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit, AccessRestriction accessRestriction) {}
        public void accept(ISourceType[] sourceType, PackageBinding packageBinding, AccessRestriction accessRestriction) {}
      };
      le.typeRequestor = typeRequestor;

      le.buildTypeBindings(unit, null);
      le.completeTypeBindings();
      fixTypes(unit.types);

      AST ast = AST.newAST(AST.JLS3);
      ast.setFlag(AST.RESOLVED_BINDINGS);
      ast.setDefaultNodeFlag(ASTNode.ORIGINAL);

      org.eclipse.jdt.core.dom.ASTConverter converter =
        new org.eclipse.jdt.core.dom.ASTConverter(compilerOptions0, true, monitor);

      org.eclipse.jdt.core.dom.BindingResolver resolver =
        new org.eclipse.jdt.core.dom.DefaultBindingResolver(
          unit.scope,
          DefaultWorkingCopyOwner.PRIMARY,
          new org.eclipse.jdt.core.dom.DefaultBindingResolver.BindingTables(),
          true);
      ast.setBindingResolver(resolver);
      converter.setAST(ast);

      ASTNode node = converter.convert(unit, sourceUnit.getContents());
      return node;
    } catch (JavaModelException ex) {
      throw new IllegalArgumentException(ex);
    }
  }

  private void fixTypes(TypeDeclaration[] types) {
    for(int i = 0, iLimit = types.length; i < iLimit ; ++i) {
      TypeDeclaration tpe = types[i];
      tpe.binding.getAnnotationTagBits();
      tpe.scope.buildFields();
      tpe.scope.buildMethods();
      fixFields(tpe.fields);
      fixMethods(tpe.methods);
      fixTypes(tpe.memberTypes);
    }
  }

  private void fixMethods(AbstractMethodDeclaration[] methods) {
    if (methods == null)
      return;

    for(int i = 0, iLimit = methods.length; i < iLimit; ++i) {
      AbstractMethodDeclaration m = methods[i];
      m.bodyStart = m.declarationSourceStart;
      m.bodyEnd = m.declarationSourceEnd;
      m.binding.getAnnotationTagBits();
    }
  }

  private void fixFields(AbstractVariableDeclaration[] fields) {
    if (fields == null)
      return;

    for(int i = 0, iLimit = fields.length; i < iLimit; ++i) {
      AbstractVariableDeclaration f = fields[i];
      f.declarationEnd = f.declarationSourceEnd;
    }
  }

  AbstractMethodDeclaration around(SourceTypeConverter stc, SourceMethod methodHandle, SourceMethodElementInfo methodInfo, CompilationResult compilationResult) throws JavaModelException :
    convert(stc, methodHandle, methodInfo, compilationResult) {
    AbstractMethodDeclaration method;

    /* only source positions available */
    int start = methodInfo.getNameSourceStart();
    int end = methodInfo.getNameSourceEnd();

    // convert 1.5 specific constructs only if compliance is 1.5 or above
    TypeParameter[] typeParams = null;
    if (stc.has1_5Compliance) {
      /* convert type parameters */
      char[][] typeParameterNames = methodInfo.getTypeParameterNames();
      if (typeParameterNames != null) {
        int parameterCount = typeParameterNames.length;
        if (parameterCount > 0) { // method's type parameters must be null if no type parameter
          char[][][] typeParameterBounds = methodInfo.getTypeParameterBounds();
          typeParams = new TypeParameter[parameterCount];
          for (int i = 0; i < parameterCount; i++) {
            typeParams[i] = stc.createTypeParameter(typeParameterNames[i], typeParameterBounds[i], start, end);
          }
        }
      }
    }

    int modifiers = methodInfo.getModifiers();
    if (methodInfo.isConstructor()) {
      ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult);
      decl.bits &= ~org.eclipse.jdt.internal.compiler.ast.ASTNode.IsDefaultConstructor;
      method = decl;
      decl.typeParameters = typeParams;
    } else {
      MethodDeclaration decl;
      if (methodInfo.isAnnotationMethod()) {
        AnnotationMethodDeclaration annotationMethodDeclaration = new AnnotationMethodDeclaration(compilationResult);

        /* conversion of default value */
        SourceAnnotationMethodInfo annotationMethodInfo = (SourceAnnotationMethodInfo) methodInfo;
        boolean hasDefaultValue = annotationMethodInfo.defaultValueStart != -1 || annotationMethodInfo.defaultValueEnd != -1;
        if ((stc.flags & SourceTypeConverter.FIELD_INITIALIZATION) != 0) {
          if (hasDefaultValue) {
            char[] defaultValueSource = CharOperation.subarray(stc.getSource(), annotationMethodInfo.defaultValueStart, annotationMethodInfo.defaultValueEnd+1);
            if (defaultValueSource != null) {
                Expression expression =  stc.parseMemberValue(defaultValueSource);
                if (expression != null) {
                  annotationMethodDeclaration.defaultValue = expression;
                }
            } else {
              // could not retrieve the default value
              hasDefaultValue = false;
            }
          }
        }
        if (hasDefaultValue)
          modifiers |= ClassFileConstants.AccAnnotationDefault;
        decl = annotationMethodDeclaration;
      } else {
        decl = new MethodDeclaration(compilationResult);
      }

      // convert return type
      decl.returnType = stc.createTypeReference(methodInfo.getReturnTypeName(), start, end);

      // type parameters
      decl.typeParameters = typeParams;

      method = decl;
    }
    method.selector = methodHandle.getElementName().toCharArray();
    boolean isVarargs = (modifiers & ClassFileConstants.AccVarargs) != 0;
    method.modifiers = modifiers & ~ClassFileConstants.AccVarargs;
    method.sourceStart = start;
    method.sourceEnd = end;
    method.declarationSourceStart = methodInfo.getDeclarationSourceStart();
    method.declarationSourceEnd = methodInfo.getDeclarationSourceEnd();

    // convert 1.5 specific constructs only if compliance is 1.5 or above
    if (stc.has1_5Compliance) {
      /* convert annotations */
      method.annotations = stc.convertAnnotations(methodHandle);
    }

    /* convert arguments */
    String[] argumentTypeSignatures = methodHandle.getParameterTypes();
    char[][] argumentNames = methodInfo.getArgumentNames();
    int argumentCount = argumentTypeSignatures == null ? 0 : argumentTypeSignatures.length;
    if (argumentCount > 0) {
      long position = ((long) start << 32) + end;
      method.arguments = new Argument[argumentCount];
      for (int i = 0; i < argumentCount; i++) {
        TypeReference typeReference = stc.createTypeReference(argumentTypeSignatures[i], start, end);
        if (isVarargs && i == argumentCount-1) {
          typeReference.bits |= org.eclipse.jdt.internal.compiler.ast.ASTNode.IsVarArgs;
        }
        method.arguments[i] =
          new Argument(
            argumentNames[i],
            position,
            typeReference,
            ClassFileConstants.AccDefault);
        // do not care whether was final or not
      }
    }

    /* convert thrown exceptions */
    char[][] exceptionTypeNames = methodInfo.getExceptionTypeNames();
    int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length;
    if (exceptionCount > 0) {
      method.thrownExceptions = new TypeReference[exceptionCount];
      for (int i = 0; i < exceptionCount; i++) {
        method.thrownExceptions[i] =
          stc.createTypeReference(exceptionTypeNames[i], start, end);
      }
    }

    /* convert local and anonymous types */
    if ((stc.flags & SourceTypeConverter.LOCAL_TYPE) != 0) {
      IJavaElement[] children = methodInfo.getChildren();
      int typesLength = 0;
      int childrenLength = children.length;
      for (int i = 0; i < childrenLength; ++i)
        if (children[i] instanceof SourceType)
          ++typesLength;

      if (typesLength != 0) {
        Statement[] statements = new Statement[typesLength];
        int typeIndex = 0;
        for (int i = 0; i < childrenLength; i++) {
          if (children[i] instanceof SourceType) {
            SourceType type = (SourceType) children[i];
            TypeDeclaration localType = stc.convert(type, compilationResult);
            if ((localType.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsAnonymousType) != 0) {
              QualifiedAllocationExpression expression = new QualifiedAllocationExpression(localType);
              expression.type = localType.superclass;
              localType.superclass = null;
              localType.superInterfaces = null;
              localType.allocation = expression;
              statements[typeIndex] = expression;
            } else {
              statements[typeIndex] = localType;
            }
            ++typeIndex;
          }
        }
        method.statements = statements;
      }
    }

    return method;
  }
}


Fixed #2884.

Fixed #2884.

git-svn-id: f4ecfe233223879a4a16cd7937f11b5152963d8e@20439 5e8d7ff9-d8ef-0310-90f0-a4852d11357a

/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.core;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.IJavaElementRequestor;
import org.eclipse.jdt.internal.core.NameLookup;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaCompilationUnit;
import scala.tools.eclipse.contribution.weaving.jdt.IScalaElement;

@SuppressWarnings("restriction")
public privileged aspect NameLookupAspect {
  pointcut seekTypesInSourcePackage(
    NameLookup nl,
    String name,
    IPackageFragment pkg,
    int firstDot,
    boolean partialMatch,
    String topLevelTypeName,
    int acceptFlags,
    IJavaElementRequestor requestor) :
    execution(void NameLookup.seekTypesInSourcePackage(
      String,
      IPackageFragment,
      int,
      boolean,
      String,
      int,
      IJavaElementRequestor)) &&
    target(nl) &&
    args(
      name,
      pkg,
      firstDot,
      partialMatch,
      topLevelTypeName,
      acceptFlags,
      requestor);

  void around(
    NameLookup nl,
    String name,
    IPackageFragment pkg,
    int firstDot,
    boolean partialMatch,
    String topLevelTypeName,
    int acceptFlags,
    IJavaElementRequestor requestor) :
      seekTypesInSourcePackage(
        nl,
        name,
        pkg,
        firstDot,
        partialMatch,
        topLevelTypeName,
        acceptFlags,
        requestor) {

    long start = -1;
    if (NameLookup.VERBOSE)
      start = System.currentTimeMillis();
    try {
      if (!partialMatch) {
        try {
          IJavaElement[] compilationUnits = pkg.getChildren();
          for (int i = 0, length = compilationUnits.length; i < length; i++) {
            if (requestor.isCanceled())
              return;
            IJavaElement cu = compilationUnits[i];
            String cuName = cu.getElementName();
            int lastDot = cuName.lastIndexOf('.');
            boolean isScala = cu instanceof IScalaCompilationUnit;
            if (!isScala && (lastDot != topLevelTypeName.length() || !topLevelTypeName.regionMatches(0, cuName, 0, lastDot)))
              continue;
            IType type = ((ICompilationUnit) cu).getType(topLevelTypeName);
            type = nl.getMemberType(type, name, firstDot);
            if ((isScala && (type instanceof IScalaElement)) || (!isScala && nl.acceptType(type, acceptFlags, true/*a source type*/))) { // accept type checks for existence unless cu is Scala
              requestor.acceptType(type);
              break;  // since an exact match was requested, no other matching type can exist
            }
          }
        } catch (JavaModelException e) {
          // package doesn't exist -> ignore
        }
      } else {
        try {
          String cuPrefix = firstDot == -1 ? name : name.substring(0, firstDot);
          IJavaElement[] compilationUnits = pkg.getChildren();
          for (int i = 0, length = compilationUnits.length; i < length; i++) {
            if (requestor.isCanceled())
              return;
            IJavaElement cu = compilationUnits[i];
            if (!(cu instanceof IScalaCompilationUnit) && !cu.getElementName().toLowerCase().startsWith(cuPrefix))
              continue;
            try {
              IType[] types = ((ICompilationUnit) cu).getTypes();
              for (int j = 0, typeLength = types.length; j < typeLength; j++)
                nl.seekTypesInTopLevelType(name, firstDot, types[j], requestor, acceptFlags);
            } catch (JavaModelException e) {
              // cu doesn't exist -> ignore
            }
          }
        } catch (JavaModelException e) {
          // package doesn't exist -> ignore
        }
      }
    } finally {
      if (NameLookup.VERBOSE)
        nl.timeSpentInSeekTypesInSourcePackage += System.currentTimeMillis()-start;
    }
  }
}

/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.core;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.IJavaElementRequestor;
import org.eclipse.jdt.internal.core.NameLookup;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaCompilationUnit;

@SuppressWarnings("restriction")
public privileged aspect NameLookupAspect {
  pointcut seekTypesInSourcePackage(
    NameLookup nl,
    String name,
    IPackageFragment pkg,
    int firstDot,
    boolean partialMatch,
    String topLevelTypeName,
    int acceptFlags,
    IJavaElementRequestor requestor) :
    execution(void NameLookup.seekTypesInSourcePackage(
      String,
      IPackageFragment,
      int,
      boolean,
      String,
      int,
      IJavaElementRequestor)) &&
    target(nl) &&
    args(
      name,
      pkg,
      firstDot,
      partialMatch,
      topLevelTypeName,
      acceptFlags,
      requestor);

  void around(
    NameLookup nl,
    String name,
    IPackageFragment pkg,
    int firstDot,
    boolean partialMatch,
    String topLevelTypeName,
    int acceptFlags,
    IJavaElementRequestor requestor) :
      seekTypesInSourcePackage(
        nl,
        name,
        pkg,
        firstDot,
        partialMatch,
        topLevelTypeName,
        acceptFlags,
        requestor) {

    long start = -1;
    if (NameLookup.VERBOSE)
      start = System.currentTimeMillis();
    try {
      if (!partialMatch) {
        try {
          IJavaElement[] compilationUnits = pkg.getChildren();
          for (int i = 0, length = compilationUnits.length; i < length; i++) {
            if (requestor.isCanceled())
              return;
            IJavaElement cu = compilationUnits[i];
            String cuName = cu.getElementName();
            int lastDot = cuName.lastIndexOf('.');
            if (!(cu instanceof IScalaCompilationUnit) && (lastDot != topLevelTypeName.length() || !topLevelTypeName.regionMatches(0, cuName, 0, lastDot)))
              continue;
            IType type = ((ICompilationUnit) cu).getType(topLevelTypeName);
            type = nl.getMemberType(type, name, firstDot);
            if (nl.acceptType(type, acceptFlags, true/*a source type*/)) { // accept type checks for existence
              requestor.acceptType(type);
              break;  // since an exact match was requested, no other matching type can exist
            }
          }
        } catch (JavaModelException e) {
          // package doesn't exist -> ignore
        }
      } else {
        try {
          String cuPrefix = firstDot == -1 ? name : name.substring(0, firstDot);
          IJavaElement[] compilationUnits = pkg.getChildren();
          for (int i = 0, length = compilationUnits.length; i < length; i++) {
            if (requestor.isCanceled())
              return;
            IJavaElement cu = compilationUnits[i];
            if (!(cu instanceof IScalaCompilationUnit) && !cu.getElementName().toLowerCase().startsWith(cuPrefix))
              continue;
            try {
              IType[] types = ((ICompilationUnit) cu).getTypes();
              for (int j = 0, typeLength = types.length; j < typeLength; j++)
                nl.seekTypesInTopLevelType(name, firstDot, types[j], requestor, acceptFlags);
            } catch (JavaModelException e) {
              // cu doesn't exist -> ignore
            }
          }
        } catch (JavaModelException e) {
          // package doesn't exist -> ignore
        }
      }
    } finally {
      if (NameLookup.VERBOSE)
        nl.timeSpentInSeekTypesInSourcePackage += System.currentTimeMillis()-start;
    }
  }
}


Strange... SAIS seems to have a memory complexity equal to naive sort (no extra memory allocation). The aspect is correct, the only way I can explain this is that internal variables inside methods
are freed before the actual calculation of the memory usage.

git-svn-id: 4050ee570c0b454ed3c2eee326cdaf8b6ad603bd@35 e65ff1b4-dc2a-11dd-afbb-e3e17473af86

package org.jsuffixarrays;

/**
 * This aspect logs the memory state at entry and exit from methods
 * declared in inheriting aspects. The aspect is a singleton, so is generally
 * not very useful for multi-threaded applications or whenever more than one instance
 * of a given instrumented class is used.
 */
abstract aspect MemoryLogger issingleton()
{
    /**
     * Declare classes to track memory from.
     */
    abstract pointcut tracedClasses();

    /**
     * Override and remove methods for which logging should not occur.
     */
    pointcut excludedMethods() : !execution(* *(..));

    /**
     * Declare methods to track memory in.
     */
    final pointcut tracedMethods() :
        tracedClasses() && execution(* *(..)) && !excludedMethods();

    /**
     *
     */
    before () : tracedClasses() && tracedMethods()
    {
        update();
    }

    /**
     *
     */
    after () returning : tracedMethods()
    {
        update();
    }

    /**
     * Starting amount of memory from which we will begin measurements.
     *
     * @see #reset()
     */
    private static volatile long startingPoint;

    /*
     *
     */
    private static volatile long maxMemoryUsed;

    /*
     *
     */
    private static void update()
    {
        final long now = getUsedMemory();
        if (maxMemoryUsed < now)
        {
            maxMemoryUsed = now;
        }
    }

    /*
     *
     */
    private static long getUsedMemory()
    {
        final Runtime rt = Runtime.getRuntime();
        return rt.totalMemory() - rt.freeMemory();
    }

    /**
     * Reset memory status, preparing for measurement.
     */
    public static void reset()
    {
        // Try to clean the GC. Will not work for parallel GC, but we did our best.
        for (int i = 0; i < 5; i++)
        {
            System.gc();
        }

        startingPoint = getUsedMemory();
        maxMemoryUsed = 0;
    }

    /**
     * Returns the absolute memory peak recorded so far.
     */
    public static long getMemoryPeak()
    {
        return maxMemoryUsed;
    }

    /**
     * Returns the maximum memory difference from the last time
     * since {@link #reset()} was called. This value may be negative
     * with certain GCs and scenarios.
     */
    public static long getMemoryUsed()
    {
        return maxMemoryUsed - startingPoint;
    }
}

/**
 * Track memory in {@link Skew} algorithm.
 */
aspect SkewMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(Skew);
    @Override
    pointcut excludedMethods(): execution(* leq*(..));
}

/**
 * Track memory in {@link NaiveSort} algorithm.
 */
aspect NaiveSortMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(NaiveSort);
    @Override
    pointcut excludedMethods(): execution(* compare(..));
}

/**
 * Track memory in {@link DivSufSort} algorithm.
 */
aspect DivSufSortMemLogger extends MemoryLogger
{
    /* 3 methods using stack are excluded, because they use max. 64 * 4 bytes of extra memory for stack */
    // TODO: somehow exclude TRBudget class; within(DivSufSort && !DivSufSort.TRBudget) does not work);
    @Override
    pointcut tracedClasses(): within(DivSufSort);
    @Override
    pointcut excludedMethods(): execution(private * *(..)) ;
}

/**
 * Track memory in {@link QSufSort} algorithm.
 */
aspect QSUfSortMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(QSufSort);
    @Override
    pointcut excludedMethods(): execution(private * *(..));
}

/**
 * Track memory in {@link BPR} algorithm.
 */
aspect BPRMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(BPR);
    @Override
    pointcut excludedMethods(): execution(private * *(..));
}

/**
 * Track memory in {@link DeepShallow} algorithm.
 */
aspect DeepShallowMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(DeepShallow);
    @Override
    pointcut excludedMethods(): execution(private * *(..));
}

/**
 * Track memory in {@link SAIS} algorithm.
 */
aspect SaisMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(SAIS) && !within(org.jsuffixarrays.SAIS..*);

    @Override
    pointcut excludedMethods(): execution(private * *(..))
        && !execution(private * SA_IS(..))
        && !execution(private * induceSA(..));
}

package org.jsuffixarrays;

/**
 * This aspect logs the memory state at entry and exit from methods
 * declared in inheriting aspects. The aspect is a singleton, so is generally
 * not very useful for multi-threaded applications or whenever more than one instance
 * of a given instrumented class is used.
 */
abstract aspect MemoryLogger issingleton()
{
    /**
     * Declare classes to track memory from.
     */
    abstract pointcut tracedClasses();

    /**
     * Override and remove methods for which logging should not occur.
     */
    pointcut excludedMethods() : !execution(* *(..));

    /**
     * Declare methods to track memory in.
     */
    final pointcut tracedMethods() :
        tracedClasses() && execution(* *(..)) && !excludedMethods();

    /**
     *
     */
    before () : tracedClasses() && tracedMethods()
    {
        update();
    }

    /**
     *
     */
    after () returning : tracedMethods()
    {
        update();
    }

    /**
     * Starting amount of memory from which we will begin measurements.
     *
     * @see #reset()
     */
    private static volatile long startingPoint;

    /*
     *
     */
    private static volatile long maxMemoryUsed;

    /*
     *
     */
    private static void update()
    {
        final long now = getUsedMemory();
        if (maxMemoryUsed < now)
        {
            maxMemoryUsed = now;
        }
    }

    /*
     *
     */
    private static long getUsedMemory()
    {
        final Runtime rt = Runtime.getRuntime();
        return rt.totalMemory() - rt.freeMemory();
    }

    /**
     * Reset memory status, preparing for measurement.
     */
    public static void reset()
    {
        // Try to clean the GC. Will not work for parallel GC, but we did our best.
        for (int i = 0; i < 5; i++)
        {
            System.gc();
        }

        startingPoint = getUsedMemory();
        maxMemoryUsed = 0;
    }

    /**
     * Returns the absolute memory peak recorded so far.
     */
    public static long getMemoryPeak()
    {
        return maxMemoryUsed;
    }

    /**
     * Returns the maximum memory difference from the last time
     * since {@link #reset()} was called. This value may be negative
     * with certain GCs and scenarios.
     */
    public static long getMemoryUsed()
    {
        return maxMemoryUsed - startingPoint;
    }
}

/**
 * Track memory in {@link Skew} algorithm.
 */
aspect SkewMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(Skew);
    @Override
    pointcut excludedMethods(): execution(* leq*(..));
}

/**
 * Track memory in {@link NaiveSort} algorithm.
 */
aspect NaiveSortMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(NaiveSort);
    @Override
    pointcut excludedMethods(): execution(* compare(..));
}

/**
 * Track memory in {@link DivSufSort} algorithm.
 */
aspect DivSufSortMemLogger extends MemoryLogger
{
    /* 3 methods using stack are excluded, because they use max. 64 * 4 bytes of extra memory for stack */
    // TODO: somehow exclude TRBudget class; within(DivSufSort && !DivSufSort.TRBudget) does not work);
    @Override
    pointcut tracedClasses(): within(DivSufSort);
    @Override
    pointcut excludedMethods(): execution(private * *(..)) ;
}

/**
 * Track memory in {@link QSufSort} algorithm.
 */
aspect QSUfSortMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(QSufSort);
    @Override
    pointcut excludedMethods(): execution(private * *(..));
}

/**
 * Track memory in {@link BPR} algorithm.
 */
aspect BPRMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(BPR);
    @Override
    pointcut excludedMethods(): execution(private * *(..));
}

/**
 * Track memory in {@link DeepShallow} algorithm.
 */
aspect DeepShallowMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(DeepShallow);
    @Override
    pointcut excludedMethods(): execution(private * *(..));
}

/**
 * Track memory in {@link SAIS} algorithm.
 */
aspect SaisMemLogger extends MemoryLogger
{
    @Override
    pointcut tracedClasses() : within(SAIS) && !within(org.jsuffixarrays.SAIS..*);
    @Override
    pointcut excludedMethods(): execution(private * *(..));
}


Add a precedence for Program adapter of core project

/*
 *     ParallelJ, framework for parallel computing
 *
 *     Copyright (C) 2010, 2011, 2012 Atos Worldline or third-party contributors as
 *     indicated by the @author tags or express copyright attribution
 *     statements applied by the authors.
 *
 *     This library is free software; you can redistribute it and/or
 *     modify it under the terms of the GNU Lesser General Public
 *     License as published by the Free Software Foundation; either
 *     version 2.1 of the License.
 *
 *     This library is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *     Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public
 *     License along with this library; if not, write to the Free Software
 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
package org.parallelj.launching.quartz;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.parallelj.Programs;
import org.parallelj.Programs.ProcessHelper;
import org.parallelj.internal.kernel.KCall;
import org.parallelj.internal.kernel.KProgram;
import org.parallelj.internal.reflect.ProgramAdapter;
import org.parallelj.internal.reflect.ProgramAdapter.Adapter;
import org.parallelj.launching.LaunchingMessageKind;
import org.parallelj.launching.ReturnCodes;
import org.parallelj.mirror.ProgramType;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * Implements the Job.execute(..) method
 *
 *
 */
privileged public aspect ProgramJobsAdapter percflow (execution(public void Job+.execute(..) throws JobExecutionException)) {

	/**
	 * The JobExecutionContext where get Program's arguments ant where to put
	 * the Result.
	 */
	public JobExecutionContext context;

	/*
	 * The Aspect JobsAdapter must be passed before this.
	 */
	declare precedence :
		org.parallelj.internal.reflect.ProgramAdapter,
		org.parallelj.launching.quartz.JobsAdapter;

	private Adapter adpater;

	/**
	 * Launch a Program and initialize the Result as a JobDataMap.
	 *
	 * @param self
	 * @param context
	 * @throws JobExecutionException
	 */
	void around(Job self, JobExecutionContext context)
			throws JobExecutionException :
		execution( public void  Job+.execute(..) throws JobExecutionException)
			&& (within(@org.parallelj.Program *) || within(JobsAdapter))
				&& args(context) && this(self) {
		this.adpater = (Adapter) self;
		this.context = context;
		JobDataMap jobDataMap = new JobDataMap();
		context.setResult(jobDataMap);
		jobDataMap.put(QuartzUtils.RETURN_CODE, ReturnCodes.SUCCESS);
		try {
			proceed(self, context);

			try {
				// Initialize an ExecutorService with the Capacity of the Program
				ProcessHelper<?> processHelper = Programs.as((Adapter) self);
				ProgramType programType = processHelper.getProcess().getProgram();
				ExecutorService service = null;
				if (programType instanceof KProgram) {
					short programCapacity = ((KProgram) programType)
							.getCapacity();
					service = (programCapacity == Short.MAX_VALUE) ? Executors
							.newCachedThreadPool() : Executors
							.newFixedThreadPool(programCapacity);
				} else {
					service = Executors
							.newCachedThreadPool();
				}
				// Launch the program with the initialized ExecutorService
				processHelper.execute(service).join();
				service.shutdown();
				ProgramFieldsBinder.getProgramOutputFields(this, context);
			} catch (IllegalAccessException e) {
				jobDataMap.put(QuartzUtils.RETURN_CODE, ReturnCodes.FAILURE);
			} catch (NoSuchFieldException e) {
				jobDataMap.put(QuartzUtils.RETURN_CODE, ReturnCodes.FAILURE);
			}
		} catch (InvocationTargetException e) {
			jobDataMap.put(QuartzUtils.RETURN_CODE, ReturnCodes.FAILURE);
		}
	}

	/**
	 * Intercept Exception thrown in RunnableProcedure/CallableProcedure for
	 * tracing. If an Exception is thrown, the return code of a Launch becomes
	 * FAILURE.
	 *
	 * @param self
	 */
	pointcut enter(KCall _kCall): call(* org.parallelj.internal.kernel.callback.Entry+.enter(KCall)) && args(_kCall);

	pointcut invoke(): call(public Object Method.invoke(Object, ..)) && !within(ProgramJobsAdapter);

	after(Object oo, KCall _kCall) throwing (InvocationTargetException ite) :
    	invoke() && args(oo, ..) && cflow(enter(_kCall)) {

		LaunchingMessageKind.ELAUNCH0002.format(this.adpater, ite);
		if (this.context != null && this.context.getResult() != null
				&& this.context.getResult() instanceof JobDataMap) {
			((JobDataMap) this.context.getResult()).put(
					QuartzUtils.RETURN_CODE, ReturnCodes.FAILURE);
		}
	}
}

/*
 *     ParallelJ, framework for parallel computing
 *
 *     Copyright (C) 2010, 2011, 2012 Atos Worldline or third-party contributors as
 *     indicated by the @author tags or express copyright attribution
 *     statements applied by the authors.
 *
 *     This library is free software; you can redistribute it and/or
 *     modify it under the terms of the GNU Lesser General Public
 *     License as published by the Free Software Foundation; either
 *     version 2.1 of the License.
 *
 *     This library is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *     Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public
 *     License along with this library; if not, write to the Free Software
 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
package org.parallelj.launching.quartz;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.parallelj.Programs;
import org.parallelj.Programs.ProcessHelper;
import org.parallelj.internal.kernel.KCall;
import org.parallelj.internal.kernel.KProgram;
import org.parallelj.internal.kernel.KReflection;
import org.parallelj.internal.reflect.ProgramAdapter.Adapter;
import org.parallelj.launching.LaunchingMessageKind;
import org.parallelj.launching.ReturnCodes;
import org.parallelj.mirror.ProgramType;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * Implements the Job.execute(..) method
 *
 *
 */
privileged public aspect ProgramJobsAdapter percflow (execution(public void Job+.execute(..) throws JobExecutionException)) {

	/**
	 * The JobExecutionContext where get Program's arguments ant where to put
	 * the Result.
	 */
	public JobExecutionContext context;

	/*
	 * The Aspect JobsAdapter must be passed before this.
	 */
	declare precedence :
		org.parallelj.launching.quartz.JobsAdapter;

	private Adapter adpater;

	/**
	 * Launch a Program and initialize the Result as a JobDataMap.
	 *
	 * @param self
	 * @param context
	 * @throws JobExecutionException
	 */
	void around(Job self, JobExecutionContext context)
			throws JobExecutionException :
		execution( public void  Job+.execute(..) throws JobExecutionException)
			&& (within(@org.parallelj.Program *) || within(JobsAdapter))
				&& args(context) && this(self) {
		this.adpater = (Adapter) self;
		this.context = context;
		JobDataMap jobDataMap = new JobDataMap();
		context.setResult(jobDataMap);
		jobDataMap.put(QuartzUtils.RETURN_CODE, ReturnCodes.SUCCESS);
		try {
			proceed(self, context);

			try {
				// Initialize an ExecutorService with the Capacity of the Program
				ProcessHelper<?> processHelper = Programs.as((Adapter) self);
				ProgramType programType = processHelper.getProcess().getProgram();
				ExecutorService service = null;
				if (programType instanceof KProgram) {
					short programCapacity = ((KProgram) programType)
							.getCapacity();
					service = (programCapacity == Short.MAX_VALUE) ? Executors
							.newCachedThreadPool() : Executors
							.newFixedThreadPool(programCapacity);
				} else {
					service = Executors
							.newCachedThreadPool();
				}
				// Launch the program with the initialized ExecutorService
				processHelper.execute(service).join();
				service.shutdown();
				ProgramFieldsBinder.getProgramOutputFields(this, context);
			} catch (IllegalAccessException e) {
				jobDataMap.put(QuartzUtils.RETURN_CODE, ReturnCodes.FAILURE);
			} catch (NoSuchFieldException e) {
				jobDataMap.put(QuartzUtils.RETURN_CODE, ReturnCodes.FAILURE);
			}
		} catch (InvocationTargetException e) {
			jobDataMap.put(QuartzUtils.RETURN_CODE, ReturnCodes.FAILURE);
		}
	}

	/**
	 * Intercept Exception thrown in RunnableProcedure/CallableProcedure for
	 * tracing. If an Exception is thrown, the return code of a Launch becomes
	 * FAILURE.
	 *
	 * @param self
	 */
	pointcut enter(KCall _kCall): call(* org.parallelj.internal.kernel.callback.Entry+.enter(KCall)) && args(_kCall);

	pointcut invoke(): call(public Object Method.invoke(Object, ..)) && !within(ProgramJobsAdapter);

	after(Object oo, KCall _kCall) throwing (InvocationTargetException ite) :
    	invoke() && args(oo, ..) && cflow(enter(_kCall)) {

		LaunchingMessageKind.ELAUNCH0002.format(this.adpater, ite);
		if (this.context != null && this.context.getResult() != null
				&& this.context.getResult() instanceof JobDataMap) {
			((JobDataMap) this.context.getResult()).put(
					QuartzUtils.RETURN_CODE, ReturnCodes.FAILURE);
		}
	}
}