Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the ghc api to get imports #32

Merged
merged 19 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ stack_snapshot(
name = "stackage",
packages = [
"aeson",
"parsec",
],
# Most snapshots of your choice might do
snapshot = "lts-18.1",
Expand Down
1 change: 0 additions & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ stack_snapshot(
packages = [
"aeson",
"hspec",
"parsec",
"string-qq",
"tasty",
"tasty-discover",
Expand Down
4 changes: 0 additions & 4 deletions defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ def _gazelle_haskell_modules_dependencies_impl(repository_ctx):
package(default_visibility = ["//visibility:public"])

alias(name="aeson", actual="{aeson}")
alias(name="parsec", actual="{parsec}")
'''.format(
aeson = repository_ctx.attr.aeson,
parsec = repository_ctx.attr.parsec,
),
executable = False,
)
Expand All @@ -20,7 +18,6 @@ _gazelle_haskell_modules_dependencies = repository_rule(
local = True,
attrs = {
"aeson": attr.label(default = "@stackage//:aeson"),
"parsec": attr.label(default = "@stackage//:parsec"),
},
)

Expand All @@ -41,7 +38,6 @@ def gazelle_haskell_modules_dependencies(**kargs):
# Dependencies overriden
gazelle_haskell_modules_dependencies(
aeson = "@someother//:some-other-aeson",
parsec = "@someother//:parsec",
)

```
Expand Down
2 changes: 1 addition & 1 deletion example/WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ stack_snapshot(
packages = [
"aeson",
"base",
"ghc-paths",
"inspection-testing",
"parsec",
"tasty",
"tasty-discover",
"tasty-hunit",
Expand Down
14 changes: 12 additions & 2 deletions example/package-a/app/Main.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE MagicHash #-}
module Main where

#define a_multiline macro \
a second line of the macro
import NonModulesLib (nonModulesLib)
import PackageA.Other.C()
import PackageA.Other.C(type DataC, DataC(DataC), pattern PatTrue)
import GHC.Exts (Int(..), Int#)

main :: IO ()
main = putStrLn $ "Hello, Haskell! " ++ show nonModulesLib
main = do
let
dataC :: DataC
dataC = DataC PatTrue
int# :: Int#
int# = case 1 of I# i -> i
putStrLn $ "Hello, Haskell! " ++ show nonModulesLib ++ show dataC ++ show (I# int#)
7 changes: 7 additions & 0 deletions example/package-a/app/PackageA/Other/C.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
{-# LANGUAGE PatternSynonyms #-}
module PackageA.Other.C where

import PackageA.Exposed.A()

data DataC = DataC Bool
deriving Show

pattern PatTrue :: Bool
pattern PatTrue = True
33 changes: 28 additions & 5 deletions gazelle_haskell_modules/rule_generation.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gazelle_haskell_modules

import (
"bytes"
"encoding/json"
"fmt"
"io/fs"
Expand Down Expand Up @@ -151,15 +152,37 @@ func haskellModulesToModuleData(moduleFiles []string) []*ModuleData {
cmd := exec.Command(himportscan)

cmd.Stdin = strings.NewReader(strings.Join(moduleFiles, "\n"))
out, err := cmd.CombinedOutput()

var stdout bytes.Buffer
cmd.Stdout = &stdout

var stderr strings.Builder
cmd.Stderr = &stderr

err = cmd.Start()
if err != nil {
log.Printf("%s", out)
log.Fatal(err)
log.Fatalf("himportscan failed to start %v", err)
}

err = cmd.Wait()
stdoutBytes := stdout.Bytes()
stderrString := stderr.String()

if err != nil {
fmt.Printf("%s\n", stdout.Bytes())
fmt.Printf("%s\n", stderrString)
log.Fatalf("himportscan exited unsuccessfully %v\n", err)
}

// print stderr so if himportscan generates some stderr but doesn't fail the user might see useful output
if stderrString != "" {
log.Printf("%s\n", stderrString)
}

var modDatas []*ModuleData
err = json.Unmarshal(out, &modDatas)
err = json.Unmarshal(stdoutBytes, &modDatas)
if err != nil {
log.Printf("Incorrect json: %s\n", out)
log.Printf("Incorrect json: %s\n", stdoutBytes)
log.Fatal(err)
}
return modDatas
Expand Down
11 changes: 10 additions & 1 deletion himportscan/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ haskell_toolchain_library(name = "base")

haskell_toolchain_library(name = "bytestring")

haskell_toolchain_library(name = "containers")

haskell_toolchain_library(name = "directory")

haskell_toolchain_library(name = "ghc")

# Needed for GHC.LanguageExtensions.
# You can probably revisit this when changing ghc versions.
haskell_toolchain_library(name = "ghc-boot")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this is redundant now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it isn't - it seems I introduced another dependency on this package without knowing. Updated the comment.


haskell_toolchain_library(name = "text")

haskell_library(
Expand All @@ -28,11 +34,12 @@ haskell_library(
deps = [
":base",
":bytestring",
":containers",
":directory",
":ghc",
":ghc-boot",
":text",
"@io_tweag_gazelle_haskell_modules_deps//:aeson",
"@io_tweag_gazelle_haskell_modules_deps//:parsec",
],
)

Expand All @@ -46,6 +53,7 @@ haskell_binary(
deps = [
":base",
":bytestring",
":containers",
":ghc",
":himportscan-library",
":text",
Expand All @@ -66,6 +74,7 @@ haskell_test(
],
deps = [
":base",
":containers",
":himportscan-library",
":text",
"@stackage//:hspec",
Expand Down
2 changes: 1 addition & 1 deletion himportscan/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
{-# LANGUAGE OverloadedStrings #-}
module Main where

import HImportScan.ImportScanner (ScannedImports, scanImportsFromFile)
import qualified Data.Aeson as Aeson
import qualified Data.ByteString.Lazy.Char8 as ByteString.Lazy
import Data.Maybe (catMaybes)
import HImportScan.ImportScanner (ScannedImports, scanImportsFromFile)

main :: IO ()
main = do
Expand Down
21 changes: 19 additions & 2 deletions himportscan/src/HImportScan/GHC.hs
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
-- | A module abstracting the provenance of GHC API names
module HImportScan.GHC(module X) where

import DynFlags as X (DynFlags, defaultDynFlags, xopt_set, xopt_unset)
import EnumSet as X (empty, fromList)
import FastString as X (mkFastString, unpackFS)
import ErrUtils as X (printBagOfErrors)
import FastString as X (FastString, mkFastString, bytesFS)
import GHC as X (runGhc, getSessionDynFlags)
import GHC.LanguageExtensions as X
(Extension
( ImportQualifiedPost
, PackageImports
, TemplateHaskell
, ImplicitPrelude
, PatternSynonyms
, ExplicitNamespaces
, MagicHash
)
)
import HeaderInfo as X (getOptions, getImports)
import HscTypes as X (mkSrcErr)
import Lexer as X
( ParseResult(..)
, Token(..)
Expand All @@ -11,6 +27,7 @@ import Lexer as X
, mkParserFlags'
, mkPStatePure, unP
)
import Module as X (ModuleName, moduleNameString)
import SrcLoc as X
( Located
, RealSrcLoc
Expand All @@ -22,4 +39,4 @@ import SrcLoc as X
, srcSpanStart
, unLoc
)
import StringBuffer as X (StringBuffer(StringBuffer))
import StringBuffer as X (StringBuffer(StringBuffer), stringToStringBuffer)
50 changes: 50 additions & 0 deletions himportscan/src/HImportScan/GHC/Settings.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
-- Copyright (c) 2020, Shayne Fletcher. All rights reserved.
-- SPDX-License-Identifier: BSD-3-Clause.

{-# OPTIONS_GHC -Wno-missing-fields #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}

-- This file is a single code path copied over from https://hackage.haskell.org/package/ghc-lib-parser-ex-8.10.0.24/docs/src/Language.Haskell.GhclibParserEx.GHC.Settings.Config.html
-- TODO[GL]: We can get rid of this file once we only support >=9.2, as ParserOpts are much smaller there.
module HImportScan.GHC.Settings(
fakeSettings
, fakeLlvmConfig
)
where

import Config
import DynFlags
import Fingerprint
import GHC.Platform
import ToolSettings

fakeSettings :: Settings
fakeSettings = Settings
{ sGhcNameVersion=ghcNameVersion
, sFileSettings=fileSettings
, sTargetPlatform=platform
, sPlatformMisc=platformMisc
, sPlatformConstants=platformConstants
, sToolSettings=toolSettings
}
where
toolSettings = ToolSettings {
toolSettings_opt_P_fingerprint=fingerprint0
}
fileSettings = FileSettings {}
platformMisc = PlatformMisc {}
ghcNameVersion =
GhcNameVersion{ghcNameVersion_programName="ghc"
,ghcNameVersion_projectVersion=cProjectVersion
}
platform =
Platform{
platformWordSize=PW8
, platformMini=PlatformMini {platformMini_arch=ArchUnknown, platformMini_os=OSUnknown}
, platformUnregisterised=True
}
platformConstants =
PlatformConstants{pc_DYNAMIC_BY_DEFAULT=False,pc_WORD_SIZE=8}

fakeLlvmConfig :: LlvmConfig
fakeLlvmConfig = LlvmConfig [] []
Loading