org.eclipse.ajdt.core.parserbridge.ITDInserter.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ajdt.core.parserbridge.ITDInserter.java

Source

/*******************************************************************************
 * Copyright (c) 2008 SpringSource 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:
 *      Andrew Eisenberg - Initial implementation
 *******************************************************************************/
package org.eclipse.ajdt.core.parserbridge;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.aspectj.asm.IProgramElement;
import org.eclipse.ajdt.core.AJLog;
import org.eclipse.ajdt.core.model.AJProjectModelFacade;
import org.eclipse.ajdt.core.model.AJProjectModelFactory;
import org.eclipse.ajdt.core.model.AJRelationshipManager;
import org.eclipse.ajdt.core.model.AJWorldFacade;
import org.eclipse.ajdt.core.model.AJWorldFacade.ErasedTypeSignature;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
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.TypeAnnotationWalker;
import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SignatureWrapper;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.parser.TypeConverter;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;

/**
 * Inserts ITD information into a TypeDeclaration so that
 * when reconciling occurs introduced methods, fields, and constructors
 * can be found.
 * 
 * This class works by mocking up the ITDs in the type declaration including 
 * altering the type hierarchy.  
 * 
 * This mocking up occurs after parsing, but before binding.  The mocked up elements
 * are then used as part of the type binding.
 * 
 * The mocked up elements are then removed after the compilation is finished because
 * the compilation results are used elsewhere.
 * 
 * This class is a visitor.  It visits a compilation unit and augments all types
 * with ITDs.
 * 
 * See Bug 255848
 * 
 * @author andrew
 * @created Nov 26, 2008
 */
public class ITDInserter extends ASTVisitor {

    private static class OrigContents {
        AbstractMethodDeclaration[] methods;
        FieldDeclaration[] fields;
        TypeReference superClass;
        TypeReference[] superInterfaces;
        TypeDeclaration[] memberTypes;
    }

    private static class ITDTypeConverter extends TypeConverter {
        public ITDTypeConverter(ProblemReporter reporter) {
            super(reporter, Signature.C_DOT);
        }

        protected TypeReference createTypeReference(char[] typeName) {
            return super.createTypeReference(typeName, 0, typeName.length);
        }

        protected TypeReference createTypeReference(String typeSignature) {
            return super.createTypeReference(typeSignature.replace('/', '.'), 0, typeSignature.length());
        }
    }

    private final ICompilationUnit unit;

    private final LookupEnvironment env;

    private Map<TypeDeclaration, OrigContents> origMap = new HashMap<TypeDeclaration, OrigContents>();

    private final ITDTypeConverter typeConverter;

    private AJProjectModelFacade model;

    public ITDInserter(ICompilationUnit unit, LookupEnvironment env, ProblemReporter reporter) {
        this.unit = unit;
        typeConverter = new ITDTypeConverter(reporter);
        model = AJProjectModelFactory.getInstance().getModelForJavaElement(unit);
        this.env = env;
    }

    public boolean visit(TypeDeclaration type, BlockScope blockScope) {
        augmentType(type);
        return false; // no local/anonymous type
    }

    public boolean visit(TypeDeclaration type, CompilationUnitScope compilationUnitScope) {
        augmentType(type);
        return true;
    }

    public boolean visit(TypeDeclaration memberType, ClassScope classScope) {
        augmentType(memberType);
        return true;
    }

