All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.xtext.xbase.serializer.SerializerScopeProvider Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2013 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.eclipse.xtext.xbase.serializer;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.common.types.JvmConstructor;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmExecutable;
import org.eclipse.xtext.common.types.JvmField;
import org.eclipse.xtext.common.types.JvmFormalParameter;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.JvmMember;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.TypesPackage;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.EObjectDescription;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.SimpleScope;
import org.eclipse.xtext.scoping.impl.SingletonScope;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.xbase.XAbstractFeatureCall;
import org.eclipse.xtext.xbase.XAssignment;
import org.eclipse.xtext.xbase.XBinaryOperation;
import org.eclipse.xtext.xbase.XConstructorCall;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.XFeatureCall;
import org.eclipse.xtext.xbase.XMemberFeatureCall;
import org.eclipse.xtext.xbase.XSwitchExpression;
import org.eclipse.xtext.xbase.XUnaryOperation;
import org.eclipse.xtext.xbase.XVariableDeclaration;
import org.eclipse.xtext.xbase.imports.IImportsConfiguration;
import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider;
import org.eclipse.xtext.xbase.scoping.XImportSectionNamespaceScopeProvider;
import org.eclipse.xtext.xbase.scoping.batch.ConstructorTypeScopeWrapper;
import org.eclipse.xtext.xbase.scoping.batch.IFeatureNames;
import org.eclipse.xtext.xbase.scoping.batch.XbaseBatchScopeProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.OperatorMapping;
import org.eclipse.xtext.xbase.typesystem.util.IVisibilityHelper;
import org.eclipse.xtext.xtype.XImportDeclaration;
import org.eclipse.xtext.xtype.XImportSection;

import com.google.common.collect.Lists;
import com.google.inject.Inject;

/**
 * Provides minimal scopes for the serialization of feature calls, e.g.
 * scopes that contain only a single element or two elements in case of aliased
 * feature names.
 * 
 * @author Sebastian Zarnekow - Initial contribution and API
 */
public class SerializerScopeProvider extends XbaseBatchScopeProvider implements IFeatureNames {

	@Inject
	private OperatorMapping operatorMapping;
	
	@Inject
	private ILogicalContainerProvider logicalContainerProvider;
	
	@Inject
	private IQualifiedNameConverter qualifiedNameConverter;
	
	@Inject
	private IImportsConfiguration importsConfiguration;
	
	@Override
	public IScope getScope(EObject context, EReference reference) {
		if (isFeatureCallScope(reference)) {
			IScope result = createFeatureCallSerializationScope(context);
			return result;
		}
		if (isConstructorCallScope(reference)) {
			IScope result = createConstructorCallSerializationScope(context);
			return result;
		}
		return super.getScope(context, reference);
	}
	
	public IScope createConstructorCallSerializationScope(EObject context) {
		if (!(context instanceof XConstructorCall)) {
			return IScope.NULLSCOPE;
		}
		XConstructorCall constructorCall = (XConstructorCall) context;
		JvmConstructor constructor = constructorCall.getConstructor();
		if (constructor.eIsProxy()) {
			return IScope.NULLSCOPE;
		}
		IScope typeScope = getScope(context, TypesPackage.Literals.JVM_PARAMETERIZED_TYPE_REFERENCE__TYPE);
		ConstructorTypeScopeWrapper result = new ConstructorTypeScopeWrapper(context, IVisibilityHelper.ALL, typeScope);
		return result;
	}

	// TODO split this into smaller methods, investigate override / overload semantics
	// This assumes that the model was linked properly and not changed in an incompatible way
	// which is quite hard anyway ...
	public IScope createFeatureCallSerializationScope(EObject context) {
		if (!(context instanceof XAbstractFeatureCall)) {
			return IScope.NULLSCOPE;
		}
		XAbstractFeatureCall call = (XAbstractFeatureCall) context;
		JvmIdentifiableElement feature = call.getFeature();
		// this and super - logical container aware FeatureScopes
		if (feature instanceof JvmType) {
			return getTypeScope(call, (JvmType) feature);
		}
		if (feature instanceof JvmConstructor) {
			return getThisOrSuperScope(call, (JvmConstructor) feature);
		}
		if (feature instanceof JvmExecutable) {
			return getExecutableScope(call, feature);
		}
		if (feature instanceof JvmFormalParameter || feature instanceof JvmField || feature instanceof XVariableDeclaration || feature instanceof XSwitchExpression) {
			return new SingletonScope(EObjectDescription.create(feature.getSimpleName(), feature), IScope.NULLSCOPE);
		}
		return IScope.NULLSCOPE;
	}

