diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/formatter/FormatterTester.java b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/formatter/FormatterTester.java index f922c2a35..a3a9fe556 100644 --- a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/formatter/FormatterTester.java +++ b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/formatter/FormatterTester.java @@ -155,7 +155,9 @@ public class FormatterTester { if (req.isUseNodeModel() && useSerializer) { ITextRegionAccess nmRegions = createRegionAccessViaNodeModel(resource); ITextRegionAccess serRegions = createRegionAccessViaSerializer(resource); - Assert.assertEquals(toString(nmRegions), toString(serRegions)); + String nmString = toString(nmRegions); + String serString = toString(serRegions); + Assert.assertEquals(nmString, serString); return nmRegions; } else if (req.isUseNodeModel()) { ITextRegionAccess nmRegions = createRegionAccessViaNodeModel(resource); diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/debug/TextRegionAccessToString.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/debug/TextRegionAccessToString.java index 2b017a96b..708673a2d 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/debug/TextRegionAccessToString.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/debug/TextRegionAccessToString.java @@ -9,14 +9,17 @@ package org.eclipse.xtext.formatting2.debug; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.List; -import java.util.Set; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.xtext.AbstractElement; import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.formatting2.regionaccess.IAstRegion; import org.eclipse.xtext.formatting2.regionaccess.IComment; +import org.eclipse.xtext.formatting2.regionaccess.IEObjectRegion; import org.eclipse.xtext.formatting2.regionaccess.IHiddenRegion; import org.eclipse.xtext.formatting2.regionaccess.IHiddenRegionPart; import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion; @@ -30,22 +33,48 @@ import org.eclipse.xtext.util.EmfFormatter; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Strings; -import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; /** * @author Moritz Eysholdt - Initial contribution and API */ public class TextRegionAccessToString { + protected static enum AstRegionComparator implements Comparator { + CHILDREN_FIRST { + @Override + public int compare(IAstRegion o1, IAstRegion o2) { + EObject e1 = o1.getSemanticElement(); + EObject e2 = o2.getSemanticElement(); + if (e1 == e2) + return 0; + if (EcoreUtil.isAncestor(e1, e2)) + return 1; + return -1; + } + }, + CONTAINER_FIRST { + @Override + public int compare(IAstRegion o1, IAstRegion o2) { + EObject e1 = o1.getSemanticElement(); + EObject e2 = o2.getSemanticElement(); + if (e1 == e2) + return 0; + if (EcoreUtil.isAncestor(e1, e2)) + return -1; + return 1; + } + }; + } + private static final int TITLE_WIDTH = 9; - private static final String SEMANTIC_PADDED = Strings.padEnd("Semantic", TITLE_WIDTH, ' '); + private static final String EOBJECT_END_PADDED = Strings.padEnd("End", TITLE_WIDTH, ' '); + private static final String EOBJECT_START_PADDED = Strings.padEnd("Start", TITLE_WIDTH, ' '); private static final String HIDDEN = "Hidden"; private static final String HIDDEN_PADDED = Strings.padEnd(HIDDEN, TITLE_WIDTH, ' '); - private static final String EOBJECT_START_PADDED = Strings.padEnd("Start", TITLE_WIDTH, ' '); - private static final String EOBJECT_END_PADDED = Strings.padEnd("End", TITLE_WIDTH, ' '); + private static final String SEMANTIC_PADDED = Strings.padEnd("Semantic", TITLE_WIDTH, ' '); private Function grammarToString = new GrammarElementTitleSwitch().showRule() .showAssignments().showQualified(); @@ -56,42 +85,6 @@ public class TextRegionAccessToString { private ITextSegment origin; - protected void collectHiddenRegionsBySemanticObject(List regions, - Multimap leadingHiddens, Multimap trailingHiddens, - List errors) { - Set sem = Sets.newHashSet(); - for (ITextSegment s : regions) - if (s instanceof ISemanticRegion) - sem.add(((ISemanticRegion) s).getSemanticElement()); - ISemanticRegion previous = ((ISequentialRegion) regions.get(0)).getPreviousSemanticRegion(); - if (previous != null) - sem.add(previous.getSemanticElement()); - ISemanticRegion next = ((ISequentialRegion) regions.get(regions.size() - 1)).getNextSemanticRegion(); - if (next != null) - sem.add(next.getSemanticElement()); - sem.remove(null); - Set containers = Sets.newHashSet(); - for (EObject s : sem) { - EObject container = s.eContainer(); - while (container != null && containers.add(container)) - container = container.eContainer(); - } - sem.addAll(containers); - ITextRegionAccess access = regions.get(0).getTextRegionAccess(); - for (EObject s : sem) { - IHiddenRegion leading = access.leadingHiddenRegion(s); - if (leading == null) - errors.add("ERROR: " + EmfFormatter.objPath(s) + " has no leading HiddenRegion."); - else - leadingHiddens.put(leading, s); - IHiddenRegion trailing = access.trailingHiddenRegion(s); - if (trailing == null) - errors.add("ERROR: " + EmfFormatter.objPath(s) + " has no trailing HiddenRegion."); - else - trailingHiddens.put(trailing, s); - } - } - public TextRegionAccessToString hideColumnExplanation() { this.hideColumnExplanation = true; return this; @@ -122,10 +115,27 @@ public class TextRegionAccessToString { @Override public String toString() { List list = toTokenAndGapList(); - Multimap leadingHiddens = LinkedHashMultimap.create(); - Multimap trailingHiddens = LinkedHashMultimap.create(); + if (list.isEmpty()) + return "(empty)"; + Multimap hiddens = LinkedListMultimap.create(); List errors = Lists.newArrayList(); - collectHiddenRegionsBySemanticObject(list, leadingHiddens, trailingHiddens, errors); + ITextRegionAccess access = list.get(0).getTextRegionAccess(); + List objects = access.regionsForAllEObjects(); + for (IEObjectRegion obj : objects) { + IHiddenRegion previous = obj.getPreviousHiddenRegion(); + IHiddenRegion next = obj.getNextHiddenRegion(); + EObject element = obj.getSemanticElement(); + if (previous == null) + errors.add("ERROR: " + EmfFormatter.objPath(element) + " has no leading HiddenRegion."); + else + hiddens.put(previous, obj); + if (previous != next) { + if (next == null) + errors.add("ERROR: " + EmfFormatter.objPath(element) + " has no trailing HiddenRegion."); + else + hiddens.put(next, obj); + } + } TextRegionListToString result = new TextRegionListToString(); if (!hideColumnExplanation) { String explanation = "Columns: 1:offset; 2:length; 3:hidden/semantic; 4: text; 5..n:grammar elements or whispace/comments"; @@ -134,17 +144,30 @@ public class TextRegionAccessToString { for (String error : errors) result.add(error, false); for (ITextSegment region : list) { + List previous = Lists.newArrayList(); + List next = Lists.newArrayList(); + List middle = Lists.newArrayList(toString(region)); if (region instanceof IHiddenRegion) { - Collection collection = trailingHiddens.get((IHiddenRegion) region); - if (!collection.isEmpty()) - result.add(EOBJECT_END_PADDED + toString(collection)); - } - result.add(region, toString(region)); - if (region instanceof IHiddenRegion) { - Collection collection = leadingHiddens.get((IHiddenRegion) region); - if (!collection.isEmpty()) - result.add(EOBJECT_START_PADDED + toString(collection)); + Collection found = hiddens.get((IHiddenRegion) region); + for (IEObjectRegion obj : found) { + boolean p = obj.getNextHiddenRegion().equals(region); + boolean n = obj.getPreviousHiddenRegion().equals(region); + if (p && n) + middle.add("Semantic " + toString(obj)); + else if (p) + previous.add(obj); + else if (n) + next.add(obj); + } + Collections.sort(previous, AstRegionComparator.CHILDREN_FIRST); + Collections.sort(next, AstRegionComparator.CONTAINER_FIRST); } + for (IEObjectRegion obj : previous) + result.add(EOBJECT_END_PADDED + toString(obj)); + + result.add(region, Joiner.on(", ").join(middle)); + for (IEObjectRegion obj : next) + result.add(EOBJECT_START_PADDED + toString(obj)); } return result.toString(); } @@ -153,32 +176,6 @@ public class TextRegionAccessToString { return rule == null ? "null" : rule.getName(); } - protected String toString(Collection objs) { - List result = Lists.newArrayList(); - for (EObject obj : objs) { - StringBuilder builder = new StringBuilder(); - EStructuralFeature containingFeature = obj.eContainingFeature(); - if (containingFeature != null) { - builder.append(containingFeature.getName()); - if (containingFeature.isMany()) { - int index = ((List) obj.eContainer().eGet(containingFeature)).indexOf(obj); - builder.append("[" + index + "]"); - } - builder.append("="); - } - builder.append(obj.eClass().getName()); - EStructuralFeature nameFeature = obj.eClass().getEStructuralFeature("name"); - if (nameFeature != null) { - Object name = obj.eGet(nameFeature); - if (name != null) - builder.append("'" + name + "'"); - } - result.add(builder.toString()); - } - Collections.sort(result); - return Joiner.on(", ").join(result); - } - protected String toString(EObject ele) { if (ele instanceof AbstractElement) return grammarToString.apply((AbstractElement) ele); @@ -193,6 +190,35 @@ public class TextRegionAccessToString { return String.format("%s Comment:%s", text, gammar); } + protected String toString(IEObjectRegion region) { + EObject obj = region.getSemanticElement(); + StringBuilder builder = new StringBuilder(); + EStructuralFeature containingFeature = obj.eContainingFeature(); + if (containingFeature != null) { + builder.append(containingFeature.getName()); + if (containingFeature.isMany()) { + int index = ((List) obj.eContainer().eGet(containingFeature)).indexOf(obj); + builder.append("[" + index + "]"); + } + builder.append("="); + } + builder.append(obj.eClass().getName()); + EStructuralFeature nameFeature = obj.eClass().getEStructuralFeature("name"); + if (nameFeature != null) { + Object name = obj.eGet(nameFeature); + if (name != null) + builder.append("'" + name + "'"); + } + EObject element = region.getGrammarElement(); + if (element instanceof AbstractElement) + builder.append(" via " + grammarToString.apply((AbstractElement) element)); + else if (element instanceof AbstractRule) + builder.append(" via " + ((AbstractRule) element).getName()); + else + builder.append(": ERROR: EObject has no grammar element."); + return builder.toString(); + } + protected String toString(IHiddenRegion gap) { List whitespaceAndComments = gap.getParts(); List children = Lists.newArrayListWithExpectedSize(whitespaceAndComments.size()); @@ -210,7 +236,9 @@ public class TextRegionAccessToString { protected String toString(ITextSegment region) { String result; - if (region instanceof ISemanticRegion) + if (region instanceof IEObjectRegion) + result = toString((IEObjectRegion) region); + else if (region instanceof ISemanticRegion) result = toString((ISemanticRegion) region); else if (region instanceof IHiddenRegion) result = toString((IHiddenRegion) region); @@ -268,15 +296,15 @@ public class TextRegionAccessToString { return result; } + public TextRegionAccessToString withOrigin(ITextSegment origin) { + this.origin = origin; + return this; + } + public TextRegionAccessToString withRegionAccess(ITextRegionAccess access) { this.origin = access.regionForRootEObject(); this.hightlightOrigin = false; return this; } - public TextRegionAccessToString withOrigin(ITextSegment origin) { - this.origin = origin; - return this; - } - } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/ITextRegionAccess.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/ITextRegionAccess.java index 92846040c..1a60d6d24 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/ITextRegionAccess.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/ITextRegionAccess.java @@ -192,4 +192,6 @@ public interface ITextRegionAccess { String textForOffset(int offset, int length); List expandToLines(ITextSegment segment, int leadingLinesToAdd, int trailingLinesToAdd); + + List regionsForAllEObjects(); } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/TextRegionAccessBuilder.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/TextRegionAccessBuilder.java index 2d6ec4de8..698fa15a1 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/TextRegionAccessBuilder.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/TextRegionAccessBuilder.java @@ -27,8 +27,8 @@ public class TextRegionAccessBuilder { return this; } - public ISequenceAcceptor forSequence(EObject root) { - return this.fromSequencer = createTextRegionAccessBuildingSequencer().withRoot(root); + public ISequenceAcceptor forSequence(EObject ctx, EObject root) { + return this.fromSequencer = createTextRegionAccessBuildingSequencer().withRoot(ctx, root); } private TextRegionAccessBuildingSequencer createTextRegionAccessBuildingSequencer() { diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/AbstractEObjectRegion.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/AbstractEObjectRegion.java index cc2e0359e..32e7b3166 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/AbstractEObjectRegion.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/AbstractEObjectRegion.java @@ -22,6 +22,7 @@ import com.google.common.collect.Lists; */ public abstract class AbstractEObjectRegion extends AbstractTextSegment implements IEObjectRegion { private final ITextRegionAccess access; + private EObject grammarElement; private IHiddenRegion nextHidden; private IHiddenRegion previousHidden; private EObject semantcElement; @@ -32,6 +33,11 @@ public abstract class AbstractEObjectRegion extends AbstractTextSegment implemen this.access = access; } + @Override + public EObject getGrammarElement() { + return grammarElement; + } + public IHiddenRegion getLeadingHiddenRegion() { return previousHidden; } @@ -85,6 +91,10 @@ public abstract class AbstractEObjectRegion extends AbstractTextSegment implemen return nextHidden; } + protected void setGrammarElement(EObject grammarElement) { + this.grammarElement = grammarElement; + } + protected void setLeadingHiddenRegion(IHiddenRegion leading) { this.previousHidden = leading; } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeEObjectRegion.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeEObjectRegion.java index 504a3886c..9e0f485ca 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeEObjectRegion.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeEObjectRegion.java @@ -7,11 +7,6 @@ *******************************************************************************/ package org.eclipse.xtext.formatting2.regionaccess.internal; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.AbstractElement; -import org.eclipse.xtext.Action; -import org.eclipse.xtext.GrammarUtil; -import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; /** @@ -25,25 +20,7 @@ public class NodeEObjectRegion extends AbstractEObjectRegion { this.node = node; } - @Override - public AbstractElement getGrammarElement() { - INode current = node; - while (current != null) { - EObject grammarElement = current.getGrammarElement(); - if (GrammarUtil.isAssignedEObjectRuleCall(grammarElement)) - return (AbstractElement) grammarElement; - if (grammarElement instanceof Action) { - Action action = (Action) grammarElement; - if (action.getFeature() != null) - return (AbstractElement) grammarElement; - else { - EObject grammarElement2 = ((ICompositeNode) current).getFirstChild().getGrammarElement(); - if (GrammarUtil.isAssignedEObjectRuleCall(grammarElement2)) - return (AbstractElement) grammarElement2; - } - } - current = current.getParent(); - } - return null; + public INode getNode() { + return node; } } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeModelBasedRegionAccess.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeModelBasedRegionAccess.java index 5408ba28b..48472840a 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeModelBasedRegionAccess.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeModelBasedRegionAccess.java @@ -7,6 +7,7 @@ *******************************************************************************/ package org.eclipse.xtext.formatting2.regionaccess.internal; +import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.EObject; @@ -17,6 +18,7 @@ import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; /** @@ -77,4 +79,9 @@ public class NodeModelBasedRegionAccess extends AbstractRegionAccess { return new TextSegment(this, 0, resource.getParseResult().getRootNode().getTotalEndOffset()); } + @Override + public List regionsForAllEObjects() { + return ImmutableList. copyOf(eObjectToTokens.values()); + } + } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeModelBasedRegionAccessBuilder.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeModelBasedRegionAccessBuilder.java index 2a2d6adf8..2205148eb 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeModelBasedRegionAccessBuilder.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/NodeModelBasedRegionAccessBuilder.java @@ -13,6 +13,7 @@ import java.util.Map; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.Action; +import org.eclipse.xtext.Assignment; import org.eclipse.xtext.CrossReference; import org.eclipse.xtext.GrammarUtil; import org.eclipse.xtext.RuleCall; @@ -146,6 +147,38 @@ public class NodeModelBasedRegionAccessBuilder { return false; } + protected EObject findGrammarElement(INode node, EObject obj) { + INode current = node; + String feature = obj.eContainingFeature().getName(); + while (current != null) { + EObject grammarElement = current.getGrammarElement(); + Assignment assignment = GrammarUtil.containingAssignment(grammarElement); + if (assignment != null && feature.equals(assignment.getFeature())) + return grammarElement; + if (grammarElement instanceof Action) { + Action action = (Action) grammarElement; + if (feature.equals(action.getFeature())) + return grammarElement; + else if (current == node && current instanceof ICompositeNode) { + INode child = ((ICompositeNode) current).getFirstChild(); + while (child instanceof ICompositeNode) { + EObject grammarElement2 = child.getGrammarElement(); + Assignment assignment2 = GrammarUtil.containingAssignment(grammarElement2); + if (assignment2 != null && feature.equals(assignment2.getFeature())) + return grammarElement2; + // if (child.hasDirectSemanticElement() && child.getSemanticElement() != obj) + // break; + child = ((ICompositeNode) child).getFirstChild(); + } + } + } + if (current.hasDirectSemanticElement() && current.getSemanticElement() != obj) + return null; + current = current.getParent(); + } + return null; + } + protected void process(INode node, NodeModelBasedRegionAccess access) { NodeEObjectRegion tokens = stack.peek(); boolean creator = isEObjectRoot(node); @@ -155,10 +188,13 @@ public class NodeModelBasedRegionAccessBuilder { stack.push(tokens); } if (tokens.getSemanticElement() == null) { - if (node.getParent() == null) + if (node.getParent() == null) { tokens.setSemantcElement(resource.getContents().get(0)); - else if (node.hasDirectSemanticElement()) + tokens.setGrammarElement(node.getGrammarElement()); + } else if (node.hasDirectSemanticElement()) { tokens.setSemantcElement(node.getSemanticElement()); + tokens.setGrammarElement(findGrammarElement(node, tokens.getSemanticElement())); + } } if (include(node)) { if (node instanceof ICompositeNode) { @@ -179,6 +215,12 @@ public class NodeModelBasedRegionAccessBuilder { EObject semanticElement = popped.getSemanticElement(); if (semanticElement == null) throw new IllegalStateException(); + if (!stack.isEmpty() && semanticElement.eContainer() != stack.peek().getSemanticElement()) + throw new IllegalStateException(); + EObject grammarElement = popped.getGrammarElement(); + if (grammarElement == null) { + throw new IllegalStateException(); + } NodeEObjectRegion old = eObjToTokens.put(semanticElement, popped); if (old != null) throw new IllegalStateException(); diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/StringBasedRegionAccess.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/StringBasedRegionAccess.java index 5fb4506f6..2444bf0ad 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/StringBasedRegionAccess.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/StringBasedRegionAccess.java @@ -7,6 +7,7 @@ *******************************************************************************/ package org.eclipse.xtext.formatting2.regionaccess.internal; +import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.EObject; @@ -14,6 +15,7 @@ import org.eclipse.xtext.formatting2.regionaccess.IEObjectRegion; import org.eclipse.xtext.formatting2.regionaccess.ITextSegment; import org.eclipse.xtext.resource.XtextResource; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; /** @@ -84,4 +86,9 @@ public class StringBasedRegionAccess extends AbstractRegionAccess { return string.substring(offset, offset + length); } + @Override + public List regionsForAllEObjects() { + return ImmutableList. copyOf(eObjectToTokens.values()); + } + } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/StringEObjectRegion.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/StringEObjectRegion.java index 094b718b5..053202d53 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/StringEObjectRegion.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/StringEObjectRegion.java @@ -8,23 +8,16 @@ package org.eclipse.xtext.formatting2.regionaccess.internal; import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.AbstractElement; /** * @author Moritz Eysholdt - Initial contribution and API */ public class StringEObjectRegion extends AbstractEObjectRegion { - private final AbstractElement grammarElement; - public StringEObjectRegion(StringBasedRegionAccess access, AbstractElement grammarElement, - EObject semanticElement) { + public StringEObjectRegion(StringBasedRegionAccess access, EObject grammarElement, EObject semanticElement) { super(access); - this.grammarElement = grammarElement; + this.setGrammarElement(grammarElement); this.setSemantcElement(semanticElement); } - @Override - public AbstractElement getGrammarElement() { - return grammarElement; - } } \ No newline at end of file diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/TextRegionAccessBuildingSequencer.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/TextRegionAccessBuildingSequencer.java index fe6eda9e4..a49efe655 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/TextRegionAccessBuildingSequencer.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/formatting2/regionaccess/internal/TextRegionAccessBuildingSequencer.java @@ -157,7 +157,7 @@ public class TextRegionAccessBuildingSequencer implements ISequenceAcceptor { return true; } - protected StringEObjectRegion enterEObject(AbstractElement ele, EObject semanticChild) { + protected StringEObjectRegion enterEObject(EObject ele, EObject semanticChild) { StringEObjectRegion tokens = new StringEObjectRegion(regionAccess, ele, semanticChild); regionAccess.add(tokens); tokens.setLeadingHiddenRegion(last); @@ -201,10 +201,10 @@ public class TextRegionAccessBuildingSequencer implements ISequenceAcceptor { // not relevant } - public TextRegionAccessBuildingSequencer withRoot(EObject root) { + public TextRegionAccessBuildingSequencer withRoot(EObject ctx, EObject root) { this.regionAccess = new StringBasedRegionAccess((XtextResource) root.eResource()); this.last = createHiddenRegion(); - this.regionAccess.setRootEObject(enterEObject(null, root)); + this.regionAccess.setRootEObject(enterEObject(ctx, root)); return this; } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/impl/Serializer.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/impl/Serializer.java index 97f642b18..9c4293923 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/impl/Serializer.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/serializer/impl/Serializer.java @@ -129,7 +129,7 @@ public class Serializer implements ISerializer { EObject context = getContext(obj); TextRegionAccessBuilder builder = textRegionBuilderProvider.get(); ISerializationDiagnostic.Acceptor errors = ISerializationDiagnostic.EXCEPTION_THROWING_ACCEPTOR; - serialize(obj, context, builder.forSequence(obj), errors); + serialize(obj, context, builder.forSequence(context, obj), errors); ITextRegionAccess regionAccess = builder.create(); return regionAccess; } diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/formatting2/regionaccess/internal/RegionAccessTest.xtend b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/formatting2/regionaccess/internal/RegionAccessTest.xtend index c954a728c..7ff6638b3 100644 --- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/formatting2/regionaccess/internal/RegionAccessTest.xtend +++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/formatting2/regionaccess/internal/RegionAccessTest.xtend @@ -39,11 +39,11 @@ class RegionAccessTest { 1 foo '''.toString.trim === ''' 0 0 Hidden - Start Simple'foo' + Start Simple'foo' via Root 0 1 Semantic "1" Simple:'1' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 3 Semantic "foo" Simple:name=ID - End Simple'foo' + End Simple'foo' via Root 5 0 Hidden ''' } @@ -53,12 +53,13 @@ class RegionAccessTest { 2 foo '''.toString.trim === ''' 0 0 Hidden - Start Delegation + Start Delegation via Root 0 1 Semantic "2" Delegation:'2' 1 1 Hidden " " Whitespace:TerminalRule'WS' - Start delegate=Delegate'foo' + Start delegate=Delegate'foo' via Delegation:delegate=Delegate 2 3 Semantic "foo" Delegate:name=ID - End Delegation, delegate=Delegate'foo' + End delegate=Delegate'foo' via Delegation:delegate=Delegate + End Delegation via Root 5 0 Hidden ''' } @@ -68,11 +69,11 @@ class RegionAccessTest { 3 foo '''.toString.trim === ''' 0 0 Hidden - Start Delegate'foo' + Start Delegate'foo' via Root 0 1 Semantic "3" Unassigned:'3' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 3 Semantic "foo" Delegate:name=ID - End Delegate'foo' + End Delegate'foo' via Root 5 0 Hidden ''' } @@ -82,14 +83,15 @@ class RegionAccessTest { 4 prefix foo '''.toString.trim === ''' 0 0 Hidden - Start PrefixedUnassigned + Start PrefixedUnassigned via Root 0 1 Semantic "4" PrefixedUnassigned:'4' 1 1 Hidden " " Whitespace:TerminalRule'WS' - Start delegate=Delegate'foo' + Start delegate=Delegate'foo' via PrefixedUnassigned:delegate=PrefixedDelegate 2 6 Semantic "prefix" PrefixedDelegate:'prefix' 8 1 Hidden " " Whitespace:TerminalRule'WS' 9 3 Semantic "foo" Delegate:name=ID - End PrefixedUnassigned, delegate=Delegate'foo' + End delegate=Delegate'foo' via PrefixedUnassigned:delegate=PrefixedDelegate + End PrefixedUnassigned via Root 12 0 Hidden ''' } @@ -99,18 +101,19 @@ class RegionAccessTest { 5 a + b '''.toString.trim === ''' 0 0 Hidden - Start Add + Start Add via Root 0 1 Semantic "5" Root:'5' 1 1 Hidden " " Whitespace:TerminalRule'WS' - Start left=Named'a' + Start left=Named'a' via Expression:{Add.left=} 2 1 Semantic "a" Primary:name=ID - End left=Named'a' + End left=Named'a' via Expression:{Add.left=} 3 1 Hidden " " Whitespace:TerminalRule'WS' 4 1 Semantic "+" Expression:'+' 5 1 Hidden " " Whitespace:TerminalRule'WS' - Start right=Named'b' + Start right=Named'b' via Expression:right=Primary 6 1 Semantic "b" Primary:name=ID - End Add, right=Named'b' + End right=Named'b' via Expression:right=Primary + End Add via Root 7 0 Hidden ''' } @@ -120,30 +123,31 @@ class RegionAccessTest { 5 (a + b) + c '''.toString.trim === ''' 0 0 Hidden - Start Add + Start Add via Root 0 1 Semantic "5" Root:'5' 1 1 Hidden " " Whitespace:TerminalRule'WS' - Start left=Add + Start left=Add via Expression:{Add.left=} 2 1 Semantic "(" Parenthesized:'(' 3 0 Hidden - Start left=Named'a' + Start left=Named'a' via Expression:{Add.left=} 3 1 Semantic "a" Primary:name=ID - End left=Named'a' + End left=Named'a' via Expression:{Add.left=} 4 1 Hidden " " Whitespace:TerminalRule'WS' 5 1 Semantic "+" Expression:'+' 6 1 Hidden " " Whitespace:TerminalRule'WS' - Start right=Named'b' + Start right=Named'b' via Expression:right=Primary 7 1 Semantic "b" Primary:name=ID - End right=Named'b' + End right=Named'b' via Expression:right=Primary 8 0 Hidden 8 1 Semantic ")" Parenthesized:')' - End left=Add + End left=Add via Expression:{Add.left=} 9 1 Hidden " " Whitespace:TerminalRule'WS' 10 1 Semantic "+" Expression:'+' 11 1 Hidden " " Whitespace:TerminalRule'WS' - Start right=Named'c' + Start right=Named'c' via Expression:right=Primary 12 1 Semantic "c" Primary:name=ID - End Add, right=Named'c' + End right=Named'c' via Expression:right=Primary + End Add via Root 13 0 Hidden ''' } @@ -153,7 +157,7 @@ class RegionAccessTest { 6 (unassigned foo) '''.toString.trim === ''' 0 0 Hidden - Start Action + Start Action via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -163,7 +167,7 @@ class RegionAccessTest { 14 3 Semantic "foo" Mixed:ID 17 0 Hidden 17 1 Semantic ")" Mixed:')' - End Action + End Action via Root 18 0 Hidden ''' } @@ -173,7 +177,7 @@ class RegionAccessTest { 6 (unassigned datatype foo) '''.toString.trim === ''' 0 0 Hidden - Start Action + Start Action via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -183,7 +187,7 @@ class RegionAccessTest { 14 12 Semantic "datatyp..." Mixed:Datatype 26 0 Hidden 26 1 Semantic ")" Mixed:')' - End Action + End Action via Root 27 0 Hidden ''' } @@ -193,7 +197,7 @@ class RegionAccessTest { 6 (unassigned datatype datatype foo) '''.toString.trim === ''' 0 0 Hidden - Start Action + Start Action via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -203,7 +207,7 @@ class RegionAccessTest { 14 21 Semantic "datatyp..." Mixed:Datatype 35 0 Hidden 35 1 Semantic ")" Mixed:')' - End Action + End Action via Root 36 0 Hidden ''' } @@ -213,13 +217,13 @@ class RegionAccessTest { 6 () '''.toString.trim === ''' 0 0 Hidden - Start Action + Start Action via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' 3 0 Hidden 3 1 Semantic ")" Mixed:')' - End Action + End Action via Root 4 0 Hidden ''' } @@ -229,7 +233,7 @@ class RegionAccessTest { 6 (()) '''.toString.trim === ''' 0 0 Hidden - Start Action + Start Action via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -239,7 +243,7 @@ class RegionAccessTest { 4 1 Semantic ")" Mixed:')' 5 0 Hidden 5 1 Semantic ")" Mixed:')' - End Action + End Action via Root 6 0 Hidden ''' } @@ -249,7 +253,7 @@ class RegionAccessTest { 6 ((())) '''.toString.trim === ''' 0 0 Hidden - Start Action + Start Action via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -263,7 +267,7 @@ class RegionAccessTest { 6 1 Semantic ")" Mixed:')' 7 0 Hidden 7 1 Semantic ")" Mixed:')' - End Action + End Action via Root 8 0 Hidden ''' } @@ -273,7 +277,7 @@ class RegionAccessTest { 6 (((foo))) '''.toString.trim === ''' 0 0 Hidden - Start Mixed'foo' + Start Mixed'foo' via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -289,7 +293,7 @@ class RegionAccessTest { 9 1 Semantic ")" Mixed:')' 10 0 Hidden 10 1 Semantic ")" Mixed:')' - End Mixed'foo' + End Mixed'foo' via Root 11 0 Hidden ''' } @@ -299,14 +303,14 @@ class RegionAccessTest { 6 (child(((foo)))) '''.toString.trim === ''' 0 0 Hidden - Start Mixed + Start Mixed via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' 3 0 Hidden 3 5 Semantic "child" Mixed:'child' 8 0 Hidden - Start eobj=Mixed'foo' + Start eobj=Mixed'foo' via Mixed:eobj=Mixed 8 1 Semantic "(" Mixed:'(' 9 0 Hidden 9 1 Semantic "(" Mixed:'(' @@ -320,10 +324,10 @@ class RegionAccessTest { 15 1 Semantic ")" Mixed:')' 16 0 Hidden 16 1 Semantic ")" Mixed:')' - End eobj=Mixed'foo' + End eobj=Mixed'foo' via Mixed:eobj=Mixed 17 0 Hidden 17 1 Semantic ")" Mixed:')' - End Mixed + End Mixed via Root 18 0 Hidden ''' } @@ -333,7 +337,7 @@ class RegionAccessTest { 6 (datatype foo) '''.toString.trim === ''' 0 0 Hidden - Start Mixed + Start Mixed via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -341,7 +345,7 @@ class RegionAccessTest { 3 12 Semantic "datatyp..." Mixed:datatype=Datatype 15 0 Hidden 15 1 Semantic ")" Mixed:')' - End Mixed + End Mixed via Root 16 0 Hidden ''' } @@ -351,7 +355,7 @@ class RegionAccessTest { 6 (datatype datatype foo) '''.toString.trim === ''' 0 0 Hidden - Start Mixed + Start Mixed via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -359,7 +363,7 @@ class RegionAccessTest { 3 21 Semantic "datatyp..." Mixed:datatype=Datatype 24 0 Hidden 24 1 Semantic ")" Mixed:')' - End Mixed + End Mixed via Root 25 0 Hidden ''' } @@ -369,20 +373,20 @@ class RegionAccessTest { 6 (foo) action (ref foo) end '''.toString.trim === ''' 0 0 Hidden - Start AssignedAction + Start AssignedAction via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' - Start child=Mixed'foo' + Start child=Mixed'foo' via Mixed:{AssignedAction.child=} 2 1 Semantic "(" Mixed:'(' 3 0 Hidden 3 3 Semantic "foo" Mixed:name=ID 6 0 Hidden 6 1 Semantic ")" Mixed:')' - End child=Mixed'foo' + End child=Mixed'foo' via Mixed:{AssignedAction.child=} 7 1 Hidden " " Whitespace:TerminalRule'WS' 8 6 Semantic "action" Mixed:'action' 14 1 Hidden " " Whitespace:TerminalRule'WS' - Start body=Mixed + Start body=Mixed via Mixed:body=Mixed 15 1 Semantic "(" Mixed:'(' 16 0 Hidden 16 3 Semantic "ref" Mixed:'ref' @@ -390,10 +394,10 @@ class RegionAccessTest { 20 3 Semantic "foo" Mixed:ref=[Mixed|ID] 23 0 Hidden 23 1 Semantic ")" Mixed:')' - End body=Mixed + End body=Mixed via Mixed:body=Mixed 24 1 Hidden " " Whitespace:TerminalRule'WS' 25 3 Semantic "end" Mixed:'end' - End AssignedAction + End AssignedAction via Root 28 0 Hidden ''' } @@ -403,7 +407,7 @@ class RegionAccessTest { 6 (lit1) '''.toString.trim === ''' 0 0 Hidden - Start Mixed + Start Mixed via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' 2 1 Semantic "(" Mixed:'(' @@ -411,7 +415,7 @@ class RegionAccessTest { 3 4 Semantic "lit1" Mixed:lit=Enum 7 0 Hidden 7 1 Semantic ")" Mixed:')' - End Mixed + End Mixed via Root 8 0 Hidden ''' } @@ -421,19 +425,19 @@ class RegionAccessTest { 6 (foo) action '''.toString.trim === ''' 0 0 Hidden - Start AssignedAction + Start AssignedAction via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' - Start child=Mixed'foo' + Start child=Mixed'foo' via Mixed:{AssignedAction.child=} 2 1 Semantic "(" Mixed:'(' 3 0 Hidden 3 3 Semantic "foo" Mixed:name=ID 6 0 Hidden 6 1 Semantic ")" Mixed:')' - End child=Mixed'foo' + End child=Mixed'foo' via Mixed:{AssignedAction.child=} 7 1 Hidden " " Whitespace:TerminalRule'WS' 8 6 Semantic "action" Mixed:'action' - End AssignedAction + End AssignedAction via Root 14 0 Hidden ''' } @@ -443,22 +447,23 @@ class RegionAccessTest { 6 (foo) action action '''.toString.trim === ''' 0 0 Hidden - Start AssignedAction + Start AssignedAction via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' - Start child=AssignedAction, child=Mixed'foo' + Start child=AssignedAction via Mixed:{AssignedAction.child=} + Start child=Mixed'foo' via Mixed:{AssignedAction.child=} 2 1 Semantic "(" Mixed:'(' 3 0 Hidden 3 3 Semantic "foo" Mixed:name=ID 6 0 Hidden 6 1 Semantic ")" Mixed:')' - End child=Mixed'foo' + End child=Mixed'foo' via Mixed:{AssignedAction.child=} 7 1 Hidden " " Whitespace:TerminalRule'WS' 8 6 Semantic "action" Mixed:'action' - End child=AssignedAction + End child=AssignedAction via Mixed:{AssignedAction.child=} 14 1 Hidden " " Whitespace:TerminalRule'WS' 15 6 Semantic "action" Mixed:'action' - End AssignedAction + End AssignedAction via Root 21 0 Hidden ''' } @@ -468,20 +473,21 @@ class RegionAccessTest { 6 () action action '''.toString.trim === ''' 0 0 Hidden - Start AssignedAction + Start AssignedAction via Root 0 1 Semantic "6" Root:'6' 1 1 Hidden " " Whitespace:TerminalRule'WS' - Start child=Action, child=AssignedAction + Start child=AssignedAction via Mixed:{AssignedAction.child=} + Start child=Action via Mixed:{AssignedAction.child=} 2 1 Semantic "(" Mixed:'(' 3 0 Hidden 3 1 Semantic ")" Mixed:')' - End child=Action + End child=Action via Mixed:{AssignedAction.child=} 4 1 Hidden " " Whitespace:TerminalRule'WS' 5 6 Semantic "action" Mixed:'action' - End child=AssignedAction + End child=AssignedAction via Mixed:{AssignedAction.child=} 11 1 Hidden " " Whitespace:TerminalRule'WS' 12 6 Semantic "action" Mixed:'action' - End AssignedAction + End AssignedAction via Root 18 0 Hidden ''' }