Skip to content
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

Extract method #16960

Closed
wants to merge 60 commits into from
Closed
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
be27a1a
Rebased EM WIP
RyanCavanaugh Jun 30, 2017
e798257
Change refactor api in fourslash
RyanCavanaugh Jul 5, 2017
bf176a6
Add comments
RyanCavanaugh Jul 5, 2017
0130ebb
Better baselines
RyanCavanaugh Jul 5, 2017
bbf5cd7
Rename test we we can run it independent of unit tests
RyanCavanaugh Jul 5, 2017
9dd6bef
Change fourslash refactor API
RyanCavanaugh Jul 5, 2017
f21b7ae
Remove invalid assert
RyanCavanaugh Jul 5, 2017
674b1bf
Fix undefined computation of length
RyanCavanaugh Jul 5, 2017
9367473
Improved type baselines for EM .js
RyanCavanaugh Jul 5, 2017
1ea9972
Add validation to fourslash test
RyanCavanaugh Jul 5, 2017
1787fa8
Move text to diagnostic messages
RyanCavanaugh Jul 5, 2017
fb89c00
Merge branch 'master' into extract-method
RyanCavanaugh Jul 5, 2017
4aef5e7
Properly widen literal param types + emit correct return statements f…
RyanCavanaugh Jul 5, 2017
b5c5c40
Don't offer to extract lone identifiers
RyanCavanaugh Jul 6, 2017
b1fa49f
Don't fail if span is zero-length
RyanCavanaugh Jul 6, 2017
825237b
Don't crash when span is empty
RyanCavanaugh Jul 6, 2017
aa6f3aa
Restore assert and fix synthetic type node creation
RyanCavanaugh Jul 18, 2017
b7e4451
Re-use noop
RyanCavanaugh Jul 18, 2017
419a4c2
Address portion of CR feedback
RyanCavanaugh Jul 18, 2017
4218738
Only compute changes for requested refactors
RyanCavanaugh Jul 19, 2017
6d2bc90
Address more PR comments
RyanCavanaugh Jul 19, 2017
9a24549
Merge master
RyanCavanaugh Jul 19, 2017
271ecb1
Remove WS
RyanCavanaugh Jul 19, 2017
bdefcc3
Emit return types in ctxly-typed functions and don't emit annotations…
RyanCavanaugh Jul 19, 2017
6428b1e
Fix broken test
RyanCavanaugh Jul 19, 2017
8af8ac2
Handle fn params and duplicated scope names properly
RyanCavanaugh Jul 19, 2017
ede6671
Re-use isJS result
RyanCavanaugh Jul 19, 2017
55b28ad
You may not extract-method on exported declarations
RyanCavanaugh Jul 19, 2017
2d9eaa9
Correctly apply overlapped edits in fourslash
RyanCavanaugh Jul 20, 2017
2f2c780
Fix some parenting issues & start detecting stranded references
RyanCavanaugh Jul 20, 2017
63193da
Add return type annotation and regression test for a prior assert
RyanCavanaugh Jul 20, 2017
889292a
Detect would-be stranded references to extracted declarations
RyanCavanaugh Jul 24, 2017
e229d42
Tests
RyanCavanaugh Jul 24, 2017
7b2dd8a
Fix line ending
RyanCavanaugh Jul 24, 2017
bf6c0a9
Function blocks aren't statements!
RyanCavanaugh Jul 25, 2017
3424312
Disallow certain classes of refactors
RyanCavanaugh Jul 25, 2017
ff18df3
Add test
RyanCavanaugh Jul 25, 2017
7f29fcd
Handle static methods and static method name conflicts
RyanCavanaugh Jul 25, 2017
d39d95b
Merge
RyanCavanaugh Jul 25, 2017
dda5496
No extracting other non-statement blocks
RyanCavanaugh Jul 28, 2017
e88ff21
More disallowed extraction position
RyanCavanaugh Jul 28, 2017
bd80005
Block more nonworking extraction locations
RyanCavanaugh Jul 28, 2017
ff716d0
Properly enumerate class blocks
RyanCavanaugh Jul 28, 2017
1291cfd
Add tests task
RyanCavanaugh Jul 28, 2017
a26790f
Don't re-use nodes
RyanCavanaugh Jul 28, 2017
56e1d6d
Correctly detect JavaScriptness
RyanCavanaugh Jul 28, 2017
7f3a0a8
Create multi-line bodies
RyanCavanaugh Jul 31, 2017
003cd0a
Add support for validating specific refactor actions' availability
RyanCavanaugh Aug 3, 2017
a76664c
More testcases
RyanCavanaugh Aug 3, 2017
42e0652
Accept baselines
RyanCavanaugh Aug 3, 2017
46a84c3
Innumerable bugfixes
RyanCavanaugh Aug 3, 2017
a97ab93
Merge branch 'master' into extract-method
RyanCavanaugh Aug 3, 2017
37ae957
Add additional test
RyanCavanaugh Aug 3, 2017
2adb2b3
Fix some class scenarios (static methods, readonly inits in ctor)
RyanCavanaugh Aug 4, 2017
ba37830
Prevent extraction of exported variables
RyanCavanaugh Aug 4, 2017
4dafb40
No extraction of ambient declarations
RyanCavanaugh Aug 4, 2017
c1c7e83
Put __return first
RyanCavanaugh Aug 4, 2017
a4c41b8
Don't wrongly exclude accessor in indexed access exprs
RyanCavanaugh Aug 4, 2017
b5a88c1
Share selection logic; fix typos
RyanCavanaugh Aug 4, 2017
568d5f6
Merge branch 'master' into extract-method
RyanCavanaugh Aug 4, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Jakefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ var harnessSources = harnessCoreSources.concat([
"projectErrors.ts",
"matchFiles.ts",
"initializeTSConfig.ts",
"extractMethods.ts",
"printer.ts",
"textChanges.ts",
"telemetry.ts",
Expand Down
7 changes: 3 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,10 @@ namespace ts {
getSuggestionForNonexistentProperty,
getSuggestionForNonexistentSymbol,
getBaseConstraintOfType,
getJsxNamespace,
resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined {
location = getParseTreeNode(location);
return resolveName(location, name, meaning, /*nameNotFoundMessage*/ undefined, name);
resolveName(name, location, meaning) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the same as resolveNameAtLocation, but with a changed argument order and no looking up of parse tree nodes (I can only assume so it works on synthesized nodes with parent pointers setup)? Can we not just remove the looking up of parse tree nodes in resolveNameAtLocation if that's the case? Oh, nameArg is also undefined. Can that not just be added as an optional parameter to this existing function?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rbuckton would know authoritatively, but as I understand it, we check isParseTreeNode on public API requests because the checker does not work well with synthesized nodes, since we don't perform binding on synthesized nodes as part of transforms (for performance reasons?) and we may inspect the literal text as part of some checker operations. That is, the checker API is only supposed to work with trees parsed and bound from an actual source file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aozgaa is correct. If the checker receives a node that did not originate from a parse tree, we attempt to find the parse tree node from which it was created. Passing in a synthesized node to the checker without a parse-tree check will likely result in compiler crashes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, resolveNameAtLocation (nee. resolveName) is marked /* @internal */ and isn't used in transforms. The guard is mostly present in case we decide to use it at some point down the road.

return resolveName(location, name, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
},
getJsxNamespace,
};

const tupleTypes: GenericType[] = [];
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3647,6 +3647,16 @@
"code": 95002
},

"Extract function": {
"category": "Message",
"code": 95003
},

"Extract function into '{0}'": {
"category": "Message",
"code": 95004
},

"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
"category": "Error",
"code": 8017
Expand Down
3 changes: 1 addition & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2645,9 +2645,8 @@ namespace ts {
* Does not include properties of primitive types.
*/
/* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[];

/* @internal */ resolveName(name: string, location: Node, meaning: SymbolFlags): Symbol;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to | undefined? Does it throw on failure?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler doesn't have strictNullChecks on. Added | undefined to be explicit.

/* @internal */ getJsxNamespace(): string;
/* @internal */ resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined;
}

export enum NodeBuilderFlags {
Expand Down
56 changes: 56 additions & 0 deletions src/harness/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ namespace FourSlash {

// The current caret position in the active file
public currentCaretPosition = 0;
// The position of the end of the current selection, or -1 if nothing is selected
public selectionEnd = -1;

public lastKnownMarker = "";

// The file that's currently 'opened'
Expand Down Expand Up @@ -433,11 +436,19 @@ namespace FourSlash {

public goToPosition(pos: number) {
this.currentCaretPosition = pos;
this.selectionEnd = -1;
}

public select(startMarker: string, endMarker: string) {
const start = this.getMarkerByName(startMarker), end = this.getMarkerByName(endMarker);
this.goToPosition(start.position);
this.selectionEnd = end.position;
}

public moveCaretRight(count = 1) {
this.currentCaretPosition += count;
this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length);
this.selectionEnd = -1;
}

// Opens a file given its 0-based index or fileName
Expand Down Expand Up @@ -2748,6 +2759,25 @@ namespace FourSlash {
}
}

public verifyRefactorAvailable(negative: boolean, name?: string) {
const selection = {
pos: this.currentCaretPosition,
end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd
};

let refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, selection) || [];
if (name) {
refactors = refactors.filter(r => r.name === name);
}
const isAvailable = refactors.length > 0;
if (negative && isAvailable) {
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some.`);
}
if (!negative && !isAvailable) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if [](start = 12, length = 2)

else if

this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`);
}
}

public verifyApplicableRefactorAvailableForRange(negative: boolean) {
const ranges = this.getRanges();
if (!(ranges && ranges.length === 1)) {
Expand All @@ -2764,6 +2794,20 @@ namespace FourSlash {
}
}

public applyRefactor(refactorName: string, actionName: string) {
const range = { pos: this.currentCaretPosition, end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ pos: this.currentCaretPosition, end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd } [](start = 26, length = 113)

Duplicated from above?

const refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, range);
const refactor = ts.find(refactors, r => r.name === refactorName);
if (!refactor) {
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.`);
}

const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName);
for (const edit of editInfo.edits) {
this.applyEdits(edit.fileName, edit.textChanges);
}
}

public verifyFileAfterApplyingRefactorAtMarker(
markerName: string,
expectedContent: string,
Expand Down Expand Up @@ -3505,6 +3549,10 @@ namespace FourSlashInterface {
public file(indexOrName: any, content?: string, scriptKindName?: string): void {
this.state.openFile(indexOrName, content, scriptKindName);
}

public select(startMarker: string, endMarker: string) {
this.state.select(startMarker, endMarker);
}
}

export class VerifyNegatable {
Expand Down Expand Up @@ -3626,6 +3674,10 @@ namespace FourSlashInterface {
public applicableRefactorAvailableForRange() {
this.state.verifyApplicableRefactorAvailableForRange(this.negative);
}

public refactorAvailable(name?: string) {
this.state.verifyRefactorAvailable(this.negative, name);
}
}

export class Verify extends VerifyNegatable {
Expand Down Expand Up @@ -4017,6 +4069,10 @@ namespace FourSlashInterface {
public disableFormatting() {
this.state.enableFormatting = false;
}

public applyRefactor(refactorName: string, actionName: string) {
this.state.applyRefactor(refactorName, actionName);
}
}

export class Debug {
Expand Down
Loading