org.axdt.avm.scoping.AvmElementScope.java Source code

Java tutorial

Introduction

Here is the source code for org.axdt.avm.scoping.AvmElementScope.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Martin Schnabel <mb0@mb0.org>.
 * 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
 ******************************************************************************/
package org.axdt.avm.scoping;

import java.util.Iterator;
import java.util.List;

import org.axdt.avm.access.DefinitionNotFoundException;
import org.axdt.avm.model.AvmClass;
import org.axdt.avm.model.AvmDeclaredType;
import org.axdt.avm.model.AvmExecutable;
import org.axdt.avm.model.AvmInterface;
import org.axdt.avm.model.AvmMember;
import org.axdt.avm.model.AvmReferable;
import org.axdt.avm.model.AvmType;
import org.axdt.avm.model.AvmTypeReference;
import org.axdt.avm.naming.AvmQualifiedNameConverter;
import org.axdt.avm.util.AvmTypeAccess;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.EObjectDescription;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.AbstractScope;

import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

public abstract class AvmElementScope<T extends EObject> extends AbstractScope {

    public final static Function<AvmReferable, IEObjectDescription> GetDesciption = new Function<AvmReferable, IEObjectDescription>() {
        public IEObjectDescription apply(AvmReferable from) {
            String name = from.getName();
            return name != null ? EObjectDescription.create(name, from) : null;
        }
    };

    protected final T element;
    protected final EReference ref;
    protected AvmDeclaredType typeEnclosingElement;

    protected final IScope lookup;

    public AvmElementScope(IScope scope, T element, EReference ref, IScope lookup) {
        super(scope, false);
        this.element = element;
        this.ref = ref;
        this.lookup = lookup;
    }

    public IScope getLookupScope() {
        return lookup;
    }

    @Override
    protected Iterable<IEObjectDescription> getAllLocalElements() {
        return Iterables.filter(getCandidates(), Predicates.notNull());
    }

    protected abstract Iterable<IEObjectDescription> getCandidates();

    protected AvmType resolveType(AvmType type, AvmTypeReference ref) {
        if (type.eIsProxy()) {
            InternalEObject internal = (InternalEObject) type;
            String urlString = internal.eProxyURI().toString();
            if (urlString.startsWith("avm:/lookup/")) {
                String lookupName = urlString.replaceFirst("avm:/lookup/", "");
                // lets lookup the type name in the parent scope
                IScope current = getLookupScope();
                AvmLibraryScope avmScope = null;
                while (current != null) {
                    if (current instanceof AvmLibraryScope) {
                        avmScope = (AvmLibraryScope) current;
                        break;
                    }
                    if (current instanceof AbstractScope)
                        current = ((AbstractScope) current).getParent();
                    else
                        break;
                }
                if (avmScope != null) {
                    try {
                        QualifiedName qname = new AvmQualifiedNameConverter().toQualifiedName(lookupName);
                        Iterable<IEObjectDescription> desciptions = avmScope.getTypedElementsByName(qname,
                                type.eClass());
                        Iterator<IEObjectDescription> iterator = desciptions.iterator();
                        if (iterator.hasNext()) {
                            IEObjectDescription next = iterator.next();
                            EObject object = next.getEObjectOrProxy();
                            // resolve if proxy
                            if (object.eIsProxy())
                                object = EcoreUtil2.resolve(object, element);
                            type = (AvmType) object;
                            // set the canonical type name so we can skip the scope lookup next time
                            internal.eSetProxyURI(URI.createURI("avm:/types/" + type.getCanonicalName()));
                            if (ref != null) {
                                Resource resource = ref.eResource();
                                if (resource != null) {
                                    resource.setModified(true);
                                }
                            }
                        }
                    } catch (DefinitionNotFoundException e) {
                    }
                }
            } else {
                type = (AvmType) EcoreUtil2.resolve(type, element);
            }
        }
        return type;
    }

