1 extern crate rustc_ast;
2 extern crate rustc_data_structures;
3 extern crate rustc_span;
4 
5 use rustc_ast::ast::{
6     AngleBracketedArg, AngleBracketedArgs, AnonConst, Arm, AssocItemKind, AssocTyConstraint,
7     AssocTyConstraintKind, Async, AttrId, AttrItem, AttrKind, AttrStyle, Attribute, BareFnTy,
8     BinOpKind, BindingMode, Block, BlockCheckMode, BorrowKind, CaptureBy, Const, Crate, CrateSugar,
9     Defaultness, EnumDef, Expr, ExprKind, Extern, Field, FieldPat, FloatTy, FnDecl, FnHeader,
10     FnRetTy, FnSig, ForeignItemKind, ForeignMod, GenericArg, GenericArgs, GenericBound,
11     GenericParam, GenericParamKind, Generics, GlobalAsm, ImplPolarity, InlineAsm, InlineAsmOperand,
12     InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, IntTy, IsAuto, Item,
13     ItemKind, Label, Lifetime, Lit, LitFloatType, LitIntType, LitKind, LlvmAsmDialect,
14     LlvmInlineAsm, LlvmInlineAsmOutput, Local, MacArgs, MacCall, MacCallStmt, MacDelimiter,
15     MacStmtStyle, MacroDef, Mod, Movability, MutTy, Mutability, NodeId, Param, ParenthesizedArgs,
16     Pat, PatKind, Path, PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt,
17     StmtKind, StrLit, StrStyle, StructField, StructRest, TraitBoundModifier, TraitObjectSyntax,
18     TraitRef, Ty, TyKind, UintTy, UnOp, Unsafe, UnsafeSource, UseTree, UseTreeKind, Variant,
19     VariantData, Visibility, VisibilityKind, WhereBoundPredicate, WhereClause, WhereEqPredicate,
20     WherePredicate, WhereRegionPredicate,
21 };
22 use rustc_ast::ptr::P;
23 use rustc_ast::token::{self, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
24 use rustc_ast::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
25 use rustc_data_structures::sync::Lrc;
26 use rustc_data_structures::thin_vec::ThinVec;
27 use rustc_span::source_map::Spanned;
28 use rustc_span::symbol::{sym, Ident};
29 use rustc_span::{Span, Symbol, SyntaxContext, DUMMY_SP};
30 
31 pub trait SpanlessEq {
eq(&self, other: &Self) -> bool32     fn eq(&self, other: &Self) -> bool;
33 }
34 
35 impl<T: SpanlessEq> SpanlessEq for P<T> {
eq(&self, other: &Self) -> bool36     fn eq(&self, other: &Self) -> bool {
37         SpanlessEq::eq(&**self, &**other)
38     }
39 }
40 
41 impl<T: ?Sized + SpanlessEq> SpanlessEq for Lrc<T> {
eq(&self, other: &Self) -> bool42     fn eq(&self, other: &Self) -> bool {
43         SpanlessEq::eq(&**self, &**other)
44     }
45 }
46 
47 impl<T: SpanlessEq> SpanlessEq for Option<T> {
eq(&self, other: &Self) -> bool48     fn eq(&self, other: &Self) -> bool {
49         match (self, other) {
50             (None, None) => true,
51             (Some(this), Some(other)) => SpanlessEq::eq(this, other),
52             _ => false,
53         }
54     }
55 }
56 
57 impl<T: SpanlessEq> SpanlessEq for [T] {
eq(&self, other: &Self) -> bool58     fn eq(&self, other: &Self) -> bool {
59         self.len() == other.len() && self.iter().zip(other).all(|(a, b)| SpanlessEq::eq(a, b))
60     }
61 }
62 
63 impl<T: SpanlessEq> SpanlessEq for Vec<T> {
eq(&self, other: &Self) -> bool64     fn eq(&self, other: &Self) -> bool {
65         <[T] as SpanlessEq>::eq(self, other)
66     }
67 }
68 
69 impl<T: SpanlessEq> SpanlessEq for ThinVec<T> {
eq(&self, other: &Self) -> bool70     fn eq(&self, other: &Self) -> bool {
71         self.len() == other.len()
72             && self
73                 .iter()
74                 .zip(other.iter())
75                 .all(|(a, b)| SpanlessEq::eq(a, b))
76     }
77 }
78 
79 impl<T: SpanlessEq> SpanlessEq for Spanned<T> {
eq(&self, other: &Self) -> bool80     fn eq(&self, other: &Self) -> bool {
81         SpanlessEq::eq(&self.node, &other.node)
82     }
83 }
84 
85 impl<A: SpanlessEq, B: SpanlessEq> SpanlessEq for (A, B) {
eq(&self, other: &Self) -> bool86     fn eq(&self, other: &Self) -> bool {
87         SpanlessEq::eq(&self.0, &other.0) && SpanlessEq::eq(&self.1, &other.1)
88     }
89 }
90 
91 macro_rules! spanless_eq_true {
92     ($name:ty) => {
93         impl SpanlessEq for $name {
94             fn eq(&self, _other: &Self) -> bool {
95                 true
96             }
97         }
98     };
99 }
100 
101 spanless_eq_true!(Span);
102 spanless_eq_true!(DelimSpan);
103 spanless_eq_true!(AttrId);
104 spanless_eq_true!(NodeId);
105 spanless_eq_true!(SyntaxContext);
106 
107 macro_rules! spanless_eq_partial_eq {
108     ($name:ty) => {
109         impl SpanlessEq for $name {
110             fn eq(&self, other: &Self) -> bool {
111                 PartialEq::eq(self, other)
112             }
113         }
114     };
115 }
116 
117 spanless_eq_partial_eq!(bool);
118 spanless_eq_partial_eq!(u8);
119 spanless_eq_partial_eq!(u16);
120 spanless_eq_partial_eq!(u128);
121 spanless_eq_partial_eq!(usize);
122 spanless_eq_partial_eq!(char);
123 spanless_eq_partial_eq!(String);
124 spanless_eq_partial_eq!(Symbol);
125 spanless_eq_partial_eq!(CommentKind);
126 spanless_eq_partial_eq!(DelimToken);
127 spanless_eq_partial_eq!(InlineAsmOptions);
128 spanless_eq_partial_eq!(token::LitKind);
129 
130 macro_rules! spanless_eq_struct {
131     {
132         $($name:ident)::+ $(<$param:ident>)?;
133         $([$field:ident $other:ident])*
134         $(![$ignore:ident])*
135     } => {
136         impl $(<$param: SpanlessEq>)* SpanlessEq for $($name)::+ $(<$param>)* {
137             fn eq(&self, other: &Self) -> bool {
138                 let $($name)::+ { $($field,)* $($ignore: _,)* } = self;
139                 let $($name)::+ { $($field: $other,)* $($ignore: _,)* } = other;
140                 true $(&& SpanlessEq::eq($field, $other))*
141             }
142         }
143     };
144 
145     {
146         $($name:ident)::+ $(<$param:ident>)?;
147         $([$field:ident $other:ident])*
148         $(![$ignore:ident])*
149         $next:ident
150         $($rest:tt)*
151     } => {
152         spanless_eq_struct! {
153             $($name)::+ $(<$param>)*;
154             $([$field $other])*
155             [$next other]
156             $(![$ignore])*
157             $($rest)*
158         }
159     };
160 
161     {
162         $($name:ident)::+ $(<$param:ident>)?;
163         $([$field:ident $other:ident])*
164         $(![$ignore:ident])*
165         !$next:ident
166         $($rest:tt)*
167     } => {
168         spanless_eq_struct! {
169             $($name)::+ $(<$param>)*;
170             $([$field $other])*
171             $(![$ignore])*
172             ![$next]
173             $($rest)*
174         }
175     };
176 }
177 
178 macro_rules! spanless_eq_enum {
179     {
180         $($name:ident)::+;
181         $([$($variant:ident)::+; $([$field:tt $this:ident $other:ident])* $(![$ignore:tt])*])*
182     } => {
183         impl SpanlessEq for $($name)::+ {
184             fn eq(&self, other: &Self) -> bool {
185                 match self {
186                     $(
187                         $($variant)::+ { .. } => {}
188                     )*
189                 }
190                 #[allow(unreachable_patterns)]
191                 match (self, other) {
192                     $(
193                         (
194                             $($variant)::+ { $($field: $this,)* $($ignore: _,)* },
195                             $($variant)::+ { $($field: $other,)* $($ignore: _,)* },
196                         ) => {
197                             true $(&& SpanlessEq::eq($this, $other))*
198                         }
199                     )*
200                     _ => false,
201                 }
202             }
203         }
204     };
205 
206     {
207         $($name:ident)::+;
208         $([$($variant:ident)::+; $($fields:tt)*])*
209         $next:ident [$([$($named:tt)*])* $(![$ignore:tt])*] (!$i:tt $($field:tt)*)
210         $($rest:tt)*
211     } => {
212         spanless_eq_enum! {
213             $($name)::+;
214             $([$($variant)::+; $($fields)*])*
215             $next [$([$($named)*])* $(![$ignore])* ![$i]] ($($field)*)
216             $($rest)*
217         }
218     };
219 
220     {
221         $($name:ident)::+;
222         $([$($variant:ident)::+; $($fields:tt)*])*
223         $next:ident [$([$($named:tt)*])* $(![$ignore:tt])*] ($i:tt $($field:tt)*)
224         $($rest:tt)*
225     } => {
226         spanless_eq_enum! {
227             $($name)::+;
228             $([$($variant)::+; $($fields)*])*
229             $next [$([$($named)*])* [$i this other] $(![$ignore])*] ($($field)*)
230             $($rest)*
231         }
232     };
233 
234     {
235         $($name:ident)::+;
236         $([$($variant:ident)::+; $($fields:tt)*])*
237         $next:ident [$($named:tt)*] ()
238         $($rest:tt)*
239     } => {
240         spanless_eq_enum! {
241             $($name)::+;
242             $([$($variant)::+; $($fields)*])*
243             [$($name)::+::$next; $($named)*]
244             $($rest)*
245         }
246     };
247 
248     {
249         $($name:ident)::+;
250         $([$($variant:ident)::+; $($fields:tt)*])*
251         $next:ident ($($field:tt)*)
252         $($rest:tt)*
253     } => {
254         spanless_eq_enum! {
255             $($name)::+;
256             $([$($variant)::+; $($fields)*])*
257             $next [] ($($field)*)
258             $($rest)*
259         }
260     };
261 
262     {
263         $($name:ident)::+;
264         $([$($variant:ident)::+; $($fields:tt)*])*
265         $next:ident
266         $($rest:tt)*
267     } => {
268         spanless_eq_enum! {
269             $($name)::+;
270             $([$($variant)::+; $($fields)*])*
271             [$($name)::+::$next;]
272             $($rest)*
273         }
274     };
275 }
276 
277 spanless_eq_struct!(AngleBracketedArgs; span args);
278 spanless_eq_struct!(AnonConst; id value);
279 spanless_eq_struct!(Arm; attrs pat guard body span id is_placeholder);
280 spanless_eq_struct!(AssocTyConstraint; id ident gen_args kind span);
281 spanless_eq_struct!(AttrItem; path args tokens);
282 spanless_eq_struct!(Attribute; kind id style span);
283 spanless_eq_struct!(BareFnTy; unsafety ext generic_params decl);
284 spanless_eq_struct!(Block; stmts id rules span tokens);
285 spanless_eq_struct!(Crate; module attrs span proc_macros);
286 spanless_eq_struct!(EnumDef; variants);
287 spanless_eq_struct!(Expr; id kind span attrs !tokens);
288 spanless_eq_struct!(Field; attrs id span ident expr is_shorthand is_placeholder);
289 spanless_eq_struct!(FieldPat; ident pat is_shorthand attrs id span is_placeholder);
290 spanless_eq_struct!(FnDecl; inputs output);
291 spanless_eq_struct!(FnHeader; constness asyncness unsafety ext);
292 spanless_eq_struct!(FnSig; header decl span);
293 spanless_eq_struct!(ForeignMod; unsafety abi items);
294 spanless_eq_struct!(GenericParam; id ident attrs bounds is_placeholder kind);
295 spanless_eq_struct!(Generics; params where_clause span);
296 spanless_eq_struct!(GlobalAsm; asm);
297 spanless_eq_struct!(InlineAsm; template operands options line_spans);
298 spanless_eq_struct!(Item<K>; attrs id span vis ident kind !tokens);
299 spanless_eq_struct!(Label; ident);
300 spanless_eq_struct!(Lifetime; id ident);
301 spanless_eq_struct!(Lit; token kind span);
302 spanless_eq_struct!(LlvmInlineAsm; asm asm_str_style outputs inputs clobbers volatile alignstack dialect);
303 spanless_eq_struct!(LlvmInlineAsmOutput; constraint expr is_rw is_indirect);
304 spanless_eq_struct!(Local; pat ty init id span attrs !tokens);
305 spanless_eq_struct!(MacCall; path args prior_type_ascription);
306 spanless_eq_struct!(MacCallStmt; mac style attrs tokens);
307 spanless_eq_struct!(MacroDef; body macro_rules);
308 spanless_eq_struct!(Mod; inner unsafety items inline);
309 spanless_eq_struct!(MutTy; ty mutbl);
310 spanless_eq_struct!(ParenthesizedArgs; span inputs inputs_span output);
311 spanless_eq_struct!(Pat; id kind span tokens);
312 spanless_eq_struct!(Path; span segments tokens);
313 spanless_eq_struct!(PathSegment; ident id args);
314 spanless_eq_struct!(PolyTraitRef; bound_generic_params trait_ref span);
315 spanless_eq_struct!(QSelf; ty path_span position);
316 spanless_eq_struct!(Stmt; id kind span);
317 spanless_eq_struct!(StrLit; style symbol suffix span symbol_unescaped);
318 spanless_eq_struct!(StructField; attrs id span vis ident ty is_placeholder);
319 spanless_eq_struct!(Token; kind span);
320 spanless_eq_struct!(TraitRef; path ref_id);
321 spanless_eq_struct!(Ty; id kind span tokens);
322 spanless_eq_struct!(UseTree; prefix kind span);
323 spanless_eq_struct!(Variant; attrs id span !vis ident data disr_expr is_placeholder);
324 spanless_eq_struct!(Visibility; kind span tokens);
325 spanless_eq_struct!(WhereBoundPredicate; span bound_generic_params bounded_ty bounds);
326 spanless_eq_struct!(WhereClause; has_where_token predicates span);
327 spanless_eq_struct!(WhereEqPredicate; id span lhs_ty rhs_ty);
328 spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds);
329 spanless_eq_struct!(token::Lit; kind symbol suffix);
330 spanless_eq_enum!(AngleBracketedArg; Arg(0) Constraint(0));
331 spanless_eq_enum!(AssocItemKind; Const(0 1 2) Fn(0 1 2 3) TyAlias(0 1 2 3) MacCall(0));
332 spanless_eq_enum!(AssocTyConstraintKind; Equality(ty) Bound(bounds));
333 spanless_eq_enum!(Async; Yes(span closure_id return_impl_trait_id) No);
334 spanless_eq_enum!(AttrStyle; Outer Inner);
335 spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt);
336 spanless_eq_enum!(BindingMode; ByRef(0) ByValue(0));
337 spanless_eq_enum!(BlockCheckMode; Default Unsafe(0));
338 spanless_eq_enum!(BorrowKind; Ref Raw);
339 spanless_eq_enum!(CaptureBy; Value Ref);
340 spanless_eq_enum!(Const; Yes(0) No);
341 spanless_eq_enum!(CrateSugar; PubCrate JustCrate);
342 spanless_eq_enum!(Defaultness; Default(0) Final);
343 spanless_eq_enum!(Extern; None Implicit Explicit(0));
344 spanless_eq_enum!(FloatTy; F32 F64);
345 spanless_eq_enum!(FnRetTy; Default(0) Ty(0));
346 spanless_eq_enum!(ForeignItemKind; Static(0 1 2) Fn(0 1 2 3) TyAlias(0 1 2 3) MacCall(0));
347 spanless_eq_enum!(GenericArg; Lifetime(0) Type(0) Const(0));
348 spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0));
349 spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0));
350 spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty kw_span default));
351 spanless_eq_enum!(ImplPolarity; Positive Negative(0));
352 spanless_eq_enum!(InlineAsmRegOrRegClass; Reg(0) RegClass(0));
353 spanless_eq_enum!(InlineAsmTemplatePiece; String(0) Placeholder(operand_idx modifier span));
354 spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128);
355 spanless_eq_enum!(IsAuto; Yes No);
356 spanless_eq_enum!(LitFloatType; Suffixed(0) Unsuffixed);
357 spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed);
358 spanless_eq_enum!(LlvmAsmDialect; Att Intel);
359 spanless_eq_enum!(MacArgs; Empty Delimited(0 1 2) Eq(0 1));
360 spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace);
361 spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces);
362 spanless_eq_enum!(Movability; Static Movable);
363 spanless_eq_enum!(Mutability; Mut Not);
364 spanless_eq_enum!(RangeEnd; Included(0) Excluded);
365 spanless_eq_enum!(RangeLimits; HalfOpen Closed);
366 spanless_eq_enum!(StmtKind; Local(0) Item(0) Expr(0) Semi(0) Empty MacCall(0));
367 spanless_eq_enum!(StrStyle; Cooked Raw(0));
368 spanless_eq_enum!(StructRest; Base(0) Rest(0) None);
369 spanless_eq_enum!(TokenTree; Token(0) Delimited(0 1 2));
370 spanless_eq_enum!(TraitBoundModifier; None Maybe MaybeConst MaybeConstMaybe);
371 spanless_eq_enum!(TraitObjectSyntax; Dyn None);
372 spanless_eq_enum!(UintTy; Usize U8 U16 U32 U64 U128);
373 spanless_eq_enum!(UnOp; Deref Not Neg);
374 spanless_eq_enum!(Unsafe; Yes(0) No);
375 spanless_eq_enum!(UnsafeSource; CompilerGenerated UserProvided);
376 spanless_eq_enum!(UseTreeKind; Simple(0 1 2) Nested(0) Glob);
377 spanless_eq_enum!(VariantData; Struct(0 1) Tuple(0 1) Unit(0));
378 spanless_eq_enum!(VisibilityKind; Public Crate(0) Restricted(path id) Inherited);
379 spanless_eq_enum!(WherePredicate; BoundPredicate(0) RegionPredicate(0) EqPredicate(0));
380 spanless_eq_enum!(ExprKind; Box(0) Array(0) ConstBlock(0) Call(0 1)
381     MethodCall(0 1 2) Tup(0) Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1)
382     Let(0 1) If(0 1 2) While(0 1 2) ForLoop(0 1 2 3) Loop(0 1) Match(0 1)
383     Closure(0 1 2 3 4 5) Block(0 1) Async(0 1 2) Await(0) TryBlock(0)
384     Assign(0 1 2) AssignOp(0 1 2) Field(0 1) Index(0 1) Underscore Range(0 1 2)
385     Path(0 1) AddrOf(0 1 2) Break(0 1) Continue(0) Ret(0) InlineAsm(0)
386     LlvmInlineAsm(0) MacCall(0) Struct(0 1 2) Repeat(0 1) Paren(0) Try(0)
387     Yield(0) Err);
388 spanless_eq_enum!(InlineAsmOperand; In(reg expr) Out(reg late expr)
389     InOut(reg late expr) SplitInOut(reg late in_expr out_expr) Const(expr)
390     Sym(expr));
391 spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1 2)
392     Fn(0 1 2 3) Mod(0) ForeignMod(0) GlobalAsm(0) TyAlias(0 1 2 3) Enum(0 1)
393     Struct(0 1) Union(0 1) Trait(0 1 2 3 4) TraitAlias(0 1)
394     Impl(unsafety polarity defaultness constness generics of_trait self_ty items)
395     MacCall(0) MacroDef(0));
396 spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0) Byte(0) Char(0) Int(0 1)
397     Float(0 1) Bool(0) Err(0));
398 spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2) TupleStruct(0 1)
399     Or(0) Path(0 1) Tuple(0) Box(0) Ref(0 1) Lit(0) Range(0 1 2) Slice(0) Rest
400     Paren(0) MacCall(0));
401 spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Rptr(0 1) BareFn(0) Never
402     Tup(0) Path(0 1) TraitObject(0 1) ImplTrait(0 1) Paren(0) Typeof(0) Infer
403     ImplicitSelf MacCall(0) Err CVarArgs);
404 
405 impl SpanlessEq for Ident {
eq(&self, other: &Self) -> bool406     fn eq(&self, other: &Self) -> bool {
407         self.as_str() == other.as_str()
408     }
409 }
410 
411 impl SpanlessEq for RangeSyntax {
eq(&self, _other: &Self) -> bool412     fn eq(&self, _other: &Self) -> bool {
413         match self {
414             RangeSyntax::DotDotDot | RangeSyntax::DotDotEq => true,
415         }
416     }
417 }
418 
419 impl SpanlessEq for Param {
eq(&self, other: &Self) -> bool420     fn eq(&self, other: &Self) -> bool {
421         let Param {
422             attrs,
423             ty,
424             pat,
425             id,
426             span: _,
427             is_placeholder,
428         } = self;
429         let Param {
430             attrs: attrs2,
431             ty: ty2,
432             pat: pat2,
433             id: id2,
434             span: _,
435             is_placeholder: is_placeholder2,
436         } = other;
437         SpanlessEq::eq(id, id2)
438             && SpanlessEq::eq(is_placeholder, is_placeholder2)
439             && (matches!(ty.kind, TyKind::Err)
440                 || matches!(ty2.kind, TyKind::Err)
441                 || SpanlessEq::eq(attrs, attrs2)
442                     && SpanlessEq::eq(ty, ty2)
443                     && SpanlessEq::eq(pat, pat2))
444     }
445 }
446 
447 impl SpanlessEq for TokenKind {
eq(&self, other: &Self) -> bool448     fn eq(&self, other: &Self) -> bool {
449         match (self, other) {
450             (TokenKind::Literal(this), TokenKind::Literal(other)) => SpanlessEq::eq(this, other),
451             (TokenKind::DotDotEq, _) | (TokenKind::DotDotDot, _) => match other {
452                 TokenKind::DotDotEq | TokenKind::DotDotDot => true,
453                 _ => false,
454             },
455             (TokenKind::Interpolated(this), TokenKind::Interpolated(other)) => {
456                 match (this.as_ref(), other.as_ref()) {
457                     (Nonterminal::NtExpr(this), Nonterminal::NtExpr(other)) => {
458                         SpanlessEq::eq(this, other)
459                     }
460                     _ => this == other,
461                 }
462             }
463             _ => self == other,
464         }
465     }
466 }
467 
468 impl SpanlessEq for TokenStream {
eq(&self, other: &Self) -> bool469     fn eq(&self, other: &Self) -> bool {
470         let mut this_trees = self.trees_ref();
471         let mut other_trees = other.trees_ref();
472         loop {
473             let this = match this_trees.next() {
474                 None => return other_trees.next().is_none(),
475                 Some(tree) => tree,
476             };
477             let other = match other_trees.next() {
478                 None => return false,
479                 Some(tree) => tree,
480             };
481             if SpanlessEq::eq(this, other) {
482                 continue;
483             }
484             if let (TokenTree::Token(this), TokenTree::Token(other)) = (this, other) {
485                 if match (&this.kind, &other.kind) {
486                     (TokenKind::Literal(this), TokenKind::Literal(other)) => {
487                         SpanlessEq::eq(this, other)
488                     }
489                     (TokenKind::DocComment(_kind, style, symbol), TokenKind::Pound) => {
490                         doc_comment(*style, *symbol, &mut other_trees)
491                     }
492                     (TokenKind::Pound, TokenKind::DocComment(_kind, style, symbol)) => {
493                         doc_comment(*style, *symbol, &mut this_trees)
494                     }
495                     _ => false,
496                 } {
497                     continue;
498                 }
499             }
500             return false;
501         }
502     }
503 }
504 
doc_comment<'a>( style: AttrStyle, unescaped: Symbol, trees: &mut impl Iterator<Item = &'a TokenTree>, ) -> bool505 fn doc_comment<'a>(
506     style: AttrStyle,
507     unescaped: Symbol,
508     trees: &mut impl Iterator<Item = &'a TokenTree>,
509 ) -> bool {
510     if match style {
511         AttrStyle::Outer => false,
512         AttrStyle::Inner => true,
513     } {
514         match trees.next() {
515             Some(TokenTree::Token(Token {
516                 kind: TokenKind::Not,
517                 span: _,
518             })) => {}
519             _ => return false,
520         }
521     }
522     let stream = match trees.next() {
523         Some(TokenTree::Delimited(_span, DelimToken::Bracket, stream)) => stream,
524         _ => return false,
525     };
526     let mut trees = stream.trees_ref();
527     match trees.next() {
528         Some(TokenTree::Token(Token {
529             kind: TokenKind::Ident(symbol, false),
530             span: _,
531         })) if *symbol == sym::doc => {}
532         _ => return false,
533     }
534     match trees.next() {
535         Some(TokenTree::Token(Token {
536             kind: TokenKind::Eq,
537             span: _,
538         })) => {}
539         _ => return false,
540     }
541     match trees.next() {
542         Some(TokenTree::Token(token)) => {
543             is_escaped_literal(token, unescaped) && trees.next().is_none()
544         }
545         _ => false,
546     }
547 }
548 
is_escaped_literal(token: &Token, unescaped: Symbol) -> bool549 fn is_escaped_literal(token: &Token, unescaped: Symbol) -> bool {
550     match match token {
551         Token {
552             kind: TokenKind::Literal(lit),
553             span: _,
554         } => Lit::from_lit_token(*lit, DUMMY_SP),
555         Token {
556             kind: TokenKind::Interpolated(nonterminal),
557             span: _,
558         } => match nonterminal.as_ref() {
559             Nonterminal::NtExpr(expr) => match &expr.kind {
560                 ExprKind::Lit(lit) => Ok(lit.clone()),
561                 _ => return false,
562             },
563             _ => return false,
564         },
565         _ => return false,
566     } {
567         Ok(Lit {
568             token:
569                 token::Lit {
570                     kind: token::LitKind::Str,
571                     symbol: _,
572                     suffix: None,
573                 },
574             kind: LitKind::Str(symbol, StrStyle::Cooked),
575             span: _,
576         }) => symbol.as_str().replace('\r', "") == unescaped.as_str().replace('\r', ""),
577         _ => false,
578     }
579 }
580 
581 impl SpanlessEq for LazyTokenStream {
eq(&self, other: &Self) -> bool582     fn eq(&self, other: &Self) -> bool {
583         let this = self.create_token_stream();
584         let other = other.create_token_stream();
585         SpanlessEq::eq(&this, &other)
586     }
587 }
588 
589 impl SpanlessEq for AttrKind {
eq(&self, other: &Self) -> bool590     fn eq(&self, other: &Self) -> bool {
591         match (self, other) {
592             (AttrKind::Normal(item, tokens), AttrKind::Normal(item2, tokens2)) => {
593                 SpanlessEq::eq(item, item2) && SpanlessEq::eq(tokens, tokens2)
594             }
595             (AttrKind::DocComment(kind, symbol), AttrKind::DocComment(kind2, symbol2)) => {
596                 SpanlessEq::eq(kind, kind2) && SpanlessEq::eq(symbol, symbol2)
597             }
598             (AttrKind::DocComment(kind, unescaped), AttrKind::Normal(item2, _tokens)) => {
599                 match kind {
600                     CommentKind::Line | CommentKind::Block => {}
601                 }
602                 let path = Path::from_ident(Ident::with_dummy_span(sym::doc));
603                 SpanlessEq::eq(&path, &item2.path)
604                     && match &item2.args {
605                         MacArgs::Empty | MacArgs::Delimited(..) => false,
606                         MacArgs::Eq(_span, token) => is_escaped_literal(token, *unescaped),
607                     }
608             }
609             (AttrKind::Normal(..), AttrKind::DocComment(..)) => SpanlessEq::eq(other, self),
610         }
611     }
612 }
613