Skip to content

Commit

Permalink
[NTI] Handle namespace aliasing that uses object literals.
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=160612671
  • Loading branch information
dimvar authored and brad4d committed Jun 30, 2017
1 parent 5127e7e commit 511e40b
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 27 deletions.
54 changes: 27 additions & 27 deletions src/com/google/javascript/jscomp/GlobalTypeInfoCollector.java
Expand Up @@ -902,21 +902,26 @@ private boolean isAliasedNamespaceDefinition(Node qnameNode) {
if (rhs == null || !rhs.isQualifiedName()) {
return false;
}
Node parent = qnameNode.getParent();
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(qnameNode);
if (jsdoc == null) {
return (qnameNode.isFromExterns()
// An ES6-module default export is transpiled to an assignment without @const,
// but we still consider it an alias.
|| (qnameNode.isGetProp()
&& qnameNode.getLastChild().getString().equals("default")
&& this.currentScope.isNamespace(qnameNode.getFirstChild())))
// If the aliased namespace is a variable, do the aliasing at
// declaration, not at a random assignment later.
&& (qnameNode.getParent().isVar() || !qnameNode.isName())
&& this.currentScope.isNamespace(rhs);
} else {
if (jsdoc != null) {
return jsdoc.isConstructorOrInterface() || jsdoc.hasConstAnnotation();
}
// You can only alias variable namespaces at declaration, not at a random assignment later.
if (qnameNode.isName() && !parent.isVar()) {
return false;
}
if (!this.currentScope.isNamespace(rhs)) {
return false;
}
return qnameNode.isFromExterns()
// An ES6-module default export is transpiled to an assignment without @const,
// but we still consider it an alias.
|| (qnameNode.isGetProp()
&& qnameNode.getLastChild().getString().equals("default"))
// Aliased object-literal property; can happen after goog.module rewriting.
|| (qnameNode.isStringKey()
&& this.currentScope.isNamespace(NodeUtil.getBestLValue(parent)));
}

private boolean isQualifiedFunctionDefinition(Node qnameNode) {
Expand Down Expand Up @@ -968,8 +973,7 @@ private void visitObjlitNamespace(Node qnameNode) {
markAssignNodeAsAnalyzed(qnameNode.getParent());
}
if (currentScope.isDefined(qnameNode)) {
if (qnameNode.isGetProp()
&& !NodeUtil.getRValueOfLValue(qnameNode).isOr()) {
if (qnameNode.isGetProp() && !NodeUtil.getRValueOfLValue(qnameNode).isOr()) {
warnings.add(JSError.make(qnameNode, REDECLARED_PROPERTY,
qnameNode.getLastChild().getString(),
qnameNode.getFirstChild().getQualifiedName()));
Expand All @@ -990,8 +994,7 @@ private void visitObjlitNamespace(Node qnameNode) {
for (Node propNode : maybeObjlit.children()) {
if (isAliasedNamespaceDefinition(propNode)) {
// Pretend that the alias was defined as an assignment to a qname
Node fakeGetprop =
IR.getprop(qnameNode.cloneTree(), IR.string(propNode.getString()));
Node fakeGetprop = IR.getprop(qnameNode.cloneTree(), IR.string(propNode.getString()));
IR.assign(fakeGetprop, propNode.getFirstChild().cloneTree());
visitAliasedNamespace(fakeGetprop);
}
Expand Down Expand Up @@ -1526,8 +1529,7 @@ private void visitObjectLit(Node objLitNode, Node parent) {
lendsObjlits.add(objLitNode);
}
Node maybeLvalue = parent.isAssign() ? parent.getFirstChild() : parent;
if (NodeUtil.isNamespaceDecl(maybeLvalue)
&& currentScope.isNamespace(maybeLvalue)) {
if (NodeUtil.isNamespaceDecl(maybeLvalue) && currentScope.isNamespace(maybeLvalue)) {
for (Node prop : objLitNode.children()) {
recordPropertyName(prop.getString(), prop);
visitNamespacePropertyDeclaration(prop, maybeLvalue, prop.getString());
Expand All @@ -1536,10 +1538,9 @@ private void visitObjectLit(Node objLitNode, Node parent) {
&& !NodeUtil.isPrototypeAssignment(maybeLvalue)) {
for (Node prop : objLitNode.children()) {
recordPropertyName(prop.getString(), prop);
if (prop.getJSDocInfo() != null) {
getDeclaredObjLitProps().put(prop,
getDeclaredTypeOfNode(
prop.getJSDocInfo(), currentScope));
JSDocInfo propJsdoc = prop.getJSDocInfo();
if (propJsdoc != null) {
getDeclaredObjLitProps().put(prop, getDeclaredTypeOfNode(propJsdoc, currentScope));
}
if (isAnnotatedAsConst(prop)) {
warnings.add(JSError.make(prop, MISPLACED_CONST_ANNOTATION));
Expand Down Expand Up @@ -1802,13 +1803,12 @@ private void visitNamespacePropertyDeclaration(Node getProp) {
visitNamespacePropertyDeclaration(getProp, recv, pname);
}

private void visitNamespacePropertyDeclaration(
Node declNode, Node recv, String pname) {
private void visitNamespacePropertyDeclaration(Node declNode, Node recv, String pname) {
checkArgument(
declNode.isGetProp()
|| declNode.isStringKey()
|| declNode.isGetterDef()
|| declNode.isSetterDef(),
|| declNode.isStringKey()
|| declNode.isGetterDef()
|| declNode.isSetterDef(),
declNode);
checkArgument(currentScope.isNamespace(recv));
if (declNode.isGetterDef()) {
Expand Down
11 changes: 11 additions & 0 deletions test/com/google/javascript/jscomp/NewTypeInferenceTest.java
Expand Up @@ -15055,6 +15055,17 @@ public void testNamespacePropsAfterAliasing() {
"Foo3.prop = '';"),
NewTypeInference.INVALID_OPERAND_TYPE,
NewTypeInference.INVALID_OPERAND_TYPE);

// This style of code is generated by goog.module rewriting
typeCheck(LINE_JOINER.join(
"/** @const */",
"var exports$foo = {};",
"/** @param {string} x */",
"exports$foo.f = function(x) {};",
"/** @const */",
"var contents$bar_g = { foo: exports$foo.f };",
"contents$bar_g.foo(1);"),
NewTypeInference.INVALID_ARGUMENT_TYPE);
}

public void testNamespaceAliasingWithoutJsdoc() {
Expand Down

0 comments on commit 511e40b

Please sign in to comment.