All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.xtext.nodemodel.impl.InvariantChecker Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2010 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.nodemodel.impl;

import java.util.Iterator;

import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;

/**
 * @author Sebastian Zarnekow - Initial contribution and API
 * @noextend This class is not intended to be subclassed by clients.
 */
public class InvariantChecker {

	public static class InconsistentNodeModelException extends RuntimeException {

		private static final long serialVersionUID = 1L;

		public InconsistentNodeModelException(String message, Throwable cause) {
			super(message, cause);
		}

		public InconsistentNodeModelException(String message) {
			super(message);
		}
		
	}
	
	/**
	 * Whether we have already passed an exception.
	 */
	private boolean exceptionSeen;
	
	/**
	 * Assert the invariant of completely build node model.
	 * Checks that every pointer is correct, e.g.
	 * 
    *
  • a parent points to its first child,
  • *
  • siblings point to the very same parent,
  • *
  • the offset and length data is in sync, and
  • *
  • no null fields are present (besides some empty first child pointers).
  • *
* @param node an arbitrary node of the complete node model that should be checked. * @throws InconsistentNodeModelException if the node is part of an inconsistent node tree. */ public void checkInvariant(INode node) throws InconsistentNodeModelException { try { doCheckInvariant(node.getRootNode()); } catch(ClassCastException e) { throw new InconsistentNodeModelException("node has no root node", e); } catch(NullPointerException e) { throw new InconsistentNodeModelException("node's pointer is null", e); } } protected void doCheckInvariant(ICompositeNode rootNode) { int length = doCheckCompositeNodeAndReturnTotalLength(rootNode, 0); if (length != rootNode.getTotalLength()) throw new InconsistentNodeModelException("node's computed length differs from actual total length"); } protected int doCheckCompositeNodeAndReturnTotalLength(ICompositeNode node, int startsAt) { if (node.getTotalOffset() != startsAt) throw new InconsistentNodeModelException("node with unexpected offset"); int length = 0; Iterator iter = ((CompositeNode) node).basicGetChildren().iterator(); while(iter.hasNext()) { INode child = iter.next(); length += doCheckChildNodeAndReturnTotalLength(child, node, startsAt + length); } if (length != node.getTotalLength()) throw new InconsistentNodeModelException("node's computed length differs from actual total length"); return length; } protected int doCheckChildNodeAndReturnTotalLength(INode child, ICompositeNode parent, int startsAt) { exceptionSeen |= child.getSyntaxErrorMessage() != null; if (((AbstractNode) child).basicGetNextSibling().basicGetPreviousSibling() != child) throw new InconsistentNodeModelException("child.next.previous != child"); if (((AbstractNode) child).basicGetPreviousSibling().basicGetNextSibling() != child) throw new InconsistentNodeModelException("child.previous.next != child"); if (((AbstractNode) child).basicGetPreviousSibling().basicGetParent() != ((AbstractNode) child).basicGetParent()) throw new InconsistentNodeModelException("child.previous.parent != child.parent"); if (((AbstractNode) child).basicGetNextSibling().basicGetParent() != ((AbstractNode) child).basicGetParent()) throw new InconsistentNodeModelException("child.next.parent != child.parent"); if (((AbstractNode) child).basicGetParent() != parent) { throw new InconsistentNodeModelException("node does not point to its parent"); } if (child instanceof ILeafNode) { if (child.getGrammarElement() == null) { if (!exceptionSeen) { throw new InconsistentNodeModelException("leaf node without grammar element"); } } return doCheckLeafNodeAndReturnLength((ILeafNode) child, startsAt); } else { if (child.getGrammarElement() == null) { throw new InconsistentNodeModelException("node without grammar element"); } return doCheckCompositeNodeAndReturnTotalLength((ICompositeNode) child, startsAt); } } protected int doCheckLeafNodeAndReturnLength(ILeafNode leafNode, int startsAt) { if (leafNode.getTotalOffset() != startsAt) throw new InconsistentNodeModelException("node with unexpected offset"); return leafNode.getTotalLength(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy