/*******************************************************************************
* Copyright (c) 2012 itemis AG (http://www.itemis.eu) 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.xpect.scoping;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmFeature;
import org.eclipse.xtext.common.types.JvmOperation;
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.IScopeProvider;
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
import org.eclipse.xtext.scoping.impl.AbstractScopeProvider;
import org.eclipse.xtext.scoping.impl.SimpleScope;
import org.eclipse.xtext.util.Strings;
import org.xpect.Assignment;
import org.xpect.Component;
import org.xpect.XjmMethod;
import org.xpect.XjmTest;
import org.xpect.XpectFile;
import org.xpect.XpectJavaModel;
import org.xpect.XpectPackage;
import org.xpect.XpectTest;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.name.Named;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
@SuppressWarnings("restriction")
public class XpectScopeProvider extends AbstractScopeProvider {
@Inject
@Named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE)
private IScopeProvider delegate;
@Inject
private IJvmTypeProvider.Factory typeProviderFactory;
private Set<JvmDeclaredType> getAssignableTypes(EObject context) {
EObject current = context;
XpectJavaModel xjm = EcoreUtil2.getContainerOfType(context, XpectFile.class).getJavaModel();
ComponentUtil util = new ComponentUtil(xjm);
while (current != null) {
if (current instanceof Assignment)
return util.getValidTypes((Assignment) current);
if (current instanceof XpectTest)
return util.getValidRootTypes();
current = current.eContainer();
}
return Collections.emptySet();
}
private String getAssignmentTargetFeatureName(JvmFeature feature) {
if (feature instanceof JvmOperation) {
JvmOperation op = (JvmOperation) feature;
if (op.getParameters().size() == 1) {
String fullname = op.getSimpleName();
if (fullname.startsWith("set") || fullname.startsWith("add")) {
String name = Strings.toFirstLower(fullname.substring(3));
if (name.length() > 0)
return name;
}
}
}
return null;
}
public IScope getScope(EObject context, EReference reference) {
if (reference == XpectPackage.Literals.XPECT_TEST__DECLARED_SUITE)
return getScopeForTestClassOrSuite(EcoreUtil2.getContainerOfType(context, XpectFile.class));
if (reference == XpectPackage.Literals.XPECT_INVOCATION__METHOD)
return getScopeForXpectInvocationTestMethod(EcoreUtil2.getContainerOfType(context, XpectFile.class));
if (reference == XpectPackage.Literals.ASSIGNMENT__DECLARED_TARGET)
return getScopeForAssignmentTarget(EcoreUtil2.getContainerOfType(context, Component.class));
if (reference == XpectPackage.Literals.COMPONENT__COMPONENT_CLASS) {
return getScopeForComponentClass(context, reference);
}
return delegate.getScope(context, reference);
}
private IScope getScopeForAssignmentTarget(Component owner) {
List<IEObjectDescription> descs = Lists.newArrayList();
if (owner != null) {
JvmDeclaredType type = ((Component) owner).getComponentClass();
if (type != null && !type.eIsProxy())
for (JvmFeature feature : type.getAllFeatures()) {
String name = getAssignmentTargetFeatureName(feature);
if (name != null)
descs.add(EObjectDescription.create(QualifiedName.create(name), feature));
}
}
return new SimpleScope(descs);
}
private IScope getScopeForComponentClass(EObject context, EReference reference) {
Set<JvmDeclaredType> types = getAssignableTypes(context);
List<IEObjectDescription> descriptions = Lists.newArrayList();
for (JvmDeclaredType type : types)
descriptions.add(EObjectDescription.create(QualifiedName.create(type.getSimpleName()), type));
SimpleTypeScope typeScope = new SimpleTypeScope(typeProviderFactory.findOrCreateTypeProvider(context.eResource().getResourceSet()));
return new SimpleScope(typeScope, descriptions);
}
private IScope getScopeForTestClassOrSuite(XpectFile xpectFile) {
ResourceSet resourceSet = xpectFile.eResource().getResourceSet();
return new SimpleTypeScope(typeProviderFactory.findOrCreateTypeProvider(resourceSet));
}
private IScope getScopeForXpectInvocationTestMethod(XpectFile file) {
XpectJavaModel model = file.getJavaModel();
if (model == null || model.eIsProxy())
return IScope.NULLSCOPE;
List<IEObjectDescription> descs = Lists.newArrayList();
for (XjmTest op : model.getTests())
for (XjmMethod method : op.getMethods())
if (method != null)
descs.add(EObjectDescription.create(QualifiedName.create(method.getName()), method));
return new SimpleScope(descs);
}
}