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

org.eclipse.xtext.xbase.resource.XbaseResource Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2011 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.resource;

import java.util.Map;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.xtext.common.types.JvmConstructor;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.TypesPackage;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.resource.DerivedStateAwareResource;
import org.eclipse.xtext.util.OnChangeEvictingCache;
import org.eclipse.xtext.util.Triple;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
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 com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Provider;

/**
 * @author Sven Efftinge - Initial contribution and API
 * @author Sebastian Zarnekow - Linking assumptions
 */
public class XbaseResource extends DerivedStateAwareResource {
	
	protected static class AssumptionTracker implements LinkingAssumptions.Tracker {
		private boolean independent = true;
		private final AssumptionTracker delegate;
		private final AssumptionState host;
		
		protected AssumptionTracker(AssumptionState host) {
			this.host = host;
			if (host != null) {
				this.delegate = host.assumptionTracker;
				host.assumptionTracker = this;
			} else {
				this.delegate = null;
			}
		}
		
		public boolean isIndependentOfAssumptions() {
			return independent;
		}
		
		public void stopTracking() {
			if (host.assumptionTracker != this) {
				throw new IllegalStateException("Unexpected assumption tracker");
			}
			host.assumptionTracker = delegate;
		}
		
		protected void markDependent() {
			if (independent) {
				independent = false;
				if (delegate != null) {
					delegate.markDependent();
				}
			}
		}
		
		@Override
		public String toString() {
			return "AssumptionTracker [independent=" + independent + "]";
		}
	}
	
	protected static class RootAssumptionTracker extends AssumptionTracker {
		protected RootAssumptionTracker() {
			super(null);
		}
		@Override
		public boolean isIndependentOfAssumptions() {
			return true;
		}
		@Override
		public void stopTracking() {
			throw new UnsupportedOperationException();
		}
		@Override
		protected void markDependent() {
		}
		@Override
		public String toString() {
			return "RootAssumptionTracker";
		}
	}
	
	protected static class AssumptionState {
		protected Map proxyToAssumption = Maps.newHashMap();
		protected Map featureCallToReceiverAssumption = Maps.newHashMap();
		protected Map featureCallToFirstArgumentAssumption = Maps.newHashMap();
		protected AssumptionTracker assumptionTracker = new RootAssumptionTracker();
	}
	
	@Inject
	private OnChangeEvictingCache onChangeEvictingCache;
	
	private ThreadLocal assumptionState = new ThreadLocal() {
		@Override
		protected AssumptionState initialValue() {
			return new AssumptionState();
		}
	};
	
	protected LinkingAssumptions.Tracker trackAssumptions() {
		return new AssumptionTracker(assumptionState.get());
	}
	
	protected  T assumeLinked(
			final JvmIdentifiableElement proxy, 
			final JvmIdentifiableElement candidate, 
			final XAbstractFeatureCall featureCall, 
			final XExpression implicitReceiver,
			final XExpression implicitFirstArgument,
			final Provider algorithm) {
		AssumptionState state = assumptionState.get();
		try {
			if (state.proxyToAssumption.put(proxy, candidate) != null)
				throw new AssertionError("There is already another assumption about the given proxy. " +
						"Please make sure that you don't use XAbstractFeatureCall#getFeature in the type inference or " +
						"in your scoping implementation but AbstractTypeProvider#getFeature instead.\n" +
						"You may want to look out for invocations of XAbstractFeatureCall#getFeature in the " +
						"stack trace to spot the misbehaving implementation.");
			if (featureCall != null) {
				state.featureCallToReceiverAssumption.put(featureCall, implicitReceiver);
				state.featureCallToFirstArgumentAssumption.put(featureCall, implicitFirstArgument);
			}
			return algorithm.get();
		} finally {
			state.proxyToAssumption.remove(proxy);
			state.featureCallToFirstArgumentAssumption.remove(featureCall);
			state.featureCallToReceiverAssumption.remove(featureCall);
		}
	}
	
	protected XExpression getImplicitReceiver(XAbstractFeatureCall featureCall) {
		AssumptionState state = assumptionState.get();
		XExpression result = state.featureCallToReceiverAssumption.get(featureCall);
		if (result == null) {
			if (state.featureCallToReceiverAssumption.containsKey(featureCall)) {
				state.assumptionTracker.markDependent();
				return null;
			}
			return featureCall.getImplicitReceiver();
		}
		state.assumptionTracker.markDependent();
		return result;
	}
	