    /**
     * augments a type with ITD info
     */
    private void augmentType(TypeDeclaration type) {

        OrigContents orig = new OrigContents();
        orig.methods = type.methods;
        orig.fields = type.fields;
        orig.superClass = type.superclass;
        orig.superInterfaces = type.superInterfaces;
        orig.memberTypes = type.memberTypes;

        try {
            List<FieldDeclaration> itdFields = new LinkedList<FieldDeclaration>();
            List<AbstractMethodDeclaration> itdMethods = new LinkedList<AbstractMethodDeclaration>();
            List<TypeDeclaration> itits = new LinkedList<TypeDeclaration>();
            IType handle = getHandle(type);

            List<IProgramElement> ipes = getITDs(handle);
            for (IProgramElement elt : ipes) {
                if (elt.getKind() == IProgramElement.Kind.INTER_TYPE_METHOD) {
                    // ignore if type is an interface.
                    // assumption is that this ITD is an implementation of an interface method
                    // adding it here would cause a duplicate method error.
                    // These are added to the first class that instantiates this interface
                    // See bug 257437
                    if (TypeDeclaration.kind(type.modifiers) == TypeDeclaration.CLASS_DECL) {
                        if (elt.getAccessibility() != IProgramElement.Accessibility.PRIVATE) {
                            itdMethods.add(createMethod(elt, type, handle));
                        }
                    }

                } else if (elt.getKind() == IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR) {
                    if (elt.getAccessibility() != IProgramElement.Accessibility.PRIVATE) {
                        itdMethods.add(createConstructor(elt, type));
                    }
                } else if (elt.getKind() == IProgramElement.Kind.INTER_TYPE_FIELD) {
                    // XXX hmmmm..should I also skip this if the type is an interface???
                    if (elt.getAccessibility() != IProgramElement.Accessibility.PRIVATE) {
                        itdFields.add(createField(elt, type));
                    }
                } else if (elt.getKind() == IProgramElement.Kind.DECLARE_PARENTS) {
                    boolean isClass = isClass(elt);
                    if (isClass && TypeDeclaration.kind(type.modifiers) == TypeDeclaration.CLASS_DECL) {
                        addSuperClass(elt, type);
                    } else {
                        addSuperInterfaces(elt, type);
                    }
                } else if (elt.getKind() == IProgramElement.Kind.CLASS) {
                    // this is an ITIT - intertype inner type
                    TypeDeclaration ititAST = createITIT(elt.getName(), type);
                    if (ititAST != null) {
                        // add children, etc
                        populateITIT(ititAST, elt);
                        itits.add(ititAST);
                    }
                } else if (elt.getKind() == IProgramElement.Kind.ASPECT) {
                    // probably an instantiation of a declare parents relationship from an abstact aspect
                    Map<String, List<String>> parentsMap = elt.getDeclareParentsMap();
                    if (parentsMap != null && type.binding != null && type.binding.compoundName != null) {
                        List<String> parents = parentsMap
                                .get(String.valueOf(CharOperation.concatWith(type.binding.compoundName, '.')));
                        List<String> interfacesToAdd = new LinkedList<String>();
                        for (String parent : parents) {
                            try {
                                IType parentElt = unit.getJavaProject().findType(parent, (IProgressMonitor) null);
                                if (parentElt != null && parentElt.isClass()) {
                                    addSuperClass(parent, type);
                                } else if (parentElt != null && parentElt.isInterface()) {
                                    interfacesToAdd.add(parent);
                                }
                            } catch (JavaModelException e) {
                            }
                        }
                        addSuperInterfaces(interfacesToAdd, type);
                    }
                }
            }

            if (ipes.size() > 0) {
                origMap.put(type, orig);

                // now add the ITDs into the declaration
                if (itdFields.size() > 0) {
                    int numFields = type.fields == null ? 0 : type.fields.length;
                    FieldDeclaration[] fields = new FieldDeclaration[numFields + itdFields.size()];
                    if (numFields > 0) {
                        System.arraycopy(type.fields, 0, fields, 0, numFields);
                    }
                    for (int i = 0; i < itdFields.size(); i++) {
                        fields[i + numFields] = itdFields.get(i);
                    }
                    type.fields = fields;
                }
                if (itdMethods.size() > 0) {
                    int numMethods = type.methods == null ? 0 : type.methods.length;
                    AbstractMethodDeclaration[] methods = new AbstractMethodDeclaration[numMethods
                            + itdMethods.size()];
                    if (numMethods > 0) {
                        System.arraycopy(type.methods, 0, methods, 0, numMethods);
                    }
                    for (int i = 0; i < itdMethods.size(); i++) {
                        methods[i + numMethods] = itdMethods.get(i);
                    }
                    type.methods = methods;
                }
                if (itits.size() > 0) {
                    int numInners = type.memberTypes == null ? 0 : type.memberTypes.length;
                    TypeDeclaration[] inners = new TypeDeclaration[numInners + itits.size()];
                    if (numInners > 0) {
                        System.arraycopy(type.memberTypes, 0, inners, 0, numInners);
                    }
                    for (int i = 0; i < itits.size(); i++) {
                        inners[i + numInners] = itits.get(i);
                    }
                    type.memberTypes = inners;
                }
            }
        } catch (Exception e) {
            // back out what we have done
            origMap.remove(type);
            revertType(type, orig);
        }
    }

