From 1956d57ed4896bb29dfcfaed2a5291ec69251f52 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Sun, 24 Nov 2019 15:50:45 +0300
Subject: [PATCH] Slightly reduce code duplication

---
 crates/ra_hir_def/src/attr.rs        | 54 ++++++++++++++--------------
 crates/ra_hir_def/src/lang_item.rs   |  2 +-
 crates/ra_hir_def/src/nameres/raw.rs |  7 ++--
 3 files changed, 30 insertions(+), 33 deletions(-)

diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 7d8f0d915e6..5c1b151f7d1 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -2,7 +2,7 @@
 
 use std::{ops, sync::Arc};
 
-use hir_expand::{either::Either, hygiene::Hygiene, AstId};
+use hir_expand::{either::Either, hygiene::Hygiene, AstId, Source};
 use mbe::ast_to_token_tree;
 use ra_cfg::CfgOptions;
 use ra_syntax::{
@@ -40,23 +40,19 @@ impl Attrs {
                     Some(it) => it,
                     None => return Attrs::default(),
                 };
-                let hygiene = Hygiene::new(db, src.file_id);
-                Attr::from_attrs_owner(&src.value, &hygiene)
+                Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
             }
             AttrDefId::StructFieldId(it) => {
                 let src = it.parent.child_source(db);
                 match &src.value[it.local_id] {
                     Either::A(_tuple) => Attrs::default(),
-                    Either::B(record) => {
-                        let hygiene = Hygiene::new(db, src.file_id);
-                        Attr::from_attrs_owner(record, &hygiene)
-                    }
+                    Either::B(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
                 }
             }
-            AttrDefId::EnumVariantId(it) => {
-                let src = it.parent.child_source(db);
-                let hygiene = Hygiene::new(db, src.file_id);
-                Attr::from_attrs_owner(&src.value[it.local_id], &hygiene)
+            AttrDefId::EnumVariantId(var_id) => {
+                let src = var_id.parent.child_source(db);
+                let src = src.as_ref().map(|it| &it[var_id.local_id]);
+                Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
             }
             AttrDefId::AdtId(it) => match it {
                 AdtId::StructId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db),
@@ -73,6 +69,22 @@ impl Attrs {
         }
     }
 
+    fn from_attrs_owner(db: &impl DefDatabase, owner: Source<&dyn AttrsOwner>) -> Attrs {
+        let hygiene = Hygiene::new(db, owner.file_id);
+        Attrs::new(owner.value, &hygiene)
+    }
+
+    pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
+        let mut attrs = owner.attrs().peekable();
+        let entries = if attrs.peek().is_none() {
+            // Avoid heap allocation
+            None
+        } else {
+            Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
+        };
+        Attrs { entries }
+    }
+
     pub fn has_atom(&self, atom: &str) -> bool {
         self.iter().any(|it| it.is_simple_atom(atom))
     }
@@ -100,7 +112,7 @@ pub enum AttrInput {
 }
 
 impl Attr {
-    pub(crate) fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
+    fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
         let path = Path::from_src(ast.path()?, hygiene)?;
         let input = match ast.input() {
             None => None,
@@ -117,17 +129,6 @@ impl Attr {
         Some(Attr { path, input })
     }
 
-    pub fn from_attrs_owner(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
-        let mut attrs = owner.attrs().peekable();
-        let entries = if attrs.peek().is_none() {
-            // Avoid heap allocation
-            None
-        } else {
-            Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
-        };
-        Attrs { entries }
-    }
-
     pub fn is_simple_atom(&self, name: &str) -> bool {
         // FIXME: Avoid cloning
         self.path.as_ident().map_or(false, |s| s.to_string() == name)
@@ -154,8 +155,8 @@ where
     N: ast::AttrsOwner,
     D: DefDatabase,
 {
-    let hygiene = Hygiene::new(db, src.file_id());
-    Attr::from_attrs_owner(&src.to_node(db), &hygiene)
+    let src = Source::new(src.file_id(), src.to_node(db));
+    Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
 }
 
 fn attrs_from_loc<T, D>(node: T, db: &D) -> Attrs
@@ -165,6 +166,5 @@ where
     D: DefDatabase,
 {
     let src = node.source(db);
-    let hygiene = Hygiene::new(db, src.file_id);
-    Attr::from_attrs_owner(&src.value, &hygiene)
+    Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
 }
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
index df951c53304..69d7bf21a35 100644
--- a/crates/ra_hir_def/src/lang_item.rs
+++ b/crates/ra_hir_def/src/lang_item.rs
@@ -114,7 +114,7 @@ impl LangItems {
     {
         let attrs = db.attrs(item.into());
         if let Some(lang_item_name) = attrs.find_string_value("lang") {
-            self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
+            self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item));
         }
     }
 }
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 552cbe5448a..19857875381 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -17,10 +17,7 @@ use ra_syntax::{
 use test_utils::tested_by;
 
 use crate::{
-    attr::{Attr, Attrs},
-    db::DefDatabase,
-    path::Path,
-    FileAstId, HirFileId, LocalImportId, Source,
+    attr::Attrs, db::DefDatabase, path::Path, FileAstId, HirFileId, LocalImportId, Source,
 };
 
 /// `RawItems` is a set of top-level items in a file (except for impls).
@@ -407,6 +404,6 @@ impl RawItemsCollector {
     }
 
     fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
-        Attr::from_attrs_owner(item, &self.hygiene)
+        Attrs::new(item, &self.hygiene)
     }
 }