org.eclipse.ajdt.core.javaelements.AJCompilationUnit.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ajdt.core.javaelements.AJCompilationUnit.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2010 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Luzius Meisser - initial implementation
 *     Sian January - added eager parsing support
 *     Andrew Eisenberg - changes for AJDT 2.0
 *******************************************************************************/
package org.eclipse.ajdt.core.javaelements;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.aspectj.asm.IProgramElement;
import org.aspectj.lang.annotation.Aspect;
import org.eclipse.ajdt.core.AJLog;
import org.eclipse.ajdt.core.AJMementoTokenizer;
import org.eclipse.ajdt.core.AspectJPlugin;
import org.eclipse.ajdt.core.codeconversion.ConversionOptions;
import org.eclipse.ajdt.core.codeconversion.ITDAwareNameEnvironment;
import org.eclipse.ajdt.core.codeconversion.JavaCompatibleBuffer;
import org.eclipse.ajdt.core.model.AJProjectModelFacade;
import org.eclipse.ajdt.core.model.AJProjectModelFactory;
import org.eclipse.ajdt.core.parserbridge.AJCompilationUnitStructureRequestor;
import org.eclipse.ajdt.core.parserbridge.AJSourceElementParser;
import org.eclipse.ajdt.core.reconcile.AJReconcileWorkingCopyOperation;
import org.eclipse.ajdt.internal.core.AJWorkingCopyOwner;
import org.eclipse.ajdt.internal.core.contentassist.ProposalRequestorFilter;
import org.eclipse.ajdt.internal.core.contentassist.ProposalRequestorWrapper;
import org.eclipse.ajdt.internal.core.parserbridge.AJCompilationUnitDeclarationWrapper;
import org.eclipse.ajdt.internal.core.ras.NoFFDC;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.PerformanceStats;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IProblemRequestor;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.internal.codeassist.CompletionEngine;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.parser.Scanner;
import org.eclipse.jdt.internal.core.BecomeWorkingCopyOperation;
import org.eclipse.jdt.internal.core.BufferManager;
import org.eclipse.jdt.internal.core.CompilationUnit;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.JavaModelStatus;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.NameLookup;
import org.eclipse.jdt.internal.core.Openable;
import org.eclipse.jdt.internal.core.OpenableElementInfo;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.ReconcileWorkingCopyOperation;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;

/**
 * An ICompilationUnit for .aj files.
 * 
 * In order to obtain better interoperability with jdt, AJCompilationUnits pretend
 * to have java syntax compatible contents. To get the real contents,
 * requestOriginalContentMode()
 * must be called before getting the Buffer. Please make sure to call
 * discardOriginalContentMode()
 * afterwards to get back into non-original mode.
 * 
 * @author Luzius Meisser
 */
public class AJCompilationUnit extends CompilationUnit implements NoFFDC {

    int originalContentMode = 0;
    private IFile ajFile;
    protected JavaCompatibleBuffer javaCompBuffer;

    private Object contentModeLock = new Object();

    public boolean isInOriginalContentMode() throws JavaModelException {
        synchronized (contentModeLock) {
            Object info = getElementInfo();
            if (info instanceof AJCompilationUnitInfo) {
                return ((AJCompilationUnitInfo) info).originalContentMode > 0;
            }
        }
        return false;
    }

    /**
     * ensure that the next time the buffer is asked for,
     * the actual AJ contents are returned (not the 
     * converted contents)
     */
    public void requestOriginalContentMode() throws JavaModelException {
        synchronized (contentModeLock) {
            Object info = getElementInfo();
            if (info instanceof AJCompilationUnitInfo) {
                ((AJCompilationUnitInfo) info).originalContentMode++;
            }
        }
    }

    /**
     * discard this request for original contents
     */
    public void discardOriginalContentMode() throws JavaModelException {
        synchronized (contentModeLock) {
            Object info = getElementInfo();
            if (info instanceof AJCompilationUnitInfo) {
                ((AJCompilationUnitInfo) info).originalContentMode--;
            }
        }
    }

    public AJCompilationUnit(IFile ajFile) {
        super(CompilationUnitTools.getParentPackage(ajFile), ajFile.getName(), AJWorkingCopyOwner.INSTANCE);
        this.ajFile = ajFile;
    }

    /**
     * @param fragment
     * @param elementName
     * @param workingCopyOwner
     */
    public AJCompilationUnit(PackageFragment fragment, String elementName, WorkingCopyOwner workingCopyOwner) {
        super(fragment, elementName, workingCopyOwner);
        if (fragment.getResource() instanceof IProject) {
            IProject p = (IProject) fragment.getResource();
            this.ajFile = (IFile) p.findMember(elementName);
        } else {
            IFolder f = (IFolder) fragment.getResource();
            this.ajFile = (IFile) f.findMember(elementName);
        }
    }

