class NameAnalyzer {
/**
* Creates name information for the current node during a traversal.
*
* @param t The node traversal
* @param n The current node
* @param parent The parent of n
* @return The name information, or null if the name is irrelevant to this
* pass
*/
private NameInformation createNameInformation(NodeTraversal t, Node n,
Node parent) {
// Build the full name and find its root node by iterating down through all
// GETPROP/GETELEM nodes.
String name = "";
Node rootNameNode = n;
boolean bNameWasShortened = false;
while (NodeUtil.isGet(rootNameNode)) {
Node prop = rootNameNode.getLastChild();
if (rootNameNode.getType() == Token.GETPROP) {
name = "." + prop.getString() + name;
} else {
// We consider the name to be "a.b" in a.b['c'] or a.b[x].d.
bNameWasShortened = true;
name = "";
}
rootNameNode = rootNameNode.getFirstChild();
}
// Check whether this is a class-defining call. Classes may only be defined
// in the global scope.
if (NodeUtil.isCall(parent) && t.inGlobalScope()) {
CodingConvention convention = compiler.getCodingConvention();
SubclassRelationship classes = convention.getClassesDefinedByCall(parent);
if (classes != null) {
NameInformation nameInfo = new NameInformation();
nameInfo.name = classes.subclassName;
nameInfo.onlyAffectsClassDef = true;
nameInfo.superclass = classes.superclassName;
return nameInfo;
}
String singletonGetterClass =
convention.getSingletonGetterClassName(parent);
if (singletonGetterClass != null) {
NameInformation nameInfo = new NameInformation();
nameInfo.name = singletonGetterClass;
nameInfo.onlyAffectsClassDef = true;
return nameInfo;
}
}
switch (rootNameNode.getType()) {
case Token.NAME:
// Check whether this is an assignment to a prototype property
// of an object defined in the global scope.
if (!bNameWasShortened &&
n.getType() == Token.GETPROP &&
parent.getType() == Token.ASSIGN &&
"prototype".equals(n.getLastChild().getString())) {
if (createNameInformation(t, n.getFirstChild(), n) != null) {
name = rootNameNode.getString() + name;
name = name.substring(0, name.length() - PROTOTYPE_SUFFIX_LEN);
NameInformation nameInfo = new NameInformation();
nameInfo.name = name;
return nameInfo;
} else {
return null;
}
}
return createNameInformation(
rootNameNode.getString() + name, t.getScope(), rootNameNode);
case Token.THIS:
if (t.inGlobalScope()) {
NameInformation nameInfo = new NameInformation();
if (name.indexOf('.') == 0) {
nameInfo.name = name.substring(1); // strip leading "."
} else {
nameInfo.name = name;
}
nameInfo.isExternallyReferenceable = true;
return nameInfo;
}
return null;
default:
return null;
}
}
}