Skip to content

Commit eb4650a

Browse files
committed
Suppress missing-require warnings in ES6 extends clauses from externs, e.g. class MyClass extends React.Component (rework of PR 1192 to match rest of class more closely)
1 parent 7bc6b88 commit eb4650a

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

src/com/google/javascript/jscomp/CheckRequiresForConstructors.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
166166
visitNewNode(t, n);
167167
break;
168168
case Token.CLASS:
169-
visitClassNode(n);
169+
visitClassNode(t, n);
170170
break;
171171
case Token.IMPORT:
172172
case Token.EXPORT:
@@ -320,14 +320,32 @@ private void visitNewNode(NodeTraversal t, Node newNode) {
320320
}
321321
}
322322

323-
private void visitClassNode(Node classNode) {
323+
private void visitClassNode(NodeTraversal t, Node classNode) {
324324
String name = NodeUtil.getClassName(classNode);
325325
if (name != null) {
326326
constructors.add(name);
327327
}
328+
328329
Node extendClass = classNode.getSecondChild();
330+
331+
// If the superclass is something other than a qualified name, ignore it.
329332
if (extendClass.isQualifiedName()) {
330-
usages.put(extendClass.getQualifiedName(), extendClass);
333+
// Grab the root superclass namespace.
334+
Node root = NodeUtil.getRootOfQualifiedName(extendClass);
335+
336+
// It should always be a name. Extending this.something or
337+
// super.something is unlikely.
338+
// We only consider programmer-defined superclasses that are
339+
// global variables, or are defined on global variables.
340+
if (root.isName()) {
341+
String rootName = root.getString();
342+
Var var = t.getScope().getVar(rootName);
343+
if (var != null && (var.isLocal() || var.isExtern())) {
344+
// "require" not needed for these
345+
} else {
346+
usages.put(extendClass.getQualifiedName(), extendClass);
347+
}
348+
}
331349
}
332350
}
333351

test/com/google/javascript/jscomp/MissingRequireTest.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import com.google.common.collect.ImmutableList;
2323
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
2424

25+
import java.util.List;
26+
2527
/**
2628
* Tests for the "missing requires" check in {@link CheckRequiresForConstructors}.
2729
*
@@ -140,7 +142,31 @@ public void testFailEs6ClassExtends() {
140142
String warning = "'goog.foo.Bar.Inner' used but not goog.require'd";
141143
test(js, js, null, MISSING_REQUIRE_WARNING, warning);
142144
}
143-
145+
146+
public void testFailEs6ClassExtendsSomethingWithoutNS() {
147+
setAcceptedLanguage(LanguageMode.ECMASCRIPT6);
148+
String js = "var goog = {}; class SubClass extends SomethingWithoutNS {}";
149+
String warning = "'SomethingWithoutNS' used but not goog.require'd";
150+
test(js, js, null, MISSING_REQUIRE_WARNING, warning);
151+
}
152+
153+
public void testEs6ClassExtendsSomethingInExterns() {
154+
setAcceptedLanguage(LanguageMode.ECMASCRIPT6);
155+
String js = "var goog = {}; class SubClass extends SomethingInExterns {}";
156+
List<SourceFile> externs = ImmutableList.of(SourceFile.fromCode("externs",
157+
"/** @constructor */ var SomethingInExterns;"));
158+
test(externs, js, js, null, null, null);
159+
}
160+
161+
public void testEs6ClassExtendsSomethingInExternsWithNS() {
162+
setAcceptedLanguage(LanguageMode.ECMASCRIPT6);
163+
String js = "var goog = {}; class SubClass extends MyExterns.SomethingInExterns {}";
164+
List<SourceFile> externs = ImmutableList.of(SourceFile.fromCode("externs",
165+
"var MyExterns;\n"
166+
+ "/** @constructor */ MyExterns.SomethingInExterns;"));
167+
test(externs, js, js, null, null, null);
168+
}
169+
144170
public void testFailWithNestedNewNodes() {
145171
String[] js =
146172
new String[] {"var goog = {}; goog.require('goog.foo.Bar'); "

0 commit comments

Comments
 (0)