diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 5f8eb72a050..5ca331380ea 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -43,7 +43,7 @@ impl FunctionData {
             attrs: item_tree.attrs(loc.id.value.into()).clone(),
             has_self_param: func.has_self_param,
             is_unsafe: func.is_unsafe,
-            visibility: func.visibility.clone(),
+            visibility: item_tree[func.visibility].clone(),
         })
     }
 }
@@ -69,7 +69,7 @@ impl TypeAliasData {
         Arc::new(TypeAliasData {
             name: typ.name.clone(),
             type_ref: typ.type_ref.clone(),
-            visibility: typ.visibility.clone(),
+            visibility: item_tree[typ.visibility].clone(),
             bounds: typ.bounds.clone(),
         })
     }
@@ -175,7 +175,7 @@ impl ConstData {
         Arc::new(ConstData {
             name: konst.name.clone(),
             type_ref: konst.type_ref.clone(),
-            visibility: konst.visibility.clone(),
+            visibility: item_tree[konst.visibility].clone(),
         })
     }
 }
@@ -197,7 +197,7 @@ impl StaticData {
         Arc::new(StaticData {
             name: Some(statik.name.clone()),
             type_ref: statik.type_ref.clone(),
-            visibility: statik.visibility.clone(),
+            visibility: item_tree[statik.visibility].clone(),
             mutable: statik.mutable,
         })
     }
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
index 40bb78b57a5..bbaa7c1f6fb 100644
--- a/crates/ra_hir_def/src/item_tree.rs
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -29,12 +29,59 @@ use crate::{
     attr::Attrs,
     db::DefDatabase,
     generics::GenericParams,
-    path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path},
+    path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
     type_ref::{Mutability, TypeBound, TypeRef},
     visibility::RawVisibility,
 };
 use smallvec::SmallVec;
 
+#[derive(Default, Debug, Eq, PartialEq)]
+struct ItemVisibilities {
+    arena: Arena<RawVisibility>,
+}
+
+impl ItemVisibilities {
+    fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
+        match &vis {
+            RawVisibility::Public => RawVisibilityId::PUB,
+            RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind {
+                PathKind::Super(0) => RawVisibilityId::PRIV,
+                PathKind::Crate => RawVisibilityId::PUB_CRATE,
+                _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
+            },
+            _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
+        }
+    }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct RawVisibilityId(u32);
+
+impl RawVisibilityId {
+    pub const PUB: Self = RawVisibilityId(u32::max_value());
+    pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
+    pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
+}
+
+impl fmt::Debug for RawVisibilityId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut f = f.debug_tuple("RawVisibilityId");
+        match *self {
+            Self::PUB => f.field(&"pub"),
+            Self::PRIV => f.field(&"pub(self)"),
+            Self::PUB_CRATE => f.field(&"pub(crate)"),
+            _ => f.field(&self.0),
+        };
+        f.finish()
+    }
+}
+
+static VIS_PUB: RawVisibility = RawVisibility::Public;
+static VIS_PRIV: RawVisibility =
+    RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() });
+static VIS_PUB_CRATE: RawVisibility =
+    RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() });
+
 #[derive(Default, Debug, Eq, PartialEq)]
 struct ItemTreeData {
     imports: Arena<Import>,
@@ -53,6 +100,8 @@ struct ItemTreeData {
     mods: Arena<Mod>,
     macro_calls: Arena<MacroCall>,
     exprs: Arena<Expr>,
+
+    vis: ItemVisibilities,
 }
 
 #[derive(Debug, Eq, PartialEq, Hash)]
@@ -303,6 +352,18 @@ macro_rules! impl_index {
 
 impl_index!(fields: Field, variants: Variant, exprs: Expr);
 
+impl Index<RawVisibilityId> for ItemTree {
+    type Output = RawVisibility;
+    fn index(&self, index: RawVisibilityId) -> &Self::Output {
+        match index {
+            RawVisibilityId::PRIV => &VIS_PRIV,
+            RawVisibilityId::PUB => &VIS_PUB,
+            RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
+            _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
+        }
+    }
+}
+
 impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
     type Output = N;
     fn index(&self, id: FileItemTreeId<N>) -> &N {
@@ -315,7 +376,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
 pub struct Import {
     pub path: ModPath,
     pub alias: Option<ImportAlias>,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub is_glob: bool,
     pub is_prelude: bool,
     /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
@@ -327,7 +388,7 @@ pub struct Import {
 pub struct ExternCrate {
     pub path: ModPath,
     pub alias: Option<ImportAlias>,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     /// Whether this is a `#[macro_use] extern crate ...`.
     pub is_macro_use: bool,
     pub ast_id: FileAstId<ast::ExternCrateItem>,
@@ -336,7 +397,7 @@ pub struct ExternCrate {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Function {
     pub name: Name,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub generic_params: GenericParams,
     pub has_self_param: bool,
     pub is_unsafe: bool,
@@ -348,7 +409,7 @@ pub struct Function {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Struct {
     pub name: Name,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub generic_params: GenericParams,
     pub fields: Fields,
     pub ast_id: FileAstId<ast::StructDef>,
@@ -368,7 +429,7 @@ pub enum StructDefKind {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Union {
     pub name: Name,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub generic_params: GenericParams,
     pub fields: Fields,
     pub ast_id: FileAstId<ast::UnionDef>,
@@ -377,7 +438,7 @@ pub struct Union {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Enum {
     pub name: Name,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub generic_params: GenericParams,
     pub variants: Range<Idx<Variant>>,
     pub ast_id: FileAstId<ast::EnumDef>,
@@ -387,7 +448,7 @@ pub struct Enum {
 pub struct Const {
     /// const _: () = ();
     pub name: Option<Name>,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub type_ref: TypeRef,
     pub ast_id: FileAstId<ast::ConstDef>,
 }
@@ -395,7 +456,7 @@ pub struct Const {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Static {
     pub name: Name,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub mutable: bool,
     pub type_ref: TypeRef,
     pub ast_id: FileAstId<ast::StaticDef>,
@@ -404,7 +465,7 @@ pub struct Static {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Trait {
     pub name: Name,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub generic_params: GenericParams,
     pub auto: bool,
     pub items: Vec<AssocItem>,
@@ -424,7 +485,7 @@ pub struct Impl {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TypeAlias {
     pub name: Name,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
     pub bounds: Vec<TypeBound>,
     pub generic_params: GenericParams,
@@ -435,7 +496,7 @@ pub struct TypeAlias {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Mod {
     pub name: Name,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
     pub kind: ModKind,
     pub ast_id: FileAstId<ast::Module>,
 }
@@ -549,5 +610,5 @@ pub enum Fields {
 pub struct Field {
     pub name: Name,
     pub type_ref: TypeRef,
-    pub visibility: RawVisibility,
+    pub visibility: RawVisibilityId,
 }
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 3af22149d86..73c21b9ec11 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -36,7 +36,7 @@ pub(super) struct Ctx {
     source_ast_id_map: Arc<AstIdMap>,
     body_ctx: crate::body::LowerCtx,
     inner_items: Vec<ModItem>,
-    forced_visibility: Option<RawVisibility>,
+    forced_visibility: Option<RawVisibilityId>,
 }
 
 impl Ctx {
@@ -201,7 +201,7 @@ impl Ctx {
         start..end
     }
 
-    fn lower_record_field(&self, field: &ast::RecordFieldDef) -> Option<Field> {
+    fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> {
         let name = field.name()?.as_name();
         let visibility = self.lower_visibility(field);
         let type_ref = self.lower_type_ref(&field.ascribed_type()?);
@@ -220,7 +220,7 @@ impl Ctx {
         start..end
     }
 
-    fn lower_tuple_field(&self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> {
+    fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> {
         let name = Name::new_tuple_field(idx);
         let visibility = self.lower_visibility(field);
         let type_ref = self.lower_type_ref(&field.type_ref()?);
@@ -399,7 +399,7 @@ impl Ctx {
         let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def);
         let auto = trait_def.auto_token().is_some();
         let items = trait_def.item_list().map(|list| {
-            self.with_inherited_visibility(visibility.clone(), |this| {
+            self.with_inherited_visibility(visibility, |this| {
                 list.items()
                     .filter_map(|item| {
                         let attrs = Attrs::new(&item, &this.hygiene);
@@ -463,7 +463,7 @@ impl Ctx {
                 imports.push(id(tree.imports.alloc(Import {
                     path,
                     alias,
-                    visibility: visibility.clone(),
+                    visibility,
                     is_glob,
                     is_prelude,
                     ast_id,
@@ -596,11 +596,13 @@ impl Ctx {
         }
     }
 
-    fn lower_visibility(&self, item: &impl ast::VisibilityOwner) -> RawVisibility {
-        match &self.forced_visibility {
-            Some(vis) => vis.clone(),
+    fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
+        let vis = match self.forced_visibility {
+            Some(vis) => return vis,
             None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene),
-        }
+        };
+
+        self.data().vis.alloc(vis)
     }
 
     fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef {
@@ -613,7 +615,7 @@ impl Ctx {
     /// Forces the visibility `vis` to be used for all items lowered during execution of `f`.
     fn with_inherited_visibility<R>(
         &mut self,
-        vis: RawVisibility,
+        vis: RawVisibilityId,
         f: impl FnOnce(&mut Self) -> R,
     ) -> R {
         let old = mem::replace(&mut self.forced_visibility, Some(vis));
diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs
index 179baee788c..42394a96075 100644
--- a/crates/ra_hir_def/src/item_tree/tests.rs
+++ b/crates/ra_hir_def/src/item_tree/tests.rs
@@ -219,31 +219,31 @@ inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments
 
 top-level items:
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
-Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) }
+Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
-Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) }
+Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }]
-ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: Module(ModPath { kind: Super(0), segments: [] }), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrateItem>(1) }
+ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrateItem>(1) }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }]
-Trait { name: Name(Text("Tr")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 2, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }, TypeParamData { name: Some(Name(Text("U"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(2) }
+Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 2, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }, TypeParamData { name: Some(Name(Text("U"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(2) }
 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }]
-> TypeAlias { name: Name(Text("AssocTy")), visibility: Module(ModPath { kind: Super(0), segments: [] }), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAliasDef>(8) }
+> TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAliasDef>(8) }
 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }]
-> Const { name: Some(Name(Text("CONST"))), visibility: Module(ModPath { kind: Super(0), segments: [] }), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ConstDef>(9) }
+> Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ConstDef>(9) }
 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }]
-> Function { name: Name(Text("method")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(10) }
+> Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(10) }
 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }]
-> Function { name: Name(Text("dfl_method")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(11) }
+> Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(11) }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }]
-Struct { name: Name(Text("Struct0")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(3), kind: Unit }
+Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: Some(Tuple([])), provenance: TypeParamList }] }, where_predicates: [] }, fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(3), kind: Unit }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }]
-Struct { name: Name(Text("Struct1")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::<Field>(0)..Idx::<Field>(1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(4), kind: Tuple }
+Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Tuple(Idx::<Field>(0)..Idx::<Field>(1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(4), kind: Tuple }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }]
-Struct { name: Name(Text("Struct2")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::<Field>(1)..Idx::<Field>(2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(5), kind: Record }
+Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [] }, fields: Record(Idx::<Field>(1)..Idx::<Field>(2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(5), kind: Record }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }]
-Enum { name: Name(Text("En")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::<Variant>(0)..Idx::<Variant>(1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::EnumDef>(6) }
+Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, variants: Idx::<Variant>(0)..Idx::<Variant>(1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::EnumDef>(6) }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }]
-Union { name: Name(Text("Un")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::<Field>(3)..Idx::<Field>(4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UnionDef>(7) }
+Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, fields: Record(Idx::<Field>(3)..Idx::<Field>(4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UnionDef>(7) }
     "###);
 }
 
@@ -267,12 +267,12 @@ inner attrs: Attrs { entries: None }
 
 top-level items:
 Impl { generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("T"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("A"))] }, generic_args: [None] }) }] }, target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) }
-> Function { name: Name(Text("foo")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
+> Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
 
 inner items:
 
 for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(2):
-Function { name: Name(Text("end")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
+Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("W"))), default: None, provenance: TypeParamList }] }, where_predicates: [WherePredicate { target: TypeRef(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("W"))] }, generic_args: [None] })), bound: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Write"))] }, generic_args: [None] }) }] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
 
     "###);
 }
@@ -296,9 +296,9 @@ inner attrs: Attrs { entries: None }
 
 top-level items:
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
-Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
+Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
-Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
+Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
     "###);
 }
 
@@ -321,11 +321,11 @@ inner attrs: Attrs { entries: None }
 
 top-level items:
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }]
-Trait { name: Name(Text("Tr")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }] }, where_predicates: [] }, auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(0) }
+Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 1, data: [TypeParamData { name: Some(Name(Text("Self"))), default: None, provenance: TraitSelf }] }, where_predicates: [] }, auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(0) }
 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
-> Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
+> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
-> Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
+> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
     "###);
 }
 
@@ -350,9 +350,9 @@ top-level items:
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }]
 Impl { generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) }
 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
