blob: 08190fab780b6fb81da2f8ac8f02b715122dd89f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 IBM Corporation 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.dom;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ArrayCreation;
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
@SuppressWarnings("rawtypes")
public class SourceRangeVerifier extends ASTVisitor {
public static boolean DEBUG = false;
public static boolean DEBUG_THROW = false;
private StringBuffer bugs;
/**
* Verifies proper node nesting as specified in {@link ASTParser#setKind(int)}:
* <p>
* Source ranges nest properly: the source range for a child is always
* within the source range of its parent, and the source ranges of sibling
* nodes never overlap.
* </p>
*
* @param node
* @return <code>null</code> if everything is OK; a list of errors otherwise
*/
public String process(ASTNode node) {
StringBuffer buffer = new StringBuffer();
this.bugs = buffer;
node.accept(this);
this.bugs = null;
if (buffer.length() == 0)
return null;
return buffer.toString();
}
public boolean preVisit2(ASTNode node) {
ASTNode previous = null;
List properties = node.structuralPropertiesForType();
for (int i = 0; i < properties.size(); i++) {
StructuralPropertyDescriptor property = (StructuralPropertyDescriptor) properties.get(i);
if (property.isChildProperty()) {
ASTNode child = (ASTNode) node.getStructuralProperty(property);
if (child != null) {
boolean ok = checkChild(node, previous, child);
if (ok) {
previous = child;
} else {
return false;
}
}
} else if (property.isChildListProperty()) {
List children = (List) node.getStructuralProperty(property);
for (int j= 0; j < children.size(); j++) {
ASTNode child = (ASTNode) children.get(j);
boolean ok = checkChild(node, previous, child);
if (ok) {
previous = child;
} else {
return false;
}
}
}
}
return true;
}
private boolean checkChild(ASTNode parent, ASTNode previous, ASTNode child) {
if ((parent.getFlags() & (ASTNode.RECOVERED | ASTNode.MALFORMED)) != 0
|| (child.getFlags() & (ASTNode.RECOVERED | ASTNode.MALFORMED)) != 0)
return false;
int parentStart = parent.getStartPosition();
int parentEnd = parentStart + parent.getLength();
int childStart = child.getStartPosition();
int childEnd = childStart + child.getLength();
if (previous != null) {
// Turn a blind eye on a known problem ... see https://bugs.eclipse.org/391894#c4
if (child.getLocationInParent() == ArrayCreation.DIMENSIONS_PROPERTY)
return false;
int previousStart = previous.getStartPosition();
int previousEnd = previousStart + previous.getLength();
if (childStart < previousEnd) {
String bug = "- parent [" + parentStart + ", " + parentEnd + "] " + parent.getClass().getName() + '\n' //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ " previous [" + previousStart + ", " + previousEnd + "] " + previous.getClass().getName() + '\n'//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ " " + child.getLocationInParent().getId() + " [" + childStart + ", " + childEnd + "] " + child.getClass().getName() + '\n'; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
this.bugs.append(bug);
}
}
if (!(parentStart <= childStart && childEnd <= parentEnd)) {
String bug = "- parent [" + parentStart + ", " + parentEnd + "] " + parent.getClass().getName() + '\n' //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ " " + child.getLocationInParent().getId() + " [" + childStart + ", " + childEnd + "] " + child.getClass().getName() + '\n'; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
this.bugs.append(bug);
}
return true;
}
}