    /**
     * Adds all children field and methods to this ITIT
     * @param ititAST
     * @param elt the AspectJ element that knows about children 
     */
    private void populateITIT(TypeDeclaration ititAST, IProgramElement elt) {
        List<FieldDeclaration> fields = new LinkedList<FieldDeclaration>();
        List<FieldBinding> fieldBindings = new LinkedList<FieldBinding>();
        List<AbstractMethodDeclaration> methods = new LinkedList<AbstractMethodDeclaration>();
        List<MethodBinding> methodBindings = new LinkedList<MethodBinding>();

        for (IProgramElement child : elt.getChildren()) {
            if (child.getKind() == IProgramElement.Kind.FIELD) {
                FieldDeclaration field = createField(child, ititAST);
                fields.add(field);
                fieldBindings.add(new FieldBinding(field,
                        getReturnTypeBinding(child.getCorrespondingTypeSignature().toCharArray(), ititAST.binding),
                        field.modifiers, ititAST.binding));
            } else if (child.getKind() == IProgramElement.Kind.METHOD) {
                MethodDeclaration method = createMethod(child, ititAST, null);
                methods.add(method);
                methodBindings.add(new MethodBinding(method.modifiers, method.selector,
                        getReturnTypeBinding(child.getCorrespondingTypeSignature().toCharArray(), ititAST.binding),
                        getParameterBindings(elt, ititAST.binding), new ReferenceBinding[0], ititAST.binding));
            }
        }
        ititAST.fields = (FieldDeclaration[]) fields.toArray(new FieldDeclaration[0]);
        ititAST.methods = (AbstractMethodDeclaration[]) methods.toArray(new MethodDeclaration[0]);

        // figure out how to make type bindings and figure out method bindings
        ititAST.binding.setFields(fieldBindings.toArray(new FieldBinding[0]));
    }

    private TypeBinding[] getParameterBindings(IProgramElement elt, ReferenceBinding ititBinding) {
        List<char[]> paramTypes = elt.getParameterSignatures();
        if (paramTypes == null) {
            return new TypeBinding[0];
        }
        TypeBinding[] paramBindings = new TypeBinding[paramTypes.size()];
        int i = 0;
        for (char[] paramType : paramTypes) {
            paramBindings[i++] = getReturnTypeBinding(paramType, ititBinding);
        }
        return paramBindings;
    }

    private boolean isClass(IProgramElement elt) throws JavaModelException {
        List<String> parentTypes = elt.getParentTypes();
        if (parentTypes != null && parentTypes.size() > 0) {
            for (String parentTypeName : parentTypes) {
                int genericsIndex = parentTypeName.indexOf("<");
                if (genericsIndex > 0) {
                    parentTypeName = parentTypeName.substring(0, genericsIndex);
                }
                IType parentType = unit.getJavaProject().findType(parentTypeName, (IProgressMonitor) null);
                if (parentType != null) {
                    return parentType.isClass();
                }
            }
        }
        // don't really know
        return false;
    }

    /**
     * Ask the oracle for the type binding with the given name
     * @param child
     * @return
     */
    protected TypeBinding getReturnTypeBinding(char[] typeName, TypeBinding ititBinding) {
        TypeBinding typeBinding = env.getTypeFromTypeSignature(new SignatureWrapper(typeName),
                new TypeVariableBinding[0], (ReferenceBinding) ititBinding, new char[0][][],
                TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER);
        typeBinding = BinaryTypeBinding.resolveType(typeBinding, env, false);
        return typeBinding;
    }

