Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Add support for collapsing parameter properties with default values. #738

Merged
merged 9 commits into from
May 25, 2018
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ boolean maybeOverrideCodeGen(Node n) {
add(n.getDeclaredTypeExpression());
add(")");
return true;
case DEFAULT_VALUE:
case NAME:
// Prepend access modifiers on constructor params
if (n.getParent().isParamList()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@ public void visit(NodeTraversal t, Node n, Node parent) {
maybeSetInlineTypeExpression(parent, n, bestJSDocInfo, true);
}
break;
// If a DEVAULE_VALUE is in a PARAM_LIST we type annotate its first child which is the
// actual parameter.
case DEFAULT_VALUE:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default values can occur in ES6 destructuring too:

let {x = 0} = {};

Are sure this makes sense for those cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know this syntax before.

Added a test case. It seems fine because the parent node here is not a parameter list.

Node paramNode = n.getFirstChild();
if (parent != null && parent.isParamList() && paramNode != null && paramNode.isName()) {
boolean wasSetFromFunctionDoc = setParameterTypeFromFunctionDoc(paramNode, parent);
if (!wasSetFromFunctionDoc) {
// If we didn't set the parameter type from the functions's JsDoc, then maybe the type
// is inlined just before the parameter?
maybeSetInlineTypeExpression(paramNode, paramNode, bestJSDocInfo, false);
}
}
break;
case CAST:
setTypeExpression(n, n.getJSDocInfo().getType(), false);
break;
Expand Down Expand Up @@ -257,7 +270,9 @@ private boolean setParameterTypeFromFunctionDoc(Node node, Node parent) {
// Modify the AST to represent an optional parameter
if (parameterType.getRoot().getToken() == Token.EQUALS) {
attachTypeExpr = IR.name(node.getString());
attachTypeExpr.putBooleanProp(Node.OPT_ES6_TYPED, true);
if (!node.getParent().isDefaultValue()) {
attachTypeExpr.putBooleanProp(Node.OPT_ES6_TYPED, true);
}
nodeComments.replaceWithComment(node, attachTypeExpr);
}
setTypeExpression(attachTypeExpr, parameterType, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,16 +309,18 @@ public void visit(NodeTraversal t, Node n, Node parent) {
if (!nodeAfterDefault.isName()) {
continue;
}
// It appears that adding ACCESS_MODIFIERs to Default params do not come out though
// the CodeGenerator, thus not safe to remove the declaration.
// TODO(rado): fix in emitting code and remove this line.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, for cleaning up my TODOs!

if (param.isDefaultValue()) {
continue;
}
String paramName = nodeAfterDefault.getString();
@Nullable
JSTypeExpression paramType =
constructorJsDoc == null ? null : constructorJsDoc.getParameterType(paramName);
// The class member declaration on "this" will not have "=" in the JSDoc most of the
// time. Therefore we need to remove the "=" from the JSDoc of the parameter
// declaration so we can compare the types and collapse the parameter property.
if (param.isDefaultValue() && Token.EQUALS.equals(paramType.getRoot().getToken())) {
paramType =
new JSTypeExpression(
paramType.getRoot().getFirstChild(), paramType.getSourceName());
}
// Names must be equal. Types must be equal, or if the declaration has no type it is
// assumed to be the type of the parameter.
if (declaration.memberName.equals(paramName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ class C {
/** @private {number} */
this.d = d;
}
}
}

let {x = 0} = {};
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@
class C {
private a: number;
private b: number;
private c: number;

/**
* @param c with default
*/
constructor({a}, {b} = {b: 1}, c = 0, private d: number) {
constructor({a}, {b} = {b: 1}, private c: number = 0, private d: number) {
this.a = a;
this.b = b;
//!! Due to a closure bug this one stays behind even though it is possible
//!! to write it in shorthand form.
//!! Note: Tslint fix pass will pick it up.
this.c = c;
}
}
let {x = 0} = {};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ let oneParam = function(n: number) {};

function twoParams(b: boolean, s: string) {}

function withDefaultValue(list = []) {}
function withDefaultValue(list: any[] = []) {}

// Function returns
let anyReturn = function(): any {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
/** Possibly outdated information about Klass. */
export class Klass {
n: any;
list: any[];
x: any = 4;

constructor(n: number, list = []) {
constructor(n: number, public readonly list: any[] = []) {
this.n = n;
this.list = list;
}

foo(): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,12 @@ function B(a, b, c, d, e) {
this.d = d;
/** @const {number} */
this.e = e;
}

class C {
/** @param {string} a */
constructor(a = 'default value') {
/** @const */
this.a = a;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ class B {
public a: number, public b: number, protected c: number,
private d: number, public readonly e: number) {}
}

class C {
constructor(public readonly a: string = 'default value') {}
}