Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef,
},
has_source::HasSource,
- semantics::{original_range, PathResolution, Semantics, SemanticsScope},
+ semantics::{PathResolution, Semantics, SemanticsScope},
};
pub use hir_def::{
use hir_ty::associated_type_shorthand_candidates;
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
-use syntax::{
- algo::{find_node_at_offset, skip_trivia_token},
- ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
-};
+use syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode, SyntaxToken, TextSize};
use crate::{
code_model::Access,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{resolve_hir_path, SourceAnalyzer},
AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
- Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
+ Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
};
#[derive(Debug, Clone, PartialEq, Eq)]
fn original_range(&self, node: &SyntaxNode) -> FileRange {
let node = self.find_file(node.clone());
- original_range(self.db, node.as_ref())
+ node.as_ref().original_file_range(self.db.upcast())
}
fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
let root = self.db.parse_or_expand(src.file_id).unwrap();
let node = src.value.to_node(&root);
self.cache(root, src.file_id);
- original_range(self.db, src.with_value(&node))
+ src.with_value(&node).original_file_range(self.db.upcast())
}
fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
resolve_hir_path(self.db, &self.resolver, &path)
}
}
-
-// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?
-pub fn original_range(db: &dyn HirDatabase, node: InFile<&SyntaxNode>) -> FileRange {
- if let Some(range) = original_range_opt(db, node) {
- let original_file = range.file_id.original_file(db.upcast());
- if range.file_id == original_file.into() {
- return FileRange { file_id: original_file, range: range.value };
- }
-
- log::error!("Fail to mapping up more for {:?}", range);
- return FileRange { file_id: range.file_id.original_file(db.upcast()), range: range.value };
- }
-
- // Fall back to whole macro call
- if let Some(expansion) = node.file_id.expansion_info(db.upcast()) {
- if let Some(call_node) = expansion.call_node() {
- return FileRange {
- file_id: call_node.file_id.original_file(db.upcast()),
- range: call_node.value.text_range(),
- };
- }
- }
-
- FileRange { file_id: node.file_id.original_file(db.upcast()), range: node.value.text_range() }
-}
-
-fn original_range_opt(
- db: &dyn HirDatabase,
- node: InFile<&SyntaxNode>,
-) -> Option<InFile<TextRange>> {
- let expansion = node.file_id.expansion_info(db.upcast())?;
-
- // the input node has only one token ?
- let single = skip_trivia_token(node.value.first_token()?, Direction::Next)?
- == skip_trivia_token(node.value.last_token()?, Direction::Prev)?;
-
- Some(node.value.descendants().find_map(|it| {
- let first = skip_trivia_token(it.first_token()?, Direction::Next)?;
- let first = ascend_call_token(db, &expansion, node.with_value(first))?;
-
- let last = skip_trivia_token(it.last_token()?, Direction::Prev)?;
- let last = ascend_call_token(db, &expansion, node.with_value(last))?;
-
- if (!single && first == last) || (first.file_id != last.file_id) {
- return None;
- }
-
- Some(first.with_value(first.value.text_range().cover(last.value.text_range())))
- })?)
-}
-
-fn ascend_call_token(
- db: &dyn HirDatabase,
- expansion: &ExpansionInfo,
- token: InFile<SyntaxToken>,
-) -> Option<InFile<SyntaxToken>> {
- let (mapped, origin) = expansion.map_token_up(token.as_ref())?;
- if origin != Origin::Call {
- return None;
- }
- if let Some(info) = mapped.file_id.expansion_info(db.upcast()) {
- return ascend_call_token(db, &info, mapped);
- }
- Some(mapped)
-}
use std::hash::Hash;
use std::sync::Arc;
-use base_db::{impl_intern_key, salsa, CrateId, FileId};
+use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
use syntax::{
- algo,
+ algo::{self, skip_trivia_token},
ast::{self, AstNode},
- SyntaxNode, SyntaxToken, TextSize,
+ Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
};
use crate::ast_id_map::FileAstId;
}
}
+impl<'a> InFile<&'a SyntaxNode> {
+ pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
+ if let Some(range) = original_range_opt(db, self) {
+ let original_file = range.file_id.original_file(db);
+ if range.file_id == original_file.into() {
+ return FileRange { file_id: original_file, range: range.value };
+ }
+
+ log::error!("Fail to mapping up more for {:?}", range);
+ return FileRange { file_id: range.file_id.original_file(db), range: range.value };
+ }
+
+ // Fall back to whole macro call
+ if let Some(expansion) = self.file_id.expansion_info(db) {
+ if let Some(call_node) = expansion.call_node() {
+ return FileRange {
+ file_id: call_node.file_id.original_file(db),
+ range: call_node.value.text_range(),
+ };
+ }
+ }
+
+ FileRange { file_id: self.file_id.original_file(db), range: self.value.text_range() }
+ }
+}
+
+fn original_range_opt(
+ db: &dyn db::AstDatabase,
+ node: InFile<&SyntaxNode>,
+) -> Option<InFile<TextRange>> {
+ let expansion = node.file_id.expansion_info(db)?;
+
+ // the input node has only one token ?
+ let single = skip_trivia_token(node.value.first_token()?, Direction::Next)?
+ == skip_trivia_token(node.value.last_token()?, Direction::Prev)?;
+
+ Some(node.value.descendants().find_map(|it| {
+ let first = skip_trivia_token(it.first_token()?, Direction::Next)?;
+ let first = ascend_call_token(db, &expansion, node.with_value(first))?;
+
+ let last = skip_trivia_token(it.last_token()?, Direction::Prev)?;
+ let last = ascend_call_token(db, &expansion, node.with_value(last))?;
+
+ if (!single && first == last) || (first.file_id != last.file_id) {
+ return None;
+ }
+
+ Some(first.with_value(first.value.text_range().cover(last.value.text_range())))
+ })?)
+}
+
+fn ascend_call_token(
+ db: &dyn db::AstDatabase,
+ expansion: &ExpansionInfo,
+ token: InFile<SyntaxToken>,
+) -> Option<InFile<SyntaxToken>> {
+ let (mapped, origin) = expansion.map_token_up(token.as_ref())?;
+ if origin != Origin::Call {
+ return None;
+ }
+ if let Some(info) = mapped.file_id.expansion_info(db) {
+ return ascend_call_token(db, &info, mapped);
+ }
+ Some(mapped)
+}
+
impl InFile<SyntaxToken> {
pub fn ancestors_with_macros(
self,
//! FIXME: write short doc here
use either::Either;
-use hir::{original_range, AssocItem, FieldSource, HasSource, InFile, ModuleSource};
+use hir::{AssocItem, FieldSource, HasSource, InFile, ModuleSource};
use ide_db::base_db::{FileId, SourceDatabase};
use ide_db::{defs::Definition, RootDatabase};
use syntax::{
pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
if let Some(src) = module.declaration_source(db) {
- let frange = original_range(db, src.as_ref().map(|it| it.syntax()));
+ let node = src.as_ref().map(|it| it.syntax());
+ let frange = node.original_file_range(db);
let mut res = NavigationTarget::from_syntax(
frange.file_id,
name,
let name =
node.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
let focus_range =
- node.value.name().map(|it| original_range(db, node.with_value(it.syntax())).range);
- let frange = original_range(db, node.map(|it| it.syntax()));
+ node.value.name().map(|it| node.with_value(it.syntax()).original_file_range(db).range);
+ let frange = node.map(|it| it.syntax()).original_file_range(db);
NavigationTarget::from_syntax(
frange.file_id,
) -> NavigationTarget {
let name =
named.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
- let frange = original_range(db, node.map(|it| it.syntax()));
+ let frange = node.map(|it| it.syntax()).original_file_range(db);
NavigationTarget::from_syntax(
frange.file_id,
(node.syntax(), node.name().map(|it| it.syntax().text_range()))
}
};
- let frange = original_range(db, src.with_value(syntax));
+ let frange = src.with_value(syntax).original_file_range(db);
NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind())
}
}
let src = self.source(db);
let derive_attr = self.is_builtin_derive(db);
let frange = if let Some(item) = &derive_attr {
- original_range(db, item.syntax())
+ item.syntax().original_file_range(db)
} else {
- original_range(db, src.as_ref().map(|it| it.syntax()))
+ src.as_ref().map(|it| it.syntax()).original_file_range(db)
};
let focus_range = if derive_attr.is_some() {
None
} else {
- src.value.self_ty().map(|ty| original_range(db, src.with_value(ty.syntax())).range)
+ src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range)
};
NavigationTarget::from_syntax(
res
}
FieldSource::Pos(it) => {
- let frange = original_range(db, src.with_value(it.syntax()));
+ let frange = src.with_value(it.syntax()).original_file_range(db);
NavigationTarget::from_syntax(
frange.file_id,
"".into(),
}
Either::Right(it) => it.syntax().clone(),
};
- let full_range = original_range(db, src.with_value(&node));
+ let full_range = src.with_value(&node).original_file_range(db);
let name = match self.name(db) {
Some(it) => it.to_string().into(),
None => "".into(),
use hir::{
db::{AstDatabase, DefDatabase, HirDatabase},
- original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
+ AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
};
use hir_def::FunctionId;
use hir_ty::{Ty, TypeWalk};
// But also, we should just turn the type mismatches into diagnostics and provide these
let root = db.parse_or_expand(src.file_id).unwrap();
let node = src.map(|e| e.to_node(&root).syntax().clone());
- let original_range = original_range(db, node.as_ref());
+ let original_range = node.as_ref().original_file_range(db);
let path = vfs.file_path(original_range.file_id);
let line_index =
host.analysis().file_line_index(original_range.file_id).unwrap();