[xtext][locationInFileProvider] Improved the computation of significant and full regions

This commit is contained in:
Sebastian Zarnekow 2012-03-08 11:55:23 +01:00
parent cc25489506
commit 41df70b922
2 changed files with 55 additions and 4 deletions

View file

@ -28,6 +28,8 @@ import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.SyntaxErrorMessage;
import org.eclipse.xtext.nodemodel.impl.AbstractNode;
import org.eclipse.xtext.resource.EObjectAtOffsetHelper;
import org.eclipse.xtext.resource.ILocationInFileProvider;
import com.google.common.collect.Lists;
@ -35,6 +37,11 @@ import com.google.common.collect.Lists;
* The NodeModelUtils are a collection of useful methods when dealing with the node model directly. They encapsulate the
* default construction semantics of the node model as it is created by the parser.
*
* This API is quite low level and internal functionality of the framework relies on the implemened contracts.
* Clients should rather use the language specific APIs that provide almost the same functionality, e.g.
* {@link ILocationInFileProvider} and {@link EObjectAtOffsetHelper} if they want to to access the region
* of a {@link EObject semantic object}.
*
* @author Sebastian Zarnekow - Initial contribution and API
*/
public class NodeModelUtils {
@ -104,6 +111,7 @@ public class NodeModelUtils {
/**
* Returns the node that is directly associated with the given object by means of an EMF-Adapter.
*
* @param object the semantic object whose direct node should be provided.
* @return the node that is directly associated with the given object.
* @see NodeModelUtils#findActualNodeFor(EObject)
*/
@ -178,9 +186,23 @@ public class NodeModelUtils {
}
/**
* Returns the node that covers all assigned values of the given object. It handles the semantics of {@link Action
* actions} and {@link RuleCall unassigned rule calls}.
* <p>Returns the node that covers all assigned values of the given object. It handles the semantics of {@link Action
* actions} and {@link RuleCall unassigned rule calls}. The returned node will include unassigned surrounding leafs,
* e.g. if you use something like {@code Parenthesized expressions} redundant parentheses will be part of the returned node.</p>
* <p>Consider the following simple expression (a number literal):
* <pre>
* ((1))
* </pre>
* Assuming it was parsed from a grammar like this:
* <pre>
* Expression: Number | Parentheses;
* Parentheses: '(' Expression ')';
* Number: value=INT
* </pre>
* The actual node for the only semantic object that was produced from the input {@code ((1))} is the root node
* even though the minimal node would be the one with the text {@code 1}.
*
* @param semanticObject the semantic object whose node should be provided.
* @return the node that covers all assigned values of the given object.
*/
public static ICompositeNode findActualNodeFor(EObject semanticObject) {

View file

@ -20,6 +20,8 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.nodemodel.ICompositeNode;
@ -72,7 +74,7 @@ public class DefaultLocationInFileProvider implements ILocationInFileProvider, I
* @since 2.3
*/
protected ITextRegion doGetTextRegion(EObject obj, @NonNull RegionDescription query) {
ICompositeNode node = NodeModelUtils.findActualNodeFor(obj);
ICompositeNode node = findNodeFor(obj);
if (node == null) {
if (obj.eContainer() == null)
return ITextRegion.EMPTY_REGION;
@ -210,7 +212,7 @@ public class DefaultLocationInFileProvider implements ILocationInFileProvider, I
}
List<INode> resultNodes = Lists.newArrayList();
final ICompositeNode startNode = NodeModelUtils.getNode(obj);
final ICompositeNode startNode = findNodeFor(obj);
INode keywordNode = null;
// use LeafNodes instead of children?
for (INode child : startNode.getChildren()) {
@ -299,4 +301,31 @@ public class DefaultLocationInFileProvider implements ILocationInFileProvider, I
protected boolean isHidden(INode node) {
return node instanceof ILeafNode && ((ILeafNode) node).isHidden();
}
/**
* Returns the smallest node that covers all assigned values of the given object. It handles the semantics of {@link Action
* actions} and {@link RuleCall unassigned rule calls}.
*
* @return the minimal node that covers all assigned values of the given object.
* @since 2.3
*/
protected ICompositeNode findNodeFor(EObject semanticObject) {
ICompositeNode result = NodeModelUtils.getNode(semanticObject);
if (result != null) {
ICompositeNode node = result;
while (GrammarUtil.containingAssignment(node.getGrammarElement()) == null && node.getParent() != null && !node.getParent().hasDirectSemanticElement()) {
ICompositeNode parent = node.getParent();
if (node.hasSiblings()) {
for(INode sibling: parent.getChildren()) {
if (GrammarUtil.containingAssignment(sibling.getGrammarElement()) != null) {
result = parent;
}
}
}
node = parent;
}
}
return result;
}
}