diff --git a/data/Default.hs b/data/Default.hs
--- a/data/Default.hs
+++ b/data/Default.hs
@@ -197,6 +197,7 @@
 error = (if isNothing x then y else fromJust x) ==> fromMaybe y x
 error = (if isJust x then fromJust x else y) ==> fromMaybe y x
 error = isJust x && (fromJust x == y) ==> x == Just y
+error = mapMaybe f (map g x) ==> mapMaybe (f . g) x
 
 -- INFIX
 
diff --git a/hlint.cabal b/hlint.cabal
--- a/hlint.cabal
+++ b/hlint.cabal
@@ -1,7 +1,7 @@
 cabal-version:      >= 1.6
 build-type:         Simple
 name:               hlint
-version:            1.8.8
+version:            1.8.9
 -- license is GPL v2 only
 license:            GPL
 license-file:       LICENSE
@@ -38,7 +38,7 @@
         transformers >= 0.0 && < 0.3,
         hscolour == 1.17.*,
         cpphs == 1.11.*,
-        haskell-src-exts >= 1.9.6 && < 1.11,
+        haskell-src-exts >= 1.11 && < 1.12,
         uniplate >= 1.5 && < 1.7
 
     hs-source-dirs:     src
diff --git a/src/Apply.hs b/src/Apply.hs
--- a/src/Apply.hs
+++ b/src/Apply.hs
@@ -1,8 +1,9 @@
 
-module Apply(applyHint, applyHintStr) where
+module Apply(applyHintFile, applyHintFiles, applyHintString) where
 
 import HSE.All
 import Hint.All
+import Control.Arrow
 import Data.Char
 import Data.List
 import Data.Maybe
@@ -12,32 +13,72 @@
 import Util
 
 
-applyHint :: ParseFlags -> [Setting] -> FilePath -> IO [Idea]
-applyHint flags s file = do
+-- | Apply hints to a single file.
+applyHintFile :: ParseFlags -> [Setting] -> FilePath -> IO [Idea]
+applyHintFile flags s file = do
+    res <- parseModuleFile flags s file
+    return $ case res of
+        Left err -> [err]
+        Right m -> executeHints s [m]
+
+
+-- | Apply hints to the contents of a single file.
+applyHintString :: ParseFlags -> [Setting] -> FilePath -> String -> IO [Idea]
+applyHintString flags s file src = do
+    res <- parseModuleString flags s file src
+    return $ case res of
+        Left err -> [err]
+        Right m -> executeHints s [m]
+
+
+-- | Apply hints to multiple files, allowing cross-file hints to fire.
+applyHintFiles :: ParseFlags -> [Setting] -> [FilePath] -> IO [Idea]
+applyHintFiles flags s files = do
+    (err, ms) <- fmap unzipEither $ mapM (parseModuleFile flags s) files
+    return $ err ++ executeHints s ms
+
+
+-- | Given a list of settings (a way to classify) and a list of hints, run them over a list of modules.
+executeHints :: [Setting] -> [Module_] -> [Idea]
+executeHints s ms = concat $
+    [ map (classify $ s ++ mapMaybe readPragma (moduleDecls m)) $
+        order "" [i | ModuHint h <- hints, i <- h nm m] ++
+        concat [order (fromNamed d) [i | h <- decHints, i <- h d] | d <- moduleDecls m]
+    | (nm,m) <- mns
+    , let decHints = [h nm m | DeclHint h <- hints] -- partially apply
+    , let order n = map (\i -> i{func = (moduleName m,n)}) . sortBy (comparing loc)] ++
+    [map (classify s) $ op mns | CrossHint op <- hints]
+    where
+        mns = map (moduleScope &&& id) ms
+
+        hints = for (allHints s) $ \x -> case x of
+            CrossHint op | length ms <= 1 -> ModuHint $ \a b -> op [(a,b)]
+            _ -> x
+
+
+-- | Like 'parseModuleString', but also load the file from disk.
+parseModuleFile :: ParseFlags -> [Setting] -> FilePath -> IO (Either Idea Module_)
+parseModuleFile flags s file = do
     src <- readFileEncoding (encoding flags) file
-    applyHintStr flags s file src
+    parseModuleString flags s file src
 
 
-applyHintStr :: ParseFlags -> [Setting] -> FilePath -> String -> IO [Idea]
-applyHintStr flags s file src = do
+-- | Return either an idea (a parse error) or the module. In IO because might call the C pre processor.
+parseModuleString :: ParseFlags -> [Setting] -> FilePath -> String -> IO (Either Idea Module_)
+parseModuleString flags s file src = do
     res <- parseString flags{infixes=[x | Infix x <- s]} file src
     case snd res of
