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

org.eclipse.xtext.xbase.linking.BestMatchingJvmFeatureScope Maven / Gradle / Ivy

There is a newer version: 2.4.3
Show newest version
/*******************************************************************************
 * Copyright (c) 2010 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.linking;

import static org.eclipse.xtext.xbase.validation.IssueCodes.*;

import java.util.Collections;
import java.util.EnumSet;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.common.types.JvmExecutable;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.common.types.util.IRawTypeHelper;
import org.eclipse.xtext.common.types.util.ITypeArgumentContext;
import org.eclipse.xtext.common.types.util.TypeConformanceComputer;
import org.eclipse.xtext.common.types.util.TypeConformanceResult.Kind;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.xbase.XAbstractFeatureCall;
import org.eclipse.xtext.xbase.XConstructorCall;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.XbasePackage;
import org.eclipse.xtext.xbase.scoping.featurecalls.IValidatedEObjectDescription;
import org.eclipse.xtext.xbase.scoping.featurecalls.JvmFeatureDescription;

/**
 * A scope which goes through all returned EObjectDescriptions in order to find the best fit, if it is asked for the
 * 'first' element.
 * 
 * @author Sven Efftinge - Initial contribution and API
 */
@SuppressWarnings("deprecation")
public class BestMatchingJvmFeatureScope implements IScope {

	protected final EObject context;
	protected final EReference reference;
	private TypeConformanceComputer conformanceComputer;
	private IScope delegate;
	private FeatureCallChecker featureCallChecker;
	private IRawTypeHelper rawTypeHelper;

	public BestMatchingJvmFeatureScope(TypeConformanceComputer conformanceComputer, EObject context, EReference ref,
			IScope delegate, FeatureCallChecker featureCallChecker, IRawTypeHelper rawTypeHelper) {
		this.conformanceComputer = conformanceComputer;
		this.context = context;
		this.reference = ref;
		this.delegate = delegate;
		this.featureCallChecker = featureCallChecker;
		this.rawTypeHelper = rawTypeHelper;
	}

	public Iterable getAllElements() {
		throw new UnsupportedOperationException();
	}

	public Iterable getElements(EObject object) {
		throw new UnsupportedOperationException();
	}

	public Iterable getElements(QualifiedName name) {
		throw new UnsupportedOperationException();
	}

	public IEObjectDescription getSingleElement(EObject object) {
		throw new UnsupportedOperationException();
	}

	public IEObjectDescription getSingleElement(QualifiedName name) {
		Iterable unsorted = delegate.getElements(name);
		return setImplicitReceiverAndIsValid(getBestMatch(unsorted));
	}

	protected IEObjectDescription setImplicitReceiverAndIsValid(IEObjectDescription bestMatch) {
		if (bestMatch instanceof IValidatedEObjectDescription) {
			if (this.reference == XbasePackage.Literals.XABSTRACT_FEATURE_CALL__FEATURE) {
				final XAbstractFeatureCall featureCall = (XAbstractFeatureCall) this.context;
				IValidatedEObjectDescription validated = (IValidatedEObjectDescription) bestMatch;
				featureCall.eSetDeliver(false);
				try {
					featureCall.setInvalidFeatureIssueCode(validated.getIssueCode());
					if (validated instanceof JvmFeatureDescription) {
						final XExpression implicitReceiver = ((JvmFeatureDescription) validated).getImplicitReceiver();
						if (implicitReceiver!=null) {
							featureCall.setImplicitReceiver(EcoreUtil2.clone(implicitReceiver));
						}
						XExpression implicitArgument = ((JvmFeatureDescription) validated).getImplicitArgument();
						if (implicitArgument != null) {
							featureCall.setImplicitFirstArgument(EcoreUtil2.clone(implicitArgument));
						}
					}
				} finally {
					featureCall.eSetDeliver(true);
				}
			} else if(this.reference == XbasePackage.Literals.XCONSTRUCTOR_CALL__CONSTRUCTOR) {
				final XConstructorCall constructorCall = (XConstructorCall) this.context;
				constructorCall.eSetDeliver(false);
				try {
					constructorCall.setInvalidFeatureIssueCode(((IValidatedEObjectDescription) bestMatch).getIssueCode());
				} finally {
					constructorCall.eSetDeliver(true);
				}
			}
		}
		return bestMatch;
	}

	protected IEObjectDescription getBestMatch(Iterable iterable) {
		IEObjectDescription bestMatch = null;
		for (IEObjectDescription description : iterable) {
			featureCallChecker.checkWithoutTypes(description);
			if (bestMatch == null) {
				bestMatch = description;
			} else {
				bestMatch = getBestMatch(bestMatch, description);
			}
		}
		return bestMatch;
	}

