/* * Copyright 2004 The Closure Compiler Authors. * * 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.javascript.jscomp; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.TokenStream; /** * Utility class that extracts the qualified name out of a node. * Useful when trying to get a human-friendly string representation of * a property node that can be used to describe the node or name * related nodes based on it (as done by the NameAnonymousFunctions * compiler pass). * */ class NodeNameExtractor { private final char delimiter; private int nextUniqueInt = 0; NodeNameExtractor(char delimiter) { this.delimiter = delimiter; } /** * Returns a qualified name of the specified node. Dots and brackets * are changed to the delimiter passed in when constructing the * NodeNameExtractor object. We also replace ".prototype" with the * delimiter to keep names short, while still differentiating them * from static properties. (Prototype properties will end up * looking like "a$b$$c" if this.delimiter = '$'.) */ String getName(Node node) { switch (node.getToken()) { case CLASS: case FUNCTION: return NodeUtil.getName(node); case GETPROP: Node lhsOfDot = node.getFirstChild(); Node rhsOfDot = lhsOfDot.getNext(); String lhsOfDotName = getName(lhsOfDot); String rhsOfDotName = getName(rhsOfDot); if ("prototype".equals(rhsOfDotName)) { return lhsOfDotName + delimiter; } else { return lhsOfDotName + delimiter + rhsOfDotName; } case GETELEM: Node outsideBrackets = node.getFirstChild(); Node insideBrackets = outsideBrackets.getNext(); String nameOutsideBrackets = getName(outsideBrackets); String nameInsideBrackets = getName(insideBrackets); if ("prototype".equals(nameInsideBrackets)) { return nameOutsideBrackets + delimiter; } else { return nameOutsideBrackets + delimiter + nameInsideBrackets; } case NAME: return node.getString(); case STRING: case STRING_KEY: case MEMBER_FUNCTION_DEF: return TokenStream.isJSIdentifier(node.getString()) ? node.getString() : ("__" + nextUniqueInt++); case NUMBER: return NodeUtil.getStringValue(node); case THIS: return "this"; case CALL: return getName(node.getFirstChild()); default: StringBuilder sb = new StringBuilder(); for (Node child = node.getFirstChild(); child != null; child = child.getNext()) { if (sb.length() > 0) { sb.append(delimiter); } sb.append(getName(child)); } return sb.toString(); } } }