Search in sources :

Example 26 with Ref

use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.

the class CollapseProperties method flattenSimpleStubDeclaration.

/**
 * Flattens a stub declaration.
 * This is mostly a hack to support legacy users.
 */
private void flattenSimpleStubDeclaration(Name name, String alias) {
    Ref ref = Iterables.getOnlyElement(name.getRefs());
    Node nameNode = NodeUtil.newName(compiler, alias, ref.node, name.getFullName());
    Node varNode = IR.var(nameNode).useSourceInfoIfMissingFrom(nameNode);
    checkState(ref.node.getParent().isExprResult());
    Node parent = ref.node.getParent();
    Node grandparent = parent.getParent();
    grandparent.replaceChild(parent, varNode);
    compiler.reportChangeToEnclosingScope(varNode);
}
Also used : Ref(com.google.javascript.jscomp.GlobalNamespace.Ref) Node(com.google.javascript.rhino.Node)

Example 27 with Ref

use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.

the class CollapseProperties method declareVariablesForObjLitValues.

/**
 * Declares global variables to serve as aliases for the values in an object literal, optionally
 * removing all of the object literal's keys and values.
 *
 * @param alias The object literal's flattened name (e.g. "a$b$c")
 * @param objlit The OBJLIT node
 * @param varNode The VAR node to which new global variables should be added as children
 * @param nameToAddAfter The child of {@code varNode} after which new variables should be added
 *     (may be null)
 * @param varParent {@code varNode}'s parent
 */
private void declareVariablesForObjLitValues(Name objlitName, String alias, Node objlit, Node varNode, Node nameToAddAfter, Node varParent) {
    int arbitraryNameCounter = 0;
    boolean discardKeys = !objlitName.shouldKeepKeys();
    for (Node key = objlit.getFirstChild(), nextKey; key != null; key = nextKey) {
        Node value = key.getFirstChild();
        nextKey = key.getNext();
        // A computed property, or a get or a set can not be rewritten as a VAR.
        if (key.isGetterDef() || key.isSetterDef() || key.isComputedProp()) {
            continue;
        }
        // We generate arbitrary names for keys that aren't valid JavaScript
        // identifiers, since those keys are never referenced. (If they were,
        // this object literal's child names wouldn't be collapsible.) The only
        // reason that we don't eliminate them entirely is the off chance that
        // their values are expressions that have side effects.
        boolean isJsIdentifier = !key.isNumber() && TokenStream.isJSIdentifier(key.getString());
        String propName = isJsIdentifier ? key.getString() : String.valueOf(++arbitraryNameCounter);
        // If the name cannot be collapsed, skip it.
        String qName = objlitName.getFullName() + '.' + propName;
        Name p = nameMap.get(qName);
        if (p != null && !canCollapse(p)) {
            continue;
        }
        String propAlias = appendPropForAlias(alias, propName);
        Node refNode = null;
        if (discardKeys) {
            objlit.removeChild(key);
            value.detach();
        // Don't report a change here because the objlit has already been removed from the tree.
        } else {
            // Substitute a reference for the value.
            refNode = IR.name(propAlias);
            if (key.getBooleanProp(Node.IS_CONSTANT_NAME)) {
                refNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
            }
            key.replaceChild(value, refNode);
            compiler.reportChangeToEnclosingScope(refNode);
        }
        // Declare the collapsed name as a variable with the original value.
        Node nameNode = IR.name(propAlias);
        nameNode.addChildToFront(value);
        if (key.getBooleanProp(Node.IS_CONSTANT_NAME)) {
            nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
        }
        Node newVar = IR.var(nameNode).useSourceInfoIfMissingFromForTree(key);
        if (nameToAddAfter != null) {
            varParent.addChildAfter(newVar, nameToAddAfter);
        } else {
            varParent.addChildBefore(newVar, varNode);
        }
        compiler.reportChangeToEnclosingScope(newVar);
        nameToAddAfter = newVar;
        // for the same global name.)
        if (isJsIdentifier && p != null) {
            if (!discardKeys) {
                Ref newAlias = p.getDeclaration().cloneAndReclassify(Ref.Type.ALIASING_GET);
                newAlias.node = refNode;
                p.addRef(newAlias);
            }
            p.getDeclaration().node = nameNode;
            if (value.isFunction()) {
                checkForHosedThisReferences(value, key.getJSDocInfo(), p);
            }
        }
    }
}
Also used : Ref(com.google.javascript.jscomp.GlobalNamespace.Ref) Node(com.google.javascript.rhino.Node) Name(com.google.javascript.jscomp.GlobalNamespace.Name)

Example 28 with Ref

use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.

the class CollapseProperties method flattenPrefixes.

/**
 * Flattens all occurrences of a name as a prefix of subnames beginning
 * with a particular subname.
 *
 * @param n A global property name (e.g. "a.b.c.d")
 * @param alias A flattened prefix name (e.g. "a$b")
 * @param depth The difference in depth between the property name and
 *    the prefix name (e.g. 2)
 */
private void flattenPrefixes(String alias, Name n, int depth) {
    // Only flatten the prefix of a name declaration if the name being
    // initialized is fully qualified (i.e. not an object literal key).
    String originalName = n.getFullName();
    Ref decl = n.getDeclaration();
    if (decl != null && decl.node != null && decl.node.isGetProp()) {
        flattenNameRefAtDepth(alias, decl.node, depth, originalName);
    }
    for (Ref r : n.getRefs()) {
        if (r == decl) {
            // Declarations are handled separately.
            continue;
        }
        // have twins. We should only flatten one of the twins.
        if (r.getTwin() == null || r.isSet()) {
            flattenNameRefAtDepth(alias, r.node, depth, originalName);
        }
    }
    if (n.props != null) {
        for (Name p : n.props) {
            flattenPrefixes(alias, p, depth + 1);
        }
    }
}
Also used : Ref(com.google.javascript.jscomp.GlobalNamespace.Ref) Name(com.google.javascript.jscomp.GlobalNamespace.Name)