	protected IScope getExecutableScope(XAbstractFeatureCall call, JvmIdentifiableElement feature) {
		QualifiedName name = QualifiedName.create(feature.getSimpleName());
		if (call instanceof XBinaryOperation || call instanceof XUnaryOperation) {
			QualifiedName operator = operatorMapping.getOperator(name);
			if (operator == null) {
				return IScope.NULLSCOPE;
			}
			return new SingletonScope(EObjectDescription.create(operator, feature), IScope.NULLSCOPE);
		}
		if (call instanceof XAssignment) {
			String propertyName = Strings.toFirstLower(feature.getSimpleName().substring(3));
			return new SingletonScope(EObjectDescription.create(propertyName, feature), IScope.NULLSCOPE);
		}
		if (call.isExplicitOperationCallOrBuilderSyntax() || ((JvmExecutable) feature).getParameters().size() >= 1) {
			return new SingletonScope(EObjectDescription.create(name, feature), IScope.NULLSCOPE);
		}
		if (feature.getSimpleName().startsWith("get") || feature.getSimpleName().startsWith("is")) {
			List result = Lists.newArrayListWithCapacity(2);
			result.add(EObjectDescription.create(name, feature));
			if (feature.getSimpleName().startsWith("get")) {
				String propertyName = Strings.toFirstLower(feature.getSimpleName().substring(3));
				result.add(EObjectDescription.create(propertyName, feature));
			} else {
				String propertyName = Strings.toFirstLower(feature.getSimpleName().substring(2));
				result.add(EObjectDescription.create(propertyName, feature));
			}
			return new SimpleScope(result);
		}
		return new SingletonScope(EObjectDescription.create(name, feature), IScope.NULLSCOPE);
	}

	protected IScope getThisOrSuperScope(XAbstractFeatureCall call, JvmConstructor constructor) {
		QualifiedName name = THIS;
		JvmIdentifiableElement logicalContainer = logicalContainerProvider.getNearestLogicalContainer(call);
		if (logicalContainer instanceof JvmConstructor) {
			JvmDeclaredType thisType = ((JvmConstructor) logicalContainer).getDeclaringType();
			if (thisType != constructor.getDeclaringType()) {
				name = SUPER;
			}
		}
		return new SingletonScope(EObjectDescription.create(name, constructor), IScope.NULLSCOPE);
	}
	
	protected IScope getTypeScope(XAbstractFeatureCall call, JvmType type) {
		if (call.isTypeLiteral() || call.isPackageFragment()) {
			return doGetTypeScope(call, type);
		}
		return getThisOrSuperScope(call, type);
	}
	
	protected IScope doGetTypeScope(XAbstractFeatureCall call, JvmType type) {
		if (call instanceof XFeatureCall) {
			return doGetTypeScope((XFeatureCall) call, type);
		} else if (call instanceof XMemberFeatureCall) {
			return doGetTypeScope((XMemberFeatureCall) call, type);
		} else {
			return IScope.NULLSCOPE;
		}
	}
	
