/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.engine.parser; import com.google.dart.engine.ast.AstNode; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.ast.visitor.UnifyingAstVisitor; import junit.framework.Assert; import java.util.ArrayList; /** * Instances of the class {@code AstValidator} are used to validate the correct construction of an * AST structure. */ public class AstValidator extends UnifyingAstVisitor<Void> { /** * A list containing the errors found while traversing the AST structure. */ private ArrayList<String> errors = new ArrayList<String>(); /** * Assert that no errors were found while traversing any of the AST structures that have been * visited. */ public void assertValid() { if (!errors.isEmpty()) { StringBuilder builder = new StringBuilder(); builder.append("Invalid AST structure:"); for (String message : errors) { builder.append("\r\n "); builder.append(message); } Assert.fail(builder.toString()); } } @Override public Void visitNode(AstNode node) { validate(node); return super.visitNode(node); } /** * Validate that the given AST node is correctly constructed. * * @param node the AST node being validated */ private void validate(AstNode node) { AstNode parent = node.getParent(); if (node instanceof CompilationUnit) { if (parent != null) { errors.add("Compilation units should not have a parent"); } } else { if (parent == null) { errors.add("No parent for " + node.getClass().getName()); } } if (node.getBeginToken() == null) { errors.add("No begin token for " + node.getClass().getName()); } if (node.getEndToken() == null) { errors.add("No end token for " + node.getClass().getName()); } int nodeStart = node.getOffset(); int nodeLength = node.getLength(); if (nodeStart < 0 || nodeLength < 0) { errors.add("No source info for " + node.getClass().getName()); } if (parent != null) { int nodeEnd = nodeStart + nodeLength; int parentStart = parent.getOffset(); int parentEnd = parentStart + parent.getLength(); if (nodeStart < parentStart) { errors.add("Invalid source start (" + nodeStart + ") for " + node.getClass().getName() + " inside " + parent.getClass().getName() + " (" + parentStart + ")"); } if (nodeEnd > parentEnd) { errors.add("Invalid source end (" + nodeEnd + ") for " + node.getClass().getName() + " inside " + parent.getClass().getName() + " (" + parentStart + ")"); } } } }