]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir/src/semantics.rs
internal: Expand the derive attribute into a pseudo expansion
[rust.git] / crates / hir / src / semantics.rs
index 243ba63b8a0a8b52a583f0d8f14b6b4a35288b6e..1156dfe98e15b18a2972bc51da28afa2b544544b 100644 (file)
@@ -5,7 +5,6 @@
 use std::{cell::RefCell, fmt, iter};
 
 use base_db::{FileId, FileRange};
-use either::Either;
 use hir_def::{
     body,
     resolver::{self, HasResolver, Resolver, TypeNs},
 use syntax::{
     algo::skip_trivia_token,
     ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody},
-    match_ast, AstNode, AstToken, Direction, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken,
-    TextSize, T,
+    match_ast, AstNode, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
 };
 
 use crate::{
     db::HirDatabase,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{resolve_hir_path, SourceAnalyzer},
-    Access, AssocItem, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasAttrs as _,
-    HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef,
-    Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
+    Access, AssocItem, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
+    HirFileId, Impl, InFile, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path,
+    ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -350,14 +348,6 @@ pub fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef
         self.imp.resolve_bind_pat_to_const(pat)
     }
 
-    pub fn resolve_derive_ident(
-        &self,
-        derive: &ast::Attr,
-        ident: &ast::Ident,
-    ) -> Option<PathResolution> {
-        self.imp.resolve_derive_ident(derive, ident)
-    }
-
     pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
         self.imp.record_literal_missing_fields(literal)
     }
@@ -475,7 +465,7 @@ fn derive_macro_calls(&self, attr: &ast::Attr) -> Option<Vec<Option<MacroCallId>
         let adt = InFile::new(file_id, &adt);
         let src = InFile::new(file_id, attr.clone());
         self.with_ctx(|ctx| {
-            let (_, res) = ctx.attr_to_derive_macro_call(adt, src)?;
+            let (.., res) = ctx.attr_to_derive_macro_call(adt, src)?;
             Some(res.to_vec())
         })
     }
@@ -668,7 +658,27 @@ fn descend_into_macros_impl(
                     // FIXME replace map.while_some with take_while once stable
                     token.value.ancestors().map(ast::TokenTree::cast).while_some().last()
                 {
-                    let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
+                    let parent = tt.syntax().parent()?;
+                    // check for derive attribute here
+                    let macro_call = match_ast! {
+                        match parent {
+                            ast::MacroCall(mcall) => mcall,
+                            // attribute we failed expansion for earlier, this might be a derive invocation
+                            // so try downmapping the token into the pseudo derive expansion
+                            ast::Meta(meta) => {
+                                let attr = meta.parent_attr()?;
+                                let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
+                                let call_id = self.with_ctx(|ctx| {
+                                    let (_, call_id, _) = ctx.attr_to_derive_macro_call(token.with_value(&adt), token.with_value(attr))?;
+                                    Some(call_id)
+                                })?;
+                                let file_id = call_id.as_file();
+                                return process_expansion_for_token(&mut stack,file_id,Some(adt.into()),token.as_ref(),);
+                            },
+                            _ => return None,
+                        }
+                    };
+
                     if tt.left_delimiter_token().map_or(false, |it| it == token.value) {
                         return None;
                     }
@@ -898,72 +908,6 @@ fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
         self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat)
     }
 
-    fn resolve_derive_ident(
-        &self,
-        derive: &ast::Attr,
-        ident: &ast::Ident,
-    ) -> Option<PathResolution> {
-        debug_assert!(ident.syntax().parent().and_then(ast::TokenTree::cast).is_some());
-        debug_assert!(ident.syntax().ancestors().any(|anc| anc == *derive.syntax()));
-        // derive macros are always at depth 2, tokentree -> meta -> attribute
-        let syntax = ident.syntax();
-
-        let tt = derive.token_tree()?;
-        let file = self.find_file(derive.syntax());
-        let adt = derive.syntax().parent().and_then(ast::Adt::cast)?;
-        let adt_def = ToDef::to_def(self, file.with_value(adt.clone()))?;
-        let res = self.with_ctx(|ctx| {
-            let (attr_id, derives) = ctx.attr_to_derive_macro_call(
-                file.with_value(&adt),
-                file.with_value(derive.clone()),
-            )?;
-            let attrs = adt_def.attrs(self.db);
-            let mut derive_paths = attrs.get(attr_id)?.parse_path_comma_token_tree()?;
-
-            let derive_idx = tt
-                .syntax()
-                .children_with_tokens()
-                .filter_map(SyntaxElement::into_token)
-                .take_while(|tok| tok != syntax)
-                .filter(|t| t.kind() == T![,])
-                .count();
-            let path_segment_idx = syntax
-                .siblings_with_tokens(Direction::Prev)
-                .filter_map(SyntaxElement::into_token)
-                .take_while(|tok| matches!(tok.kind(), T![:] | T![ident]))
-                .filter(|tok| tok.kind() == T![ident])
-                .count();
-
-            let mut mod_path = derive_paths.nth(derive_idx)?;
-
-            if path_segment_idx < mod_path.len() {
-                // the path for the given ident is a qualifier, resolve to module if possible
-                while path_segment_idx < mod_path.len() {
-                    mod_path.pop_segment();
-                }
-                Some(Either::Left(mod_path))
-            } else {
-                // otherwise fetch the derive
-                Some(Either::Right(derives[derive_idx]))
-            }
-        })?;
-
-        match res {
-            Either::Left(path) => {
-                let len = path.len();
-                resolve_hir_path(
-                    self.db,
-                    &self.scope(derive.syntax()).resolver,
-                    &Path::from_known_path(path, vec![None; len]),
-                )
-                .filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_))))
-            }
-            Either::Right(derive) => derive
-                .map(|call| MacroDef { id: self.db.lookup_intern_macro_call(call).def })
-                .map(PathResolution::Macro),
-        }
-    }
-
     fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
         self.analyze(literal.syntax())
             .record_literal_missing_fields(self.db, literal)