Skip to content

Commit

Permalink
feat: ability to go to a symbol dep's definition (#314)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret authored Nov 1, 2023
1 parent 72b229a commit 73bb61c
Show file tree
Hide file tree
Showing 4 changed files with 355 additions and 38 deletions.
24 changes: 24 additions & 0 deletions src/type_tracer/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use super::collections::LockableRefCell;
use super::cross_module;
use super::cross_module::Definition;
use super::ImportedExports;
use super::ResolvedSymbolDepEntry;
use super::TypeTraceDiagnostic;
use super::TypeTraceDiagnosticKind;
use super::TypeTraceHandler;
Expand Down Expand Up @@ -94,6 +95,20 @@ impl RootSymbol {
&|specifier| self.get_module_from_specifier(specifier),
)
}

pub fn resolve_symbol_dep<'a>(
&'a self,
module_graph: &ModuleGraph,
module: ModuleSymbolRef<'a>,
dep: &'a SymbolDep,
) -> Vec<ResolvedSymbolDepEntry<'a>> {
super::cross_module::resolve_symbol_dep(
module_graph,
module,
dep,
&|specifier| self.get_module_from_specifier(specifier),
)
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -446,6 +461,15 @@ pub struct UniqueSymbolId {
pub symbol_id: SymbolId,
}

impl UniqueSymbolId {
pub fn new(module_id: ModuleId, symbol_id: SymbolId) -> Self {
Self {
module_id,
symbol_id,
}
}
}

#[derive(Debug, Clone, Copy)]
pub enum ModuleSymbolRef<'a> {
Json(&'a JsonModuleSymbol),
Expand Down
184 changes: 148 additions & 36 deletions src/type_tracer/cross_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

use std::collections::HashSet;

use anyhow::Result;
use deno_ast::SourceRange;
use indexmap::IndexMap;

use crate::ModuleGraph;
use crate::ModuleSpecifier;

use super::analyzer::SymbolDeclKind;
use super::analyzer::SymbolDep;
use super::FileDep;
use super::FileDepName;
use super::ModuleSymbolRef;
Expand All @@ -33,6 +33,13 @@ pub struct Definition<'a> {
}

impl<'a> Definition<'a> {
pub fn unique_id(&self) -> UniqueSymbolId {
UniqueSymbolId {
module_id: self.module.module_id(),
symbol_id: self.symbol.symbol_id(),
}
}

pub fn range(&self) -> &SourceRange {
&self.symbol_decl.range
}
Expand Down Expand Up @@ -112,31 +119,14 @@ fn go_to_definitions_internal<'a>(
}
}
SymbolDeclKind::QualifiedTarget(target_id, parts) => {
if let Some(symbol_id) =
module.esm().unwrap().symbol_id_from_swc(target_id)
{
if let Ok(results) = resolve_qualified_name(
module_graph,
module,
symbol_id,
parts,
specifier_to_module,
) {
for (specifier, symbol_id) in results {
if let Some(module_symbol) = specifier_to_module(&specifier) {
if let Some(symbol) = module_symbol.symbol(symbol_id) {
definitions.extend(go_to_definitions_internal(
module_graph,
module_symbol,
symbol,
visited_symbols,
specifier_to_module,
));
}
}
}
}
}
definitions.extend(go_to_id_and_parts_definitions(
module_graph,
module,
target_id,
parts,
specifier_to_module,
visited_symbols,
));
}
SymbolDeclKind::FileRef(file_ref) => match &file_ref.name {
FileDepName::Star => {
Expand Down Expand Up @@ -179,13 +169,135 @@ fn go_to_definitions_internal<'a>(
definitions
}

/// A resolved `SymbolDep`.
pub enum ResolvedSymbolDepEntry<'a> {
/// The definition of the symbol dep.
Definition(Definition<'a>),
/// If the symbol dep was an import type with no property access.
///
/// Ex. `type MyType = typeof import("./my_module.ts");`
ImportType(ModuleSymbolRef<'a>),
}

pub fn resolve_symbol_dep<'a>(
module_graph: &ModuleGraph,
module: ModuleSymbolRef<'a>,
dep: &SymbolDep,
specifier_to_module: &impl Fn(&ModuleSpecifier) -> Option<ModuleSymbolRef<'a>>,
) -> Vec<ResolvedSymbolDepEntry<'a>> {
match &dep {
SymbolDep::Id(id) => {
if let Some(symbol) = module.esm().and_then(|m| m.symbol_from_swc(id)) {
go_to_definitions(module_graph, module, symbol, specifier_to_module)
.into_iter()
.map(ResolvedSymbolDepEntry::Definition)
.collect()
} else {
Vec::new()
}
}
SymbolDep::QualifiedId(id, parts) => go_to_id_and_parts_definitions(
module_graph,
module,
id,
parts,
specifier_to_module,
&mut Default::default(),
)
.into_iter()
.map(ResolvedSymbolDepEntry::Definition)
.collect(),
SymbolDep::ImportType(import_specifier, parts) => {
let maybe_dep_specifier = module_graph.resolve_dependency(
import_specifier,
module.specifier(),
/* prefer types */ true,
);
let Some(module_symbol) =
maybe_dep_specifier.as_ref().and_then(specifier_to_module)
else {
return Vec::new();
};
if parts.is_empty() {
// an ImportType includes default exports
vec![ResolvedSymbolDepEntry::ImportType(module_symbol)]
} else {
let symbols = resolve_qualified_export_name(
module_graph,
module_symbol,
&parts[0],
&parts[1..],
specifier_to_module,
);
let mut visited_symbols = HashSet::new();
let mut definitions = Vec::new();
for (specifier, symbol_id) in symbols {
if let Some(module) = specifier_to_module(&specifier) {
if let Some(symbol) = module.esm().and_then(|m| m.symbol(symbol_id))
{
definitions.extend(
go_to_definitions_internal(
module_graph,
module,
symbol,
&mut visited_symbols,
specifier_to_module,
)
.into_iter()
.map(ResolvedSymbolDepEntry::Definition),
);
}
}
}
definitions
}
}
}
}

