Skip to content

Commit 1250b48

Browse files
authored
Suggest simplifications for overzealous shifts (microsoft#59519)
1 parent 25e09d9 commit 1250b48

File tree

9 files changed

+1464
-4
lines changed

9 files changed

+1464
-4
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39831,6 +39831,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3983139831
}
3983239832
if (leftOk && rightOk) {
3983339833
checkAssignmentOperator(resultType);
39834+
switch (operator) {
39835+
case SyntaxKind.LessThanLessThanToken:
39836+
case SyntaxKind.LessThanLessThanEqualsToken:
39837+
case SyntaxKind.GreaterThanGreaterThanToken:
39838+
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
39839+
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
39840+
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
39841+
const rhsEval = evaluate(right);
39842+
if (typeof rhsEval.value === "number" && Math.abs(rhsEval.value) >= 32) {
39843+
errorOrSuggestion(
39844+
isEnumMember(walkUpParenthesizedExpressions(right.parent.parent)), // elevate from suggestion to error within an enum member
39845+
errorNode || operatorToken,
39846+
Diagnostics.This_operation_can_be_simplified_This_shift_is_identical_to_0_1_2,
39847+
getTextOfNode(left),
39848+
tokenToString(operator),
39849+
rhsEval.value % 32,
39850+
);
39851+
}
39852+
break;
39853+
default:
39854+
break;
39855+
}
3983439856
}
3983539857
return resultType;
3983639858
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6420,6 +6420,10 @@
64206420
"category": "Message",
64216421
"code": 6806
64226422
},
6423+
"This operation can be simplified. This shift is identical to `{0} {1} {2}`.": {
6424+
"category": "Error",
6425+
"code": 6807
6426+
},
64236427

64246428
"one of:": {
64256429
"category": "Message",

src/harness/compilerImpl.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ export class CompilationResult {
241241
}
242242
}
243243

244-
export function compileFiles(host: fakes.CompilerHost, rootFiles: string[] | undefined, compilerOptions: ts.CompilerOptions, typeScriptVersion?: string): CompilationResult {
244+
export function compileFiles(host: fakes.CompilerHost, rootFiles: string[] | undefined, compilerOptions: ts.CompilerOptions, typeScriptVersion?: string, captureSuggestions?: boolean): CompilationResult {
245245
if (compilerOptions.project || !rootFiles || rootFiles.length === 0) {
246246
const project = readProject(host.parseConfigHost, compilerOptions.project, compilerOptions);
247247
if (project) {
@@ -265,11 +265,17 @@ export function compileFiles(host: fakes.CompilerHost, rootFiles: string[] | und
265265
// and if the test is running `skipLibCheck` - an indicator that we want the tets to run quickly - skip the before/after error comparison, too
266266
const skipErrorComparison = ts.length(rootFiles) >= 100 || (!!compilerOptions.skipLibCheck && !!compilerOptions.declaration);
267267
const preProgram = !skipErrorComparison ? ts.createProgram({ rootNames: rootFiles || [], options: { ...compilerOptions, configFile: compilerOptions.configFile, traceResolution: false }, host, typeScriptVersion }) : undefined;
268-
const preErrors = preProgram && ts.getPreEmitDiagnostics(preProgram);
268+
let preErrors = preProgram && ts.getPreEmitDiagnostics(preProgram);
269+
if (preProgram && captureSuggestions) {
270+
preErrors = ts.concatenate(preErrors, ts.flatMap(preProgram.getSourceFiles(), f => preProgram.getSuggestionDiagnostics(f)));
271+
}
269272

270273
const program = ts.createProgram({ rootNames: rootFiles || [], options: compilerOptions, host, typeScriptVersion });
271274
const emitResult = program.emit();
272-
const postErrors = ts.getPreEmitDiagnostics(program);
275+
let postErrors = ts.getPreEmitDiagnostics(program);
276+
if (captureSuggestions) {
277+
postErrors = ts.concatenate(postErrors, ts.flatMap(program.getSourceFiles(), f => program.getSuggestionDiagnostics(f)));
278+
}
273279
const longerErrors = ts.length(preErrors) > postErrors.length ? preErrors : postErrors;
274280
const shorterErrors = longerErrors === preErrors ? postErrors : preErrors;
275281
const errors = preErrors && (preErrors.length !== postErrors.length) ? [

src/harness/harnessIO.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ export namespace Compiler {
282282
baselineFile?: string;
283283
libFiles?: string;
284284
noTypesAndSymbols?: boolean;
285+
captureSuggestions?: boolean;
285286
}
286287

287288
// Additional options not already in ts.optionDeclarations
@@ -303,6 +304,7 @@ export namespace Compiler {
303304
{ name: "fullEmitPaths", type: "boolean", defaultValueDescription: false },
304305
{ name: "noCheck", type: "boolean", defaultValueDescription: false },
305306
{ name: "reportDiagnostics", type: "boolean", defaultValueDescription: false }, // used to enable error collection in `transpile` baselines
307+
{ name: "captureSuggestions", type: "boolean", defaultValueDescription: false }, // Adds suggestion diagnostics to error baselines
306308
];
307309

308310
let optionsIndex: Map<string, ts.CommandLineOption>;
@@ -428,7 +430,7 @@ export namespace Compiler {
428430

429431
ts.assign(options, ts.convertToOptionsWithAbsolutePaths(options, path => ts.getNormalizedAbsolutePath(path, currentDirectory)));
430432
const host = new fakes.CompilerHost(fs, options);
431-
const result = compiler.compileFiles(host, programFileNames, options, typeScriptVersion);
433+
const result = compiler.compileFiles(host, programFileNames, options, typeScriptVersion, harnessSettings?.captureSuggestions === "true");
432434
result.symlinks = symlinks;
433435
(result as CompileFilesResult).repeat = newOptions => compileFiles(inputFiles, otherFiles, { ...harnessSettings, ...newOptions }, compilerOptions, originalCurrentDirectory, symlinks);
434436
return result as CompileFilesResult;

0 commit comments

Comments
 (0)