	protected IScope doGetTypeScope(XFeatureCall call, JvmType type) {
		if (call.isPackageFragment()) {
			if (type instanceof JvmDeclaredType) {
				String packageName = ((JvmDeclaredType) type).getPackageName();
				int dot = packageName.indexOf('.');
				if (dot == -1) {
					return new SingletonScope(EObjectDescription.create(packageName, type), IScope.NULLSCOPE);
				} else {
					String firstSegment = packageName.substring(0, dot);
					return new SingletonScope(EObjectDescription.create(firstSegment, type), IScope.NULLSCOPE);
				}
			}
			return IScope.NULLSCOPE;
		} else {
			if (type instanceof JvmDeclaredType && ((JvmDeclaredType) type).getDeclaringType() != null) {
				Resource resource = call.eResource();
				if (resource instanceof XtextResource) {
					XImportSection importSection = importsConfiguration.getImportSection((XtextResource) resource);
					if (importSection != null) {
						List importDeclarations = importSection.getImportDeclarations();
						List descriptions = Lists.newArrayList();
						for(XImportDeclaration importDeclaration: importDeclarations) {
							if (!importDeclaration.isStatic() && !importDeclaration.isWildcard() && !importDeclaration.isExtension()) {
								JvmDeclaredType importedType = importDeclaration.getImportedType();
								if (importedType == type) {
									String syntax = importsConfiguration.getLegacyImportSyntax(importDeclaration);
									if (syntax != null /* no node model attached */ && syntax.equals(type.getQualifiedName())) {
										String packageName = importedType.getPackageName();
										descriptions.add(EObjectDescription.create(syntax.substring(packageName.length() + 1), type));
									}
								}
								if (EcoreUtil.isAncestor(importedType, type)) {
									String name = type.getSimpleName();
									JvmType worker = type;
									while(worker != importedType) {
										worker = (JvmType) worker.eContainer();
										name = worker.getSimpleName() + "$" + name;
									}
									descriptions.add(EObjectDescription.create(name, type));
								}
							}
						}
						return new SimpleScope(descriptions);
					}
				}
				return new SingletonScope(EObjectDescription.create(type.getSimpleName(), type), IScope.NULLSCOPE);
			} else {
				return new SingletonScope(EObjectDescription.create(type.getSimpleName(), type), IScope.NULLSCOPE);
			}
		}
	}
	
	protected IScope doGetTypeScope(XMemberFeatureCall call, JvmType type) {
		if (call.isPackageFragment()) {
			if (type instanceof JvmDeclaredType) {
				int segmentIndex = countSegments(call);
				String packageName = ((JvmDeclaredType) type).getPackageName();
				List splitted = Strings.split(packageName, '.');
				String segment = splitted.get(segmentIndex);
				return new SingletonScope(EObjectDescription.create(segment, type), IScope.NULLSCOPE);
			}
			return IScope.NULLSCOPE;
		} else {
			if (type instanceof JvmDeclaredType && ((JvmDeclaredType) type).getDeclaringType() == null) {
				return new SingletonScope(EObjectDescription.create(type.getSimpleName(), type), IScope.NULLSCOPE);
			} else {
				XAbstractFeatureCall target = (XAbstractFeatureCall) call.getMemberCallTarget();
				if (target.isPackageFragment()) {
					String qualifiedName = type.getQualifiedName();
					int dot = qualifiedName.lastIndexOf('.');
					String simpleName = qualifiedName.substring(dot + 1);
					return new SingletonScope(EObjectDescription.create(simpleName, type), IScope.NULLSCOPE);
				} else {
					return new SingletonScope(EObjectDescription.create(type.getSimpleName(), type), IScope.NULLSCOPE);	
				}
			}
		}
	}
	
	private int countSegments(XMemberFeatureCall call) {
		int result = 1;
		while(call.getMemberCallTarget() instanceof XMemberFeatureCall) {
			call = (XMemberFeatureCall) call.getMemberCallTarget();
			result++;
		}
		return result;
	}

	protected IScope getThisOrSuperScope(XAbstractFeatureCall call, JvmType thisOrSuper) {
		QualifiedName name = THIS;
		JvmIdentifiableElement logicalContainer = logicalContainerProvider.getNearestLogicalContainer(call);
		if (logicalContainer instanceof JvmMember) {
			JvmDeclaredType thisType = ((JvmMember) logicalContainer).getDeclaringType();
			if (thisType != thisOrSuper) {
				name = SUPER;
			}
		}
		return new SingletonScope(EObjectDescription.create(name, thisOrSuper), IScope.NULLSCOPE);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy