Skip to content

Commit 6132e47

Browse files
lukesandbergcopybara-github
authored andcommitted
Instead of using @noinline to tell OptimizeParameters to back off, create a new jsdoc annotation that is more precise @usedViaDotConstructor
This should be more intuitive and doesn't confuse the linter. PiperOrigin-RevId: 704434645
1 parent e3d3882 commit 6132e47

File tree

11 files changed

+69
-30
lines changed

11 files changed

+69
-30
lines changed

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

+12
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
160160
validateReturnJsDoc(n, info);
161161
validateTsType(n, info);
162162
validateJsDocTypeNames(info);
163+
validateIsUsedViaDotConstructor(n, info);
163164
}
164165

165166
private void validateSuppress(Node n, JSDocInfo info) {
@@ -837,4 +838,15 @@ public void visit(Node typeRefNode) {
837838
}
838839
}
839840
}
841+
842+
/** Checks that @usedViaDotConstructor is only used on constructors. */
843+
private void validateIsUsedViaDotConstructor(Node n, JSDocInfo info) {
844+
if (info == null || !info.isUsedViaDotConstructor()) {
845+
return;
846+
}
847+
if (!(n.isFunction() && info.isConstructor())
848+
&& !NodeUtil.isEs6ConstructorMemberFunctionDef(n)) {
849+
report(n, MISPLACED_ANNOTATION, "usedViaDotConstructor", "must be on a constructor");
850+
}
851+
}
840852
}

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