    protected void collectAllMembers(AvmTypeAccess access, List<AvmMember> list, boolean intMod, boolean first) {
        AvmDeclaredType type = (AvmDeclaredType) access.getType();
        for (AvmMember member : type.getMembers()) {
            if (member instanceof AvmExecutable && type.getName() != null
                    && type.getName().equals(member.getName())) {
                // skip constructor for now
                // we can work with type references in new expressions
                // and we usually want to access the type instead of the constructor
                // we can lookup the constructor on demand when we need parameter information
                continue;
            }
            if (member.isStatic()) {
                if (!access.isStatic())
                    continue;
            } else {
                if (!access.isInstance())
                    continue;
            }
            switch (member.getVisibility()) {
            case PUBLIC:
                break;
            case PROTECTED:
                if (access.isProtected())
                    break;
                continue;
            case PRIVATE:
                if (access.isPrivate())
                    break;
                continue;
            case INTERNAL:
                if (intMod)
                    break;
                continue;
            }
            list.add(member);
        }
        if (type.isClass()) {
            AvmClass clss = (AvmClass) type;
            AvmTypeReference extendedClass = clss.getExtendedClass();
            if (extendedClass == null && !type.getCanonicalName().equals("Object"))
                extendedClass = getObjectReference();
            AvmDeclaredType superType = resolveTypeReference(extendedClass);
            if (superType instanceof AvmClass) {
                AvmTypeAccess newaccess = AvmTypeAccess.Factory.access(superType).setProtected(access.isProtected())
                        .setInstance(access.isInstance()).setStatic(access.isStatic());
                boolean newIntMod = sameQualifier(superType, getTypeEnclosingElement());
                collectAllMembers(newaccess, list, newIntMod, false);
            }
        }
        List<AvmTypeReference> interfaces = type.getExtendedInterfaces();
        for (AvmTypeReference ref : interfaces) {
            AvmDeclaredType superType = resolveTypeReference(ref);
            if (superType instanceof AvmInterface) {
                AvmTypeAccess newaccess = AvmTypeAccess.Factory.access(superType);
                collectAllMembers(newaccess, list, false, false);
            }
        }
    }

    protected abstract AvmTypeReference getObjectReference();

    protected boolean sameQualifier(AvmDeclaredType t1, AvmDeclaredType t2) {
        if (t2 == null)
            return false;
        String qualifier = t1.getQualifier();
        if (qualifier == null) {
            if (t2.getQualifier() == null)
                return true;
        } else if (qualifier.equals(t2.getQualifier())) {
            return true;
        }
        return false;
    }

    protected Iterable<AvmMember> getAllMembers(AvmDeclaredType type, AvmTypeAccess access) {
        AvmTypeAccess newAccess = AvmTypeAccess.Factory.access(type);
        boolean intMod = false;
        AvmDeclaredType refType = getTypeEnclosingElement();
        intMod = sameQualifier(type, refType);
        if (access != null) {
            newAccess.setProtected(access.isProtected());
            newAccess.setPrivate(access.isPrivate());
            newAccess.setStatic(access.isStatic());
            newAccess.setInstance(access.isInstance());
        }
        if (intMod && type.getName().equals(refType.getName())) {
            newAccess.setProtected(true);
            newAccess.setPrivate(true);
        }
        List<AvmMember> result = Lists.newArrayList();
        collectAllMembers(newAccess, result, intMod, true);
        return result;
    }

    protected AvmDeclaredType getTypeEnclosingElement() {
        if (typeEnclosingElement == null) {
            for (EObject current = element; current != null; current = current.eContainer()) {
                if (current instanceof AvmDeclaredType) {
                    typeEnclosingElement = (AvmDeclaredType) current;
                    break;
                }
            }
        }
        return typeEnclosingElement;
    }

    protected AvmDeclaredType resolveTypeReference(AvmTypeReference ref) {
        if (ref != null) {
            AvmType parent = resolveType(ref.getType(), ref);
            if (parent instanceof AvmDeclaredType) {
                return (AvmDeclaredType) parent;
            }
        }
        return null;
    }

    protected boolean isShadowed(IEObjectDescription input) {
        QualifiedName name = input.getName();
        int count = name.getSegmentCount();
        if (count < 1 || count > 1)
            return false;
        return getLocalElementsByName(name).iterator().hasNext();
    }
}