Enable strictFunctionTypes (#49929)

This commit is contained in:
Jake Bailey
2023-01-17 17:20:51 -08:00
committed by GitHub
parent 436833aba1
commit 22b362ceac
60 changed files with 1263 additions and 869 deletions

View File

@@ -17,6 +17,7 @@ import {
isJSDocIndexSignature,
isOptionalJSDocPropertyLikeTag,
isParameter,
isTypeNode,
JSDocFunctionType,
JSDocNonNullableType,
JSDocNullableType,
@@ -35,7 +36,6 @@ import {
SyntaxKind,
textChanges,
tryCast,
TypeNode,
TypeReferenceNode,
VariableDeclaration,
visitEachChild,
@@ -100,19 +100,19 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, de
for (const param of decl.parameters) {
if (!param.type) {
const paramType = getJSDocType(param);
if (paramType) changes.tryInsertTypeAnnotation(sourceFile, param, transformJSDocType(paramType));
if (paramType) changes.tryInsertTypeAnnotation(sourceFile, param, visitNode(paramType, transformJSDocType, isTypeNode));
}
}
if (needParens) changes.insertNodeAfter(sourceFile, last(decl.parameters), factory.createToken(SyntaxKind.CloseParenToken));
if (!decl.type) {
const returnType = getJSDocReturnType(decl);
if (returnType) changes.tryInsertTypeAnnotation(sourceFile, decl, transformJSDocType(returnType));
if (returnType) changes.tryInsertTypeAnnotation(sourceFile, decl, visitNode(returnType, transformJSDocType, isTypeNode));
}
}
else {
const jsdocType = Debug.checkDefined(getJSDocType(decl), "A JSDocType for this declaration should exist"); // If not defined, shouldn't have been an error to fix
Debug.assert(!decl.type, "The JSDocType decl should have a type"); // If defined, shouldn't have been an error to fix.
changes.tryInsertTypeAnnotation(sourceFile, decl, transformJSDocType(jsdocType));
changes.tryInsertTypeAnnotation(sourceFile, decl, visitNode(jsdocType, transformJSDocType, isTypeNode));
}
}
@@ -123,7 +123,7 @@ function isDeclarationWithType(node: Node): node is DeclarationWithType {
node.kind === SyntaxKind.PropertyDeclaration;
}
function transformJSDocType(node: TypeNode): TypeNode {
function transformJSDocType(node: Node): Node {
switch (node.kind) {
case SyntaxKind.JSDocAllType:
case SyntaxKind.JSDocUnknownType:
@@ -155,21 +155,21 @@ function transformJSDocTypeLiteral(node: JSDocTypeLiteral) {
/*modifiers*/ undefined,
isIdentifier(tag.name) ? tag.name : tag.name.right,
isOptionalJSDocPropertyLikeTag(tag) ? factory.createToken(SyntaxKind.QuestionToken) : undefined,
tag.typeExpression && visitNode(tag.typeExpression.type, transformJSDocType) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword))));
tag.typeExpression && visitNode(tag.typeExpression.type, transformJSDocType, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword))));
setEmitFlags(typeNode, EmitFlags.SingleLine);
return typeNode;
}
function transformJSDocOptionalType(node: JSDocOptionalType) {
return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType), factory.createTypeReferenceNode("undefined", emptyArray)]);
return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType, isTypeNode), factory.createTypeReferenceNode("undefined", emptyArray)]);
}
function transformJSDocNullableType(node: JSDocNullableType) {
return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType), factory.createTypeReferenceNode("null", emptyArray)]);
return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType, isTypeNode), factory.createTypeReferenceNode("null", emptyArray)]);
}
function transformJSDocVariadicType(node: JSDocVariadicType) {
return factory.createArrayTypeNode(visitNode(node.type, transformJSDocType));
return factory.createArrayTypeNode(visitNode(node.type, transformJSDocType, isTypeNode));
}
function transformJSDocFunctionType(node: JSDocFunctionType) {
@@ -183,7 +183,7 @@ function transformJSDocParameter(node: ParameterDeclaration) {
const isRest = node.type!.kind === SyntaxKind.JSDocVariadicType && index === node.parent.parameters.length - 1; // TODO: GH#18217
const name = node.name || (isRest ? "rest" : "arg" + index);
const dotdotdot = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : node.dotDotDotToken;
return factory.createParameterDeclaration(node.modifiers, dotdotdot, name, node.questionToken, visitNode(node.type, transformJSDocType), node.initializer);
return factory.createParameterDeclaration(node.modifiers, dotdotdot, name, node.questionToken, visitNode(node.type, transformJSDocType, isTypeNode), node.initializer);
}
function transformJSDocTypeReference(node: TypeReferenceNode) {
@@ -212,7 +212,7 @@ function transformJSDocTypeReference(node: TypeReferenceNode) {
args = factory.createNodeArray([factory.createTypeReferenceNode("any", emptyArray)]);
}
else {
args = visitNodes(node.typeArguments, transformJSDocType);
args = visitNodes(node.typeArguments, transformJSDocType, isTypeNode);
}
}
return factory.createTypeReferenceNode(name, args);

View File

@@ -51,6 +51,7 @@ import {
isPropertyAssignment,
isSetAccessorDeclaration,
isStringLiteral,
isTypeNode,
isYieldExpression,
LanguageServiceHost,
length,
@@ -100,6 +101,7 @@ import {
UserPreferences,
visitEachChild,
visitNode,
visitNodes,
} from "../_namespaces/ts";
import { ImportAdder } from "../_namespaces/ts.codefix";
@@ -852,12 +854,11 @@ export function findJsonProperty(obj: ObjectLiteralExpression, name: string): Pr
*/
export function tryGetAutoImportableReferenceFromTypeNode(importTypeNode: TypeNode | undefined, scriptTarget: ScriptTarget) {
let symbols: Symbol[] | undefined;
const typeNode = visitNode(importTypeNode, visit);
const typeNode = visitNode(importTypeNode, visit, isTypeNode);
if (symbols && typeNode) {
return { typeNode, symbols };
}
function visit(node: TypeNode): TypeNode;
function visit(node: Node): Node {
if (isLiteralImportTypeNode(node) && node.qualifier) {
// Symbol for the left-most thing after the dot
@@ -868,7 +869,7 @@ export function tryGetAutoImportableReferenceFromTypeNode(importTypeNode: TypeNo
: node.qualifier;
symbols = append(symbols, firstIdentifier.symbol);
const typeArguments = node.typeArguments?.map(visit);
const typeArguments = visitNodes(node.typeArguments, visit, isTypeNode);
return factory.createTypeReferenceNode(qualifier, typeArguments);
}
return visitEachChild(node, visit, nullTransformationContext);

View File

@@ -1002,9 +1002,13 @@ function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined {
// The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`.
const { parent } = token;
return (isJsxOpeningLikeElement(parent) && parent.tagName === token) || isJsxOpeningFragment(parent)
? tryCast(checker.resolveName(checker.getJsxNamespace(parent), isJsxOpeningLikeElement(parent) ? token : parent, SymbolFlags.Value, /*excludeGlobals*/ false), isUMDExportSymbol)
: undefined;
if ((isJsxOpeningLikeElement(parent) && parent.tagName === token) || isJsxOpeningFragment(parent)) {
const parentSymbol = checker.resolveName(checker.getJsxNamespace(parent), isJsxOpeningLikeElement(parent) ? token : parent, SymbolFlags.Value, /*excludeGlobals*/ false);
if (isUMDExportSymbol(parentSymbol)) {
return parentSymbol;
}
}
return undefined;
}
/**

View File

@@ -1595,7 +1595,7 @@ function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly
const statements = factory.createNodeArray(isBlock(body) ? body.statements.slice(0) : [isStatement(body) ? body : factory.createReturnStatement(skipParentheses(body as Expression))]);
// rewrite body if either there are writes that should be propagated back via return statements or there are substitutions
if (hasWritesOrVariableDeclarations || substitutions.size) {
const rewrittenStatements = visitNodes(statements, visitor).slice();
const rewrittenStatements = visitNodes(statements, visitor, isStatement).slice();
if (hasWritesOrVariableDeclarations && !hasReturn && isStatement(body)) {
// add return at the end to propagate writes back in case if control flow falls out of the function body
// it is ok to know that range has at least one return since it we only allow unconditional returns
@@ -1620,7 +1620,7 @@ function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly
if (!returnValueProperty) {
returnValueProperty = "__return";
}
assignments.unshift(factory.createPropertyAssignment(returnValueProperty, visitNode(node.expression, visitor)));
assignments.unshift(factory.createPropertyAssignment(returnValueProperty, visitNode(node.expression, visitor, isExpression)));
}
if (assignments.length === 1) {
return factory.createReturnStatement(assignments[0].name as Expression);

View File

@@ -1342,11 +1342,18 @@ export function assignPositionsToNode(node: Node): Node {
return newNode;
}
function assignPositionsToNodeArray(nodes: NodeArray<any>, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number) {
function assignPositionsToNodeArray(
nodes: NodeArray<Node> | undefined,
visitor: Visitor,
test?: (node: Node) => boolean,
start?: number,
count?: number,
): NodeArray<Node> | undefined {
const visited = visitNodes(nodes, visitor, test, start, count);
if (!visited) {
return visited;
}
Debug.assert(nodes);
// clone nodearray if necessary
const nodeArray = visited === nodes ? factory.createNodeArray(visited.slice(0)) : visited;
setTextRangePosEnd(nodeArray, getPos(nodes), getEnd(nodes));

View File

@@ -3069,10 +3069,10 @@ export function getSynthesizedDeepCloneWithReplacements<T extends Node>(
}
function getSynthesizedDeepCloneWorker<T extends Node>(node: T, replaceNode?: (node: Node) => Node | undefined): T {
const nodeClone: (n: T) => T = replaceNode
const nodeClone: <T extends Node>(n: T) => T = replaceNode
? n => getSynthesizedDeepCloneWithReplacements(n, /*includeTrivia*/ true, replaceNode)
: getSynthesizedDeepClone;
const nodesClone: (ns: NodeArray<T>) => NodeArray<T> = replaceNode
const nodesClone: <T extends Node>(ns: NodeArray<T> | undefined) => NodeArray<T> | undefined = replaceNode
? ns => ns && getSynthesizedDeepClonesWithReplacements(ns, /*includeTrivia*/ true, replaceNode)
: ns => ns && getSynthesizedDeepClones(ns);
const visited =
@@ -3964,7 +3964,7 @@ export function isNonGlobalDeclaration(declaration: Declaration) {
return false;
}
// If the file is a module written in TypeScript, it still might be in a `declare global` augmentation
return isInJSFile(declaration) || !findAncestor(declaration, isGlobalScopeAugmentation);
return isInJSFile(declaration) || !findAncestor(declaration, d => isModuleDeclaration(d) && isGlobalScopeAugmentation(d));
}
/** @internal */