org.eclipse.xtext.xbase.scoping.XbaseScopeProvider Maven / Gradle / Ivy
/*******************************************************************************
* 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.scoping;
import static com.google.common.collect.Iterables.*;
import static com.google.common.collect.Lists.*;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
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.JvmAnyTypeReference;
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.JvmFeature;
import org.eclipse.xtext.common.types.JvmField;
import org.eclipse.xtext.common.types.JvmFormalParameter;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
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.JvmUnknownTypeReference;
import org.eclipse.xtext.common.types.TypesPackage;
import org.eclipse.xtext.common.types.util.ITypeArgumentContext;
import org.eclipse.xtext.common.types.util.TypeReferences;
import org.eclipse.xtext.common.types.util.VisibilityService;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.DelegatingScopeProvider;
import org.eclipse.xtext.util.IAcceptor;
import org.eclipse.xtext.xbase.XAbstractFeatureCall;
import org.eclipse.xtext.xbase.XAssignment;
import org.eclipse.xtext.xbase.XBinaryOperation;
import org.eclipse.xtext.xbase.XBlockExpression;
import org.eclipse.xtext.xbase.XCasePart;
import org.eclipse.xtext.xbase.XCatchClause;
import org.eclipse.xtext.xbase.XClosure;
import org.eclipse.xtext.xbase.XConstructorCall;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.XFeatureCall;
import org.eclipse.xtext.xbase.XForLoopExpression;
import org.eclipse.xtext.xbase.XMemberFeatureCall;
import org.eclipse.xtext.xbase.XNullLiteral;
import org.eclipse.xtext.xbase.XSwitchExpression;
import org.eclipse.xtext.xbase.XUnaryOperation;
import org.eclipse.xtext.xbase.XVariableDeclaration;
import org.eclipse.xtext.xbase.XbaseFactory;
import org.eclipse.xtext.xbase.XbasePackage;
import org.eclipse.xtext.xbase.impl.FeatureCallToJavaMapping;
import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.DefaultConstructorDescriptionProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.DefaultJvmFeatureDescriptionProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.IFeaturesForTypeProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.IJvmFeatureDescriptionProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.IJvmFeatureScopeProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.IJvmFeatureScopeProvider.FeatureScopeDescription;
import org.eclipse.xtext.xbase.scoping.featurecalls.IValidatedEObjectDescription;
import org.eclipse.xtext.xbase.scoping.featurecalls.JvmFeatureDescription;
import org.eclipse.xtext.xbase.scoping.featurecalls.JvmFeatureScope;
import org.eclipse.xtext.xbase.scoping.featurecalls.LocalVarDescription;
import org.eclipse.xtext.xbase.scoping.featurecalls.StaticImplicitMethodsFeatureForTypeProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.XAssignmentDescriptionProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.XAssignmentSugarDescriptionProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.XConstructorProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.XFeatureCallSugarDescriptionProvider;
import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver;
import org.eclipse.xtext.xbase.typesystem.IResolvedTypes;
import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
import org.eclipse.xtext.xbase.typing.ITypeProvider;
import org.eclipse.xtext.xbase.validation.IssueCodes;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.util.Providers;
/**
* The scope provider for languages that use Xbase.
*
* @author Sven Efftinge - Initial contribution and API
* @author Sebastian Zarnekow - Refactored feature scoping to acceptor pattern
*/
@Deprecated
public class XbaseScopeProvider extends DelegatingScopeProvider {
protected static final int DEFAULT_MEMBER_CALL_PRIORITY = 0;
protected static final int DEFAULT_IT_PRIORITY = 10;
protected static final int DEFAULT_THIS_PRIORITY = 20;
protected static final int DEFAULT_IMPLICIT_STATIC_FEATURE_PRIORITY = 60;
protected static final int DEFAULT_SUGAR_PRIORITY_OFFSET = 100;
protected static final int DEFAULT_STATIC_EXTENSION_PRIORITY_OFFSET = 230;
private final static Logger log = Logger.getLogger(XbaseScopeProvider.class);
public static final QualifiedName THIS = QualifiedName.create("this");
public static final QualifiedName SUPER = QualifiedName.create("super");
public static final QualifiedName IT = QualifiedName.create("it");
@Inject
protected IJvmFeatureScopeProvider jvmFeatureScopeProvider;
@Inject
private Provider defaultFeatureDescProvider;
@Inject
private Provider defaultConstructorDescProvider;
@Inject
private Provider constructorProvider;
@Inject
private Provider sugarFeatureDescProvider;
@Inject
private Provider implicitStaticFeatures;
@Inject
private Provider assignmentFeatureDescProvider;
@Inject
private Provider assignmentSugarFeatureDescProvider;
@Inject
private ITypeProvider typeProvider;
@Inject
private IBatchTypeResolver batchTypeResolver;
@Inject
private FeatureCallToJavaMapping featureCallToJavaMapping;
@Inject
private TypeReferences typeReferences;
@Inject
private ILogicalContainerProvider logicalContainerProvider;
@Inject
private VisibilityService visibilityService;
public void setTypeProvider(ITypeProvider typeProvider) {
this.typeProvider = typeProvider;
}
protected ITypeProvider getTypeProvider() {
return typeProvider;
}
public void setSugarFeatureDescProvider(Provider sugarFeatureDescProvider) {
this.sugarFeatureDescProvider = sugarFeatureDescProvider;
}
public void setDefaultFeatureDescProvider(Provider defaultFeatureDescProvider) {
this.defaultFeatureDescProvider = defaultFeatureDescProvider;
}
@Override
public IScope getScope(EObject context, EReference reference) {
if (log.isDebugEnabled()) {
log.debug("enter getScope(" + context + ", " + reference.getEContainingClass().getName() + "#" + reference.getName() + ")");
}
try {
if (isFeatureCallScope(reference)) {
if (!(context instanceof XAbstractFeatureCall)) {
return IScope.NULLSCOPE;
}
return createFeatureCallScope((XAbstractFeatureCall) context, reference);
}
if (isConstructorCallScope(reference)) {
return createConstructorCallScope(context, reference);
}
return super.getScope(context, reference);
} catch (RuntimeException e) {
log.error("error during scoping", e);
throw e;
} finally {
if (log.isDebugEnabled()) {
log.debug("leave getScope(" + context + ", " + reference.getEContainingClass().getName() + "#" + reference.getName() + ")");
}
}
}
protected boolean isVisible(JvmFeature feature, JvmDeclaredType contextType) {
return visibilityService.isVisible(feature, contextType);
}
protected IScope createConstructorCallScope(final EObject context, EReference reference) {
final IScope scope = super.getScope(context, reference);
return new IScope() {
public Iterable getAllElements() {
Iterable original = scope.getAllElements();
return createFeatureDescriptions(original);
}
protected Iterable createFeatureDescriptions(Iterable original) {
Iterable result = transform(original,
new Function() {
public IEObjectDescription apply(IEObjectDescription from) {
JvmConstructor constructor = (JvmConstructor) from.getEObjectOrProxy();
if (constructor.eIsProxy()) {
EObject resolved = EcoreUtil.resolve(constructor, context);
if (resolved instanceof JvmConstructor)
constructor = (JvmConstructor) resolved;
}
XConstructorCall constructorCall = null;
if (context instanceof XConstructorCall)
constructorCall = (XConstructorCall) context;
ITypeArgumentContext typeArgumentContext = typeProvider.getTypeArgumentContext(constructorCall, constructor);
JvmDeclaredType contextType = getContextType(constructorCall);
JvmFeatureDescription result = new JvmFeatureDescription(
from.getQualifiedName(),
constructor,
typeArgumentContext,
constructor.getIdentifier(),
isVisible(constructor, contextType),
true,
null,
null,
0);
result.setGenericTypeContext(typeArgumentContext);
return result;
}
});
return result;
}
public Iterable getElements(EObject object) {
Iterable original = scope.getElements(object);
return createFeatureDescriptions(original);
}
public Iterable getElements(QualifiedName name) {
Iterable original = scope.getElements(name);
return createFeatureDescriptions(original);
}
public IEObjectDescription getSingleElement(EObject object) {
Iterable elements = getElements(object);
return (isEmpty(elements)) ? null : elements.iterator().next();
}
public IEObjectDescription getSingleElement(QualifiedName name) {
throw new UnsupportedOperationException();
}
};
}
protected boolean isConstructorCallScope(EReference reference) {
return reference.getEReferenceType() == TypesPackage.Literals.JVM_CONSTRUCTOR;
}
public boolean isFeatureCallScope(EReference reference) {
return reference == XbasePackage.Literals.XABSTRACT_FEATURE_CALL__FEATURE;
}
/**
* creates the feature scope for {@link XAbstractFeatureCall}, including the local variables in case it is a feature
* call without receiver (XFeatureCall).
*/
protected IScope createFeatureCallScope(final XAbstractFeatureCall call, EReference reference) {
if (call instanceof XFeatureCall
|| ((call instanceof XAssignment) && ((XAssignment) call).getAssignable() == null)) {
IScope result = createSimpleFeatureCallScope(call, reference, call.eResource(), false, -1);
return result;
}
final XExpression syntacticalReceiver = getSyntacticalReceiver(call);
IScope result = createFeatureCallScopeForReceiver(call, syntacticalReceiver, reference);
return result;
}
/**
* This method serves as an entry point for the content assist scoping for simple feature calls.
* @param context the context e.g. a for loop expression, a block or a catch clause
* @param reference the reference who's value shall be scoped. Not necessarily a feature of the context.
* @param includeCurrentBlock false
in the context of scoping but content assist will not have the
* actual value holder of the reference at hand so it passes its container to this method and expects the
* declared variables to be exposed in the scope.
* @param idx the index in an expression list of a block. Otherwise to be ignored.
*/
public IScope createSimpleFeatureCallScope(EObject context, EReference reference, Resource resource, boolean includeCurrentBlock, int idx) {
if (context instanceof XFeatureCall) {
XFeatureCall featureCall = (XFeatureCall) context;
if (featureCall.getDeclaringType() != null) {
JvmTypeReference typeReference = typeReferences.createTypeRef(featureCall.getDeclaringType());
JvmFeatureScopeAcceptor featureScopeDescriptions = new JvmFeatureScopeAcceptor();
IAcceptor curried = featureScopeDescriptions.curry(typeReference, featureCall);
addFeatureDescriptionProviders(getContextType(featureCall), null, null, null, getDefaultPriority(), true, curried);
IScope result = featureScopeDescriptions.createScope(IScope.NULLSCOPE);
return result;
}
}
DelegatingScope implicitFeaturesAndStatics = new DelegatingScope(IScope.NULLSCOPE);
LocalVariableScopeContext scopeContext = createLocalVariableScopeContext(context, reference, includeCurrentBlock, idx);
IScope localVariableScope = createLocalVarScope(implicitFeaturesAndStatics, scopeContext);
IScope scopeForImplicitFeatures = createImplicitFeatureCallScope(context, resource, IScope.NULLSCOPE, localVariableScope);
implicitFeaturesAndStatics.setDelegate(scopeForImplicitFeatures);
return localVariableScope;
}
/**
* @param declaringType the type that declares the feature
* @param implicitReceiver the instance that will receive the message.
* @param expression the expression that is closest to the to-be-created scope. Usually the feature call.
*/
protected IScope createFeatureScopeForTypeRef(
JvmTypeReference declaringType,
EObject expression,
XExpression implicitReceiver,
IScope parent) {
JvmFeatureScopeAcceptor featureScopeDescriptions = new JvmFeatureScopeAcceptor();
addFeatureScopes(declaringType, expression, getContextType(expression), implicitReceiver, null, getDefaultPriority(), featureScopeDescriptions);
IScope result = featureScopeDescriptions.createScope(parent);
return result;
}
protected LocalVariableScopeContext createLocalVariableScopeContext(final EObject context, EReference reference,
boolean includeCurrentBlock, int idx) {
return new LocalVariableScopeContext(context, reference, includeCurrentBlock, idx, false, logicalContainerProvider);
}
/**
* This method serves as an entry point for the content assist scoping for features.
* @param context the context provides access to the resource set. If it is an assignment, it
* will be used to restrict scoping.
* @param receiver the receiver of the feature call.
*/
public IScope createFeatureCallScopeForReceiver(final XExpression context, final XExpression receiver, EReference reference) {
if (!isFeatureCallScope(reference))
return IScope.NULLSCOPE;
if (receiver == null || receiver.eIsProxy())
return IScope.NULLSCOPE;
JvmTypeReference receiverType = typeProvider.getType(receiver,true);
if (context instanceof XNullLiteral)
receiverType = unkownToObject(receiverType, receiver);
if (receiverType != null) {
return createFeatureScopeForTypeRef(receiverType, context, null, IScope.NULLSCOPE);
} else {
return IScope.NULLSCOPE;
}
}
protected XExpression getSyntacticalReceiver(final XAbstractFeatureCall call) {
if (call instanceof XMemberFeatureCall) {
return ((XMemberFeatureCall) call).getMemberCallTarget();
}
if (call instanceof XBinaryOperation) {
return ((XBinaryOperation) call).getLeftOperand();
}
if (call instanceof XUnaryOperation) {
return ((XUnaryOperation) call).getOperand();
}
if (call instanceof XAssignment) {
return ((XAssignment) call).getAssignable();
}
return null;
}
/**
* override to add any other implicit feature calls.
*/
protected IScope createImplicitFeatureCallScope(EObject call, Resource resource, IScope parent, IScope localVariableScope) {
JvmFeatureScopeAcceptor featureScopeDescriptions = new JvmFeatureScopeAcceptor();
addFeatureCallScopes(call, localVariableScope, featureScopeDescriptions);
JvmDeclaredType contextType = getContextType(call);
IAcceptor acceptorWithoutContext = featureScopeDescriptions.curry(null, call);
addStaticFeatureDescriptionProviders(resource, contextType, acceptorWithoutContext);
if (contextType != null) {
IAcceptor acceptorWithContext = featureScopeDescriptions.curry(typeReferences.createTypeRef(contextType), call);
addFeatureDescriptionProviders(contextType, null, null, null, getImplicitStaticFeaturePriority(), true, acceptorWithContext);
}
IScope result = featureScopeDescriptions.createScope(parent);
return result;
}
protected void addFeatureCallScopes(EObject featureCall, IScope localVariableScope,
IJvmFeatureScopeAcceptor featureScopeDescriptions) {
addFeatureCallScopes(featureCall, localVariableScope, THIS, getThisPriority(), featureScopeDescriptions);
addFeatureCallScopes(featureCall, localVariableScope, IT, getItPriority(), featureScopeDescriptions);
JvmIdentifiableElement logicalContainer = logicalContainerProvider.getNearestLogicalContainer(featureCall);
if (logicalContainer instanceof JvmConstructor) {
JvmConstructor constructor = (JvmConstructor) logicalContainer;
JvmDeclaredType contextType = constructor.getDeclaringType();
JvmTypeReference receiverType = typeReferences.createTypeRef(contextType);
IAcceptor acceptor = featureScopeDescriptions.curry(receiverType, featureCall);
DefaultConstructorDescriptionProvider defaultProvider = newDefaultConstructorDescriptionProvider();
XConstructorProvider featureProvider = newConstructorProvider();
defaultProvider.setContextType(contextType);
defaultProvider.setPriority(getDefaultPriority());
defaultProvider.setFeaturesForTypeProvider(featureProvider);
acceptor.accept(defaultProvider);
}
}
protected void addFeatureCallScopes(
EObject expression,
IScope localVariableScope,
QualifiedName variableName,
int priority,
IJvmFeatureScopeAcceptor featureScopeDescriptions) {
IEObjectDescription implicitVariable = localVariableScope.getSingleElement(variableName);
if (implicitVariable != null) {
EObject implicitReceiver = implicitVariable.getEObjectOrProxy();
if (implicitReceiver instanceof JvmIdentifiableElement) {
IResolvedTypes resolvedTypes = batchTypeResolver.getResolvedTypesInContextOf(expression);
LightweightTypeReference lightweightReceiverType = resolvedTypes.getActualType((JvmIdentifiableElement) implicitReceiver);
JvmTypeReference receiverType = null;
if (lightweightReceiverType != null) {
receiverType = lightweightReceiverType.toTypeReference();
} else {
receiverType = typeProvider.getTypeForIdentifiable((JvmIdentifiableElement) implicitReceiver);
}
receiverType = unkownToObject(receiverType, expression);
if (receiverType != null) {
XFeatureCall receiver = XbaseFactory.eINSTANCE.createXFeatureCall();
receiver.setFeature((JvmIdentifiableElement) implicitReceiver);
addFeatureScopes(receiverType, expression, getContextType(expression), receiver, null, priority, featureScopeDescriptions);
}
}
}
}
protected JvmTypeReference unkownToObject(JvmTypeReference receiverType, EObject context) {
if (receiverType instanceof JvmUnknownTypeReference) {
return typeReferences.getTypeForName(Object.class, context);
}
if (receiverType instanceof JvmAnyTypeReference && receiverType.getType() != null && receiverType.getType().eIsProxy()) {
EObject resolved = EcoreUtil.resolve(receiverType.getType(), context);
((JvmAnyTypeReference) receiverType).setType((JvmType) resolved);
}
return receiverType;
}
protected JvmDeclaredType getContextType(EObject obj) {
if (obj == null)
return null;
if (obj instanceof JvmDeclaredType) {
return (JvmDeclaredType) obj;
}
if (obj instanceof XExpression) {
JvmIdentifiableElement element = logicalContainerProvider.getLogicalContainer(obj);
if (element != null) {
if (element instanceof JvmDeclaredType) {
return (JvmDeclaredType) element;
} else if (element instanceof JvmMember) {
return ((JvmMember) element).getDeclaringType();
}
}
}
return getContextType(obj.eContainer());
}
/**
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface LocalVariableAcceptor {
void accept(String description, IValidatedEObjectDescription object);
void accept(String description, List extends IValidatedEObjectDescription> objects);
}
protected IScope createLocalVarScope(final IScope parentScope, LocalVariableScopeContext scopeContext) {
if (scopeContext == null || scopeContext.getContext() == null)
return parentScope;
class ScopeBuilder implements LocalVariableAcceptor {
IScope scope = parentScope;
public void accept(String description, IValidatedEObjectDescription object) {
if (object != null)
accept(description, Collections.singletonList(object));
}
public void accept(String description, List extends IValidatedEObjectDescription> objects) {
if (!objects.isEmpty())
scope = new JvmFeatureScope(scope, description, objects);
}
}
ScopeBuilder builder = new ScopeBuilder();
createLocalVarScope(builder, scopeContext);
return builder.scope;
}
protected void createLocalVarScope(LocalVariableAcceptor acceptor, LocalVariableScopeContext scopeContext) {
EObject context = scopeContext.getContext();
if (context instanceof JvmOperation) {
JvmOperation jvmOperation = (JvmOperation) context;
if (jvmOperation.getDeclaringType() != null) {
JvmDeclaredType declaredType = jvmOperation.getDeclaringType();
if (!jvmOperation.isStatic()) {
createLocalVarScopeForJvmDeclaredType(declaredType, acceptor);
}
}
createLocalVarScopeForJvmOperation((JvmOperation)context, acceptor);
return;
}
if (context instanceof JvmConstructor) {
JvmConstructor constructor = (JvmConstructor) context;
if (constructor.getDeclaringType() != null) {
JvmDeclaredType declaredType = constructor.getDeclaringType();
createLocalVarScopeForJvmDeclaredType(declaredType, acceptor);
}
createLocalVarScopeForJvmConstructor((JvmConstructor)context, acceptor);
return;
}
if (context instanceof JvmField) {
JvmField field = (JvmField) context;
if (field.getDeclaringType() != null) {
JvmDeclaredType declaredType = field.getDeclaringType();
if (!field.isStatic()) {
createLocalVarScopeForJvmDeclaredType(declaredType, acceptor);
}
}
return;
}
if(context instanceof JvmDeclaredType) {
createLocalVarScopeForJvmDeclaredType((JvmDeclaredType) context, acceptor);
return;
}
if (scopeContext.canSpawnForContainer())
createLocalVarScope(acceptor, scopeContext.spawnForContainer());
if (context.eContainer() instanceof XBlockExpression) {
XBlockExpression block = (XBlockExpression) context.eContainer();
createLocalVarScopeForBlock(block, block.getExpressions().indexOf(context), scopeContext.isReferredFromClosure(), acceptor);
}
if (context.eContainer() instanceof XForLoopExpression && context.eContainingFeature() == XbasePackage.Literals.XFOR_LOOP_EXPRESSION__EACH_EXPRESSION) {
XForLoopExpression loop = (XForLoopExpression) context.eContainer();
createLocalScopeForParameter(loop.getDeclaredParam(), acceptor);
}
if (context.eContainer() instanceof XCatchClause) {
XCatchClause catchClause = (XCatchClause) context.eContainer();
createLocalScopeForParameter(catchClause.getDeclaredParam(), acceptor);
}
if (context instanceof XClosure) {
createLocalVarScopeForClosure((XClosure) context, acceptor);
}
if (context instanceof XCasePart) {
createLocalVarScopeForTypeGuardedCase((XCasePart) context, acceptor);
}
if (context instanceof XSwitchExpression) {
createLocalVarScopeForSwitchExpression((XSwitchExpression) context, acceptor);
}
if (scopeContext.isIncludeCurrentBlock()) {
if (context instanceof XBlockExpression) {
XBlockExpression block = (XBlockExpression) context;
if (!block.getExpressions().isEmpty()) {
createLocalVarScopeForBlock(block, scopeContext.getIndex(), scopeContext.isReferredFromClosure(), acceptor);
}
}
if (context instanceof XForLoopExpression) {
createLocalScopeForParameter(((XForLoopExpression) context).getDeclaredParam(), acceptor);
}
if (context instanceof XCatchClause) {
createLocalScopeForParameter(((XCatchClause) context).getDeclaredParam(), acceptor);
}
}
}
protected void createLocalVarScopeForJvmOperation(JvmOperation context, LocalVariableAcceptor acceptor) {
List parameters = context.getParameters();
if (parameters.isEmpty())
return;
List descriptions = newArrayList();
for (JvmFormalParameter p : parameters) {
if (p.getName() != null)
descriptions.add(new LocalVarDescription(QualifiedName.create(p.getName()), p));
}
acceptor.accept("operation "+context.getSimpleName(), descriptions);
}
protected void createLocalVarScopeForJvmConstructor(JvmConstructor context, LocalVariableAcceptor acceptor) {
List parameters = context.getParameters();
if (parameters.isEmpty())
return;
List descriptions = newArrayList();
for (JvmFormalParameter p : parameters) {
if (p.getName() != null)
descriptions.add(new LocalVarDescription(QualifiedName.create(p.getName()), p));
}
acceptor.accept("constructor "+context.getSimpleName(), descriptions);
}
protected void createLocalVarScopeForJvmDeclaredType(JvmDeclaredType type, LocalVariableAcceptor acceptor) {
Iterator classes = filter(type.getSuperTypes(), new Predicate() {
public boolean apply(JvmTypeReference input) {
if (input.getType() instanceof JvmGenericType) {
return !((JvmGenericType)input.getType()).isInterface();
}
return false;
}
}).iterator();
JvmGenericType superType = null;
if (classes.hasNext()) {
superType = (JvmGenericType) classes.next().getType();
}
if (superType == null) {
acceptor.accept("this", new LocalVarDescription(THIS, type));
} else {
acceptor.accept("this & super", newArrayList(
new LocalVarDescription(THIS, type),
new LocalVarDescription(SUPER, superType)));
}
}
protected boolean adaptsToJvmElement(EObject context) {
if (context instanceof XExpression) {
return logicalContainerProvider.getLogicalContainer(context) != null;
}
return false;
}
protected void createLocalVarScopeForSwitchExpression(XSwitchExpression context, LocalVariableAcceptor acceptor) {
if (context.getLocalVarName() != null) {
acceptor.accept("XSwitchExpression",
new LocalVarDescription(QualifiedName.create(context.getLocalVarName()), context));
}
}
/**
* Allows to hook into the case guards to introduce new local variables with a specialized type.
* Implemented as no-op by default.
* @param context the case part.
* @param acceptor the acceptor.
*/
protected void createLocalVarScopeForTypeGuardedCase(XCasePart context, LocalVariableAcceptor acceptor) {
}
/**
* Allows to hook into the local variable definition for catch clauses.
* @param catchClause the catch clause.
* @param indexOfContextExpressionInBlock the index of the context expression in its surrounding block.
* @param acceptor the the acceptor.
*/
protected void createLocalVarScopeForCatchClause(XCatchClause catchClause, int indexOfContextExpressionInBlock,
LocalVariableAcceptor acceptor) {
createLocalScopeForParameter(catchClause.getDeclaredParam(), acceptor);
}
protected void createLocalVarScopeForBlock(
XBlockExpression block, int indexOfContextExpressionInBlock,
boolean referredFromClosure, LocalVariableAcceptor acceptor) {
List descriptions = Lists.newArrayList();
for (int i = 0; i < indexOfContextExpressionInBlock; i++) {
XExpression expression = block.getExpressions().get(i);
if (expression instanceof XVariableDeclaration) {
XVariableDeclaration varDecl = (XVariableDeclaration) expression;
if (varDecl.getName() != null) {
IValidatedEObjectDescription desc = createLocalVarDescription(varDecl);
if (referredFromClosure && varDecl.isWriteable())
desc.setIssueCode(IssueCodes.INVALID_MUTABLE_VARIABLE_ACCESS);
descriptions.add(desc);
}
}
}
if (descriptions.isEmpty())
return;
acceptor.accept("XBlockExpression", descriptions);
}
protected void createLocalVarScopeForClosure(XClosure closure, LocalVariableAcceptor acceptor) {
List descriptions = Lists.newArrayList();
EList params = closure.getFormalParameters();
for (JvmFormalParameter p : params) {
if (p.getName() != null) {
IValidatedEObjectDescription desc = createLocalVarDescription(p);
descriptions.add(desc);
}
}
acceptor.accept("XClosure", descriptions);
}
public interface IJvmFeatureScopeAcceptor {
void acceptScope(
JvmTypeReference featureDeclarator,
Function contextFactory,
IJvmFeatureDescriptionProvider provider);
IAcceptor curry(
JvmTypeReference featureDeclarator,
EObject expression);
}
protected abstract class AbstractJvmFeatureScopeAcceptor implements IJvmFeatureScopeAcceptor {
public IAcceptor curry(
JvmTypeReference featureDeclarator,
EObject expression) {
return new SimpleAcceptor(this, featureDeclarator, expression);
}
}
protected class SimpleAcceptor implements IAcceptor {
private final Function contextFactory;
private final IJvmFeatureScopeAcceptor parent;
private final JvmTypeReference receiverType;
private final EObject expression;
protected SimpleAcceptor(
IJvmFeatureScopeAcceptor parent,
JvmTypeReference receiverType,
EObject expression) {
this.parent = parent;
this.receiverType = receiverType;
this.expression = expression;
this.contextFactory = new GenericTypeArgumentContextFactory(receiverType, expression);
}
public void accept(IJvmFeatureDescriptionProvider provider) {
parent.acceptScope(receiverType, contextFactory, provider);
}
public IJvmFeatureScopeAcceptor getParent() {
return parent;
}
public EObject getExpression() {
return expression;
}
public JvmTypeReference getReceiverType() {
return receiverType;
}
}
protected class JvmFeatureScopeAcceptor extends AbstractJvmFeatureScopeAcceptor {
private final List descriptions;
public JvmFeatureScopeAcceptor() {
this.descriptions = Lists.newArrayList();
}
public void acceptScope(
JvmTypeReference featureDeclarator,
Function contextFactory,
IJvmFeatureDescriptionProvider provider) {
descriptions.add(new IJvmFeatureScopeProvider.FeatureScopeDescription(featureDeclarator, contextFactory, provider));
}
public IScope createScope(IScope parent) {
if (descriptions.isEmpty())
return parent;
sortDescriptionsFromLowestToHighest(descriptions);
IScope result = jvmFeatureScopeProvider.createFeatureScope(parent, descriptions);
return result;
}
}
protected void sortDescriptionsFromLowestToHighest(List list) {
Collections.sort(list, new Comparator() {
public int compare(FeatureScopeDescription o1, FeatureScopeDescription o2) {
int prio1 = o1.getDescriptionProvider().getPriority();
int prio2 = o2.getDescriptionProvider().getPriority();
if (prio1 < prio2)
return 1;
if (prio1 > prio2)
return -1;
return 0;
}
});
if (log.isDebugEnabled()) {
log.debug("sortedDescriptionsFromLowestToHighest:\n" + Joiner.on('\n').join(list));
}
}
protected class GenericTypeArgumentContextFactory implements Function {
private final EObject expression;
private final JvmTypeReference receiverType;
public GenericTypeArgumentContextFactory(JvmTypeReference receiverType, EObject expression) {
this.receiverType = receiverType;
this.expression = expression;
}
public ITypeArgumentContext apply(JvmFeatureDescription from) {
JvmIdentifiableElement feature = from.getEObjectOrProxy();
if (feature instanceof JvmExecutable && expression instanceof XAbstractFeatureCall) {
XAbstractFeatureCall featureCall = (XAbstractFeatureCall) expression;
List arguments = featureCallToJavaMapping.getActualArguments(
featureCall, feature,
from.getImplicitReceiver(),
from.getImplicitArgument());
ITypeArgumentContext result = typeProvider.getTypeArgumentContext(
featureCall,
arguments,
receiverType != null ? Providers.of(receiverType) : null,
feature);
return result;
}
return null;
}
}
protected void addFeatureScopes(
JvmTypeReference receiverType,
EObject expression,
JvmDeclaredType contextType,
XExpression implicitReceiver,
XExpression implicitArgument,
int priority,
IJvmFeatureScopeAcceptor acceptor) {
IAcceptor curried = acceptor.curry(receiverType, expression);
if (expression instanceof XAssignment) {
addFeatureDescriptionProvidersForAssignment(expression.eResource(), contextType, implicitReceiver, implicitArgument, priority, curried);
} else {
addFeatureDescriptionProviders(expression.eResource(), contextType, implicitReceiver, implicitArgument, priority, curried);
}
}
protected void addStaticFeatureDescriptionProviders(
Resource resource,
JvmDeclaredType contextType,
IAcceptor acceptor) {
StaticImplicitMethodsFeatureForTypeProvider implicitMethodsProvider = newImplicitStaticFeaturesProvider();
implicitMethodsProvider.setResourceContext(resource);
addFeatureDescriptionProviders(contextType, implicitMethodsProvider, null, null, getImplicitStaticFeaturePriority(), true, acceptor);
}
protected int getThisPriority() {
return DEFAULT_THIS_PRIORITY;
}
protected int getDefaultPriority() {
return DEFAULT_MEMBER_CALL_PRIORITY;
}
protected int getItPriority() {
return DEFAULT_IT_PRIORITY;
}
protected int getSugarPriorityOffset() {
return DEFAULT_SUGAR_PRIORITY_OFFSET;
}
protected int getImplicitStaticExtensionPriorityOffset() {
return DEFAULT_STATIC_EXTENSION_PRIORITY_OFFSET;
}
protected int getImplicitStaticFeaturePriority() {
return DEFAULT_IMPLICIT_STATIC_FEATURE_PRIORITY;
}
protected void addFeatureDescriptionProviders(
JvmDeclaredType contextType,
IFeaturesForTypeProvider featureProvider,
XExpression implicitReceiver,
XExpression implicitArgument,
int priority,
boolean preferStatics,
IAcceptor acceptor) {
DefaultJvmFeatureDescriptionProvider defaultProvider = newDefaultFeatureDescriptionProvider();
defaultProvider.setContextType(contextType);
defaultProvider.setPriority(priority);
if (featureProvider != null)
defaultProvider.setFeaturesForTypeProvider(featureProvider);
defaultProvider.setImplicitReceiver(implicitReceiver);
defaultProvider.setImplicitArgument(implicitArgument);
defaultProvider.setPreferStatics(preferStatics);
acceptor.accept(defaultProvider);
XFeatureCallSugarDescriptionProvider sugarProvider = newSugarDescriptionProvider();
sugarProvider.setContextType(contextType);
sugarProvider.setPriority(priority + getSugarPriorityOffset());
if (featureProvider != null)
sugarProvider.setFeaturesForTypeProvider(featureProvider);
sugarProvider.setImplicitReceiver(implicitReceiver);
sugarProvider.setImplicitArgument(implicitArgument);
sugarProvider.setPreferStatics(preferStatics);
acceptor.accept(sugarProvider);
}
protected void addFeatureDescriptionProviders(
Resource resource,
JvmDeclaredType contextType,
XExpression implicitReceiver,
XExpression implicitArgument,
int priority,
IAcceptor acceptor) {
addFeatureDescriptionProviders(contextType, null, implicitReceiver, implicitArgument, priority, false, acceptor);
if (implicitArgument == null) {
StaticImplicitMethodsFeatureForTypeProvider implicitStaticFeatures = newImplicitStaticFeaturesProvider();
implicitStaticFeatures.setResourceContext(resource);
implicitStaticFeatures.setExtensionProvider(true);
addFeatureDescriptionProviders(contextType, implicitStaticFeatures, implicitReceiver, implicitArgument, priority + getImplicitStaticExtensionPriorityOffset(), true, acceptor);
}
}
protected StaticImplicitMethodsFeatureForTypeProvider newImplicitStaticFeaturesProvider() {
return implicitStaticFeatures.get();
}
/**
* @param resource the resource which may define implicitly available feature description providers.
*/
protected void addFeatureDescriptionProvidersForAssignment(
Resource resource,
JvmDeclaredType contextType,
XExpression implicitReceiver,
XExpression implicitArgument,
int priority,
IAcceptor acceptor) {
addFeatureDescriptionProvidersForAssignment(contextType, null, implicitReceiver, implicitArgument, priority, false, acceptor);
}
protected void addFeatureDescriptionProvidersForAssignment(
JvmDeclaredType contextType,
IFeaturesForTypeProvider featureProvider,
XExpression implicitReceiver,
XExpression implicitArgument,
int priority,
boolean preferStatics,
IAcceptor acceptor) {
XAssignmentDescriptionProvider assignmentProvider = assignmentFeatureDescProvider.get();
assignmentProvider.setContextType(contextType);
if (featureProvider != null)
assignmentProvider.setFeaturesForTypeProvider(featureProvider);
assignmentProvider.setImplicitReceiver(implicitReceiver);
assignmentProvider.setImplicitArgument(implicitArgument);
assignmentProvider.setPriority(priority);
assignmentProvider.setPreferStatics(preferStatics);
acceptor.accept(assignmentProvider);
XAssignmentSugarDescriptionProvider sugarProvider = assignmentSugarFeatureDescProvider.get();
sugarProvider.setContextType(contextType);
if (featureProvider != null)
sugarProvider.setFeaturesForTypeProvider(featureProvider);
sugarProvider.setImplicitReceiver(implicitReceiver);
sugarProvider.setImplicitArgument(implicitArgument);
sugarProvider.setPriority(getSugarPriorityOffset() + priority);
sugarProvider.setPreferStatics(preferStatics);
acceptor.accept(sugarProvider);
}
protected void createLocalScopeForParameter(JvmFormalParameter p, LocalVariableAcceptor acceptor) {
if (p.getName() != null)
acceptor.accept("JvmFormalParameter", createLocalVarDescription(p));
}
protected IValidatedEObjectDescription createLocalVarDescription(JvmFormalParameter p) {
return new LocalVarDescription(QualifiedName.create(p.getName()), p);
}
protected IValidatedEObjectDescription createLocalVarDescription(XVariableDeclaration varDecl) {
return new LocalVarDescription(QualifiedName.create(varDecl.getName()), varDecl);
}
protected DefaultJvmFeatureDescriptionProvider newDefaultFeatureDescriptionProvider() {
return defaultFeatureDescProvider.get();
}
protected DefaultConstructorDescriptionProvider newDefaultConstructorDescriptionProvider() {
return defaultConstructorDescProvider.get();
}
protected XConstructorProvider newConstructorProvider() {
return constructorProvider.get();
}
protected XFeatureCallSugarDescriptionProvider newSugarDescriptionProvider() {
return sugarFeatureDescProvider.get();
}
protected FeatureCallToJavaMapping getFeatureCallToJavaMapping() {
return featureCallToJavaMapping;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy