packages feed

clang-pure 0.2.0.2 → 0.2.0.3

raw patch · 11 files changed

+220/−98 lines, 11 filessetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Language.C.Clang.Type: typeArraySize :: Type -> Maybe Word64
+ Language.C.Clang.Type: typeCanonicalType :: Type -> Type
+ Language.C.Clang.Type: typeElementType :: Type -> Maybe Type
+ Language.C.Clang.Type: typeSizeOf :: Type -> Either TypeLayoutError Word64
- Language.C.Clang.Cursor.Typed: cursorDescendants :: CursorK kind -> [Cursor]
+ Language.C.Clang.Cursor.Typed: cursorDescendants :: HasChildren kind => CursorK kind -> [Cursor]
- Language.C.Clang.Cursor.Typed: cursorDescendantsF :: Fold (CursorK kind) Cursor
+ Language.C.Clang.Cursor.Typed: cursorDescendantsF :: HasChildren kind => Fold (CursorK kind) Cursor
- Language.C.Clang.Cursor.Typed: offsetOfField :: CursorK FieldDecl -> Either TypeLayoutError Word64
+ Language.C.Clang.Cursor.Typed: offsetOfField :: CursorK 'FieldDecl -> Either TypeLayoutError Word64
- Language.C.Clang.Cursor.Typed: translationUnitCursor :: TranslationUnit -> CursorK TranslationUnit
+ Language.C.Clang.Cursor.Typed: translationUnitCursor :: TranslationUnit -> CursorK 'TranslationUnit

Files

