/* * generated by Xtext */ package org.eclipselabs.spray.xtext.scoping; import java.util.Collections; import java.util.Iterator; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.common.types.JvmDeclaredType; import org.eclipse.xtext.common.types.JvmField; import org.eclipse.xtext.common.types.JvmGenericType; import org.eclipse.xtext.common.types.JvmMember; import org.eclipse.xtext.common.types.JvmOperation; import org.eclipse.xtext.common.types.JvmType; import org.eclipse.xtext.common.types.JvmTypeReference; import org.eclipse.xtext.common.types.TypesPackage; import org.eclipse.xtext.common.types.access.IJvmTypeProvider; 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.Scopes; import org.eclipse.xtext.scoping.impl.FilteringScope; import org.eclipse.xtext.scoping.impl.MapBasedScope; import org.eclipse.xtext.scoping.impl.SimpleScope; import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociations; import org.eclipse.xtext.xbase.scoping.LocalVariableScopeContext; import org.eclipse.xtext.xbase.scoping.XbaseScopeProvider; import org.eclipselabs.spray.mm.spray.ColorConstantRef; import org.eclipselabs.spray.mm.spray.Connection; import org.eclipselabs.spray.mm.spray.MetaAttribute; import org.eclipselabs.spray.mm.spray.MetaClass; import org.eclipselabs.spray.mm.spray.MetaReference; import org.eclipselabs.spray.xtext.api.IColorConstantTypeProvider; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.inject.Inject; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.COLOR_CONSTANT_REF__FIELD; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.CONNECTION; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.CONNECTION__FROM; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.CONNECTION__TO; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.META_ATTRIBUTE; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.META_ATTRIBUTE__ATTRIBUTE; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.META_ATTRIBUTE__PATHSEGMENTS; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.META_CLASS__TYPE; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.META_REFERENCE; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.META_REFERENCE__LABEL_PROPERTY; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.META_REFERENCE__REFERENCE; import static org.eclipselabs.spray.mm.spray.SprayPackage.Literals.TEXT; /** * This class contains custom scoping description. * see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping on * how and when to use it */ @SuppressWarnings("restriction") public class SprayScopeProvider extends XbaseScopeProvider { @Inject private IJvmModelAssociations associations; @Inject private IJvmTypeProvider.Factory typeProviderFactory; @Inject(optional = true) private IColorConstantTypeProvider colorConstantTypeProvider; @Override public IScope getScope(EObject context, EReference reference) { if (reference == META_CLASS__TYPE) { // filter out types with URL schema qualified names final IScope scope = delegateGetScope(context, reference); final Predicate<IEObjectDescription> filter = new Predicate<IEObjectDescription>() { @Override public boolean apply(IEObjectDescription input) { return !input.getQualifiedName().toString().startsWith("http://"); } }; return new FilteringScope(scope, filter); } else if (context.eClass() == CONNECTION && reference == CONNECTION__FROM) { final MetaClass metaClass = EcoreUtil2.getContainerOfType(context, MetaClass.class); final IScope result = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(metaClass.getType().getEAllReferences())); return result; } else if (context.eClass() == CONNECTION && reference == CONNECTION__TO) { final Connection connection = (Connection) context; final MetaClass metaClass = EcoreUtil2.getContainerOfType(context, MetaClass.class); // filter 'from' from the possible references Iterable<EReference> targetReferences = Iterables.filter(metaClass.getType().getEAllReferences(), new Predicate<EReference>() { @Override public boolean apply(EReference input) { return input != connection.getFrom(); } }); final IScope result = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(targetReferences)); return result; } else if (context.eClass() == META_REFERENCE && reference == META_REFERENCE__REFERENCE) { final MetaClass metaClass = EcoreUtil2.getContainerOfType(context, MetaClass.class); final IScope result = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(metaClass.getType().getEAllReferences())); return result; } else if (context.eClass() == META_REFERENCE && reference == META_REFERENCE__LABEL_PROPERTY) { MetaReference metaRef = (MetaReference) context; EReference ref = metaRef.getReference(); if (ref.eIsProxy()) { ref = (EReference) EcoreUtil.resolve(ref, context); if (ref.eIsProxy()) { // still a proxy? return IScope.NULLSCOPE; } } final IScope result = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(metaRef.getReference().getEReferenceType().getEAllAttributes())); return result; } else if (context.eClass() == META_ATTRIBUTE && reference == META_ATTRIBUTE__PATHSEGMENTS) { MetaClass metaClass = EcoreUtil2.getContainerOfType(context, MetaClass.class); MetaAttribute attr = (MetaAttribute) context; EClass currentClass = metaClass.getType(); for (EReference ref : attr.getPathsegments()) { if (ref.eIsProxy()) { IScope scope = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(currentClass.getEAllReferences())); return scope; } currentClass = ref.getEReferenceType(); } IScope scope = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(currentClass.getEAllReferences())); return scope; } else if (context.eClass() == META_ATTRIBUTE && reference == META_ATTRIBUTE__ATTRIBUTE) { MetaClass metaClass = EcoreUtil2.getContainerOfType(context, MetaClass.class); EClass currentClass = metaClass.getType(); MetaAttribute metaAttr = (MetaAttribute) context; for (EReference ref : metaAttr.getPathsegments()) { if (ref.eIsProxy()) { ref = (EReference) EcoreUtil.resolve(ref, currentClass); if (ref.eIsProxy()) { // still a proxy? return IScope.NULLSCOPE; } } currentClass = ref.getEReferenceType(); } final IScope scope = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(currentClass.getEAllAttributes())); return scope; } else if (context.eClass() == TEXT && reference == META_ATTRIBUTE__PATHSEGMENTS) { MetaClass metaClass = EcoreUtil2.getContainerOfType(context, MetaClass.class); IScope scope = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(metaClass.getType().getEAllReferences())); return scope; } else if (context.eClass() == TEXT && reference == META_ATTRIBUTE__ATTRIBUTE) { MetaClass metaClass = EcoreUtil2.getContainerOfType(context, MetaClass.class); IScope scope = MapBasedScope.createScope(IScope.NULLSCOPE, Scopes.scopedElementsFor(metaClass.getType().getEAllAttributes())); return scope; } else if (reference == TypesPackage.Literals.JVM_PARAMETERIZED_TYPE_REFERENCE__TYPE) { ColorConstantRef colorConstant = EcoreUtil2.getContainerOfType(context, ColorConstantRef.class); if (colorConstant != null) { return getColorConstantTypeScope(colorConstant); } } else if (reference == COLOR_CONSTANT_REF__FIELD) { return getColorConstantFieldScope(context); } return super.getScope(context, reference); } protected IScope getColorConstantTypeScope(ColorConstantRef colorConstantRef) { IScope typesScope = delegateGetScope(colorConstantRef, TypesPackage.Literals.JVM_PARAMETERIZED_TYPE_REFERENCE__TYPE); Predicate<IEObjectDescription> colorConstantsFilter = new Predicate<IEObjectDescription>() { @Override public boolean apply(IEObjectDescription input) { if (input.getEObjectOrProxy() instanceof JvmGenericType) { return isColorConstant((JvmGenericType) input.getEObjectOrProxy()); } else { return false; } } private boolean isColorConstant(JvmGenericType type) { if ("org.eclipse.graphiti.util.IColorConstant".equals(type.getIdentifier())) { return true; } for (JvmTypeReference itfRef : type.getExtendedInterfaces()) { if (isColorConstant(itfRef)) { return true; } } for (JvmTypeReference superTypeRef : type.getSuperTypes()) { if (isColorConstant(superTypeRef)) { return true; } } return false; } private boolean isColorConstant(JvmTypeReference typeRef) { if ("org.eclipse.graphiti.util.IColorConstant".equals(typeRef.getIdentifier())) { return true; } JvmGenericType type = (JvmGenericType) typeRef.getType(); for (JvmTypeReference itfRef : type.getExtendedInterfaces()) { if ("org.eclipse.graphiti.util.IColorConstant".equals(itfRef.getIdentifier())) { return true; } } for (JvmTypeReference superTypeRef : type.getSuperTypes()) { if (isColorConstant(superTypeRef)) { return true; } } return false; } }; IScope result = new FilteringScope(typesScope, colorConstantsFilter); return result; } protected IScope getColorConstantFieldScope(EObject context) { if (context instanceof ColorConstantRef && ((ColorConstantRef) context).getType() != null) { JvmTypeReference typeRef = ((ColorConstantRef) context).getType(); if (!(typeRef.getType() instanceof JvmGenericType)) return IScope.NULLSCOPE; JvmGenericType type = (JvmGenericType) typeRef.getType(); Iterable<JvmField> fields = Iterables.filter(type.getMembers(), JvmField.class); // Filter out all fields that are not of type IColorConstant // fields = Iterables.filter(fields, colorConstantsFilter); Function<JvmField, IEObjectDescription> toObjDesc = new Function<JvmField, IEObjectDescription>() { @Override public IEObjectDescription apply(JvmField from) { return EObjectDescription.create(from.getSimpleName(), from); } }; final IScope scope = MapBasedScope.createScope(IScope.NULLSCOPE, Iterables.transform(fields, toObjDesc)); return scope; } else { if (colorConstantTypeProvider == null) { // colorConstantTypeProvider not set => no implicit colors return IScope.NULLSCOPE; } // implicit color constants IJvmTypeProvider typeProvider = typeProviderFactory.findOrCreateTypeProvider(context.eResource().getResourceSet()); // get the Jvm Type that represents a color (Graphiti: IColorConstant) JvmDeclaredType colorJvmType = (JvmDeclaredType) typeProvider.findTypeByName(colorConstantTypeProvider.getColorType().getName()); if (colorJvmType == null) { return null; } final JvmDeclaredType colorJvmType2 = colorJvmType; // this filter selects members that have the required type 'colorJvmType' Predicate<JvmMember> memberFilter = new Predicate<JvmMember>() { @Override public boolean apply(JvmMember input) { if (input instanceof JvmField) { return ((JvmField) input).getType().getType() == colorJvmType2; } else if (input instanceof JvmOperation) { return ((JvmOperation) input).getReturnType().getType() == colorJvmType2; } else { return false; } } }; // Function to create IEObjectDescriptions for JvmMembers Function<JvmMember, QualifiedName> trafo = new Function<JvmMember, QualifiedName>() { @Override public QualifiedName apply(JvmMember from) { return QualifiedName.create(from.getSimpleName().toLowerCase()); } }; // for each class, create a scope with the JvmFields of the class IScope scope = IScope.NULLSCOPE; for (Class<?> clazz : colorConstantTypeProvider.getColorConstantTypes()) { JvmType t = typeProvider.findTypeByName(clazz.getName()); if (t != null && t instanceof JvmDeclaredType) { scope = Scopes.scopeFor(Iterables.filter(((JvmDeclaredType) t).getMembers(), memberFilter), trafo, scope); } } return scope; } } /** * Create the local variable scope for expressions. * The method will bind a variable 'this' which refers to the JvmType of the EClass associated with the current MetaClass. */ @Override protected IScope createLocalVarScope(IScope parentScope, LocalVariableScopeContext scopeContext) { // Look up the containment hierarchy of the current object to find the MetaClass MetaClass mc = EcoreUtil2.getContainerOfType(scopeContext.getContext(), MetaClass.class); if (mc != null) { // get the JvmType for MetaClass. It is inferred by the SprayJvmModelInferrer JvmGenericType jvmType = (JvmGenericType) getJvmType(mc); if (jvmType == null || jvmType.getMembers().isEmpty()) { // should not happen! return IScope.NULLSCOPE; } // the JvmType has a field named 'ecoreClass' JvmField eClassField = (JvmField) jvmType.getMembers().get(0); Assert.isTrue(eClassField.getSimpleName().equals("ecoreClass")); // get the JvmType of the associated EClass JvmType jvmTypeOfEcoreClass = eClassField.getType().getType(); // bind the EClass' JvmType as variable 'this' IScope result = new SimpleScope(parentScope, Collections.singleton(EObjectDescription.create(XbaseScopeProvider.THIS, jvmTypeOfEcoreClass))); return result; } return super.createLocalVarScope(parentScope, scopeContext); } protected JvmType getJvmType(EObject context) { Iterable<JvmType> jvmTypes = Iterables.filter(associations.getJvmElements(context), JvmType.class); Iterator<JvmType> it = jvmTypes.iterator(); JvmType result = it.hasNext() ? it.next() : null; return result; } }