	protected XExpression getImplicitFirstArgument(XAbstractFeatureCall featureCall) {
		AssumptionState state = assumptionState.get();
		XExpression result = state.featureCallToFirstArgumentAssumption.get(featureCall);
		if (result == null) {
			if (state.featureCallToFirstArgumentAssumption.containsKey(featureCall)) {
				state.assumptionTracker.markDependent();
				return null;
			}
			return featureCall.getImplicitFirstArgument();
		}
		state.assumptionTracker.markDependent();
		return result;
	}
	
	protected JvmIdentifiableElement getFeature(XAbstractFeatureCall featureCall, boolean resolve) {
		JvmIdentifiableElement potentialProxy = (JvmIdentifiableElement) featureCall.eGet(XbasePackage.Literals.XABSTRACT_FEATURE_CALL__FEATURE, false);
		if (potentialProxy == null || !potentialProxy.eIsProxy())
			return potentialProxy;
		AssumptionState state = assumptionState.get();
		JvmIdentifiableElement assumption = state.proxyToAssumption.get(potentialProxy);
		if (assumption != null) {
			state.assumptionTracker.markDependent();
			return assumption;
		}
		if (!resolve)
			return potentialProxy;
		JvmIdentifiableElement resolvedResult = trackResolution(potentialProxy, featureCall, XbasePackage.Literals.XABSTRACT_FEATURE_CALL__FEATURE);
		return resolvedResult;
	}
	
	/**
	 * This one is currently implemented as a no-op.
	 * 
	 * Intentional implementation would return the resolved instance without changing the owner of the reference. Only single-valued references
	 * are currently supported.
	 * 
	 * @param proxy the proxy which should be resolved with tracking.
	 * @param owner the owner of the proxy.
	 * @param reference the cross reference.
	 */
	protected JvmIdentifiableElement trackResolution(JvmIdentifiableElement proxy, XExpression owner, EReference reference) {
		return (JvmIdentifiableElement) owner.eGet(reference);
//		Tracker tracker = trackAssumptions();
//		try {
//			URI proxyURI = EcoreUtil.getURI(proxy);
//			String proxyFragment = proxyURI.fragment();
//			EObject result = uncheckedGetEObject(proxyFragment);
//			if (result != null) {
//				if (tracker.isIndependentOfAssumptions()) {
//					owner.eSet(reference, result);
//				}
//				return (JvmIdentifiableElement) result;
//			}
//		} finally {
//			tracker.stopTracking();			
//		}
//		return proxy;
	}
	
	protected JvmConstructor getConstructor(XConstructorCall featureCall, boolean resolve) {
		JvmConstructor potentialProxy = (JvmConstructor) featureCall.eGet(XbasePackage.Literals.XCONSTRUCTOR_CALL__CONSTRUCTOR, false);
		if (potentialProxy == null || !potentialProxy.eIsProxy())
			return potentialProxy;
		AssumptionState state = assumptionState.get();
		JvmConstructor assumption = (JvmConstructor) state.proxyToAssumption.get(potentialProxy);
		if (assumption != null) {
			state.assumptionTracker.markDependent();
			return assumption;
		}
		if (!resolve)
			return potentialProxy;
		return (JvmConstructor) trackResolution(potentialProxy, featureCall, XbasePackage.Literals.XCONSTRUCTOR_CALL__CONSTRUCTOR);
	}
	
	@Override
	public synchronized EObject getEObject(final String uriFragment) {
		return onChangeEvictingCache.execWithoutCacheClear(this, new IUnitOfWork(){
			public EObject exec(XbaseResource state) throws Exception {
				return XbaseResource.super.getEObject(uriFragment);
			}
		});
	}
	
	@Override
	protected boolean isUnresolveableProxyCacheable(Triple triple) {
		boolean result = TypesPackage.Literals.JVM_TYPE.isSuperTypeOf(triple.getSecond().getEReferenceType());
		return result;
	}

	@Override
	protected EObject handleCyclicResolution(Triple triple) throws AssertionError {
		return null;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy