diff options
Diffstat (limited to 'utils/check-api-annotations')
-rw-r--r-- | utils/check-api-annotations/Main.hs | 34 | ||||
-rw-r--r-- | utils/check-api-annotations/README | 85 |
2 files changed, 103 insertions, 16 deletions
diff --git a/utils/check-api-annotations/Main.hs b/utils/check-api-annotations/Main.hs index 7dc2eb3f77..20e6aa0ca2 100644 --- a/utils/check-api-annotations/Main.hs +++ b/utils/check-api-annotations/Main.hs @@ -7,6 +7,7 @@ import DynFlags import Outputable import ApiAnnotation import System.Environment( getArgs ) +import System.Exit import qualified Data.Map as Map import qualified Data.Set as Set @@ -19,7 +20,7 @@ main = do testOneFile :: FilePath -> String -> IO () testOneFile libdir fileName = do - ((anns,cs),p) <- runGhc (Just libdir) $ do + ((anns,_cs),p) <- runGhc (Just libdir) $ do dflags <- getSessionDynFlags _ <- setSessionDynFlags dflags let mn =mkModuleName fileName @@ -33,9 +34,6 @@ testOneFile libdir fileName = do let sspans = Set.fromList $ getAllSrcSpans (pm_parsed_source p) - problems = filter (\(s,_a) -> not (Set.member s sspans)) - $ getAnnSrcSpans (anns,cs) - exploded = [((kw,ss),[anchor]) | ((anchor,kw),sss) <- Map.toList anns,ss <- sss] @@ -45,17 +43,20 @@ testOneFile libdir fileName = do -> not (any (\a -> Set.member a sspans) anchors)) exploded' - putStrLn "---Problems---------------------" - putStrLn (intercalate "\n" [showAnns $ Map.fromList $ map snd problems]) - putStrLn "---Problems'--------------------" - putStrLn (intercalate "\n" [pp $ Map.fromList $ map fst problems']) - putStrLn "--------------------------------" - putStrLn (intercalate "\n" [showAnns anns]) + problems'' = filter (\((a,_),_) -> a /= AnnEofPos) problems' - where - getAnnSrcSpans :: ApiAnns -> [(SrcSpan,(ApiAnnKey,[SrcSpan]))] - getAnnSrcSpans (anns,_) = map (\a@((ss,_),_) -> (ss,a)) $ Map.toList anns + putStrLn "---Problems (should be empty list)---" + putStrLn (intercalate "\n" [pp $ Map.fromList $ map fst problems'']) + putStrLn "---Annotations-----------------------" + putStrLn "-- SrcSpan the annotation is attached to, AnnKeywordId," + putStrLn "-- list of locations the keyword item appears in" + -- putStrLn (intercalate "\n" [showAnns anns]) + putStrLn (showAnns anns) + if null problems'' + then exitSuccess + else exitFailure + where getAllSrcSpans :: (Data t) => t -> [SrcSpan] getAllSrcSpans ast = everything (++) ([] `mkQ` getSrcSpan) ast where @@ -64,11 +65,12 @@ testOneFile libdir fileName = do showAnns :: Map.Map ApiAnnKey [SrcSpan] -> String -showAnns anns = "[\n" ++ (intercalate "\n" +showAnns anns = "[\n" ++ (intercalate ",\n" $ map (\((s,k),v) - -> ("(AK " ++ pp s ++ " " ++ show k ++" = " ++ pp v ++ ")\n")) + -- -> ("(AK " ++ pp s ++ " " ++ show k ++" = " ++ pp v ++ ")\n")) + -> ("((" ++ pp s ++ "," ++ show k ++"), " ++ pp v ++ ")")) $ Map.toList anns) - ++ "]\n" + ++ "\n]\n" pp :: (Outputable a) => a -> String pp a = showPpr unsafeGlobalDynFlags a diff --git a/utils/check-api-annotations/README b/utils/check-api-annotations/README index 7c2815a403..fcadc50ff6 100644 --- a/utils/check-api-annotations/README +++ b/utils/check-api-annotations/README @@ -16,3 +16,88 @@ In a test Makefile $(CHECK_API_ANNOTATIONS) "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`" FileToParse.hs See examples in (REPO_HOME)/testsuite/tests/ghc-api/annotations/Makefile + + +Description of operation +------------------------ + +The programme is called with the name of a haskell source file. + +It uses the GHC API to load and parse this, and extracts the API annotations. + +These are of the form + + Map.Map ApiAnnKey [SrcSpan] + +where + + type ApiAnnKey = (SrcSpan,AnnKeywordId) + +So an annotation is a key comprising the parent SrcSpan in the ParsedSource +together with an AnnKeywordId, and this maps to a list of locations where the +specific keyword item occurs in the original source. + +The utility extracts all SrcSpans in the ParsedSource, and makes sure that for +every ApiAnnKey the SrcSpan is actually present in the final ParsedSource. This +is to ensure that when a given parser production is postprocessed anywhere along +the line the relevant SrcSpan is not discarded, thus detaching the annotation +from the final output. + +It also provides a list of each ApiAnnKey and the corresponding source +locations, so these can be checked against the original source for correctness. + +Example +------- + +Test10255.hs in the ghc-api/annotations tests has the following source + +------------------------------ +1:{-# LANGUAGE ScopedTypeVariables #-} +2:module Test10255 where +3: +4:import Data.Maybe +5: +6:fob (f :: (Maybe t -> Int)) = +7: undefined +------------------------------ + +The output of this utility is + +------------------------------------------------------------------------ +---Problems (should be empty list)--- +[] +---Annotations----------------------- +-- SrcSpan the annotation is attached to, AnnKeywordId, +-- list of locations the keyword item appears in +[ +((Test10255.hs:1:1,AnnModule), [Test10255.hs:2:1-6]), +((Test10255.hs:1:1,AnnWhere), [Test10255.hs:2:18-22]), +((Test10255.hs:4:1-17,AnnImport), [Test10255.hs:4:1-6]), +((Test10255.hs:4:1-17,AnnSemi), [Test10255.hs:6:1]), +((Test10255.hs:(6,1)-(7,11),AnnEqual), [Test10255.hs:6:29]), +((Test10255.hs:(6,1)-(7,11),AnnFunId), [Test10255.hs:6:1-3]), +((Test10255.hs:(6,1)-(7,11),AnnSemi), [Test10255.hs:8:1]), +((Test10255.hs:6:5-27,AnnCloseP), [Test10255.hs:6:27]), +((Test10255.hs:6:5-27,AnnOpenP), [Test10255.hs:6:5]), +((Test10255.hs:6:6-26,AnnDcolon), [Test10255.hs:6:8-9]), +((Test10255.hs:6:11-26,AnnCloseP), [Test10255.hs:6:26]), +((Test10255.hs:6:11-26,AnnOpenP), [Test10255.hs:6:11]), +((Test10255.hs:6:12-18,AnnRarrow), [Test10255.hs:6:20-21]), +((Test10255.hs:6:12-25,AnnRarrow), [Test10255.hs:6:20-21]), +((<no location info>,AnnEofPos), [Test10255.hs:8:1]) +] +------------------------------------------------------------------------ + +To interpret this, firstly the problems list is empty, so there are not +annotations that do not appear in the final AST. + +Secondly, the list of annotations and locations can be checked against the test +source code to ensure that every AnnKeywordId does in fact appear. + +It will return a zero exit code if the list of problems is empty, non-zero +otherwise. + +Note: In some cases, such as T10269 in the ghc-api/annotations tests the list is +non-empty, due to postprocessing of the parsed result. In general this should +only happen for an `AnnVal` and if it does the actual annotations provided need +to be inspected to check that an equivalent annotation is provided. |