-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Promises to Async Await Code Fix #24939
Changes from 202 commits
f3971df
6f803f6
b8d8183
69795c8
6c0a712
546ee1b
8019335
6e31ff9
469da81
8c8ebe9
635cc04
5099bd1
b8353dc
25efbed
0b760bf
d3a92d9
460c6dd
73ed97e
effb559
3b1aff1
71b422d
9b2aa30
2384440
b806922
602a8a9
c1e5de6
bece3e1
4820eff
84521cb
f9e3840
8a80eef
dd69f0d
6e4810d
024ad02
015f972
41e007e
5b958c5
68e0195
4f972ff
bc9d554
25ea1b1
515b5ff
8104e36
4075943
92ecaf1
e29e0e8
28dca79
4ac1742
cfc3418
0b75df3
4483758
f992010
2b56131
f113a41
b1ff6d1
abeace9
caf2431
806d14a
4ed331e
32d07ba
bd54e37
6e5b414
3b69059
b1f5837
f324936
2d3e5a9
3a23df8
1b72493
a4fcd03
cb1cfab
4c5af5a
40f136b
6856457
8dfeac3
8b7ed24
9895781
d64ddb5
97156d1
cd0d492
588cb56
a57c6d0
fc2c9be
7ba13d8
28aef07
81cd525
182648a
6eef8ad
aed1c73
b23946e
99bc200
ae5efa4
a030b1e
209a14f
2e470cd
bc618d5
13fefe6
f3dafad
fe1c20c
7e0c435
0eb995e
7d89e1e
78e6dd7
563d7b7
84139b6
9acf608
e6bcadd
2a98d64
2b31faa
70d4173
d0d4aff
b88022b
71f9419
08dd6a2
4e7a1c0
67275d8
f00af95
ac1046b
607aded
404705b
26f3787
50c6b4a
eae41dd
627ac68
82bc741
6b25e01
18e18d8
c90ce2c
dbf7928
3088e43
963a759
c2879de
b446923
3cf0dfd
9e3302e
2b04c4a
d3d43d3
99320bc
5989e3a
136e2f3
4d9584d
1ea6daf
c71c5a5
c374480
5065ce9
d9597f0
366b812
15249e1
cb98743
02c37d9
4f26e8c
8ba2097
906b2ff
ccca0c0
f0e1ff4
64b1276
d3f125a
ebd69f2
b39772d
db243ad
9e548a0
fd7977b
994c5e7
5b32226
aa41e2f
41f0bb8
35b9638
4d8f6d2
cf331b4
60ababa
d472124
6c7a10c
774aece
b73bb55
87dd683
1a4eb08
de28298
32d9bae
5c01d7b
57b7ad2
9d6a0e6
8f9e306
16fc028
d1d5e76
794c52b
9bc4aa5
e8a6fb9
55d4cad
1cfee77
a17738d
0f4d97c
52b7c96
bb6b869
f41da80
2d21376
af20f70
e36b55a
31e5433
39ba3ea
8777657
e6c676e
25edf4c
54b6f2a
e2c02d6
1e72a46
ee994f1
8bcac69
05cb7bf
12bd6fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ namespace ts { | |
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] { | ||
program.getSemanticDiagnostics(sourceFile, cancellationToken); | ||
const diags: DiagnosticWithLocation[] = []; | ||
const checker = program.getDiagnosticsProducingTypeChecker(); | ||
|
||
if (sourceFile.commonJsModuleIndicator && | ||
(programContainsEs6Modules(program) || compilerOptionsIndicateEs6Modules(program.getCompilerOptions())) && | ||
|
@@ -68,6 +69,9 @@ namespace ts { | |
} | ||
} | ||
|
||
if (isFunctionLikeDeclaration(node)) { | ||
addConvertToAsyncFunctionDiagnostics(node, checker, diags); | ||
} | ||
node.forEachChild(check); | ||
} | ||
} | ||
|
@@ -109,7 +113,64 @@ namespace ts { | |
} | ||
} | ||
|
||
function addConvertToAsyncFunctionDiagnostics(node: FunctionLikeDeclaration, checker: TypeChecker, diags: DiagnosticWithLocation[]): void { | ||
|
||
const functionType = node.type ? checker.getTypeFromTypeNode(node.type) : undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should get the type of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if (isAsyncFunction(node) || !node.body) {
return;
}
const functionType = checker.getTypeAtLocation(node);
if (!functionType)
{
return;
} |
||
if (isAsyncFunction(node) || !node.body || !functionType) { | ||
return; | ||
} | ||
|
||
const callSignatures = checker.getSignaturesOfType(functionType, SignatureKind.Call); | ||
const returnType = callSignatures.length ? checker.getReturnTypeOfSignature(callSignatures[0]) : undefined; | ||
|
||
if (!returnType || !checker.getPromisedTypeOfPromise(returnType)) { | ||
return; | ||
} | ||
|
||
// collect all the return statements | ||
// check that a property access expression exists in there and that it is a handler | ||
const returnStatements = getReturnStatementsWithPromiseHandlers(node); | ||
if (returnStatements.length > 0) { | ||
diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_may_be_converted_to_an_async_function)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
} | ||
|
||
function getErrorNodeFromCommonJsIndicator(commonJsModuleIndicator: Node): Node { | ||
return isBinaryExpression(commonJsModuleIndicator) ? commonJsModuleIndicator.left : commonJsModuleIndicator; | ||
} | ||
|
||
/** @internal */ | ||
export function getReturnStatementsWithPromiseHandlers(node: Node): Node[] { | ||
const returnStatements: Node[] = []; | ||
if (isFunctionLike(node)) { | ||
forEachChild(node, visit); | ||
} | ||
else { | ||
visit(node); | ||
} | ||
|
||
function visit(child: Node) { | ||
if (isFunctionLike(child)) { | ||
return; | ||
} | ||
|
||
if (isReturnStatement(child)) { | ||
forEachChild(child, addHandlers); | ||
} | ||
|
||
function addHandlers(returnChild: Node) { | ||
if (isPromiseHandler(returnChild)) { | ||
returnStatements.push(child as ReturnStatement); | ||
} | ||
} | ||
|
||
forEachChild(child, visit); | ||
} | ||
return returnStatements; | ||
} | ||
|
||
function isPromiseHandler(node: Node): boolean { | ||
return (isCallExpression(node) && isPropertyAccessExpression(node.expression) && | ||
(node.expression.name.text === "then" || node.expression.name.text === "catch")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see you handling |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -226,7 +226,7 @@ namespace ts { | |
|
||
export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement } { | ||
return node.kind === SyntaxKind.Identifier && isBreakOrContinueStatement(node.parent) && node.parent.label === node; | ||
} | ||
} | ||
|
||
export function isLabelOfLabeledStatement(node: Node): node is Identifier { | ||
return node.kind === SyntaxKind.Identifier && isLabeledStatement(node.parent) && node.parent.label === node; | ||
|
@@ -396,7 +396,7 @@ namespace ts { | |
export function isThis(node: Node): boolean { | ||
switch (node.kind) { | ||
case SyntaxKind.ThisKeyword: | ||
// case SyntaxKind.ThisType: TODO: GH#9267 | ||
// case SyntaxKind.ThisType: TODO: GH#9267 | ||
return true; | ||
case SyntaxKind.Identifier: | ||
// 'this' as a parameter | ||
|
@@ -1650,14 +1650,34 @@ namespace ts { | |
* WARNING: This is an expensive operation and is only intended to be used in refactorings | ||
* and code fixes (because those are triggered by explicit user actions). | ||
*/ | ||
export function getSynthesizedDeepClone<T extends Node | undefined>(node: T, includeTrivia = true): T { | ||
const clone = node && getSynthesizedDeepCloneWorker(node as NonNullable<T>); | ||
export function getSynthesizedDeepClone<T extends Node | undefined>(node: T, includeTrivia = true, renameMap?: Map<Identifier>, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather this be left as-is and have the extra logic in the refactor code file. I don't want There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggested putting it here because it requires a deep clone. Are you okay with the code-fix-specific helper being largely copied from the shared helper? |
||
|
||
let clone; | ||
if (node && isIdentifier(node!) && renameMap && checker) { | ||
const symbol = checker.getSymbolAtLocation(node!); | ||
const renameInfo = symbol && renameMap.get(String(getSymbolId(symbol))); | ||
|
||
if (renameInfo) { | ||
clone = createIdentifier(renameInfo.text); | ||
} | ||
} | ||
|
||
if (!clone) { | ||
clone = node && getSynthesizedDeepCloneWorker(node as NonNullable<T>, renameMap, checker, callback); | ||
} | ||
|
||
if (clone && !includeTrivia) suppressLeadingAndTrailingTrivia(clone); | ||
return clone; | ||
if (callback && node) callback(node!, clone); | ||
|
||
return clone as T; | ||
} | ||
|
||
function getSynthesizedDeepCloneWorker<T extends Node>(node: T): T { | ||
const visited = visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext); | ||
|
||
function getSynthesizedDeepCloneWorker<T extends Node>(node: T, renameMap?: Map<Identifier>, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T { | ||
const visited = visitEachChild(node, function wrapper(node) { | ||
return getSynthesizedDeepClone(node, /*includeTrivia*/ true, renameMap, checker, callback); | ||
}, nullTransformationContext); | ||
|
||
if (visited === node) { | ||
// This only happens for leaf nodes - internal nodes always see their children change. | ||
const clone = getSynthesizedClone(node); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mark this as
/** @internal */