    public char[] getMainTypeName() {
        if (AspectJPlugin.USING_CU_PROVIDER) {
            return super.getMainTypeName();
        }
        String elementName = name;
        //remove the .aj
        elementName = elementName.substring(0, elementName.length() - ".aj".length()); //$NON-NLS-1$
        return elementName.toCharArray();
    }

    /* Eclipse 3.1M3: prior to this we overrode isValidCompilationUnit, but now we need to
     * override validateCompilationUnit, otherwise the check for valid name will fail on
     * .aj files
     */
    //   protected IStatus validateCompilationUnit(IResource resource) {
    //      IPackageFragmentRoot root = getPackageFragmentRoot();
    //      try {
    //         if (!(resource.getProject().exists()) || root.getKind() != IPackageFragmentRoot.K_SOURCE) 
    //            return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, root);
    //      } catch (JavaModelException e) {
    //         return e.getJavaModelStatus();
    //      }
    //      return JavaModelStatus.OK_STATUS;
    //   }

    /* Eclipse 3.2M6: bypass buffer cache to ensure fake buffer is used
     */
    /**
     * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getContents()
     */
    public char[] getContents() {
        try {
            IBuffer buffer = this.getBuffer();
            return buffer == null ? CharOperation.NO_CHAR : buffer.getCharacters();
        } catch (JavaModelException e) {
            AspectJPlugin.getDefault().getLog().log(e.getStatus());
            return CharOperation.NO_CHAR;
        }
    }

    public IResource getResource() {
        if (AspectJPlugin.USING_CU_PROVIDER) {
            return super.getResource();
        }
        return ajFile;
    }

    /*
     * needs to return real path for organize imports 
     */
    public IPath getPath() {
        if (AspectJPlugin.USING_CU_PROVIDER || ajFile == null) {
            return super.getPath();
        }
        return ajFile.getFullPath();
    }

    public IResource getUnderlyingResource() throws JavaModelException {
        if (AspectJPlugin.USING_CU_PROVIDER) {
            return super.getUnderlyingResource();
        }
        return ajFile;
    }

    protected void generateInfos(Object info, HashMap newElements, IProgressMonitor monitor)
            throws JavaModelException {
        if (!(info instanceof AJCompilationUnitInfo)) {
            info = new AJCompilationUnitInfo();
        }
        // only generate infos if on build path of the project.
        if (getJavaProject().isOnClasspath(this)) {
            super.generateInfos(info, newElements, monitor);
        }
    }

    /**
     * return the type as an aspect if it exists
     */
    public IType getType(String typeName) {
        IType maybeType = findAspectType(typeName);
        if (maybeType != null && maybeType.exists()) {
            return maybeType;
        }
        return super.getType(typeName);
    }

    /**
     * return null if doesn't exist or an error
     * return type otherwise Might be an aspect
     */
    public IType findAspectType(String typeName) {
        try {
            IJavaElement[] children = getChildren();
            for (int i = 0; i < children.length; i++) {
                if (children[i].getElementType() == TYPE) {
                    if (children[i].getElementName().equals(typeName)) {
                        return (IType) children[i]; // might be an aspect
                    }
                }
            }
        } catch (JavaModelException e) {
            AspectJPlugin.getDefault().getLog().log(e.getStatus());
        }
        return null;
    }

    /**
     * return as aspect if it is an aspect, or class/interface if it is that
     * performs a deep search
     * returns null if doesn't exist
     */
    public IType maybeConvertToAspect(IType maybeAspect) {
        IJavaElement[] elts = maybeAspect.getCompilationUnit().findElements(maybeAspect);
        if (elts != null && elts.length > 0 && elts[0] instanceof AspectElement) {
            return (IType) elts[0];
        }
        return maybeAspect;
    }

