aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/syntax_highlighting
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/syntax_highlighting')
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs108
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs118
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs28
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html8
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html12
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html6
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs44
9 files changed, 207 insertions, 125 deletions
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index b0cfdd8b7..8cc877c1c 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -1,6 +1,6 @@
1//! Computes color for a single element. 1//! Computes color for a single element.
2 2
3use hir::{AsAssocItem, Semantics, VariantDef}; 3use hir::{AsAssocItem, AssocItemContainer, Semantics, VariantDef};
4use ide_db::{ 4use ide_db::{
5 defs::{Definition, NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
6 RootDatabase, SymbolKind, 6 RootDatabase, SymbolKind,
@@ -12,7 +12,10 @@ use syntax::{
12 SyntaxNode, SyntaxToken, T, 12 SyntaxNode, SyntaxToken, T,
13}; 13};
14 14
15use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag}; 15use crate::{
16 syntax_highlighting::tags::{HlOperator, HlPunct},
17 Highlight, HlMod, HlTag,
18};
16 19
17pub(super) fn element( 20pub(super) fn element(
18 sema: &Semantics<RootDatabase>, 21 sema: &Semantics<RootDatabase>,
@@ -132,7 +135,7 @@ pub(super) fn element(
132 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), 135 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
133 BYTE => HlTag::ByteLiteral.into(), 136 BYTE => HlTag::ByteLiteral.into(),
134 CHAR => HlTag::CharLiteral.into(), 137 CHAR => HlTag::CharLiteral.into(),
135 QUESTION => Highlight::new(HlTag::Operator) | HlMod::ControlFlow, 138 QUESTION => Highlight::new(HlTag::Operator(HlOperator::Other)) | HlMod::ControlFlow,
136 LIFETIME => { 139 LIFETIME => {
137 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); 140 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
138 141
@@ -146,8 +149,11 @@ pub(super) fn element(
146 } 149 }
147 } 150 }
148 p if p.is_punct() => match p { 151 p if p.is_punct() => match p {
152 T![&] if element.parent().and_then(ast::BinExpr::cast).is_some() => {
153 HlTag::Operator(HlOperator::Bitwise).into()
154 }
149 T![&] => { 155 T![&] => {
150 let h = HlTag::Operator.into(); 156 let h = HlTag::Operator(HlOperator::Other).into();
151 let is_unsafe = element 157 let is_unsafe = element
152 .parent() 158 .parent()
153 .and_then(ast::RefExpr::cast) 159 .and_then(ast::RefExpr::cast)
@@ -159,13 +165,18 @@ pub(super) fn element(
159 h 165 h
160 } 166 }
161 } 167 }
162 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlTag::Operator.into(), 168 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => {
169 HlTag::Operator(HlOperator::Other).into()
170 }
163 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { 171 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
164 HlTag::Symbol(SymbolKind::Macro).into() 172 HlTag::Symbol(SymbolKind::Macro).into()
165 } 173 }
166 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => { 174 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
167 HlTag::BuiltinType.into() 175 HlTag::BuiltinType.into()
168 } 176 }
177 T![!] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
178 HlTag::Operator(HlOperator::Logical).into()
179 }
169 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { 180 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
170 HlTag::Keyword.into() 181 HlTag::Keyword.into()
171 } 182 }
@@ -175,9 +186,9 @@ pub(super) fn element(
175 let expr = prefix_expr.expr()?; 186 let expr = prefix_expr.expr()?;
176 let ty = sema.type_of_expr(&expr)?; 187 let ty = sema.type_of_expr(&expr)?;
177 if ty.is_raw_ptr() { 188 if ty.is_raw_ptr() {
178 HlTag::Operator | HlMod::Unsafe 189 HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
179 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { 190 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
180 HlTag::Operator.into() 191 HlTag::Operator(HlOperator::Other).into()
181 } else { 192 } else {
182 HlTag::Punctuation(HlPunct::Other).into() 193 HlTag::Punctuation(HlPunct::Other).into()
183 } 194 }
@@ -188,19 +199,43 @@ pub(super) fn element(
188 let expr = prefix_expr.expr()?; 199 let expr = prefix_expr.expr()?;
189 match expr { 200 match expr {
190 ast::Expr::Literal(_) => HlTag::NumericLiteral, 201 ast::Expr::Literal(_) => HlTag::NumericLiteral,
191 _ => HlTag::Operator, 202 _ => HlTag::Operator(HlOperator::Other),
192 } 203 }
193 .into() 204 .into()
194 } 205 }
195 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { 206 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
196 HlTag::Operator.into() 207 HlTag::Operator(HlOperator::Other).into()
208 }
209 T![+] | T![-] | T![*] | T![/] | T![+=] | T![-=] | T![*=] | T![/=]
210 if element.parent().and_then(ast::BinExpr::cast).is_some() =>
211 {
212 HlTag::Operator(HlOperator::Arithmetic).into()
213 }
214 T![|] | T![&] | T![!] | T![^] | T![|=] | T![&=] | T![^=]
215 if element.parent().and_then(ast::BinExpr::cast).is_some() =>
216 {
217 HlTag::Operator(HlOperator::Bitwise).into()
218 }
219 T![&&] | T![||] if element.parent().and_then(ast::BinExpr::cast).is_some() => {
220 HlTag::Operator(HlOperator::Logical).into()
221 }
222 T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=]
223 if element.parent().and_then(ast::BinExpr::cast).is_some() =>
224 {
225 HlTag::Operator(HlOperator::Comparision).into()
226 }
227 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => {
228 HlTag::Operator(HlOperator::Other).into()
197 } 229 }
198 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => HlTag::Operator.into(),
199 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => { 230 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => {
200 HlTag::Operator.into() 231 HlTag::Operator(HlOperator::Other).into()
232 }
233 _ if element.parent().and_then(ast::RangePat::cast).is_some() => {
234 HlTag::Operator(HlOperator::Other).into()
235 }
236 _ if element.parent().and_then(ast::RestPat::cast).is_some() => {
237 HlTag::Operator(HlOperator::Other).into()
201 } 238 }
202 _ if element.parent().and_then(ast::RangePat::cast).is_some() => HlTag::Operator.into(),
203 _ if element.parent().and_then(ast::RestPat::cast).is_some() => HlTag::Operator.into(),
204 _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(), 239 _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(),
205 kind => HlTag::Punctuation(match kind { 240 kind => HlTag::Punctuation(match kind {
206 T!['['] | T![']'] => HlPunct::Bracket, 241 T!['['] | T![']'] => HlPunct::Bracket,
@@ -275,12 +310,24 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
275 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), 310 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module),
276 hir::ModuleDef::Function(func) => { 311 hir::ModuleDef::Function(func) => {
277 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); 312 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
278 if func.as_assoc_item(db).is_some() { 313 if let Some(item) = func.as_assoc_item(db) {
279 h |= HlMod::Associated; 314 h |= HlMod::Associated;
280 if func.self_param(db).is_none() { 315 if func.self_param(db).is_none() {
281 h |= HlMod::Static 316 h |= HlMod::Static
282 } 317 }
318
319 match item.container(db) {
320 AssocItemContainer::Impl(i) => {
321 if i.trait_(db).is_some() {
322 h |= HlMod::Trait;
323 }
324 }
325 AssocItemContainer::Trait(_t) => {
326 h |= HlMod::Trait;
327 }
328 }
283 } 329 }
330
284 if func.is_unsafe(db) { 331 if func.is_unsafe(db) {
285 h |= HlMod::Unsafe; 332 h |= HlMod::Unsafe;
286 } 333 }
@@ -292,16 +339,37 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
292 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), 339 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant),
293 hir::ModuleDef::Const(konst) => { 340 hir::ModuleDef::Const(konst) => {
294 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); 341 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
295 if konst.as_assoc_item(db).is_some() { 342 if let Some(item) = konst.as_assoc_item(db) {
296 h |= HlMod::Associated 343 h |= HlMod::Associated;
344 match item.container(db) {
345 AssocItemContainer::Impl(i) => {
346 if i.trait_(db).is_some() {
347 h |= HlMod::Trait;
348 }
349 }
350 AssocItemContainer::Trait(_t) => {
351 h |= HlMod::Trait;
352 }
353 }
297 } 354 }
355
298 return h; 356 return h;
299 } 357 }
300 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), 358 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait),
301 hir::ModuleDef::TypeAlias(type_) => { 359 hir::ModuleDef::TypeAlias(type_) => {
302 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); 360 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
303 if type_.as_assoc_item(db).is_some() { 361 if let Some(item) = type_.as_assoc_item(db) {
304 h |= HlMod::Associated 362 h |= HlMod::Associated;
363 match item.container(db) {
364 AssocItemContainer::Impl(i) => {
365 if i.trait_(db).is_some() {
366 h |= HlMod::Trait;
367 }
368 }
369 AssocItemContainer::Trait(_t) => {
370 h |= HlMod::Trait;
371 }
372 }
305 } 373 }
306 return h; 374 return h;
307 } 375 }
@@ -362,6 +430,10 @@ fn highlight_method_call(
362 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { 430 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
363 h |= HlMod::Unsafe; 431 h |= HlMod::Unsafe;
364 } 432 }
433 if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() {
434 h |= HlMod::Trait
435 }
436
365 if let Some(self_param) = func.self_param(sema.db) { 437 if let Some(self_param) = func.self_param(sema.db) {
366 match self_param.access(sema.db) { 438 match self_param.access(sema.db) {
367 hir::Access::Shared => (), 439 hir::Access::Shared => (),
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 963c3fb59..04fafd244 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -1,17 +1,18 @@
1//! "Recursive" Syntax highlighting for code in doctests and fixtures. 1//! "Recursive" Syntax highlighting for code in doctests and fixtures.
2 2
3use std::{mem, ops::Range}; 3use std::mem;
4 4
5use either::Either; 5use either::Either;
6use hir::{HasAttrs, InFile, Semantics}; 6use hir::{InFile, Semantics};
7use ide_db::{call_info::ActiveParameter, defs::Definition, SymbolKind}; 7use ide_db::{call_info::ActiveParameter, SymbolKind};
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode}, 9 ast::{self, AstNode},
10 match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, 10 AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
11}; 11};
12 12
13use crate::{ 13use crate::{
14 doc_links::extract_definitions_from_markdown, Analysis, HlMod, HlRange, HlTag, RootDatabase, 14 doc_links::{doc_attributes, extract_definitions_from_markdown, resolve_doc_path_for_def},
15 Analysis, HlMod, HlRange, HlTag, RootDatabase,
15}; 16};
16 17
17use super::{highlights::Highlights, injector::Injector}; 18use super::{highlights::Highlights, injector::Injector};
@@ -89,33 +90,6 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
89 "edition2021", 90 "edition2021",
90]; 91];
91 92
92fn doc_attributes<'node>(
93 sema: &Semantics<RootDatabase>,
94 node: &'node SyntaxNode,
95) -> Option<(hir::AttrsWithOwner, Definition)> {
96 match_ast! {
97 match node {
98 ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
99 ast::Module(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
100 ast::Fn(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))),
101 ast::Struct(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))),
102 ast::Union(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))),
103 ast::Enum(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))),
104 ast::Variant(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))),
105 ast::Trait(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))),
106 ast::Static(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))),
107 ast::Const(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))),
108 ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))),
109 ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))),
110 ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
111 ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
112 ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))),
113 // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
114 _ => return None
115 }
116 }
117}
118
119/// Injection of syntax highlighting of doctests. 93/// Injection of syntax highlighting of doctests.
120pub(super) fn doc_comment( 94pub(super) fn doc_comment(
121 hl: &mut Highlights, 95 hl: &mut Highlights,
@@ -138,8 +112,28 @@ pub(super) fn doc_comment(
138 // Replace the original, line-spanning comment ranges by new, only comment-prefix 112 // Replace the original, line-spanning comment ranges by new, only comment-prefix
139 // spanning comment ranges. 113 // spanning comment ranges.
140 let mut new_comments = Vec::new(); 114 let mut new_comments = Vec::new();
141 let mut intra_doc_links = Vec::new();
142 let mut string; 115 let mut string;
116
117 if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
118 extract_definitions_from_markdown(docs.as_str())
119 .into_iter()
120 .filter_map(|(range, link, ns)| {
121 let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?;
122 let InFile { file_id, value: range } = doc_mapping.map(range)?;
123 (file_id == node.file_id).then(|| (range, def))
124 })
125 .for_each(|(range, def)| {
126 hl.add(HlRange {
127 range,
128 highlight: module_def_to_hl_tag(def)
129 | HlMod::Documentation
130 | HlMod::Injected
131 | HlMod::IntraDocLink,
132 binding_hash: None,
133 })
134 });
135 }
136
143 for attr in attributes.by_key("doc").attrs() { 137 for attr in attributes.by_key("doc").attrs() {
144 let InFile { file_id, value: src } = attrs_source_map.source_of(&attr); 138 let InFile { file_id, value: src } = attrs_source_map.source_of(&attr);
145 if file_id != node.file_id { 139 if file_id != node.file_id {
@@ -185,25 +179,7 @@ pub(super) fn doc_comment(
185 is_doctest = is_codeblock && is_rust; 179 is_doctest = is_codeblock && is_rust;
186 continue; 180 continue;
187 } 181 }
188 None if !is_doctest => { 182 None if !is_doctest => continue,
189 intra_doc_links.extend(
190 extract_definitions_from_markdown(line)
191 .into_iter()
192 .filter_map(|(range, link, ns)| {
193 Some(range).zip(validate_intra_doc_link(sema.db, &def, &link, ns))
194 })
195 .map(|(Range { start, end }, def)| {
196 (
197 def,
198 TextRange::at(
199 prev_range_start + TextSize::from(start as u32),
200 TextSize::from((end - start) as u32),
201 ),
202 )
203 }),
204 );
205 continue;
206 }
207 None => (), 183 None => (),
208 } 184 }
209 185
@@ -222,17 +198,6 @@ pub(super) fn doc_comment(
222 } 198 }
223 } 199 }
224 200
225 for (def, range) in intra_doc_links {
226 hl.add(HlRange {
227 range,
228 highlight: module_def_to_hl_tag(def)
229 | HlMod::Documentation
230 | HlMod::Injected
231 | HlMod::IntraDocLink,
232 binding_hash: None,
233 });
234 }
235
236 if new_comments.is_empty() { 201 if new_comments.is_empty() {
237 return; // no need to run an analysis on an empty file 202 return; // no need to run an analysis on an empty file
238 } 203 }
@@ -283,33 +248,6 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri
283 } 248 }
284} 249}
285 250
286fn validate_intra_doc_link(
287 db: &RootDatabase,
288 def: &Definition,
289 link: &str,
290 ns: Option<hir::Namespace>,
291) -> Option<hir::ModuleDef> {
292 match def {
293 Definition::ModuleDef(def) => match def {
294 hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns),
295 hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns),
296 hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns),
297 hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns),
298 hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns),
299 hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns),
300 hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns),
301 hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns),
302 hir::ModuleDef::BuiltinType(_) => None,
303 },
304 Definition::Macro(it) => it.resolve_doc_path(db, &link, ns),
305 Definition::Field(it) => it.resolve_doc_path(db, &link, ns),
306 Definition::SelfType(_)
307 | Definition::Local(_)
308 | Definition::GenericParam(_)
309 | Definition::Label(_) => None,
310 }
311}
312
313fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag { 251fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag {
314 let symbol = match def { 252 let symbol = match def {
315 hir::ModuleDef::Module(_) => SymbolKind::Module, 253 hir::ModuleDef::Module(_) => SymbolKind::Module,
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 93db79b89..8128d231d 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -28,7 +28,7 @@ pub enum HlTag {
28 FormatSpecifier, 28 FormatSpecifier,
29 Keyword, 29 Keyword,
30 NumericLiteral, 30 NumericLiteral,
31 Operator, 31 Operator(HlOperator),
32 Punctuation(HlPunct), 32 Punctuation(HlPunct),
33 StringLiteral, 33 StringLiteral,
34 UnresolvedReference, 34 UnresolvedReference,
@@ -58,6 +58,8 @@ pub enum HlMod {
58 Associated, 58 Associated,
59 /// Used for intra doc links in doc injection. 59 /// Used for intra doc links in doc injection.
60 IntraDocLink, 60 IntraDocLink,
61 /// Used for items in traits and trait impls.
62 Trait,
61 63
62 /// Keep this last! 64 /// Keep this last!
63 Unsafe, 65 Unsafe,
@@ -85,6 +87,20 @@ pub enum HlPunct {
85 Other, 87 Other,
86} 88}
87 89
90#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
91pub enum HlOperator {
92 /// |, &, !, ^, |=, &=, ^=
93 Bitwise,
94 /// +, -, *, /, +=, -=, *=, /=
95 Arithmetic,
96 /// &&, ||, !
97 Logical,
98 /// >, <, ==, >=, <=, !=
99 Comparision,
100 ///
101 Other,
102}
103
88impl HlTag { 104impl HlTag {
89 fn as_str(self) -> &'static str { 105 fn as_str(self) -> &'static str {
90 match self { 106 match self {
@@ -131,7 +147,13 @@ impl HlTag {
131 HlPunct::Other => "punctuation", 147 HlPunct::Other => "punctuation",
132 }, 148 },
133 HlTag::NumericLiteral => "numeric_literal", 149 HlTag::NumericLiteral => "numeric_literal",
134 HlTag::Operator => "operator", 150 HlTag::Operator(op) => match op {
151 HlOperator::Bitwise => "bitwise",
152 HlOperator::Arithmetic => "arithmetic",
153 HlOperator::Logical => "logical",
154 HlOperator::Comparision => "comparision",
155 HlOperator::Other => "operator",
156 },
135 HlTag::StringLiteral => "string_literal", 157 HlTag::StringLiteral => "string_literal",
136 HlTag::UnresolvedReference => "unresolved_reference", 158 HlTag::UnresolvedReference => "unresolved_reference",
137 HlTag::None => "none", 159 HlTag::None => "none",
@@ -158,6 +180,7 @@ impl HlMod {
158 HlMod::Callable, 180 HlMod::Callable,
159 HlMod::Static, 181 HlMod::Static,
160 HlMod::Associated, 182 HlMod::Associated,
183 HlMod::Trait,
161 HlMod::Unsafe, 184 HlMod::Unsafe,
162 ]; 185 ];
163 186
@@ -174,6 +197,7 @@ impl HlMod {
174 HlMod::IntraDocLink => "intra_doc_link", 197 HlMod::IntraDocLink => "intra_doc_link",
175 HlMod::Mutable => "mutable", 198 HlMod::Mutable => "mutable",
176 HlMod::Static => "static", 199 HlMod::Static => "static",
200 HlMod::Trait => "trait",
177 HlMod::Unsafe => "unsafe", 201 HlMod::Unsafe => "unsafe",
178 } 202 }
179 } 203 }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 4635ea927..8cde3906c 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -47,12 +47,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
47<span class="brace">}</span> 47<span class="brace">}</span>
48 48
49<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> 49<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span>
50 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 50 <span class="keyword">fn</span> <span class="function declaration static associated trait">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
51 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 51 <span class="keyword">fn</span> <span class="function declaration associated trait">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
52<span class="brace">}</span> 52<span class="brace">}</span>
53 53
54<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> 54<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span>
55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated trait">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
56 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 56 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated trait">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
57<span class="brace">}</span> 57<span class="brace">}</span>
58 </code></pre> \ No newline at end of file 58 </code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 045162eb8..6ee6d85fb 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -76,7 +76,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
76 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> 76 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span>
77 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> 77 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
78 <span class="comment documentation">///</span> 78 <span class="comment documentation">///</span>
79 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="operator injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span> 79 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="logical injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span>
80 <span class="comment documentation">///</span> 80 <span class="comment documentation">///</span>
81 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span> 81 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span>
82 <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> 82 <span class="comment documentation">/// </span><span class="comment injected"> comment */</span>
@@ -100,10 +100,18 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
100<span class="brace">}</span> 100<span class="brace">}</span>
101 101
102<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span> 102<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span>
103<span class="comment documentation">/// </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span> 103<span class="comment documentation">/// This function is &gt; </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> &lt;</span>
104<span class="comment documentation">/// [`noop`](noop) is a macro below</span> 104<span class="comment documentation">/// [`noop`](noop) is a macro below</span>
105<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Item`]</span><span class="comment documentation"> is a struct in the module </span><span class="module documentation intra_doc_link injected">[`module`]</span>
106<span class="comment documentation">///</span>
107<span class="comment documentation">/// [`Item`]: module::Item</span>
108<span class="comment documentation">/// [mix_and_match]: ThisShouldntResolve</span>
105<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 109<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
106 110
111<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">module</span> <span class="brace">{</span>
112 <span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration">Item</span><span class="semicolon">;</span>
113<span class="brace">}</span>
114
107<span class="comment documentation">/// ```</span> 115<span class="comment documentation">/// ```</span>
108<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> 116<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
109<span class="comment documentation">/// ```</span> 117<span class="comment documentation">/// ```</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 9215ddd9e..7c6694a27 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -42,7 +42,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
42<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 42<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
43 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> 43 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
44 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> 44 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span>
45 <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 45 <span class="keyword">fn</span> <span class="function declaration static associated trait">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
46 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> 46 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span>
47 <span class="brace">}</span> 47 <span class="brace">}</span>
48 <span class="brace">}</span><span class="string_literal">"#</span> 48 <span class="brace">}</span><span class="string_literal">"#</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 6a6555208..72910421d 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -62,11 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
62<span class="brace">}</span> 62<span class="brace">}</span>
63 63
64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> 64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
65 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> 65 <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
66<span class="brace">}</span> 66<span class="brace">}</span>
67 67
68<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> 68<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
69 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 69 <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
70<span class="brace">}</span> 70<span class="brace">}</span>
71 71
72<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 72<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
@@ -96,6 +96,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
96 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> 96 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
97 97
98 <span class="comment">// unsafe auto ref of packed field</span> 98 <span class="comment">// unsafe auto ref of packed field</span>
99 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> 99 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
100 <span class="brace">}</span> 100 <span class="brace">}</span>
101<span class="brace">}</span></code></pre> \ No newline at end of file 101<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 1eaa7b75b..c43bcb691 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -67,11 +67,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
67<span class="brace">}</span> 67<span class="brace">}</span>
68 68
69<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> 69<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
70 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span> 70 <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
71<span class="brace">}</span> 71<span class="brace">}</span>
72 72
73<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> 73<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
74 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 74 <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
75 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 75 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
76 <span class="brace">}</span> 76 <span class="brace">}</span>
77<span class="brace">}</span> 77<span class="brace">}</span>
@@ -213,7 +213,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
213 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> 213 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span>
214 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> 214 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span>
215 215
216 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> 216 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
217 217
218 <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span> 218 <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span>
219 <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span> 219 <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 369ae0972..933cfa6f3 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,6 +1,8 @@
1use std::time::Instant;
2
1use expect_test::{expect_file, ExpectFile}; 3use expect_test::{expect_file, ExpectFile};
2use ide_db::SymbolKind; 4use ide_db::SymbolKind;
3use test_utils::{bench, bench_fixture, skip_slow_tests}; 5use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear};
4 6
5use crate::{fixture, FileRange, HlTag, TextRange}; 7use crate::{fixture, FileRange, HlTag, TextRange};
6 8
@@ -258,6 +260,36 @@ fn benchmark_syntax_highlighting_long_struct() {
258} 260}
259 261
260#[test] 262#[test]
263fn syntax_highlighting_not_quadratic() {
264 if skip_slow_tests() {
265 return;
266 }
267
268 let mut al = AssertLinear::default();
269 while al.next_round() {
270 for i in 6..=10 {
271 let n = 1 << i;
272
273 let fixture = bench_fixture::big_struct_n(n);
274 let (analysis, file_id) = fixture::file(&fixture);
275
276 let time = Instant::now();
277
278 let hash = analysis
279 .highlight(file_id)
280 .unwrap()
281 .iter()
282 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
283 .count();
284 assert!(hash > n as usize);
285
286 let elapsed = time.elapsed();
287 al.sample(n as f64, elapsed.as_millis() as f64);
288 }
289 }
290}
291
292#[test]
261fn benchmark_syntax_highlighting_parser() { 293fn benchmark_syntax_highlighting_parser() {
262 if skip_slow_tests() { 294 if skip_slow_tests() {
263 return; 295 return;
@@ -544,10 +576,18 @@ impl Foo {
544} 576}
545 577
546/// [`Foo`](Foo) is a struct 578/// [`Foo`](Foo) is a struct
547/// [`all_the_links`](all_the_links) is this function 579/// This function is > [`all_the_links`](all_the_links) <
548/// [`noop`](noop) is a macro below 580/// [`noop`](noop) is a macro below
581/// [`Item`] is a struct in the module [`module`]
582///
583/// [`Item`]: module::Item
584/// [mix_and_match]: ThisShouldntResolve
549pub fn all_the_links() {} 585pub fn all_the_links() {}
550 586
587pub mod module {
588 pub struct Item;
589}
590
551/// ``` 591/// ```
552/// noop!(1); 592/// noop!(1);
553/// ``` 593/// ```