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

Enable method signature completion for object literals #48168

Merged
merged 38 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
41913b7
skeleton of new feature
gabritto Feb 23, 2022
d5038ce
working prototype
gabritto Feb 25, 2022
fca74c1
refactor print and format code into its own function
gabritto Feb 25, 2022
249c3ba
minor changes; don't support overloads
gabritto Mar 1, 2022
ef15f81
have two completion entries
gabritto Mar 2, 2022
1f26a52
get rid of accessor support
gabritto Mar 4, 2022
1c28090
add snippet support
gabritto Mar 4, 2022
e628590
add formatting
gabritto Mar 4, 2022
515fc73
add trailing comma
gabritto Mar 4, 2022
0229a7d
add sourcedisplay
gabritto Mar 5, 2022
9892dc8
support auto-imports via completion details
gabritto Mar 5, 2022
8550bba
add user preference option and fix ordering of entries
gabritto Mar 7, 2022
78c7d9e
cleanup
gabritto Mar 7, 2022
1f67d97
don't return code actions for no import fixes
gabritto Mar 8, 2022
6c96290
Merge branch 'main' into gabritto/issue46590
gabritto Mar 8, 2022
814561f
make sortText lower priority for snippets
gabritto Mar 9, 2022
088904e
get rid of flag
gabritto Mar 9, 2022
4e63276
use optional member sort text
gabritto Mar 9, 2022
474d9a9
update baselines
gabritto Mar 9, 2022
b5d05c0
don't collect method symbols if insert text is not supported
gabritto Mar 9, 2022
6914576
remove comment
gabritto Mar 16, 2022
0e0ae05
return undefined if type is not function type
gabritto Mar 17, 2022
36eac73
only slice if needed
gabritto Mar 17, 2022
b9cb703
use union reduction; more test cases
gabritto Mar 17, 2022
7c9cbdb
WIP: modify sort text system
gabritto Mar 21, 2022
07c4fcf
Improve new sort text system
gabritto Mar 22, 2022
5b0d86d
add signature and union type check
gabritto Mar 22, 2022
b032aa5
Merge branch 'main' into gabritto/issue46590
gabritto Mar 23, 2022
08a55c3
re-add flag
gabritto Mar 23, 2022
6ebe361
fix tests
gabritto Mar 23, 2022
411bc18
rename sort text helper
gabritto Mar 23, 2022
1ebdf3d
fix test and code for union case
gabritto Mar 24, 2022
5477408
add new flag to protocol type
gabritto Mar 24, 2022
af7de76
fix spaces
gabritto Mar 24, 2022
1b884c4
CR: minor fixes
gabritto Mar 29, 2022
3820f32
CR: more fixes
gabritto Mar 29, 2022
e7a51e6
CR: restructure main flow
gabritto Mar 29, 2022
203aab0
minor fix
gabritto Mar 29, 2022
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
24 changes: 12 additions & 12 deletions src/harness/fourslashImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -960,36 +960,36 @@ namespace FourSlash {
expected = typeof expected === "string" ? { name: expected } : expected;

if (actual.insertText !== expected.insertText) {
this.raiseError(`Completion insert text did not match: ${showTextDiff(expected.insertText || "", actual.insertText || "")}`);
this.raiseError(`At entry ${actual.name}: Completion insert text did not match: ${showTextDiff(expected.insertText || "", actual.insertText || "")}`);
}
const convertedReplacementSpan = expected.replacementSpan && ts.createTextSpanFromRange(expected.replacementSpan);
if (convertedReplacementSpan?.length) {
try {
assert.deepEqual(actual.replacementSpan, convertedReplacementSpan);
}
catch {
this.raiseError(`Expected completion replacementSpan to be ${stringify(convertedReplacementSpan)}, got ${stringify(actual.replacementSpan)}`);
this.raiseError(`At entry ${actual.name}: Expected completion replacementSpan to be ${stringify(convertedReplacementSpan)}, got ${stringify(actual.replacementSpan)}`);
}
}

if (expected.kind !== undefined || expected.kindModifiers !== undefined) {
assert.equal(actual.kind, expected.kind, `Expected 'kind' for ${actual.name} to match`);
assert.equal(actual.kindModifiers, expected.kindModifiers || "", `Expected 'kindModifiers' for ${actual.name} to match`);
assert.equal(actual.kind, expected.kind, `At entry ${actual.name}: Expected 'kind' for ${actual.name} to match`);
assert.equal(actual.kindModifiers, expected.kindModifiers || "", `At entry ${actual.name}: Expected 'kindModifiers' for ${actual.name} to match`);
}
if (expected.isFromUncheckedFile !== undefined) {
assert.equal<boolean | undefined>(actual.isFromUncheckedFile, expected.isFromUncheckedFile, "Expected 'isFromUncheckedFile' properties to match");
assert.equal<boolean | undefined>(actual.isFromUncheckedFile, expected.isFromUncheckedFile, `At entry ${actual.name}: Expected 'isFromUncheckedFile' properties to match`);
}
if (expected.isPackageJsonImport !== undefined) {
assert.equal<boolean | undefined>(actual.isPackageJsonImport, expected.isPackageJsonImport, "Expected 'isPackageJsonImport' properties to match");
assert.equal<boolean | undefined>(actual.isPackageJsonImport, expected.isPackageJsonImport, `At entry ${actual.name}: Expected 'isPackageJsonImport' properties to match`);
}

assert.equal(actual.hasAction, expected.hasAction, `Expected 'hasAction' properties to match`);
assert.equal(actual.isRecommended, expected.isRecommended, `Expected 'isRecommended' properties to match'`);
assert.equal(actual.isSnippet, expected.isSnippet, `Expected 'isSnippet' properties to match`);
assert.equal(actual.source, expected.source, `Expected 'source' values to match`);
assert.equal(actual.sortText, expected.sortText || ts.Completions.SortText.LocationPriority, `Expected 'sortText' properties to match`);
assert.equal(actual.hasAction, expected.hasAction, `At entry ${actual.name}: Expected 'hasAction' properties to match`);
assert.equal(actual.isRecommended, expected.isRecommended, `At entry ${actual.name}: Expected 'isRecommended' properties to match'`);
assert.equal(actual.isSnippet, expected.isSnippet, `At entry ${actual.name}: Expected 'isSnippet' properties to match`);
assert.equal(actual.source, expected.source, `At entry ${actual.name}: Expected 'source' values to match`);
assert.equal(actual.sortText, expected.sortText || ts.Completions.SortText.LocationPriority, `At entry ${actual.name}: Expected 'sortText' properties to match`);
if (expected.sourceDisplay && actual.sourceDisplay) {
assert.equal(ts.displayPartsToString(actual.sourceDisplay), expected.sourceDisplay, `Expected 'sourceDisplay' properties to match`);
assert.equal(ts.displayPartsToString(actual.sourceDisplay), expected.sourceDisplay, `At entry ${actual.name}: Expected 'sourceDisplay' properties to match`);
}

if (expected.text !== undefined) {
Expand Down
32 changes: 29 additions & 3 deletions src/harness/fourslashInterfaceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -950,9 +950,35 @@ namespace FourSlashInterface {
}

export namespace Completion {
export import SortText = ts.Completions.SortText;
import SortTextType = ts.Completions.SortText;
export type SortText = SortTextType;
export import CompletionSource = ts.Completions.CompletionSource;

export const SortText = {
// Presets
LocalDeclarationPriority: "10" as SortText,
LocationPriority: "11" as SortText,
OptionalMember: "12" as SortText,
MemberDeclaredBySpreadAssignment: "13" as SortText,
SuggestedClassMembers: "14" as SortText,
GlobalsOrKeywords: "15" as SortText,
AutoImportSuggestions: "16" as SortText,
JavascriptIdentifiers: "17" as SortText,

// Transformations
Deprecated(sortText: SortText): SortText {
return "z" + sortText as SortText;
},

ObjectLiteralProperty(presetSortText: SortText, symbolDisplayName: string): SortText {
return `${presetSortText}\0${symbolDisplayName}\0` as SortText;
},

AddIsSnippetSuffix(sortText: SortText): SortText {
return sortText + "1" as SortText;
},
};

const functionEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
kind: "function",
Expand All @@ -963,7 +989,7 @@ namespace FourSlashInterface {
name,
kind: "function",
kindModifiers: "deprecated,declare",
sortText: SortText.DeprecatedGlobalsOrKeywords
sortText: "z15" as SortText,
});
const varEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
Expand Down Expand Up @@ -992,7 +1018,7 @@ namespace FourSlashInterface {
name,
kind: "method",
kindModifiers: "deprecated,declare",
sortText: SortText.DeprecatedLocationPriority
sortText: "z11" as SortText,
});
const propertyEntry = (name: string): ExpectedCompletionEntryObject => ({
name,
Expand Down
6 changes: 3 additions & 3 deletions src/services/codefixes/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,10 @@ namespace ts.codefix {
return parameters;
}

function createMethodImplementingSignatures(
export function createMethodImplementingSignatures(
checker: TypeChecker,
context: TypeConstructionContext,
enclosingDeclaration: ClassLikeDeclaration,
enclosingDeclaration: Node,
signatures: readonly Signature[],
name: PropertyName,
optional: boolean,
Expand Down Expand Up @@ -420,7 +420,7 @@ namespace ts.codefix {
body);
}

function getReturnTypeFromSignatures(signatures: readonly Signature[], checker: TypeChecker, context: TypeConstructionContext, enclosingDeclaration: ClassLikeDeclaration): TypeNode | undefined {
function getReturnTypeFromSignatures(signatures: readonly Signature[], checker: TypeChecker, context: TypeConstructionContext, enclosingDeclaration: Node): TypeNode | undefined {
if (length(signatures)) {
const type = checker.getUnionType(map(signatures, checker.getReturnTypeOfSignature));
return checker.typeToTypeNode(type, enclosingDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context));
Expand Down
Loading