diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-03-03 17:55:25 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-03-03 17:55:25 +0000 |
commit | 5abc45982b5558d4c5f8753cb531a4a0858faa0f (patch) | |
tree | c22bce8448c1b61e3c00cf8d7bb6f55d94204280 /crates | |
parent | 074474fe00a08d394cbdcac2a136bca825d93377 (diff) | |
parent | 53cab1cd21aa817a3588e64415a26b507ca00edd (diff) |
Merge #3428
3428: Move reference classification to ra_ide_db r=matklad a=matklad
Lost some marks along the way :-(
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide/src/display/navigation_target.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 14 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 3 | ||||
-rw-r--r-- | crates/ra_ide/src/marks.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide/src/references.rs | 12 | ||||
-rw-r--r-- | crates/ra_ide/src/references/classify.rs | 84 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide_db/src/defs.rs | 78 |
8 files changed, 90 insertions, 122 deletions
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index c9c14561a..d57451cc8 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use either::Either; | 3 | use either::Either; |
4 | use hir::{original_range, AssocItem, FieldSource, HasSource, InFile, ModuleSource}; | 4 | use hir::{original_range, AssocItem, FieldSource, HasSource, InFile, ModuleSource}; |
5 | use ra_db::{FileId, SourceDatabase}; | 5 | use ra_db::{FileId, SourceDatabase}; |
6 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::{defs::Definition, RootDatabase}; |
7 | use ra_syntax::{ | 7 | use ra_syntax::{ |
8 | ast::{self, DocCommentsOwner, NameOwner}, | 8 | ast::{self, DocCommentsOwner, NameOwner}, |
9 | match_ast, AstNode, SmolStr, | 9 | match_ast, AstNode, SmolStr, |
@@ -11,11 +11,7 @@ use ra_syntax::{ | |||
11 | TextRange, | 11 | TextRange, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::FileSymbol; |
15 | // expand::original_range, | ||
16 | references::Definition, | ||
17 | FileSymbol, | ||
18 | }; | ||
19 | 15 | ||
20 | use super::short_label::ShortLabel; | 16 | use super::short_label::ShortLabel; |
21 | 17 | ||
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 76ee232a3..4a8107d60 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -1,7 +1,10 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ra_ide_db::{defs::classify_name, symbol_index, RootDatabase}; | 4 | use ra_ide_db::{ |
5 | defs::{classify_name, classify_name_ref}, | ||
6 | symbol_index, RootDatabase, | ||
7 | }; | ||
5 | use ra_syntax::{ | 8 | use ra_syntax::{ |
6 | ast::{self}, | 9 | ast::{self}, |
7 | match_ast, AstNode, | 10 | match_ast, AstNode, |
@@ -11,7 +14,6 @@ use ra_syntax::{ | |||
11 | 14 | ||
12 | use crate::{ | 15 | use crate::{ |
13 | display::{ToNav, TryToNav}, | 16 | display::{ToNav, TryToNav}, |
14 | references::classify_name_ref, | ||
15 | FilePosition, NavigationTarget, RangeInfo, | 17 | FilePosition, NavigationTarget, RangeInfo, |
16 | }; | 18 | }; |
17 | 19 | ||
@@ -94,7 +96,7 @@ pub(crate) fn reference_definition( | |||
94 | 96 | ||
95 | #[cfg(test)] | 97 | #[cfg(test)] |
96 | mod tests { | 98 | mod tests { |
97 | use test_utils::{assert_eq_text, covers}; | 99 | use test_utils::assert_eq_text; |
98 | 100 | ||
99 | use crate::mock_analysis::analysis_and_position; | 101 | use crate::mock_analysis::analysis_and_position; |
100 | 102 | ||
@@ -206,7 +208,6 @@ mod tests { | |||
206 | 208 | ||
207 | #[test] | 209 | #[test] |
208 | fn goto_def_for_macros() { | 210 | fn goto_def_for_macros() { |
209 | covers!(goto_def_for_macros); | ||
210 | check_goto( | 211 | check_goto( |
211 | " | 212 | " |
212 | //- /lib.rs | 213 | //- /lib.rs |
@@ -223,7 +224,6 @@ mod tests { | |||
223 | 224 | ||
224 | #[test] | 225 | #[test] |
225 | fn goto_def_for_macros_from_other_crates() { | 226 | fn goto_def_for_macros_from_other_crates() { |
226 | covers!(goto_def_for_macros); | ||
227 | check_goto( | 227 | check_goto( |
228 | " | 228 | " |
229 | //- /lib.rs | 229 | //- /lib.rs |
@@ -335,7 +335,6 @@ mod tests { | |||
335 | 335 | ||
336 | #[test] | 336 | #[test] |
337 | fn goto_def_for_methods() { | 337 | fn goto_def_for_methods() { |
338 | covers!(goto_def_for_methods); | ||
339 | check_goto( | 338 | check_goto( |
340 | " | 339 | " |
341 | //- /lib.rs | 340 | //- /lib.rs |
@@ -355,7 +354,6 @@ mod tests { | |||
355 | 354 | ||
356 | #[test] | 355 | #[test] |
357 | fn goto_def_for_fields() { | 356 | fn goto_def_for_fields() { |
358 | covers!(goto_def_for_fields); | ||
359 | check_goto( | 357 | check_goto( |
360 | " | 358 | " |
361 | //- /lib.rs | 359 | //- /lib.rs |
@@ -374,7 +372,6 @@ mod tests { | |||
374 | 372 | ||
375 | #[test] | 373 | #[test] |
376 | fn goto_def_for_record_fields() { | 374 | fn goto_def_for_record_fields() { |
377 | covers!(goto_def_for_record_fields); | ||
378 | check_goto( | 375 | check_goto( |
379 | " | 376 | " |
380 | //- /lib.rs | 377 | //- /lib.rs |
@@ -787,7 +784,6 @@ mod tests { | |||
787 | 784 | ||
788 | #[test] | 785 | #[test] |
789 | fn goto_def_for_field_init_shorthand() { | 786 | fn goto_def_for_field_init_shorthand() { |
790 | covers!(goto_def_for_field_init_shorthand); | ||
791 | check_goto( | 787 | check_goto( |
792 | " | 788 | " |
793 | //- /lib.rs | 789 | //- /lib.rs |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 26c8996bc..e9c682557 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use hir::{Adt, HasSource, HirDisplay, Semantics}; | 3 | use hir::{Adt, HasSource, HirDisplay, Semantics}; |
4 | use ra_ide_db::{ | 4 | use ra_ide_db::{ |
5 | defs::{classify_name, Definition}, | 5 | defs::{classify_name, classify_name_ref, Definition}, |
6 | RootDatabase, | 6 | RootDatabase, |
7 | }; | 7 | }; |
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
@@ -14,7 +14,6 @@ use ra_syntax::{ | |||
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, | 16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, |
17 | references::classify_name_ref, | ||
18 | FilePosition, RangeInfo, | 17 | FilePosition, RangeInfo, |
19 | }; | 18 | }; |
20 | 19 | ||
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs index 7b8b727b4..1236cb773 100644 --- a/crates/ra_ide/src/marks.rs +++ b/crates/ra_ide/src/marks.rs | |||
@@ -3,11 +3,6 @@ | |||
3 | test_utils::marks!( | 3 | test_utils::marks!( |
4 | inserts_angle_brackets_for_generics | 4 | inserts_angle_brackets_for_generics |
5 | inserts_parens_for_function_calls | 5 | inserts_parens_for_function_calls |
6 | goto_def_for_macros | ||
7 | goto_def_for_methods | ||
8 | goto_def_for_fields | ||
9 | goto_def_for_record_fields | ||
10 | goto_def_for_field_init_shorthand | ||
11 | call_info_bad_offset | 6 | call_info_bad_offset |
12 | dont_complete_current_use | 7 | dont_complete_current_use |
13 | test_resolve_parent_module_on_module_decl | 8 | test_resolve_parent_module_on_module_decl |
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index 95a5c1914..67be3f6c9 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs | |||
@@ -9,14 +9,16 @@ | |||
9 | //! at the index that the match starts at and its tree parent is | 9 | //! at the index that the match starts at and its tree parent is |
10 | //! resolved to the search element definition, we get a reference. | 10 | //! resolved to the search element definition, we get a reference. |
11 | 11 | ||
12 | mod classify; | ||
13 | mod rename; | 12 | mod rename; |
14 | mod search_scope; | 13 | mod search_scope; |
15 | 14 | ||
16 | use hir::Semantics; | 15 | use hir::Semantics; |
17 | use once_cell::unsync::Lazy; | 16 | use once_cell::unsync::Lazy; |
18 | use ra_db::SourceDatabaseExt; | 17 | use ra_db::SourceDatabaseExt; |
19 | use ra_ide_db::RootDatabase; | 18 | use ra_ide_db::{ |
19 | defs::{classify_name, classify_name_ref, Definition}, | ||
20 | RootDatabase, | ||
21 | }; | ||
20 | use ra_prof::profile; | 22 | use ra_prof::profile; |
21 | use ra_syntax::{ | 23 | use ra_syntax::{ |
22 | algo::find_node_at_offset, | 24 | algo::find_node_at_offset, |
@@ -27,11 +29,7 @@ use test_utils::tested_by; | |||
27 | 29 | ||
28 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; | 30 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; |
29 | 31 | ||
30 | pub(crate) use self::{ | 32 | pub(crate) use self::rename::rename; |
31 | classify::{classify_name_ref, NameRefClass}, | ||
32 | rename::rename, | ||
33 | }; | ||
34 | pub(crate) use ra_ide_db::defs::{classify_name, Definition}; | ||
35 | 33 | ||
36 | pub use self::search_scope::SearchScope; | 34 | pub use self::search_scope::SearchScope; |
37 | 35 | ||
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs deleted file mode 100644 index 0bbf893f8..000000000 --- a/crates/ra_ide/src/references/classify.rs +++ /dev/null | |||
@@ -1,84 +0,0 @@ | |||
1 | //! Functions that are used to classify an element from its definition or reference. | ||
2 | |||
3 | use hir::{Local, PathResolution, Semantics}; | ||
4 | use ra_ide_db::defs::Definition; | ||
5 | use ra_ide_db::RootDatabase; | ||
6 | use ra_prof::profile; | ||
7 | use ra_syntax::{ast, AstNode}; | ||
8 | use test_utils::tested_by; | ||
9 | |||
10 | pub enum NameRefClass { | ||
11 | Definition(Definition), | ||
12 | FieldShorthand { local: Local, field: Definition }, | ||
13 | } | ||
14 | |||
15 | impl NameRefClass { | ||
16 | pub fn definition(self) -> Definition { | ||
17 | match self { | ||
18 | NameRefClass::Definition(def) => def, | ||
19 | NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local), | ||
20 | } | ||
21 | } | ||
22 | } | ||
23 | |||
24 | pub(crate) fn classify_name_ref( | ||
25 | sema: &Semantics<RootDatabase>, | ||
26 | name_ref: &ast::NameRef, | ||
27 | ) -> Option<NameRefClass> { | ||
28 | let _p = profile("classify_name_ref"); | ||
29 | |||
30 | let parent = name_ref.syntax().parent()?; | ||
31 | |||
32 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { | ||
33 | tested_by!(goto_def_for_methods); | ||
34 | if let Some(func) = sema.resolve_method_call(&method_call) { | ||
35 | return Some(NameRefClass::Definition(Definition::ModuleDef(func.into()))); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | ||
40 | tested_by!(goto_def_for_fields); | ||
41 | if let Some(field) = sema.resolve_field(&field_expr) { | ||
42 | return Some(NameRefClass::Definition(Definition::StructField(field))); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | if let Some(record_field) = ast::RecordField::cast(parent.clone()) { | ||
47 | tested_by!(goto_def_for_record_fields); | ||
48 | tested_by!(goto_def_for_field_init_shorthand); | ||
49 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { | ||
50 | let field = Definition::StructField(field); | ||
51 | let res = match local { | ||
52 | None => NameRefClass::Definition(field), | ||
53 | Some(local) => NameRefClass::FieldShorthand { field, local }, | ||
54 | }; | ||
55 | return Some(res); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { | ||
60 | tested_by!(goto_def_for_macros); | ||
61 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { | ||
62 | return Some(NameRefClass::Definition(Definition::Macro(macro_def))); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; | ||
67 | let resolved = sema.resolve_path(&path)?; | ||
68 | let res = match resolved { | ||
69 | PathResolution::Def(def) => Definition::ModuleDef(def), | ||
70 | PathResolution::AssocItem(item) => { | ||
71 | let def = match item { | ||
72 | hir::AssocItem::Function(it) => it.into(), | ||
73 | hir::AssocItem::Const(it) => it.into(), | ||
74 | hir::AssocItem::TypeAlias(it) => it.into(), | ||
75 | }; | ||
76 | Definition::ModuleDef(def) | ||
77 | } | ||
78 | PathResolution::Local(local) => Definition::Local(local), | ||
79 | PathResolution::TypeParam(par) => Definition::TypeParam(par), | ||
80 | PathResolution::Macro(def) => Definition::Macro(def), | ||
81 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), | ||
82 | }; | ||
83 | Some(NameRefClass::Definition(res)) | ||
84 | } | ||
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 9e0ee2158..7fc94d3cd 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -7,7 +7,7 @@ mod tests; | |||
7 | 7 | ||
8 | use hir::{Name, Semantics}; | 8 | use hir::{Name, Semantics}; |
9 | use ra_ide_db::{ | 9 | use ra_ide_db::{ |
10 | defs::{classify_name, Definition, NameClass}, | 10 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use ra_prof::profile; | 13 | use ra_prof::profile; |
@@ -19,11 +19,7 @@ use ra_syntax::{ | |||
19 | }; | 19 | }; |
20 | use rustc_hash::FxHashMap; | 20 | use rustc_hash::FxHashMap; |
21 | 21 | ||
22 | use crate::{ | 22 | use crate::{call_info::call_info_for_token, Analysis, FileId}; |
23 | call_info::call_info_for_token, | ||
24 | references::{classify_name_ref, NameRefClass}, | ||
25 | Analysis, FileId, | ||
26 | }; | ||
27 | 23 | ||
28 | pub(crate) use html::highlight_as_html; | 24 | pub(crate) use html::highlight_as_html; |
29 | pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}; | 25 | pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}; |
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 215daa441..f057435bf 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -6,8 +6,8 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | Adt, FieldSource, HasSource, ImplDef, Local, MacroDef, Module, ModuleDef, Name, Semantics, | 9 | Adt, FieldSource, HasSource, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution, |
10 | StructField, TypeParam, | 10 | Semantics, StructField, TypeParam, |
11 | }; | 11 | }; |
12 | use ra_prof::profile; | 12 | use ra_prof::profile; |
13 | use ra_syntax::{ | 13 | use ra_syntax::{ |
@@ -117,6 +117,8 @@ impl NameClass { | |||
117 | } | 117 | } |
118 | 118 | ||
119 | pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { | 119 | pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { |
120 | let _p = profile("classify_name"); | ||
121 | |||
120 | if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) { | 122 | if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) { |
121 | if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { | 123 | if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { |
122 | return Some(NameClass::ConstReference(Definition::ModuleDef(def))); | 124 | return Some(NameClass::ConstReference(Definition::ModuleDef(def))); |
@@ -127,7 +129,6 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option | |||
127 | } | 129 | } |
128 | 130 | ||
129 | fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Definition> { | 131 | fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Definition> { |
130 | let _p = profile("classify_name"); | ||
131 | let parent = name.syntax().parent()?; | 132 | let parent = name.syntax().parent()?; |
132 | 133 | ||
133 | match_ast! { | 134 | match_ast! { |
@@ -192,3 +193,74 @@ fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Opti | |||
192 | } | 193 | } |
193 | } | 194 | } |
194 | } | 195 | } |
196 | |||
197 | pub enum NameRefClass { | ||
198 | Definition(Definition), | ||
199 | FieldShorthand { local: Local, field: Definition }, | ||
200 | } | ||
201 | |||
202 | impl NameRefClass { | ||
203 | pub fn definition(self) -> Definition { | ||
204 | match self { | ||
205 | NameRefClass::Definition(def) => def, | ||
206 | NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local), | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | pub fn classify_name_ref( | ||
212 | sema: &Semantics<RootDatabase>, | ||
213 | name_ref: &ast::NameRef, | ||
214 | ) -> Option<NameRefClass> { | ||
215 | let _p = profile("classify_name_ref"); | ||
216 | |||
217 | let parent = name_ref.syntax().parent()?; | ||
218 | |||
219 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { | ||
220 | if let Some(func) = sema.resolve_method_call(&method_call) { | ||
221 | return Some(NameRefClass::Definition(Definition::ModuleDef(func.into()))); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | ||
226 | if let Some(field) = sema.resolve_field(&field_expr) { | ||
227 | return Some(NameRefClass::Definition(Definition::StructField(field))); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | if let Some(record_field) = ast::RecordField::cast(parent.clone()) { | ||
232 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { | ||
233 | let field = Definition::StructField(field); | ||
234 | let res = match local { | ||
235 | None => NameRefClass::Definition(field), | ||
236 | Some(local) => NameRefClass::FieldShorthand { field, local }, | ||
237 | }; | ||
238 | return Some(res); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { | ||
243 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { | ||
244 | return Some(NameRefClass::Definition(Definition::Macro(macro_def))); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; | ||
249 | let resolved = sema.resolve_path(&path)?; | ||
250 | let res = match resolved { | ||
251 | PathResolution::Def(def) => Definition::ModuleDef(def), | ||
252 | PathResolution::AssocItem(item) => { | ||
253 | let def = match item { | ||
254 | hir::AssocItem::Function(it) => it.into(), | ||
255 | hir::AssocItem::Const(it) => it.into(), | ||
256 | hir::AssocItem::TypeAlias(it) => it.into(), | ||
257 | }; | ||
258 | Definition::ModuleDef(def) | ||
259 | } | ||
260 | PathResolution::Local(local) => Definition::Local(local), | ||
261 | PathResolution::TypeParam(par) => Definition::TypeParam(par), | ||
262 | PathResolution::Macro(def) => Definition::Macro(def), | ||
263 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), | ||
264 | }; | ||
265 | Some(NameRefClass::Definition(res)) | ||
266 | } | ||