Merge pull request #33300 from JoshuaKGoldberg/too-large-integer-bigint-codefix

Added codefix for numeric literals >= 2 ** 53
This commit is contained in:
Orta 2019-09-11 22:53:19 +02:00 committed by GitHub
commit e8fc62e1a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 143 additions and 0 deletions

View file

@ -33716,9 +33716,33 @@ namespace ts {
return grammarErrorOnNode(withMinus ? node.parent : node, diagnosticMessage, literal);
}
}
// Realism (size) checking
checkNumericLiteralValueSize(node);
return false;
}
function checkNumericLiteralValueSize(node: NumericLiteral) {
// Scientific notation (e.g. 2e54 and 1e00000000010) can't be converted to bigint
// Literals with 15 or fewer characters aren't long enough to reach past 2^53 - 1
// Fractional numbers (e.g. 9000000000000000.001) are inherently imprecise anyway
if (node.numericLiteralFlags & TokenFlags.Scientific || node.text.length <= 15 || node.text.indexOf(".") !== -1) {
return;
}
// We can't rely on the runtime to accurately store and compare extremely large numeric values
// Even for internal use, we use getTextOfNode: https://github.com/microsoft/TypeScript/issues/33298
// Thus, if the runtime claims a too-large number is lower than Number.MAX_SAFE_INTEGER,
// it's likely addition operations on it will fail too
const apparentValue = +getTextOfNode(node);
if (apparentValue <= 2 ** 53 - 1 && apparentValue + 1 > apparentValue) {
return;
}
addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers));
}
function checkGrammarBigIntLiteral(node: BigIntLiteral): boolean {
const literalType = isLiteralTypeNode(node.parent) ||
isPrefixUnaryExpression(node.parent) && isLiteralTypeNode(node.parent.parent);

View file

@ -4643,6 +4643,10 @@
"category": "Suggestion",
"code": 80007
},
"Numeric literals with absolute values equal to 2^53 or greater are too large to be represented accurately as integers.": {
"category": "Suggestion",
"code": 80008
},
"Add missing 'super()' call": {
"category": "Message",
@ -5124,6 +5128,14 @@
"category": "Message",
"code": 95090
},
"Convert to a bigint numeric literal": {
"category": "Message",
"code": 95091
},
"Convert all to bigint numeric literals": {
"category": "Message",
"code": 95092
},
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
"category": "Error",

View file

@ -0,0 +1,33 @@
/* @internal */
namespace ts.codefix {
const fixId = "useBigintLiteral";
const errorCodes = [
Diagnostics.Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers.code,
];
registerCodeFix({
errorCodes,
getCodeActions: context => {
const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span));
if (changes.length > 0) {
return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_a_bigint_numeric_literal, fixId, Diagnostics.Convert_all_to_bigint_numeric_literals)];
}
},
fixIds: [fixId],
getAllCodeActions: context => {
return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag));
},
});
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan) {
const numericLiteral = tryCast(getTokenAtPosition(sourceFile, span.start), isNumericLiteral);
if (!numericLiteral) {
return;
}
// We use .getText to overcome parser inaccuracies: https://github.com/microsoft/TypeScript/issues/33298
const newText = numericLiteral.getText(sourceFile) + "n";
changeTracker.replaceNode(sourceFile, numericLiteral, createBigIntLiteral(newText));
}
}

View file

@ -79,6 +79,7 @@
"codefixes/fixStrictClassInitialization.ts",
"codefixes/requireInTs.ts",
"codefixes/useDefaultImport.ts",
"codefixes/useBigintLiteral.ts",
"codefixes/fixAddModuleReferTypeMissingTypeof.ts",
"codefixes/convertToMappedObjectType.ts",
"codefixes/removeUnnecessaryAwait.ts",

View file

@ -0,0 +1,73 @@
/// <reference path="fourslash.ts" />
////9007199254740991;
////-9007199254740991;
////9007199254740992;
////-9007199254740992;
////9007199254740993;
////-9007199254740993;
////9007199254740994;
////-9007199254740994;
////0x19999999999998;
////-0x19999999999998;
////0x19999999999999;
////-0x19999999999999;
////0x20000000000000;
////-0x20000000000000;
////0x20000000000001;
////-0x20000000000001;
////2e52;
////2e53;
////2e54;
////1e00000000010;
verify.codeFix({
description: ts.Diagnostics.Convert_to_a_bigint_numeric_literal.message,
index: 0,
newFileContent:
`9007199254740991;
-9007199254740991;
9007199254740992n;
-9007199254740992;
9007199254740993;
-9007199254740993;
9007199254740994;
-9007199254740994;
0x19999999999998;
-0x19999999999998;
0x19999999999999;
-0x19999999999999;
0x20000000000000;
-0x20000000000000;
0x20000000000001;
-0x20000000000001;
2e52;
2e53;
2e54;
1e00000000010;`
});
verify.codeFixAll({
fixAllDescription: ts.Diagnostics.Convert_all_to_bigint_numeric_literals.message,
fixId: "useBigintLiteral",
newFileContent:
`9007199254740991;
-9007199254740991;
9007199254740992n;
-9007199254740992n;
9007199254740993n;
-9007199254740993n;
9007199254740994n;
-9007199254740994n;
0x19999999999998;
-0x19999999999998;
0x19999999999999;
-0x19999999999999;
0x20000000000000n;
-0x20000000000000n;
0x20000000000001n;
-0x20000000000001n;
2e52;
2e53;
2e54;
1e00000000010;`
});