Example 29 with Ref

use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.

the class CollapseProperties method updateGlobalNameDeclarationAtFunctionNode.

/**
 * Updates the first initialization (a.k.a "declaration") of a global name
 * that occurs at a FUNCTION node. See comment for
 * {@link #updateGlobalNameDeclaration}.
 *
 * @param n An object representing a global name (e.g. "a")
 */
private void updateGlobalNameDeclarationAtFunctionNode(Name n, boolean canCollapseChildNames) {
    if (!canCollapseChildNames || !canCollapse(n)) {
        return;
    }
    Ref ref = n.getDeclaration();
    String fnName = ref.node.getString();
    addStubsForUndeclaredProperties(n, fnName, ref.node.getAncestor(2), ref.node.getParent());
}
Also used : Ref(com.google.javascript.jscomp.GlobalNamespace.Ref)

Example 30 with Ref

use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.

the class CollapseProperties method updateGlobalNameDeclarationAtAssignNode.

/**
 * Updates the first initialization (a.k.a "declaration") of a global name
 * that occurs at an ASSIGN node. See comment for
 * {@link #updateGlobalNameDeclaration}.
 *
 * @param n An object representing a global name (e.g. "a", "a.b.c")
 * @param alias The flattened name for {@code n} (e.g. "a", "a$b$c")
 */
private void updateGlobalNameDeclarationAtAssignNode(Name n, String alias, boolean canCollapseChildNames) {
    // NOTE: It's important that we don't add additional nodes
    // (e.g. a var node before the exprstmt) because the exprstmt might be
    // the child of an if statement that's not inside a block).
    // All qualified names - even for variables that are initially declared as LETS and CONSTS -
    // are being declared as VAR statements, but this is not incorrect because
    // we are only collapsing for global names.
    Ref ref = n.getDeclaration();
    Node rvalue = ref.node.getNext();
    if (ref.getTwin() != null) {
        updateTwinnedDeclaration(alias, ref.name, ref);
        return;
    }
    Node varNode = new Node(Token.VAR);
    Node varParent = ref.node.getAncestor(3);
    Node grandparent = ref.node.getAncestor(2);
    boolean isObjLit = rvalue.isObjectLit();
    boolean insertedVarNode = false;
    if (isObjLit && canEliminate(n)) {
        // Eliminate the object literal altogether.
        varParent.replaceChild(grandparent, varNode);
        ref.node = null;
        insertedVarNode = true;
        compiler.reportChangeToEnclosingScope(varNode);
    } else if (!n.isSimpleName()) {
        // Create a VAR node to declare the name.
        if (rvalue.isFunction()) {
            checkForHosedThisReferences(rvalue, n.docInfo, n);
        }
        compiler.reportChangeToEnclosingScope(rvalue);
        ref.node.getParent().removeChild(rvalue);
        Node nameNode = NodeUtil.newName(compiler, alias, ref.node.getAncestor(2), n.getFullName());
        JSDocInfo info = NodeUtil.getBestJSDocInfo(ref.node.getParent());
        if (ref.node.getLastChild().getBooleanProp(Node.IS_CONSTANT_NAME) || (info != null && info.isConstant())) {
            nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
        }
        if (info != null) {
            varNode.setJSDocInfo(info);
        }
        varNode.addChildToBack(nameNode);
        nameNode.addChildToFront(rvalue);
        varParent.replaceChild(grandparent, varNode);
        // Update the node ancestry stored in the reference.
        ref.node = nameNode;
        insertedVarNode = true;
        compiler.reportChangeToEnclosingScope(varNode);
    }
    if (canCollapseChildNames) {
        if (isObjLit) {
            declareVariablesForObjLitValues(n, alias, rvalue, varNode, varNode.getPrevious(), varParent);
        }
        addStubsForUndeclaredProperties(n, alias, varParent, varNode);
    }
    if (insertedVarNode) {
        if (!varNode.hasChildren()) {
            varParent.removeChild(varNode);
        }
    }
}
Also used : Ref(com.google.javascript.jscomp.GlobalNamespace.Ref) Node(com.google.javascript.rhino.Node) JSDocInfo(com.google.javascript.rhino.JSDocInfo)

Aggregations

Ref (com.google.javascript.jscomp.GlobalNamespace.Ref)34 Name (com.google.javascript.jscomp.GlobalNamespace.Name)25 Node (com.google.javascript.rhino.Node)24 Test (org.junit.Test)13 NodeSubject.assertNode (com.google.javascript.rhino.testing.NodeSubject.assertNode)9 JSDocInfo (com.google.javascript.rhino.JSDocInfo)7 AstChange (com.google.javascript.jscomp.GlobalNamespace.AstChange)4 ArrayList (java.util.ArrayList)3 LinkedHashSet (java.util.LinkedHashSet)3 JSTypeExpression (com.google.javascript.rhino.JSTypeExpression)2 JSType (com.google.javascript.rhino.jstype.JSType)2 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableSet (com.google.common.collect.ImmutableSet)1 Module (com.google.javascript.jscomp.modules.Module)1 FeatureSet (com.google.javascript.jscomp.parsing.parser.FeatureSet)1 QualifiedName (com.google.javascript.rhino.QualifiedName)1 Nullable (javax.annotation.Nullable)1