/* * Copyright (C) 2012-2016 NS Solutions Corporation * * 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.htmlhifive.tools.rhino; import java.util.HashSet; import java.util.Set; import org.mozilla.javascript.Token; import org.mozilla.javascript.ast.Assignment; import org.mozilla.javascript.ast.AstNode; import org.mozilla.javascript.ast.ExpressionStatement; import org.mozilla.javascript.ast.FunctionCall; import org.mozilla.javascript.ast.FunctionNode; import org.mozilla.javascript.ast.Name; import org.mozilla.javascript.ast.NodeVisitor; import org.mozilla.javascript.ast.PropertyGet; import org.mozilla.javascript.ast.VariableDeclaration; import org.mozilla.javascript.ast.VariableInitializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * ログ出力を行っているコードを削除する. */ public class SuppressLoggerVisitor implements NodeVisitor { private static Logger logger = LoggerFactory.getLogger(SuppressLoggerVisitor.class); /** 削除対象ロガー名. */ public static final String FW_LOGGER_NAME = "fwLogger"; /** 生成したロガーの名前. */ private Set<String> loggerNames = new HashSet<String>(); /** 出力ストリーム. */ // private PrintStream out; /** コンストラクタ. */ public SuppressLoggerVisitor() { // this(System.out); } /** コンストラクタ. */ // public SuppressLoggerVisitor(PrintStream systemOut) { // // // out = systemOut; // } @Override public boolean visit(AstNode node) { if (node instanceof FunctionCall) { FunctionCall an = (FunctionCall) node; AstNode target = an.getTarget(); String id = getId(target); if (id.endsWith("createLogger")) { String loggerName = removeLoggerInitialization(node); if (null != loggerName) { loggerNames.add(loggerName); } } if (useLogger(id)) { removeNode(node); } } return true; } public boolean useLogger(String id) { if (null == id) { return false; } for (String loggerName : loggerNames) { if (id.startsWith(loggerName)) { return true; } } return false; } /** * ロガーの初期化コードを削除する. * * @param target * @return */ public String removeLoggerInitialization(AstNode target) { AstNode parent = target.getParent(); if (parent instanceof VariableInitializer) { VariableInitializer varInit = (VariableInitializer) parent; AstNode grandParent = varInit.getParent(); if (!(grandParent instanceof VariableDeclaration)) { throw new IllegalStateException("VariableInitializer is not define in VariableDeclaration."); } String id = getId(varInit.getTarget()); if (id.endsWith(FW_LOGGER_NAME)) { VariableDeclaration varDecl = (VariableDeclaration) grandParent; int size = varDecl.getVariables().size(); if (size > 1) { varDecl.removeChild(varInit); // TODO ","とかインデントとかもセットで消さないといかん筈. logger.trace(SourceMaker.toSource(varInit)); // out.println(SourceMaker.toSource(varInit)); } else { removeNode(varDecl); } } return id; } else if (parent instanceof Assignment) { Assignment assignment = (Assignment) parent; AstNode left = assignment.getLeft(); String id = getId(left); if (id.endsWith(FW_LOGGER_NAME)) { removeNode(parent); } return id; } else { logger.trace("[" + parent.getLineno() + "] return statement is not assigned !"); // out.println("[" + parent.getLineno() + "] return statement is not assigned !"); return null; } } /** * 対象ノードを削除する. * * @param node */ public void removeNode(AstNode node) { AstNode parent = node.getParent(); AstNode target = node; if (parent instanceof ExpressionStatement) { target = parent; parent = parent.getParent(); } parent.removeChild(target); logger.debug("[lno:" + target.getLineno() + "] " + SourceMaker.toSource(target).trim()); // out.println("[lno:" + target.getLineno() + "] " + SourceMaker.toSource(target).trim()); } /** * ノードのId情報を取得する. * * @param node * @return */ public String getId(AstNode node) { int type = node.getType(); switch (type) { case Token.GETPROP: PropertyGet pg = (PropertyGet) node; AstNode left = pg.getLeft(); AstNode right = pg.getRight(); return (getId(left) + "." + getId(right)); case Token.NAME: return ((Name) node).getIdentifier(); case Token.FUNCTION: return ((FunctionNode) node).getName(); case Token.LP: return node.getClass().toString(); default: return "[" + Util.typeToName(node) + "]"; } } }