/** * Copyright (c) 2012 committers of YAKINDU 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 * * Contributors: * Andreas Mülder (itemis AG) * Axel Terfloth (itemis AG) */ package org.yakindu.sct.model.stext.scoping; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.emf.common.util.EList; 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.resource.IEObjectDescription; import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.scoping.Scopes; import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; import org.eclipse.xtext.scoping.impl.FilteringScope; import org.eclipse.xtext.scoping.impl.SimpleScope; import org.eclipse.xtext.util.PolymorphicDispatcher.ErrorHandler; import org.yakindu.base.expressions.expressions.ElementReferenceExpression; import org.yakindu.base.expressions.expressions.Expression; import org.yakindu.base.expressions.expressions.FeatureCall; import org.yakindu.base.types.ComplexType; import org.yakindu.base.types.EnumerationType; import org.yakindu.base.types.Type; import org.yakindu.base.types.inferrer.ITypeSystemInferrer; import org.yakindu.base.types.inferrer.ITypeSystemInferrer.InferenceResult; import org.yakindu.base.types.typesystem.ITypeSystem; import org.yakindu.sct.model.sgraph.SGraphPackage; import org.yakindu.sct.model.sgraph.Scope; import org.yakindu.sct.model.sgraph.Statechart; import org.yakindu.sct.model.sgraph.util.ContextElementAdapter; import org.yakindu.sct.model.stext.scoping.ContextPredicateProvider.EmptyPredicate; import org.yakindu.sct.model.stext.stext.InterfaceScope; import org.yakindu.sct.model.stext.stext.InternalScope; import com.google.common.base.Predicate; import com.google.common.collect.Lists; import com.google.inject.Inject; /** * * @author andreas muelder * @author axel terfloth * @author alexander nyssen Added support for scoping of enumeration literals * */ public class STextScopeProvider extends AbstractDeclarativeScopeProvider { @Inject private ITypeSystemInferrer typeInferrer; @Inject private ITypeSystem typeSystem; private static class ErrorHandlerDelegate<T> implements ErrorHandler<T> { private ErrorHandler<T> delegate; public static final Log LOG = LogFactory.getLog(STextScopeProvider.class); public ErrorHandlerDelegate(ErrorHandler<T> delegate) { this.delegate = delegate; } public T handle(Object[] params, Throwable throwable) { if (throwable instanceof NoSuchMethodException) { LOG.debug("Error in scope method, using fallback", throwable); } else { LOG.warn("Error in scope method, using fallback", throwable); } return delegate.handle(params, throwable); } } @Override public IScope getScope(EObject context, EReference reference) { try { ErrorHandler<IScope> originalHandler = getErrorHandler(); setErrorHandler(new ErrorHandlerDelegate<IScope>(originalHandler)); IScope scope = super.getScope(context, reference); setErrorHandler(originalHandler); return scope; } catch (Throwable t) { t.printStackTrace(); return null; } } @Inject private ContextPredicateProvider predicateProvider; /** * Scoping for types and taking imported namespaces into account e.g. in * variable declarations. */ public IScope scope_TypeSpecifier_type(final EObject context, EReference reference) { IScope scope = getDelegate().getScope(context, reference); Predicate<IEObjectDescription> predicate = calculateFilterPredicate(context, reference); return new FilteringScope(scope, predicate); } public IScope scope_ElementReferenceExpression_reference(final EObject context, EReference reference) { IScope namedScope = getNamedTopLevelScope(context, reference); IScope unnamedScope = getUnnamedTopLevelScope(context, reference); Predicate<IEObjectDescription> predicate = calculateFilterPredicate(context, reference); unnamedScope = new FilteringScope(unnamedScope, predicate); return new SimpleScope(unnamedScope, namedScope.getAllElements()); } public IScope scope_FeatureCall_feature(final FeatureCall context, EReference reference) { Predicate<IEObjectDescription> predicate = calculateFilterPredicate(context, reference); Expression owner = context.getOwner(); EObject element = null; if (owner instanceof ElementReferenceExpression) { element = ((ElementReferenceExpression) owner).getReference(); } else if (owner instanceof FeatureCall) { element = ((FeatureCall) owner).getFeature(); } else { return getDelegate().getScope(context, reference); } IScope scope = IScope.NULLSCOPE; InferenceResult result = typeInferrer.infer(owner); Type ownerType = result != null ? result.getType() : null; if (element instanceof Scope) { scope = Scopes.scopeFor(((Scope) element).getDeclarations()); return new FilteringScope(scope, predicate); }else if(ownerType != null){ scope = Scopes.scopeFor(typeSystem.getPropertyExtensions(ownerType)); scope = Scopes.scopeFor(typeSystem.getOperationExtensions(ownerType),scope); } if (ownerType instanceof ComplexType) { return addScopeForComplexType((ComplexType) ownerType, scope, predicate); } if (ownerType instanceof EnumerationType) { return addScopeForEnumType((EnumerationType) ownerType, scope, predicate); } return scope; } protected IScope addScopeForEnumType(EnumerationType element, IScope scope, final Predicate<IEObjectDescription> predicate) { scope = Scopes.scopeFor((element).getEnumerator(), scope); scope = new FilteringScope(scope, predicate); return scope; } protected IScope addScopeForComplexType(final ComplexType type, IScope scope, final Predicate<IEObjectDescription> predicate) { scope = Scopes.scopeFor(type.getAllFeatures(), scope); scope = new FilteringScope(scope, predicate); return scope; } private Predicate<IEObjectDescription> calculateFilterPredicate(final EObject context, final EReference reference) { Predicate<IEObjectDescription> predicate = null; EObject container = context; EReference ref = reference; while (container != null) { predicate = predicateProvider.getPredicate(container.eClass(), ref); if (!(predicate instanceof EmptyPredicate)) { break; } ref = (EReference) container.eContainingFeature(); container = container.eContainer(); } return predicate; } /** * Returns the toplevel scope */ protected IScope getNamedTopLevelScope(final EObject context, EReference reference) { List<EObject> scopeCandidates = Lists.newArrayList(); Statechart statechart = getStatechart(context); if (statechart == null) return IScope.NULLSCOPE; EList<Scope> scopes = statechart.getScopes(); for (Scope scope : scopes) { if (scope instanceof InterfaceScope) { String name = ((InterfaceScope) scope).getName(); if (name != null && name.trim().length() > 0) { scopeCandidates.add(scope); } } } return Scopes.scopeFor(scopeCandidates); } /** * Returns a scope with all toplevel declarations of unnamed scope */ protected IScope getUnnamedTopLevelScope(final EObject context, EReference reference) { List<EObject> scopeCandidates = Lists.newArrayList(); Statechart statechart = getStatechart(context); if (statechart == null) return IScope.NULLSCOPE; EList<Scope> scopes = statechart.getScopes(); for (Scope scope : scopes) { if (scope instanceof InterfaceScope) { String name = ((InterfaceScope) scope).getName(); if (name == null || name.trim().length() == 0) { scopeCandidates.addAll(scope.getDeclarations()); } } else if (scope instanceof InternalScope) { scopeCandidates.addAll(scope.getDeclarations()); } } // Add import scope IScope scope = getDelegate().getScope(context, reference); return Scopes.scopeFor(scopeCandidates, scope); } /** * Returns the {@link Statechart} for a context element */ protected Statechart getStatechart(EObject context) { final ContextElementAdapter provider = (ContextElementAdapter) EcoreUtil.getExistingAdapter(context.eResource(), ContextElementAdapter.class); if (provider == null) { return EcoreUtil2.getContainerOfType(context, Statechart.class); } else { return (Statechart) EcoreUtil.getObjectByType(provider.getElement().eResource().getContents(), SGraphPackage.Literals.STATECHART); } } }