Repository: microsoft/TypeScript
File: src/services/codefixes/addNameToNamelessParameter.ts (TypeScript)

Code before:

    const parameters = param.parent.parameters;
    const i = parameters.indexOf(param);
    Debug.assert(!param.type, "Tried to add a parameter name to a parameter that already had one.");
    Debug.assert(i > -1, "Parameter not found in parent parameter list.");

    let end = param.name.getEnd();
    let typeNode: TypeNode = factory.createTypeReferenceNode(param.name as Identifier, /*typeArguments*/ undefined);
    let nextParam = tryGetNextParam(sourceFile, param);
    while (nextParam) {
        typeNode = factory.createArrayTypeNode(typeNode);
        end = nextParam.getEnd();
        nextParam = tryGetNextParam(sourceFile, nextParam);
    }

    const replacement = factory.createParameterDeclaration(
        param.modifiers,
        param.dotDotDotToken,
        "arg" + i,
        param.questionToken,
        param.dotDotDotToken ? isArrayTypeNode(typeNode) ? typeNode : factory.createArrayTypeNode(typeNode) : typeNode,
        param.initializer,
    );
    changeTracker.replaceRange(sourceFile, createRange(param.getStart(sourceFile), end), replacement);
}

function tryGetNextParam(sourceFile: SourceFile, param: ParameterDeclaration) {
    const nextToken = findNextToken(param.name, param.parent, sourceFile);
    if (nextToken && nextToken.kind === SyntaxKind.OpenBracketToken
        && isArrayBindingPattern(nextToken.parent) && isParameter(nextToken.parent.parent)) {
        return nextToken.parent.parent;
    }
    return undefined;
}


Review comment (suggestion):
```suggestion
/**
 * If a user wrote
 *
 *     (string[][]) => string
 *
 * the parser will see this as an erroneously written
 *
 *     (string, [], []) => string
 *
 * Here we effectively reparse and return these binding pattern parameters
 * as long as we have subsequent '[]' pairs.
 */
 function tryGetNextEmptyArrayBindingParam(sourceFile: SourceFile, param: ParameterDeclaration) {
```

Code after:

    const i = param.parent.parameters.indexOf(param);
    Debug.assert(!param.type, "Tried to add a parameter name to a parameter that already had one.");
    Debug.assert(i > -1, "Parameter not found in parent parameter list.");

    let end = param.name.getEnd();
    let typeNode: TypeNode = factory.createTypeReferenceNode(param.name as Identifier, /*typeArguments*/ undefined);
    let nextParam = tryGetNextParam(sourceFile, param);
    while (nextParam) {
        typeNode = factory.createArrayTypeNode(typeNode);
        end = nextParam.getEnd();
        nextParam = tryGetNextParam(sourceFile, nextParam);
    }

    const replacement = factory.createParameterDeclaration(
        param.modifiers,
        param.dotDotDotToken,
        "arg" + i,
        param.questionToken,
        param.dotDotDotToken && !isArrayTypeNode(typeNode) ? factory.createArrayTypeNode(typeNode) : typeNode,
        param.initializer,
    );
    changeTracker.replaceRange(sourceFile, createRange(param.getStart(sourceFile), end), replacement);
}

function tryGetNextParam(sourceFile: SourceFile, param: ParameterDeclaration) {
    const nextToken = findNextToken(param.name, param.parent, sourceFile);
    if (
        nextToken && nextToken.kind === SyntaxKind.OpenBracketToken
        && isArrayBindingPattern(nextToken.parent) && isParameter(nextToken.parent.parent)
    ) {
        return nextToken.parent.parent;
    }
    return undefined;
}