[464867] fixed 'ITextRegionAccess cannot handle duplicate keywords'

https://bugs.eclipse.org/bugs/show_bug.cgi?id=464867

Signed-off-by: Moritz Eysholdt <moritz.eysholdt@itemis.de>
This commit is contained in:
Moritz Eysholdt 2015-04-21 16:15:39 +02:00
parent 4296349f3e
commit 7dc4339d7f
3 changed files with 79 additions and 7 deletions

View file

@ -13,6 +13,8 @@ import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.nodemodel.ILeafNode;
@ -166,6 +168,8 @@ public interface ITextRegionAccess {
*/
ISemanticRegion regionForKeyword(EObject owner, String keyword);
ISemanticRegion regionForKeyword(EObject owner, Keyword keyword);
ITextSegment regionForOffset(int offset, int length);
IEObjectRegion regionForRootEObject();
@ -178,6 +182,8 @@ public interface ITextRegionAccess {
ISemanticRegion regionForRuleCall(EObject owner, RuleCall ruleCall);
ISemanticRegion regionForCrossRef(EObject owner, CrossReference crossRef);
List<ISemanticRegion> regionsForRuleCalls(EObject owner, RuleCall... ruleCalls);
List<IEObjectRegion> regionsForAllEObjects();
@ -186,7 +192,11 @@ public interface ITextRegionAccess {
* @return All {@link ISemanticRegion semantic regions} that represent one of the provided 'keyword's and directly
* belong to the provided 'EObject'. Keywords of child-EObjects are not considered.
*/
List<ISemanticRegion> regionsForKeywords(EObject owner, String... string);
List<ISemanticRegion> regionsForKeywords(EObject owner, String... keywords);
List<ISemanticRegion> regionsForKeywords(EObject owner, Keyword... keywords);
List<ISemanticRegion> regionsForCrossRefs(EObject owner, CrossReference... crossRefs);
/**
* @return All {@link ISemanticRegion semantic regions} that represent a RuleCall to one of the provided

View file

@ -21,6 +21,7 @@ import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
@ -168,6 +169,19 @@ public abstract class AbstractRegionAccess implements ITextRegionAccess {
return null;
}
@Override
public ISemanticRegion regionForCrossRef(EObject owner, CrossReference crossRef) {
return regionForRuleCall(owner, (RuleCall) crossRef.getTerminal());
}
@Override
public List<ISemanticRegion> regionsForCrossRefs(EObject owner, CrossReference... crossRefs) {
List<RuleCall> rcs = Lists.newArrayList();
for (int i = 0; i < crossRefs.length; i++)
rcs.add((RuleCall) crossRefs[i].getTerminal());
return regionsForRuleCalls(owner, rcs.toArray(new RuleCall[rcs.size()]));
}
protected void assertNoContainment(EStructuralFeature feat) {
if (!(feat instanceof EAttribute) && !(feat instanceof EReference && !((EReference) feat).isContainment()))
throw new IllegalStateException("Only EAttributes and CrossReferences allowed.");
@ -183,7 +197,7 @@ public abstract class AbstractRegionAccess implements ITextRegionAccess {
}
AbstractEObjectRegion tokens = regionForEObject(owner);
if (tokens == null)
return null;
return Collections.emptyList();
List<ISemanticRegion> result = Lists.newArrayList();
for (ISemanticRegion region : tokens.getSemanticLeafRegions()) {
Assignment assignment = GrammarUtil.containingAssignment(region.getGrammarElement());
@ -209,6 +223,17 @@ public abstract class AbstractRegionAccess implements ITextRegionAccess {
return null;
}
@Override
public ISemanticRegion regionForKeyword(EObject owner, Keyword keyword) {
AbstractEObjectRegion tokens = regionForEObject(owner);
if (tokens == null)
return null;
for (ISemanticRegion region : tokens.getSemanticLeafRegions())
if (region.getGrammarElement() == keyword)
return region;
return null;
}
@Override
public ISemanticRegion regionForRuleCall(EObject owner, RuleCall ruleCall) {
assertNoEObjectRuleCall(ruleCall);
@ -227,7 +252,7 @@ public abstract class AbstractRegionAccess implements ITextRegionAccess {
assertNoEObjectRuleCall(ruleCalls[i]);
AbstractEObjectRegion tokens = regionForEObject(owner);
if (tokens == null)
return null;
return Collections.emptyList();
List<ISemanticRegion> result = Lists.newArrayList();
for (ISemanticRegion region : tokens.getSemanticLeafRegions())
for (int i = 0; i < ruleCalls.length; i++)
@ -275,7 +300,20 @@ public abstract class AbstractRegionAccess implements ITextRegionAccess {
if (kwSet.contains(kw.getValue()))
result.add(token);
}
return result;
return ImmutableList.copyOf(result);
}
@Override
public List<ISemanticRegion> regionsForKeywords(EObject owner, Keyword... keywords) {
AbstractEObjectRegion tokens = regionForEObject(owner);
if (tokens == null)
return Collections.emptyList();
List<ISemanticRegion> result = Lists.newArrayList();
for (ISemanticRegion region : tokens.getSemanticLeafRegions())
for (int i = 0; i < keywords.length; i++)
if (region.getGrammarElement() == keywords[i])
result.add(region);
return ImmutableList.copyOf(result);
}
@Override

View file

@ -57,7 +57,7 @@ class RegionAccessAccessTest {
assertEquals("foo", actual, actuals)
}
def void regionForFeatureContainmentReference() {
@Test def void regionForFeatureContainmentReference() {
val mixed = '''6 (foo) action'''.parseAs(AssignedAction)
val access = mixed.toAccess
try {
@ -112,8 +112,8 @@ class RegionAccessAccessTest {
assertEquals("foo", actual, actuals)
}
def void regionForRuleCallEObjectParserRule() {
val mixed = '''6 (child foo)'''.parseAs(Mixed)
@Test def void regionForRuleCallEObjectParserRule() {
val mixed = '''6 (child (foo))'''.parseAs(Mixed)
val access = mixed.toAccess
try {
access.regionForRuleCall(mixed, mixedAccess.eobjMixedParserRuleCall_2_2_1_1_0)
@ -127,6 +127,30 @@ class RegionAccessAccessTest {
}
}
@Test def void regionForKeywordString() {
val mixed = '''6 (foo)'''.parseAs(Mixed)
val access = mixed.toAccess
val actual = access.regionForKeyword(mixed, "(")
val actuals = access.regionsForKeywords(mixed, "(")
assertEquals("(", actual, actuals)
}
@Test def void regionForKeyword() {
val mixed = '''6 (foo)'''.parseAs(Mixed)
val access = mixed.toAccess
val actual = access.regionForKeyword(mixed, mixedAccess.leftParenthesisKeyword_0)
val actuals = access.regionsForKeywords(mixed, mixedAccess.leftParenthesisKeyword_0)
assertEquals("(", actual, actuals)
}
@Test def void regionForCrossReference() {
val mixed = '''6 (ref foo) action (foo) end'''.parseAs(AssignedAction)
val access = mixed.toAccess
val actual = access.regionForCrossRef(mixed.child, mixedAccess.refMixedCrossReference_2_2_3_1_0)
val actuals = access.regionsForCrossRefs(mixed.child, mixedAccess.refMixedCrossReference_2_2_3_1_0)
assertEquals("foo", actual, actuals)
}
def private <T extends EObject> parseAs(CharSequence seq, Class<T> cls) {
val result = seq.parse
result.assertNoErrors