    -- | Various fixups in the introspection data.
    module Data.GI.CodeGen.Fixups
        ( dropMovedItems
        , guessPropertyNullability
        , detectGObject
        , dropDuplicatedFields
        , checkClosureDestructors
        , fixClosures
        , fixCallbackUserData
        , fixSymbolNaming
        ) where

    import Data.Char (generalCategory, GeneralCategory(UppercaseLetter))
    import Data.Maybe (fromMaybe, isNothing, isJust)
    import qualified Data.Map as M
    #if !MIN_VERSION_base(4,13,0)
    import Data.Monoid ((<>))
    #endif
    import qualified Data.Set as S
    import qualified Data.Text as T

    import Data.GI.CodeGen.Type
    import Data.GI.CodeGen.API

    -- | Remove functions and methods annotated with "moved-to".
    dropMovedItems :: API -> Maybe API
    dropMovedItems :: API -> Maybe API
    dropMovedItems (APIFunction Function
    f) = if Function -> Maybe Text
    fnMovedTo Function
    f Maybe Text -> Maybe Text -> Bool
    forall a. Eq a => a -> a -> Bool
    == Maybe Text
    forall a. Maybe a
    Nothing
                                     then API -> Maybe API
    forall a. a -> Maybe a
    Just (Function -> API
    APIFunction Function
    f)
                                     else Maybe API
    forall a. Maybe a
    Nothing
    dropMovedItems (APIInterface Interface
    i) =
        (API -> Maybe API
    forall a. a -> Maybe a
    Just (API -> Maybe API) -> (Interface -> API) -> Interface -> Maybe API
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Interface -> API
    APIInterface) Interface
    i {ifMethods = filterMovedMethods (ifMethods i)}
    dropMovedItems (APIObject Object
    o) =
        (API -> Maybe API
    forall a. a -> Maybe a
    Just (API -> Maybe API) -> (Object -> API) -> Object -> Maybe API
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Object -> API
    APIObject) Object
    o {objMethods = filterMovedMethods (objMethods o)}
    dropMovedItems (APIStruct Struct
    s) =
        (API -> Maybe API
    forall a. a -> Maybe a
    Just (API -> Maybe API) -> (Struct -> API) -> Struct -> Maybe API
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Struct -> API
    APIStruct) Struct
    s {structMethods = filterMovedMethods (structMethods s)}
    dropMovedItems (APIUnion Union
    u) =
        (API -> Maybe API
    forall a. a -> Maybe a
    Just (API -> Maybe API) -> (Union -> API) -> Union -> Maybe API
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Union -> API
    APIUnion) Union
    u {unionMethods = filterMovedMethods (unionMethods u)}
    dropMovedItems API
    a = API -> Maybe API
    forall a. a -> Maybe a
    Just API
    a

    -- | Drop the moved methods.
    filterMovedMethods :: [Method] -> [Method]
    filterMovedMethods :: [Method] -> [Method]
    filterMovedMethods = (Method -> Bool) -> [Method] -> [Method]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Maybe Text -> Bool
    forall a. Maybe a -> Bool
    isNothing (Maybe Text -> Bool) -> (Method -> Maybe Text) -> Method -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Method -> Maybe Text
    methodMovedTo)

    -- | GObject-introspection does not currently support nullability
    -- annotations, so we try to guess the nullability from the
    -- nullability annotations of the curresponding get/set methods, which
    -- in principle should be reliable.
    guessPropertyNullability :: (Name, API) -> (Name, API)
    guessPropertyNullability :: (Name, API) -> (Name, API)
    guessPropertyNullability (Name
    n, APIObject Object
    obj) =
        (Name
    n, Object -> API
    APIObject (Object -> Object
    guessObjectPropertyNullability Object
    obj))
    guessPropertyNullability (Name
    n, APIInterface Interface
    iface) =
        (Name
    n, Interface -> API
    APIInterface (Interface -> Interface
    guessInterfacePropertyNullability Interface
    iface))
    guessPropertyNullability (Name, API)
    other = (Name, API)
    other

    -- | Guess nullability for the properties of an object.
    guessObjectPropertyNullability :: Object -> Object
    guessObjectPropertyNullability :: Object -> Object
    guessObjectPropertyNullability Object
    obj =
        Object
    obj {objProperties = map (guessNullability (objMethods obj))
                             (objProperties obj)}

    -- | Guess nullability for the properties of an interface.
    guessInterfacePropertyNullability :: Interface -> Interface
    guessInterfacePropertyNullability :: Interface -> Interface
    guessInterfacePropertyNullability Interface
    iface =
        Interface
    iface { ifProperties = map (guessNullability (ifMethods iface))
                                  (ifProperties iface)}

    -- | Guess the nullability for a property, given the list of methods
    -- for the object/interface.
    guessNullability :: [Method] -> Property -> Property
    guessNullability :: [Method] -> Property -> Property
    guessNullability [Method]
    methods = [Method] -> Property -> Property
    guessReadNullability [Method]
    methods
                               (Property -> Property)
    -> (Property -> Property) -> Property -> Property
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Method] -> Property -> Property
    guessWriteNullability [Method]
    methods

    -- | Guess whether "get" on the given property may return NULL, based
    -- on the corresponding "get_prop_name" method, if it exists.
    guessReadNullability :: [Method] -> Property -> Property
    guessReadNullability :: [Method] -> Property -> Property
    guessReadNullability [Method]
    methods Property
    p
        | Maybe Bool -> Bool
    forall a. Maybe a -> Bool
    isJust (Property -> Maybe Bool
    propReadNullable Property
    p) = Property
    p
        | Bool
    otherwise = Property
    p {propReadNullable = nullableGetter}
        where
          nullableGetter :: Maybe Bool
          nullableGetter :: Maybe Bool
    nullableGetter =
              let prop_name :: Text
    prop_name = HasCallStack => Text -> Text -> Text -> Text
    Text -> Text -> Text -> Text
    T.replace Text
    "-" Text
    "_" (Property -> Text
    propName Property
    p)
                  getter :: Text
    getter = Text -> Maybe Text -> Text
    forall a. a -> Maybe a -> a
    fromMaybe (Text
    "get_" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    prop_name) (Property -> Maybe Text
    propGetter Property
    p)
              in case [Method] -> Text -> Maybe Method
    findMethod [Method]
    methods Text
    getter of
                   Maybe Method
    Nothing -> Maybe Bool
    forall a. Maybe a
    Nothing
                   -- Check that it looks like a sensible getter
                   -- for the property.
                   Just Method
    m ->
                       let c :: Callable
    c = Method -> Callable
    methodCallable Method
    m
                       in if [Arg] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length (Callable -> [Arg]
    args Callable
    c) Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    1 Bool -> Bool -> Bool
    &&
                          Callable -> Maybe Type
    returnType Callable
    c Maybe Type -> Maybe Type -> Bool
    forall a. Eq a => a -> a -> Bool
    == Type -> Maybe Type
    forall a. a -> Maybe a
    Just (Property -> Type
    propType Property
    p) Bool -> Bool -> Bool
    &&
                          Callable -> Transfer
    returnTransfer Callable
    c Transfer -> Transfer -> Bool
    forall a. Eq a => a -> a -> Bool
    == Transfer
    TransferNothing Bool -> Bool -> Bool
    &&
                          Callable -> Bool
    skipReturn Callable
    c Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Bool
    False Bool -> Bool -> Bool
    &&
                          Callable -> Bool
    callableThrows Callable
    c Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Bool
    False Bool -> Bool -> Bool
    &&
                          Method -> MethodType
    methodType Method
    m MethodType -> MethodType -> Bool
    forall a. Eq a => a -> a -> Bool
    == MethodType
    OrdinaryMethod Bool -> Bool -> Bool
    &&
                          Method -> Maybe Text
    methodMovedTo Method
    m Maybe Text -> Maybe Text -> Bool
    forall a. Eq a => a -> a -> Bool
    == Maybe Text
    forall a. Maybe a
    Nothing
                          then Bool -> Maybe Bool
    forall a. a -> Maybe a
    Just (Callable -> Bool
    returnMayBeNull Callable
    c)
                          else Maybe Bool
    forall a. Maybe a
    Nothing

    -- | Guess whether "set" on the given property may return NULL, based
    -- on the corresponding "set_prop_name" method, if it exists.
    guessWriteNullability :: [Method] -> Property -> Property
    guessWriteNullability :: [Method] -> Property -> Property
    guessWriteNullability [Method]
    methods Property
    p
        | Maybe Bool -> Bool
    forall a. Maybe a -> Bool
    isJust (Property -> Maybe Bool
    propWriteNullable Property
    p) = Property
    p
        | Bool
    otherwise = Property
    p {propWriteNullable = nullableSetter}
        where
          nullableSetter :: Maybe Bool
          nullableSetter :: Maybe Bool
    nullableSetter =
              let prop_name :: Text
    prop_name = HasCallStack => Text -> Text -> Text -> Text
    Text -> Text -> Text -> Text
    T.replace Text
    "-" Text
    "_" (Property -> Text
    propName Property
    p)
                  setter :: Text
    setter = Text -> Maybe Text -> Text
    forall a. a -> Maybe a -> a
    fromMaybe (Text
    "set_" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    prop_name) (Property -> Maybe Text
    propSetter Property
    p)
              in case [Method] -> Text -> Maybe Method
    findMethod [Method]
    methods Text
    setter of
                   Maybe Method
    Nothing -> Maybe Bool
    forall a. Maybe a
    Nothing
                   -- Check that it looks like a sensible setter.
                   Just Method
    m ->
                       let c :: Callable
    c = Method -> Callable
    methodCallable Method
    m
                       in if [Arg] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length (Callable -> [Arg]
    args Callable
    c) Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    2 Bool -> Bool -> Bool
    &&
                              (Arg -> Type
    argType (Arg -> Type) -> (Callable -> Arg) -> Callable -> Type
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Arg] -> Arg
    forall a. HasCallStack => [a] -> a
    last ([Arg] -> Arg) -> (Callable -> [Arg]) -> Callable -> Arg
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Callable -> [Arg]
    args) Callable
    c Type -> Type -> Bool
    forall a. Eq a => a -> a -> Bool
    == Property -> Type
    propType Property
    p Bool -> Bool -> Bool
    &&
                              Callable -> Maybe Type
    returnType Callable
    c Maybe Type -> Maybe Type -> Bool
    forall a. Eq a => a -> a -> Bool
    == Maybe Type
    forall a. Maybe a
    Nothing Bool -> Bool -> Bool
    &&
                              (Arg -> Transfer
    transfer (Arg -> Transfer) -> (Callable -> Arg) -> Callable -> Transfer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Arg] -> Arg
    forall a. HasCallStack => [a] -> a
    last ([Arg] -> Arg) -> (Callable -> [Arg]) -> Callable -> Arg
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Callable -> [Arg]
    args) Callable
    c Transfer -> Transfer -> Bool
    forall a. Eq a => a -> a -> Bool
    == Transfer
    TransferNothing Bool -> Bool -> Bool
    &&
                              (Arg -> Direction
    direction (Arg -> Direction) -> (Callable -> Arg) -> Callable -> Direction
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Arg] -> Arg
    forall a. HasCallStack => [a] -> a
    last ([Arg] -> Arg) -> (Callable -> [Arg]) -> Callable -> Arg
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Callable -> [Arg]
    args) Callable
    c Direction -> Direction -> Bool
    forall a. Eq a => a -> a -> Bool
    == Direction
    DirectionIn Bool -> Bool -> Bool
    &&
                              Method -> Maybe Text
    methodMovedTo Method
    m Maybe Text -> Maybe Text -> Bool
    forall a. Eq a => a -> a -> Bool
    == Maybe Text
    forall a. Maybe a
    Nothing Bool -> Bool -> Bool
    &&
                              Method -> MethodType
    methodType Method
    m MethodType -> MethodType -> Bool
    forall a. Eq a => a -> a -> Bool
    == MethodType
    OrdinaryMethod Bool -> Bool -> Bool
    &&
                              Callable -> Bool
    callableThrows Callable
    c Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Bool
    False
                          then Bool -> Maybe Bool
    forall a. a -> Maybe a
    Just ((Arg -> Bool
    mayBeNull (Arg -> Bool) -> (Callable -> Arg) -> Callable -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Arg] -> Arg
    forall a. HasCallStack => [a] -> a
    last ([Arg] -> Arg) -> (Callable -> [Arg]) -> Callable -> Arg
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Callable -> [Arg]
    args) Callable
    c)
                          else Maybe Bool
    forall a. Maybe a
    Nothing

    -- | Find the first method with the given name, if any.
    findMethod :: [Method] -> T.Text -> Maybe Method
    findMethod :: [Method] -> Text -> Maybe Method
    findMethod [Method]
    methods Text
    n = case (Method -> Bool) -> [Method] -> [Method]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Text -> Text -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text
    n) (Text -> Bool) -> (Method -> Text) -> Method -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Name -> Text
    name (Name -> Text) -> (Method -> Name) -> Method -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Method -> Name
    methodName) [Method]
    methods of
                             [Method
    m] -> Method -> Maybe Method
    forall a. a -> Maybe a
    Just Method
    m
                             [Method]
    _ -> Maybe Method
    forall a. Maybe a
    Nothing

    -- | Not every interface that provides signals/properties is marked as
    -- requiring GObject, but this is necessarily the case, so fix the
    -- introspection data accordingly.
    detectGObject :: (Name, API) -> (Name, API)
    detectGObject :: (Name, API) -> (Name, API)
    detectGObject (Name
    n, APIInterface Interface
    iface) =
      if Bool -> Bool
    not ([Property] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (Interface -> [Property]
    ifProperties Interface
    iface) Bool -> Bool -> Bool
    && [Signal] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (Interface -> [Signal]
    ifSignals Interface
    iface))
      then let gobject :: Name
    gobject = Text -> Text -> Name
    Name Text
    "GObject" Text
    "Object"
           in if Name
    gobject Name -> [Name] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` (Interface -> [Name]
    ifPrerequisites Interface
    iface)
              then (Name
    n, Interface -> API
    APIInterface Interface
    iface)
              else (Name
    n, Interface -> API
    APIInterface (Interface
    iface {ifPrerequisites =
                                            gobject : ifPrerequisites iface}))
      else (Name
    n, Interface -> API
    APIInterface Interface
    iface)
    detectGObject (Name, API)
    api = (Name, API)
    api

    -- | Drop any fields whose name coincides with that of a previous
    -- element. Note that this function keeps ordering.
    dropDuplicatedEnumFields :: Enumeration -> Enumeration
    dropDuplicatedEnumFields :: Enumeration -> Enumeration
    dropDuplicatedEnumFields Enumeration
    enum =
      Enumeration
    enum{enumMembers = dropDuplicates S.empty (enumMembers enum)}
      where dropDuplicates :: S.Set T.Text -> [EnumerationMember] -> [EnumerationMember]
            dropDuplicates :: Set Text -> [EnumerationMember] -> [EnumerationMember]
    dropDuplicates Set Text
    _        []     = []
            dropDuplicates Set Text
    previous (EnumerationMember
    m:[EnumerationMember]
    ms) =
              if EnumerationMember -> Text
    enumMemberName EnumerationMember
    m Text -> Set Text -> Bool
    forall a. Ord a => a -> Set a -> Bool
    `S.member` Set Text
    previous
              then Set Text -> [EnumerationMember] -> [EnumerationMember]
    dropDuplicates Set Text
    previous [EnumerationMember]
    ms
              else EnumerationMember
    m EnumerationMember -> [EnumerationMember] -> [EnumerationMember]
    forall a. a -> [a] -> [a]
    : Set Text -> [EnumerationMember] -> [EnumerationMember]
    dropDuplicates (Text -> Set Text -> Set Text
    forall a. Ord a => a -> Set a -> Set a
    S.insert (EnumerationMember -> Text
    enumMemberName EnumerationMember
    m) Set Text
    previous) [EnumerationMember]
    ms

    -- | Some libraries include duplicated flags by mistake, drop those.
    dropDuplicatedFields :: (Name, API) -> (Name, API)
    dropDuplicatedFields :: (Name, API) -> (Name, API)
    dropDuplicatedFields (Name
    n, APIFlags (Flags Enumeration
    enum)) =
      (Name
    n, Flags -> API
    APIFlags (Enumeration -> Flags
    Flags (Enumeration -> Flags) -> Enumeration -> Flags
    forall a b. (a -> b) -> a -> b
    $ Enumeration -> Enumeration
    dropDuplicatedEnumFields Enumeration
    enum))
    dropDuplicatedFields (Name
    n, API
    api) = (Name
    n, API
    api)

    -- | Sometimes arguments are marked as being a user_data destructor,
    -- but there is no associated user_data argument. In this case we drop
    -- the annotation.
    checkClosureDestructors :: (Name, API) -> (Name, API)
    checkClosureDestructors :: (Name, API) -> (Name, API)
    checkClosureDestructors (Name
    n, APIObject Object
    o) =
      (Name
    n, Object -> API
    APIObject (Object
    o {objMethods = checkMethodDestructors (objMethods o)}))
    checkClosureDestructors (Name
    n, APIInterface Interface
    i) =
      (Name
    n, Interface -> API
    APIInterface (Interface
    i {ifMethods = checkMethodDestructors (ifMethods i)}))
    checkClosureDestructors (Name
    n, APIStruct Struct
    s) =
      (Name
    n, Struct -> API
    APIStruct (Struct
    s {structMethods = checkMethodDestructors (structMethods s)}))
    checkClosureDestructors (Name
    n, APIUnion Union
    u) =
      (Name
    n, Union -> API
    APIUnion (Union
    u {unionMethods = checkMethodDestructors (unionMethods u)}))
    checkClosureDestructors (Name
    n, APIFunction Function
    f) =
      (Name
    n, Function -> API
    APIFunction (Function
    f {fnCallable = checkCallableDestructors (fnCallable f)}))
    checkClosureDestructors (Name
    n, API
    api) = (Name
    n, API
    api)

    checkMethodDestructors :: [Method] -> [Method]
    checkMethodDestructors :: [Method] -> [Method]
    checkMethodDestructors = (Method -> Method) -> [Method] -> [Method]
    forall a b. (a -> b) -> [a] -> [b]
    map Method -> Method
    checkMethod
      where checkMethod :: Method -> Method
            checkMethod :: Method -> Method
    checkMethod Method
    m = Method
    m {methodCallable =
                                 checkCallableDestructors (methodCallable m)}

    -- | If any argument for the callable has an associated destroyer for
    -- the user_data, but no associated user_data, drop the destroyer
    -- annotation.
    checkCallableDestructors :: Callable -> Callable
    checkCallableDestructors :: Callable -> Callable
    checkCallableDestructors Callable
    c = Callable
    c {args = map checkArg (args c)}
      where checkArg :: Arg -> Arg
            checkArg :: Arg -> Arg
    checkArg Arg
    arg = if Arg -> Int
    argDestroy Arg
    arg Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Int
    0 Bool -> Bool -> Bool
    && Arg -> Int
    argClosure Arg
    arg Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == -Int
    1
                           then Arg
    arg {argDestroy = -1}
                           else Arg
    arg

    -- | Sometimes it is the callback that is annotated with the (closure
    -- user_data) annotation, and sometimes the user_data parameter
    -- itself, with (closure callback) pointing to the callback. The
    -- following code makes sure that the annotation is on the callable
    -- only. Note that this goes against the official gobject
    -- introspection spec, but there is more code using this convention
    -- than otherwise, and the gir generator seems to add closure
    -- annotations in both directions when using the new convention
    -- anyway.
    fixCallableClosures :: Callable -> Callable
    fixCallableClosures :: Callable -> Callable
    fixCallableClosures Callable
    c = Callable
    c {args = map fixupArg (zip [0..] (args c))}
      where fixupArg :: (Int, Arg) -> Arg
            fixupArg :: (Int, Arg) -> Arg
    fixupArg (Int
    n, Arg
    arg) = if Arg -> Bool
    isUserData Arg
    arg
                                then Arg
    arg {argClosure = -1}
                                else
                                  case Int -> Map Int Int -> Maybe Int
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup Int
    n Map Int Int
    reverseMap of
                                    Just Int
    user_data -> Arg
    arg {argClosure = user_data}
                                    Maybe Int
    Nothing -> Arg
    arg

            -- Map from callbacks to their corresponding user_data
            -- arguments, obtained by looking to the argClosure value for
            -- the user_data argument.
            reverseMap :: M.Map Int Int
            reverseMap :: Map Int Int
    reverseMap = [(Int, Int)] -> Map Int Int
    forall k a. Ord k => [(k, a)] -> Map k a
    M.fromList
              ([(Int, Int)] -> Map Int Int)
    -> ([(Int, Arg)] -> [(Int, Int)]) -> [(Int, Arg)] -> Map Int Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((Int, Arg) -> (Int, Int)) -> [(Int, Arg)] -> [(Int, Int)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\(Int
    n, Arg
    arg) -> (Arg -> Int
    argClosure Arg
    arg, Int
    n))
              ([(Int, Arg)] -> [(Int, Int)])
    -> ([(Int, Arg)] -> [(Int, Arg)]) -> [(Int, Arg)] -> [(Int, Int)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((Int, Arg) -> Bool) -> [(Int, Arg)] -> [(Int, Arg)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Arg -> Bool
    isUserData (Arg -> Bool) -> ((Int, Arg) -> Arg) -> (Int, Arg) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Int, Arg) -> Arg
    forall a b. (a, b) -> b
    snd)
              ([(Int, Arg)] -> [(Int, Arg)])
    -> ([(Int, Arg)] -> [(Int, Arg)]) -> [(Int, Arg)] -> [(Int, Arg)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((Int, Arg) -> Bool) -> [(Int, Arg)] -> [(Int, Arg)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= -Int
    1) (Int -> Bool) -> ((Int, Arg) -> Int) -> (Int, Arg) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Arg -> Int
    argClosure (Arg -> Int) -> ((Int, Arg) -> Arg) -> (Int, Arg) -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Int, Arg) -> Arg
    forall a b. (a, b) -> b
    snd)
              ([(Int, Arg)] -> Map Int Int) -> [(Int, Arg)] -> Map Int Int
    forall a b. (a -> b) -> a -> b
    $ [Int] -> [Arg] -> [(Int, Arg)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Int
    0..] (Callable -> [Arg]
    args Callable
    c)

            isUserData :: Arg -> Bool
            isUserData :: Arg -> Bool
    isUserData Arg
    arg = Arg -> Scope
    argScope Arg
    arg Scope -> Scope -> Bool
    forall a. Eq a => a -> a -> Bool
    == Scope
    ScopeTypeInvalid Bool -> Bool -> Bool
    ||
                             Arg -> Type
    argType Arg
    arg Type -> Type -> Bool
    forall a. Eq a => a -> a -> Bool
    == BasicType -> Type
    TBasicType BasicType
    TPtr

    -- | Closures are often incorrectly assigned, with the closure
    -- annotation on the callback, instead of in the closure (user_data)
    -- parameter itself. The following makes sure that things are as they
    -- should.
    fixClosures :: (Name, API) -> (Name, API)
    fixClosures :: (Name, API) -> (Name, API)
    fixClosures (Name
    n, APIObject Object
    o) =
      (Name
    n, Object -> API
    APIObject (Object
    o {objMethods = fixMethodClosures (objMethods o)}))
    fixClosures (Name
    n, APIInterface Interface
    i) =
      (Name
    n, Interface -> API
    APIInterface (Interface
    i {ifMethods = fixMethodClosures (ifMethods i)}))
    fixClosures (Name
    n, APIStruct Struct
    s) =
      (Name
    n, Struct -> API
    APIStruct (Struct
    s {structMethods = fixMethodClosures (structMethods s)}))
    fixClosures (Name
    n, APIUnion Union
    u) =
      (Name
    n, Union -> API
    APIUnion (Union
    u {unionMethods = fixMethodClosures (unionMethods u)}))
    fixClosures (Name
    n, APIFunction Function
    f) =
      (Name
    n, Function -> API
    APIFunction (Function
    f {fnCallable = fixCallableClosures (fnCallable f)}))
    fixClosures (Name
    n, API
    api) = (Name
    n, API
    api)

    fixMethodClosures :: [Method] -> [Method]
    fixMethodClosures :: [Method] -> [Method]
    fixMethodClosures = (Method -> Method) -> [Method] -> [Method]
    forall a b. (a -> b) -> [a] -> [b]
    map Method -> Method
    fixMethod
      where fixMethod :: Method -> Method
            fixMethod :: Method -> Method
    fixMethod Method
    m = Method
    m {methodCallable =
                                fixCallableClosures (methodCallable m)}

    -- | The last argument of callbacks is often a @user_data@ argument,
    -- but currently gobject-introspection does not have an annotation
    -- representing this. This is generally OK, since the gir generator
    -- will mark these arguments as @(closure)@ if they are named
    -- @user_data@, and we do the right things in this case, but recently
    -- there has been a push to "fix" these annotations by removing them
    -- without providing any replacement, which breaks the bindings. See
    -- https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/450
    -- Here we try to guess which arguments in callbacks are user_data
    -- arguments.
    fixCallbackUserData :: (Name, API) -> (Name, API)
    fixCallbackUserData :: (Name, API) -> (Name, API)
    fixCallbackUserData (Name
    n, APICallback Callback
    cb) =
      (Name
    n, Callback -> API
    APICallback (Callback
    cb {cbCallable = fixCallableUserData (cbCallable cb)}))
    fixCallbackUserData (Name
    n, API
    api) = (Name
    n, API
    api)

    -- | Any argument with a closure index pointing to itself is a
    -- "user_data" type argument.
    fixCallableUserData :: Callable -> Callable
    fixCallableUserData :: Callable -> Callable
    fixCallableUserData Callable
    c = Callable
    c {args = fixLast 0 (args c)}
      where
        fixLast :: Int -> [Arg] -> [Arg]
        fixLast :: Int -> [Arg] -> [Arg]
    fixLast Int
    _ [] = []
        fixLast Int
    n (Arg
    arg:[])
          | Arg -> Type
    argType Arg
    arg Type -> Type -> Bool
    forall a. Eq a => a -> a -> Bool
    == BasicType -> Type
    TBasicType BasicType
    TPtr Bool -> Bool -> Bool
    &&
            Arg -> Int
    argClosure Arg
    arg Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    n =
              [Arg
    arg {argClosure = -1, argCallbackUserData = True}]
          | Bool
    otherwise = [Arg
    arg]
        fixLast Int
    n (Arg
    arg:[Arg]
    rest) = Arg
    arg Arg -> [Arg] -> [Arg]
    forall a. a -> [a] -> [a]
    : Int -> [Arg] -> [Arg]
    fixLast (Int
    nInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    1) [Arg]
    rest

    -- | Some symbols have names that are not valid Haskell identifiers,
    -- fix that here.
    fixSymbolNaming :: (Name, API) -> (Name, API)
    fixSymbolNaming :: (Name, API) -> (Name, API)
    fixSymbolNaming (Name
    n, APIConst Constant
    c) = (Name -> Name
    fixConstantName Name
    n, Constant -> API
    APIConst Constant
    c)
    fixSymbolNaming (Name
    n, API
    api) = (Name
    n, API
    api)

    -- | Make sure that the given name is a valid Haskell identifier in
    -- patterns.
    --
    -- === __Examples__
    -- >>> fixConstantName (Name "IBus" "0")
    -- Name {namespace = "IBus", name = "C'0"}
    --
    -- >>> fixConstantName (Name "IBus" "a")
    -- Name {namespace = "IBus", name = "C'a"}
    --
    -- >>> fixConstantName (Name "IBus" "A")
    -- Name {namespace = "IBus", name = "A"}
    fixConstantName :: Name -> Name
    fixConstantName :: Name -> Name
    fixConstantName (Name Text
    ns Text
    n)
      | Bool -> Bool
    not (Text -> Bool
    T.null Text
    n) Bool -> Bool -> Bool
    && Char -> GeneralCategory
    generalCategory (HasCallStack => Text -> Char
    Text -> Char
    T.head Text
    n) GeneralCategory -> GeneralCategory -> Bool
    forall a. Eq a => a -> a -> Bool
    /= GeneralCategory
    UppercaseLetter
      = Text -> Text -> Name
    Name Text
    ns (Text
    "C'" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    n)
      | Bool
    otherwise = Text -> Text -> Name
    Name Text
    ns Text
    n