@@ -6,6 +6,7 @@
66
77module Ormolu.Diff
88 ( diff
9+ , Diff(..)
910 )
1011where
1112
@@ -15,43 +16,74 @@ import GHC
1516import Ormolu.Imports (sortImports)
1617import Ormolu.Parser.Result
1718
19+-- | Result of comparing two 'ParseResult's.
20+
21+data Diff
22+ = Same -- ^ Two parse results are the same
23+ | Different [SrcSpan] -- ^ Two parse results differ
24+
25+instance Semigroup Diff where
26+ Same <> a = a
27+ a <> Same = a
28+ Different xs <> Different ys = Different (xs ++ ys)
29+
30+instance Monoid Diff where
31+ mempty = Same
32+
1833-- | Return 'False' if two annotated ASTs are the same modulo span
1934-- positions.
2035
21−diff :: ParseResult -> ParseResult -> Bool
36+diff :: ParseResult -> ParseResult -> Diff
2237diff ParseResult { prCommentStream = cstream0
2338 , prParsedSource = ps0
2439 }
2540 ParseResult { prCommentStream = cstream1
2641 , prParsedSource = ps1
2742 } =
28− not (matchIgnoringSrcSpans cstream0 cstream1)
29− || not (matchIgnoringSrcSpans ps0 ps1)
43+ matchIgnoringSrcSpans cstream0 cstream1 <>
44+ matchIgnoringSrcSpans ps0 ps1
3045
3146-- | Compare two values for equality disregarding differences in 'SrcSpan's
3247-- and the ordering of import lists.
3348
34−matchIgnoringSrcSpans :: Data a => a -> a -> Bool
49+matchIgnoringSrcSpans :: Data a => a -> a -> Diff
3550matchIgnoringSrcSpans = genericQuery
3651 where
37− genericQuery :: GenericQ (GenericQ Bool)
38− genericQuery x y = (toConstr x == toConstr y)
39− && and (gzipWithQ (genericQuery
40− `extQ` srcSpanEq
41− `extQ` hsModuleEq
42− `extQ` sourceTextEq) x y)
52+ genericQuery :: GenericQ (GenericQ Diff)
53+ genericQuery x y
54+ | typeOf x == typeOf y, toConstr x == toConstr y =
55+ mconcat $ gzipWithQ
56+ (genericQuery
57+ `extQ` srcSpanEq
58+ `extQ` hsModuleEq
59+ `extQ` sourceTextEq
60+ `ext2Q` forLocated)
61+ x y
62+ | otherwise = Different []
4363
44− srcSpanEq :: SrcSpan -> GenericQ Bool
45− srcSpanEq _ _ = True
64+ srcSpanEq :: SrcSpan -> GenericQ Diff
65+ srcSpanEq _ _ = Same
4666
47− hsModuleEq :: HsModule GhcPs -> GenericQ Bool
67+ hsModuleEq :: HsModule GhcPs -> GenericQ Diff
4868 hsModuleEq hs0 hs1' =
4969 case cast hs1' :: Maybe (HsModule GhcPs) of
50− Nothing -> False
70+ Nothing -> Different []
5171 Just hs1 ->
5272 matchIgnoringSrcSpans
5373 hs0 { hsmodImports = sortImports (hsmodImports hs0) }
5474 hs1 { hsmodImports = sortImports (hsmodImports hs1) }
5575
56− sourceTextEq :: SourceText -> GenericQ Bool
57− sourceTextEq _ _ = True
76+ sourceTextEq :: SourceText -> GenericQ Diff
77+ sourceTextEq _ _ = Same
78+
79+ forLocated
80+ :: (Data e0, Data e1)
81+ => GenLocated e0 e1
82+ -> GenericQ Diff
83+ forLocated x@(L mspn _) y =
84+ maybe id appendSpan (cast mspn) (genericQuery x y)
85+
86+ appendSpan :: SrcSpan -> Diff -> Diff
87+ appendSpan s (Different ss) | fresh = Different (s:ss)
88+ where fresh = not $ any (flip isSubspanOf s) ss
89+ appendSpan _ d = d