/* * Copyright 2015 Google Inc. * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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.gwt.dev.js.ast; import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap; import com.google.gwt.dev.js.JsUtils; import com.google.gwt.dev.js.ast.JsVars.JsVar; import com.google.gwt.thirdparty.guava.common.collect.Sets; import java.util.Set; /** * Verifies that the JavaScript AST and the map are consistent. */ public class JavaScriptVerifier { public static void verify(JsProgram jsProgram, JavaToJavaScriptMap map) { if (!JavaScriptVerifier.class.desiredAssertionStatus()) { return; } verifyTopLevelMethodMapping(jsProgram, map); verifyGlobalNameOrdering(jsProgram, map); } private static void verifyGlobalNameOrdering(JsProgram jsProgram, final JavaToJavaScriptMap map) { final Set<JsName> declaredEntities = Sets.newHashSet(); new JsVisitor() { @Override public boolean visit(JsFunction x, JsContext ctx) { declaredEntities.add(x.getName()); // Do not examine function bodies. return false; } }.accept(jsProgram); new JsVisitor() { @Override public boolean visit(JsFunction x, JsContext ctx) { // Do not examine function bodies. return false; } @Override public boolean visit(JsVars x, JsContext ctx) { for (JsVar var : x) { declaredEntities.add(var.getName()); } return true; } @Override public boolean visit(JsBinaryOperation x, JsContext ctx) { if (x.getOperator().isAssignment()) { JsNameRef nameRef = (JsNameRef) x.getArg1(); if (nameRef.getQualifier() == null) { declaredEntities.add(nameRef.getName()); } } return true; } @Override public boolean visit(JsObjectLiteral x, JsContext ctx) { for (JsPropertyInitializer propertyInitializer : x.getPropertyInitializers()) { accept(propertyInitializer.getValueExpr()); } return false; } @Override public void endVisit(JsNameRef x, JsContext ctx) { if (x.getQualifier() != null || !x.getName().isObfuscatable()) { return; } assert declaredEntities.contains(x.getName()) : x.getName() + " reference found before " + " definition."; map.nameToField(x.getName()); } }.accept(jsProgram); } public static void verifyTopLevelMethodMapping(JsProgram jsProgram, JavaToJavaScriptMap map) { for (JsProgramFragment fragment : jsProgram.getFragments()) { for (JsStatement statement : fragment.getGlobalBlock().getStatements()) { JsFunction function = JsUtils.isFunctionDeclaration(statement); if (function == null) { continue; } assert map.nameToMethod(function.getName()) == map.methodForStatement(statement); } } } private JavaScriptVerifier() { } }