    /**
     * builds the structure of this Compilation unit.  We need to use an aspect-aware parser for this (in the org.aspectj.org.eclipse... world, which
     * makes things a little messy
     */
    protected boolean buildStructure(OpenableElementInfo info, final IProgressMonitor pm, Map newElements,
            IResource underlyingResource) throws JavaModelException {
        AJCompilationUnitInfo unitInfo = (AJCompilationUnitInfo) info;

        if (ajFile == null) {
            return false;
        }

        // ensure buffer is opened
        IBuffer buffer = getBufferManager().getBuffer(this);
        if (buffer == null) {
            openBuffer(pm, unitInfo); // open buffer independently from the info, since we are building the info
        }

        // generate structure and compute syntax problems if needed
        AJCompilationUnitStructureRequestor requestor = new AJCompilationUnitStructureRequestor(this, unitInfo,
                newElements);
        JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = getPerWorkingCopyInfo();
        IJavaProject project = getJavaProject();

        boolean createAST;
        boolean resolveBindings;
        int reconcileFlags;
        //        HashMap problems;
        AJCompilationUnitInfo astHolder = (AJCompilationUnitInfo) info;
        createAST = astHolder.getASTLevel() != NO_AST;
        resolveBindings = astHolder.doResolveBindings();
        reconcileFlags = astHolder.getReconcileFlags();
        //        problems = astHolder.getProblems();

        boolean computeProblems = perWorkingCopyInfo != null && perWorkingCopyInfo.isActive() && project != null
                && AspectJPlugin.isAJProject(project.getProject());
        org.aspectj.org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory problemFactory = new org.aspectj.org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory();
        Map options = project == null ? JavaCore.getOptions() : project.getOptions(true);
        if (!computeProblems) {
            // disable task tags checking to speed up parsing
            options.put(JavaCore.COMPILER_TASK_TAGS, ""); //$NON-NLS-1$
        }

        // ensure parser sees the real contents (not the fake java buffer)
        this.requestOriginalContentMode();

        // use an aspectj aware source parser
        AJSourceElementParser ajdtParser = new AJSourceElementParser(requestor, problemFactory,
                new org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions(options),
                true/*report local declarations*/,
                !createAST /*optimize string literals only if not creating a DOM AST*/);

        ajdtParser.reportOnlyOneSyntaxError = !computeProblems;
        ajdtParser.setMethodsFullRecovery(true);
        ajdtParser.setStatementsRecovery((reconcileFlags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0);

        if (!computeProblems && !resolveBindings && !createAST) {
            // disable javadoc parsing if not computing problems, not resolving and not creating ast
            ajdtParser.javadocParser.checkDocComment = false;
        }
        requestor.setParser(ajdtParser);

        // update timestamp (might be IResource.NULL_STAMP if original does not exist)
        if (underlyingResource == null) {
            underlyingResource = getResource();
        }
        // underlying resource is null in the case of a working copy on a class file in a jar
        if (underlyingResource != null)
            unitInfo.setTimestamp(((IFile) underlyingResource).getModificationStamp());

        // compute other problems if needed
        CompilationUnitDeclaration compilationUnitDeclaration = null;
        final AJCompilationUnit source = ajCloneCachingContents();
        requestor.setSource(source.getContents());
        try {
            if (false) {
                // for now, don't go here
                // the problem is that we can't find problems and build structure at the same time
                // they require difference kinds of parsers.
                //            if (computeProblems) {
                //                if (problems == null) {
                //                    // report problems to the problem requestor
                //                    problems = new HashMap();
                //                    compilationUnitDeclaration = AJCompilationUnitProblemFinder.processAJ(
                //                            source, ajdtParser, this.owner, problems, createAST, reconcileFlags, pm);
                //                    try {
                //                        perWorkingCopyInfo.beginReporting();
                //                        for (Iterator iteraror = problems.values().iterator(); iteraror.hasNext();) {
                //                            CategorizedProblem[] categorizedProblems = (CategorizedProblem[]) iteraror.next();
                //                            if (categorizedProblems == null) continue;
                //                            for (int i = 0, length = categorizedProblems.length; i < length; i++) {
                //                                perWorkingCopyInfo.acceptProblem(categorizedProblems[i]);
                //                            }
                //                        }
                //                    } finally {
                //                        perWorkingCopyInfo.endReporting();
                //                    }
                //                } else {
                //                    // collect problems
                //                    compilationUnitDeclaration = AJCompilationUnitProblemFinder.processAJ(source, ajdtParser, this.owner, problems, createAST, reconcileFlags, pm);
                //                }
            } else {
                // since we are doing n aspectj aware parse with the AJ parser
                // need to wrap the results in a JDT CompilationUnitDeclaration
                org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration ajDeclaration = ajdtParser
                        .parseCompilationUnit(
                                new org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
                                    public char[] getContents() {
                                        return source.getContents();
                                    }

                                    public char[] getMainTypeName() {
                                        return source.getMainTypeName();
                                    }

                                    public char[][] getPackageName() {
                                        return source.getPackageName();
                                    }

                                    public char[] getFileName() {
                                        return source.getFileName();
                                    }

                                    public boolean ignoreOptionalProblems() {
                                        return false;
                                    }
                                }, true /*full parse to find local elements*/);
                compilationUnitDeclaration = new AJCompilationUnitDeclarationWrapper(ajDeclaration, source);
            }

            if (createAST) {
                // XXX hmmmm...may not work
                int astLevel = unitInfo.getASTLevel();
                org.eclipse.jdt.core.dom.CompilationUnit cu = AST.convertCompilationUnit(astLevel,
                        compilationUnitDeclaration, options, computeProblems, source, reconcileFlags, pm);
                unitInfo.setAST(cu);
            }
        } finally {
            discardOriginalContentMode();
            if (compilationUnitDeclaration != null) {
                compilationUnitDeclaration.cleanUp();
            }
        }

        return unitInfo.isStructureKnown();
    }

    public boolean isPrimary() {
        return this.owner == AJWorkingCopyOwner.INSTANCE;
    }

