/**
* Copyright (c) 2011-2012 Eclipse contributors 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
*/
package org.eclipse.emf.ecore.xcore.scoping;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.codegen.ecore.genmodel.GenBase;
import org.eclipse.emf.codegen.ecore.genmodel.GenClass;
import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier;
import org.eclipse.emf.codegen.ecore.genmodel.GenFeature;
import org.eclipse.emf.codegen.ecore.genmodel.GenOperation;
import org.eclipse.emf.codegen.ecore.genmodel.GenTypeParameter;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EGenericType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.ETypeParameter;
import org.eclipse.emf.ecore.xcore.XClass;
import org.eclipse.emf.ecore.xcore.XGenericType;
import org.eclipse.emf.ecore.xcore.XOperation;
import org.eclipse.emf.ecore.xcore.XReference;
import org.eclipse.emf.ecore.xcore.XcorePackage;
import org.eclipse.emf.ecore.xcore.mappings.XcoreMapper;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
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 org.eclipse.xtext.xbase.scoping.XbaseScopeProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.JvmFeatureScope;
import org.eclipse.xtext.xbase.scoping.featurecalls.LocalVarDescription;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
/**
* This class contains custom scoping description.
*
* see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping on
* how and when to use it
*
*/
public class XcoreScopeProvider extends XbaseScopeProvider
{
@Inject
private XcoreMapper mapper;
@Inject
private IQualifiedNameConverter qualifiedNameConverter;
@Override
protected IScope createLocalVarScopeForJvmDeclaredType(JvmDeclaredType type, IScope parentScope)
{
EList<JvmTypeReference> superTypes = type.getSuperTypes();
if (superTypes.isEmpty())
{
return new JvmFeatureScope(parentScope, "this", new LocalVarDescription(THIS, type));
}
else
{
return
new JvmFeatureScope
(parentScope,
"this & super",
Lists.newArrayList( new LocalVarDescription(THIS, type), new LocalVarDescription(SUPER, superTypes.get(0).getType())));
}
}
@Override
protected JvmDeclaredType getContextType(EObject call)
{
if (call == null)
{
return null;
}
else
{
XClass containerClass = EcoreUtil2.getContainerOfType(call, XClass.class);
return
containerClass != null ?
mapper.getMapping(containerClass).getInterfaceType() : // TODO use implementation class
super.getContextType(call);
}
}
@Override
public IScope getScope(final EObject context, EReference reference)
{
if (reference == XcorePackage.Literals.XREFERENCE__OPPOSITE)
{
return
new AbstractScope(IScope.NULLSCOPE, false)
{
@Override
protected Iterable<IEObjectDescription> getAllLocalElements()
{
ArrayList<IEObjectDescription> result = new ArrayList<IEObjectDescription>();
if (context instanceof XReference)
{
XReference xReference = (XReference)context;
XGenericType type = xReference.getType();
if (type != null)
{
GenBase genType = type.getType();
if (genType instanceof GenTypeParameter)
{
GenTypeParameter genTypeParameter = (GenTypeParameter)genType;
ETypeParameter eTypeParameter = genTypeParameter.getEcoreTypeParameter();
for (EGenericType eGenericType : eTypeParameter.getEBounds())
{
EClassifier eRawType = eGenericType.getERawType();
if (eRawType instanceof EClass)
{
genType = genType.getGenModel().findGenClassifier(eRawType);
break;
}
}
}
if (genType instanceof GenClass)
{
GenClass genClass = (GenClass)genType;
for (GenFeature opposite : genClass.getGenFeatures())
{
if (opposite.isReferenceType())
{
String name = opposite.getName();
if (name != null)
{
result.add(new EObjectDescription(qualifiedNameConverter.toQualifiedName(name), opposite, null));
}
}
}
}
}
}
return result;
}
};
}
else if (reference == XcorePackage.Literals.XREFERENCE__KEYS)
{
return
new AbstractScope(IScope.NULLSCOPE, false)
{
@Override
protected Iterable<IEObjectDescription> getAllLocalElements()
{
ArrayList<IEObjectDescription> result = new ArrayList<IEObjectDescription>();
if (context instanceof XReference)
{
XReference ref = (XReference)context;
GenFeature genFeature = mapper.getMapping(ref).getGenFeature();
if (genFeature != null)
{
GenClass genClass = genFeature.getTypeGenClass();
if (genClass != null)
{
for (GenFeature key : genClass.getAllGenFeatures())
{
if (!key.isReferenceType())
{
String name = key.getName();
if (name != null)
{
result.add(new EObjectDescription(qualifiedNameConverter.toQualifiedName(name), key, null));
}
}
}
}
}
}
return result;
}
};
}
else
{
IScope scope = super.getScope(context, reference);
return
reference == XcorePackage.Literals.XGENERIC_TYPE__TYPE ?
new TypeParameterScope(scope, false, context) :
scope;
}
}
protected class TypeParameterScope extends AbstractScope
{
private final EObject context;
public TypeParameterScope(IScope parent, boolean ignoreCase, EObject context)
{
super(parent, ignoreCase);
this.context = context;
}
void handleGenTypeParameters(List<IEObjectDescription> result, EList<GenTypeParameter> genTypeParameters)
{
for (final GenTypeParameter genTypeParameter : genTypeParameters)
{
result.add
(new EObjectDescription
(qualifiedNameConverter.toQualifiedName(genTypeParameter.getName()),
genTypeParameter,
null));
}
}
@Override
protected Iterable<IEObjectDescription> getAllLocalElements()
{
ArrayList<IEObjectDescription> result = new ArrayList<IEObjectDescription>();
for (EObject eObject = context; eObject != null; eObject = eObject.eContainer())
{
if (eObject instanceof XOperation)
{
GenOperation genOperation = mapper.getMapping((XOperation)eObject).getGenOperation();
if (genOperation != null)
{
handleGenTypeParameters(result, genOperation.getGenTypeParameters());
}
}
else if (eObject instanceof XClass)
{
GenClassifier genClassifier = mapper.getMapping((XClass)eObject).getGenClass();
if (genClassifier != null)
{
handleGenTypeParameters(result, genClassifier.getGenTypeParameters());
}
break;
}
}
return result;
}
}
}