David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 1 | extern crate rustc_data_structures; |
| 2 | extern crate rustc_target; |
| 3 | extern crate syntax; |
| 4 | extern crate syntax_pos; |
| 5 | |
| 6 | use std::mem; |
| 7 | |
| 8 | use self::rustc_data_structures::sync::Lrc; |
David Tolnay | c865992 | 2018-08-14 22:40:50 -0700 | [diff] [blame] | 9 | use self::rustc_data_structures::thin_vec::ThinVec; |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 10 | use self::rustc_target::abi::FloatTy; |
| 11 | use self::rustc_target::spec::abi::Abi; |
| 12 | use self::syntax::ast::{ |
| 13 | AngleBracketedArgs, AnonConst, Arg, Arm, AsmDialect, AttrId, AttrStyle, Attribute, BareFnTy, |
| 14 | BinOpKind, BindingMode, Block, BlockCheckMode, CaptureBy, Constness, Crate, CrateSugar, |
| 15 | Defaultness, EnumDef, Expr, ExprKind, Field, FieldPat, FnDecl, FnHeader, ForeignItem, |
| 16 | ForeignItemKind, ForeignMod, FunctionRetTy, GenericArg, GenericArgs, GenericBound, |
| 17 | GenericParam, GenericParamKind, Generics, GlobalAsm, Ident, ImplItem, ImplItemKind, |
| 18 | ImplPolarity, InlineAsm, InlineAsmOutput, IntTy, IsAsync, IsAuto, Item, ItemKind, Label, |
| 19 | Lifetime, LitIntType, LitKind, Local, MacDelimiter, MacStmtStyle, Mac_, MacroDef, MethodSig, |
| 20 | Mod, Movability, MutTy, Mutability, NodeId, ParenthesisedArgs, Pat, PatKind, Path, PathSegment, |
| 21 | PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind, StrStyle, StructField, |
| 22 | TraitBoundModifier, TraitItem, TraitItemKind, TraitObjectSyntax, TraitRef, Ty, TyKind, |
| 23 | TypeBinding, UintTy, UnOp, UnsafeSource, Unsafety, UseTree, UseTreeKind, VariantData, Variant_, |
| 24 | VisibilityKind, WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate, |
| 25 | WhereRegionPredicate, |
| 26 | }; |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 27 | use self::syntax::parse::lexer::comments; |
| 28 | use self::syntax::parse::token::{DelimToken, Lit, Token}; |
| 29 | use self::syntax::ptr::P; |
David Tolnay | d1c31cc | 2018-08-24 14:47:15 -0400 | [diff] [blame] | 30 | use self::syntax::source_map::Spanned; |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 31 | use self::syntax::symbol::Symbol; |
| 32 | use self::syntax::tokenstream::{Delimited, ThinTokenStream, TokenStream, TokenTree}; |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 33 | use self::syntax_pos::{Span, SyntaxContext, DUMMY_SP}; |
| 34 | |
| 35 | pub trait SpanlessEq { |
| 36 | fn eq(&self, other: &Self) -> bool; |
| 37 | } |
| 38 | |
| 39 | impl<T: SpanlessEq> SpanlessEq for P<T> { |
| 40 | fn eq(&self, other: &Self) -> bool { |
| 41 | SpanlessEq::eq(&**self, &**other) |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | impl<T: SpanlessEq> SpanlessEq for Lrc<T> { |
| 46 | fn eq(&self, other: &Self) -> bool { |
| 47 | SpanlessEq::eq(&**self, &**other) |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | impl<T: SpanlessEq> SpanlessEq for Option<T> { |
| 52 | fn eq(&self, other: &Self) -> bool { |
| 53 | match (self, other) { |
| 54 | (None, None) => true, |
| 55 | (Some(this), Some(other)) => SpanlessEq::eq(this, other), |
| 56 | _ => false, |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | impl<T: SpanlessEq> SpanlessEq for Vec<T> { |
| 62 | fn eq(&self, other: &Self) -> bool { |
| 63 | self.len() == other.len() && self.iter().zip(other).all(|(a, b)| SpanlessEq::eq(a, b)) |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | impl<T: SpanlessEq> SpanlessEq for ThinVec<T> { |
| 68 | fn eq(&self, other: &Self) -> bool { |
David Tolnay | a25d1dc | 2018-07-31 21:46:19 -0700 | [diff] [blame] | 69 | self.len() == other.len() && self |
| 70 | .iter() |
| 71 | .zip(other.iter()) |
| 72 | .all(|(a, b)| SpanlessEq::eq(a, b)) |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 73 | } |
| 74 | } |
| 75 | |
| 76 | impl<T: SpanlessEq> SpanlessEq for Spanned<T> { |
| 77 | fn eq(&self, other: &Self) -> bool { |
| 78 | SpanlessEq::eq(&self.node, &other.node) |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | impl<A: SpanlessEq, B: SpanlessEq> SpanlessEq for (A, B) { |
| 83 | fn eq(&self, other: &Self) -> bool { |
| 84 | SpanlessEq::eq(&self.0, &other.0) && SpanlessEq::eq(&self.1, &other.1) |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | impl<A: SpanlessEq, B: SpanlessEq, C: SpanlessEq> SpanlessEq for (A, B, C) { |
| 89 | fn eq(&self, other: &Self) -> bool { |
| 90 | SpanlessEq::eq(&self.0, &other.0) |
| 91 | && SpanlessEq::eq(&self.1, &other.1) |
| 92 | && SpanlessEq::eq(&self.2, &other.2) |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | macro_rules! spanless_eq_true { |
| 97 | ($name:ident) => { |
| 98 | impl SpanlessEq for $name { |
| 99 | fn eq(&self, _other: &Self) -> bool { |
| 100 | true |
| 101 | } |
| 102 | } |
| 103 | }; |
| 104 | } |
| 105 | |
| 106 | spanless_eq_true!(Span); |
| 107 | spanless_eq_true!(AttrId); |
| 108 | spanless_eq_true!(NodeId); |
| 109 | spanless_eq_true!(SyntaxContext); |
| 110 | |
| 111 | macro_rules! spanless_eq_partial_eq { |
| 112 | ($name:ident) => { |
| 113 | impl SpanlessEq for $name { |
| 114 | fn eq(&self, other: &Self) -> bool { |
| 115 | PartialEq::eq(self, other) |
| 116 | } |
| 117 | } |
| 118 | }; |
| 119 | } |
| 120 | |
| 121 | spanless_eq_partial_eq!(bool); |
| 122 | spanless_eq_partial_eq!(u8); |
| 123 | spanless_eq_partial_eq!(u16); |
| 124 | spanless_eq_partial_eq!(u128); |
| 125 | spanless_eq_partial_eq!(usize); |
| 126 | spanless_eq_partial_eq!(char); |
| 127 | spanless_eq_partial_eq!(Symbol); |
| 128 | spanless_eq_partial_eq!(Abi); |
| 129 | spanless_eq_partial_eq!(DelimToken); |
| 130 | |
| 131 | macro_rules! spanless_eq_struct { |
| 132 | { |
| 133 | $name:ident; |
| 134 | $([$field:ident $other:ident])* |
| 135 | $(![$ignore:ident])* |
| 136 | } => { |
| 137 | impl SpanlessEq for $name { |
| 138 | fn eq(&self, other: &Self) -> bool { |
| 139 | let $name { $($field,)* $($ignore: _,)* } = self; |
| 140 | let $name { $($field: $other,)* $($ignore: _,)* } = other; |
| 141 | $(SpanlessEq::eq($field, $other))&&* |
| 142 | } |
| 143 | } |
| 144 | }; |
| 145 | |
| 146 | { |
| 147 | $name:ident; |
| 148 | $([$field:ident $other:ident])* |
| 149 | $next:ident |
| 150 | $($rest:ident)* |
| 151 | $(!$ignore:ident)* |
| 152 | } => { |
| 153 | spanless_eq_struct! { |
| 154 | $name; |
| 155 | $([$field $other])* |
| 156 | [$next other] |
| 157 | $($rest)* |
| 158 | $(!$ignore)* |
| 159 | } |
| 160 | }; |
| 161 | |
| 162 | { |
| 163 | $name:ident; |
| 164 | $([$field:ident $other:ident])* |
| 165 | $(![$ignore:ident])* |
| 166 | !$next:ident |
| 167 | $(!$rest:ident)* |
| 168 | } => { |
| 169 | spanless_eq_struct! { |
| 170 | $name; |
| 171 | $([$field $other])* |
| 172 | $(![$ignore])* |
| 173 | ![$next] |
| 174 | $(!$rest)* |
| 175 | } |
| 176 | }; |
| 177 | } |
| 178 | |
| 179 | macro_rules! spanless_eq_enum { |
| 180 | { |
| 181 | $name:ident; |
| 182 | $([$variant:ident $([$field:tt $this:ident $other:ident])*])* |
| 183 | } => { |
| 184 | impl SpanlessEq for $name { |
| 185 | fn eq(&self, other: &Self) -> bool { |
| 186 | match self { |
| 187 | $( |
| 188 | $name::$variant { .. } => {} |
| 189 | )* |
| 190 | } |
| 191 | match (self, other) { |
| 192 | $( |
| 193 | ( |
| 194 | $name::$variant { $($field: $this),* }, |
| 195 | $name::$variant { $($field: $other),* }, |
| 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)*] ( $i:tt $($field:tt)* ) |
| 210 | $($rest:tt)* |
| 211 | } => { |
| 212 | spanless_eq_enum! { |
| 213 | $name; |
| 214 | $([$variant $($fields)*])* |
| 215 | $next [$($named)* [$i this other]] ( $($field)* ) |
| 216 | $($rest)* |
| 217 | } |
| 218 | }; |
| 219 | |
| 220 | { |
| 221 | $name:ident; |
| 222 | $([$variant:ident $($fields:tt)*])* |
| 223 | $next:ident [$($named:tt)*] () |
| 224 | $($rest:tt)* |
| 225 | } => { |
| 226 | spanless_eq_enum! { |
| 227 | $name; |
| 228 | $([$variant $($fields)*])* |
| 229 | [$next $($named)*] |
| 230 | $($rest)* |
| 231 | } |
| 232 | }; |
| 233 | |
| 234 | { |
| 235 | $name:ident; |
| 236 | $([$variant:ident $($fields:tt)*])* |
| 237 | $next:ident ( $($field:tt)* ) |
| 238 | $($rest:tt)* |
| 239 | } => { |
| 240 | spanless_eq_enum! { |
| 241 | $name; |
| 242 | $([$variant $($fields)*])* |
| 243 | $next [] ( $($field)* ) |
| 244 | $($rest)* |
| 245 | } |
| 246 | }; |
| 247 | |
| 248 | { |
| 249 | $name:ident; |
| 250 | $([$variant:ident $($fields:tt)*])* |
| 251 | $next:ident |
| 252 | $($rest:tt)* |
| 253 | } => { |
| 254 | spanless_eq_enum! { |
| 255 | $name; |
| 256 | $([$variant $($fields)*])* |
| 257 | [$next] |
| 258 | $($rest)* |
| 259 | } |
| 260 | }; |
| 261 | } |
| 262 | |
| 263 | spanless_eq_struct!(AngleBracketedArgs; span args bindings); |
| 264 | spanless_eq_struct!(AnonConst; id value); |
| 265 | spanless_eq_struct!(Arg; ty pat id); |
| 266 | spanless_eq_struct!(Arm; attrs pats guard body); |
| 267 | spanless_eq_struct!(Attribute; id style path tokens span !is_sugared_doc); |
| 268 | spanless_eq_struct!(BareFnTy; unsafety abi generic_params decl); |
| 269 | spanless_eq_struct!(Block; stmts id rules span recovered); |
| 270 | spanless_eq_struct!(Crate; module attrs span); |
| 271 | spanless_eq_struct!(Delimited; delim tts); |
| 272 | spanless_eq_struct!(EnumDef; variants); |
| 273 | spanless_eq_struct!(Expr; id node span attrs); |
| 274 | spanless_eq_struct!(Field; ident expr span is_shorthand attrs); |
| 275 | spanless_eq_struct!(FieldPat; ident pat is_shorthand attrs); |
| 276 | spanless_eq_struct!(FnDecl; inputs output variadic); |
| 277 | spanless_eq_struct!(FnHeader; unsafety asyncness constness abi); |
| 278 | spanless_eq_struct!(ForeignItem; ident attrs node id span vis); |
| 279 | spanless_eq_struct!(ForeignMod; abi items); |
| 280 | spanless_eq_struct!(GenericParam; id ident attrs bounds kind); |
| 281 | spanless_eq_struct!(Generics; params where_clause span); |
| 282 | spanless_eq_struct!(GlobalAsm; asm ctxt); |
| 283 | spanless_eq_struct!(ImplItem; id ident vis defaultness attrs generics node span !tokens); |
| 284 | spanless_eq_struct!(InlineAsm; asm asm_str_style outputs inputs clobbers volatile alignstack dialect ctxt); |
| 285 | spanless_eq_struct!(InlineAsmOutput; constraint expr is_rw is_indirect); |
| 286 | spanless_eq_struct!(Item; ident attrs id node vis span !tokens); |
| 287 | spanless_eq_struct!(Label; ident); |
| 288 | spanless_eq_struct!(Lifetime; id ident); |
| 289 | spanless_eq_struct!(Local; pat ty init id span attrs); |
| 290 | spanless_eq_struct!(Mac_; path delim tts); |
| 291 | spanless_eq_struct!(MacroDef; tokens legacy); |
| 292 | spanless_eq_struct!(MethodSig; header decl); |
| 293 | spanless_eq_struct!(Mod; inner items); |
| 294 | spanless_eq_struct!(MutTy; ty mutbl); |
| 295 | spanless_eq_struct!(ParenthesisedArgs; span inputs output); |
| 296 | spanless_eq_struct!(Pat; id node span); |
| 297 | spanless_eq_struct!(Path; span segments); |
| 298 | spanless_eq_struct!(PathSegment; ident args); |
| 299 | spanless_eq_struct!(PolyTraitRef; bound_generic_params trait_ref span); |
| 300 | spanless_eq_struct!(QSelf; ty path_span position); |
| 301 | spanless_eq_struct!(Stmt; id node span); |
| 302 | spanless_eq_struct!(StructField; span ident vis id ty attrs); |
| 303 | spanless_eq_struct!(TraitItem; id ident attrs generics node span !tokens); |
| 304 | spanless_eq_struct!(TraitRef; path ref_id); |
| 305 | spanless_eq_struct!(Ty; id node span); |
| 306 | spanless_eq_struct!(TypeBinding; id ident ty span); |
| 307 | spanless_eq_struct!(UseTree; prefix kind span); |
| 308 | spanless_eq_struct!(Variant_; ident attrs data disr_expr); |
| 309 | spanless_eq_struct!(WhereBoundPredicate; span bound_generic_params bounded_ty bounds); |
| 310 | spanless_eq_struct!(WhereClause; id predicates span); |
| 311 | spanless_eq_struct!(WhereEqPredicate; id span lhs_ty rhs_ty); |
| 312 | spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds); |
| 313 | spanless_eq_enum!(AsmDialect; Att Intel); |
| 314 | spanless_eq_enum!(AttrStyle; Outer Inner); |
| 315 | spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt); |
| 316 | spanless_eq_enum!(BindingMode; ByRef(0) ByValue(0)); |
| 317 | spanless_eq_enum!(BlockCheckMode; Default Unsafe(0)); |
| 318 | spanless_eq_enum!(CaptureBy; Value Ref); |
| 319 | spanless_eq_enum!(Constness; Const NotConst); |
| 320 | spanless_eq_enum!(CrateSugar; PubCrate JustCrate); |
| 321 | spanless_eq_enum!(Defaultness; Default Final); |
| 322 | spanless_eq_enum!(FloatTy; F32 F64); |
| 323 | spanless_eq_enum!(ForeignItemKind; Fn(0 1) Static(0 1) Ty Macro(0)); |
| 324 | spanless_eq_enum!(FunctionRetTy; Default(0) Ty(0)); |
| 325 | spanless_eq_enum!(GenericArg; Lifetime(0) Type(0)); |
| 326 | spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0)); |
| 327 | spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0)); |
| 328 | spanless_eq_enum!(GenericParamKind; Lifetime Type(default)); |
David Tolnay | 72972e7 | 2018-07-21 18:35:24 -0700 | [diff] [blame] | 329 | spanless_eq_enum!(ImplItemKind; Const(0 1) Method(0 1) Type(0) Existential(0) Macro(0)); |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 330 | spanless_eq_enum!(ImplPolarity; Positive Negative); |
| 331 | spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128); |
| 332 | spanless_eq_enum!(IsAsync; Async(closure_id return_impl_trait_id) NotAsync); |
| 333 | spanless_eq_enum!(IsAuto; Yes No); |
| 334 | spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed); |
| 335 | spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace); |
| 336 | spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces); |
| 337 | spanless_eq_enum!(Movability; Static Movable); |
| 338 | spanless_eq_enum!(Mutability; Mutable Immutable); |
| 339 | spanless_eq_enum!(RangeEnd; Included(0) Excluded); |
| 340 | spanless_eq_enum!(RangeLimits; HalfOpen Closed); |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 341 | spanless_eq_enum!(StmtKind; Local(0) Item(0) Expr(0) Semi(0) Mac(0)); |
| 342 | spanless_eq_enum!(StrStyle; Cooked Raw(0)); |
| 343 | spanless_eq_enum!(TokenTree; Token(0 1) Delimited(0 1)); |
| 344 | spanless_eq_enum!(TraitBoundModifier; None Maybe); |
| 345 | spanless_eq_enum!(TraitItemKind; Const(0 1) Method(0 1) Type(0 1) Macro(0)); |
| 346 | spanless_eq_enum!(TraitObjectSyntax; Dyn None); |
| 347 | spanless_eq_enum!(UintTy; Usize U8 U16 U32 U64 U128); |
| 348 | spanless_eq_enum!(UnOp; Deref Not Neg); |
| 349 | spanless_eq_enum!(UnsafeSource; CompilerGenerated UserProvided); |
| 350 | spanless_eq_enum!(Unsafety; Unsafe Normal); |
| 351 | spanless_eq_enum!(UseTreeKind; Simple(0 1 2) Nested(0) Glob); |
| 352 | spanless_eq_enum!(VariantData; Struct(0 1) Tuple(0 1) Unit(0)); |
| 353 | spanless_eq_enum!(VisibilityKind; Public Crate(0) Restricted(path id) Inherited); |
| 354 | spanless_eq_enum!(WherePredicate; BoundPredicate(0) RegionPredicate(0) EqPredicate(0)); |
| 355 | spanless_eq_enum!(ExprKind; Box(0) ObsoleteInPlace(0 1) Array(0) Call(0 1) |
| 356 | MethodCall(0 1) Tup(0) Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1) |
| 357 | If(0 1 2) IfLet(0 1 2 3) While(0 1 2) WhileLet(0 1 2 3) ForLoop(0 1 2 3) |
David Tolnay | d1c31cc | 2018-08-24 14:47:15 -0400 | [diff] [blame] | 358 | Loop(0 1) Match(0 1) Closure(0 1 2 3 4 5) Block(0 1) Async(0 1 2) TryBlock(0) |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 359 | Assign(0 1) AssignOp(0 1 2) Field(0 1) Index(0 1) Range(0 1 2) Path(0 1) |
| 360 | AddrOf(0 1) Break(0 1) Continue(0) Ret(0) InlineAsm(0) Mac(0) Struct(0 1 2) |
| 361 | Repeat(0 1) Paren(0) Try(0) Yield(0)); |
| 362 | spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1) |
David Tolnay | 72972e7 | 2018-07-21 18:35:24 -0700 | [diff] [blame] | 363 | Fn(0 1 2 3) Mod(0) ForeignMod(0) GlobalAsm(0) Ty(0 1) Existential(0 1) |
| 364 | Enum(0 1) Struct(0 1) Union(0 1) Trait(0 1 2 3 4) TraitAlias(0 1) |
| 365 | Impl(0 1 2 3 4 5 6) Mac(0) MacroDef(0)); |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 366 | spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0) Byte(0) Char(0) Int(0 1) |
| 367 | Float(0 1) FloatUnsuffixed(0) Bool(0)); |
| 368 | spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2) TupleStruct(0 1 2) |
| 369 | Path(0 1) Tuple(0 1) Box(0) Ref(0 1) Lit(0) Range(0 1 2) Slice(0 1 2) |
| 370 | Paren(0) Mac(0)); |
| 371 | spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Rptr(0 1) BareFn(0) Never |
| 372 | Tup(0) Path(0 1) TraitObject(0 1) ImplTrait(0 1) Paren(0) Typeof(0) Infer |
| 373 | ImplicitSelf Mac(0) Err); |
| 374 | |
| 375 | impl SpanlessEq for Ident { |
| 376 | fn eq(&self, other: &Self) -> bool { |
| 377 | self.as_str() == other.as_str() |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | // Give up on comparing literals inside of macros because there are so many |
| 382 | // equivalent representations of the same literal; they are tested elsewhere |
| 383 | impl SpanlessEq for Lit { |
| 384 | fn eq(&self, other: &Self) -> bool { |
| 385 | mem::discriminant(self) == mem::discriminant(other) |
| 386 | } |
| 387 | } |
| 388 | |
David Tolnay | c6b5e81 | 2018-07-21 14:04:28 -0700 | [diff] [blame] | 389 | impl SpanlessEq for RangeSyntax { |
| 390 | fn eq(&self, _other: &Self) -> bool { |
| 391 | match self { |
| 392 | RangeSyntax::DotDotDot | RangeSyntax::DotDotEq => true, |
| 393 | } |
| 394 | } |
| 395 | } |
| 396 | |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 397 | impl SpanlessEq for Token { |
| 398 | fn eq(&self, other: &Self) -> bool { |
| 399 | match (self, other) { |
| 400 | (Token::Literal(this, _), Token::Literal(other, _)) => SpanlessEq::eq(this, other), |
David Tolnay | c6b5e81 | 2018-07-21 14:04:28 -0700 | [diff] [blame] | 401 | (Token::DotDotEq, _) | (Token::DotDotDot, _) => match other { |
| 402 | Token::DotDotEq | Token::DotDotDot => true, |
| 403 | _ => false, |
David Tolnay | 72972e7 | 2018-07-21 18:35:24 -0700 | [diff] [blame] | 404 | }, |
David Tolnay | ecd024d | 2018-07-21 09:07:56 -0700 | [diff] [blame] | 405 | _ => self == other, |
| 406 | } |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | impl SpanlessEq for TokenStream { |
| 411 | fn eq(&self, other: &Self) -> bool { |
| 412 | SpanlessEq::eq(&expand_tts(self), &expand_tts(other)) |
| 413 | } |
| 414 | } |
| 415 | |
| 416 | impl SpanlessEq for ThinTokenStream { |
| 417 | fn eq(&self, other: &Self) -> bool { |
| 418 | SpanlessEq::eq( |
| 419 | &TokenStream::from(self.clone()), |
| 420 | &TokenStream::from(other.clone()), |
| 421 | ) |
| 422 | } |
| 423 | } |
| 424 | |
| 425 | fn expand_tts(tts: &TokenStream) -> Vec<TokenTree> { |
| 426 | let mut tokens = Vec::new(); |
| 427 | for tt in tts.clone().into_trees() { |
| 428 | let c = match tt { |
| 429 | TokenTree::Token(_, Token::DocComment(c)) => c, |
| 430 | _ => { |
| 431 | tokens.push(tt); |
| 432 | continue; |
| 433 | } |
| 434 | }; |
| 435 | let contents = comments::strip_doc_comment_decoration(&c.as_str()); |
| 436 | let style = comments::doc_comment_style(&c.as_str()); |
| 437 | tokens.push(TokenTree::Token(DUMMY_SP, Token::Pound)); |
| 438 | if style == AttrStyle::Inner { |
| 439 | tokens.push(TokenTree::Token(DUMMY_SP, Token::Not)); |
| 440 | } |
| 441 | let lit = Lit::Str_(Symbol::intern(&contents)); |
| 442 | let mut tts = vec![ |
| 443 | TokenTree::Token(DUMMY_SP, Token::Ident(Ident::from_str("doc"), false)), |
| 444 | TokenTree::Token(DUMMY_SP, Token::Eq), |
| 445 | TokenTree::Token(DUMMY_SP, Token::Literal(lit, None)), |
| 446 | ]; |
| 447 | tokens.push(TokenTree::Delimited( |
| 448 | DUMMY_SP, |
| 449 | Delimited { |
| 450 | delim: DelimToken::Bracket, |
| 451 | tts: tts.into_iter().collect::<TokenStream>().into(), |
| 452 | }, |
| 453 | )); |
| 454 | } |
| 455 | tokens |
| 456 | } |