-        ParseFailed sl msg | length src `seq` True -> map (classify s) `fmap` parseFailed flags sl msg src
-        ParseOk m -> return $
-            let settings = mapMaybe readPragma $ moduleDecls m
-            in map (classify $ s ++ settings) $ parseOk (allHints s) m
-
-
-parseFailed :: ParseFlags -> SrcLoc -> String -> String -> IO [Idea]
-parseFailed flags sl msg src = do
-    -- figure out the best line number to grab context from, by reparsing
-    (str2,pr2) <- parseString (parseFlagsNoLocations flags) "" src
-    let ctxt = case pr2 of
-            ParseFailed sl2 _ -> context (srcLine sl2) str2
-            _ -> context (srcLine sl) src
-    return [ParseError Warning "Parse error" sl msg ctxt]
+        ParseOk m -> return $ Right m
+        ParseFailed sl msg | length src `seq` True -> do
+            -- figure out the best line number to grab context from, by reparsing
+            (str2,pr2) <- parseString (parseFlagsNoLocations flags) "" src
+            let ctxt = case pr2 of
+                    ParseFailed sl2 _ -> context (srcLine sl2) str2
+                    _ -> context (srcLine sl) src
+            return $ Left $ classify s $ ParseError Warning "Parse error" sl msg ctxt
 
 
+-- | Given a line number, and some source code, put bird ticks around the appropriate bit.
 context :: Int -> String -> String
 context lineNo src =
     unlines $ trimBy (all isSpace) $
@@ -45,22 +86,14 @@
     where ticks = ["  ","  ","> ","  ","  "]
 
 
-parseOk :: [Hint] -> Module_ -> [Idea]
-parseOk h m =
-        order "" [i | ModuHint h <- h, i <- h nm m] ++
-        concat [order (fromNamed d) [i | h <- decHints, i <- h d] | d <- moduleDecls m]
-    where
-        decHints = [h nm m | DeclHint h <- h] -- partially apply
-        order n = map (\i -> i{func = (moduleName m,n)}) . sortBy (comparing loc)
-        nm = moduleScope m
-
-
+-- | Find which hints a list of settings implies.
 allHints :: [Setting] -> [Hint]
 allHints xs = dynamicHints xs : map f builtin
     where builtin = nub $ concat [if x == "All" then map fst staticHints else [x] | Builtin x <- xs]
           f x = fromMaybe (error $ "Unknown builtin hints: HLint.Builtin." ++ x) $ lookup x staticHints
 
 
+-- | Given some settings, make sure the severity field of the Idea is correct.
 classify :: [Setting] -> Idea -> Idea
 classify xs i = i{severity = foldl' (f i) (severity i) $ filter isClassify xs}
     where
diff --git a/src/CmdLine.hs b/src/CmdLine.hs
--- a/src/CmdLine.hs
+++ b/src/CmdLine.hs
@@ -35,10 +35,11 @@
     ,cmdColor :: Bool                -- ^ color the result
     ,cmdCpp :: CppFlags              -- ^ options for CPP
     ,cmdDataDir :: FilePath          -- ^ the data directory
-    ,cmdEncoding :: Encoding           -- ^ the text encoding
+    ,cmdEncoding :: Encoding         -- ^ the text encoding
     ,cmdFindHints :: [FilePath]      -- ^ source files to look for hints in
     ,cmdLanguage :: [Extension]      -- ^ the extensions (may be prefixed by "No")
     ,cmdQuiet :: Bool                -- ^ supress all console output
+    ,cmdCross :: Bool                -- ^ work between source files
     }
 
 
@@ -59,6 +60,7 @@
           | FindHints FilePath
           | Language String
           | Quiet
+          | Cross
             deriving Eq
 
 
@@ -73,6 +75,7 @@
        ,Option "X" ["language"] (ReqArg Language "lang") "Language extensions (Arrows, NoCPP)"
        ,Option "u" ["utf8"] (NoArg $ Encoding "UTF-8") "Use UTF-8 text encoding"
        ,Option ""  ["encoding"] (ReqArg Encoding "encoding") "Choose the text encoding"
+       ,Option "x" ["cross"] (NoArg Cross) "Work between modules"
        ,Option "f" ["find"] (ReqArg FindHints "file") "Find hints in a Haskell file"
        ,Option "t" ["test"] (NoArg Test) "Run in test mode"
        ,Option "d" ["datadir"] (ReqArg DataDir "dir") "Override the data directory"
@@ -137,6 +140,7 @@
         ,cmdFindHints = findHints
         ,cmdLanguage = languages
         ,cmdQuiet = Quiet `elem` opt
+        ,cmdCross = Cross `elem` opt
         }
 
 