-> Function { name: Name(Text("a")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
+> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
-> Function { name: Name(Text("b")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
+> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
     "###);
 }
 
@@ -398,13 +398,13 @@ fn inner_item_attrs() {
 inner attrs: Attrs { entries: None }
 
 top-level items:
-Function { name: Name(Text("foo")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(0) }
+Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(0) }
 
 inner items:
 
 for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(1):
 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }]
-Function { name: Name(Text("inner")), visibility: Module(ModPath { kind: Super(0), segments: [] }), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
+Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParams { types: Arena { len: 0, data: [] }, where_predicates: [] }, has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
 
     "###);
 }
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 40aff830f07..94da700ad37 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -20,7 +20,9 @@ use test_utils::mark;
 use crate::{
     attr::Attrs,
     db::DefDatabase,
-    item_tree::{self, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind},
+    item_tree::{
+        self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind,
+    },
     nameres::{
         diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
         BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
@@ -114,26 +116,28 @@ struct Import {
     pub is_macro_use: bool,
 }
 
-impl From<item_tree::Import> for Import {
-    fn from(it: item_tree::Import) -> Self {
+impl Import {
+    fn from_use(tree: &ItemTree, id: FileItemTreeId<item_tree::Import>) -> Self {
+        let it = &tree[id];
+        let visibility = &tree[it.visibility];
         Self {
-            path: it.path,
-            alias: it.alias,
-            visibility: it.visibility,
+            path: it.path.clone(),
+            alias: it.alias.clone(),
+            visibility: visibility.clone(),
             is_glob: it.is_glob,
             is_prelude: it.is_prelude,
             is_extern_crate: false,
             is_macro_use: false,
         }
     }
-}
 
-impl From<item_tree::ExternCrate> for Import {
-    fn from(it: item_tree::ExternCrate) -> Self {
+    fn from_extern_crate(tree: &ItemTree, id: FileItemTreeId<item_tree::ExternCrate>) -> Self {
+        let it = &tree[id];
+        let visibility = &tree[it.visibility];
         Self {
-            path: it.path,
-            alias: it.alias,
-            visibility: it.visibility,
+            path: it.path.clone(),
+            alias: it.alias.clone(),
+            visibility: visibility.clone(),
             is_glob: false,
             is_prelude: false,
             is_extern_crate: true,
@@ -761,14 +765,14 @@ impl ModCollector<'_, '_> {
                     ModItem::Import(import_id) => {
                         self.def_collector.unresolved_imports.push(ImportDirective {
                             module_id: self.module_id,
-                            import: self.item_tree[import_id].clone().into(),
+                            import: Import::from_use(&self.item_tree, import_id),
                             status: PartialResolvedImport::Unresolved,
                         })
                     }
                     ModItem::ExternCrate(import_id) => {
                         self.def_collector.unresolved_imports.push(ImportDirective {
                             module_id: self.module_id,
-                            import: self.item_tree[import_id].clone().into(),
+                            import: Import::from_extern_crate(&self.item_tree, import_id),
                             status: PartialResolvedImport::Unresolved,
                         })
                     }
@@ -795,7 +799,7 @@ impl ModCollector<'_, '_> {
                             .intern(self.def_collector.db)
                             .into(),
                             name: &func.name,
-                            visibility: &func.visibility,
+                            visibility: &self.item_tree[func.visibility],
                             has_constructor: false,
                         });
                     }
@@ -812,7 +816,7 @@ impl ModCollector<'_, '_> {
                                 .intern(self.def_collector.db)
                                 .into(),
                             name: &it.name,
-                            visibility: &it.visibility,
+                            visibility: &self.item_tree[it.visibility],
                             has_constructor: it.kind != StructDefKind::Record,
                         });
                     }
@@ -829,7 +833,7 @@ impl ModCollector<'_, '_> {
                                 .intern(self.def_collector.db)
                                 .into(),
                             name: &it.name,
-                            visibility: &it.visibility,
+                            visibility: &self.item_tree[it.visibility],
                             has_constructor: false,
                         });
                     }
@@ -846,7 +850,7 @@ impl ModCollector<'_, '_> {
                                 .intern(self.def_collector.db)
                                 .into(),
                             name: &it.name,
-                            visibility: &it.visibility,
+                            visibility: &self.item_tree[it.visibility],
                             has_constructor: false,
                         });
                     }
@@ -862,7 +866,7 @@ impl ModCollector<'_, '_> {
                                 .intern(self.def_collector.db)
                                 .into(),
                                 name,
-                                visibility: &it.visibility,
+                                visibility: &self.item_tree[it.visibility],
                                 has_constructor: false,
                             });
                         }
@@ -875,7 +879,7 @@ impl ModCollector<'_, '_> {
                                 .intern(self.def_collector.db)
                                 .into(),
                             name: &it.name,
-                            visibility: &it.visibility,
+                            visibility: &self.item_tree[it.visibility],
                             has_constructor: false,
                         });
                     }
@@ -887,7 +891,7 @@ impl ModCollector<'_, '_> {
                                 .intern(self.def_collector.db)
                                 .into(),
                             name: &it.name,
-                            visibility: &it.visibility,
+                            visibility: &self.item_tree[it.visibility],
                             has_constructor: false,
                         });
                     }
@@ -902,7 +906,7 @@ impl ModCollector<'_, '_> {
                             .intern(self.def_collector.db)
                             .into(),
                             name: &it.name,
-                            visibility: &it.visibility,
+                            visibility: &self.item_tree[it.visibility],
                             has_constructor: false,
                         });
                     }
@@ -935,7 +939,7 @@ impl ModCollector<'_, '_> {
                     module.name.clone(),
                     AstId::new(self.file_id, module.ast_id),
                     None,
-                    &module.visibility,
+                    &self.item_tree[module.visibility],
                 );
 
                 ModCollector {
@@ -965,7 +969,7 @@ impl ModCollector<'_, '_> {
                             module.name.clone(),
                             ast_id,
                             Some((file_id, is_mod_rs)),
-                            &module.visibility,
+                            &self.item_tree[module.visibility],
                         );
                         let item_tree = self.def_collector.db.item_tree(file_id.into());
                         ModCollector {