use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.
the class CollapseProperties method updateGlobalNameDeclarationAtClassNode.
/**
* Updates the first initialization (a.k.a "declaration") of a global name that occurs at a CLASS
* node. See comment for {@link #updateGlobalNameDeclaration}.
*
* @param n An object representing a global name (e.g. "a")
*/
private void updateGlobalNameDeclarationAtClassNode(Name n, boolean canCollapseChildNames) {
if (!canCollapseChildNames || !canCollapse(n)) {
return;
}
Ref ref = n.getDeclaration();
String className = ref.node.getString();
addStubsForUndeclaredProperties(n, className, ref.node.getAncestor(2), ref.node.getParent());
}
use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.
the class AggressiveInlineAliases method inlineGlobalAliasIfPossible.
/**
* Attempt to inline an global alias of a global name. This requires that the name is well
* defined: assigned unconditionally, assigned exactly once. It is assumed that, the name for
* which it is an alias must already meet these same requirements.
*
* @param alias The alias to inline
* @return Whether the alias was inlined.
*/
private boolean inlineGlobalAliasIfPossible(Name name, Ref alias, GlobalNamespace namespace) {
// Ensure that the alias is assigned to global name at that the
// declaration.
Node aliasParent = alias.node.getParent();
if (((aliasParent.isAssign() || aliasParent.isName()) && NodeUtil.isExecutedExactlyOnce(aliasParent)) || // TODO(tbreisacher): Do we still need this special case?
(aliasParent.isName() && name.isConstructor())) {
Node lvalue = aliasParent.isName() ? aliasParent : aliasParent.getFirstChild();
if (!lvalue.isQualifiedName()) {
return false;
}
if (lvalue.isName() && compiler.getCodingConvention().isExported(lvalue.getString(), /* local */
false)) {
return false;
}
name = namespace.getSlot(lvalue.getQualifiedName());
if (name != null && name.isInlinableGlobalAlias()) {
Set<AstChange> newNodes = new LinkedHashSet<>();
List<Ref> refs = new ArrayList<>(name.getRefs());
for (Ref ref : refs) {
switch(ref.type) {
case SET_FROM_GLOBAL:
continue;
case DIRECT_GET:
case ALIASING_GET:
case PROTOTYPE_GET:
case CALL_GET:
Node newNode = alias.node.cloneTree();
Node node = ref.node;
node.getParent().replaceChild(node, newNode);
compiler.reportChangeToEnclosingScope(newNode);
newNodes.add(new AstChange(ref.module, ref.scope, newNode));
name.removeRef(ref);
break;
default:
throw new IllegalStateException();
}
}
rewriteAliasProps(name, alias.node, 0, newNodes);
// just set the original alias to null.
aliasParent.replaceChild(alias.node, IR.nullNode());
codeChanged = true;
compiler.reportChangeToEnclosingScope(aliasParent);
// Inlining the variable may have introduced new references
// to descendants of {@code name}. So those need to be collected now.
namespace.scanNewNodes(newNodes);
return true;
}
}
return false;
}
use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.
the class AggressiveInlineAliases method rewriteAliasProp.
/**
* @param value The value to use when rewriting.
* @param depth The chain depth.
* @param newNodes Expression nodes that have been updated.
* @param prop The property to rewrite with value.
*/
private void rewriteAliasProp(Node value, int depth, Set<AstChange> newNodes, Name prop) {
rewriteAliasProps(prop, value, depth + 1, newNodes);
List<Ref> refs = new ArrayList<>(prop.getRefs());
for (Ref ref : refs) {
Node target = ref.node;
for (int i = 0; i <= depth; i++) {
if (target.isGetProp()) {
target = target.getFirstChild();
} else if (NodeUtil.isObjectLitKey(target)) {
// Object literal key definitions are a little trickier, as we
// need to find the assignment target
Node gparent = target.getGrandparent();
if (gparent.isAssign()) {
target = gparent.getFirstChild();
} else {
checkState(NodeUtil.isObjectLitKey(gparent));
target = gparent;
}
} else {
throw new IllegalStateException("unexpected: " + target);
}
}
checkState(target.isGetProp() || target.isName());
Node newValue = value.cloneTree();
target.replaceWith(newValue);
compiler.reportChangeToEnclosingScope(newValue);
prop.removeRef(ref);
// Rescan the expression root.
newNodes.add(new AstChange(ref.module, ref.scope, ref.node));
codeChanged = true;
}
}
use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.
the class CheckGlobalNames method propertyMustBeInitializedByFullName.
/**
* The input name is a property. Check whether this property
* must be initialized with its full qualified name.
*/
private boolean propertyMustBeInitializedByFullName(Name name) {
// chain of functions and objects.
if (name.parent == null) {
return false;
}
boolean parentIsAliased = false;
if (name.parent.aliasingGets > 0) {
for (Ref ref : name.parent.getRefs()) {
if (ref.type == Ref.Type.ALIASING_GET) {
Node aliaser = ref.getNode().getParent();
// We don't need to worry about known aliased, because
// they're already covered by the getIndirectlyDeclaredProperties
// call at the top.
boolean isKnownAlias = aliaser.isCall() && (convention.getClassesDefinedByCall(aliaser) != null || convention.getSingletonGetterClassName(aliaser) != null);
if (!isKnownAlias) {
parentIsAliased = true;
}
}
}
}
if (parentIsAliased) {
return false;
}
if (objectPrototypeProps.contains(name.getBaseName())) {
return false;
}
if (name.parent.type == Name.Type.OBJECTLIT || name.parent.type == Name.Type.CLASS) {
return true;
}
return name.parent.type == Name.Type.FUNCTION && name.parent.isDeclaredType() && !functionPrototypeProps.contains(name.getBaseName());
}
use of com.google.javascript.jscomp.GlobalNamespace.Ref in project closure-compiler by google.
the class AggressiveInlineAliases method rewriteAllSubclassInheritedAccesses.
/**
* Inline all references to inherited static superclass properties from the subclass or any
* descendant of the given subclass. Avoids inlining references to inherited methods when
* possible, since they may use this or super().
*
* @param superclassNameObj The Name of the superclass
* @param subclassNameObj The Name of the subclass
* @param prop The property on the superclass to rewrite, if any descendant accesses it.
* @param namespace The GlobalNamespace containing superclassNameObj
*/
private boolean rewriteAllSubclassInheritedAccesses(Name superclassNameObj, Name subclassNameObj, Name prop, GlobalNamespace namespace) {
Ref propDeclRef = prop.getDeclaration();
if (propDeclRef == null || propDeclRef.node == null || !propDeclRef.node.getParent().isAssign()) {
return false;
}
Node propRhs = propDeclRef.node.getParent().getLastChild();
if (propRhs.isFunction()) {
return false;
}
String subclassQualifiedPropName = subclassNameObj.getFullName() + "." + prop.getBaseName();
Name subclassPropNameObj = namespace.getOwnSlot(subclassQualifiedPropName);
// shadows it.
if (subclassPropNameObj != null && (subclassPropNameObj.localSets > 0 || subclassPropNameObj.globalSets > 0)) {
return false;
}
// Recurse to find potential sub-subclass accesses of the superclass property.
if (subclassNameObj.subclasses != null) {
for (Name name : subclassNameObj.subclasses) {
rewriteAllSubclassInheritedAccesses(superclassNameObj, name, prop, namespace);
}
}
if (subclassPropNameObj != null) {
Set<AstChange> newNodes = new LinkedHashSet<>();
// Use this node as a template for rewriteAliasProp.
Node superclassNameNode = superclassNameObj.getDeclaration().node;
if (superclassNameNode.isName()) {
superclassNameNode = superclassNameNode.cloneNode();
} else if (superclassNameNode.isGetProp()) {
superclassNameNode = superclassNameNode.cloneTree();
} else {
return false;
}
rewriteAliasProp(superclassNameNode, 0, newNodes, subclassPropNameObj);
namespace.scanNewNodes(newNodes);
}
return true;
}
Aggregations