mod source_to_def;
-use std::{cell::RefCell, fmt, iter};
+use std::{cell::RefCell, fmt, iter, ops};
use base_db::{FileId, FileRange};
use hir_def::{
name::{known, AsName},
ExpansionInfo, MacroCallId,
};
-use hir_ty::Interner;
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec};
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{resolve_hir_path, SourceAnalyzer},
- Access, AssocItem, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
+ Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path,
ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
};
/// A const parameter
ConstParam(ConstParam),
SelfType(Impl),
- AssocItem(AssocItem),
BuiltinAttr(BuiltinAttr),
ToolModule(ToolModule),
}
| PathResolution::ConstParam(_) => None,
PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
- PathResolution::AssocItem(AssocItem::Const(_) | AssocItem::Function(_)) => None,
- PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
- Some(TypeNs::TypeAliasId((*alias).into()))
- }
}
}
}
self.imp.descend_into_macros(token)
}
+ /// Descend the token into macrocalls to all its mapped counterparts that have the same text as the input token.
+ ///
+ /// Returns the original non descended token if none of the mapped counterparts have the same text.
+ pub fn descend_into_macros_with_same_text(
+ &self,
+ token: SyntaxToken,
+ ) -> SmallVec<[SyntaxToken; 1]> {
+ self.imp.descend_into_macros_with_same_text(token)
+ }
+
/// Maps a node down by mapping its first and last token down.
pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
self.imp.descend_node_into_attributes(node)
self.imp.type_of_self(param)
}
+ pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
+ self.imp.pattern_adjustments(pat)
+ }
+
+ pub fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
+ self.imp.binding_mode_of_pat(pat)
+ }
+
pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
self.imp.resolve_method_call(call).map(Function::from)
}
};
if first == last {
- self.descend_into_macros_impl(
- first,
- &mut |InFile { value, .. }| {
- if let Some(node) = value.ancestors().find_map(N::cast) {
- res.push(node)
- }
- },
- false,
- );
+ self.descend_into_macros_impl(first, &mut |InFile { value, .. }| {
+ if let Some(node) = value.parent_ancestors().find_map(N::cast) {
+ res.push(node)
+ }
+ false
+ });
} else {
// Descend first and last token, then zip them to look for the node they belong to
let mut scratch: SmallVec<[_; 1]> = smallvec![];
- self.descend_into_macros_impl(
- first,
- &mut |token| {
- scratch.push(token);
- },
- false,
- );
+ self.descend_into_macros_impl(first, &mut |token| {
+ scratch.push(token);
+ false
+ });
let mut scratch = scratch.into_iter();
self.descend_into_macros_impl(
}
}
}
+ false
},
- false,
);
}
res
fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
let mut res = smallvec![];
- self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res.push(value), false);
+ self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
+ res.push(value);
+ false
+ });
+ res
+ }
+
+ fn descend_into_macros_with_same_text(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
+ let text = token.text();
+ let mut res = smallvec![];
+ self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
+ if value.text() == text {
+ res.push(value);
+ }
+ false
+ });
+ if res.is_empty() {
+ res.push(token);
+ }
res
}
fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
let mut res = token.clone();
- self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res = value, true);
+ self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
+ res = value;
+ true
+ });
res
}
fn descend_into_macros_impl(
&self,
token: SyntaxToken,
- f: &mut dyn FnMut(InFile<SyntaxToken>),
- single: bool,
+ f: &mut dyn FnMut(InFile<SyntaxToken>) -> bool,
) {
let _p = profile::span("descend_into_macros");
let parent = match token.parent() {
self.cache(value, file_id);
}
- let mut mapped_tokens =
- expansion_info.map_token_down(self.db.upcast(), item, token)?;
-
+ let mapped_tokens = expansion_info.map_token_down(self.db.upcast(), item, token)?;
let len = stack.len();
+
// requeue the tokens we got from mapping our current token down
- if single {
- stack.extend(mapped_tokens.next());
- } else {
- stack.extend(mapped_tokens);
- }
+ stack.extend(mapped_tokens);
// if the length changed we have found a mapping for the token
(stack.len() != len).then(|| ())
};
let was_not_remapped = (|| {
// are we inside an attribute macro call
let containing_attribute_macro_call = self.with_ctx(|ctx| {
- token.value.ancestors().filter_map(ast::Item::cast).find_map(|item| {
+ token.value.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| {
if item.attrs().next().is_none() {
// Don't force populate the dyn cache for items that don't have an attribute anyways
return None;
// or are we inside a function-like macro call
if let Some(tt) =
// FIXME replace map.while_some with take_while once stable
- token.value.ancestors().map(ast::TokenTree::cast).while_some().last()
+ token
+ .value
+ .parent_ancestors()
+ .map(ast::TokenTree::cast)
+ .while_some()
+ .last()
{
let parent = tt.syntax().parent()?;
// check for derive attribute here
})()
.is_none();
- if was_not_remapped {
- f(token)
+ if was_not_remapped && f(token) {
+ break;
}
}
}
self.analyze(param.syntax())?.type_of_self(self.db, param)
}
+ fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
+ self.analyze(pat.syntax())
+ .and_then(|it| it.pattern_adjustments(self.db, pat))
+ .unwrap_or_default()
+ }
+
+ fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
+ self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
+ }
+
fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
- self.analyze(call.syntax())?.resolve_method_call(self.db, call).map(|(id, _)| id)
+ self.analyze(call.syntax())?.resolve_method_call(self.db, call)
}
fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
- let source_analyzer = self.analyze(call.syntax())?;
- let (func, subst) = source_analyzer.resolve_method_call(self.db, call)?;
- let ty = self.db.value_ty(func.into()).substitute(Interner, &subst);
- let resolver = source_analyzer.resolver;
- let ty = Type::new_with_resolver(self.db, &resolver, ty);
- let mut res = ty.as_callable(self.db)?;
- res.is_bound_method = true;
- Some(res)
+ self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
}
fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
&self.resolver
}
- /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
- pub fn visible_traits(&self) -> FxHashSet<TraitId> {
+ /// Note: `VisibleTraits` should be treated as an opaque type, passed into `Type
+ pub fn visible_traits(&self) -> VisibleTraits {
let resolver = &self.resolver;
- resolver.traits_in_scope(self.db.upcast())
+ VisibleTraits(resolver.traits_in_scope(self.db.upcast()))
}
pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
)
}
}
+
+pub struct VisibleTraits(pub FxHashSet<TraitId>);
+
+impl ops::Deref for VisibleTraits {
+ type Target = FxHashSet<TraitId>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}