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);
}
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);
}
}
}
}
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);
}
}
}
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());
}
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);
}
}
}
Aggregations