Setup.hs view
@@ -15,6 +15,7 @@  {-# LANGUAGE CPP #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -Wall #-}  module Main (main) where@@ -25,13 +26,14 @@ import Distribution.Simple import Distribution.Simple.LocalBuildInfo import Distribution.Simple.Setup+import Distribution.Simple.Configure+import Distribution.Simple.Utils+import Distribution.Verbosity import System.Environment import System.IO.Error import System.Process--data SetupException = SetupException String deriving Show--instance Exception SetupException+import qualified Data.Version as Version+import Text.ParserCombinators.ReadP  data LLVMPathInfo = LLVMPathInfo   { llvmLibraryDir :: FilePath@@ -44,57 +46,94 @@ llvmIncludeDirEnvVarName :: String llvmIncludeDirEnvVarName = "CLANG_PURE_LLVM_INCLUDE_DIR" -findLLVMConfigPaths :: IO LLVMPathInfo-findLLVMConfigPaths = do+minVersion :: Version.Version+minVersion = Version.makeVersion [ 3, 8, 0 ]++#if !(MIN_VERSION_Cabal(2, 0, 0))+die' :: Verbosity -> String -> IO a+die' _ = die+#endif++findLLVMConfigPaths :: Verbosity -> IO LLVMPathInfo+findLLVMConfigPaths verbosity = do   let llvmConfigCandidates =         "llvm-config" :           [ "llvm-config-" ++ show major ++ "." ++ show minor           | major <- [9,8..3 :: Int]           , minor <- [9,8..0 :: Int]           ]-  let tryCandidates [] = throwIO $ SetupException "Could not find llvm-config."+  let tryCandidates [] = die' verbosity $ "Could not find llvm-config with minimum version " ++ Version.showVersion minVersion ++ "."       tryCandidates (llvmConfig : candidates) = do-        llvmConfigResult <- tryJust (guard . isDoesNotExistError) (readProcess llvmConfig ["--libdir", "--includedir"] "")+        llvmConfigResult <- tryJust+          (guard . isDoesNotExistError)+          (readProcess llvmConfig ["--version", "--libdir", "--includedir"] "")         case llvmConfigResult of-          Left _ -> tryCandidates candidates-          Right llvmConfigOutput -> case lines llvmConfigOutput of-            [ libraryDir, includeDir ] -> return $ LLVMPathInfo libraryDir includeDir-            _ -> throwIO $ SetupException "Unexpected llvm-config output."+          Left _ -> do+            putStrLn ("Could not execute " ++ llvmConfig)+            tryCandidates candidates+          Right llvmConfigOutput -> do+            putStrLn ("Found " ++ llvmConfig)+            case lines llvmConfigOutput of+              [ versionString, libraryDir, includeDir ] ->+                case readP_to_S (Version.parseVersion <* eof) versionString of+                  [ ( version, _ ) ]+                    | version >= minVersion -> return $ LLVMPathInfo libraryDir includeDir+                    | otherwise -> do+                      putStrLn ("Version too low: " ++ show version)+                      tryCandidates candidates+                  _ -> die' verbosity "Couldn't parse llvm-config version string."+              _ -> die' verbosity "Unexpected llvm-config output."   tryCandidates llvmConfigCandidates -getLLVMPathInfo :: IO LLVMPathInfo-getLLVMPathInfo = do+getLLVMPathInfo :: Verbosity -> IO LLVMPathInfo+getLLVMPathInfo verbosity = do   m'llvmLibDirEnvVar <- lookupEnv llvmLibDirEnvVarName   m'llvmIncludeDirEnvVar <- lookupEnv llvmIncludeDirEnvVarName   case (m'llvmLibDirEnvVar, m'llvmIncludeDirEnvVar) of     ( Just libraryDir, Just includeDir ) -> return $ LLVMPathInfo libraryDir includeDir-    _ -> findLLVMConfigPaths+    _ -> findLLVMConfigPaths verbosity  clangPureConfHook :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo clangPureConfHook (d, bi) flags = do   localBuildInfo <- confHook simpleUserHooks (d, bi) flags   let pd = localPkgDescr localBuildInfo-  let Just lib = library pd-  let lbi = libBuildInfo lib -  LLVMPathInfo{..} <- getLLVMPathInfo+  -- see if it just works (eg on Nix)+  mbError <- try $ checkForeignDeps pd localBuildInfo normal -  return localBuildInfo {-    localPkgDescr = pd {-      library = Just $ lib {-        libBuildInfo = lbi-        { includeDirs = llvmIncludeDir : includeDirs lbi-        , extraLibDirs = llvmLibraryDir : extraLibDirs lbi-        , cSources = -- define the generated c-sources here so that they don't get picked up by sdist-#ifdef mingw32_HOST_OS-            ["srcLanguageCClangInternalFFI.c"] -- work around a bug in inline-c (?)+  let verbosity = fromFlagOrDefault normal (configVerbosity flags)++  let addCSources libBuildInfo =+        libBuildInfo+#if !(MIN_VERSION_GLASGOW_HASKELL(8, 2, 1, 0) && MIN_VERSION_inline_c(0, 6, 0))+          { cSources = -- define the generated c-sources here so that they don't get picked up by sdist+#if defined(mingw32_HOST_OS) && !(MIN_VERSION_GLASGOW_HASKELL(8, 0, 2, 0))+              ["srcLanguageCClangInternalFFI.c"] -- work around a bug in hsc2hs #else-            ["src/Language/C/Clang/Internal/FFI.c"]+              ["src/Language/C/Clang/Internal/FFI.c"] #endif+          }+#endif++  addDirs <- case mbError of+    Right () -> return id+    Left (_ :: SomeException) -> do+      warn verbosity "Couldn't find libclang, attempting to find it with llvm-config or environment variables..."++      LLVMPathInfo{..} <- getLLVMPathInfo verbosity++      return $ \libBuildInfo -> libBuildInfo+        { includeDirs = llvmIncludeDir : includeDirs libBuildInfo+        , extraLibDirs = llvmLibraryDir : extraLibDirs libBuildInfo         }++  let Just lib = library pd+  let lbi = libBuildInfo lib+  return localBuildInfo+    { localPkgDescr = pd+      { library = Just lib { libBuildInfo = addDirs $ addCSources lbi }       }     }-  }  main :: IO () main = defaultMainWithHooks simpleUserHooks { confHook = clangPureConfHook }
+ cbits/clang-pure-utils.h view
@@ -0,0 +1,35 @@+/*+Copyright 2014 Google Inc. All Rights Reserved.++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+*/++typedef void (*haskell_visitor)(CXCursor*);++// Macro that evaluates to a copy on the heap of the result of a given expression.+#define ALLOC(__ALLOC_EXPR__) ({\+  typeof (__ALLOC_EXPR__) __alloc_res__ = (__ALLOC_EXPR__);\+  typeof (__ALLOC_EXPR__) *__alloc_ptr__ = malloc(sizeof(__alloc_res__));\+  *__alloc_ptr__ = __alloc_res__;\+  __alloc_ptr__;\+  })++// Traverse children using a haskell_visitor passed in as client_data.+// The visitor gets a copy of the cursor on the heap and is responsible+// for freeing it.+static enum CXChildVisitResult visit_haskell(CXCursor cursor,+                                             CXCursor parent,+                                             CXClientData client_data) {+  ((haskell_visitor) client_data)(ALLOC(cursor));+  return CXChildVisit_Continue;+};
− cbits/utils.h
@@ -1,35 +0,0 @@-/*-Copyright 2014 Google Inc. All Rights Reserved.--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at--    http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.-*/--typedef void (*haskell_visitor)(CXCursor*);--// Macro that evaluates to a copy on the heap of the result of a given expression.-#define ALLOC(__ALLOC_EXPR__) ({\-  typeof (__ALLOC_EXPR__) __alloc_res__ = (__ALLOC_EXPR__);\-  typeof (__ALLOC_EXPR__) *__alloc_ptr__ = malloc(sizeof(__alloc_res__));\-  *__alloc_ptr__ = __alloc_res__;\-  __alloc_ptr__;\-  })--// Traverse children using a haskell_visitor passed in as client_data.-// The visitor gets a copy of the cursor on the heap and is responsible-// for freeing it.-static enum CXChildVisitResult visit_haskell(CXCursor cursor,-                                             CXCursor parent,-                                             CXClientData client_data) {-  ((haskell_visitor) client_data)(ALLOC(cursor));-  return CXChildVisit_Continue;-};
clang-pure.cabal view
@@ -1,5 +1,5 @@ name:                  clang-pure-version:               0.2.0.2+version:               0.2.0.3 synopsis:              Pure C++ code analysis with libclang description:   Pure C++ code analysis with libclang.@@ -13,9 +13,16 @@ copyright:             Copyright 2014 Google Inc. All Rights Reserved. category:              Language build-type:            Custom-cabal-version:         >=1.10-extra-source-files:    cbits/utils.h+cabal-version:         >=1.24+extra-source-files:    cbits/clang-pure-utils.h +custom-setup+  setup-depends:+    base >= 4.5 && < 5,+    Cabal >= 1.24,+    process >= 1.3.0.0,+    inline-c+ source-repository head   type: git   location: https://github.com/chpatrick/clang-pure.git@@ -57,35 +64,39 @@   build-tools:         hsc2hs   default-language:    Haskell2010   include-dirs:        cbits/-  cc-options:          -Wall+  includes:            clang-c/Index.h+  cc-options:          -Wall -Werror   extra-libraries:     clang-  ghc-options:         -Wall -O2+  ghc-options:         -Wall   if impl(ghc >= 8.0.0)     ghc-options: -fno-warn-redundant-constraints  executable find-classes   main-is:             FindClasses.hs+  default-language:    Haskell2010   build-depends:       base, clang-pure, lens, unordered-containers, hashable, bytestring   hs-source-dirs:      app   buildable:           False-  ghc-options:         -Wall -O2 -fno-warn-orphans+  ghc-options:         -Wall -fno-warn-orphans   if impl(ghc >= 8.0.0)     ghc-options: -fno-warn-redundant-constraints -executable list-fun-types+test-suite list-fun-types+  type:                exitcode-stdio-1.0   main-is:             ListTypes.hs+  default-language:    Haskell2010   build-depends:       base, clang-pure, lens, bytestring   hs-source-dirs:      examples-  buildable:           False-  ghc-options:         -Wall -O2+  ghc-options:         -Wall   if impl(ghc >= 8.0.0)     ghc-options: -fno-warn-redundant-constraints -executable list-structs+test-suite list-structs+  type:                exitcode-stdio-1.0+  default-language:    Haskell2010   main-is:             ListStructs.hs   build-depends:       base, clang-pure, lens, bytestring   hs-source-dirs:      examples-  buildable:           False-  ghc-options:         -Wall -O2+  ghc-options:         -Wall   if impl(ghc >= 8.0.0)     ghc-options: -fno-warn-redundant-constraints
examples/ListStructs.hs view
@@ -6,14 +6,24 @@ import           Language.C.Clang.Cursor.Typed import           Control.Lens import qualified Data.ByteString.Char8 as BS-import           Data.Monoid+import           Data.Maybe import           Data.Word import           System.Environment +data CType =+  CArrayType  { cType :: Type+              , cCanonicalType :: Type+              , cElementType :: CType+              , cArraySize :: Word64, cSize :: Word64} |+  CScalarType { cType :: Type+              , cCanonicalType :: Type+              , cSize :: Word64+              } deriving (Show)+ data CField = CField   { cFieldName :: BS.ByteString   , cFieldOffset :: Word64-  , cFieldType :: Type+  , cFieldType :: CType   } deriving (Show)  data CStruct = CStruct@@ -29,12 +39,33 @@       idx <- createIndex       tu <- parseTranslationUnit idx path clangArgs +      let toCType tp = let canonicalType = typeCanonicalType tp+                       in case typeKind canonicalType of+            ConstantArray -> do+              elementType <- toCType . fromJust . typeElementType $ canonicalType+              size <- typeSizeOf tp+              pure $ CArrayType+                { cType = tp+                , cCanonicalType = canonicalType+                , cElementType = elementType+                , cArraySize = fromJust (typeArraySize canonicalType)+                , cSize = size+                }+            _ -> do+              size <- typeSizeOf tp+              pure $ CScalarType+                { cType = tp+                , cCanonicalType = canonicalType+                , cSize = size+                }+       let toCField fieldDecC = do-            offset <- offsetOfField fieldDecC+            fieldOffset <- offsetOfField fieldDecC+            fieldType <- toCType (cursorType fieldDecC)             return $ CField               { cFieldName = cursorSpelling fieldDecC-              , cFieldOffset = offset-              , cFieldType = cursorType fieldDecC+              , cFieldOffset = fieldOffset+              , cFieldType = fieldType               }        let toCStruct structDecC = do@@ -43,7 +74,10 @@                     ^.. cursorDescendantsF                       . folding (matchKind @'FieldDecl)             cFields <- traverse toCField fieldDecs-            return $ CStruct (cursorSpelling structDecC) cFields+            return CStruct+              { cStructName = cursorSpelling structDecC+              , cStructFields = cFields+              }        let cStructs =             translationUnitCursor tu
examples/ListTypes.hs view
@@ -6,8 +6,8 @@ import           Language.C.Clang.Cursor.Typed import           Control.Lens import qualified Data.ByteString.Char8 as BS-import           Data.Monoid import           System.Environment+import           Data.Monoid ((<>))  main :: IO () main = do
src/Language/C/Clang/Cursor/Typed.hs view
@@ -83,11 +83,11 @@ cursorChildren = UT.cursorChildren . withoutKind  -- | `Fold` over a `CursorK` and all of its descendants recursively.-cursorDescendantsF :: Fold (CursorK kind) Cursor+cursorDescendantsF :: HasChildren kind => Fold (CursorK kind) Cursor cursorDescendantsF = to withoutKind . UT.cursorDescendantsF  -- | List a `CursorK` and all of its descendants recursively.-cursorDescendants :: CursorK kind -> [ Cursor ]+cursorDescendants :: HasChildren kind => CursorK kind -> [ Cursor ] cursorDescendants = UT.cursorDescendants . withoutKind  class HasExtent (kind :: CursorKind)
src/Language/C/Clang/Internal/Context.hs view
@@ -17,7 +17,7 @@ module Language.C.Clang.Internal.Context where  import qualified Data.Map as M-import Data.Monoid+import Data.Monoid ((<>)) import qualified Language.C.Inline as C import qualified Language.C.Inline.Context as C import qualified Language.C.Types as C
src/Language/C/Clang/Internal/FFI.hsc view
@@ -42,7 +42,7 @@ C.include "stdlib.h" #include  "clang-c/Index.h" C.include "clang-c/Index.h"-C.include "utils.h"+C.include "clang-pure-utils.h"  foreign import ccall "clang_disposeIndex"   clang_disposeIndex :: Ptr CXIndexImpl -> Finalizer@@ -117,7 +117,7 @@ cursorChildrenF f c = uderef c $ \cp -> do   -- initialize the "Fold state" with no effect   fRef <- newIORef $ phantom $ pure ()-  let +  let     visitChild chp = do       ch <- newLeaf (cursorTranslationUnit c) $ \_ ->         return ( chp, free chp )@@ -468,6 +468,31 @@     then return Nothing     else (Just . Type) <$> newLeaf (parent c) (\_ -> return ( tp, free tp )) +typeArraySize :: Type -> Maybe Word64+typeArraySize t = uderef t $ \tp -> do+    as <- [C.exp| long long { clang_getArraySize(*$(CXType *tp)) } |]+    return $ if as == -1 then Nothing else Just (fromIntegral as)++typeCanonicalType :: Type -> Type+typeCanonicalType t = uderef t $ \tp -> do+  ctp <- [C.exp| CXType* { ALLOC(clang_getCanonicalType(*$(CXType *tp))) } |]+  Type <$> newLeaf (parent t) (\_ -> pure (ctp, free ctp))++typeElementType :: Type -> Maybe Type+typeElementType t = uderef t $ \tp -> do+  etp <- [C.block| CXType* {+    CXType type = clang_getElementType(*$(CXType *tp));++    if (type.kind == CXType_Invalid) {+      return NULL;+    }++    return ALLOC(type);+    } |]+  if etp == nullPtr+    then return Nothing+    else (Just . Type) <$> newLeaf (parent t) (\_ -> return ( etp, free etp ))+ typeKind :: Type -> TypeKind typeKind t = uderef t $ fmap parseTypeKind . #peek CXType, kind @@ -525,6 +550,23 @@   #{const CXType_MemberPointer} -> MemberPointer   _ -> Unexposed +eitherTypeLayoutErrorOrWord64 :: CLLong -> Either TypeLayoutError Word64+eitherTypeLayoutErrorOrWord64 n = case n of+  #{const CXTypeLayoutError_Invalid} -> Left TypeLayoutErrorInvalid+  #{const CXTypeLayoutError_Incomplete} -> Left TypeLayoutErrorIncomplete+  #{const CXTypeLayoutError_Dependent} -> Left TypeLayoutErrorDependent+  _ -> Right $ fromIntegral n++typeSizeOf :: Type -> Either TypeLayoutError Word64+typeSizeOf t = uderef t $ \tp ->+  eitherTypeLayoutErrorOrWord64 <$>+  [C.exp| long long { clang_Type_getSizeOf(*$(CXType *tp)) } |]++offsetOfField :: Cursor -> Either TypeLayoutError Word64+offsetOfField c = uderef c $ \cp ->+  eitherTypeLayoutErrorOrWord64 <$>+  [C.exp| long long { clang_Cursor_getOffsetOfField(*$(CXCursor* cp)) } |]+ typeSpelling :: Type -> ByteString typeSpelling t = uderef t $ \tp ->   withCXString $ \cxsp ->@@ -548,7 +590,7 @@       ( tsp, tn ) <- C.withPtrs_ $ \( tspp, tnp ) ->         [C.exp| void {           clang_tokenize(-            $(CXTranslationUnit tup), +            $(CXTranslationUnit tup),             *$(CXSourceRange *srp),             $(CXToken **tspp),             $(unsigned int *tnp));@@ -610,12 +652,3 @@     "File { fileName = "     ++ show (fileName f)     ++ "}"--offsetOfField :: Cursor -> Either TypeLayoutError Word64-offsetOfField c = uderef c $ \cp -> do-  res <- [C.exp| long long { clang_Cursor_getOffsetOfField(*$(CXCursor* cp)) } |]-  return $ case res of-    #{const CXTypeLayoutError_Invalid} -> Left TypeLayoutErrorInvalid-    #{const CXTypeLayoutError_Incomplete} -> Left TypeLayoutErrorIncomplete-    #{const CXTypeLayoutError_Dependent} -> Left TypeLayoutErrorDependent-    n -> Right (fromIntegral n)
src/Language/C/Clang/Internal/Types.hs view
@@ -17,6 +17,7 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE GADTs #-}  module Language.C.Clang.Internal.Types where 
src/Language/C/Clang/Type.hs view
@@ -16,6 +16,10 @@  module Language.C.Clang.Type   ( Type()+  , typeArraySize+  , typeCanonicalType+  , typeElementType+  , typeSizeOf   , typeSpelling   , typeKind   , TypeKind(..)