diff --git a/src/HLint.hs b/src/HLint.hs
--- a/src/HLint.hs
+++ b/src/HLint.hs
@@ -67,7 +67,10 @@
     settings3 <- return [Classify Ignore x ("","") | x <- cmdIgnore]
     let settings = settings1 ++ settings2 ++ settings3
 
-    ideas <- fmap concat $ parallel [listM' =<< applyHint flags settings x | x <- fromMaybe [] cmdFiles]
+    let files = fromMaybe [] cmdFiles
+    ideas <- if cmdCross
+        then applyHintFiles flags settings files
+        else fmap concat $ parallel [listM' =<< applyHintFile flags settings x | x <- files]
     let (showideas,hideideas) = partition (\i -> cmdShowAll || severity i /= Ignore) ideas
     showItem <- if cmdColor then showANSI else return show
     mapM_ (outStrLn . showItem) showideas
diff --git a/src/HSE/All.hs b/src/HSE/All.hs
--- a/src/HSE/All.hs
+++ b/src/HSE/All.hs
@@ -1,23 +1,20 @@
 
 module HSE.All(
-    module HSE.Util, module HSE.Evaluate,
-    module HSE.Bracket, module HSE.Match,
-    module HSE.Type,
-    module HSE.NameMatch,
+    module X,
     ParseFlags(..), parseFlags, parseFlagsNoLocations,
     parseFile, parseString, parseResult
     ) where
 
+import HSE.Util as X
+import HSE.Evaluate as X
+import HSE.Type as X
+import HSE.Bracket as X
+import HSE.Match as X
+import HSE.NameMatch as X
 import Util
 import CmdLine
 import Data.List
 import Data.Maybe
-import HSE.Util
-import HSE.Evaluate
-import HSE.Type
-import HSE.Bracket
-import HSE.Match
-import HSE.NameMatch
 import Language.Preprocessor.Cpphs
 
 
@@ -52,7 +49,7 @@
         mode = defaultParseMode
             {parseFilename = file
             ,extensions = language flags
-            ,fixities = []
+            ,fixities = Nothing
             ,ignoreLinePragmas = False
             }
 
diff --git a/src/HSE/Util.hs b/src/HSE/Util.hs
--- a/src/HSE/Util.hs
+++ b/src/HSE/Util.hs
@@ -7,7 +7,7 @@
 import Data.Maybe
 import System.FilePath
 import HSE.Type
-import Language.Haskell.Exts.Annotated.Simplify(sOp, sAssoc)
+import Language.Haskell.Exts.Annotated.Simplify(sQName, sAssoc)
 
 
 ---------------------------------------------------------------------
@@ -302,5 +302,7 @@
 -- FIXITIES
 
 getFixity :: Decl a -> [Fixity]
-getFixity (InfixDecl _ a mp ops) = [Fixity (sAssoc a) (fromMaybe 9 mp) (sOp op) | op <- ops]
+getFixity (InfixDecl sl a mp ops) = [Fixity (sAssoc a) (fromMaybe 9 mp) (sQName $ UnQual sl $ f op) | op <- ops]
+    where f (VarOp _ x) = x
+          f (ConOp _ x) = x
 getFixity _ = []
diff --git a/src/Hint/All.hs b/src/Hint/All.hs
--- a/src/Hint/All.hs
+++ b/src/Hint/All.hs
@@ -23,19 +23,22 @@
 
 staticHints :: [(String,Hint)]
 staticHints =
-    let x*y = (x,DeclHint y) ; x+y = (x,ModuHint y) in
-    ["List"       * listHint
-    ,"ListRec"    * listRecHint
-    ,"Monad"      * monadHint
-    ,"Lambda"     * lambdaHint
-    ,"Bracket"    * bracketHint
-    ,"Naming"     * namingHint
-    ,"Structure"  * structureHint
+    ["List"       ! listHint
+    ,"ListRec"    ! listRecHint
+    ,"Monad"      ! monadHint
+    ,"Lambda"     ! lambdaHint
+    ,"Bracket"    ! bracketHint
+    ,"Naming"     ! namingHint
+    ,"Structure"  ! structureHint
     ,"Import"     + importHint
     ,"Pragma"     + pragmaHint
     ,"Extensions" + extensionsHint
-    ,"Duplicate"  + duplicateHint
+    ,"Duplicate"  * duplicateHint
     ]
+    where
+        x!y = (x,DeclHint y)
+        x+y = (x,ModuHint y)
+        x*y = (x,CrossHint y)
 
 dynamicHints :: [Setting] -> Hint
 dynamicHints = DeclHint . readMatch
diff --git a/src/Hint/Duplicate.hs b/src/Hint/Duplicate.hs
--- a/src/Hint/Duplicate.hs
+++ b/src/Hint/Duplicate.hs
@@ -24,10 +24,11 @@
 import qualified Data.Map as Map
 
 
-duplicateHint :: ModuHint
-duplicateHint _ modu =
+duplicateHint :: CrossHint
+duplicateHint ms =
     dupes [y | Do _ y :: Exp S <- universeBi modu] ++
     dupes [y | BDecls l y :: Binds S <- universeBi modu]
+    where modu = map snd ms
 
 
 dupes ys =
diff --git a/src/Hint/Extensions.hs b/src/Hint/Extensions.hs
--- a/src/Hint/Extensions.hs
+++ b/src/Hint/Extensions.hs
@@ -27,6 +27,8 @@
 record field = Record{..}
 {-# LANGUAGE RecordWildCards #-} \
 record = 1 --
+{-# LANGUAGE UnboxedTuples #-} \
+record = 1 --
 </TEST>
 -}
 
@@ -55,7 +57,7 @@
 
 minimalExtensions :: Module_ -> [Extension] -> [Extension]
 minimalExtensions x es = nub $ concatMap f es
-    where f e = if used e x then [e] else []
+    where f e = [e | used e x]
 
 
 -- RecordWildCards implies DisambiguateRecordFields, but most people probably don't want it
diff --git a/src/Hint/List.hs b/src/Hint/List.hs
--- a/src/Hint/List.hs
+++ b/src/Hint/List.hs
@@ -17,6 +17,7 @@
 yes = if x == e then l2 ++ xs else [x] ++ check_elem xs -- x : check_elem xs
 data Yes = Yes (Maybe [Char]) -- Maybe String
 yes = y :: [Char] -> a -- String -> a
+instance C [Char]
 </TEST>
 -}
 
@@ -30,8 +31,7 @@
 listHint _ _ = listDecl
 
 listDecl :: Decl_ -> [Idea]
-listDecl x = concatMap (listExp False) (childrenBi x) ++
-             concatMap stringType (childrenBi x)
+listDecl x = concatMap (listExp False) (childrenBi x) ++ stringType x
 
 -- boolean = are you in a ++ chain
 listExp :: Bool -> Exp_ -> [Idea]
@@ -76,6 +76,13 @@
 typeString = TyCon an (toNamed "String")
 
 
-stringType :: Type_ -> [Idea]
-stringType (fromTyParen -> x) = [warn "Use String" x (transform f x) | any (=~= typeListChar) $ universe x]
-    where f x = if x =~= typeListChar then typeString else x
+stringType :: Decl_ -> [Idea]
+stringType x = case x of
+    InstDecl _ _ _ x -> f x
+    _ -> f x
+    where
+        f x = concatMap g $ childrenBi x
+
+        g :: Type_ -> [Idea]
+        g (fromTyParen -> x) = [warn "Use String" x (transform f x) | any (=~= typeListChar) $ universe x]
+            where f x = if x =~= typeListChar then typeString else x
diff --git a/src/Hint/Type.hs b/src/Hint/Type.hs
--- a/src/Hint/Type.hs
+++ b/src/Hint/Type.hs
@@ -7,5 +7,8 @@
 
 type DeclHint = Scope -> Module_ -> Decl_ -> [Idea]
 type ModuHint = Scope -> Module_          -> [Idea]
+type CrossHint = [(Scope, Module_)] -> [Idea]
 
-data Hint = DeclHint {declHint :: DeclHint} | ModuHint {moduHint :: ModuHint}
+data Hint = DeclHint {declHint :: DeclHint}
+          | ModuHint {moduHint :: ModuHint}
+          | CrossHint {crossHint :: CrossHint}
diff --git a/src/Test.hs b/src/Test.hs
--- a/src/Test.hs
+++ b/src/Test.hs
@@ -138,7 +138,7 @@
     return $ Result (length failures) (length tests)
     where
         f (Test loc inp out) = do
-            ideas <- applyHintStr parseFlags setting file inp
+            ideas <- applyHintString parseFlags setting file inp
             let good = case out of
                     Nothing -> null ideas
                     Just x -> length ideas == 1 &&
@@ -201,7 +201,7 @@
         else error "checkInputOutput, couldn't find or figure out flags"
 
     got <- fmap (fmap lines) $ captureOutput $
-        handle (\(e::SomeException) -> print $ e) $
+        handle (\(e::SomeException) -> print e) $
         handle (\(e::ExitCode) -> return ()) $
         main flags
     want <- fmap lines $ reader "output"
diff --git a/src/Util.hs b/src/Util.hs
--- a/src/Util.hs
+++ b/src/Util.hs
@@ -81,6 +81,8 @@
 unzipEither [] = ([], [])
 
 
+for = flip map
+
 ---------------------------------------------------------------------
 -- DATA.STRING
 
