Skip to content

Commit 4980bf4

Browse files
committed
more
1 parent 35c7b97 commit 4980bf4

File tree

2 files changed

+159
-1
lines changed

2 files changed

+159
-1
lines changed

internal/ls/findallreferences.go

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,93 @@ func getMergedAliasedSymbolOfNamespaceExportDeclaration(node *ast.Node, symbol *
976976
}
977977

978978
func getReferencedSymbolsForModule(program *compiler.Program, symbol *ast.Symbol, excludeImportTypeOfExportEquals bool, sourceFiles []*ast.SourceFile, sourceFilesSet *collections.Set[string]) []*SymbolAndEntries {
979-
// !!! not implemented
979+
debug.Assert(symbol.ValueDeclaration != nil)
980+
981+
checker, done := program.GetTypeChecker(nil)
982+
defer done()
983+
984+
references := core.MapNonNil(findModuleReferences(program, sourceFiles, symbol, checker), func(reference ModuleReference) *referenceEntry {
985+
switch reference.kind {
986+
case ModuleReferenceKindImport:
987+
parent := reference.literal.Parent
988+
if ast.IsLiteralTypeNode(parent) {
989+
importType := parent.Parent
990+
if ast.IsImportTypeNode(importType) {
991+
importTypeNode := importType.AsImportTypeNode()
992+
if excludeImportTypeOfExportEquals && importTypeNode.Qualifier == nil {
993+
return nil
994+
}
995+
}
996+
}
997+
// import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway.
998+
return newNodeEntry(reference.literal)
999+
case ModuleReferenceKindImplicit:
1000+
// For implicit references (e.g., JSX runtime imports), return the first statement or the whole file.
1001+
// We skip the complex JSX detection for now and just use the first statement or the file itself.
1002+
var rangeNode *ast.Node
1003+
if reference.referencingFile.Statements != nil && len(reference.referencingFile.Statements.Nodes) > 0 {
1004+
rangeNode = reference.referencingFile.Statements.Nodes[0]
1005+
} else {
1006+
rangeNode = reference.referencingFile.AsNode()
1007+
}
1008+
return newNodeEntry(rangeNode)
1009+
case ModuleReferenceKindReference:
1010+
// <reference path> or <reference types>
1011+
// We can't easily create a proper range entry here without access to LanguageService,
1012+
// but we can create a node-based entry pointing to the source file which will be resolved later
1013+
return newNodeEntry(reference.referencingFile.AsNode())
1014+
}
1015+
return nil
1016+
})
1017+
1018+
// Add references to the module declarations themselves
1019+
if len(symbol.Declarations) > 0 {
1020+
for _, decl := range symbol.Declarations {
1021+
switch decl.Kind {
1022+
case ast.KindSourceFile:
1023+
// Don't include the source file itself. (This may not be ideal behavior, but awkward to include an entire file as a reference.)
1024+
continue
1025+
case ast.KindModuleDeclaration:
1026+
if sourceFilesSet.Has(ast.GetSourceFileOfNode(decl).FileName()) {
1027+
references = append(references, newNodeEntry(decl.AsModuleDeclaration().Name()))
1028+
}
1029+
default:
1030+
// This may be merged with something.
1031+
debug.Assert(symbol.Flags&ast.SymbolFlagsTransient != 0, "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration.")
1032+
}
1033+
}
1034+
}
1035+
1036+
// Handle export equals declarations
1037+
exported := symbol.Exports[ast.InternalSymbolNameExportEquals]
1038+
if exported != nil && len(exported.Declarations) > 0 {
1039+
for _, decl := range exported.Declarations {
1040+
sourceFile := ast.GetSourceFileOfNode(decl)
1041+
if sourceFilesSet.Has(sourceFile.FileName()) {
1042+
var node *ast.Node
1043+
// At `module.exports = ...`, reference node is `module`
1044+
if ast.IsBinaryExpression(decl) && ast.IsPropertyAccessExpression(decl.AsBinaryExpression().Left) {
1045+
node = decl.AsBinaryExpression().Left.AsPropertyAccessExpression().Expression
1046+
} else if ast.IsExportAssignment(decl) {
1047+
// Find the export keyword - for now, just use the declaration itself
1048+
node = decl
1049+
} else {
1050+
node = ast.GetNameOfDeclaration(decl)
1051+
if node == nil {
1052+
node = decl
1053+
}
1054+
}
1055+
references = append(references, newNodeEntry(node))
1056+
}
1057+
}
1058+
}
1059+
1060+
if len(references) > 0 {
1061+
return []*SymbolAndEntries{{
1062+
definition: &Definition{Kind: definitionKindSymbol, symbol: symbol},
1063+
references: references,
1064+
}}
1065+
}
9801066
return nil
9811067
}
9821068

internal/ls/importTracker.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/microsoft/typescript-go/internal/ast"
77
"github.com/microsoft/typescript-go/internal/checker"
88
"github.com/microsoft/typescript-go/internal/collections"
9+
"github.com/microsoft/typescript-go/internal/compiler"
910
"github.com/microsoft/typescript-go/internal/core"
1011
"github.com/microsoft/typescript-go/internal/debug"
1112
)
@@ -42,6 +43,22 @@ type ImportsResult struct {
4243

4344
type ImportTracker func(exportSymbol *ast.Symbol, exportInfo *ExportInfo, isForRename bool) *ImportsResult
4445

46+
type ModuleReferenceKind int32
47+
48+
const (
49+
ModuleReferenceKindImport ModuleReferenceKind = iota
50+
ModuleReferenceKindReference
51+
ModuleReferenceKindImplicit
52+
)
53+
54+
// ModuleReference represents a reference to a module, either via import, <reference>, or implicit reference
55+
type ModuleReference struct {
56+
kind ModuleReferenceKind
57+
literal *ast.Node // for import and implicit kinds (StringLiteralLike)
58+
referencingFile *ast.SourceFile
59+
ref *ast.FileReference // for reference kind
60+
}
61+
4562
// Creates the imports map and returns an ImportTracker that uses it. Call this lazily to avoid calling `getDirectImportsMap` unnecessarily.
4663
func createImportTracker(sourceFiles []*ast.SourceFile, sourceFilesSet *collections.Set[string], checker *checker.Checker) ImportTracker {
4764
allDirectImports := getDirectImportsMap(sourceFiles, checker)
@@ -654,3 +671,58 @@ func symbolNameNoDefault(symbol *ast.Symbol) string {
654671
}
655672
return ""
656673
}
674+
675+
// findModuleReferences finds all references to a module symbol across the given source files.
676+
// This includes import statements, <reference> directives, and implicit references (e.g., JSX runtime imports).
677+
func findModuleReferences(program *compiler.Program, sourceFiles []*ast.SourceFile, searchModuleSymbol *ast.Symbol, checker *checker.Checker) []ModuleReference {
678+
refs := []ModuleReference{}
679+
680+
for _, referencingFile := range sourceFiles {
681+
searchSourceFile := searchModuleSymbol.ValueDeclaration
682+
if searchSourceFile != nil && searchSourceFile.Kind == ast.KindSourceFile {
683+
// Check <reference path> directives
684+
for _, ref := range referencingFile.ReferencedFiles {
685+
if program.GetSourceFileFromReference(referencingFile, ref) == searchSourceFile.AsSourceFile() {
686+
refs = append(refs, ModuleReference{
687+
kind: ModuleReferenceKindReference,
688+
referencingFile: referencingFile,
689+
ref: ref,
690+
})
691+
}
692+
}
693+
694+
// Check <reference types> directives
695+
for _, ref := range referencingFile.TypeReferenceDirectives {
696+
referenced := program.GetResolvedTypeReferenceDirectiveFromTypeReferenceDirective(ref, referencingFile)
697+
if referenced != nil && referenced.ResolvedFileName == searchSourceFile.AsSourceFile().FileName() {
698+
refs = append(refs, ModuleReference{
699+
kind: ModuleReferenceKindReference,
700+
referencingFile: referencingFile,
701+
ref: ref,
702+
})
703+
}
704+
}
705+
}
706+
707+
// Check all imports (including require() calls)
708+
forEachImport(referencingFile, func(importDecl *ast.Node, moduleSpecifier *ast.Node) {
709+
moduleSymbol := checker.GetSymbolAtLocation(moduleSpecifier)
710+
if moduleSymbol == searchModuleSymbol {
711+
if ast.NodeIsSynthesized(importDecl) {
712+
refs = append(refs, ModuleReference{
713+
kind: ModuleReferenceKindImplicit,
714+
literal: moduleSpecifier,
715+
referencingFile: referencingFile,
716+
})
717+
} else {
718+
refs = append(refs, ModuleReference{
719+
kind: ModuleReferenceKindImport,
720+
literal: moduleSpecifier,
721+
})
722+
}
723+
}
724+
})
725+
}
726+
727+
return refs
728+
}

0 commit comments

Comments
 (0)