Skip to content

Commit e9a9d2c

Browse files
authored
Merge pull request #18518 from amcasey/ExtractMethodFixes25
Port Extract Method fixes from master
2 parents 4a63ed7 + 27bede8 commit e9a9d2c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+792
-1099
lines changed

src/compiler/core.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,4 +2596,6 @@ namespace ts {
25962596
export function isCheckJsEnabledForFile(sourceFile: SourceFile, compilerOptions: CompilerOptions) {
25972597
return sourceFile.checkJsDirective ? sourceFile.checkJsDirective.enabled : compilerOptions.checkJs;
25982598
}
2599+
2600+
export function assertTypeIsNever(_: never): void {}
25992601
}

src/harness/unittests/extractMethods.ts

Lines changed: 164 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,37 @@ namespace A {
378378
"Cannot extract range containing conditional return statement."
379379
]);
380380

381-
testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, ["Select more than a single token."]);
381+
testExtractRangeFailed("extractRangeFailed7",
382+
`
383+
function test(x: number) {
384+
while (x) {
385+
x--;
386+
[#|break;|]
387+
}
388+
}
389+
`,
390+
[
391+
"Cannot extract range containing conditional break or continue statements."
392+
]);
393+
testExtractRangeFailed("extractRangeFailed8",
394+
`
395+
function test(x: number) {
396+
switch (x) {
397+
case 1:
398+
[#|break;|]
399+
}
400+
}
401+
`,
402+
[
403+
"Cannot extract range containing conditional break or continue statements."
404+
]);
405+
testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, ["Select more than a single identifier."]);
406+
407+
testExtractRangeFailed("extractRangeFailed9",
408+
`var x = ([#||]1 + 2);`,
409+
[
410+
"Statement or expression expected."
411+
]);
382412

383413
testExtractMethod("extractMethod1",
384414
`namespace A {
@@ -547,12 +577,141 @@ namespace A {
547577
}
548578
}
549579
}`);
580+
581+
testExtractMethod("extractMethod20",
582+
`const _ = class {
583+
a() {
584+
[#|let a1 = { x: 1 };
585+
return a1.x + 10;|]
586+
}
587+
}`);
588+
// Write + void return
589+
testExtractMethod("extractMethod21",
590+
`function foo() {
591+
let x = 10;
592+
[#|x++;
593+
return;|]
594+
}`);
595+
// Return in finally block
596+
testExtractMethod("extractMethod22",
597+
`function test() {
598+
try {
599+
}
600+
finally {
601+
[#|return 1;|]
602+
}
603+
}`);
604+
// Extraction position - namespace
605+
testExtractMethod("extractMethod23",
606+
`namespace NS {
607+
function M1() { }
608+
function M2() {
609+
[#|return 1;|]
610+
}
611+
function M3() { }
612+
}`);
613+
// Extraction position - function
614+
testExtractMethod("extractMethod24",
615+
`function Outer() {
616+
function M1() { }
617+
function M2() {
618+
[#|return 1;|]
619+
}
620+
function M3() { }
621+
}`);
622+
// Extraction position - file
623+
testExtractMethod("extractMethod25",
624+
`function M1() { }
625+
function M2() {
626+
[#|return 1;|]
627+
}
628+
function M3() { }`);
629+
// Extraction position - class without ctor
630+
testExtractMethod("extractMethod26",
631+
`class C {
632+
M1() { }
633+
M2() {
634+
[#|return 1;|]
635+
}
636+
M3() { }
637+
}`);
638+
// Extraction position - class with ctor in middle
639+
testExtractMethod("extractMethod27",
640+
`class C {
641+
M1() { }
642+
M2() {
643+
[#|return 1;|]
644+
}
645+
constructor() { }
646+
M3() { }
647+
}`);
648+
// Extraction position - class with ctor at end
649+
testExtractMethod("extractMethod28",
650+
`class C {
651+
M1() { }
652+
M2() {
653+
[#|return 1;|]
654+
}
655+
M3() { }
656+
constructor() { }
657+
}`);
658+
// Shorthand property names
659+
testExtractMethod("extractMethod29",
660+
`interface UnaryExpression {
661+
kind: "Unary";
662+
operator: string;
663+
operand: any;
664+
}
665+
666+
function parseUnaryExpression(operator: string): UnaryExpression {
667+
[#|return {
668+
kind: "Unary",
669+
operator,
670+
operand: parsePrimaryExpression(),
671+
};|]
672+
}
673+
674+
function parsePrimaryExpression(): any {
675+
throw "Not implemented";
676+
}`);
677+
// Return in nested function
678+
testExtractMethod("extractMethod31",
679+
`namespace N {
680+
681+
export const value = 1;
682+
683+
() => {
684+
var f: () => number;
685+
[#|f = function (): number {
686+
return value;
687+
}|]
688+
}
689+
}`);
690+
// Return in nested class
691+
testExtractMethod("extractMethod32",
692+
`namespace N {
693+
694+
export const value = 1;
695+
696+
() => {
697+
[#|var c = class {
698+
M() {
699+
return value;
700+
}
701+
}|]
702+
}
703+
}`);
704+
// Selection excludes leading trivia of declaration
705+
testExtractMethod("extractMethod33",
706+
`function F() {
707+
[#|function G() { }|]
708+
}`);
550709
});
551710

552711

553712
function testExtractMethod(caption: string, text: string) {
554713
it(caption, () => {
555-
Harness.Baseline.runBaseline(`extractMethod/${caption}.js`, () => {
714+
Harness.Baseline.runBaseline(`extractMethod/${caption}.ts`, () => {
556715
const t = extractTest(text);
557716
const selectionRange = t.ranges.get("selection");
558717
if (!selectionRange) {
@@ -562,7 +721,7 @@ namespace A {
562721
path: "/a.ts",
563722
content: t.source
564723
};
565-
const host = projectSystem.createServerHost([f]);
724+
const host = projectSystem.createServerHost([f, projectSystem.libFile]);
566725
const projectService = projectSystem.createProjectService(host);
567726
projectService.openClientFile(f.path);
568727
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
@@ -579,12 +738,12 @@ namespace A {
579738
assert.equal(result.errors, undefined, "expect no errors");
580739
const results = refactor.extractMethod.getPossibleExtractions(result.targetRange, context);
581740
const data: string[] = [];
582-
data.push(`==ORIGINAL==`);
741+
data.push(`// ==ORIGINAL==`);
583742
data.push(sourceFile.text);
584743
for (const r of results) {
585744
const { renameLocation, edits } = refactor.extractMethod.getExtractionAtIndex(result.targetRange, context, results.indexOf(r));
586745
assert.lengthOf(edits, 1);
587-
data.push(`==SCOPE::${r.scopeDescription}==`);
746+
data.push(`// ==SCOPE::${r.scopeDescription}==`);
588747
const newText = textChanges.applyChanges(sourceFile.text, edits[0].textChanges);
589748
const newTextWithRename = newText.slice(0, renameLocation) + "/*RENAME*/" + newText.slice(renameLocation);
590749
data.push(newTextWithRename);

0 commit comments

Comments
 (0)