content: {-# LANGUAGE ConstraintKinds #-}
  {-# LANGUAGE FlexibleContexts #-}
  
  -- | Functions for manipulating 'FFI.Diagnostic's, which represent
  -- diagnostics - warnings, errors, and the like - produced by libclang.
  --
  -- 'FFI.Diagnostic's are grouped into 'FFI.DiagnosticSet's. You
  -- usually obtain a 'FFI.DiagnosticSet' from a 'FFI.TranslationUnit'
  -- using 'Clang.TranslationUnit.getDiagnosticSet', and then analyze it
  -- using the functions in this module.
  --
  -- This module is intended to be imported qualified.
  module Clang.Diagnostic
  (
  -- * Diagnostic sets
    getElements
  
  -- * Diagnostics
  , getChildren
  , getSeverity
  , FFI.Severity(..)
  , getSpelling
  , getOptions
  , getCategoryName
  , getCategoryId
  , getRanges
  , getFixIts
  
  -- * Rendering diagnostics
  , format
  , FFI.DisplayOptions(..)
  
  -- * Deserializing diagnostics
  , load
  , FFI.LoadError(..)
  ) where
  
  import Control.Monad.IO.Class
  
  import Clang.Internal.BitFlags
  import qualified Clang.Internal.FFI as FFI
  import Clang.Internal.Monad
  
  
  -- | Retrieve the diagnostics contained in the given 'FFI.DiagnosticSet'.
  --
  -- You can obtain a 'FFI.DiagnosticSet' from a 'FFI.TranslationUnit'
  -- using 'Clang.TranslationUnit.getDiagnosticSet', or by deserializing
  -- it from a file using 'load'.
  getElements :: ClangBase m => FFI.DiagnosticSet s' -> ClangT s m [FFI.Diagnostic s]
  getElements ds = do
    numDiags <- liftIO $ FFI.getNumDiagnosticsInSet ds
    mapM (FFI.getDiagnosticInSet ds) [0..(numDiags - 1)]
  
  -- | Get the child diagnostics of the given diagnostic.
  getChildren :: ClangBase m => FFI.Diagnostic s' -> ClangT s m (FFI.DiagnosticSet s)
  getChildren = FFI.getChildDiagnostics
  
  -- | Determine the severity of the given diagnostic.
  getSeverity :: ClangBase m => FFI.Diagnostic s' -> ClangT s m FFI.Severity
  getSeverity d = liftIO $ FFI.getDiagnosticSeverity d
  
  -- | Retrieve the text of the given diagnostic.
  getSpelling :: ClangBase m => FFI.Diagnostic s' -> ClangT s m (FFI.ClangString s)
  getSpelling = FFI.getDiagnosticSpelling
  
  -- | Retrieve the name of the command-line option that enabled this diagnostic.
  getOptions :: ClangBase m
             => FFI.Diagnostic s'  -- ^ The diagnostic in question.
             -> ClangT s m (FFI.ClangString s, FFI.ClangString s)  -- ^ The options controlling
                                                                   --   this diagnostic. The
                                                                   --   first member of the pair
                                                                   --   is the option to enable
                                                                   --   this diagnostic. The
                                                                   --   second member is the
                                                                   --   option to disable it.
  getOptions = FFI.getDiagnosticOption
  
  -- | Get the name of the diagnostic category for the given diagnostic.
  --
  -- Diagnostics are categorized into groups along with other,
  -- related diagnostics (e.g., diagnostics under the same warning
  -- flag).
  getCategoryName :: ClangBase m => FFI.Diagnostic s' -> ClangT s m (FFI.ClangString s)
  getCategoryName = FFI.getDiagnosticCategoryText
  
  -- | Retrieve the category id for this diagnostic.
  --
  -- For display to the user, use 'getCategoryName'.
  getCategoryId :: ClangBase m => FFI.Diagnostic s' -> ClangT s m Int
  getCategoryId d = liftIO $ FFI.getDiagnosticCategory d
  
  -- | Retrieve the source ranges associated with this diagnostic.
  --
  -- A diagnostic's source ranges highlight important elements in the
  -- source code. On the command line, Clang displays source ranges by
  -- underlining them with '~' characters.
  getRanges :: ClangBase m => FFI.Diagnostic s' -> ClangT s m [FFI.SourceRange s]
  getRanges d = liftIO $ do
                  numRanges <- FFI.getDiagnosticNumRanges d
                  mapM (FFI.getDiagnosticRange d) [0..(numRanges - 1)]
  
  -- | Retrieve the fix-it hints associated with the given diagnostic.
  --
  -- Fix-its are described in terms of a source range whose contents
  -- should be replaced by a string. This approach generalizes over
  -- three kinds of operations: removal of source code (the range covers
  -- the code to be removed and the replacement string is empty),
  -- replacement of source code (the range covers the code to be
  -- replaced and the replacement string provides the new code), and
  -- insertion (both the start and end of the range point at the
  -- insertion location, and the replacement string provides the text to
  -- insert).
  getFixIts :: ClangBase m
            => FFI.Diagnostic s'  -- ^ The diagnostic in question.
            -> ClangT s m [(FFI.SourceRange s, FFI.ClangString s)]  -- ^ A list of replacement
                                                                    --   ranges and strings. Note
                                                                    --   that source ranges are
                                                                    --   half-open ranges '[a, b)'
                                                                    --   so the source code should
                                                                    --   be replaced from 'a' up
                                                                    --   to (but not including)
                                                                    --   'b'.
  getFixIts d = do
    numFixes <- liftIO $ FFI.getDiagnosticNumFixIts d
    mapM (FFI.getDiagnosticFixIt d) [0..(numFixes - 1)]
  
  -- | Format the given diagnostic in a manner that is suitable for
  -- display.
  format :: ClangBase m
         => Maybe [FFI.DisplayOptions]     -- ^ An optional list of options
                                           --   for rendering the diagnostic.
                                           --   If 'Nothing' is given, default
                                           --   options are used that mimic the
                                           --   behavior of the Clang compiler
                                           --   as closely as possible.
         -> FFI.Diagnostic s'              -- ^ The diagnostic to format.
         -> ClangT s m (FFI.ClangString s) -- ^ A formatted rendering of the
                                           --   given diagnostic.
  format Nothing diag     = FFI.formatDiagnostic diag =<<
                            liftIO FFI.defaultDiagnosticDisplayOptions
  format (Just opts) diag = FFI.formatDiagnostic diag (orFlags opts)
  
  -- | Deserialize a set of diagnostics from a Clang diagnostics bitcode file.
  --
  -- If an error is encountered, a 'FFI.LoadError' and a textual error
  -- message suitable for display to the user are returned.
  load :: ClangBase m
       => FilePath
       -> ClangT s m (Either (FFI.LoadError, FFI.ClangString s) (FFI.DiagnosticSet s))
  load = FFI.loadDiagnostics
  