Skip to content

Commit

Permalink
A few more code cleanups to ths ijs package
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=179740352
  • Loading branch information
blickly authored and Tyler Breisacher committed Dec 21, 2017
1 parent 07a2673 commit ac41550
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 103 deletions.
91 changes: 91 additions & 0 deletions src/com/google/javascript/jscomp/ijs/ClassUtil.java
@@ -0,0 +1,91 @@
/*
* Copyright 2017 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.ijs;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

import com.google.javascript.jscomp.NodeUtil;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;

/**
* Static utility methods for dealing with classes. The primary benefit is for papering over
* the differences between ES6 class and goog.defineClass syntax.
*/
final class ClassUtil {
private ClassUtil() {}

static boolean isThisProp(Node getprop) {
return getprop.isGetProp() && getprop.getFirstChild().isThis();
}

static String getPrototypeNameOfThisProp(Node getprop) {
checkArgument(isThisProp(getprop));
Node function = NodeUtil.getEnclosingFunction(getprop);
String className = getClassName(function);
checkState(className != null && !className.isEmpty());
return className + ".prototype." + getprop.getLastChild().getString();
}

static String getPrototypeNameOfMethod(Node function) {
checkArgument(isClassMethod(function));
String className = getClassName(function);
checkState(className != null && !className.isEmpty());
return className + ".prototype." + function.getParent().getString();
}

static boolean isClassMethod(Node functionNode) {
checkArgument(functionNode.isFunction());
Node parent = functionNode.getParent();
if (parent.isMemberFunctionDef()
&& parent.getParent().isClassMembers()) {
// ES6 class
return true;
}
// goog.defineClass
return parent.isStringKey()
&& parent.getParent().isObjectLit()
&& parent.getGrandparent().isCall()
&& parent.getGrandparent().getFirstChild().matchesQualifiedName("goog.defineClass");
}

static String getClassName(Node functionNode) {
if (isClassMethod(functionNode)) {
Node parent = functionNode.getParent();
if (parent.isMemberFunctionDef()) {
// ES6 class
Node classNode = functionNode.getGrandparent().getParent();
checkState(classNode.isClass());
return NodeUtil.getName(classNode);
}
// goog.defineClass
checkState(parent.isStringKey());
Node defineClassCall = parent.getGrandparent();
checkState(defineClassCall.isCall());
return NodeUtil.getBestLValue(defineClassCall).getQualifiedName();
}
return NodeUtil.getName(functionNode);
}

static boolean isConstructor(Node functionNode) {
if (isClassMethod(functionNode)) {
return "constructor".equals(functionNode.getParent().getString());
}
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(functionNode);
return jsdoc != null && jsdoc.isConstructor();
}
}
111 changes: 26 additions & 85 deletions src/com/google/javascript/jscomp/ijs/ConvertToTypedInterface.java
Expand Up @@ -111,7 +111,7 @@ private static class RemoveNonDeclarations implements NodeTraversal.Callback {
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
switch (n.getToken()) {
case FUNCTION:
if (!isConstructor(n)) {
if (!ClassUtil.isConstructor(n)) {
Node body = n.getLastChild();
if (!body.isNormalBlock() || body.hasChildren()) {
t.reportCodeChange(body);
Expand Down Expand Up @@ -276,7 +276,7 @@ static void splitNameDeclarationsAndRemoveDestructuring(Node n, NodeTraversal t)
}

private static class PropagateConstJsdoc extends NodeTraversal.AbstractPostOrderCallback {
FileInfo currentFile;
final FileInfo currentFile;

PropagateConstJsdoc(FileInfo currentFile) {
this.currentFile = currentFile;
Expand All @@ -293,7 +293,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
case FUNCTION:
if (NodeUtil.isStatementParent(parent)) {
currentFile.recordNameDeclaration(n.getFirstChild(), t.getScope());
} else if (isClassMethod(n)) {
} else if (ClassUtil.isClassMethod(n)) {
currentFile.recordMethod(n, t.getScope());
}
break;
Expand Down Expand Up @@ -367,7 +367,7 @@ private void propagateJsdocAtName(NodeTraversal t, Node nameNode) {
return;
}
JSDocInfo newJsdoc = JsdocUtil.getJSDocForRhs(rhs, jsdoc);
if (newJsdoc == null && isThisProp(nameNode)) {
if (newJsdoc == null && ClassUtil.isThisProp(nameNode)) {
Var decl = findNameDeclaration(t.getScope(), rhs);
newJsdoc = JsdocUtil.getJSDocForName(decl, jsdoc);
}
Expand Down Expand Up @@ -422,7 +422,7 @@ private void removeDuplicateDeclarations() {
}
}

public void simplifyAll() {
void simplifyAll() {
// Remove duplicate assignments to the same symbol
removeDuplicateDeclarations();

Expand All @@ -431,7 +431,7 @@ public void simplifyAll() {
SHORT_TO_LONG.immutableSortedCopy(currentFile.getDeclarations().keySet());
for (String name : seenNames) {
for (PotentialDeclaration decl : currentFile.getDeclarations().get(name)) {
processName(name, decl);
processDeclaration(decl);
}
}
// Simplify all names inside constructors.
Expand All @@ -440,17 +440,17 @@ public void simplifyAll() {
}
}

private void processName(String qname, PotentialDeclaration decl) {
if (NodeUtil.isCallTo(decl.lhs, "goog.define")) {
NodeUtil.deleteNode(decl.lhs.getLastChild(), compiler);
private void processDeclaration(PotentialDeclaration decl) {
if (NodeUtil.isCallTo(decl.getLhs(), "goog.define")) {
NodeUtil.deleteNode(decl.getLhs().getLastChild(), compiler);
return;
}
switch (shouldRemove(qname, decl)) {
switch (shouldRemove(decl)) {
case PRESERVE_ALL:
if (decl.rhs != null && decl.rhs.isFunction()) {
processFunction(decl.rhs);
} else if (decl.rhs != null && isClass(decl.rhs)) {
processClass(decl.rhs);
if (decl.getRhs() != null && decl.getRhs().isFunction()) {
processFunction(decl.getRhs());
} else if (decl.getRhs() != null && isClass(decl.getRhs())) {
processClass(decl.getRhs());
}
break;
case SIMPLIFY_RHS:
Expand All @@ -476,7 +476,7 @@ private void processClass(Node n) {
private void processFunction(Node n) {
checkArgument(n.isFunction());
processFunctionParameters(n.getSecondChild());
if (isConstructor(n) && n.getLastChild().hasChildren()) {
if (ClassUtil.isConstructor(n) && n.getLastChild().hasChildren()) {
currentFile.markConstructorToProcess(n);
}
}
Expand All @@ -494,7 +494,7 @@ private void processFunctionParameters(Node paramList) {
}

private void processConstructor(final Node function) {
if (getClassName(function) == null) {
if (ClassUtil.getClassName(function) == null) {
return;
}
final Node insertionPoint = NodeUtil.getEnclosingStatement(function);
Expand All @@ -507,8 +507,8 @@ public void visit(NodeTraversal t, Node n, Node parent) {
if (n.isExprResult()) {
Node expr = n.getFirstChild();
Node name = expr.isAssign() ? expr.getFirstChild() : expr;
if (isThisProp(name)) {
String fullyQualifiedName = getPrototypeNameOfThisProp(name);
if (ClassUtil.isThisProp(name)) {
String fullyQualifiedName = ClassUtil.getPrototypeNameOfThisProp(name);
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(name);
Node newProtoAssignStmt =
NodeUtil.newQNameDeclaration(compiler, fullyQualifiedName, null, jsdoc);
Expand Down Expand Up @@ -546,14 +546,15 @@ private static String rootName(String qualifiedName) {
return qualifiedName.substring(0, dotIndex);
}

private RemovalType shouldRemove(String fullyQualifiedName, PotentialDeclaration decl) {
private RemovalType shouldRemove(PotentialDeclaration decl) {
String fullyQualifiedName = decl.getFullyQualifiedName();
if ("$jscomp".equals(rootName(fullyQualifiedName))) {
// These are created by goog.scope processing, but clash with each other
// and should not be depended on.
return RemovalType.REMOVE_ALL;
}
Node nameNode = decl.lhs;
Node rhs = decl.rhs;
Node nameNode = decl.getLhs();
Node rhs = decl.getRhs();
Node jsdocNode = NodeUtil.getBestJSDocInfoNode(nameNode);
JSDocInfo jsdoc = jsdocNode.getJSDocInfo();
boolean isExport = isExportLhs(nameNode);
Expand Down Expand Up @@ -589,34 +590,16 @@ private RemovalType shouldRemove(String fullyQualifiedName, PotentialDeclaration
}

private boolean isAliasDefinition(PotentialDeclaration decl) {
boolean isExport = isExportLhs(decl.lhs);
if (isConstToBeInferred(decl.getJsDoc(), decl.lhs, isExport) && decl.rhs.isQualifiedName()) {
String aliasedName = decl.rhs.getQualifiedName();
boolean isExport = isExportLhs(decl.getLhs());
if (isConstToBeInferred(decl.getJsDoc(), decl.getLhs(), isExport)
&& decl.getRhs().isQualifiedName()) {
String aliasedName = decl.getRhs().getQualifiedName();
return currentFile.isPrefixRequired(aliasedName) || currentFile.isNameDeclared(aliasedName);
}
return false;
}
}

static boolean isThisProp(Node getprop) {
return getprop.isGetProp() && getprop.getFirstChild().isThis();
}

static String getPrototypeNameOfThisProp(Node getprop) {
checkArgument(isThisProp(getprop));
Node function = NodeUtil.getEnclosingFunction(getprop);
String className = getClassName(function);
checkState(className != null && !className.isEmpty());
return className + ".prototype." + getprop.getLastChild().getString();
}

static String getPrototypeNameOfMethod(Node function) {
checkArgument(isClassMethod(function));
String className = getClassName(function);
checkState(className != null && !className.isEmpty());
return className + ".prototype." + function.getParent().getString();
}

// TODO(blickly): Move to NodeUtil if it makes more sense there.
private static boolean isDeclaration(Node nameNode) {
checkArgument(nameNode.isQualifiedName());
Expand Down Expand Up @@ -644,47 +627,6 @@ static boolean isConstToBeInferred(
&& !NodeUtil.isNamespaceDecl(nameNode);
}

static boolean isClassMethod(Node functionNode) {
checkArgument(functionNode.isFunction());
Node parent = functionNode.getParent();
if (parent.isMemberFunctionDef()
&& parent.getParent().isClassMembers()) {
// ES6 class
return true;
}
// goog.defineClass
return parent.isStringKey()
&& parent.getParent().isObjectLit()
&& parent.getGrandparent().isCall()
&& parent.getGrandparent().getFirstChild().matchesQualifiedName("goog.defineClass");
}

private static String getClassName(Node functionNode) {
if (isClassMethod(functionNode)) {
Node parent = functionNode.getParent();
if (parent.isMemberFunctionDef()) {
// ES6 class
Node classNode = functionNode.getGrandparent().getParent();
checkState(classNode.isClass());
return NodeUtil.getName(classNode);
}
// goog.defineClass
checkState(parent.isStringKey());
Node defineClassCall = parent.getGrandparent();
checkState(defineClassCall.isCall());
return NodeUtil.getBestLValue(defineClassCall).getQualifiedName();
}
return NodeUtil.getName(functionNode);
}

private static boolean isConstructor(Node functionNode) {
if (isClassMethod(functionNode)) {
return "constructor".equals(functionNode.getParent().getString());
}
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(functionNode);
return jsdoc != null && jsdoc.isConstructor();
}

private static boolean isImportRhs(@Nullable Node rhs) {
if (rhs == null || !rhs.isCall()) {
return false;
Expand All @@ -694,5 +636,4 @@ private static boolean isImportRhs(@Nullable Node rhs) {
|| callee.matchesQualifiedName("goog.forwardDeclare");
}


}
3 changes: 2 additions & 1 deletion src/com/google/javascript/jscomp/ijs/FileInfo.java
Expand Up @@ -66,7 +66,8 @@ boolean isNameDeclared(String fullyQualifiedName) {
return declarations.containsKey(fullyQualifiedName);
}

static boolean containsPrefix(String fullyQualifiedName, Iterable<String> prefixNamespaces) {
private static boolean containsPrefix(
String fullyQualifiedName, Iterable<String> prefixNamespaces) {
for (String prefix : prefixNamespaces) {
if (fullyQualifiedName.equals(prefix) || fullyQualifiedName.startsWith(prefix + ".")) {
return true;
Expand Down
3 changes: 3 additions & 0 deletions src/com/google/javascript/jscomp/ijs/JsdocUtil.java
Expand Up @@ -30,6 +30,9 @@
import com.google.javascript.rhino.Token;
import javax.annotation.Nullable;

/**
* Static utility methods for dealing with inspecting and constructing JSDoc objects.
*/
final class JsdocUtil {
private JsdocUtil() {}

Expand Down

0 comments on commit ac41550

Please sign in to comment.