+10-19
Original file line numberDiff line numberDiff line change
@@ -671,8 +671,8 @@ private boolean allDefinitionsAreCandidateFunctions(Node n) {
671671
// In `function f(a, b = a) { ... }` it's very difficult to determine if `a` is
672672
// movable.
673673
&& !mayReferenceParamBeforeBody(functionNode)
674-
// `function f(/** @noinline */ a) {...}` means back off.
675-
&& !mayHaveNoInlineParameters(functionNode);
674+
// `/** @usedViaDotConstructor */ function f(a) {...}` means back off.
675+
&& !isUsedViaDotConstructor(functionNode);
676676
}
677677
}
678678
case FUNCTION:
@@ -682,8 +682,8 @@ private boolean allDefinitionsAreCandidateFunctions(Node n) {
682682
&& !NodeUtil.doesFunctionReferenceOwnArgumentsObject(n)
683683
// In `function f(a, b = a) { ... }` it's very difficult to determine if `a` is movable.
684684
&& !mayReferenceParamBeforeBody(n)
685-
// `function f(/** @noinline */ a) {...}` means back off.
686-
&& !mayHaveNoInlineParameters(n);
685+
// `/** @usedViaDotConstructor */ function f(a) {...}` means back off.
686+
&& !isUsedViaDotConstructor(n);
687687
case CAST:
688688
case COMMA:
689689
return allDefinitionsAreCandidateFunctions(n.getLastChild());
@@ -701,23 +701,14 @@ private boolean allDefinitionsAreCandidateFunctions(Node n) {
701701
}
702702

703703
/**
704-
* Returns true if the function has any parameters tagged with @noinline.
704+
* Returns true if the function is annotated with @usedViaDotConstructor
705705
*
706-
* <p>In this case we just back off on all parameter optimizations. We could be more clever and
707-
* only back off on the ones tagged @noinline, but it's not worth the complexity.
706+
* <p>In this case we just back off on all parameter optimizations since we cannot detect which
707+
* parameters are used via calls through {@code .constructor}.
708708
*/
709-
private static boolean mayHaveNoInlineParameters(Node function) {
710-
Node paramList = function.getSecondChild();
711-
if (!paramList.hasChildren()) {
712-
return false; // Fast path; there can't possibly be @noinline params.
713-
}
714-
for (Node param = paramList.getFirstChild(); param != null; param = param.getNext()) {
715-
var jsDocInfo = param.getJSDocInfo();
716-
if (jsDocInfo != null && jsDocInfo.isNoInline()) {
717-
return true;
718-
}
719-
}
720-
return false;
709+
private static boolean isUsedViaDotConstructor(Node function) {
710+
var docInfo = NodeUtil.getBestJSDocInfo(function);
711+
return docInfo != null && docInfo.isUsedViaDotConstructor();
721712
}
722713

723714
/**

src/com/google/javascript/jscomp/parsing/Annotation.java

+2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ enum Annotation {
100100
TYPEDEF,
101101
TYPE_SUMMARY,
102102
UNRESTRICTED,
103+
USED_VIA_DOT_CONSTRUCTOR,
103104
WIZACTION,
104105
TS_TYPE,
105106
WIZ_ANALYZER,
@@ -180,6 +181,7 @@ enum Annotation {
180181
.put("typedef", Annotation.TYPEDEF)
181182
.put("typeSummary", Annotation.TYPE_SUMMARY)
182183
.put("unrestricted", Annotation.UNRESTRICTED)
184+
.put("usedViaDotConstructor", Annotation.USED_VIA_DOT_CONSTRUCTOR)
183185
.put("wizaction", Annotation.WIZACTION)
184186
.put("tsType", Annotation.TS_TYPE)
185187
.put("wizAnalyzer", Annotation.WIZ_ANALYZER)

src/com/google/javascript/jscomp/parsing/JsDocInfoParser.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -773,9 +773,6 @@ private JsDocToken parseAnnotation(JsDocToken token, List<ExtendedTypeInfo> exte
773773
}
774774
return eatUntilEOLIfNotAnnotation();
775775

776-
case NOT_IMPLEMENTED:
777-
return eatUntilEOLIfNotAnnotation();
778-
779776
case INHERIT_DOC:
780777
case OVERRIDE:
781778
if (!jsdocBuilder.recordOverride()) {
@@ -1082,12 +1079,18 @@ private JsDocToken parseAnnotation(JsDocToken token, List<ExtendedTypeInfo> exte
10821079
case LOG_TYPE_IN_COMPILER:
10831080
var unused = jsdocBuilder.recordLogTypeInCompiler();
10841081
return eatUntilEOLIfNotAnnotation();
1082+
case NOT_IMPLEMENTED:
10851083
case JSX:
10861084
case JSX_FRAGMENT:
10871085
case SOY_MODULE:
10881086
case SOY_TEMPLATE:
10891087
case WIZ_ANALYZER:
10901088
return eatUntilEOLIfNotAnnotation();
1089+
case USED_VIA_DOT_CONSTRUCTOR:
1090+
if (!jsdocBuilder.recordUsedViaDotConstructor()) {
1091+
addParserWarning(Msg.JSDOC_USEDVIADOTCONSTRUCTOR);
1092+
}
1093+
return eatUntilEOLIfNotAnnotation();
10911094
case WIZACTION:
10921095
if (!jsdocBuilder.recordWizaction()) {
10931096
addParserWarning(Msg.JSDOC_WIZACTION);

src/com/google/javascript/jscomp/parsing/ParserConfig.properties

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ jsdoc.annotations =\
150150
typeSummary,\
151151
url,\
152152
usage,\
153+
usedViaDotConstructor,\
153154
version,\
154155
virtual,\
155156
visibility,\

src/com/google/javascript/jscomp/serialization/JSDocSerializer.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ public static JSDocInfo convertJSDocInfoForOptimizations(JSDocInfo jsdoc) {
170170
if (jsdoc.getSuppressions().contains("untranspilableFeatures")) {
171171
builder.addKind(JsdocTag.JSDOC_SUPPRESS_UNTRANSPILABLE_FEATURES);
172172
}
173+
if (jsdoc.isUsedViaDotConstructor()) {
174+
builder.addKind(JsdocTag.JSDOC_USED_VIA_DOT_CONSTRUCTOR);
175+
}
173176

174177
OptimizationJsdoc result = builder.build();
175178
if (OptimizationJsdoc.getDefaultInstance().equals(result)) {
@@ -349,7 +352,11 @@ private static JSTypeExpression createPlaceholderType() {
349352
case JSDOC_SASS_GENERATED_CSS_TS:
350353
builder.recordSassGeneratedCssTs();
351354
continue;
352-
355+
case JSDOC_USED_VIA_DOT_CONSTRUCTOR:
356+
{
357+
var unused = builder.recordUsedViaDotConstructor();
358+
continue;
359+
}
353360
case JSDOC_UNSPECIFIED:
354361
case UNRECOGNIZED:
355362
throw new MalformedTypedAstException(

src/com/google/javascript/rhino/JSDocInfo.java

+11
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ private static enum Bit {
325325
NOCOMPILE,
326326
NODTS,
327327
UNRESTRICTED,
328+
USED_VIA_DOT_CONSTRUCTOR,
328329
STRUCT,
329330
DICT,
330331
NOCOLLAPSE,
@@ -1240,6 +1241,11 @@ public boolean isClosureUnawareCode() {
12401241
return checkBit(Bit.CLOSURE_UNAWARE_CODE);
12411242
}
12421243

1244+
/** Returns whether JSDoc is annotated with the {@code @usedViaDotConstructor} annotation. */
1245+
public boolean isUsedViaDotConstructor() {
1246+
return checkBit(Bit.USED_VIA_DOT_CONSTRUCTOR);
1247+
}
1248+
12431249
/** Gets the description specified by the {@code @license} annotation. */
12441250
public String getLicense() {
12451251
return LICENSE.get(this);
@@ -2712,6 +2718,11 @@ public boolean recordClosureUnawareCode() {
27122718
return populateBit(Bit.CLOSURE_UNAWARE_CODE, true);
27132719
}
27142720

2721+
/** Records that this JSDoc was annotated with the {@code @usedViaDotConstructor} annotation. */
2722+
public boolean recordUsedViaDotConstructor() {
2723+
return populateBit(Bit.USED_VIA_DOT_CONSTRUCTOR, true);
2724+
}
2725+
27152726
// TODO(sdh): this is a new method - consider removing it in favor of recordType?
27162727
// The main difference is that this force-sets the type, while recordType backs off.
27172728
// This is useful for (e.g.) copyFromWithNewType.

src/com/google/javascript/rhino/Msg.java

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ public enum Msg {
144144
JSDOC_TYPETRANSFORMATION_MISSING_PARAM("Missing parameter in {0}"),
145145
JSDOC_TYPE_RECORD_DUPLICATE("Duplicate record field {0}."),
146146
JSDOC_TYPE_SYNTAX("type not recognized due to syntax error."),
147+
JSDOC_USEDVIADOTCONSTRUCTOR("extra @usedViaDotConstructor tag"),
147148
JSDOC_UNNECESSARY_BRACES("braces are not required here"),
148149
JSDOC_VERSIONMISSING("@version tag missing version information"),
149150
JSDOC_WIZACTION("extra @wizaction tag"),

src/com/google/javascript/rhino/typed_ast/optimization_jsdoc.proto

+3
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,7 @@ enum JsdocTag {
8383
// Used to require function inlining to enable other optimizations,
8484
// especially constant folding of object literals.
8585
JSDOC_REQUIRE_INLINING = 38;
86+
87+
// Used by OptimizeParameters
88+
JSDOC_USED_VIA_DOT_CONSTRUCTOR = 39;
8689
}

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

+7
Original file line numberDiff line numberDiff line change
@@ -1304,4 +1304,11 @@ public void testNameDeclarationAndAssignForAbstractClass() {
13041304
public void testNameDeclarationAndAssignForTemplatedClass() {
13051305
testSame(lines("/** @template T */", "let A = A_1 = class A {}"));
13061306
}
1307+
1308+
@Test
1309+
public void testIsUsedViaDotConstrucctor() {
1310+
testSame("/** @constructor @usedViaDotConstructor */ function A() {}");
1311+
testSame("class Foo {/** @usedViaDotConstructor */ constructor() {} }");
1312+
testWarning("/** @usedViaDotConstructor */ function A() {}", MISPLACED_ANNOTATION);
1313+
}
13071314
}

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

+8-7
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ public void testSimpleRemoval1() {
409409
test(
410410
"const foo = (p1)=>{ }; foo(); foo()", //
411411
"const foo = ( )=>{var p1;}; foo(); foo()");
412-
testSame("const foo = (/** @noinline */ p1)=>{}; foo(); foo()");
412+
testSame("class foo { /** @usedViaDotConstructor */ constructor(p1) {}} new foo(); new foo()");
413413

414414
// constant parameter
415415
test(
@@ -421,7 +421,8 @@ public void testSimpleRemoval1() {
421421
test(
422422
"const foo = (p1)=>{ }; foo(1); foo(1)",
423423
"const foo = ( )=>{var p1 = 1;}; foo( ); foo( )");
424-
testSame("const foo = (/** @noinline */ p1)=>{}; foo(1); foo(1)");
424+
testSame(
425+
"class foo { /** @usedViaDotConstructor */ constructor(p1) {}} new foo(1); new foo(1)");
425426
}
426427

427428
@Test
@@ -441,7 +442,7 @@ public void testSimpleRemoval2() {
441442
test(
442443
"function f(p1) { } new f(1,x()); new f(1,y())",
443444
"function f( ) {var p1 = 1;} new f( x()); new f( y())");
444-
testSame("function f(/** @noinline */ p1) {} new f(); new f()");
445+
testSame("/** @usedViaDotConstructor */ function f(p1) {} new f(); new f()");
445446
}
446447

447448
@Test
@@ -469,22 +470,22 @@ public void testSimpleRemoval4() {
469470
test(
470471
"function f(p1) { } f.prop = 1; new f(); new f()",
471472
"function f( ) {var p1;} f.prop = 1; new f(); new f()");
472-
testSame("function f(/** @noinline */ p1) {} f.prop = 1; new f(); new f()");
473+
testSame("/** @usedViaDotConstructor */ function f(p1) {} f.prop = 1; new f(); new f()");
473474

474475
test(
475476
"function f(p1) { } f.prop = 1; new f(1); new f(1)",
476477
"function f( ) {var p1 = 1;} f.prop = 1; new f( ); new f( )");
477-
testSame("function f(/** @noinline */ p1) {} f.prop = 1; new f(1); new f(1)");
478+
testSame("/** @usedViaDotConstructor */ function f(p1) {} f.prop = 1; new f(1); new f(1)");
478479

479480
test(
480481
"function f(p1) { } f['prop'] = 1; new f(); new f()",
481482
"function f( ) {var p1;} f['prop'] = 1; new f(); new f()");
482-
testSame("function f(/** @noinline */ p1) {} f['prop'] = 1; new f(); new f()");
483+
testSame("/** @usedViaDotConstructor */ function f(p1) {} f['prop'] = 1; new f(); new f()");
483484

484485
test(
485486
"function f(p1) { } f['prop'] = 1; new f(1); new f(1)",
486487
"function f( ) {var p1 = 1;} f['prop'] = 1; new f( ); new f( )");
487-
testSame("function f(/** @noinline */ p1) {} f['prop'] = 1; new f(1); new f(1)");
488+
testSame("/** @usedViaDotConstructor */ function f(p1) {} f['prop'] = 1; new f(1); new f(1)");
488489
}
489490

490491
@Test

0 commit comments

Comments
 (0)