fn go_to_id_and_parts_definitions<'a>(
module_graph: &ModuleGraph,
module: ModuleSymbolRef<'a>,
target_id: &deno_ast::swc::ast::Id,
parts: &[String],
specifier_to_module: &impl Fn(&ModuleSpecifier) -> Option<ModuleSymbolRef<'a>>,
visited_symbols: &mut HashSet<UniqueSymbolId>,
) -> Vec<Definition<'a>> {
let mut definitions = Vec::new();
if let Some(symbol_id) =
module.esm().and_then(|m| m.symbol_id_from_swc(target_id))
{
let results = resolve_qualified_name(
module_graph,
module,
symbol_id,
parts,
specifier_to_module,
);
for (specifier, symbol_id) in results {
if let Some(module_symbol) = specifier_to_module(&specifier) {
if let Some(symbol) = module_symbol.symbol(symbol_id) {
definitions.extend(go_to_definitions_internal(
module_graph,
module_symbol,
symbol,
visited_symbols,
specifier_to_module,
));
}
}
}
}
definitions
}

pub fn resolve_qualified_export_name<'a>(
graph: &ModuleGraph,
module_symbol: ModuleSymbolRef<'a>,
export_name: &str,
parts: &[String],
specifier_to_module: &impl Fn(&ModuleSpecifier) -> Option<ModuleSymbolRef<'a>>,
) -> Result<Vec<(ModuleSpecifier, SymbolId)>> {
) -> Vec<(ModuleSpecifier, SymbolId)> {
resolve_qualified_export_name_internal(
graph,
module_symbol,
Expand All @@ -203,7 +315,7 @@ fn resolve_qualified_export_name_internal<'a>(
parts: &[String],
visited_symbols: &mut HashSet<UniqueSymbolId>,
specifier_to_module: &impl Fn(&ModuleSpecifier) -> Option<ModuleSymbolRef<'a>>,
) -> Result<Vec<(ModuleSpecifier, SymbolId)>> {
) -> Vec<(ModuleSpecifier, SymbolId)> {
let exports =
exports_and_re_exports(graph, module_symbol, specifier_to_module);
if let Some((module, symbol_id)) = exports.get(export_name) {
Expand All @@ -216,7 +328,7 @@ fn resolve_qualified_export_name_internal<'a>(
specifier_to_module,
)
} else {
Ok(Vec::new())
Vec::new()
}
}

Expand All @@ -226,7 +338,7 @@ pub fn resolve_qualified_name<'a>(
symbol_id: SymbolId,
parts: &[String],
specifier_to_module: &impl Fn(&ModuleSpecifier) -> Option<ModuleSymbolRef<'a>>,
) -> Result<Vec<(ModuleSpecifier, SymbolId)>> {
) -> Vec<(ModuleSpecifier, SymbolId)> {
resolve_qualified_name_internal(
graph,
module_symbol,
Expand All @@ -244,9 +356,9 @@ fn resolve_qualified_name_internal<'a>(
parts: &[String],
visited_symbols: &mut HashSet<UniqueSymbolId>,
specifier_to_module: &impl Fn(&ModuleSpecifier) -> Option<ModuleSymbolRef<'a>>,
) -> Result<Vec<(ModuleSpecifier, SymbolId)>> {
) -> Vec<(ModuleSpecifier, SymbolId)> {
if parts.is_empty() {
return Ok(vec![(module_symbol.specifier().clone(), symbol_id)]);
return vec![(module_symbol.specifier().clone(), symbol_id)];
}

let mut result = Vec::new();
Expand All @@ -272,7 +384,7 @@ fn resolve_qualified_name_internal<'a>(
&parts[1..],
visited_symbols,
specifier_to_module,
)?);
));
}
}
DefinitionKind::ExportStar(file_dep) => {
Expand All @@ -290,15 +402,15 @@ fn resolve_qualified_name_internal<'a>(
&parts[1..],
visited_symbols,
specifier_to_module,
)?);
));
}
}
}
}
}
Ok(result)
result
}
None => Ok(Vec::new()),
None => Vec::new(),
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/type_tracer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub use self::analyzer::SymbolNodeRef;
pub use self::analyzer::UniqueSymbolId;
pub use self::cross_module::Definition;
pub use self::cross_module::DefinitionKind;
pub use self::cross_module::ResolvedSymbolDepEntry;

mod analyzer;
mod collections;
Expand Down Expand Up @@ -376,7 +377,7 @@ fn trace_module<THandler: TypeTraceHandler>(
&|specifier| {
context.analyzer.get_or_analyze(specifier).ok().flatten()
},
)?);
));
}
}
SymbolDep::ImportType(import_specifier, parts) => {
Expand Down Expand Up @@ -405,7 +406,7 @@ fn trace_module<THandler: TypeTraceHandler>(
&|specifier| {
context.analyzer.get_or_analyze(specifier).ok().flatten()
},
)?);
));
}
}
}
Expand Down
Loading

0 comments on commit 73bb61c

Please sign in to comment.