All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.StaticSuperPropReplacer Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs.

There is a newer version: v20240317
Show newest version
/*
 * Copyright 2019 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 static com.google.common.base.Preconditions.checkState;

import com.google.javascript.rhino.Node;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Optional;

/**
 * Replaces references to `super` properties in static class methods with the superclass, for cases
 * where the superclass in the extends clause is a qualified name.
 *
 * 

This runs during {@link InlineAndCollapseProperties.AggressiveInlineAliases} in order to avoid * breaking references to superclass properties during {@link * InlineAndCollapseProperties.CollapseProperties}. For example: replaces * *

`class Bar extends Foo { static m() { super.m() {} }}` * *

with * *

`class Bar extends Foo { static m() { Foo.m() {} }}` * *

This makes the following assumptions: * *

    *
  • The superclass never changes after the class definition (e.g. using Object.setPrototypeOf) *
  • The superclass (if a qualified name) is effectively constant after the class definition *
  • Evaluating the qualified name of the superclass has no side effects (i.e. is not a getter * with side effects) *
*/ final class StaticSuperPropReplacer implements NodeTraversal.Callback { private final AbstractCompiler compiler; /** * Stores the Node for a superclass for static ES6 class methods only; otherwise an empty object * *

This uses Optional instead of just Node because ArrayDeque rejects nulls. */ private final Deque> superclasses = new ArrayDeque<>(); StaticSuperPropReplacer(AbstractCompiler compiler) { this.compiler = compiler; } /** Runs this pass over the entire provided subtree */ void replaceAll(Node root) { NodeTraversal.traverse(compiler, root, this); } @Override public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { if (!n.isFunction()) { return true; } // keep track of stack of current superclass, if known if (parent.isStaticMember() && parent.getParent().isClassMembers()) { Node classNode = parent.getGrandparent(); Node superclassNode = classNode.getSecondChild(); if (superclassNode.isEmpty()) { superclasses.push(Optional.empty()); } else { superclasses.push(Optional.of(superclassNode)); } } else if (!n.isArrowFunction()) { // arrow functions keep the same `super` reference, but non-arrow functions should not be // accessing super. superclasses.push(Optional.empty()); } return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n.isSuper()) { tryReplaceSuper(n); } else if (n.isFunction() && !n.isArrowFunction()) { superclasses.pop(); } } /** Replaces `super` with `Super.Class` if in a static class method with a qname superclass */ private void tryReplaceSuper(Node superNode) { checkState(!superclasses.isEmpty(), "`super` cannot appear outside a function"); Optional currentSuperclass = superclasses.peek(); if (currentSuperclass.isEmpty() || !currentSuperclass.get().isQualifiedName()) { // either if a) we're in a static class fn without an 'extends' clause or b) we're not in // a static class function return; } Node fullyQualifiedSuperRef = currentSuperclass.get().cloneTree(); superNode.replaceWith(fullyQualifiedSuperRef); compiler.reportChangeToEnclosingScope(fullyQualifiedSuperRef); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy