use of com.google.javascript.jscomp.GlobalNamespace.Name 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;
}
use of com.google.javascript.jscomp.GlobalNamespace.Name 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);
}
}
}
}
use of com.google.javascript.jscomp.GlobalNamespace.Name in project closure-compiler by google.
the class CollapseProperties method process.
@Override
public void process(Node externs, Node root) {
GlobalNamespace namespace = new GlobalNamespace(compiler, root);
nameMap = namespace.getNameIndex();
globalNames = namespace.getNameForest();
checkNamespaces();
for (Name name : globalNames) {
flattenReferencesToCollapsibleDescendantNames(name, name.getBaseName());
}
// invalidating the node ancestry stored with each reference.
for (Name name : globalNames) {
collapseDeclarationOfNameAndDescendants(name, name.getBaseName());
}
// This shouldn't be necessary, this pass should already be setting new constants as constant.
// TODO(b/64256754): Investigate.
(new PropagateConstantAnnotationsOverVars(compiler, false)).process(externs, root);
}
use of com.google.javascript.jscomp.GlobalNamespace.Name 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);
}
}
}
use of com.google.javascript.jscomp.GlobalNamespace.Name in project closure-compiler by google.
the class CollapseProperties method addStubsForUndeclaredProperties.
/**
* Adds global variable "stubs" for any properties of a global name that are only set in a local
* scope or read but never set.
*
* @param n An object representing a global name (e.g. "a", "a.b.c")
* @param alias The flattened name of the object whose properties we are adding stubs for (e.g.
* "a$b$c")
* @param parent The node to which new global variables should be added as children
* @param addAfter The child of after which new variables should be added
*/
private void addStubsForUndeclaredProperties(Name n, String alias, Node parent, Node addAfter) {
checkState(n.canCollapseUnannotatedChildNames(), n);
checkArgument(NodeUtil.isStatementBlock(parent), parent);
checkNotNull(addAfter);
if (n.props == null) {
return;
}
for (Name p : n.props) {
if (p.needsToBeStubbed()) {
String propAlias = appendPropForAlias(alias, p.getBaseName());
Node nameNode = IR.name(propAlias);
Node newVar = IR.var(nameNode).useSourceInfoIfMissingFromForTree(addAfter);
parent.addChildAfter(newVar, addAfter);
addAfter = newVar;
compiler.reportChangeToEnclosingScope(newVar);
// reference to it. Don't check the declaration, as it might be null.
if (p.getRefs().get(0).node.getLastChild().getBooleanProp(Node.IS_CONSTANT_NAME)) {
nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
compiler.reportChangeToEnclosingScope(nameNode);
}
}
}
}
Aggregations