    private TypeDeclaration createITIT(String name, TypeDeclaration enclosing) {
        TypeDeclaration decl = new TypeDeclaration(enclosing.compilationResult);
        decl.enclosingType = enclosing;
        decl.name = name.toCharArray();
        ClassScope innerClassScope = new ClassScope(enclosing.scope, decl);
        decl.binding = new MemberTypeBinding(new char[][] { enclosing.name, name.toCharArray() }, innerClassScope,
                enclosing.binding);
        decl.staticInitializerScope = enclosing.staticInitializerScope;
        decl.initializerScope = enclosing.initializerScope;
        decl.scope = innerClassScope;
        decl.binding.superInterfaces = new ReferenceBinding[0];
        decl.binding.typeVariables = new TypeVariableBinding[0];
        decl.binding.memberTypes = new ReferenceBinding[0];
        decl.modifiers = Flags.AccPublic | Flags.AccStatic;
        decl.binding.modifiers = decl.modifiers;

        // also set the bindings, but may have to unset them as well.
        ReferenceBinding[] newBindings = new ReferenceBinding[enclosing.binding.memberTypes.length + 1];
        System.arraycopy(enclosing.binding.memberTypes, 0, newBindings, 0, enclosing.binding.memberTypes.length);
        newBindings[enclosing.binding.memberTypes.length] = decl.binding;
        enclosing.binding.memberTypes = newBindings;
        return decl;
    }

    private FieldDeclaration createField(IProgramElement field, TypeDeclaration type) {
        FieldDeclaration decl = new FieldDeclaration();
        String[] split = field.getName().split("\\.");
        decl.name = split[split.length - 1].toCharArray();
        decl.type = createTypeReference(field.getCorrespondingType(true));
        decl.modifiers = field.getRawModifiers();
        return decl;
    }

    private MethodDeclaration createMethod(IProgramElement method, TypeDeclaration type, IType handle) {
        MethodDeclaration decl = new MethodDeclaration(type.compilationResult);
        decl.scope = new MethodScope(type.scope, decl, true);

        String[] split = method.getName().split("\\.");
        decl.selector = split[split.length - 1].toCharArray();
        decl.modifiers = method.getRawModifiers();

        decl.returnType = createTypeReference(method.getCorrespondingType(true));
        decl.modifiers = method.getRawModifiers();
        Argument[] args = method.getParameterTypes() != null ? new Argument[method.getParameterTypes().size()]
                : new Argument[0];
        try {
            ErasedTypeSignature sig = null;
            if (handle != null) {
                AJWorldFacade world = new AJWorldFacade(handle.getJavaProject().getProject());
                sig = world.getMethodTypeSignatures(
                        Signature.createTypeSignature(handle.getFullyQualifiedName(), true), method);
            }
            if (sig == null) {
                String[] params = new String[method.getParameterTypes().size()];
                for (int i = 0; i < params.length; i++) {
                    params[i] = new String(Signature.getTypeErasure((char[]) method.getParameterTypes().get(i)));
                }
                sig = new ErasedTypeSignature(method.getCorrespondingTypeSignature(), params);
            }

            List<String> pNames = method.getParameterNames();
            // bug 270123... no parameter names if coming in from a jar and
            // not build with debug info...mock it up.
            if (pNames == null || pNames.size() != args.length) {
                pNames = new ArrayList<String>(args.length);
                for (int i = 0; i < args.length; i++) {
                    pNames.add("args" + i);
                }
            }
            for (int i = 0; i < args.length; i++) {
                args[i] = new Argument(((String) pNames.get(i)).toCharArray(), 0,
                        createTypeReference(Signature.getElementType(sig.paramTypes[i])), 0);
            }

            decl.returnType = createTypeReferenceFromSignature(sig.returnTypeSig);
            decl.typeParameters = createTypeParameters(sig.typeParameters);
        } catch (Exception e) {
            AJLog.log("Exception occurred in ITDInserter.createMethod().  (Ignoring)");
            AJLog.log("Relevant method: " + method.getParent().getName() + "." + method.getName());
            List<String> pNames = method.getParameterNames();
            // bug 270123... no parameter names if coming in from a jar and
            // not build with debug info...mock it up.
            if (pNames == null || pNames.size() != args.length) {
                pNames = new ArrayList<String>(args.length);
                for (int i = 0; i < args.length; i++) {
                    pNames.add("args" + i);
                }
            }
            for (int i = 0; i < args.length; i++) {
                args[i] = new Argument(((String) pNames.get(i)).toCharArray(), 0,
                        createTypeReference(new String((char[]) method.getParameterTypes().get(i))), 0);
            }
        }
        decl.arguments = args;
        return decl;
    }

