diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/XtextRuntimeModule.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/XtextRuntimeModule.java
index cd4e308ac..90a1831cf 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/XtextRuntimeModule.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/XtextRuntimeModule.java
@@ -17,13 +17,18 @@ import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.parser.antlr.IReferableElementsUnloader;
import org.eclipse.xtext.parsetree.reconstr.ITokenSerializer.ICrossReferenceSerializer;
import org.eclipse.xtext.parsetree.reconstr.ITransientValueService;
+import org.eclipse.xtext.resource.DerivedStateAwareResourceDescriptionManager;
import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy;
+import org.eclipse.xtext.resource.IDerivedStateComputer;
import org.eclipse.xtext.resource.IFragmentProvider;
import org.eclipse.xtext.resource.ILocationInFileProvider;
+import org.eclipse.xtext.resource.IResourceDescription;
+import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.scoping.IGlobalScopeProvider;
import org.eclipse.xtext.scoping.IScopeProvider;
import org.eclipse.xtext.scoping.impl.DefaultGlobalScopeProvider;
import org.eclipse.xtext.validation.IDiagnosticConverter;
+import org.eclipse.xtext.xtext.GrammarResource;
import org.eclipse.xtext.xtext.XtextCrossReferenceSerializer;
import org.eclipse.xtext.xtext.XtextDiagnosticConverter;
import org.eclipse.xtext.xtext.XtextFormatter;
@@ -132,4 +137,22 @@ public class XtextRuntimeModule extends AbstractXtextRuntimeModule {
return DefaultGlobalScopeProvider.class;
}
+ @Override
+ public Class extends XtextResource> bindXtextResource() {
+ return GrammarResource.class;
+ }
+
+ /**
+ * @since 2.2
+ */
+ public Class extends IDerivedStateComputer> bindIDerivedStateComputer() {
+ return GrammarResource.LinkingTrigger.class;
+ }
+
+ /**
+ * @since 2.2
+ */
+ public Class extends IResourceDescription.Manager> bindIResourceDescriptionManager() {
+ return DerivedStateAwareResourceDescriptionManager.class;
+ }
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/DerivedStateAwareResource.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/DerivedStateAwareResource.java
index cd3385bf0..75f6b3d60 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/DerivedStateAwareResource.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/DerivedStateAwareResource.java
@@ -11,12 +11,13 @@ import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.linking.lazy.LazyLinkingResource;
import org.eclipse.xtext.parser.IParseResult;
+import org.eclipse.xtext.util.IResourceScopeCache;
+import org.eclipse.xtext.util.OnChangeEvictingCache;
import com.google.inject.Inject;
/**
- *
- * Adds a hook for late initialization to be used to create derived state
+ * Adds a hook for late initialization to be used to create derived state.
*
* @author Sven Efftinge - Initial contribution and API
* @since 2.1
@@ -33,6 +34,12 @@ public class DerivedStateAwareResource extends LazyLinkingResource {
protected volatile boolean fullyInitialized = false;
protected volatile boolean isInitializing = false;
+ /**
+ * {@inheritDoc}
+ *
+ * As soon as an external client tries to access the content of the resource,
+ * the {@link IDerivedStateComputer derived state} will be added to the content of this resource.
+ */
@Override
public synchronized EList getContents() {
if (isLoaded && !isLoading && !isInitializing && !isUpdating && !fullyInitialized) {
@@ -53,6 +60,48 @@ public class DerivedStateAwareResource extends LazyLinkingResource {
}
super.updateInternalState(oldParseResult, newParseResult);
}
+
+ /**
+ * Overridden to make sure that the cache is initialized during {@link #isLoading() loading}.
+ */
+ @Override
+ protected void updateInternalState(IParseResult newParseResult) {
+ super.updateInternalState(newParseResult);
+ // make sure that the cache adapter is installed on this resource
+ IResourceScopeCache cache = getCache();
+ if (cache instanceof OnChangeEvictingCache) {
+ ((OnChangeEvictingCache) cache).getOrCreate(this);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden to make sure that we do not initialize a resource
+ * just to compute the root URI fragment for the parse result.
+ */
+ @Override
+ protected String getURIFragmentRootSegment(EObject eObject) {
+ if (unloadingContents == null) {
+ IParseResult parseResult = getParseResult();
+ if (parseResult != null && eObject == parseResult.getRootASTElement()) {
+ return "0";
+ }
+ }
+ return super.getURIFragmentRootSegment(eObject);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Not specialized because we want to obtain a fully working root instance
+ * when the resource is queried with the root fragment.
+ */
+ @Override
+ protected EObject getEObjectForURIFragmentRootSegment(String uriFragmentRootSegment) {
+ return super.getEObjectForURIFragmentRootSegment(uriFragmentRootSegment);
+ }
+
public void discardDerivedState() {
if (fullyInitialized && !isInitializing) {
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/GrammarResource.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/GrammarResource.java
new file mode 100644
index 000000000..11632259d
--- /dev/null
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/GrammarResource.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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.xtext;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.xtext.parser.IParseResult;
+import org.eclipse.xtext.resource.DerivedStateAwareResource;
+import org.eclipse.xtext.resource.IDerivedStateComputer;
+
+/**
+ * Resource implementation that instantiates the infered packages as part of the
+ * derived state computation.
+ *
+ * @author Sebastian Zarnekow - Initial contribution and API
+ */
+public class GrammarResource extends DerivedStateAwareResource {
+
+ /**
+ * Overridden to do only the clean-part of the linking but not
+ * the actual linking. This is deferred until someone wants to access
+ * the content of the resource.
+ */
+ @Override
+ protected void doLinking() {
+ IParseResult parseResult = getParseResult();
+ if (parseResult == null || parseResult.getRootASTElement() == null)
+ return;
+
+ XtextLinker castedLinker = (XtextLinker) getLinker();
+ castedLinker.discardGeneratedPackages(parseResult.getRootASTElement());
+ }
+
+ /**
+ * Performs the actual linking.
+ */
+ protected void superDoLinking() {
+ super.doLinking();
+ }
+
+ /**
+ * Overridden to make sure the errors are up-to-date when someone wants to access them.
+ */
+ @Override
+ public EList getErrors() {
+ // trigger derived state computation
+ getContents();
+ return super.getErrors();
+ }
+
+ /**
+ * Overridden to make sure the warnings are up-to-date when someone wants to access them.
+ */
+ @Override
+ public EList getWarnings() {
+ // trigger derived state computation
+ getContents();
+ return super.getWarnings();
+ }
+
+ /**
+ * Triggers the ecore inference as soon as someone wants to access the contents
+ * of a {@link GrammarResource}.
+ */
+ public static class LinkingTrigger implements IDerivedStateComputer {
+
+ public void installDerivedState(DerivedStateAwareResource resource, boolean preLinkingPhase) {
+ if (preLinkingPhase)
+ return;
+ GrammarResource castedResource = (GrammarResource)resource;
+ castedResource.superDoLinking();
+ }
+
+ public void discardDerivedState(DerivedStateAwareResource resource) {
+ }
+
+ }
+
+}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextLinker.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextLinker.java
index 9fb79aaeb..104907b46 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextLinker.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextLinker.java
@@ -178,9 +178,15 @@ public class XtextLinker extends Linker {
@Override
protected void beforeModelLinked(EObject model, IDiagnosticConsumer diagnosticsConsumer) {
- if (model instanceof Grammar) {
+ discardGeneratedPackages(model);
+ super.beforeModelLinked(model, diagnosticsConsumer);
+ cache.getOrCreate(model.eResource()).ignoreNotifications();
+ }
+
+ void discardGeneratedPackages(EObject root) {
+ if (root instanceof Grammar) {
// unload generated metamodels as they will be recreated during linking
- for (AbstractMetamodelDeclaration metamodelDeclaration : ((Grammar) model).getMetamodelDeclarations()) {
+ for (AbstractMetamodelDeclaration metamodelDeclaration : ((Grammar) root).getMetamodelDeclarations()) {
if (metamodelDeclaration instanceof GeneratedMetamodel) {
EPackage ePackage = ((GeneratedMetamodel) metamodelDeclaration).getEPackage();
if (ePackage != null) {
@@ -197,8 +203,6 @@ public class XtextLinker extends Linker {
}
}
}
- super.beforeModelLinked(model, diagnosticsConsumer);
- cache.getOrCreate(model.eResource()).ignoreNotifications();
}
@Override
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextLinkingService.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextLinkingService.java
index 802d2a126..626498a0e 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextLinkingService.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextLinkingService.java
@@ -41,10 +41,13 @@ import org.eclipse.xtext.nodemodel.BidiIterator;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.parser.IParseResult;
import org.eclipse.xtext.resource.ClasspathUriResolutionException;
import org.eclipse.xtext.resource.ClasspathUriUtil;
+import org.eclipse.xtext.resource.DerivedStateAwareResource;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IResourceDescriptions;
+import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider;
import org.eclipse.xtext.scoping.IGlobalScopeProvider;
import org.eclipse.xtext.scoping.IScope;
@@ -95,13 +98,22 @@ public class XtextLinkingService extends DefaultLinkingService {
String grammarName = (String) valueConverterService.toValue("", "GrammarID", node);
if (grammarName != null) {
final ResourceSet resourceSet = grammar.eResource().getResourceSet();
- for(Resource resource: resourceSet.getResources()) {
- if (!resource.getContents().isEmpty()) {
- EObject content = resource.getContents().get(0);
- if (content instanceof Grammar) {
- Grammar otherGrammar = (Grammar) content;
- if (grammarName.equals(otherGrammar.getName()))
- return Collections.singletonList(otherGrammar);
+ List resources = resourceSet.getResources();
+ for(int i = 0; i < resources.size(); i++) {
+ Resource resource = resources.get(i);
+ EObject rootElement = null;
+ if (resource instanceof XtextResource) {
+ IParseResult parseResult = ((XtextResource) resource).getParseResult();
+ rootElement = parseResult.getRootASTElement();
+ } else if (!resource.getContents().isEmpty()) {
+ rootElement = resource.getContents().get(0);
+ }
+ if (rootElement instanceof Grammar) {
+ Grammar otherGrammar = (Grammar) rootElement;
+ if (grammarName.equals(otherGrammar.getName())) {
+ if (resource instanceof DerivedStateAwareResource)
+ resource.getContents();
+ return Collections.singletonList(otherGrammar);
}
}
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextValidator.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextValidator.java
index bbe16aa57..e01317f9f 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextValidator.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextValidator.java
@@ -890,6 +890,8 @@ public class XtextValidator extends AbstractDeclarativeValidator {
@Override
public Boolean caseRuleCall(RuleCall object) {
+ if (object.getRule() == null)
+ return assignedActionAllowed;
assignedActionAllowed = assignedActionAllowed || doSwitch(object.getRule())
&& !GrammarUtil.isOptionalCardinality(object);
return assignedActionAllowed;
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/EClassifierInfos.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/EClassifierInfos.java
index 257a73982..3ab58c2bd 100755
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/EClassifierInfos.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/EClassifierInfos.java
@@ -127,6 +127,8 @@ public class EClassifierInfos {
}
public EClassifierInfo getInfoOrNull(EClassifier eClassifier) {
+ if (eClassifier == null)
+ return null;
for (EClassifierInfo info : infoMap.values()) {
if (info.getEClassifier().equals(eClassifier))
return info;
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreInterpretationContext.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreInterpretationContext.java
index 2cb2a7d88..662bb9a3e 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreInterpretationContext.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreInterpretationContext.java
@@ -40,7 +40,7 @@ public class Xtext2EcoreInterpretationContext {
private final Collection currentTypes = Sets.newLinkedHashSet();
- boolean isRuleCallAllowed = true;
+ private boolean isRuleCallAllowed = true;
private Xtext2EcoreInterpretationContext(EClassifierInfos classifierInfos) {
super();
@@ -128,7 +128,7 @@ public class Xtext2EcoreInterpretationContext {
if (result == null) {
final ICompositeNode node = NodeModelUtils.getNode(terminal);
if (node != null) {
- throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable, "Cannot find type for '" + node.getText() + "'.", terminal);
+ throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable, "Cannot find type for '" + node.getText().trim() + "'.", terminal);
}
throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable, "Cannot find type for " + terminal.eClass().getName(), terminal);
}
@@ -139,8 +139,11 @@ public class Xtext2EcoreInterpretationContext {
throws TransformationException {
final EClassifierInfo featureTypeInfo = eClassifierInfos.getInfoOrNull(type);
if (featureTypeInfo == null) {
- throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable, "Cannot resolve type " + type.getName(),
- parserElement);
+ String typeName = "null";
+ if (type != null)
+ typeName = type.getName();
+ throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable,
+ "Cannot resolve type " + typeName, parserElement);
}
return featureTypeInfo;
}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreTransformer.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreTransformer.java
index 10be158c0..91834dff1 100755
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreTransformer.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/xtext/ecoreInference/Xtext2EcoreTransformer.java
@@ -12,7 +12,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -57,6 +56,7 @@ import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.util.XtextSwitch;
+import org.eclipse.xtext.xtext.GrammarResource;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
@@ -147,15 +147,16 @@ public class Xtext2EcoreTransformer {
public void removeGeneratedPackages() {
final ResourceSet resourceSet = grammar.eResource().getResourceSet();
- final Iterator resourceIter = resourceSet.getResources().iterator();
+ final List resources = resourceSet.getResources();
final Collection packages = getGeneratedPackages();
- // TODO check against grammar
- while (resourceIter.hasNext()) {
- Resource r = resourceIter.next();
- CONTENT: for (EObject content : r.getContents()) {
- if (content instanceof EPackage && packages.contains(content) || generatedEPackages != null && generatedEPackages.containsValue(content)) {
- clearPackage(r, (EPackage) content);
- break CONTENT;
+ for(int i = 0; i < resources.size(); i++) {
+ Resource r = resources.get(i);
+ if (!(r instanceof GrammarResource)) {
+ CONTENT: for (EObject content : r.getContents()) {
+ if (content instanceof EPackage && packages.contains(content) || generatedEPackages != null && generatedEPackages.containsValue(content)) {
+ clearPackage(r, (EPackage) content);
+ break CONTENT;
+ }
}
}
}
@@ -781,7 +782,6 @@ public class Xtext2EcoreTransformer {
}
else if (eClassifier instanceof EDataType) {
EDataType eDataType = (EDataType) eClassifier;
- // TODO: Enums
EClassifierInfo info = EClassifierInfo.createEDataTypeInfo(eDataType, generated);
target.addInfo(metaModel, eClassifier.getName(), info);
}
diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/grammarinheritance/ToEcoreTrafoTest.java b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/grammarinheritance/ToEcoreTrafoTest.java
index 7dbe3bc58..9e0d6d4a7 100755
--- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/grammarinheritance/ToEcoreTrafoTest.java
+++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/grammarinheritance/ToEcoreTrafoTest.java
@@ -57,7 +57,7 @@ public class ToEcoreTrafoTest extends AbstractXtextTests {
public void testConcreteLanguageToMetamodel() throws Exception {
XtextResource r = getResource("classpath:/" + ConcreteTestLanguage.class.getName().replace('.', '/') + ".xtext");
- Grammar element = (Grammar) r.getParseResult().getRootASTElement();
+ Grammar element = (Grammar) r.getContents().get(0);
List lexerRules = GrammarUtil.allTerminalRules(element);
assertEquals(8, lexerRules.size());
List list = Xtext2EcoreTransformer.doGetGeneratedPackages(element);
@@ -74,7 +74,7 @@ public class ToEcoreTrafoTest extends AbstractXtextTests {
public void testConcreteLanguageToMetamodel1() throws Exception {
XtextResource r = getResource("classpath:/" + ConcreteTestLanguage.class.getName().replace('.', '/') + ".xtext");
- EObject element = r.getParseResult().getRootASTElement();
+ EObject element = r.getContents().get(0);
Grammar g = (Grammar) element;
List mms = Lists.newArrayList(
Iterables.filter(g.getMetamodelDeclarations(), GeneratedMetamodel.class));