use of com.google.javascript.jscomp.GlobalNamespace.Name in project closure-compiler by google.
the class PolymerBehaviorExtractor method extractBehaviors.
/**
* Extracts all Behaviors from an array literal, recursively. Entries in the array can be
* object literals or array literals (of other behaviors). Behavior names must be
* global, fully qualified names.
* @see https://github.com/Polymer/polymer/blob/0.8-preview/PRIMER.md#behaviors
* @return A list of all {@code BehaviorDefinitions} in the array.
*/
ImmutableList<BehaviorDefinition> extractBehaviors(Node behaviorArray) {
if (behaviorArray == null) {
return ImmutableList.of();
}
if (!behaviorArray.isArrayLit()) {
compiler.report(JSError.make(behaviorArray, PolymerPassErrors.POLYMER_INVALID_BEHAVIOR_ARRAY));
return ImmutableList.of();
}
ImmutableList.Builder<BehaviorDefinition> behaviors = ImmutableList.builder();
for (Node behaviorName : behaviorArray.children()) {
if (behaviorName.isObjectLit()) {
PolymerPassStaticUtils.switchDollarSignPropsToBrackets(behaviorName, compiler);
PolymerPassStaticUtils.quoteListenerAndHostAttributeKeys(behaviorName, compiler);
if (NodeUtil.getFirstPropMatchingKey(behaviorName, "is") != null) {
compiler.report(JSError.make(behaviorName, PolymerPassErrors.POLYMER_INVALID_BEHAVIOR));
}
behaviors.add(new BehaviorDefinition(PolymerPassStaticUtils.extractProperties(behaviorName, PolymerClassDefinition.DefinitionType.ObjectLiteral, compiler), getBehaviorFunctionsToCopy(behaviorName), getNonPropertyMembersToCopy(behaviorName), !NodeUtil.isInFunction(behaviorName), (FeatureSet) NodeUtil.getEnclosingScript(behaviorName).getProp(Node.FEATURE_SET)));
continue;
}
Name behaviorGlobalName = globalNames.getSlot(behaviorName.getQualifiedName());
boolean isGlobalDeclaration = true;
if (behaviorGlobalName == null) {
compiler.report(JSError.make(behaviorName, PolymerPassErrors.POLYMER_UNQUALIFIED_BEHAVIOR));
continue;
}
Ref behaviorDeclaration = behaviorGlobalName.getDeclaration();
// Use any set as a backup declaration, even if it's local.
if (behaviorDeclaration == null) {
List<Ref> behaviorRefs = behaviorGlobalName.getRefs();
for (Ref ref : behaviorRefs) {
if (ref.isSet()) {
isGlobalDeclaration = false;
behaviorDeclaration = ref;
break;
}
}
}
if (behaviorDeclaration == null) {
compiler.report(JSError.make(behaviorName, PolymerPassErrors.POLYMER_UNQUALIFIED_BEHAVIOR));
continue;
}
Node behaviorDeclarationNode = behaviorDeclaration.getNode();
JSDocInfo behaviorInfo = NodeUtil.getBestJSDocInfo(behaviorDeclarationNode);
if (behaviorInfo == null || !behaviorInfo.isPolymerBehavior()) {
compiler.report(JSError.make(behaviorDeclarationNode, PolymerPassErrors.POLYMER_UNANNOTATED_BEHAVIOR));
}
Node behaviorValue = NodeUtil.getRValueOfLValue(behaviorDeclarationNode);
if (behaviorValue == null) {
compiler.report(JSError.make(behaviorName, PolymerPassErrors.POLYMER_UNQUALIFIED_BEHAVIOR));
} else if (behaviorValue.isArrayLit()) {
// Individual behaviors can also be arrays of behaviors. Parse them recursively.
behaviors.addAll(extractBehaviors(behaviorValue));
} else if (behaviorValue.isObjectLit()) {
PolymerPassStaticUtils.switchDollarSignPropsToBrackets(behaviorValue, compiler);
PolymerPassStaticUtils.quoteListenerAndHostAttributeKeys(behaviorValue, compiler);
if (NodeUtil.getFirstPropMatchingKey(behaviorValue, "is") != null) {
compiler.report(JSError.make(behaviorValue, PolymerPassErrors.POLYMER_INVALID_BEHAVIOR));
}
behaviors.add(new BehaviorDefinition(PolymerPassStaticUtils.extractProperties(behaviorValue, PolymerClassDefinition.DefinitionType.ObjectLiteral, compiler), getBehaviorFunctionsToCopy(behaviorValue), getNonPropertyMembersToCopy(behaviorValue), isGlobalDeclaration, (FeatureSet) NodeUtil.getEnclosingScript(behaviorValue).getProp(Node.FEATURE_SET)));
} else {
compiler.report(JSError.make(behaviorName, PolymerPassErrors.POLYMER_UNQUALIFIED_BEHAVIOR));
}
}
return behaviors.build();
}
use of com.google.javascript.jscomp.GlobalNamespace.Name in project closure-compiler by google.
the class GlobalNamespaceTest method testRemoveDeclaration1.
public void testRemoveDeclaration1() {
Name n = new Name("a", null, false);
Ref set1 = createNodelessRef(Ref.Type.SET_FROM_GLOBAL);
Ref set2 = createNodelessRef(Ref.Type.SET_FROM_GLOBAL);
n.addRef(set1);
n.addRef(set2);
assertEquals(set1, n.getDeclaration());
assertEquals(2, n.globalSets);
assertThat(n.getRefs()).hasSize(2);
n.removeRef(set1);
assertEquals(set2, n.getDeclaration());
assertEquals(1, n.globalSets);
assertThat(n.getRefs()).hasSize(1);
}
use of com.google.javascript.jscomp.GlobalNamespace.Name in project closure-compiler by google.
the class GlobalNamespaceTest method testRemoveDeclaration2.
public void testRemoveDeclaration2() {
Name n = new Name("a", null, false);
Ref set1 = createNodelessRef(Ref.Type.SET_FROM_GLOBAL);
Ref set2 = createNodelessRef(Ref.Type.SET_FROM_LOCAL);
n.addRef(set1);
n.addRef(set2);
assertEquals(set1, n.getDeclaration());
assertEquals(1, n.globalSets);
assertEquals(1, n.localSets);
assertThat(n.getRefs()).hasSize(2);
n.removeRef(set1);
assertNull(n.getDeclaration());
assertEquals(0, n.globalSets);
}
use of com.google.javascript.jscomp.GlobalNamespace.Name in project closure-compiler by google.
the class ProcessDefines method collectDefines.
/**
* Finds all defines, and creates a {@link DefineInfo} data structure for
* each one.
* @return A map of {@link DefineInfo} structures, keyed by name.
*/
Map<String, DefineInfo> collectDefines(Node externs, Node root) {
if (namespace == null) {
namespace = new GlobalNamespace(compiler, externs, root);
}
// Find all the global names with a @define annotation
List<Name> allDefines = new ArrayList<>();
for (Name name : namespace.getNameIndex().values()) {
Ref decl = name.getDeclaration();
if (name.docInfo != null && name.docInfo.isDefine()) {
// so we look for the JSDoc instead of the inferred type.
if (isValidDefineType(name.docInfo.getType())) {
allDefines.add(name);
} else {
JSError error = JSError.make(decl.node, INVALID_DEFINE_TYPE_ERROR);
compiler.report(error);
}
} else {
for (Ref ref : name.getRefs()) {
if (ref == decl) {
// Declarations were handled above.
continue;
}
Node n = ref.node;
Node parent = ref.node.getParent();
JSDocInfo info = n.getJSDocInfo();
if (info == null && parent.isVar() && parent.hasOneChild()) {
info = parent.getJSDocInfo();
}
if (info != null && info.isDefine()) {
allDefines.add(name);
break;
}
}
}
}
CollectDefines pass = new CollectDefines(compiler, allDefines);
NodeTraversal.traverseRootsEs6(compiler, pass, externs, root);
return pass.getAllDefines();
}
use of com.google.javascript.jscomp.GlobalNamespace.Name in project closure-compiler by google.
the class CheckGlobalNames method checkDescendantNames.
/**
* Checks to make sure all the descendants of a name are defined if they
* are referenced.
*
* @param name A global name.
* @param nameIsDefined If true, {@code name} is defined. Otherwise, it's
* undefined, and any references to descendant names should emit warnings.
*/
private void checkDescendantNames(Name name, boolean nameIsDefined) {
if (name.props != null) {
for (Name prop : name.props) {
// if the ancestor of a property is not defined, then we should emit
// warnings for all references to the property.
boolean propIsDefined = false;
if (nameIsDefined) {
// if the ancestor of a property is defined, then let's check that
// the property is also explicitly defined if it needs to be.
propIsDefined = (!propertyMustBeInitializedByFullName(prop) || prop.globalSets + prop.localSets > 0);
}
validateName(prop, propIsDefined);
checkDescendantNames(prop, propIsDefined);
}
}
}
Aggregations