diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/OverriddenValueInspector.java b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/OverriddenValueInspector.java index 25b6a7ec5..6f840ae47 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/OverriddenValueInspector.java +++ b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/OverriddenValueInspector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 itemis AG (http://www.itemis.eu) and others. + * Copyright (c) 2009, 2020 itemis AG (http://www.itemis.eu) and others. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. @@ -10,6 +10,8 @@ package org.eclipse.xtext.xtext; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import org.eclipse.xtext.AbstractElement; @@ -25,6 +27,7 @@ import org.eclipse.xtext.RuleCall; import org.eclipse.xtext.TerminalRule; import org.eclipse.xtext.validation.ValidationMessageAcceptor; +import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; @@ -40,16 +43,19 @@ public class OverriddenValueInspector extends XtextRuleInspector assignedFeatures; /** - * Remember all visited unassigned rule calls in case the grammar is broken, e.g. has + * Remember all visited rules in case the grammar is broken, e.g. has * no assignments (yet). */ private Set permanentlyVisited; private Set fragmentStack; + private Map> assignedFeaturesAtEnd; + public OverriddenValueInspector(ValidationMessageAcceptor acceptor) { super(acceptor); assignedFeatures = newMultimap(); + assignedFeaturesAtEnd = new HashMap<>(); permanentlyVisited = Sets.newHashSet(); fragmentStack = Sets.newHashSet(); } @@ -73,6 +79,10 @@ public class OverriddenValueInspector extends XtextRuleInspector prevAssignedFeatures = assignedFeatures; - assignedFeatures = newMultimap(); - doSwitch(parserRule.getAlternatives()); - for (String feature : assignedFeatures.keySet()) + + // Cannot use #computeIfAbsent since we will call this recursively and that causes ConcurrentModificationExceptions + ImmutableMultimap assignedInCalledRule = assignedFeaturesAtEnd.get(parserRule); + if (assignedInCalledRule == null) { + assignedFeatures = newMultimap(); + doSwitch(parserRule.getAlternatives()); + assignedInCalledRule = ImmutableMultimap.copyOf(assignedFeatures); + assignedFeaturesAtEnd.put(parserRule, assignedInCalledRule); + } + for (String feature : assignedInCalledRule.keySet()) prevAssignedFeatures.put(feature, object); assignedFeatures = prevAssignedFeatures; removeVisited(parserRule); diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/PredicateUsesUnorderedGroupInspector.java b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/PredicateUsesUnorderedGroupInspector.java index 033547fbd..c99605228 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/PredicateUsesUnorderedGroupInspector.java +++ b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/PredicateUsesUnorderedGroupInspector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 itemis AG (http://www.itemis.eu) and others. + * Copyright (c) 2011, 2020 itemis AG (http://www.itemis.eu) and others. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. @@ -63,7 +63,7 @@ public class PredicateUsesUnorderedGroupInspector extends XtextSwitch i validatedRules = Sets.newHashSet(); doSwitch(rule); storedRules.addAll(validatedRules); - storedRules = validatedRules; + validatedRules = storedRules; } } } diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextRuleInspector.java b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextRuleInspector.java index a4ee6c779..98cf87d4d 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextRuleInspector.java +++ b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextRuleInspector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 itemis AG (http://www.itemis.eu) and others. + * Copyright (c) 2009, 2020 itemis AG (http://www.itemis.eu) and others. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. @@ -28,7 +28,7 @@ public abstract class XtextRuleInspector private final ValidationMessageAcceptor acceptor; - private Collection visitedRules; + Collection visitedRules; public XtextRuleInspector(ValidationMessageAcceptor acceptor) { this.acceptor = acceptor; diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextScopeProvider.java b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextScopeProvider.java index 84d57a37b..699dd4829 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextScopeProvider.java +++ b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextScopeProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others. + * Copyright (c) 2008, 2020 itemis AG (http://www.itemis.eu) and others. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. @@ -9,7 +9,6 @@ package org.eclipse.xtext.xtext; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -49,6 +48,7 @@ import org.eclipse.xtext.scoping.impl.SimpleScope; import com.google.common.base.Function; import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.inject.Inject; @@ -73,7 +73,7 @@ public class XtextScopeProvider extends AbstractScopeProvider { if (metaModel != null) { EPackage pack = metaModel.getEPackage(); if (pack != null) - return createClassifierScope(pack.getEClassifiers()); + return createClassifierScope(Collections.singletonList(pack)); } else { return createReferencedPackagesScope(GrammarUtil.getGrammar(context)); } @@ -123,31 +123,50 @@ public class XtextScopeProvider extends AbstractScopeProvider { } protected IScope createEnumLiteralsScope(EEnum eEnum) { - return new SimpleScope(IScope.NULLSCOPE,Iterables.transform(eEnum.getELiterals(), new Function() { - @Override - public IEObjectDescription apply(EEnumLiteral param) { - return EObjectDescription.create(QualifiedName.create(param.getName()), param); - } - })); + return new SimpleScope(IScope.NULLSCOPE, Iterables.transform(eEnum.getELiterals(), new Function() { + @Override + public IEObjectDescription apply(EEnumLiteral param) { + return EObjectDescription.create(QualifiedName.create(param.getName()), param); + } + })); } - protected IScope createClassifierScope(Iterable classifiers) { + protected IScope createClassifierScope(List packages) { return new SimpleScope( - IScope.NULLSCOPE,Iterables.transform(classifiers, new Function() { - @Override - public IEObjectDescription apply(EClassifier param) { - return EObjectDescription.create(QualifiedName.create(param.getName()), param); + IScope.NULLSCOPE, + FluentIterable.from(packages) + .transformAndConcat(EPackage::getEClassifiers) + .transform(classifier->EObjectDescription.create(QualifiedName.create(classifier.getName()), classifier))) { + + @Override + protected IEObjectDescription getSingleLocalElementByName(QualifiedName name) { + if (name.getSegmentCount() == 1) { + EClassifier candidate = null; + for(EPackage pack: packages) { + EClassifier classifier = pack.getEClassifier(name.getFirstSegment()); + if (classifier != null) { + if (candidate != null) { + return null; + } + candidate = classifier; + } } - })); + if (candidate != null) { + return EObjectDescription.create(name, candidate); + } + } + return null; + } + }; } protected IScope createReferencedPackagesScope(Grammar g) { - final Collection allClassifiers = new ArrayList(); + List allPackages = new ArrayList(); for(AbstractMetamodelDeclaration decl: g.getMetamodelDeclarations()) { if (decl.getEPackage() != null) - allClassifiers.addAll(decl.getEPackage().getEClassifiers()); + allPackages.add(decl.getEPackage()); } - return createClassifierScope(allClassifiers); + return createClassifierScope(allPackages); } protected IScope createScope(Resource resource, EClass type, IScope parent) { @@ -164,7 +183,7 @@ public class XtextScopeProvider extends AbstractScopeProvider { if (EcorePackage.Literals.EPACKAGE == type) { return createEPackageScope(grammar); } else if (AbstractMetamodelDeclaration.class.isAssignableFrom(type.getInstanceClass())) { - return new SimpleScope(IScope.NULLSCOPE,Iterables.transform(grammar.getMetamodelDeclarations(), + return new SimpleScope(IScope.NULLSCOPE, Iterables.transform(grammar.getMetamodelDeclarations(), new Function(){ @Override public IEObjectDescription apply(AbstractMetamodelDeclaration from) { diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextValidator.java b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextValidator.java index e258beaca..61e26dc1a 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextValidator.java +++ b/org.eclipse.xtext/src/org/eclipse/xtext/xtext/XtextValidator.java @@ -1062,9 +1062,13 @@ public class XtextValidator extends AbstractDeclarativeValidator { } @Check - public void checkForOverriddenValue(final ParserRule rule) { + public void checkForOverriddenValue(final Grammar grammar) { OverriddenValueInspector inspector = new OverriddenValueInspector(this); - inspector.inspect(rule); + for(AbstractRule rule: grammar.getRules()) { + if (rule instanceof ParserRule) { + inspector.inspect((ParserRule) rule); + } + } } @Check