    protected Object createElementInfo() {
        return new AJCompilationUnitInfo();
    }

    public org.eclipse.jdt.core.dom.CompilationUnit makeConsistent(int astLevel, boolean resolveBindings,
            int reconcileFlags, HashMap problems, IProgressMonitor monitor) throws JavaModelException {
        if (isConsistent())
            return null;

        // create a new info and make it the current info
        // (this will remove the info and its children just before storing the new infos)
        if (astLevel != NO_AST || problems != null) {
            ASTHolderAJCUInfo info = new ASTHolderAJCUInfo();
            info.astLevel = astLevel;
            info.resolveBindings = resolveBindings;
            info.reconcileFlags = reconcileFlags;
            info.problems = problems;
            openWhenClosed(info, true, monitor);
            org.eclipse.jdt.core.dom.CompilationUnit result = info.ast;
            info.ast = null;
            return result;
        } else {
            openWhenClosed(createElementInfo(), true, monitor);
            return null;
        }
    }

    /**
     * @see ICompilationUnit#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)
     */
    public ICompilationUnit getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProblemRequestor problemRequestor,
            IProgressMonitor monitor) throws JavaModelException {
        if (!isPrimary())
            return this;

        JavaModelManager manager = JavaModelManager.getJavaModelManager();

        CompilationUnit workingCopy = new AJCompilationUnit((PackageFragment) getParent(), getElementName(),
                workingCopyOwner);
        JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = manager.getPerWorkingCopyInfo(workingCopy,
                false/*don't create*/, true/*record usage*/, null/*not used since don't create*/);
        if (perWorkingCopyInfo != null) {
            return perWorkingCopyInfo.getWorkingCopy(); // return existing handle instead of the one created above
        }
        BecomeWorkingCopyOperation op = new BecomeWorkingCopyOperation(workingCopy, problemRequestor);
        op.runOperation(monitor);
        return workingCopy;
    }

    public IBuffer getBuffer() throws JavaModelException {
        return convertBuffer(super.getBuffer());
    }

    public IBuffer convertBuffer(IBuffer buf) {
        try {
            if (isInOriginalContentMode() || (buf == null)) {
                return buf;
            }
        } catch (JavaModelException e) {
        }

        if (javaCompBuffer == null) {
            IBuffer myBuffer = BufferManager.createBuffer(this);
            javaCompBuffer = new JavaCompatibleBuffer(buf, myBuffer);
        } else {
            if (buf != javaCompBuffer)
                javaCompBuffer.reinitialize(buf);
        }

        return javaCompBuffer;
    }

    // copied from super, but changed to use an AJReconcileWorkingCopyOperation
    public org.eclipse.jdt.core.dom.CompilationUnit reconcile(int astLevel, int reconcileFlags,
            WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor) throws JavaModelException {
        if (!isWorkingCopy())
            return null; // Reconciling is not supported on non working copies
        if (workingCopyOwner == null)
            workingCopyOwner = AJWorkingCopyOwner.INSTANCE;

        PerformanceStats stats = null;
        if (ReconcileWorkingCopyOperation.PERF) {
            stats = PerformanceStats.getStats(JavaModelManager.RECONCILE_PERF, this);
            stats.startRun(new String(this.getFileName()));
        }

        AJReconcileWorkingCopyOperation op = new AJReconcileWorkingCopyOperation(this, astLevel, reconcileFlags,
                workingCopyOwner);
        try {
            // Eclipse 3.5.1 and 3.5.2 have different signatures for this method 
            cacheZipFiles(); // cache zip files for performance (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=134172)
            op.runOperation(monitor);
        } finally {
            flushZipFiles();
        }
        if (ReconcileWorkingCopyOperation.PERF) {
            stats.endRun();
        }
        return op.ast;
    }

    private void flushZipFiles() throws JavaModelException {
        Method flushZipFilesMethod;
        JavaModelManager manager = JavaModelManager.getJavaModelManager();
        try {
            try {
                // Eclipse 3.5.1
                flushZipFilesMethod = JavaModelManager.class.getMethod("flushZipFiles", new Class[0]);
                flushZipFilesMethod.invoke(manager, new Object[0]);
            } catch (NoSuchMethodException e) {
                // Eclipse 3.5.2
                try {
                    flushZipFilesMethod = JavaModelManager.class.getMethod("flushZipFiles",
                            new Class[] { Object.class });
                    flushZipFilesMethod.invoke(manager, new Object[] { this });
                } catch (NoSuchMethodException e1) {
                    throw new JavaModelException(e1, IJavaModelStatusConstants.CORE_EXCEPTION);
                }
            }
        } catch (SecurityException e) {
            throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
        } catch (IllegalArgumentException e) {
            throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
        } catch (IllegalAccessException e) {
            throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
        } catch (InvocationTargetException e) {
            throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
        }
    }

    private void cacheZipFiles() throws JavaModelException {
        Method cacheZipFilesMethod;
        JavaModelManager manager = JavaModelManager.getJavaModelManager();
        try {
            try {
                // Eclipse 3.5.1
                cacheZipFilesMethod = JavaModelManager.class.getMethod("cacheZipFiles", new Class[0]);
                cacheZipFilesMethod.invoke(manager, new Object[0]);
            } catch (NoSuchMethodException e) {
                // Eclipse 3.5.2
                try {
                    cacheZipFilesMethod = JavaModelManager.class.getMethod("cacheZipFiles",
                            new Class[] { Object.class });
                    cacheZipFilesMethod.invoke(manager, new Object[] { this });
                } catch (NoSuchMethodException e1) {
                    throw new JavaModelException(e1, IJavaModelStatusConstants.CORE_EXCEPTION);
                }
            }
        } catch (SecurityException e) {
            throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
        } catch (IllegalArgumentException e) {
            throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
        } catch (IllegalAccessException e) {
            throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
        } catch (InvocationTargetException e) {
            throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
        }
    }

    public IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner workingCopyOwner)
            throws JavaModelException {
        IJavaElement[] res = super.codeSelect(offset, length, workingCopyOwner);
        return res;
    }

    protected void closeBuffer() {
        if (javaCompBuffer != null) {
            javaCompBuffer.close();
            javaCompBuffer = null;
        }
        super.closeBuffer();
    }

    private static final String moveCuUpdateCreator = "org.eclipse.jdt.internal.corext.refactoring.reorg.MoveCuUpdateCreator"; //$NON-NLS-1$
    private static final int lenOfMoveCuUpdateCreator = moveCuUpdateCreator.length();

    public IType[] getAllTypes() throws JavaModelException {
        if (!AspectJPlugin.USING_CU_PROVIDER) {
            //tell MoveCuUpdateCreator that we do not contain any Types, otherwise it tries to find
            //them using java search which will cause an ugly exception
            String caller = (new RuntimeException()).getStackTrace()[1].getClassName();
            if ((lenOfMoveCuUpdateCreator == caller.length()) && moveCuUpdateCreator.equals(caller)) {
                return new IType[0];
            }
        }
        return super.getAllTypes();
    }

    /**
     * Returns all aspect types in this compilation unit in the same order
     * that {@link #getAllTypes()} works.
     * 
     * This returns types defined with the <em>aspect</em> keyword and
     * classes annotated with @{@link Aspect}.  This means that not all 
     * Aspects returned will have a type {@link AspectElement}.  The types 
     * marked with   @{@link Aspect} will be of type {@link SourceType}.
     */
    public IType[] getAllAspects() throws JavaModelException {
        IType[] allTypes = getAllTypes();
        List aspects = new ArrayList(allTypes.length);
        AJProjectModelFacade model = null;
        for (int i = 0; i < allTypes.length; i++) {
            if (allTypes[i] instanceof AspectElement) {
                aspects.add(allTypes[i]);
            } else {
                // bug 270396---annotations are not stored in the model
                // this method always returns an empty array
                // ask the AspectJ model instead
                //               IAnnotation[] annotations = allTypes[i].getAnnotations();
                //               for (int j = 0; j < annotations.length; j++) {
                //                   String annName = annotations[j].getElementName();
                //                   // no need to check fully qualified name
                //                   // just assume that any annotation with a name of Aspect
                //                   // is the one we want
                //                    if (annName != null && 
                //                            (annName.equals("Aspect") || annName.endsWith(".Aspect"))) {
                //                        aspects.add(allTypes[i]);
                //                        break;
                //                    }
                //                }
                if (model == null) {
                    model = AJProjectModelFactory.getInstance().getModelForJavaElement(this);
                }
                IProgramElement maybeAspect = model.javaElementToProgramElement(allTypes[i]);
                if (maybeAspect.getKind() == IProgramElement.Kind.ASPECT) {
                    aspects.add(allTypes[i]);
                }
            }
        }
        return (IType[]) aspects.toArray(new IType[aspects.size()]);
    }

    /**
     * Hook for code completion support for AspectJ content.
     * 
      * A description of how code completion works in AJDT can be found in bug 74419.
      * 
     * @see org.eclipse.jdt.internal.core.Openable#codeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner)
     */
    protected void codeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu,
            org.eclipse.jdt.internal.compiler.env.ICompilationUnit unitToSkip, int position,
            CompletionRequestor requestor, WorkingCopyOwner owner, ITypeRoot typeRoot,
            /* AJDT 1.7 */
            IProgressMonitor monitor) throws JavaModelException {
        // Bug 76146
        // if we are not editing in an AspectJ editor 
        // (i.e., we are editing in a Java editor), 
        // then we do not have access to a proper parser
        // and we cannot perform code completion requests.
        if (!isEditingInAspectJEditor())
            return;

        int transformedPos;

        if (javaCompBuffer == null) {
            convertBuffer(super.getBuffer());
        }
        if (javaCompBuffer == null) {
            // if still null here, then some horrendous syntax error occurred and
            // we can't do anything, so just exit
            return;
        }
        ConversionOptions optionsBefore = javaCompBuffer.getConversionOptions();

        //check if inside intertype method declaration
        IntertypeElement itd = itdMethodOrNull(position);
        if (itd != null) {
            // we are inside an intertype method declaration
            // perform content assist twice.  once with the context switch (ie- pretend to be in the ITD target type
            // and once in the context of the aspect.
            char[] targetType = itd.getTargetType();
            boolean doExtraITDFiltering = !positionIsAtDottedExpression(itd, position);

            // simulate context switch to target class
            javaCompBuffer.setConversionOptions(
                    ConversionOptions.getCodeCompletionOptionWithContextSwitch(position, targetType));
            transformedPos = javaCompBuffer.translatePositionToFake(position);

            CompletionRequestor wrappedRequestor = new ProposalRequestorWrapper(requestor, this, javaCompBuffer,
                    "");
            /* AJDT 1.7 */
            internalCodeComplete(cu, unitToSkip, transformedPos, wrappedRequestor, owner, this, monitor);

            // now set up for the regular code completion
            javaCompBuffer.setConversionOptions(ConversionOptions.CODE_COMPLETION);

            //set up proposal filter to filter away all the proposals that would be wrong because of context switch
            requestor = new ProposalRequestorFilter(requestor, this, javaCompBuffer, doExtraITDFiltering);
        } else {
            javaCompBuffer.setConversionOptions(ConversionOptions.CODE_COMPLETION);
            requestor = new ProposalRequestorWrapper(requestor, this, javaCompBuffer, "");
        }
        transformedPos = javaCompBuffer.translatePositionToFake(position);

        /* AJDT 1.7 */
        internalCodeComplete(cu, unitToSkip, transformedPos, requestor, owner, this, monitor);
        javaCompBuffer.setConversionOptions(optionsBefore);

    }

    // bug 279974: determine if the position is inside a dotted expression
    // and the expression is not 'this'
    // eg- this.foo.b<here> ==> true
    //     fo<here>         ==> false
    //     this.f<here>     ==> false
    protected boolean positionIsAtDottedExpression(IntertypeElement itd, int pos) throws JavaModelException {
        String source = itd.getSource();
        int posInSource = pos - itd.getSourceRange().getOffset();
        return positionIsAtDottedExpression(source, posInSource);
    }

    // make static for easier testing
    static protected boolean positionIsAtDottedExpression(String source, int posInSource) {
        if (posInSource <= 0) {
            return false;
        }
        // iterate backwards over chars
        // first stage:
        // '.'               ---> no filtering
        // any non-word char ---> do filtering
        // whitespace        ---> go to next stage

        char[] sourceArr = source.toCharArray();
        int currPos = posInSource - 1;
        char currChar = sourceArr[currPos];

        boolean dotFound = false;
        boolean nonWordFound = false;
        while (currPos > 0) {
            if (currChar == '.') {
                dotFound = true;
                break;
            } else if (Character.isWhitespace(currChar)) {
                break;
            } else if (Character.isJavaIdentifierPart(currChar)) {
                // fall through
            } else {
                nonWordFound = true;
                break;
            }
            currPos--;
            currChar = sourceArr[currPos];
        }

        if (nonWordFound || currPos < 0) {
            return false;
        }

        // second stage:
        // follow whitespace backwards until:
        // '.'           ---> no filtering
        // anything else ---> do filtering
        if (!dotFound) {
            currPos--;
            boolean somethingElseFound = false;
            while (currPos >= 0) {
                currChar = sourceArr[currPos];
                if (Character.isWhitespace(currChar)) {
                    // fall through
                } else if (currChar == '.') {
                    dotFound = true;
                    break;
                } else {
                    somethingElseFound = true;
                    break;
                }
                currPos--;
            }
            if (somethingElseFound) {
                return false;
            }
        }

        // third stage:
        // check to see if previous word is "this"
        // if so, then do filtering, it is not considered a dotted expression
        if (dotFound) {
            currPos--;
            while (currPos >= 0) {
                currChar = sourceArr[currPos];
                if (!Character.isWhitespace(currChar)) {
                    break;
                }
                currPos--;
            }

            return currPos < 3 || !(sourceArr[currPos - 3] == 't' && sourceArr[currPos - 2] == 'h'
                    && sourceArr[currPos - 1] == 'i' && sourceArr[currPos - 0] == 's');
        }

        return false;
    }

    /**
    * this method is a copy of {@link Openable#codeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, int, CompletionRequestor, WorkingCopyOwner, ITypeRoot)}
    * The only change is that we need to create an {@link ITDAwareNameEnvironment}, not  standard {@link SearchableEnvironment}.
     * 
    * @param cu
    * @param unitToSkip
    * @param position
    * @param requestor
    * @param owner
    * @param typeRoot
    * @throws JavaModelException
    */
    private void internalCodeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu,
            org.eclipse.jdt.internal.compiler.env.ICompilationUnit unitToSkip, int position,
            CompletionRequestor requestor, WorkingCopyOwner owner, ITypeRoot typeRoot,
            /* AJDT 1.7 */
            IProgressMonitor monitor) throws JavaModelException {

        if (requestor == null) {
            throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
        }
        PerformanceStats performanceStats = CompletionEngine.PERF
                ? PerformanceStats.getStats(JavaModelManager.COMPLETION_PERF, this)
                : null;
        if (performanceStats != null) {
            performanceStats.startRun(new String(cu.getFileName()) + " at " + position); //$NON-NLS-1$
        }
        IBuffer buffer = getBuffer();
        if (buffer == null) {
            return;
        }
        if (position < -1 || position > buffer.getLength()) {
            throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS));
        }
        JavaProject project = (JavaProject) getJavaProject();
        /* AJDT 1.7 */
        ITDAwareNameEnvironment environment = new ITDAwareNameEnvironment(project, owner, monitor);

        environment.setUnitToSkip(unitToSkip);

        // code complete
        /* AJDT 1.7 */
        CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project,
                owner, monitor);
        engine.complete(cu, position, 0, typeRoot);
        if (performanceStats != null) {
            performanceStats.endRun();
        }
        if (NameLookup.VERBOSE) {
            AJLog.log(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " //$NON-NLS-1$
                    + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$
            AJLog.log(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " //$NON-NLS-1$
                    + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$
        }

    }

    /**
     * As per Bug 76146
     * check to see if editing in Java Editor or AspectJ editor
     */
    private boolean isEditingInAspectJEditor() {
        // This is a bit kludgy.
        // when perWorkingCopyInfo is null 
        // then we are editing in Java editor
        return getPerWorkingCopyInfo() != null;
    }

    /**
     * @param pos
     * @return null if outside intertype method declaration or the name of the target type otherwise
     * @throws JavaModelException
     */
    public IntertypeElement itdMethodOrNull(int pos) throws JavaModelException {
        IJavaElement elt = this.getElementAt(pos);
        if (elt instanceof IntertypeElement) {
            IntertypeElement itd = (IntertypeElement) elt;
            if (itd.getAJKind() == IProgramElement.Kind.INTER_TYPE_METHOD
                    || itd.getAJKind() == IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR) {

                return itd;
            }
        }
        return null;
    }

    // hack: need to use protected constructor in SourceType
    private JavaElement getType(JavaElement type, String typeName) {
        try {
            try {
                Constructor cons = SourceType.class
                        .getDeclaredConstructor(new Class[] { JavaElement.class, String.class });
                cons.setAccessible(true);
                Object obj = cons.newInstance(new Object[] { type, typeName });
                return (JavaElement) obj;
            } catch (SecurityException e) {
                throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
            } catch (NoSuchMethodException e) {
                throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
            } catch (IllegalArgumentException e) {
                throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
            } catch (InstantiationException e) {
                throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
            } catch (IllegalAccessException e) {
                throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
            } catch (InvocationTargetException e) {
                throw new JavaModelException(e, IJavaModelStatusConstants.CORE_EXCEPTION);
            }
        } catch (JavaModelException jme) {
            AspectJPlugin.getDefault().getLog().log(jme.getStatus());
        }
        return null;
    }

    public IJavaElement getHandleFromMemento(MementoTokenizer memento, WorkingCopyOwner owner) {
        // if not an AJMementoTokenizer, the tokenizer may have read too far
        // create an AJMementoTokenizer and ensure to backtrack to the end of the compilation unit name
        if (!(memento instanceof AJMementoTokenizer)) {
            memento = new AJMementoTokenizer(memento, name);
        }
        return super.getHandleFromMemento(memento, owner);
    }

    /*
     * @see JavaElement 
     */
    public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento,
            WorkingCopyOwner workingCopyOwner) {
        JavaElement type = this;
        if (!(memento instanceof AJMementoTokenizer)) {
            memento = new AJMementoTokenizer(memento, name);
        }
        if ((token.charAt(0) == JavaElement.JEM_IMPORTDECLARATION)
                || (token.charAt(0) == JavaElement.JEM_PACKAGEDECLARATION)) {
            return super.getHandleFromMemento(token, memento, workingCopyOwner);
        }

        // need to handle types ourselves, because they may contain inner aspects
        // (or inner classes containing inner aspects etc)
        while ((token.charAt(0) == AspectElement.JEM_ASPECT_TYPE) || (token.charAt(0) == JavaElement.JEM_TYPE)
                || (token.charAt(0) == JavaElement.JEM_ANNOTATION)) {
            // note that we are also testing for JEM_ANNOTATION here.
            // this is because when the type handle identifiers were changed prior to 2.1.1,
            // JEM_ASPECT_TYPE and JEM_ANNOTATION were the same.
            // Some people have had problems in that the old handles were cached.
            // this can probably be safely removed post 2.1.2.
            if (!memento.hasMoreTokens())
                return type;
            String typeName = memento.nextToken();
            if (token.charAt(0) == AspectElement.JEM_ASPECT_TYPE || token.charAt(0) == JavaElement.JEM_ANNOTATION) {
                type = new AspectElement(type, typeName);
            } else if (token.charAt(0) == JavaElement.JEM_TYPE) {
                type = getType(type, typeName);
                if (type == null)
                    type = (JavaElement) getType(typeName);
            }
            if (!memento.hasMoreTokens())
                return type;
            token = memento.nextToken();
        }
        // handle pointcuts in a class (bug 124992)
        if (!(type instanceof AspectElement) && (token.charAt(0) == AspectElement.JEM_POINTCUT)) {
            String name = memento.nextToken();
            ArrayList params = new ArrayList();
            nextParam: while (memento.hasMoreTokens()) {
                token = memento.nextToken();
                switch (token.charAt(0)) {
                case JEM_TYPE:
                case JEM_TYPE_PARAMETER:
                    break nextParam;
                case AspectElement.JEM_POINTCUT:
                    if (!memento.hasMoreTokens())
                        return this;
                    String param = memento.nextToken();
                    StringBuffer buffer = new StringBuffer();
                    while (param.length() == 1 && Signature.C_ARRAY == param.charAt(0)) { // backward compatible with 3.0 mementos
                        buffer.append(Signature.C_ARRAY);
                        if (!memento.hasMoreTokens())
                            return this;
                        param = memento.nextToken();
                    }
                    params.add(buffer.toString() + param);
                    break;
                default:
                    break nextParam;
                }
            }
            String[] parameters = new String[params.size()];
            params.toArray(parameters);
            JavaElement pointcut = new PointcutElement(type, name, parameters);
            return pointcut.getHandleFromMemento(memento, workingCopyOwner);
        }

        return type.getHandleFromMemento(token, memento, workingCopyOwner);
    }

    /**
     * @see JavaElement#getHandleMementoDelimiter()
     */
    protected char getHandleMementoDelimiter() {
        if (AspectJPlugin.USING_CU_PROVIDER) {
            return super.getHandleMementoDelimiter();
        }
        return AspectElement.JEM_ASPECT_CU;
    }

    public String getHandleIdentifier() {
        if (AspectJPlugin.USING_CU_PROVIDER) {
            return super.getHandleIdentifier();
        }

        // this horrid code only exists so that when we are not using the weaving service,
        // we don't get exceptions on refactoring
        String callerName = (new RuntimeException()).getStackTrace()[1].getClassName();
        final String deletionClass = "org.eclipse.jdt.internal.corext.refactoring.changes.DeleteSourceManipulationChange"; //$NON-NLS-1$
        // are we being called in the context of a delete operation?
        if (callerName.equals(deletionClass)) {
            AJCompilationUnitManager.INSTANCE.removeFileFromModel((IFile) getResource());
            // need to return a handle identifier that JDT can use (bug 74426)
            String handleIdentifier = JavaCore.create(ajFile).getHandleIdentifier();
            ajFile = null;
            return handleIdentifier;
        }

        // are we being called in the context of a move/DnD operation?
        final String moveClass = "org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitReorgChange"; //$NON-NLS-1$
        if (callerName.equals(moveClass)) {
            // need to return a handle identifier that JDT can use (bug 121533)
            String modifiedHandle = super.getHandleIdentifier().replace(AspectElement.JEM_ASPECT_CU,
                    JavaElement.JEM_COMPILATIONUNIT);
            return modifiedHandle;
        }
        return super.getHandleIdentifier();
    }

    /*
     * Clone this handle so that it caches its contents in memory.
     * DO NOT PASS TO CLIENTS
     */
    public AJCompilationUnit ajCloneCachingContents() {
        return new AJCompilationUnit((PackageFragment) this.parent, this.name, this.owner) {
            private char[] cachedContents;

            public char[] getContents() {
                if (this.cachedContents == null)
                    this.cachedContents = AJCompilationUnit.this.getContents();
                return this.cachedContents;
            }

            public CompilationUnit originalFromClone() {
                return AJCompilationUnit.this;
            }
        };
    }

    public AJCompilationUnit ajCloneCachingContents(final char[] contents) {
        return new AJCompilationUnit((PackageFragment) this.parent, this.name, this.owner) {
            public char[] getContents() {
                return contents;
            }

            public CompilationUnit originalFromClone() {
                return AJCompilationUnit.this;
            }
        };
    }

}