git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Expose error suggestions in JSON
commit3ea5bf4cd7232cedc141bcdfb637528595f1d381 authorNicholas Wolverson <nicholas.wolverson@gmail.com> dateSun 10 Jan 2016, 10:25 (11 years ago) parent150d9c6
3 files changed+86−37
psc/JSON.hs+9 src/Language/PureScript/Errors.hs+70−32 src/Language/PureScript/Linter/Imports.hs+7−5
psc/JSON.hs+9
@@ -30,6 +30,8 @@ data ErrorPosition = ErrorPosition
3030 , endColumn :: Int
3131 }
3232
33+data ErrorSuggestion = ErrorSuggestion { replacement :: String }
34+
3335data JSONError = JSONError
3436 { position :: Maybe ErrorPosition
3537 , message :: String
@@ -37,6 +39,7 @@ data JSONError = JSONError
3739 , errorLink :: String
3840 , filename :: Maybe String
3941 , moduleName :: Maybe String
42+ , suggestion :: Maybe ErrorSuggestion
4043 }
4144
4245data JSONResult = JSONResult
@@ -47,6 +50,8 @@ data JSONResult = JSONResult
4750$(A.deriveJSON A.defaultOptions ''ErrorPosition)
4851$(A.deriveJSON A.defaultOptions ''JSONError)
4952$(A.deriveJSON A.defaultOptions ''JSONResult)
53+$(A.deriveJSON A.defaultOptions ''ErrorSuggestion)
54+
5055
5156toJSONErrors :: Bool -> P.Level -> P.MultipleErrors -> [JSONError]
5257toJSONErrors verbose level = map (toJSONError verbose level) . P.runMultipleErrors
@@ -59,6 +64,7 @@ toJSONError verbose level e =
5964 (P.wikiUri e)
6065 (P.spanName <$> sspan)
6166 (P.runModuleName <$> P.errorModule e)
67+ (toSuggestion <$> (P.errorSuggestion $ P.unwrapErrorMessage e))
6268 where
6369 sspan :: Maybe P.SourceSpan
6470 sspan = P.errorSpan e
@@ -69,3 +75,6 @@ toJSONError verbose level e =
6975 (P.sourcePosColumn (P.spanStart ss))
7076 (P.sourcePosLine (P.spanEnd ss))
7177 (P.sourcePosColumn (P.spanEnd ss))
78+ toSuggestion :: P.ErrorSuggestion -> ErrorSuggestion
79+-- TODO: Adding a newline because source spans chomp everything up to the next character
80+ toSuggestion (P.ErrorSuggestion s) = ErrorSuggestion $ if null s then s else s ++ "\n"
src/Language/PureScript/Errors.hs+70−32
@@ -124,7 +124,7 @@ data SimpleErrorMessage
124124 | MisleadingEmptyTypeImport ModuleName (ProperName 'TypeName)
125125 | ImportHidingModule ModuleName
126126 | UnusedImport ModuleName
127− | UnusedExplicitImport ModuleName [String]
127+ | UnusedExplicitImport ModuleName [String] (Maybe ModuleName) [DeclarationRef]
128128 | UnusedDctorImport (ProperName 'TypeName)
129129 | UnusedDctorExplicitImport (ProperName 'TypeName) [ProperName 'ConstructorName]
130130 | DeprecatedOperatorDecl String
@@ -179,6 +179,8 @@ data HintCategory
179179
180180data ErrorMessage = ErrorMessage [ErrorMessageHint] SimpleErrorMessage deriving (Show)
181181
182+newtype ErrorSuggestion = ErrorSuggestion String
183+
182184-- | Get the source span for an error
183185errorSpan :: ErrorMessage -> Maybe SourceSpan
184186errorSpan = findHint matchSpan
@@ -419,6 +421,40 @@ onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse
419421wikiUri :: ErrorMessage -> String
420422wikiUri e = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e
421423
424+-- TODO Other possible suggestions:
425+-- WildcardInferredType - source span not small enough
426+-- DuplicateSelectiveImport - would require 2 ranges to remove and 1 insert
427+-- DeprecatedClassExport, DeprecatedClassImport, would want to replace smaller span?
428+errorSuggestion :: SimpleErrorMessage -> Maybe ErrorSuggestion
429+errorSuggestion err = case err of
430+ UnusedImport{} -> emptySuggestion
431+ RedundantEmptyHidingImport{} -> emptySuggestion
432+ DuplicateImport{} -> emptySuggestion
433+ RedundantUnqualifiedImport{} -> emptySuggestion
434+ DeprecatedQualifiedSyntax name qualName -> suggest $
435+ "import " ++ runModuleName name ++ " as " ++ runModuleName qualName
436+ UnusedExplicitImport mn _ qual refs -> suggest $ importSuggestion mn refs qual
437+ ImplicitImport mn refs -> suggest $ importSuggestion mn refs Nothing
438+ ImplicitQualifiedImport mn asModule refs -> suggest $ importSuggestion mn refs (Just asModule)
439+ _ -> Nothing
440+
441+ where
442+ emptySuggestion = Just $ ErrorSuggestion ""
443+ suggest = Just . ErrorSuggestion
444+
445+ importSuggestion :: ModuleName -> [ DeclarationRef ] -> Maybe ModuleName -> String
446+ importSuggestion mn refs qual =
447+ "import " ++ runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")" ++ qstr qual
448+
449+ qstr :: Maybe ModuleName -> String
450+ qstr (Just mn) = " as " ++ runModuleName mn
451+ qstr Nothing = ""
452+
453+showSuggestion :: SimpleErrorMessage -> String
454+showSuggestion suggestion = case errorSuggestion suggestion of
455+ Just (ErrorSuggestion x) -> x
456+ _ -> ""
457+
422458-- |
423459-- Pretty print a single error, simplifying if necessary
424460--
@@ -796,9 +832,11 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
796832 renderSimpleErrorMessage (UnusedImport name) =
797833 line $ "The import of module " ++ runModuleName name ++ " is redundant"
798834
799− renderSimpleErrorMessage (UnusedExplicitImport name names) =
800− paras [ line $ "The import of module " ++ runModuleName name ++ " contains the following unused references:"
801− , indent $ paras $ map line names ]
835+ renderSimpleErrorMessage msg@(UnusedExplicitImport mn names _ _) =
836+ paras [ line $ "The import of module " ++ runModuleName mn ++ " contains the following unused references:"
837+ , indent $ paras $ map line names
838+ , line $ "It could be replaced with:"
839+ , indent $ line $ showSuggestion msg ]
802840
803841 renderSimpleErrorMessage (UnusedDctorImport name) =
804842 line $ "The import of type " ++ runProperName name ++ " includes data constructors but only the type is used"
@@ -860,15 +898,15 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
860898 renderSimpleErrorMessage (RedundantEmptyHidingImport mn) =
861899 line $ "The import for module " ++ runModuleName mn ++ " is redundant as all members have been explicitly hidden."
862900
863− renderSimpleErrorMessage (ImplicitQualifiedImport importedModule asModule refs) =
901+ renderSimpleErrorMessage msg@(ImplicitQualifiedImport importedModule asModule _) =
864902 paras [ line $ "Module " ++ runModuleName importedModule ++ " was imported as " ++ runModuleName asModule ++ " with unspecified imports."
865903 , line $ "As there are multiple modules being imported as " ++ runModuleName asModule ++ ", consider using the explicit form:"
866− , indent $ line $ "import " ++ runModuleName importedModule ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ") as " ++ runModuleName asModule
904+ , indent $ line $ showSuggestion msg
867905 ]
868906
869− renderSimpleErrorMessage (ImplicitImport mn refs) =
907+ renderSimpleErrorMessage msg@(ImplicitImport mn _) =
870908 paras [ line $ "Module " ++ runModuleName mn ++ " has unspecified imports, consider using the explicit form: "
871− , indent $ line $ "import " ++ runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
909+ , indent $ line $ showSuggestion msg
872910 ]
873911
874912 renderSimpleErrorMessage (HidingImport mn refs) =
@@ -1009,30 +1047,6 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
10091047 paras :: [Box.Box] -> Box.Box
10101048 paras = Box.vcat Box.left
10111049
1012− -- Pretty print and export declaration
1013− prettyPrintExport :: DeclarationRef -> String
1014− prettyPrintExport (TypeRef pn _) = runProperName pn
1015− prettyPrintExport ref = prettyPrintRef ref
1016−
1017− prettyPrintRef :: DeclarationRef -> String
1018− prettyPrintRef (TypeRef pn Nothing) = runProperName pn ++ "(..)"
1019− prettyPrintRef (TypeRef pn (Just [])) = runProperName pn
1020− prettyPrintRef (TypeRef pn (Just dctors)) = runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
1021− prettyPrintRef (ValueRef ident) = showIdent ident
1022− prettyPrintRef (TypeClassRef pn) = "class " ++ runProperName pn
1023− prettyPrintRef (ProperRef name) = name
1024− prettyPrintRef (TypeInstanceRef ident) = showIdent ident
1025− prettyPrintRef (ModuleRef name) = "module " ++ runModuleName name
1026− prettyPrintRef (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
1027−
1028− prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
1029− prettyPrintImport mn idt qual =
1030− let i = case idt of
1031− Implicit -> runModuleName mn
1032− Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
1033− Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (map prettyPrintRef refs) ++ ")"
1034− in i ++ maybe "" (\q -> " as " ++ runModuleName q) qual
1035−
10361050 -- | Simplify an error message
10371051 simplifyErrorMessage :: ErrorMessage -> ErrorMessage
10381052 simplifyErrorMessage (ErrorMessage hints simple) = ErrorMessage (simplifyHints hints) simple
@@ -1084,6 +1098,30 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
10841098 hintCategory PositionedError{} = PositionHint
10851099 hintCategory _ = OtherHint
10861100
1101+-- Pretty print and export declaration
1102+prettyPrintExport :: DeclarationRef -> String
1103+prettyPrintExport (TypeRef pn _) = runProperName pn
1104+prettyPrintExport ref = prettyPrintRef ref
1105+
1106+prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
1107+prettyPrintImport mn idt qual =
1108+ let i = case idt of
1109+ Implicit -> runModuleName mn
1110+ Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
1111+ Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (map prettyPrintRef refs) ++ ")"
1112+ in i ++ maybe "" (\q -> " as " ++ runModuleName q) qual
1113+
1114+prettyPrintRef :: DeclarationRef -> String
1115+prettyPrintRef (TypeRef pn Nothing) = runProperName pn ++ "(..)"
1116+prettyPrintRef (TypeRef pn (Just [])) = runProperName pn
1117+prettyPrintRef (TypeRef pn (Just dctors)) = runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
1118+prettyPrintRef (ValueRef ident) = showIdent ident
1119+prettyPrintRef (TypeClassRef pn) = "class " ++ runProperName pn
1120+prettyPrintRef (ProperRef name) = name
1121+prettyPrintRef (TypeInstanceRef ident) = showIdent ident
1122+prettyPrintRef (ModuleRef name) = "module " ++ runModuleName name
1123+prettyPrintRef (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
1124+
10871125-- |
10881126-- Pretty print multiple errors
10891127--
src/Language/PureScript/Linter/Imports.hs+7−5
@@ -185,10 +185,9 @@ lintImportDecl env mni qualifierName names declType =
185185 :: (ModuleName -> [DeclarationRef] -> SimpleErrorMessage)
186186 -> m ()
187187 checkImplicit warning =
188− let allRefs = findUsedRefs env mni qualifierName names
189− in if null allRefs
190− then unused
191− else tell $ errorMessage $ warning mni allRefs
188+ if null allRefs
189+ then unused
190+ else tell $ errorMessage $ warning mni allRefs
192191
193192 checkExplicit
194193 :: [DeclarationRef]
@@ -201,7 +200,7 @@ lintImportDecl env mni qualifierName names declType =
201200 case (length diff, length idents) of
202201 (0, _) -> return ()
203202 (n, m) | n == m -> unused
204− _ -> tell $ errorMessage $ UnusedExplicitImport mni diff
203+ _ -> tell $ errorMessage $ UnusedExplicitImport mni diff qualifierName allRefs
205204
206205 -- If we've not already warned a type is unused, check its data constructors
207206 forM_ (mapMaybe getTypeRef declrefs) $ \(tn, c) -> do
@@ -218,6 +217,9 @@ lintImportDecl env mni qualifierName names declType =
218217 unused :: m ()
219218 unused = tell $ errorMessage $ UnusedImport mni
220219
220+ allRefs :: [DeclarationRef]
221+ allRefs = findUsedRefs env mni qualifierName names
222+
221223 dtys
222224 :: ModuleName
223225 -> [((ProperName 'TypeName, [ProperName 'ConstructorName]), ModuleName)]