	protected IEObjectDescription getBestMatch(IEObjectDescription a, IEObjectDescription b) {
		if (a instanceof IValidatedEObjectDescription && b instanceof IValidatedEObjectDescription) {
			IValidatedEObjectDescription descA = (IValidatedEObjectDescription) a;
			IValidatedEObjectDescription descB = (IValidatedEObjectDescription) b;
			{
				IValidatedEObjectDescription result = selectByIssueCode(descA, descB);
				if (result != null)
					return result;
			}
			featureCallChecker.checkTypesWithoutGenerics(a);
			featureCallChecker.checkTypesWithoutGenerics(b);
			while(true) {
				IValidatedEObjectDescription result = selectByIssueCode(descA, descB);
				if (result != null)
					return result;
				boolean again = featureCallChecker.checkTypesWithGenerics(a);
				again = featureCallChecker.checkTypesWithGenerics(b) || again;
				if (!again) {
					break;
				}
			}
			if (a instanceof JvmFeatureDescription && b instanceof JvmFeatureDescription) {
				JvmFeatureDescription featureDescriptionA = (JvmFeatureDescription) descA;
				JvmFeatureDescription featureDescriptionB = (JvmFeatureDescription) descB;
				if (featureDescriptionA.isValid() && featureDescriptionB.isValid()) {
					JvmFeatureDescription potentialResult = getBestConformanceMatch(featureDescriptionA, featureDescriptionB);
					if (potentialResult != null)
						return potentialResult;
				}
				if (descA.getEObjectOrProxy() instanceof JvmExecutable) {
					if (descB.getEObjectOrProxy() instanceof JvmExecutable) {
						JvmExecutable opA = (JvmExecutable) descA.getEObjectOrProxy();
						JvmExecutable opB = (JvmExecutable) descB.getEObjectOrProxy();
						if (descA.isValid() && descB.isValid()) {
							if (opA.isVarArgs()) {
								if (!opB.isVarArgs()) {
									return b;
								}
							} else if (opB.isVarArgs()) {
								return a;
							}
						}
						ITypeArgumentContext contextA = featureDescriptionA.getRawTypeContext();
						ITypeArgumentContext contextB = featureDescriptionB.getRawTypeContext();
						int numParamsA = opA.getParameters().size();
						int numParamsB = opB.getParameters().size();
						for (int i = 0; i < Math.min(numParamsA, numParamsB); i++) {
							JvmTypeReference pA = opA.getParameters().get(numParamsA-i-1).getParameterType();
							pA = contextA.getLowerBound(pA);
							pA = rawTypeHelper.getRawTypeReference(pA, context.eResource());
							JvmTypeReference pB = opB.getParameters().get(numParamsB-i-1).getParameterType();
							pB = contextB.getLowerBound(pB);
							pB = rawTypeHelper.getRawTypeReference(pB, context.eResource());
							if (!conformanceComputer.isConformant(pB, pA, true))
								return b;
						}
						return a;
					}
				}
			}
		}
		return a;
	}

	protected IValidatedEObjectDescription selectByIssueCode(IValidatedEObjectDescription descA, IValidatedEObjectDescription descB) {
		if (!descA.isSameValidationState(descB))
			return null;
		if(descA.isValid()) { 
			if(!descB.isValid())
				return descA;
		} else if(descB.isValid()) {
			return descB;
		} else if (!descA.isValid() && !descB.isValid()) {
			if (descA.getIssueCode() != null && descB.getIssueCode() != null) {
				int issueCodeComparison = compareIssueCodes(descA.getIssueCode(), descB.getIssueCode());
				if (issueCodeComparison < 0)
					return descA;
				if (issueCodeComparison > 0)
					return descB;
			}
		}
		return null;
	}

	protected JvmFeatureDescription getBestConformanceMatch(JvmFeatureDescription featureDescriptionA,
			JvmFeatureDescription featureDescriptionB) {
		List> allHintsA = featureDescriptionA.getArgumentConversionHints();
		if (allHintsA == null)
			allHintsA = Collections.emptyList();
		List> allHintsB = featureDescriptionB.getArgumentConversionHints();
		if (allHintsB == null)
			allHintsB = Collections.emptyList();
		int aIsBetter = 0;
		int bIsBetter = 0;
		for(int i = 0; i < allHintsA.size() && i < allHintsB.size(); i++) {
			EnumSet hintsA = allHintsA.get(i);
			EnumSet hintsB = allHintsB.get(i);
			for(Kind kind: Kind.values()) {
				if (hintsA.contains(kind)) {
					if (!hintsB.contains(kind)) {
						aIsBetter++;
						break;
					}
				} else {
					if (hintsB.contains(kind)) {
						bIsBetter++;
						break;
					}
				}
			}
		}
		if (aIsBetter == bIsBetter)
			return null;
		if (aIsBetter > bIsBetter)
			return featureDescriptionA;
		return featureDescriptionB;
	}

	@Override
	public String toString() {
		return getClass().getSimpleName() + " -> " + delegate;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy