Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 0 additions & 1 deletion internal/fourslash/_scripts/failingTests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ TestImportNameCodeFixExistingImport11
TestImportNameCodeFixExistingImport8
TestImportNameCodeFixExistingImport9
TestImportNameCodeFixExistingImportEquals0
TestImportNameCodeFixExportAsDefault
TestImportNameCodeFixNewImportAmbient1
TestImportNameCodeFixNewImportAmbient3
TestImportNameCodeFixNewImportBaseUrl0
Expand Down
19 changes: 11 additions & 8 deletions internal/fourslash/_scripts/manualTests.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
autoImportPackageRootPathTypeModule
completionListInClosedFunction05
completionListWithLabel
completionsAtIncompleteObjectLiteralProperty
completionsImport_defaultAndNamedConflict
completionsImport_filteredByPackageJson_ambient
completionsImport_reExportDefault
completionsImport_reexportTransient
completionsSelfDeclaring1
completionsWithDeprecatedTag4
formatOnEnterInComment
duplicatePackageServices_fileChanges
navigationBarFunctionPrototype
navigationBarFunctionPrototype2
Expand All @@ -17,28 +24,24 @@ navto_excludeLib1
navto_excludeLib2
navto_excludeLib4
navto_serverExcludeLib
outliningForNonCompleteInterfaceDeclaration
outliningHintSpansForFunction
parserCorruptionAfterMapInClass
quickInfoForOverloadOnConst1
renameDefaultKeyword
renameForDefaultExport01
semicolonFormattingInsideAComment
semicolonFormattingInsideAStringLiteral
tsxCompletion12
completionsImport_reExportDefault
completionsImport_reexportTransient
jsDocFunctionSignatures2
jsDocFunctionSignatures12
outliningHintSpansForFunction
getOutliningSpans
outliningForNonCompleteInterfaceDeclaration
incrementalParsingWithJsDoc
autoCloseFragment
autoCloseTag
autoImportPackageRootPathTypeModule
completionListWithLabel
completionsImport_defaultAndNamedConflict
completionsWithStringReplacementMode1
jsdocParameterNameCompletion
stringLiteralCompletionsInPositionTypedUsingRest
importNameCodeFix_uriStyleNodeCoreModules1
completionsImport_filteredByPackageJson_ambient
importNameCodeFixDefaultExport7
importNameCodeFixOptionalImport0
18 changes: 18 additions & 0 deletions internal/fourslash/test_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ const (

func parseFileContent(fileName string, content string, fileOptions map[string]string) (*testFileWithMarkers, error) {
fileName = tspath.GetNormalizedAbsolutePath(fileName, "/")
content = chompLeadingSpace(content)

// The file content (minus metacharacters) so far
var output strings.Builder
Expand Down Expand Up @@ -466,6 +467,23 @@ func reportError(fileName string, line int, col int, message string) error {
return &fourslashError{fmt.Sprintf("%v (%v,%v): %v", fileName, line, col, message)}
}

func chompLeadingSpace(content string) string {
lines := strings.Split(content, "\n")
for _, line := range lines {
if len(line) > 0 && line[0] != ' ' {
return content
}
}

result := make([]string, len(lines))
for i, line := range lines {
if len(line) > 0 {
result[i] = line[1:]
}
}
return strings.Join(result, "\n")
}

type fourslashError struct {
err string
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import (
)

func TestFormatOnEnterInComment(t *testing.T) {
fourslash.SkipIfFailing(t)
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = ` /**
* /*1*/
*/`
const content = ` /**
* /*1*/
*/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import (
)

func TestSemicolonFormattingInsideAComment(t *testing.T) {
fourslash.SkipIfFailing(t)
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = ` ///**/`
const content = ` ///**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import (
)

func TestSemicolonFormattingInsideAStringLiteral(t *testing.T) {
fourslash.SkipIfFailing(t)
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = ` var x = "string/**/`
const content = ` var x = "string/**/`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToMarker(t, "")
Expand Down
54 changes: 42 additions & 12 deletions internal/ls/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/microsoft/typescript-go/internal/checker"
"github.com/microsoft/typescript-go/internal/collections"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/ls/lsconv"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/scanner"
)
Expand All @@ -22,24 +23,31 @@ func (l *LanguageService) ProvideDefinition(
clientSupportsLink := caps.TextDocument.Definition.LinkSupport

program, file := l.getProgramAndFile(documentURI)
node := astnav.GetTouchingPropertyName(file, int(l.converters.LineAndCharacterToPosition(file, position)))
pos := int(l.converters.LineAndCharacterToPosition(file, position))
node := astnav.GetTouchingPropertyName(file, pos)
reference := getReferenceAtPosition(file, pos, program)

if node.Kind == ast.KindSourceFile {
return lsproto.LocationOrLocationsOrDefinitionLinksOrNull{}, nil
}

originSelectionRange := l.createLspRangeFromNode(node, file)
if reference != nil && reference.file != nil {
return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, []*ast.Node{}, reference), nil
}

c, done := program.GetTypeCheckerForFile(ctx, file)
defer done()

if node.Kind == ast.KindOverrideKeyword {
if sym := getSymbolForOverriddenMember(c, node); sym != nil {
return l.createLocationsFromDeclarations(originSelectionRange, clientSupportsLink, sym.Declarations), nil
return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, sym.Declarations, nil /*reference*/), nil
}
}

if ast.IsJumpStatementTarget(node) {
if label := getTargetLabel(node.Parent, node.Text()); label != nil {
return l.createLocationsFromDeclarations(originSelectionRange, clientSupportsLink, []*ast.Node{label}), nil
return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, []*ast.Node{label}, nil /*reference*/), nil
}
}

Expand All @@ -52,7 +60,7 @@ func (l *LanguageService) ProvideDefinition(

if node.Kind == ast.KindReturnKeyword || node.Kind == ast.KindYieldKeyword || node.Kind == ast.KindAwaitKeyword {
if fn := ast.FindAncestor(node, ast.IsFunctionLikeDeclaration); fn != nil {
return l.createLocationsFromDeclarations(originSelectionRange, clientSupportsLink, []*ast.Node{fn}), nil
return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, []*ast.Node{fn}, nil /*reference*/), nil
}
}

Expand All @@ -63,7 +71,7 @@ func (l *LanguageService) ProvideDefinition(
nonFunctionDeclarations := core.Filter(slices.Clip(declarations), func(node *ast.Node) bool { return !ast.IsFunctionLike(node) })
declarations = append(nonFunctionDeclarations, calledDeclaration)
}
return l.createLocationsFromDeclarations(originSelectionRange, clientSupportsLink, declarations), nil
return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, declarations, reference), nil
}

func (l *LanguageService) ProvideTypeDefinition(
Expand Down Expand Up @@ -93,10 +101,10 @@ func (l *LanguageService) ProvideTypeDefinition(
declarations = core.Concatenate(getDeclarationsFromType(typeArgument), declarations)
}
if len(declarations) != 0 {
return l.createLocationsFromDeclarations(originSelectionRange, clientSupportsLink, declarations), nil
return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, declarations, nil /*reference*/), nil
}
if symbol.Flags&ast.SymbolFlagsValue == 0 && symbol.Flags&ast.SymbolFlagsType != 0 {
return l.createLocationsFromDeclarations(originSelectionRange, clientSupportsLink, symbol.Declarations), nil
return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, symbol.Declarations, nil /*reference*/), nil
}
}

Expand All @@ -121,13 +129,34 @@ type fileRange struct {
fileRange core.TextRange
}

func (l *LanguageService) createLocationsFromDeclarations(
func (l *LanguageService) createDefinitionLocations(
originSelectionRange *lsproto.Range,
clientSupportsLink bool,
declarations []*ast.Node,
reference *refInfo,
) lsproto.DefinitionResponse {
locations := make([]*lsproto.LocationLink, 0, len(declarations))
locations := make([]*lsproto.LocationLink, 0)
locationRanges := collections.Set[fileRange]{}

if reference != nil {
targetRange := lsproto.Range{
Start: lsproto.Position{
Line: 0,
Character: 0,
},
End: lsproto.Position{
Line: 0,
Character: 0,
},
}
locations = append(locations, &lsproto.LocationLink{
OriginSelectionRange: originSelectionRange,
TargetUri: lsconv.FileNameToDocumentURI(reference.fileName),
Copy link
Member

Choose a reason for hiding this comment

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

Could this ever need to go through the source mapper?

TargetRange: targetRange,
TargetSelectionRange: targetRange,
})
}

for _, decl := range declarations {
file := ast.GetSourceFileOfNode(decl)
fileName := file.FileName()
Expand All @@ -146,10 +175,11 @@ func (l *LanguageService) createLocationsFromDeclarations(
})
}
}
if !clientSupportsLink {
return createLocationsFromLinks(locations)

if clientSupportsLink {
return lsproto.LocationOrLocationsOrDefinitionLinksOrNull{DefinitionLinks: &locations}
}
return lsproto.LocationOrLocationsOrDefinitionLinksOrNull{DefinitionLinks: &locations}
return createLocationsFromLinks(locations)
}

func createLocationsFromLinks(links []*lsproto.LocationLink) lsproto.DefinitionResponse {
Expand Down
49 changes: 0 additions & 49 deletions internal/ls/findallreferences.go
Original file line number Diff line number Diff line change
Expand Up @@ -1451,55 +1451,6 @@ func (l *LanguageService) getReferencedSymbolsForModule(ctx context.Context, pro
return []*SymbolAndEntries{}
}

func getReferenceAtPosition(sourceFile *ast.SourceFile, position int, program *compiler.Program) *refInfo {
if referencePath := findReferenceInPosition(sourceFile.ReferencedFiles, position); referencePath != nil {
if file := program.GetSourceFileFromReference(sourceFile, referencePath); file != nil {
return &refInfo{reference: referencePath, fileName: file.FileName(), file: file, unverified: false}
}
return nil
}

if typeReferenceDirective := findReferenceInPosition(sourceFile.TypeReferenceDirectives, position); typeReferenceDirective != nil {
if reference := program.GetResolvedTypeReferenceDirectiveFromTypeReferenceDirective(typeReferenceDirective, sourceFile); reference != nil {
if file := program.GetSourceFile(reference.ResolvedFileName); file != nil {
return &refInfo{reference: typeReferenceDirective, fileName: file.FileName(), file: file, unverified: false}
}
}
return nil
}

if libReferenceDirective := findReferenceInPosition(sourceFile.LibReferenceDirectives, position); libReferenceDirective != nil {
if file := program.GetLibFileFromReference(libReferenceDirective); file != nil {
return &refInfo{reference: libReferenceDirective, fileName: file.FileName(), file: file, unverified: false}
}
return nil
}

if len(sourceFile.Imports()) == 0 && len(sourceFile.ModuleAugmentations) == 0 {
return nil
}

node := astnav.GetTouchingToken(sourceFile, position)
if !isModuleSpecifierLike(node) || !tspath.IsExternalModuleNameRelative(node.Text()) {
return nil
}
if resolution := program.GetResolvedModuleFromModuleSpecifier(sourceFile, node); resolution != nil {
verifiedFileName := resolution.ResolvedFileName
fileName := resolution.ResolvedFileName
if fileName == "" {
fileName = tspath.ResolvePath(tspath.GetDirectoryPath(sourceFile.FileName()), node.Text())
}
return &refInfo{
file: program.GetSourceFile(fileName),
fileName: fileName,
reference: nil,
unverified: verifiedFileName != "",
}
}

return nil
}

// -- Core algorithm for find all references --
func getSpecialSearchKind(node *ast.Node) string {
if node == nil {
Expand Down
52 changes: 52 additions & 0 deletions internal/ls/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/microsoft/typescript-go/internal/astnav"
"github.com/microsoft/typescript-go/internal/checker"
"github.com/microsoft/typescript-go/internal/collections"
"github.com/microsoft/typescript-go/internal/compiler"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/debug"
"github.com/microsoft/typescript-go/internal/jsnum"
Expand All @@ -18,6 +19,7 @@ import (
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/scanner"
"github.com/microsoft/typescript-go/internal/stringutil"
"github.com/microsoft/typescript-go/internal/tspath"
)

var quoteReplacer = strings.NewReplacer("'", `\'`, `\"`, `"`)
Expand Down Expand Up @@ -1484,6 +1486,56 @@ func toContextRange(textRange *core.TextRange, contextFile *ast.SourceFile, cont
return nil
}

func getReferenceAtPosition(sourceFile *ast.SourceFile, position int, program *compiler.Program) *refInfo {
if referencePath := findReferenceInPosition(sourceFile.ReferencedFiles, position); referencePath != nil {
if file := program.GetSourceFileFromReference(sourceFile, referencePath); file != nil {
return &refInfo{reference: referencePath, fileName: file.FileName(), file: file, unverified: false}
}
return nil
}

if typeReferenceDirective := findReferenceInPosition(sourceFile.TypeReferenceDirectives, position); typeReferenceDirective != nil {
if reference := program.GetResolvedTypeReferenceDirectiveFromTypeReferenceDirective(typeReferenceDirective, sourceFile); reference != nil {
if file := program.GetSourceFile(reference.ResolvedFileName); file != nil {
return &refInfo{reference: typeReferenceDirective, fileName: file.FileName(), file: file, unverified: false}
}
}
return nil
}

if libReferenceDirective := findReferenceInPosition(sourceFile.LibReferenceDirectives, position); libReferenceDirective != nil {
if file := program.GetLibFileFromReference(libReferenceDirective); file != nil {
return &refInfo{reference: libReferenceDirective, fileName: file.FileName(), file: file, unverified: false}
}
return nil
}

if len(sourceFile.Imports()) == 0 && len(sourceFile.ModuleAugmentations) == 0 {
return nil
}

node := astnav.GetTouchingToken(sourceFile, position)
if !isModuleSpecifierLike(node) || !tspath.IsExternalModuleNameRelative(node.Text()) {
return nil
}

if resolution := program.GetResolvedModuleFromModuleSpecifier(sourceFile, node); resolution != nil {
verifiedFileName := resolution.ResolvedFileName
fileName := resolution.ResolvedFileName
if fileName == "" {
fileName = tspath.ResolvePath(tspath.GetDirectoryPath(sourceFile.FileName()), node.Text())
}
return &refInfo{
file: program.GetSourceFile(fileName),
fileName: fileName,
reference: nil,
unverified: verifiedFileName != "",
}
}

return nil
}

func ptrTo[T any](v T) *T {
return &v
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@

// === documentHighlights ===
// === /d.ts ===
// /// <reference path="/*HIGHLIGHTS*/[|./a.ts|]" />
// /// <reference path="/*HIGHLIGHTS*/[|./a.ts|]" />
Loading