    /**
     * @param typeParameters
     * @return
     */
    private TypeParameter[] createTypeParameters(
            org.eclipse.ajdt.core.model.AJWorldFacade.TypeParameter[] typeParameters) {
        if (typeParameters == null || typeParameters.length == 0) {
            return null;
        }
        TypeParameter[] newTypeParameters = new TypeParameter[typeParameters.length];
        for (int i = 0; i < typeParameters.length; i++) {
            newTypeParameters[i] = new TypeParameter();
            newTypeParameters[i].name = typeParameters[i].name.toCharArray();
            if (typeParameters[i].upperBoundTypeName != null) {
                newTypeParameters[i].bounds = new TypeReference[1];
                newTypeParameters[i].bounds[0] = createTypeReference(typeParameters[i].upperBoundTypeName);
            }
        }
        return newTypeParameters;
    }

    private ConstructorDeclaration createConstructor(IProgramElement constructor, TypeDeclaration type) {
        ConstructorDeclaration decl = new ConstructorDeclaration(type.compilationResult);
        decl.scope = new MethodScope(type.scope, decl, true);
        decl.selector = constructor.getName().split("\\.")[1].toCharArray();
        decl.modifiers = constructor.getRawModifiers();
        Argument[] args = constructor.getParameterTypes() != null
                ? new Argument[constructor.getParameterTypes().size()]
                : new Argument[0];

        List<String> pNames = constructor.getParameterNames();
        // bug 270123, bug 334328... no parameter names if coming in from a jar and
        // not build with debug info...mock it up.
        if (pNames == null || pNames.size() != args.length) {
            pNames = new ArrayList<String>(args.length);
            for (int i = 0; i < args.length; i++) {
                pNames.add("args" + i);
            }
        }

        for (int i = 0; i < args.length; i++) {
            args[i] = new Argument(pNames.get(i).toCharArray(), 0,
                    createTypeReference(new String((char[]) constructor.getParameterTypes().get(i))), 0);
        }
        decl.arguments = args;
        return decl;
    }

    private void addSuperClass(IProgramElement ipe, TypeDeclaration decl) {
        List<String> types = ipe.getParentTypes();
        if (types == null || types.size() < 1)
            return;

        String typeName = types.get(0);
        addSuperClass(typeName, decl);
    }

    private void addSuperClass(String newSuper, TypeDeclaration decl) {
        decl.superclass = createTypeReference(newSuper);
        if (decl.binding != null) {
            decl.binding.superclass = createTypeBinding(newSuper);
        }
    }

    private ReferenceBinding createTypeBinding(String newSuper) {
        int genericsIndex = newSuper.indexOf("<");
        if (genericsIndex > 0) {
            newSuper = newSuper.substring(0, genericsIndex);
        }
        newSuper = newSuper.replace('$', '.');
        return env.askForType(CharOperation.splitOn('.', newSuper.toCharArray()));
    }

    private void addSuperInterfaces(IProgramElement ipe, TypeDeclaration decl) {
        List<String> newInterfaces = ipe.getParentTypes();
        if (newInterfaces != null) {
            List<String> copy = new ArrayList<String>(newInterfaces.size());
            for (String newInterface : newInterfaces) {
                copy.add(newInterface.replace('$', '.'));
            }
            addSuperInterfaces(newInterfaces, decl);
        }
    }

