Skip to content

Signature help implementation #861

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

Merged
merged 45 commits into from
Jun 3, 2025

Conversation

navya9singh
Copy link
Member

This pr covers mostly everything that is needed for signature help except for signature help in .js files. Some tests that I haven't yet ported from Strada are tests for:

  1. Tagged templates
  2. Verify no signature help
  3. Filtered triggers
  4. Tests with JSDoc comments and other comments. It needs some changes in the test setup

@Copilot Copilot AI review requested due to automatic review settings May 12, 2025 21:09
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements support for signature help in the language server and makes extensive naming refactors throughout the checker and utility modules. Key changes include adding a new handler for signature help in the server, updating configuration for the SignatureHelpProvider, and renaming many internal API functions (e.g. getSignaturesOfType → GetSignaturesOfType) to improve consistency and clarity.

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated no comments.

Show a summary per file
File Description
internal/lsp/server.go Adds new case handling for SignatureHelpParams and configures the signature help provider.
internal/ls/utilities.go Updates comments and refactors type argument info functions without altering behavior.
internal/checker/utilities.go Renames internal helper functions (e.g. CanHaveSymbol, IsCallOrNewExpression) for consistency.
internal/checker/types.go Adds accessor methods on Signature and TupleType for better API exposure.
internal/checker/services.go Consistently replaces lower-case API functions with their exported versions.
internal/checker/relater.go Refactors signature comparison and tuple handling to use new exported functions.
internal/checker/printer.go Adjusts printer logic to use the new exported APIs and updates variadic parameter expansion.
internal/checker/jsx.go Updates JSX-related checks to use renamed functions.
internal/checker/inference.go Updates inference utilities with new function names.
internal/checker/flow.go Refactors flow analysis to call updated API names.
internal/checker/checker.go Widespread updates to use capitalized exported API functions for type retrievals and checks.
internal/astnav/tokens.go Adds a new helper function, HasQuestionToken, for token analysis.
internal/ast/utilities.go Adds helpers for handling template literal tokens and string text nodes.
_submodules/TypeScript Updates the submodule commit to a new revision.

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

This is looking pretty good overall. Beyond the comments I left, I suggest you look at every declaration of a slice and ask these questions:

  • is this a displayParts slice that should just be a string or a strings.Builder?
  • if not, can I allocate it with the correct capacity up front?

Comment on lines 120 to 125
signatureInformation := []*lsproto.SignatureInformation{}
signatureInformation = append(signatureInformation, &lsproto.SignatureInformation{
Label: item.Label,
Documentation: nil,
Parameters: &parameters,
})
Copy link
Member

Choose a reason for hiding this comment

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

This can be a single initialization

}

// Creating display label
typeParameterDisplayParts := []string{}
Copy link
Member

Choose a reason for hiding this comment

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

I would use a strings.Builder here

Comment on lines 191 to 197
callTargetDisplayParts := []string{}
if callTargetSymbol != nil {
callTargetDisplayParts = append(callTargetDisplayParts, c.SymbolToString(callTargetSymbol))
}
var items [][]signatureInformation
for _, candidateSignature := range *candidates {
items = append(items, getSignatureHelpItem(candidateSignature, argumentInfo.isTypeParameterList, callTargetDisplayParts, enclosingDeclaration, sourceFile, c))
Copy link
Member

Choose a reason for hiding this comment

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

This is the only call to getSignatureHelpItem, and callTargetDisplayParts is always length 0 or 1. It could just be a string. We know we're not going to have display parts anymore, so it doesn't seem like there's a need to keep the slices around. A lot of things can probably just become strings.

if callTargetSymbol != nil {
callTargetDisplayParts = append(callTargetDisplayParts, c.SymbolToString(callTargetSymbol))
}
var items [][]signatureInformation
Copy link
Member

Choose a reason for hiding this comment

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

This can be allocated with the correct length/capacity

@navya9singh navya9singh requested a review from andrewbranch May 29, 2025 17:47
@navya9singh navya9singh requested a review from gabritto June 2, 2025 22:58
Comment on lines 305 to 309
return runWithoutResolvedSignatureCaching(c, node, func() *Signature {
var res *Signature
res, candidatesOutArray = c.getResolvedSignatureWorker(node, CheckModeIsForSignatureHelp, argumentCount)
return res
}), candidatesOutArray
Copy link
Member

Choose a reason for hiding this comment

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

I think this technically works due to the evaluation order of multi-returns, but it kinda hurts my head. I'd personally rather this callback return a struct with the two results (which are then unpacked or returned as-is), or this call be split out into its own line before the return.

Copy link
Member

Choose a reason for hiding this comment

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

e.g.

func GetResolvedSignatureForSignatureHelp(node *ast.Node, argumentCount int, c *Checker) (*Signature, []*Signature) {
	type result struct {
		signature *signature
		candidates []*signature
	}
	result := runWithoutResolvedSignatureCaching(c, node, func() result {
		signature, candidates := c.getResolvedSignatureWorker(node, CheckModeIsForSignatureHelp, argumentCount)
		return result{signature, candidates}
	})
	return result.signature, result.candidates
}

@navya9singh navya9singh added this pull request to the merge queue Jun 3, 2025
Merged via the queue into microsoft:main with commit cdff2b1 Jun 3, 2025
23 checks passed
@navya9singh navya9singh deleted the signatureHelpImplementation branch June 3, 2025 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants