Skip to content
Closed
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
35 changes: 25 additions & 10 deletions internal/ls/autoimports.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ func (e *exportInfoMap) get(importingFile tspath.Path, ch *checker.Checker, key
if e.usableByFileName != importingFile {
return nil
}
return core.Map(e.exportInfo.Get(key), func(info CachedSymbolExportInfo) *SymbolExportInfo { return e.rehydrateCachedInfo(ch, info) })
return core.MapNonNil(e.exportInfo.Get(key), func(info CachedSymbolExportInfo) *SymbolExportInfo {
return e.tryRehydrateCachedInfo(ch, info)
})
}

func (e *exportInfoMap) add(
Expand Down Expand Up @@ -227,12 +229,20 @@ func (e *exportInfoMap) search(
symbolName = info[0].capitalizedSymbolName
}
if matches(symbolName, info[0].targetFlags) {
rehydrated := core.Map(info, func(info CachedSymbolExportInfo) *SymbolExportInfo {
return e.rehydrateCachedInfo(ch, info)
})
filtered := core.FilterIndex(rehydrated, func(r *SymbolExportInfo, i int, _ []*SymbolExportInfo) bool {
return e.isNotShadowedByDeeperNodeModulesPackage(r, info[i].packageName)
})
// Rehydrate and filter in one pass to maintain correspondence between cached and rehydrated info
var rehydrated []*SymbolExportInfo
for i, cachedInfo := range info {
rehydratedInfo := e.tryRehydrateCachedInfo(ch, cachedInfo)
if rehydratedInfo == nil {
// Symbol or module is no longer available, skip it
continue
}
if !e.isNotShadowedByDeeperNodeModulesPackage(rehydratedInfo, info[i].packageName) {
continue
}
rehydrated = append(rehydrated, rehydratedInfo)
}
filtered := rehydrated
if len(filtered) > 0 {
if res := action(filtered, symbolName, ambientModuleName != "", key); res != nil {
return res
Expand All @@ -254,7 +264,10 @@ func (e *exportInfoMap) isNotShadowedByDeeperNodeModulesPackage(info *SymbolExpo
return !ok || strings.HasPrefix(info.moduleFileName, packageDeepestNodeModulesPath)
}

func (e *exportInfoMap) rehydrateCachedInfo(ch *checker.Checker, info CachedSymbolExportInfo) *SymbolExportInfo {
// tryRehydrateCachedInfo attempts to restore a SymbolExportInfo from cached data.
// Returns the info if successful, or nil if the symbol or module can no longer be found
// (e.g., due to module resolution changes or removed exports).
func (e *exportInfoMap) tryRehydrateCachedInfo(ch *checker.Checker, info CachedSymbolExportInfo) *SymbolExportInfo {
if info.symbol != nil && info.moduleSymbol != nil {
return &SymbolExportInfo{
symbol: info.symbol,
Expand Down Expand Up @@ -287,7 +300,8 @@ func (e *exportInfoMap) rehydrateCachedInfo(ch *checker.Checker, info CachedSymb
}
}
if moduleSymbol == nil {
panic(fmt.Sprintf("Could not find module symbol for %s in exportInfoMap", info.moduleName))
// TODO(andrewbranch): panic(fmt.Sprintf("Could not find module symbol for %s in exportInfoMap", info.moduleName))
return nil
}
symbol := core.Coalesce(info.symbol, cachedSymbol)
if symbol == nil {
Expand All @@ -299,7 +313,8 @@ func (e *exportInfoMap) rehydrateCachedInfo(ch *checker.Checker, info CachedSymb
}

if symbol == nil {
panic(fmt.Sprintf("Could not find symbol '%s' by key '%s' in module %s", info.symbolName, info.symbolTableKey, moduleSymbol.Name))
// TODO(andrewbranch): panic(fmt.Sprintf("Could not find symbol '%s' by key '%s' in module %s", info.symbolName, info.symbolTableKey, moduleSymbol.Name))
return nil
}
e.symbols[info.id] = symbolExportEntry{symbol, moduleSymbol}
return &SymbolExportInfo{
Expand Down