/******************************************************************************* * Copyright (c) 2010-2012, Zoltan Ujhelyi, Istvan Rath and Daniel Varro * 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: * Zoltan Ujhelyi - initial API and implementation *******************************************************************************/ package org.eclipse.incquery.patternlanguage.scoping; import java.lang.reflect.Method; import java.util.Collections; import org.apache.log4j.Logger; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.scoping.IScopeProvider; import org.eclipse.xtext.scoping.impl.AbstractScopeProvider; import org.eclipse.xtext.util.PolymorphicDispatcher; import com.google.common.base.Predicate; import com.google.inject.Inject; import com.google.inject.name.Named; /** * <p> * An extended abstract declarative scope provider to facilitate the reusing of abstract declarative scope providers * together with XBase scope provider. * </p> * <p> * See <a * href="http://www.eclipse.org/forums/index.php/mv/msg/219841/699521/#msg_699521">http://www.eclipse.org/forums/index * .php/mv/msg/219841/699521/#msg_699521</a> for details. * </p> * * @author Zoltan Ujhelyi * */ public class MyAbstractDeclarativeScopeProvider extends AbstractScopeProvider { public static final String NAMED_DELEGATE = "org.eclipse.xtext.scoping.impl.MyAbstractDeclarativeScopeProvider.delegate"; public static final String NAMED_ERROR_HANDLER = "org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider.errorHandler"; public final Logger logger = Logger.getLogger(getClass()); @Inject @Named(NAMED_DELEGATE) private IScopeProvider delegate; protected IScope delegateGetScope(EObject context, EReference reference) { return getDelegate().getScope(context, reference); } public void setDelegate(IScopeProvider delegate) { this.delegate = delegate; } public IScopeProvider getDelegate() { return delegate; } @Inject(optional = true) @Named(NAMED_ERROR_HANDLER) private PolymorphicDispatcher.ErrorHandler<IScope> errorHandler = new PolymorphicDispatcher.NullErrorHandler<IScope>(); protected Predicate<Method> getPredicate(EObject context, EClass type) { String methodName = "scope_" + type.getName(); return PolymorphicDispatcher.Predicates.forName(methodName, 2); } protected Predicate<Method> getPredicate(EObject context, EReference reference) { String methodName = "scope_" + reference.getEContainingClass().getName() + "_" + reference.getName(); return PolymorphicDispatcher.Predicates.forName(methodName, 2); } public IScope getScope(EObject context, EReference reference) { IScope scope = polymorphicFindScopeForReferenceName(context, reference); if (scope == null) { scope = polymorphicFindScopeForClassName(context, reference); if (scope == null) { scope = delegateGetScope(context, reference); } } return scope; } protected IScope polymorphicFindScopeForClassName(EObject context, EReference reference) { IScope scope = null; PolymorphicDispatcher<IScope> dispatcher = new PolymorphicDispatcher<IScope>(Collections.singletonList(this), getPredicate(context, reference.getEReferenceType()), errorHandler) { @Override protected IScope handleNoSuchMethod(Object... params) { if (PolymorphicDispatcher.NullErrorHandler.class.equals(errorHandler.getClass())) { return null; } return super.handleNoSuchMethod(params); } }; EObject current = context; while (scope == null && current != null) { scope = dispatcher.invoke(current, reference); current = current.eContainer(); } current = context; while (scope == null && current != null) { scope = dispatcher.invoke(current, reference.getEReferenceType()); if (scope != null) { logger.warn("scope_<EClass>(EObject,EClass) is deprecated. Use scope_<EClass>(EObject,EReference) instead."); } current = current.eContainer(); } return scope; } protected IScope polymorphicFindScopeForReferenceName(EObject context, EReference reference) { Predicate<Method> predicate = getPredicate(context, reference); PolymorphicDispatcher<IScope> dispatcher = new PolymorphicDispatcher<IScope>(Collections.singletonList(this), predicate, errorHandler) { @Override protected IScope handleNoSuchMethod(Object... params) { if (PolymorphicDispatcher.NullErrorHandler.class.equals(errorHandler.getClass())) { return null; } return super.handleNoSuchMethod(params); } }; EObject current = context; IScope scope = null; while (scope == null && current != null) { scope = dispatcher.invoke(current, reference); current = current.eContainer(); } return scope; } public void setErrorHandler(PolymorphicDispatcher.ErrorHandler<IScope> errorHandler) { this.errorHandler = errorHandler; } public PolymorphicDispatcher.ErrorHandler<IScope> getErrorHandler() { return errorHandler; } }