SSR: Move more resolution-related code into the resolving module

This commit is contained in:
David Lattimore 2020-07-26 14:49:18 +10:00
parent 8ff40af728
commit bb587fae1d
2 changed files with 38 additions and 27 deletions

View file

@ -51,8 +51,7 @@ pub struct MatchFinder<'db> {
/// Our source of information about the user's code. /// Our source of information about the user's code.
sema: Semantics<'db, ra_ide_db::RootDatabase>, sema: Semantics<'db, ra_ide_db::RootDatabase>,
rules: Vec<ResolvedRule>, rules: Vec<ResolvedRule>,
scope: hir::SemanticsScope<'db>, resolution_scope: resolving::ResolutionScope<'db>,
hygiene: hir::Hygiene,
} }
impl<'db> MatchFinder<'db> { impl<'db> MatchFinder<'db> {
@ -63,21 +62,8 @@ impl<'db> MatchFinder<'db> {
lookup_context: FilePosition, lookup_context: FilePosition,
) -> MatchFinder<'db> { ) -> MatchFinder<'db> {
let sema = Semantics::new(db); let sema = Semantics::new(db);
let file = sema.parse(lookup_context.file_id); let resolution_scope = resolving::ResolutionScope::new(&sema, lookup_context);
// Find a node at the requested position, falling back to the whole file. MatchFinder { sema: Semantics::new(db), rules: Vec::new(), resolution_scope }
let node = file
.syntax()
.token_at_offset(lookup_context.offset)
.left_biased()
.map(|token| token.parent())
.unwrap_or_else(|| file.syntax().clone());
let scope = sema.scope(&node);
MatchFinder {
sema: Semantics::new(db),
rules: Vec::new(),
scope,
hygiene: hir::Hygiene::new(db, lookup_context.file_id.into()),
}
} }
/// Constructs an instance using the start of the first file in `db` as the lookup context. /// Constructs an instance using the start of the first file in `db` as the lookup context.
@ -106,8 +92,7 @@ impl<'db> MatchFinder<'db> {
for parsed_rule in rule.parsed_rules { for parsed_rule in rule.parsed_rules {
self.rules.push(ResolvedRule::new( self.rules.push(ResolvedRule::new(
parsed_rule, parsed_rule,
&self.scope, &self.resolution_scope,
&self.hygiene,
self.rules.len(), self.rules.len(),
)?); )?);
} }
@ -140,8 +125,7 @@ impl<'db> MatchFinder<'db> {
for parsed_rule in pattern.parsed_rules { for parsed_rule in pattern.parsed_rules {
self.rules.push(ResolvedRule::new( self.rules.push(ResolvedRule::new(
parsed_rule, parsed_rule,
&self.scope, &self.resolution_scope,
&self.hygiene,
self.rules.len(), self.rules.len(),
)?); )?);
} }

View file

@ -3,10 +3,16 @@
use crate::errors::error; use crate::errors::error;
use crate::{parsing, SsrError}; use crate::{parsing, SsrError};
use parsing::Placeholder; use parsing::Placeholder;
use ra_db::FilePosition;
use ra_syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken}; use ra_syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use test_utils::mark; use test_utils::mark;
pub(crate) struct ResolutionScope<'db> {
scope: hir::SemanticsScope<'db>,
hygiene: hir::Hygiene,
}
pub(crate) struct ResolvedRule { pub(crate) struct ResolvedRule {
pub(crate) pattern: ResolvedPattern, pub(crate) pattern: ResolvedPattern,
pub(crate) template: Option<ResolvedPattern>, pub(crate) template: Option<ResolvedPattern>,
@ -30,12 +36,11 @@ pub(crate) struct ResolvedPath {
impl ResolvedRule { impl ResolvedRule {
pub(crate) fn new( pub(crate) fn new(
rule: parsing::ParsedRule, rule: parsing::ParsedRule,
scope: &hir::SemanticsScope, resolution_scope: &ResolutionScope,
hygiene: &hir::Hygiene,
index: usize, index: usize,
) -> Result<ResolvedRule, SsrError> { ) -> Result<ResolvedRule, SsrError> {
let resolver = let resolver =
Resolver { scope, hygiene, placeholders_by_stand_in: rule.placeholders_by_stand_in }; Resolver { resolution_scope, placeholders_by_stand_in: rule.placeholders_by_stand_in };
let resolved_template = if let Some(template) = rule.template { let resolved_template = if let Some(template) = rule.template {
Some(resolver.resolve_pattern_tree(template)?) Some(resolver.resolve_pattern_tree(template)?)
} else { } else {
@ -57,8 +62,7 @@ impl ResolvedRule {
} }
struct Resolver<'a, 'db> { struct Resolver<'a, 'db> {
scope: &'a hir::SemanticsScope<'db>, resolution_scope: &'a ResolutionScope<'db>,
hygiene: &'a hir::Hygiene,
placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>, placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
} }
@ -104,6 +108,7 @@ impl Resolver<'_, '_> {
&& !self.path_contains_placeholder(&path) && !self.path_contains_placeholder(&path)
{ {
let resolution = self let resolution = self
.resolution_scope
.resolve_path(&path) .resolve_path(&path)
.ok_or_else(|| error!("Failed to resolve path `{}`", node.text()))?; .ok_or_else(|| error!("Failed to resolve path `{}`", node.text()))?;
resolved_paths.insert(node, ResolvedPath { resolution, depth }); resolved_paths.insert(node, ResolvedPath { resolution, depth });
@ -131,9 +136,31 @@ impl Resolver<'_, '_> {
} }
false false
} }
}
impl<'db> ResolutionScope<'db> {
pub(crate) fn new(
sema: &hir::Semantics<'db, ra_ide_db::RootDatabase>,
lookup_context: FilePosition,
) -> ResolutionScope<'db> {
use ra_syntax::ast::AstNode;
let file = sema.parse(lookup_context.file_id);
// Find a node at the requested position, falling back to the whole file.
let node = file
.syntax()
.token_at_offset(lookup_context.offset)
.left_biased()
.map(|token| token.parent())
.unwrap_or_else(|| file.syntax().clone());
let scope = sema.scope(&node);
ResolutionScope {
scope,
hygiene: hir::Hygiene::new(sema.db, lookup_context.file_id.into()),
}
}
fn resolve_path(&self, path: &ast::Path) -> Option<hir::PathResolution> { fn resolve_path(&self, path: &ast::Path) -> Option<hir::PathResolution> {
let hir_path = hir::Path::from_src(path.clone(), self.hygiene)?; let hir_path = hir::Path::from_src(path.clone(), &self.hygiene)?;
// First try resolving the whole path. This will work for things like // First try resolving the whole path. This will work for things like
// `std::collections::HashMap`, but will fail for things like // `std::collections::HashMap`, but will fail for things like
// `std::collections::HashMap::new`. // `std::collections::HashMap::new`.