    /**
     * @param newInterfaces
     * @param decl
     */
    private void addSuperInterfaces(List<String> newInterfaces, TypeDeclaration decl) {
        if (newInterfaces != null) {
            int superInterfacesNum = decl.superInterfaces == null ? 0 : decl.superInterfaces.length;

            // remove duplicates
            List<TypeReference> newReferences = new ArrayList<TypeReference>(newInterfaces.size());
            for (Iterator<String> iterator = newInterfaces.iterator(); iterator.hasNext();) {
                String newInterface = iterator.next();
                TypeReference reference = createTypeReference(newInterface);
                boolean matchFound = false;
                for (int i = 0; i < superInterfacesNum; i++) {
                    if (CharOperation.equals(decl.superInterfaces[i].getTypeName(), reference.getTypeName())) {
                        iterator.remove();
                        matchFound = true;
                        break;
                    }
                }
                if (!matchFound) {
                    newReferences.add(reference);
                }
            }

            // add the ast
            TypeReference[] refs = new TypeReference[superInterfacesNum + newReferences.size()];
            if (superInterfacesNum > 0) {
                System.arraycopy(decl.superInterfaces, 0, refs, 0, decl.superInterfaces.length);
            }
            for (int i = 0; i < refs.length - superInterfacesNum; i++) {
                refs[i + superInterfacesNum] = newReferences.get(i);
            }
            decl.superInterfaces = refs;

            // now do the bindings
            if (decl.binding != null && decl.binding.superInterfaces != null) {
                superInterfacesNum = decl.binding.superInterfaces.length;
            } else {
                superInterfacesNum = 0;
            }

            ReferenceBinding[] refBindings = new ReferenceBinding[superInterfacesNum + newInterfaces.size()];
            if (superInterfacesNum > 0) {
                System.arraycopy(decl.binding.superInterfaces, 0, refBindings, 0,
                        decl.binding.superInterfaces.length);
            }
            for (int i = 0; i < refBindings.length - superInterfacesNum; i++) {
                refBindings[i + superInterfacesNum] = createTypeBinding(newInterfaces.get(i));
            }
            if (decl.binding != null) {
                decl.binding.superInterfaces = refBindings;
            }
        }
    }

    // Do it this way in order to ensure that Aspects are returned as AspectElements
    private IType getHandle(TypeDeclaration decl) {
        String typeName = new String(decl.name);
        try {
            IJavaElement maybeType = unit.getElementAt(decl.sourceStart);
            if (maybeType != null && maybeType.getElementType() == IJavaElement.TYPE) {
                return (IType) maybeType;
            }
        } catch (JavaModelException e) {
        }
        try {
            // try getting by name
            IType type = getHandleFromChild(typeName, unit);
            if (type != null) {
                return type;
            }
        } catch (JavaModelException e) {
        }
        // this type does not exist, but create a mock one anyway
        return unit.getType(typeName);
    }

    private IType getHandleFromChild(String typeName, IParent parent) throws JavaModelException {
        IJavaElement[] children = parent.getChildren();
        for (int i = 0; i < children.length; i++) {
            if ((children[i].getElementType() == IJavaElement.TYPE)
                    && typeName.equals(children[i].getElementName())) {
                return (IType) children[i];
            }
        }
        for (int i = 0; i < children.length; i++) {
            if (children[i].getElementType() == IJavaElement.TYPE
                    || children[i].getElementType() == IJavaElement.METHOD) {
                IType type = getHandleFromChild(typeName, (IParent) children[i]);
                if (type != null) {
                    return type;
                }
            }
        }
        return null;
    }

    private List<IProgramElement> getITDs(IType handle) {
        if (model.hasModel()) {
            if (model.hasProgramElement(handle)) {
                List<IJavaElement> rels = model.getRelationshipsForElement(handle,
                        AJRelationshipManager.ASPECT_DECLARATIONS);
                List<IProgramElement> elts = new ArrayList<IProgramElement>();
                for (IJavaElement je : rels) {
                    IProgramElement declareElt = model.javaElementToProgramElement(je);
                    elts.add(declareElt);
                }
                return elts;
            }
        }
        return Collections.emptyList();
    }

    private TypeReference createTypeReferenceFromSignature(String origTypeSig) {
        return typeConverter.createTypeReference(origTypeSig);
    }

    private TypeReference createTypeReference(String origTypeName) {
        // remove any references to #RAW
        if (origTypeName.endsWith("#RAW")) {
            origTypeName = origTypeName.substring(0, origTypeName.length() - 4);
        }
        // can't use the binary name
        origTypeName = origTypeName.replace('$', '.');

        return typeConverter.createTypeReference(origTypeName.toCharArray());
    }

    /**
     * replaces type declarations with their original contents after the compilation is
     * complete
     */
    public void revert() {
        for (Map.Entry<TypeDeclaration, OrigContents> entry : origMap.entrySet()) {
            revertType(entry.getKey(), entry.getValue());
        }
    }

    private void revertType(TypeDeclaration type, OrigContents orig) {
        type.methods = orig.methods;
        type.fields = orig.fields;
        type.superclass = orig.superClass;
        type.superInterfaces = orig.superInterfaces;
        type.memberTypes = orig.memberTypes;
    }
}