mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-17 01:08:56 +00:00
[linking] story lazy proxy information in a lits rather then serializing it to a string. Use a simple index as the actual fragment pointing to the entry in the list. (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=378088)
Change-Id: I04fdcc1c06c5ca484ef29ce7ce1f3db38f1d466f
This commit is contained in:
parent
c0c958d7d4
commit
c58636c1d6
8 changed files with 210 additions and 12 deletions
|
@ -312,4 +312,13 @@
|
|||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
<resource path="src/org/eclipse/xtext/linking/lazy/LazyURIEncoder.java" type="org.eclipse.xtext.linking.lazy.LazyURIEncoder">
|
||||
<filter id="388194388">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.linking.lazy.LazyURIEncoder"/>
|
||||
<message_argument value="XTEXT_LINK"/>
|
||||
<message_argument value="xtextLink_"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
</component>
|
||||
|
|
|
@ -11,12 +11,16 @@ package org.eclipse.xtext.linking.impl;
|
|||
import java.util.Iterator;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.AbstractTreeIterator;
|
||||
import org.eclipse.emf.common.util.TreeIterator;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.EReference;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Assignment;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.diagnostics.IDiagnosticConsumer;
|
||||
import org.eclipse.xtext.linking.lazy.LazyLinkingResource;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
import org.eclipse.xtext.util.internal.Stopwatches;
|
||||
|
@ -62,19 +66,46 @@ public abstract class AbstractCleaningLinker extends AbstractLinker {
|
|||
protected abstract void doLinkModel(EObject model, IDiagnosticConsumer diagnosticsConsumer);
|
||||
|
||||
protected void beforeModelLinked(EObject model, IDiagnosticConsumer diagnosticsConsumer) {
|
||||
clearAllReferences(model);
|
||||
ImportedNamesAdapter adapter = ImportedNamesAdapter.find(model.eResource());
|
||||
Resource resource = model.eResource();
|
||||
if (resource instanceof LazyLinkingResource) {
|
||||
((LazyLinkingResource) resource).clearLazyProxyInformation();
|
||||
}
|
||||
ImportedNamesAdapter adapter = ImportedNamesAdapter.find(resource);
|
||||
if (adapter!=null)
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
protected boolean isClearAllReferencesRequired(Resource resource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated no longer called, override {@link #clearReferences(EObject)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
protected void clearAllReferences(EObject model) {
|
||||
clearReferences(model);
|
||||
final Iterator<EObject> iter = model.eAllContents();
|
||||
final Iterator<EObject> iter = getAllLinkableContents(model);
|
||||
while (iter.hasNext())
|
||||
clearReferences(iter.next());
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
protected TreeIterator<EObject> getAllLinkableContents(EObject model) {
|
||||
return new AbstractTreeIterator<EObject>(model) {
|
||||
@Override
|
||||
public Iterator<EObject> getChildren(Object object) {
|
||||
return ((EObject) object).eContents().iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void clearReferences(EObject obj) {
|
||||
for (EReference ref : obj.eClass().getEAllReferences())
|
||||
clearReference(obj, ref);
|
||||
|
|
|
@ -90,10 +90,13 @@ public class LazyLinker extends AbstractCleaningLinker {
|
|||
cache.execWithoutCacheClear(model.eResource(), new IUnitOfWork.Void<Resource>() {
|
||||
@Override
|
||||
public void process(Resource state) throws Exception {
|
||||
installProxies(model, producer, settingsToLink);
|
||||
TreeIterator<EObject> iterator = model.eAllContents();
|
||||
TreeIterator<EObject> iterator = getAllLinkableContents(model);
|
||||
boolean clearAllReferencesRequired = isClearAllReferencesRequired(state);
|
||||
while (iterator.hasNext()) {
|
||||
EObject eObject = iterator.next();
|
||||
if (clearAllReferencesRequired) {
|
||||
clearReferences(eObject);
|
||||
}
|
||||
installProxies(eObject, producer, settingsToLink);
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +134,7 @@ public class LazyLinker extends AbstractCleaningLinker {
|
|||
settingsToLink.put(new SettingDelegate(setting), node);
|
||||
} else {
|
||||
createAndSetProxy(obj, node, eRef);
|
||||
afterCreateAndSetProxy(obj, node, eRef, crossReference, producer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +143,13 @@ public class LazyLinker extends AbstractCleaningLinker {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
protected void afterCreateAndSetProxy(EObject obj, INode node, EReference eRef, CrossReference crossReference,
|
||||
IDiagnosticProducer producer) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.4
|
||||
*/
|
||||
|
@ -182,13 +193,21 @@ public class LazyLinker extends AbstractCleaningLinker {
|
|||
throw new IllegalStateException("object must be contained in a resource");
|
||||
final URI uri = resource.getURI();
|
||||
final URI encodedLink = uri.appendFragment(encoder.encode(obj, eRef, node));
|
||||
EClass referenceType = ecoreGenericsUtil.getReferenceType(eRef, obj.eClass());
|
||||
EClass instantiableType = instantiableSubTypes.get(referenceType);
|
||||
final EObject proxy = EcoreUtil.create(instantiableType);
|
||||
EClass referenceType = getProxyType(obj, eRef);
|
||||
final EObject proxy = EcoreUtil.create(referenceType);
|
||||
((InternalEObject) proxy).eSetProxyURI(encodedLink);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
protected EClass getProxyType(EObject obj, EReference eRef) {
|
||||
EClass referenceType = ecoreGenericsUtil.getReferenceType(eRef, obj.eClass());
|
||||
EClass instantiableType = instantiableSubTypes.get(referenceType);
|
||||
return instantiableType;
|
||||
}
|
||||
|
||||
protected EClass findInstantiableCompatible(EClass eType) {
|
||||
if (!isInstantiatableSubType(eType, eType)) {
|
||||
// check local Package
|
||||
|
|
|
@ -8,8 +8,11 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.linking.lazy;
|
||||
|
||||
import static com.google.common.collect.Lists.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
@ -40,6 +43,7 @@ import org.eclipse.xtext.nodemodel.INode;
|
|||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.util.Triple;
|
||||
import org.eclipse.xtext.util.Tuples;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Inject;
|
||||
|
@ -450,4 +454,47 @@ public class LazyLinkingResource extends XtextResource {
|
|||
});
|
||||
return unresolveableProxies;
|
||||
}
|
||||
|
||||
private ArrayList<Triple<EObject, EReference, INode>> proxyInformation = newArrayList();
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public int addLazyProxyInformation(EObject obj, EReference ref, INode node) {
|
||||
int index = proxyInformation.size();
|
||||
proxyInformation.add(Tuples.create(obj, ref, node));
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public boolean hasLazyProxyInformation(int idx) {
|
||||
return proxyInformation.get(idx) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public Triple<EObject,EReference,INode> getLazyProxyInformation(int idx) {
|
||||
if (!hasLazyProxyInformation(idx)) {
|
||||
throw new IllegalArgumentException("No proxy information for index '"+idx+"' available.");
|
||||
}
|
||||
return proxyInformation.get(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public Triple<EObject,EReference,INode> removeLazyProxyInformation(int idx) {
|
||||
return proxyInformation.set(idx, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public void clearLazyProxyInformation() {
|
||||
proxyInformation = newArrayListWithCapacity(proxyInformation.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@ import org.eclipse.xtext.util.Strings;
|
|||
import org.eclipse.xtext.util.Triple;
|
||||
import org.eclipse.xtext.util.Tuples;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
|
@ -32,12 +34,32 @@ public class LazyURIEncoder {
|
|||
|
||||
/**
|
||||
* @since 2.3
|
||||
*
|
||||
* deprecated use {@link #isCrossLinkFragment(Resource, String)} instead
|
||||
*
|
||||
* @noreference This field is not intended to be referenced by clients.
|
||||
*/
|
||||
public static final String XTEXT_LINK = "xtextLink_";
|
||||
public static final String XTEXT_LINK = "|";
|
||||
/**
|
||||
* @since 2.3
|
||||
*
|
||||
*/
|
||||
public static final String SEP = "::";
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public final static String USE_INDEXED_FRAGMENTS_BINDING = "org.eclipse.xtext.linking.lazy.LazyURIEncoder.isUseIndexFragment";
|
||||
|
||||
@Inject(optional=true) @Named(value=USE_INDEXED_FRAGMENTS_BINDING)
|
||||
private boolean isUseIndexFragment = false;
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public boolean isUseIndexFragment(Resource context) {
|
||||
return isUseIndexFragment && context instanceof LazyLinkingResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* encodes the given three parameters into a string, so that they can be
|
||||
|
@ -49,7 +71,10 @@ public class LazyURIEncoder {
|
|||
* @return a portable string that may be used as a {@link URI#fragment() fragment}
|
||||
*/
|
||||
public String encode(EObject obj, EReference ref, INode node) {
|
||||
StringBuilder fragment = new StringBuilder(20).append(XTEXT_LINK).append(SEP);
|
||||
if (isUseIndexFragment(obj.eResource())) {
|
||||
return getIndexFragment(obj, ref, node);
|
||||
}
|
||||
StringBuilder fragment = new StringBuilder(4).append(XTEXT_LINK).append(SEP);
|
||||
appendShortFragment(obj, fragment);
|
||||
fragment.append(SEP);
|
||||
fragment.append(toShortExternalForm(obj.eClass(), ref)).append(SEP);
|
||||
|
@ -57,6 +82,19 @@ public class LazyURIEncoder {
|
|||
return fragment.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
protected String getIndexFragment(EObject obj, EReference ref, INode node) {
|
||||
Resource resource = obj.eResource();
|
||||
if (!(resource instanceof LazyLinkingResource)) {
|
||||
throw new IllegalStateException("Context object must be contained in a LazyLinkingResource : "+obj.eResource());
|
||||
}
|
||||
LazyLinkingResource lazyResource = (LazyLinkingResource) resource;
|
||||
int idx = lazyResource.addLazyProxyInformation(obj,ref,node);
|
||||
return XTEXT_LINK + idx;
|
||||
}
|
||||
|
||||
public void appendShortFragment(EObject obj, StringBuilder target) {
|
||||
EReference containmentFeature = obj.eContainmentFeature();
|
||||
if (containmentFeature == null) {
|
||||
|
@ -85,6 +123,9 @@ public class LazyURIEncoder {
|
|||
* @see LazyURIEncoder#encode(EObject, EReference, INode)
|
||||
*/
|
||||
public Triple<EObject, EReference, INode> decode(Resource res, String uriFragment) {
|
||||
if (isUseIndexFragment(res)) {
|
||||
return getLazyProxyInformation(res, uriFragment);
|
||||
}
|
||||
List<String> split = Strings.split(uriFragment, SEP);
|
||||
EObject source = resolveShortFragment(res, split.get(1));
|
||||
EReference ref = fromShortExternalForm(source.eClass(), split.get(2));
|
||||
|
@ -95,6 +136,32 @@ public class LazyURIEncoder {
|
|||
return Tuples.create(source, ref, textNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
protected Triple<EObject, EReference, INode> getLazyProxyInformation(Resource res, String uriFragment) {
|
||||
if (!(res instanceof LazyLinkingResource)) {
|
||||
throw new IllegalArgumentException("Given resource not a LazyLinkingResource");
|
||||
}
|
||||
int idx = getIndex(uriFragment);
|
||||
LazyLinkingResource lazyResource = (LazyLinkingResource) res;
|
||||
return lazyResource.getLazyProxyInformation(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public int getIndex(String uriFragment) {
|
||||
int idx = -1;
|
||||
try {
|
||||
String string = uriFragment.substring(XTEXT_LINK.length());
|
||||
idx = Integer.parseInt(string);
|
||||
} catch (RuntimeException e) {
|
||||
throw new IllegalArgumentException("Couldn't parse index from fragment '"+uriFragment+"'", e);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
public EObject resolveShortFragment(Resource res, String shortFragment) {
|
||||
List<String> split = Strings.split(shortFragment, '.');
|
||||
int contentsIdx = Integer.parseInt(split.get(0));
|
||||
|
@ -121,6 +188,8 @@ public class LazyURIEncoder {
|
|||
|
||||
/**
|
||||
* ONLY public to be testable
|
||||
*
|
||||
* @noreference This method is not intended to be referenced by clients.
|
||||
*/
|
||||
public void getRelativePath(StringBuilder result, INode parserNode, INode node) {
|
||||
if (parserNode == node)
|
||||
|
@ -154,10 +223,13 @@ public class LazyURIEncoder {
|
|||
* @since 2.4
|
||||
*/
|
||||
public INode getNode(EObject object, String fragment) {
|
||||
List<String> split = Strings.split(fragment, LazyURIEncoder.SEP);
|
||||
if (isUseIndexFragment(object.eResource())) {
|
||||
return decode(object.eResource(), fragment).getThird();
|
||||
}
|
||||
INode compositeNode = NodeModelUtils.getNode(object);
|
||||
if (compositeNode == null)
|
||||
throw new IllegalStateException("Couldn't resolve lazy link, because no node model is attached.");
|
||||
List<String> split = Strings.split(fragment, LazyURIEncoder.SEP);
|
||||
INode node = getNode(compositeNode, split.get(3));
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.eclipse.xtext.linking.LinkingScopeProviderBinding;
|
|||
import org.eclipse.xtext.linking.impl.DefaultLinkingService;
|
||||
import org.eclipse.xtext.linking.lazy.LazyLinker;
|
||||
import org.eclipse.xtext.linking.lazy.LazyLinkingResource;
|
||||
import org.eclipse.xtext.linking.lazy.LazyURIEncoder;
|
||||
import org.eclipse.xtext.naming.IQualifiedNameProvider;
|
||||
import org.eclipse.xtext.naming.SimpleNameProvider;
|
||||
import org.eclipse.xtext.parser.IEncodingProvider;
|
||||
|
@ -230,5 +231,10 @@ public abstract class DefaultRuntimeModule extends AbstractGenericModule {
|
|||
binder.bind(ISemanticSequencer.class).annotatedWith(GenericSequencer.class).to(BacktrackingSemanticSequencer.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public void configureUseIndexFragmentsForLazyLinking(com.google.inject.Binder binder) {
|
||||
binder.bind(Boolean.TYPE).annotatedWith(Names.named(LazyURIEncoder.USE_INDEXED_FRAGMENTS_BINDING)).toInstance(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,4 +23,9 @@ public class LazyLinkingTestLanguageRuntimeModule extends org.eclipse.xtext.link
|
|||
public void configureIScopeProviderDelegate(Binder binder) {
|
||||
binder.bind(IScopeProvider.class).annotatedWith(Names.named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE)).to(ImportedNamespaceAwareLocalScopeProvider.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureUseIndexFragmentsForLazyLinking(Binder binder) {
|
||||
binder.bind(Boolean.TYPE).annotatedWith(Names.named(LazyURIEncoder.USE_INDEXED_FRAGMENTS_BINDING)).toInstance(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,18 @@
|
|||
*/
|
||||
package org.eclipse.xtext.parser.bug419429;
|
||||
|
||||
import org.eclipse.xtext.linking.lazy.LazyURIEncoder;
|
||||
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
/**
|
||||
* Use this class to register components to be used at runtime / without the Equinox extension registry.
|
||||
*/
|
||||
public class Bug419429RuntimeModule extends org.eclipse.xtext.parser.bug419429.AbstractBug419429RuntimeModule {
|
||||
|
||||
@Override
|
||||
public void configureUseIndexFragmentsForLazyLinking(Binder binder) {
|
||||
binder.bind(Boolean.TYPE).annotatedWith(Names.named(LazyURIEncoder.USE_INDEXED_FRAGMENTS_BINDING)).toInstance(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue