on a290aab help sign in
115 files changed+3193−18071
since splitsnapshots
unifiedsplit
.azure/linux-stack.yml−63 .azure/windows-stack.yml−68 .editorconfig−11 .ghci+16 .gitignore−10 .hlint.yaml−132 BUILD.bazel+85 CHANGELOG.md−85 LICENSE−201 README.md−334 azure-pipelines.yml−18 bench/Main.hs−287 cbits/getmodtime.c−21 docs/Setup.md−145 exe/Arguments.hs−35 exe/Main.hs−683 exe/Utils.hs−9 extension/.gitignore−4 extension/.vscodeignore−10 extension/README.md−1 extension/package-lock.json−750 extension/package.json−72 extension/src/extension.ts−45 extension/tsconfig.json−21 extension/tslint.json−15 fmt.sh−3 ghcide.cabal−344 haskell-ide-core.cabal+118 hie.yaml−12 img/vscode2.png include/ghc-api-version.h−10 install.bat−6 src-ghc810/Development/IDE/GHC/HieAst.hs−1928 src-ghc88/Development/IDE/GHC/HieAst.hs−1789 src/Development/IDE/Compat.hs+30−11 src/Development/IDE/Core/Compile.hs−598 src/Development/IDE/Core/Debouncer.hs−52 src/Development/IDE/Core/FileExists.hs−181 src/Development/IDE/Core/FileStore.hs−187 src/Development/IDE/Core/IdeConfiguration.hs−71 src/Development/IDE/Core/OfInterest.hs−82 src/Development/IDE/Core/PositionMapping.hs−122 src/Development/IDE/Core/Preprocessor.hs−230 src/Development/IDE/Core/Rules.hs−671 src/Development/IDE/Core/Service.hs−107 src/Development/IDE/Core/Shake.hs−849 src/Development/IDE/Functions/AtPoint.hs+139 src/Development/IDE/GHC/CPP.hs → src/Development/IDE/Functions/CPP.hs+10−52 src/Development/IDE/Functions/Compile.hs+455 src/Development/IDE/Functions/DependencyInformation.hs+210 src/Development/IDE/Spans/Documentation.hs → src/Development/IDE/Functions/Documentation.hs+23−51 src/Development/IDE/Functions/FindImports.hs+148 src/Development/IDE/Functions/GHCError.hs+165 src/Development/IDE/Functions/SpanInfo.hs+134 src/Development/IDE/GHC/Warnings.hs → src/Development/IDE/Functions/Warnings.hs+13−13 src/Development/IDE/GHC/Compat.hs−309 src/Development/IDE/GHC/Error.hs−202 src/Development/IDE/GHC/Orphans.hs−72 src/Development/IDE/GHC/Util.hs−315 src/Development/IDE/GHC/WithDynFlags.hs−30 src/Development/IDE/Import/DependencyInformation.hs−376 src/Development/IDE/Import/FindImports.hs−179 src/Development/IDE/LSP/HoverDefinition.hs−62 src/Development/IDE/LSP/LanguageServer.hs−236 src/Development/IDE/LSP/Notifications.hs−81 src/Development/IDE/LSP/Outline.hs−234 src/Development/IDE/LSP/Protocol.hs−23 src/Development/IDE/LSP/Server.hs−47 src/Development/IDE/Logger.hs+26 src/Development/IDE/Orphans.hs+40 src/Development/IDE/Plugin.hs−60 src/Development/IDE/Plugin/CodeAction.hs−570 src/Development/IDE/Plugin/CodeAction/PositionIndexed.hs−112 src/Development/IDE/Plugin/CodeAction/RuleTypes.hs−61 src/Development/IDE/Plugin/CodeAction/Rules.hs−61 src/Development/IDE/Plugin/Completions.hs−103 src/Development/IDE/Plugin/Completions/Logic.hs−530 src/Development/IDE/Plugin/Completions/Types.hs−58 src/Development/IDE/Spans/AtPoint.hs−178 src/Development/IDE/Spans/Calculate.hs−273 src/Development/IDE/Spans/Common.hs−162 src/Development/IDE/State/FileStore.hs+153 src/Development/IDE/Core/RuleTypes.hs → src/Development/IDE/State/RuleTypes.hs+80−92 src/Development/IDE/State/Rules.hs+336 src/Development/IDE/State/Service.hs+120 src/Development/IDE/State/Shake.hs+426 src/Development/IDE/Types/Diagnostics.hs+128−84 src/Development/IDE/Types/LSP.hs+61 src/Development/IDE/Types/Location.hs+59−93 src/Development/IDE/Types/Logger.hs−54 src/Development/IDE/Types/Options.hs+7−99 src/Development/IDE/Spans/Type.hs → src/Development/IDE/Types/SpanInfo.hs+20−34 src/Development/IDE/UtilGHC.hs+86 stack-ghc-lib.yaml−24 stack.yaml+1−17 stack810.yaml−18 stack84.yaml−33 stack88.yaml−11 test/Demo.hs+104 test/cabal/Development/IDE/Test/Runfiles.hs−9 test/data/hover/Bar.hs−3 test/data/hover/Foo.hs−5 test/data/hover/GotoHover.hs−57 test/data/multi/a/A.hs−3 test/data/multi/a/a.cabal−9 test/data/multi/b/B.hs−3 test/data/multi/b/b.cabal−9 test/data/multi/cabal.project−1 test/data/multi/hie.yaml−6 test/exe/Main.hs−2496 test/manual/lhs/Bird.lhs−19 test/manual/lhs/Main.hs−12 test/manual/lhs/Test.lhs−36 test/preprocessor/Main.hs−10 test/src/Development/IDE/Test.hs−111
.azure/linux-stack.ymldeleted−63
@@ -1,63 +0,0 @@
1−jobs:
2−- job: ghcide_stack_linux
3− timeoutInMinutes: 60
4− pool:
5− vmImage: 'ubuntu-latest'
6− strategy:
7− matrix:
8− stack_810:
9− STACK_YAML: "stack810.yaml"
10− stack_88:
11− STACK_YAML: "stack88.yaml"
12− stack_86:
13− STACK_YAML: "stack.yaml"
14− stack_84:
15− STACK_YAML: "stack84.yaml"
16− stack_ghc_lib_88:
17− STACK_YAML: "stack-ghc-lib.yaml"
18− steps:
19− - checkout: self
20− - task: Cache@2
21− inputs:
22− key: stack-cache-v2 | $(Agent.OS) | $(Build.SourcesDirectory)/$(STACK_YAML) | $(Build.SourcesDirectory)/ghcide.cabal
23− path: .azure-cache
24− cacheHitVar: CACHE_RESTORED
25− displayName: "Cache stack artifacts"
26− - bash: |
27− mkdir -p ~/.stack
28− tar xzf .azure-cache/stack-root.tar.gz -C $HOME
29− displayName: "Unpack cache"
30− condition: eq(variables.CACHE_RESTORED, 'true')
31− - bash: |
32− ./fmt.sh
33− displayName: "HLint via ./fmt.sh"
34− - bash: |
35− sudo add-apt-repository ppa:hvr/ghc
36− sudo apt-get update
37− sudo apt-get install -y g++ gcc libc6-dev libffi-dev libgmp-dev make zlib1g-dev cabal-install-3.2
38− if ! which stack >/dev/null 2>&1; then
39− curl -sSL https://get.haskellstack.org/ | sh
40− fi
41− displayName: 'Install Stack'
42− - bash: stack setup --stack-yaml=$STACK_YAML
43− displayName: 'stack setup'
44− - bash: stack build --only-dependencies --stack-yaml=$STACK_YAML
45− displayName: 'stack build --only-dependencies'
46− - bash: |
47− export PATH=/opt/cabal/bin:$PATH
48− stack test --ghc-options=-Werror --stack-yaml=$STACK_YAML || stack test --ghc-options=-Werror --stack-yaml=$STACK_YAML|| stack test --ghc-options=-Werror --stack-yaml=$STACK_YAML
49− # ghcide stack tests are flaky, see https://github.com/digital-asset/daml/issues/2606.
50− displayName: 'stack test --ghc-options=-Werror'
51− - bash: |
52− mkdir -p .azure-cache
53− tar czf .azure-cache/stack-root.tar.gz -C $HOME .stack
54− displayName: "Pack cache"
55− - bash: |
56− set -euo pipefail
57− MESSAGE=$(git log --pretty=format:%s -n1)
58− curl -XPOST \
59− -i \
60− -H 'Content-type: application/json' \
61− --data "{\"text\":\"<!here> *FAILED* $(Agent.JobName): <https://dev.azure.com/digitalasset/ghcide/_build/results?buildId=$(Build.BuildId)|$MESSAGE>\n\"}" \
62− $(Slack.URL)
63− condition: and(failed(), eq(variables['Build.SourceBranchName'], 'master'))
.azure/windows-stack.ymldeleted−68
@@ -1,68 +0,0 @@
1−jobs:
2−- job: ghcide_stack_windows
3− timeoutInMinutes: 60
4− pool:
5− vmImage: 'windows-2019'
6− strategy:
7− matrix:
8− stack_810:
9− STACK_YAML: "stack810.yaml"
10− stack_88:
11− STACK_YAML: "stack88.yaml"
12− stack_86:
13− STACK_YAML: "stack.yaml"
14− stack_84:
15− STACK_YAML: "stack84.yaml"
16− stack_ghc_lib_88:
17− STACK_YAML: "stack-ghc-lib.yaml"
18− variables:
19− STACK_ROOT: "C:\\sr"
20− steps:
21− - checkout: self
22− - task: Cache@2
23− inputs:
24− key: stack-cache-v2 | $(Agent.OS) | $(Build.SourcesDirectory)/$(STACK_YAML) | $(Build.SourcesDirectory)/ghcide.cabal
25− path: .azure-cache
26− cacheHitVar: CACHE_RESTORED
27− displayName: "Cache stack artifacts"
28− - bash: |
29− mkdir -p $STACK_ROOT
30− tar -vxzf .azure-cache/stack-root.tar.gz -C /c
31− mkdir -p .stack-work
32− tar -vxzf .azure-cache/stack-work.tar.gz
33− displayName: "Unpack cache"
34− condition: eq(variables.CACHE_RESTORED, 'true')
35− - bash: |
36− ./fmt.sh
37− displayName: "HLint via ./fmt.sh"
38− - bash: |
39− curl -sSkL http://www.stackage.org/stack/windows-x86_64 -o /usr/bin/stack.zip
40− unzip -o /usr/bin/stack.zip -d /usr/bin/
41− mkdir -p "$STACK_ROOT"
42− displayName: 'Install Stack'
43− - bash: stack setup --stack-yaml $STACK_YAML
44− displayName: 'stack setup'
45− - bash: |
46− # Installing happy and alex standalone to avoid error "strip.exe: unable to rename ../*.exe; reason: File exists"
47− stack install happy --stack-yaml $STACK_YAML
48− stack install alex --stack-yaml $STACK_YAML
49− stack install cabal-install --stack-yaml $STACK_YAML
50− stack build --only-dependencies --stack-yaml $STACK_YAML
51− displayName: 'stack build --only-dependencies'
52− - bash: stack test --no-run-tests --ghc-options=-Werror --stack-yaml $STACK_YAML
53− displayName: 'stack test --ghc-options=-Werror'
54− # TODO: run test suite when failing tests are fixed or marked as broken. See https://github.com/digital-asset/ghcide/issues/474
55− - bash: |
56− mkdir -p .azure-cache
57− tar -vczf .azure-cache/stack-root.tar.gz $(cygpath $STACK_ROOT)
58− tar -vczf .azure-cache/stack-work.tar.gz .stack-work
59− displayName: "Pack cache"
60− - bash: |
61− set -euo pipefail
62− MESSAGE=$(git log --pretty=format:%s -n1)
63− curl -XPOST \
64− -i \
65− -H 'Content-type: application/json' \
66− --data "{\"text\":\"<!here> *FAILED* $(Agent.JobName): <https://dev.azure.com/digitalasset/ghcide/_build/results?buildId=$(Build.BuildId)|$MESSAGE>\n\"}" \
67− $(Slack.URL)
68− condition: and(failed(), eq(variables['Build.SourceBranchName'], 'master'))
.editorconfigdeleted−11
@@ -1,11 +0,0 @@
1−; This file is for unifying the coding style for different editors and IDEs.
2−; More information at https://EditorConfig.org
3−
4−root = true
5−
6−[*]
7−end_of_line = LF
8−indent_style = space
9−indent_size = 4
10−trim_trailing_whitespace = true
11−insert_final_newline = true
.ghcinew file+16
@@ -0,0 +1,16 @@
1+:set -ignore-package=ghc-lib -ignore-package=ghc-parser -package=ghc
2+:set -fwarn-unused-binds -fwarn-unused-imports -fwarn-orphans
3+:set -isrc -i../../libs-haskell/prettyprinter-syntax/src
4+:set -DGHC_STABLE
5+:set -XLambdaCase
6+:set -XBangPatterns
7+:set -XDeriveGeneric
8+:set -XRecordWildCards
9+:set -XScopedTypeVariables
10+:set -XNamedFieldPuns
11+:set -XTupleSections
12+:set -XTypeApplications
13+:set -XViewPatterns
14+:set -XGeneralizedNewtypeDeriving
15+:set -XStandaloneDeriving
16+:load test/Demo.hs
.gitignoredeleted−10
@@ -1,10 +0,0 @@
1−dist/
2−.stack-work/
3−dist-newstyle/
4−cabal.project.local
5−*~
6−*.lock
7−/.tasty-rerun-log
8−.vscode
9−/.hlint-*
10−bench/example
.hlint.yamldeleted−132
@@ -1,132 +0,0 @@
1−# HLint configuration file
2−# https://github.com/ndmitchell/hlint
3−##########################
4−
5−# To run HLint do:
6−# $ hlint --git -j4
7−
8−# Warnings currently triggered by our code
9−- ignore: {name: "Use <$>"}
10−- ignore: {name: "Use :"}
11−- ignore: {name: "Redundant do"}
12−- ignore: {name: "Avoid lambda"}
13−- ignore: {name: "Use newtype instead of data"}
14−- ignore: {name: "Use fromMaybe"}
15−- ignore: {name: "Use unless"}
16−- ignore: {name: "Move brackets to avoid $"}
17−- ignore: {name: "Eta reduce"}
18−- ignore: {name: "Parse error"}
19−- ignore: {name: "Reduce duplication"}
20−- ignore: {name: "Use ++"}
21−- ignore: {name: "Use $>"}
22−- ignore: {name: "Use section"}
23−- ignore: {name: "Use record patterns"}
24−- ignore: {name: "Use camelCase"}
25−- ignore: {name: "Use uncurry"}
26−- ignore: {name: "Avoid lambda using `infix`"}
27−
28−# Off by default hints we like
29−- warn: {name: Use module export list}
30−
31−# Condemn nub and friends
32−- warn: {lhs: nub (sort x), rhs: Data.List.Extra.nubSort x}
33−- warn: {lhs: nub, rhs: Data.List.Extra.nubOrd}
34−- warn: {lhs: nubBy, rhs: Data.List.Extra.nubOrdBy}
35−- warn: {lhs: Data.List.Extra.nubOn, rhs: Data.List.Extra.nubOrdOn}
36−
37−# DA specific hints
38−- warn: {lhs: Data.Text.pack (DA.Pretty.renderPlain x), rhs: DA.Pretty.renderPlain x}
39−- warn: {lhs: Data.Text.Extended.pack (DA.Pretty.renderPlain x), rhs: DA.Pretty.renderPlain x}
40−- warn: {lhs: DA.Pretty.renderPlain (DA.Pretty.pretty x), rhs: DA.Pretty.renderPretty x}
41−- warn: {lhs: Data.Text.readFile, rhs: Data.Text.Extended.readFileUtf8}
42−- warn: {lhs: Data.Text.writeFile, rhs: Data.Text.Extended.writeFileUtf8}
43−- warn: {lhs: Data.Text.Lazy.readFile, rhs: Data.Text.Extended.readFileUtf8}
44−- warn: {lhs: Data.Text.Lazy.writeFile, rhs: Data.Text.Extended.writeFileUtf8}
45−- warn: {lhs: System.Environment.setEnv, rhs: System.Environment.Blank.setEnv}
46−
47−# Specify additional command line arguments
48−#
49−- arguments: ["--cpp-include=include"]
50−
51−- extensions:
52− - default: true
53−
54− # Extensions enabled by `bazel` and `da-ghci` by default. We ban them here
55− # to avoid useless pragmas piling up on the top of files.
56− - {name: BangPatterns, within: []}
57− - {name: DeriveDataTypeable, within: []}
58− - {name: DeriveFoldable, within: []}
59− - {name: DeriveFunctor, within: []}
60− - {name: DeriveGeneric, within: []}
61− - {name: DeriveTraversable, within: []}
62− - {name: FlexibleContexts, within: []}
63− - {name: GeneralizedNewtypeDeriving, within: []}
64− - {name: LambdaCase, within: []}
65− - {name: NamedFieldPuns, within: []}
66− - {name: OverloadedStrings, within: []}
67− - {name: PackageImports, within: []}
68− - {name: RecordWildCards, within: []}
69− - {name: ScopedTypeVariables, within: []}
70− - {name: StandaloneDeriving, within: []}
71− - {name: TupleSections, within: []}
72− - {name: TypeApplications, within: []}
73− - {name: ViewPatterns, within: []}
74−
75− # Shady extensions
76− - name: CPP
77− within:
78− - Development.IDE.Compat
79− - Development.IDE.Core.FileStore
80− - Development.IDE.Core.Compile
81− - Development.IDE.Core.Rules
82− - Development.IDE.GHC.Compat
83− - Development.IDE.GHC.Orphans
84− - Development.IDE.GHC.Util
85− - Development.IDE.Import.FindImports
86− - Development.IDE.LSP.Outline
87− - Development.IDE.Spans.Calculate
88− - Development.IDE.Spans.Documentation
89− - Development.IDE.Spans.Common
90− - Development.IDE.Plugin.CodeAction
91− - Development.IDE.Plugin.Completions
92− - Development.IDE.Plugin.Completions.Logic
93− - Main
94−
95−- flags:
96− - default: false
97− - {name: [-Wno-missing-signatures, -Wno-orphans, -Wno-overlapping-patterns, -Wno-incomplete-patterns, -Wno-missing-fields, -Wno-unused-matches]}
98− - {name: [-Wno-dodgy-imports], within: Main}
99−# - modules:
100−# - {name: [Data.Set, Data.HashSet], as: Set} # if you import Data.Set qualified, it must be as 'Set'
101−# - {name: Control.Arrow, within: []} # Certain modules are banned entirely
102−#
103−- functions:
104− # Things that are unsafe in Haskell base library
105− - {name: unsafeInterleaveIO, within: []}
106− - {name: unsafeDupablePerformIO, within: []}
107− - {name: unsafeCoerce, within: []}
108− # Things that are a bit dangerous in the GHC API
109− - {name: nameModule, within: []}
110−
111−# Add custom hints for this project
112−#
113−# Will suggest replacing "wibbleMany [myvar]" with "wibbleOne myvar"
114−# - error: {lhs: "wibbleMany [x]", rhs: wibbleOne x}
115−
116−# Turn on hints that are off by default
117−#
118−# Ban "module X(module X) where", to require a real export list
119−# - warn: {name: Use explicit module export list}
120−#
121−# Replace a $ b $ c with a . b $ c
122−# - group: {name: dollar, enabled: true}
123−#
124−# Generalise map to fmap, ++ to <>
125−# - group: {name: generalise, enabled: true}
126−
127−# Ignore some builtin hints
128−# - ignore: {name: Use let}
129−# - ignore: {name: Use const, within: SpecialModule} # Only within certain modules
130−
131−# Define some custom infix operators
132−# - fixity: infixr 3 ~^#^~
BUILD.bazelnew file+85
@@ -0,0 +1,85 @@
1+# Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+# SPDX-License-Identifier: Apache-2.0
3+
4+load("//bazel_tools:haskell.bzl", "da_haskell_binary", "da_haskell_library")
5+load("@os_info//:os_info.bzl", "is_windows")
6+
7+depends = [
8+ "aeson",
9+ "base",
10+ "binary",
11+ "bytestring",
12+ "containers",
13+ "deepseq",
14+ "directory",
15+ "either",
16+ "extra",
17+ "filepath",
18+ "hashable",
19+ "haskell-lsp",
20+ "haskell-lsp-types",
21+ "mtl",
22+ "pretty",
23+ "safe-exceptions",
24+ "shake",
25+ "stm",
26+ "syb",
27+ "text",
28+ "time",
29+ "transformers",
30+ "uniplate",
31+ "unordered-containers",
32+ "uri-encode",
33+]
34+
35+da_haskell_library(
36+ name = "haskell-ide-core",
37+ srcs = glob(["src/**/*.hs"]),
38+ hazel_deps = depends + [
39+ "ghc-lib",
40+ "ghc-lib-parser",
41+ ],
42+ src_strip_prefix = "src",
43+ visibility = ["//visibility:public"],
44+ deps = [
45+ "//libs-haskell/prettyprinter-syntax",
46+ ],
47+)
48+
49+da_haskell_library(
50+ name = "haskell-ide-core-public",
51+ srcs = glob(["src/**/*.hs"]),
52+ compiler_flags = ["-DGHC_STABLE"],
53+ hazel_deps = depends + [
54+ "ghc",
55+ "ghc-boot",
56+ "ghc-boot-th",
57+ ],
58+ src_strip_prefix = "src",
59+ visibility = ["//visibility:public"],
60+ deps = [
61+ "//libs-haskell/prettyprinter-syntax",
62+ ],
63+)
64+
65+da_haskell_binary(
66+ name = "haskell-ide-core-demo",
67+ srcs = glob(["test/**/*.hs"]),
68+ hazel_deps = [
69+ "base",
70+ "containers",
71+ "extra",
72+ "filepath",
73+ "ghc-paths",
74+ "ghc",
75+ "shake",
76+ "text",
77+ ],
78+ main_function = "Demo.main",
79+ src_strip_prefix = "test",
80+ visibility = ["//visibility:public"],
81+ deps = [
82+ "haskell-ide-core-public",
83+ "//libs-haskell/prettyprinter-syntax",
84+ ],
85+) if not is_windows else None # Disable on Windows until ghc-paths is fixed upstream
CHANGELOG.mddeleted−85
@@ -1,85 +0,0 @@
1−### unreleased
2−
3−### 0.2.0 (2020-06-02)
4−
5−* Multi-component support (thanks @mpickering)
6−* Support for GHC 8.10 (thanks @sheaf and @chshersh)
7−* Fix some TH issues (thanks @mpickering)
8−* Automatically pick up changes to cradle dependencies (e.g. cabal
9− files) (thanks @jinwoo)
10−* Track dependencies when using `qAddDependentFile` (thanks @mpickering)
11−* Add record fields to document symbols outline (thanks @bubba)
12−* Fix some space leaks (thanks @mpickering)
13−* Strip redundant path information from diagnostics (thanks @tek)
14−* Fix import suggestions for operators (thanks @eddiemundo)
15−* Significant reductions in memory usage by using interfaces and `.hie` files (thanks
16− @pepeiborra)
17−* Minor improvements to completions
18−* More comprehensive suggestions for missing imports (thanks @pepeiborra)
19−* Group imports in document outline (thanks @fendor)
20−* Upgrade to haskell-lsp-0.22 (thanks @bubba)
21−* Upgrade to hie-bios 0.5 (thanks @fendor)
22−
23−### 0.1.0 (2020-02-04)
24−
25−* Code action for inserting new definitions (see #309).
26−* Better default GC settings (see #329 and #333).
27−* Various performance improvements (see #322 and #384).
28−* Improvements to hover information (see #317 and #338).
29−* Support GHC 8.8.2 (see #355).
30−* Include keywords in completions (see #351).
31−* Fix some issues with aborted requests (see #353).
32−* Use hie-bios 0.4.0 (see #382).
33−* Avoid stuck progress reporting (see #400).
34−* Only show progress notifications after 0.1s (see #392).
35−* Progress reporting is now in terms of the number of files rather
36− than the number of shake rules (see #379).
37−
38−### 0.0.6 (2020-01-10)
39−
40−* Fix type in hover information for do-notation and list
41− comprehensions (see #243).
42−* Fix hover and goto-definition for multi-clause definitions (see #252).
43−* Upgrade to `hie-bios-0.3` (see #257)
44−* Upgrade to `haskell-lsp-0.19` (see #254)
45−* Code lenses for missing signatures are displayed even if the warning
46− has not been enabled. The warning itself will not be shown if it is
47− not enabled. (see #232)
48−* Define `__GHCIDE__` when running CPP to allow for `ghcide`-specific
49− workarounds. (see #264)
50−* Fix some filepath normalization issues. (see #266)
51−* Fix build with `shake-0.18.4` (see #272)
52−* Fix hover for type constructors and type classes. (see #267)
53−* Support custom preprocessors (see #282)
54−* Add support for code completions (see #227)
55−* Code action for removing redundant symbols from imports (see #290)
56−* Support document symbol requests (see #293)
57−* Show CPP errors as diagnostics (see #296)
58−* Code action for adding suggested imports (see #295)
59−
60−### 0.0.5 (2019-12-12)
61−
62−* Support for GHC plugins (see #192)
63−* Update to haskell-lsp 0.18 (see #203)
64−* Initial support for `TemplateHaskell` (see #222)
65−* Code lenses for missing signatures. These are only shown if
66− `-Wmissing-signatures` is enabled. (see #224)
67−* Fix path normalisation on Windows (see #225)
68−* Fix flickering of the progress indicator (see #230)
69−
70−### 0.0.4 (2019-10-20)
71−
72−* Add a ``--version`` cli option (thanks @jacg)
73−* Update to use progress reporting as defined in LSP 3.15. The VSCode
74− extension has also been updated and should now be making use of
75− this.
76−* Properly declare that we should support code actions. This helps
77− with some clients that rely on this information to enable code
78− actions (thanks @jacg).
79−* Fix a race condition caused by sharing the finder cache between
80− concurrent compilations.
81−* Avoid normalizing include dirs. This avoids issues where the same
82− file ends up twice in the module graph, e.g., with different casing
83− for drive letters.
84−
85−### 0.0.3 (2019-09-21)
LICENSEdeleted−201
@@ -1,201 +0,0 @@
1− Apache License
2− Version 2.0, January 2004
3− http://www.apache.org/licenses/
4−
5− TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6−
7− 1. Definitions.
8−
9− "License" shall mean the terms and conditions for use, reproduction,
10− and distribution as defined by Sections 1 through 9 of this document.
11−
12− "Licensor" shall mean the copyright owner or entity authorized by
13− the copyright owner that is granting the License.
14−
15− "Legal Entity" shall mean the union of the acting entity and all
16− other entities that control, are controlled by, or are under common
17− control with that entity. For the purposes of this definition,
18− "control" means (i) the power, direct or indirect, to cause the
19− direction or management of such entity, whether by contract or
20− otherwise, or (ii) ownership of fifty percent (50%) or more of the
21− outstanding shares, or (iii) beneficial ownership of such entity.
22−
23− "You" (or "Your") shall mean an individual or Legal Entity
24− exercising permissions granted by this License.
25−
26− "Source" form shall mean the preferred form for making modifications,
27− including but not limited to software source code, documentation
28− source, and configuration files.
29−
30− "Object" form shall mean any form resulting from mechanical
31− transformation or translation of a Source form, including but
32− not limited to compiled object code, generated documentation,
33− and conversions to other media types.
34−
35− "Work" shall mean the work of authorship, whether in Source or
36− Object form, made available under the License, as indicated by a
37− copyright notice that is included in or attached to the work
38− (an example is provided in the Appendix below).
39−
40− "Derivative Works" shall mean any work, whether in Source or Object
41− form, that is based on (or derived from) the Work and for which the
42− editorial revisions, annotations, elaborations, or other modifications
43− represent, as a whole, an original work of authorship. For the purposes
44− of this License, Derivative Works shall not include works that remain
45− separable from, or merely link (or bind by name) to the interfaces of,
46− the Work and Derivative Works thereof.
47−
48− "Contribution" shall mean any work of authorship, including
49− the original version of the Work and any modifications or additions
50− to that Work or Derivative Works thereof, that is intentionally
51− submitted to Licensor for inclusion in the Work by the copyright owner
52− or by an individual or Legal Entity authorized to submit on behalf of
53− the copyright owner. For the purposes of this definition, "submitted"
54− means any form of electronic, verbal, or written communication sent
55− to the Licensor or its representatives, including but not limited to
56− communication on electronic mailing lists, source code control systems,
57− and issue tracking systems that are managed by, or on behalf of, the
58− Licensor for the purpose of discussing and improving the Work, but
59− excluding communication that is conspicuously marked or otherwise
60− designated in writing by the copyright owner as "Not a Contribution."
61−
62− "Contributor" shall mean Licensor and any individual or Legal Entity
63− on behalf of whom a Contribution has been received by Licensor and
64− subsequently incorporated within the Work.
65−
66− 2. Grant of Copyright License. Subject to the terms and conditions of
67− this License, each Contributor hereby grants to You a perpetual,
68− worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69− copyright license to reproduce, prepare Derivative Works of,
70− publicly display, publicly perform, sublicense, and distribute the
71− Work and such Derivative Works in Source or Object form.
72−
73− 3. Grant of Patent License. Subject to the terms and conditions of
74− this License, each Contributor hereby grants to You a perpetual,
75− worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76− (except as stated in this section) patent license to make, have made,
77− use, offer to sell, sell, import, and otherwise transfer the Work,
78− where such license applies only to those patent claims licensable
79− by such Contributor that are necessarily infringed by their
80− Contribution(s) alone or by combination of their Contribution(s)
81− with the Work to which such Contribution(s) was submitted. If You
82− institute patent litigation against any entity (including a
83− cross-claim or counterclaim in a lawsuit) alleging that the Work
84− or a Contribution incorporated within the Work constitutes direct
85− or contributory patent infringement, then any patent licenses
86− granted to You under this License for that Work shall terminate
87− as of the date such litigation is filed.
88−
89− 4. Redistribution. You may reproduce and distribute copies of the
90− Work or Derivative Works thereof in any medium, with or without
91− modifications, and in Source or Object form, provided that You
92− meet the following conditions:
93−
94− (a) You must give any other recipients of the Work or
95− Derivative Works a copy of this License; and
96−
97− (b) You must cause any modified files to carry prominent notices
98− stating that You changed the files; and
99−
100− (c) You must retain, in the Source form of any Derivative Works
101− that You distribute, all copyright, patent, trademark, and
102− attribution notices from the Source form of the Work,
103− excluding those notices that do not pertain to any part of
104− the Derivative Works; and
105−
106− (d) If the Work includes a "NOTICE" text file as part of its
107− distribution, then any Derivative Works that You distribute must
108− include a readable copy of the attribution notices contained
109− within such NOTICE file, excluding those notices that do not
110− pertain to any part of the Derivative Works, in at least one
111− of the following places: within a NOTICE text file distributed
112− as part of the Derivative Works; within the Source form or
113− documentation, if provided along with the Derivative Works; or,
114− within a display generated by the Derivative Works, if and
115− wherever such third-party notices normally appear. The contents
116− of the NOTICE file are for informational purposes only and
117− do not modify the License. You may add Your own attribution
118− notices within Derivative Works that You distribute, alongside
119− or as an addendum to the NOTICE text from the Work, provided
120− that such additional attribution notices cannot be construed
121− as modifying the License.
122−
123− You may add Your own copyright statement to Your modifications and
124− may provide additional or different license terms and conditions
125− for use, reproduction, or distribution of Your modifications, or
126− for any such Derivative Works as a whole, provided Your use,
127− reproduction, and distribution of the Work otherwise complies with
128− the conditions stated in this License.
129−
130− 5. Submission of Contributions. Unless You explicitly state otherwise,
131− any Contribution intentionally submitted for inclusion in the Work
132− by You to the Licensor shall be under the terms and conditions of
133− this License, without any additional terms or conditions.
134− Notwithstanding the above, nothing herein shall supersede or modify
135− the terms of any separate license agreement you may have executed
136− with Licensor regarding such Contributions.
137−
138− 6. Trademarks. This License does not grant permission to use the trade
139− names, trademarks, service marks, or product names of the Licensor,
140− except as required for reasonable and customary use in describing the
141− origin of the Work and reproducing the content of the NOTICE file.
142−
143− 7. Disclaimer of Warranty. Unless required by applicable law or
144− agreed to in writing, Licensor provides the Work (and each
145− Contributor provides its Contributions) on an "AS IS" BASIS,
146− WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147− implied, including, without limitation, any warranties or conditions
148− of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149− PARTICULAR PURPOSE. You are solely responsible for determining the
150− appropriateness of using or redistributing the Work and assume any
151− risks associated with Your exercise of permissions under this License.
152−
153− 8. Limitation of Liability. In no event and under no legal theory,
154− whether in tort (including negligence), contract, or otherwise,
155− unless required by applicable law (such as deliberate and grossly
156− negligent acts) or agreed to in writing, shall any Contributor be
157− liable to You for damages, including any direct, indirect, special,
158− incidental, or consequential damages of any character arising as a
159− result of this License or out of the use or inability to use the
160− Work (including but not limited to damages for loss of goodwill,
161− work stoppage, computer failure or malfunction, or any and all
162− other commercial damages or losses), even if such Contributor
163− has been advised of the possibility of such damages.
164−
165− 9. Accepting Warranty or Additional Liability. While redistributing
166− the Work or Derivative Works thereof, You may choose to offer,
167− and charge a fee for, acceptance of support, warranty, indemnity,
168− or other liability obligations and/or rights consistent with this
169− License. However, in accepting such obligations, You may act only
170− on Your own behalf and on Your sole responsibility, not on behalf
171− of any other Contributor, and only if You agree to indemnify,
172− defend, and hold each Contributor harmless for any liability
173− incurred by, or claims asserted against, such Contributor by reason
174− of your accepting any such warranty or additional liability.
175−
176− END OF TERMS AND CONDITIONS
177−
178− APPENDIX: How to apply the Apache License to your work.
179−
180− To apply the Apache License to your work, attach the following
181− boilerplate notice, with the fields enclosed by brackets "[]"
182− replaced with your own identifying information. (Don't include
183− the brackets!) The text should be enclosed in the appropriate
184− comment syntax for the file format. We also recommend that a
185− file or class name and description of purpose be included on the
186− same "printed page" as the copyright notice for easier
187− identification within third-party archives.
188−
189− Copyright 2019 Digital Asset (Switzerland) GmbH and/or its affiliates
190−
191− Licensed under the Apache License, Version 2.0 (the "License");
192− you may not use this file except in compliance with the License.
193− You may obtain a copy of the License at
194−
195− http://www.apache.org/licenses/LICENSE-2.0
196−
197− Unless required by applicable law or agreed to in writing, software
198− distributed under the License is distributed on an "AS IS" BASIS,
199− WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200− See the License for the specific language governing permissions and
201− limitations under the License.
README.mddeleted−334
@@ -1,334 +0,0 @@
1−# `ghcide` - A library for building Haskell IDE tooling
2−
3−Note: `ghcide` was previously called `hie-core`.
4−
5−Our vision is that you should build an IDE by combining:
6−
7−![vscode](https://raw.githubusercontent.com/digital-asset/ghcide/master/img/vscode2.png)
8−
9−* [`hie-bios`](https://github.com/mpickering/hie-bios) for determining where your files are, what are their dependencies, what extensions are enabled and so on;
10−* `ghcide` (i.e. this library) for defining how to type check, when to type check, and producing diagnostic messages;
11−* A bunch of plugins that haven't yet been written, e.g. [`hie-hlint`](https://github.com/ndmitchell/hlint) and [`hie-ormolu`](https://github.com/tweag/ormolu), to choose which features you want;
12−* [`haskell-lsp`](https://github.com/alanz/haskell-lsp) for sending those messages to a [Language Server Protocol (LSP)](https://microsoft.github.io/language-server-protocol/) server;
13−* An extension for your editor. We provide a [VS Code extension](https://code.visualstudio.com/api) as `extension` in this directory, although the components work in other LSP editors too (see below for instructions using Emacs).
14−
15−There are more details about our approach [in this blog post](https://4ta.uk/p/shaking-up-the-ide).
16−
17−## Features
18−
19−`ghcide` already exports the following features via the lsp protocol:
20−
21−| Feature | LSP name |
22−| - | - |
23−| Display error messages (parse errors, typecheck errors, etc.) and enabled warnings. | diagnostics |
24−| Go to definition in local package | definition |
25−| Display type and source module of values | hover |
26−| Remove redundant imports, replace suggested typos for values and module imports, fill type holes, insert missing type signatures, add suggested ghc extensions | codeAction (quickfix) |
27−
28−
29−## Limitations to Multi-Component support
30−
31−`ghcide` supports loading multiple components into the same session so that
32−features such as go-to definition work across components. However, there are
33−some limitations to this.
34−
35−1. You will get much better results currently manually specifying the hie.yaml file.
36−Until tools like cabal and stack provide the right interface to support multi-component
37−projects, it is always advised to specify explicitly how your project partitions.
38−2. Cross-component features only work if you have loaded at least one file
39−from each component.
40−3. There is a known issue where if you have three components, such that A depends on B which depends on C
41−then if you load A and C into the session but not B then under certain situations you
42−can get strange errors about a type coming from two different places. See [this repo](https://github.com/fendor/ghcide-bad-interface-files) for
43−a simple reproduction of the bug.
44−
45−## Using it
46−
47−### Install `ghcide`
48−
49−#### With Nix
50−
51−Note that you need to compile `ghcide` with the same `ghc` as the project you are working on.
52−
53−1. If the `ghc` you are using matches the version (or better is) from `nixpkgs` it‘s easiest to use the `ghcide` from `nixpkgs`. You can do so via
54− ```
55− nix-env -iA haskellPackages.ghcide
56− ```
57− or e.g. including `pkgs.haskellPackages.ghcide` in your projects `shell.nix`.
58− Depending on your `nixpkgs` channel that might not be the newest `ghcide`, though.
59−
60−2. If your `ghc` does not match nixpkgs you should try the [ghcide-nix repository](https://github.com/cachix/ghcide-nix)
61− which provides a `ghcide` via the `haskell.nix` infrastructure.
62−
63−#### With Cabal or Stack
64−
65−First install the `ghcide` binary using `stack` or `cabal`, e.g.
66−
67−1. `git clone https://github.com/digital-asset/ghcide.git`
68−2. `cd ghcide`
69−3. `cabal install` or `stack install` (and make sure `~/.local/bin` is on your `$PATH`)
70−
71−It's important that `ghcide` is compiled with the same compiler you use to build your projects.
72−
73−### Test `ghcide`
74−
75−Next, check that `ghcide` is capable of loading your code. Change to the project directory and run `ghcide`, which will try and load everything using the same code as the IDE, but in a way that's much easier to understand. For example, taking the example of [`shake`](https://github.com/ndmitchell/shake), running `ghcide` gives some error messages and warnings before reporting at the end:
76−
77−```console
78−Files that failed:
79− * .\model\Main.hs
80− * .\model\Model.hs
81− * .\model\Test.hs
82− * .\model\Util.hs
83− * .\output\docs\Main.hs
84− * .\output\docs\Part_Architecture_md.hs
85−Completed (152 worked, 6 failed)
86−```
87−
88−Of the 158 files in Shake, as of this moment, 152 can be loaded by the IDE, but 6 can't (error messages for the reasons they can't be loaded are given earlier). The failing files are all prototype work or test output, meaning I can confidently use Shake.
89−
90−The `ghcide` executable mostly relies on [`hie-bios`](https://github.com/mpickering/hie-bios) to do the difficult work of setting up your GHC environment. If it doesn't work, see [the `hie-bios` manual](https://github.com/mpickering/hie-bios#readme) to get it working. My default fallback is to figure it out by hand and create a `direct` style [`hie.yaml`](https://github.com/ndmitchell/shake/blob/master/hie.yaml) listing the command line arguments to load the project.
91−
92−If you can't get `ghcide` working outside the editor, see [this setup troubleshooting guide](docs/Setup.md). Once you have got `ghcide` working outside the editor, the next step is to pick which editor to integrate with.
93−
94−### Optimal project setup
95−
96−`ghcide` has been designed to handle projects with hundreds or thousands of modules. If `ghci` can handle it, then `ghcide` should be able to handle it. The only caveat is that this currently requires GHC >= 8.6, and that the first time a module is loaded in the editor will trigger generation of support files in the background if those do not already exist.
97−
98−### Using with VS Code
99−
100−You can install the VSCode extension from the [VSCode
101−marketplace](https://marketplace.visualstudio.com/items?itemName=DigitalAssetHoldingsLLC.ghcide).
102−
103−### Using with Atom
104−
105−You can follow the [instructions](https://github.com/moodmosaic/ide-haskell-ghcide#readme) to install with `apm`.
106−
107−### Using with Sublime Text
108−
109−* Install [LSP](https://packagecontrol.io/packages/LSP)
110−* Press Ctrl+Shift+P or Cmd+Shift+P in Sublime Text and search for *Preferences: LSP Settings*, then paste these settings
111−```
112−{
113− "clients":
114− {
115− "ghcide":
116− {
117− "enabled" : true,
118− "languageId": "haskell",
119− "command" : ["ghcide", "--lsp"],
120− "scopes" : ["source.haskell"],
121− "syntaxes" : ["Packages/Haskell/Haskell.sublime-syntax"]
122− }
123− }
124−}
125−```
126−
127−### Using with Emacs
128−
129−If you don't already have [MELPA](https://melpa.org/#/) package installation configured, visit MELPA [getting started](https://melpa.org/#/getting-started) page to get set up. Then, install [`use-package`](https://melpa.org/#/use-package).
130−
131−Now you have a choice of two different Emacs packages which can be used to communicate with the `ghcide` LSP server:
132−
133−+ `lsp-ui`
134−+ `eglot` (requires Emacs 26.1+)
135−
136−In each case, you can enable support by adding the shown lines to your `.emacs`:
137−
138−#### lsp-ui
139−
140−```elisp
141−;; LSP
142−(use-package flycheck
143− :ensure t
144− :init
145− (global-flycheck-mode t))
146−(use-package yasnippet
147− :ensure t)
148−(use-package lsp-mode
149− :ensure t
150− :hook (haskell-mode . lsp)
151− :commands lsp)
152−(use-package lsp-ui
153− :ensure t
154− :commands lsp-ui-mode)
155−(use-package lsp-haskell
156− :ensure t
157− :config
158− (setq lsp-haskell-process-path-hie "ghcide")
159− (setq lsp-haskell-process-args-hie '())
160− ;; Comment/uncomment this line to see interactions between lsp client/server.
161− ;;(setq lsp-log-io t)
162−)
163−```
164−
165−#### eglot
166−
167−````elisp
168−(use-package eglot
169− :ensure t
170− :config
171− (add-to-list 'eglot-server-programs '(haskell-mode . ("ghcide" "--lsp"))))
172−````
173−
174−### Using with Vim/Neovim
175−
176−#### LanguageClient-neovim
177−Install [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim)
178−
179−Add this to your vim config:
180−```vim
181−let g:LanguageClient_rootMarkers = ['*.cabal', 'stack.yaml']
182−let g:LanguageClient_serverCommands = {
183− \ 'rust': ['rls'],
184− \ 'haskell': ['ghcide', '--lsp'],
185− \ }
186−```
187−
188−Refer to `:he LanguageClient` for more details on usage and configuration.
189−
190−#### vim-lsp
191−Install [vim-lsp](https://github.com/prabirshrestha/vim-lsp).
192−
193−Add this to your vim config:
194−
195−```vim
196−au User lsp_setup call lsp#register_server({
197− \ 'name': 'ghcide',
198− \ 'cmd': {server_info->['/your/path/to/ghcide', '--lsp']},
199− \ 'whitelist': ['haskell'],
200− \ })
201−```
202−
203−To verify it works move your cursor over a symbol and run `:LspHover`.
204−
205−### coc.nvim
206−
207−Install [coc.nvim](https://github.com/neoclide/coc.nvim)
208−
209−Add this to your coc-settings.json (which you can edit with :CocConfig):
210−
211−```json
212−{
213− "languageserver": {
214− "haskell": {
215− "command": "ghcide",
216− "args": [
217− "--lsp"
218− ],
219− "rootPatterns": [
220− ".stack.yaml",
221− ".hie-bios",
222− "BUILD.bazel",
223− "cabal.config",
224− "package.yaml"
225− ],
226− "filetypes": [
227− "hs",
228− "lhs",
229− "haskell"
230− ]
231− }
232− }
233−}
234−```
235−
236−Here's a nice article on setting up neovim and coc: [Vim and Haskell in
237−2019](http://marco-lopes.com/articles/Vim-and-Haskell-in-2019/) (this is actually for haskell-ide, not ghcide)
238−
239−Here is a Docker container that pins down the build and configuration for
240−Neovim and ghcide on a minimal Debian 10 base system:
241−[docker-ghcide-neovim](https://github.com/carlohamalainen/docker-ghcide-neovim/).
242−
243−### SpaceVim
244−
245−In the `autocomplete` layer, add the `autocomplete_method` option to force the use of `coc`:
246−
247−```toml
248−[[layers]]
249− name = 'autocomplete'
250− auto-completion-return-key-behavior = "complete"
251− auto-completion-tab-key-behavior = "smart"
252− [options]
253− autocomplete_method = "coc"
254−```
255−
256−Add this to your coc-settings.json (which you can edit with :CocConfig):
257−
258−```json
259−{
260− "languageserver": {
261− "haskell": {
262− "command": "ghcide",
263− "args": [
264− "--lsp"
265− ],
266− "rootPatterns": [
267− ".stack.yaml",
268− ".hie-bios",
269− "BUILD.bazel",
270− "cabal.config",
271− "package.yaml"
272− ],
273− "filetypes": [
274− "hs",
275− "lhs",
276− "haskell"
277− ]
278− }
279− }
280−}
281−```
282−
283−This example above describes a setup in which `ghcide` is installed
284−using `stack install ghcide` within a project.
285−
286−### Using with Kakoune
287−
288−Install [kak-lsp](https://github.com/ul/kak-lsp).
289−
290−Change `kak-lsp.toml` to include this:
291−
292−```toml
293−[language.haskell]
294−filetypes = ["haskell"]
295−roots = ["Setup.hs", "stack.yaml", "*.cabal", "cabal.project", "hie.yaml"]
296−command = "ghcide"
297−args = ["--lsp"]
298−```
299−
300−## Hacking on ghcide
301−
302−To build and work on `ghcide` itself, you can use Stack or cabal, e.g.,
303−running `stack test` will execute the test suite.
304−If you are using Windows, you should disable the `auto.crlf` setting and configure your editor to use LF line endings, directly or making it use the existing `.editor-config`.
305−
306−If you are chasing down test failures, you can use the tasty-rerun feature by running tests as
307−
308− stack --stack-yaml=stack84.yaml test --test-arguments "--rerun"
309−
310−This writes a log file called `.tasty-rerun-log` of the failures, and only runs those.
311−See the [tasty-rerun](https://hackage.haskell.org/package/tasty-rerun-1.1.17/docs/Test-Tasty-Ingredients-Rerun.html) documentation for other options.
312−
313−### Building the extension
314−
315−For development, you can also the VSCode extension from this repository (see
316−https://code.visualstudio.com/docs/setup/mac for details on adding
317−`code` to your `$PATH`):
318−
319−1. `cd extension/`
320−2. `npm ci`
321−3. `npm run vscepackage`
322−4. `code --install-extension ghcide-0.0.1.vsix`
323−
324−Now opening a `.hs` file should work with `ghcide`.
325−
326−## History and relationship to other Haskell IDE's
327−
328−The teams behind this project and the [`haskell-ide-engine`](https://github.com/haskell/haskell-ide-engine#readme) have agreed to join forces under the [`haskell-language-server` project](https://github.com/haskell/haskell-language-server), see the [original announcement](https://neilmitchell.blogspot.com/2020/01/one-haskell-ide-to-rule-them-all.html). The technical work is ongoing, with the likely model being that this project serves as the core, while plugins and integrations are kept in the [`haskell-language-server` project](https://github.com/haskell/haskell-language-server).
329−
330−The code behind `ghcide` was originally developed by [Digital Asset](https://digitalasset.com/) as part of the [DAML programming language](https://github.com/digital-asset/daml). DAML is a smart contract language targeting distributed-ledger runtimes, based on [GHC](https://www.haskell.org/ghc/) with custom language extensions. The DAML programming language has [an IDE](https://webide.daml.com/), and work was done to separate off a reusable Haskell-only IDE (what is now `ghcide`) which the [DAML IDE then builds upon](https://github.com/digital-asset/daml/tree/master/compiler/damlc). Since that time, there have been various [non-Digital Asset contributors](https://github.com/digital-asset/ghcide/graphs/contributors), in addition to continued investment by Digital Asset. All contributions require a [Contributor License Agreement](https://cla.digitalasset.com/digital-asset/ghcide) that states you license the code under the [Apache License](LICENSE).
331−
332−The Haskell community [has](https://github.com/DanielG/ghc-mod) [various](https://github.com/chrisdone/intero) [IDE](https://github.com/rikvdkleij/intellij-haskell) [choices](http://leksah.org/), but the one that had been gathering momentum is [`haskell-ide-engine`](https://github.com/haskell/haskell-ide-engine#readme). Our project owes a debt of gratitude to the `haskell-ide-engine`. We reuse libraries from their ecosystem, including [`hie-bios`](https://github.com/mpickering/hie-bios#readme) (a likely future environment setup layer in `haskell-ide-engine`), [`haskell-lsp`](https://github.com/alanz/haskell-lsp#readme) and [`lsp-test`](https://github.com/bubba/lsp-test#readme) (the `haskell-ide-engine` [LSP protocol](https://microsoft.github.io/language-server-protocol/) pieces). We make heavy use of their contributions to GHC itself, in particular the work to make GHC take string buffers rather than files.
333−
334−The best summary of the architecture of `ghcide` is available [this talk](https://www.youtube.com/watch?v=cijsaeWNf2E&list=PLxxF72uPfQVRdAsvj7THoys-nVj-oc4Ss) ([slides](https://ndmitchell.com/downloads/slides-making_a_haskell_ide-07_sep_2019.pdf)), given at [MuniHac 2019](https://munihac.de/2019.html). However, since that talk the project has renamed from `hie-core` to `ghcide`, and the repo has moved to [this location](https://github.com/digital-asset/ghcide/).
azure-pipelines.ymldeleted−18
@@ -1,18 +0,0 @@
1−# Build master commits
2−trigger:
3− batch: false
4− branches:
5− include:
6− - master
7− - azure*
8−
9−# Enable PR triggers that target the master branch
10−pr:
11− autoCancel: true # cancel previous builds on push
12− branches:
13− include:
14− - master
15−
16−jobs:
17− - template: ./.azure/linux-stack.yml
18− - template: ./.azure/windows-stack.yml
bench/Main.hsdeleted−287
@@ -1,287 +0,0 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE ExistentialQuantification #-}
3−{-# LANGUAGE ImplicitParams #-}
4−
5−{- An automated benchmark built around the simple experiment described in:
6−
7− > https://neilmitchell.blogspot.com/2020/05/fixing-space-leaks-in-ghcide.html
8−
9− As an example project, it unpacks Cabal-3.2.0.0 in the local filesystem and
10− loads the module 'Distribution.Simple'. The rationale for this choice is:
11−
12− - It's convenient to download with `cabal unpack Cabal-3.2.0.0`
13− - It has very few dependencies, and all are already needed to build ghcide
14− - Distribution.Simple has 235 transitive module dependencies, so non trivial
15−
16− The experiments are sequences of lsp commands scripted using lsp-test.
17− A more refined approach would be to record and replay real IDE interactions,
18− once the replay functionality is available in lsp-test.
19− A more declarative approach would be to reuse ide-debug-driver:
20−
21− > https://github.com/digital-asset/daml/blob/master/compiler/damlc/ide-debug-driver/README.md
22−
23− The result of an experiment is a total duration in seconds after a preset
24− number of iterations. There is ample room for improvement:
25− - Statistical analysis to detect outliers and auto infer the number of iterations needed
26− - GC stats analysis (currently -S is printed as part of the experiment)
27− - Analyisis of performance over the commit history of the project
28−
29− How to run:
30− 1. `cabal bench`
31− 2. `cabal exec <absolute-path-to-ghcide-bench> -- ghcide-bench-options`
32−
33− Note that the package database influences the response times of certain actions,
34− e.g. code actions, and therefore the two methods above do not necessarily
35− produce the same results.
36−
37− -}
38−
39−import Control.Applicative.Combinators
40−import Control.Concurrent
41−import Control.Exception.Safe
42−import Control.Monad.Extra
43−import Control.Monad.IO.Class
44−import Data.Aeson
45−import Data.List
46−import Data.Maybe
47−import Data.Version
48−import Language.Haskell.LSP.Test
49−import Language.Haskell.LSP.Types
50−import Language.Haskell.LSP.Types.Capabilities
51−import Numeric.Natural
52−import Options.Applicative
53−import System.Directory
54−import System.FilePath ((</>))
55−import System.Process
56−import System.Time.Extra
57−
58−-- Points to a string in the target file,
59−-- convenient for hygienic edits
60−hygienicP :: Position
61−hygienicP = Position 854 23
62−
63−-- Points to the middle of an identifier,
64−-- convenient for requesting goto-def, hover and completions
65−identifierP :: Position
66−identifierP = Position 853 12
67−
68−main :: IO ()
69−main = do
70− config <- execParser $ info configP fullDesc
71− let ?config = config
72−
73− output "starting test"
74−
75− cleanUp <- setup
76−
77− runBenchmarks
78− [ ---------------------------------------------------------------------------------------
79− bench "hover" 10 $ \doc ->
80− isJust <$> getHover doc identifierP,
81− ---------------------------------------------------------------------------------------
82− bench "getDefinition" 10 $ \doc ->
83− not . null <$> getDefinitions doc identifierP,
84− ---------------------------------------------------------------------------------------
85− bench "documentSymbols" 100 $
86− fmap (either (not . null) (not . null)) . getDocumentSymbols,
87− ---------------------------------------------------------------------------------------
88− bench "documentSymbols after edit" 100 $ \doc -> do
89− let change =
90− TextDocumentContentChangeEvent
91− { _range = Just (Range hygienicP hygienicP),
92− _rangeLength = Nothing,
93− _text = " "
94− }
95− changeDoc doc [change]
96− either (not . null) (not . null) <$> getDocumentSymbols doc,
97− ---------------------------------------------------------------------------------------
98− bench "completions after edit" 10 $ \doc -> do
99− let change =
100− TextDocumentContentChangeEvent
101− { _range = Just (Range hygienicP hygienicP),
102− _rangeLength = Nothing,
103− _text = " "
104− }
105− changeDoc doc [change]
106− not . null <$> getCompletions doc identifierP,
107− ---------------------------------------------------------------------------------------
108− benchWithSetup
109− "code actions"
110− 10
111− ( \doc -> do
112− let p = identifierP
113− let change =
114− TextDocumentContentChangeEvent
115− { _range = Just (Range p p),
116− _rangeLength = Nothing,
117− _text = "a"
118− }
119− changeDoc doc [change]
120− void (skipManyTill anyMessage message :: Session WorkDoneProgressEndNotification)
121− return p
122− )
123− ( \p doc -> do
124− not . null <$> getCodeActions doc (Range p p)
125− ),
126− ---------------------------------------------------------------------------------------
127− bench "code actions after edit" 10 $ \doc -> do
128− let p = identifierP
129− let change =
130− TextDocumentContentChangeEvent
131− { _range = Just (Range p p),
132− _rangeLength = Nothing,
133− _text = "a"
134− }
135− changeDoc doc [change]
136− void (skipManyTill anyMessage message :: Session WorkDoneProgressEndNotification)
137− not . null <$> getCodeActions doc (Range p p)
138− ]
139− `finally` cleanUp
140−
141−---------------------------------------------------------------------------------------------
142−
143−examplePackageName :: String
144−examplePackageName = "Cabal"
145−
146−examplePackageVersion :: Version
147−examplePackageVersion = makeVersion [3, 2, 0, 0]
148−
149−examplePackage :: String
150−examplePackage = examplePackageName <> "-" <> showVersion examplePackageVersion
151−
152−exampleModulePath :: FilePath
153−exampleModulePath = "Distribution" </> "Simple.hs"
154−
155−examplesPath :: FilePath
156−examplesPath = "bench/example"
157−
158−data Config = Config
159− { verbose :: !Bool,
160− -- For some reason, the Shake profile files are truncated and won't load
161− shakeProfiling :: !(Maybe FilePath),
162− outputCSV :: !Bool
163− }
164−
165−type HasConfig = (?config :: Config)
166−
167−configP :: Parser Config
168−configP = Config
169− <$> (not <$> switch (long "quiet"))
170− <*> optional (strOption (long "shake-profiling" <> metavar "PATH"))
171− <*> switch (long "csv")
172−
173−output :: (MonadIO m, HasConfig) => String -> m ()
174−output = if verbose ?config then liftIO . putStrLn else (\_ -> pure ())
175−
176−---------------------------------------------------------------------------------------
177−
178−type Experiment = TextDocumentIdentifier -> Session Bool
179−
180−data Bench = forall setup.
181− Bench
182− { name :: !String,
183− samples :: !Natural,
184− benchSetup :: TextDocumentIdentifier -> Session setup,
185− experiment :: setup -> Experiment
186− }
187−
188−bench :: String -> Natural -> Experiment -> Bench
189−bench name samples userExperiment = Bench {..}
190− where
191− experiment () = userExperiment
192− benchSetup _ = return ()
193−
194−benchWithSetup ::
195− String ->
196− Natural ->
197− (TextDocumentIdentifier -> Session p) ->
198− (p -> Experiment) ->
199− Bench
200−benchWithSetup = Bench
201−
202−runBenchmarks :: HasConfig => [Bench] -> IO ()
203−runBenchmarks benchmarks = do
204− results <- forM benchmarks $ \b -> (b,) <$> runBench b
205−
206− forM_ results $ \(Bench {name, samples}, duration) ->
207− output $
208− "TOTAL "
209− <> name
210− <> " = "
211− <> showDuration duration
212− <> " ("
213− <> show samples
214− <> " repetitions)"
215−
216− when (outputCSV ?config) $ do
217− putStrLn $ intercalate ", " $ map name benchmarks
218− putStrLn $ intercalate ", " $ map (showDuration . snd) results
219−
220−runBench :: HasConfig => Bench -> IO Seconds
221−runBench Bench {..} = handleAny (\e -> print e >> return (-1))
222− $ runSessionWithConfig conf cmd lspTestCaps dir
223− $ do
224− doc <- openDoc exampleModulePath "haskell"
225− void (skipManyTill anyMessage message :: Session WorkDoneProgressEndNotification)
226−
227− liftIO $ output $ "Running " <> name <> " benchmark"
228− userState <- benchSetup doc
229− let loop 0 = return True
230− loop n = do
231− (t, res) <- duration $ experiment userState doc
232− if not res
233− then return False
234− else do
235− output (showDuration t)
236− loop (n -1)
237−
238− (t, res) <- duration $ loop samples
239−
240− exitServer
241− -- sleeep to give ghcide a chance to print the RTS stats
242− liftIO $ threadDelay 50000
243−
244− return $ if res then t else -1
245− where
246− cmd =
247− unwords $
248− [ "ghcide",
249− "--lsp",
250− "--cwd",
251− dir,
252− "+RTS",
253− "-S",
254− "-RTS"
255− ]
256− ++ concat
257− [ ["--shake-profiling", path]
258− | Just path <- [shakeProfiling ?config]
259− ]
260− dir = "bench/example/" <> examplePackage
261− lspTestCaps =
262− fullCaps {_window = Just $ WindowClientCapabilities $ Just True}
263− conf =
264− defaultConfig
265− { logStdErr = verbose ?config,
266− logMessages = False,
267− logColor = False
268− }
269−
270−setup :: HasConfig => IO (IO ())
271−setup = do
272− alreadyExists <- doesDirectoryExist examplesPath
273− when alreadyExists $ removeDirectoryRecursive examplesPath
274− callCommand $ "cabal get -v0 " <> examplePackage <> " -d " <> examplesPath
275− writeFile
276− (examplesPath </> examplePackage </> "hie.yaml")
277− ("cradle: {cabal: {component: " <> show examplePackageName <> "}}")
278−
279− whenJust (shakeProfiling ?config) $ createDirectoryIfMissing True
280−
281− return $ removeDirectoryRecursive examplesPath
282−
283−-- | Asks the server to shutdown and exit politely
284−exitServer :: Session ()
285−exitServer = request_ Shutdown (Nothing :: Maybe Value) >> sendNotification Exit ExitParams
286−
287−--------------------------------------------------------------------------------------------
cbits/getmodtime.cdeleted−21
@@ -1,21 +0,0 @@
1−// Copyright (c) 2019 The DAML Authors. All rights reserved.
2−// SPDX-License-Identifier: Apache-2.0
3−
4−#include <sys/stat.h>
5−#include <time.h>
6−int getmodtime(const char* pathname, time_t* sec, long* nsec) {
7− struct stat s;
8− int r = stat(pathname, &s);
9− if (r != 0) {
10− return r;
11− }
12−#ifdef __APPLE__
13− *sec = s.st_mtimespec.tv_sec;
14− *nsec = s.st_mtimespec.tv_nsec;
15−#else
16− *sec = s.st_mtim.tv_sec;
17− *nsec = s.st_mtim.tv_nsec;
18−#endif
19− return 0;
20−}
21−
docs/Setup.mddeleted−145
@@ -1,145 +0,0 @@
1−# Setup Troubleshooting
2−
3−This page serves as a dumping ground for setup problems and their resolutions. We recommend everyone first runs `ghcide` on the console to check what files in their project load, and only the moves on to using `ghcide` through an editor (e.g. VS Code).
4−
5−## "mismatched interface file versions"
6−
7−If you see a problem such as:
8−
9−```console
10−File: ./test/Spec.hs
11−Range: 1:0-1:0
12−Source: typecheck
13−Severity: DsError
14−Message:
15− test/Spec.hs:1:1: error:
16− Bad interface file:
17− /Users/daml/.stack/programs/x86_64-osx/ghc-8.6.4/lib/ghc-8.6.4/base-4.12.0.0/Prelude.hi
18− mismatched interface file versions (wanted "8065", got "8064")
19−```
20−
21−The cause is that your program is configured to use a different GHC to the one you built `ghcide` with. In `ghcide` you can view the version number it was compiled with on the first line as:
22−
23−```console
24−ghcide version: 0.0.3 (GHC: 8.6.5)
25−```
26−
27−You can see the version of GHC being used by this project in the second-last line of the output with `ghc-8.6.4/`, or in in mismatch interfaces of wanted `8065` (aka 8.6.5), got `8064` (aka 8.6.4). The solution is to use the same GHC version in both places.
28−
29−## “failed to load interface for ‘…’ There are files missing”
30−
31−If you see a problem such as:
32−
33−```console
34−File: ./src/File/FileStream.hs
35−Range: 1:0-100001:0
36−Source: typecheck
37−Severity: DsError
38−Message:
39− Program error: Failed to load interface for ‘Data.DList’
40−Files that failed:
41− There are files missing in the ‘dlist-0.8.0.7’ package,
42− * ./src/File/FileStream.hs
43− try running 'ghc-pkg check'.
44− Use -v to see a list of the files searched for.
45−```
46−
47−It might be caused by `ghcide` picking up the wrong cradle. In
48−particular, this has been observed when running in a `nix-shell` where
49−`ghcide` picked up the default cradle. Try setting the cradle
50−explicitly, e.g., to use the cabal cradle create a `hie.yaml` file
51−with the following content:
52−
53−```
54−cradle: {cabal: {component: "mylibrary"}}
55−```
56−
57−If you are using stack, find the list of names you can use:
58−
59− $ stack ide targets
60− mypackage:lib
61− mypackage:exe:mypackage-exe
62− mypackage:test:mypackage-test
63−
64−and create a `hie.yaml` file as follows:
65−
66− {stack: {component: "mypackage:lib"}}
67−
68−## ghc: readCreateProcess: does not exist
69−
70−On Linux: try `stack exec ghcide`` instead of `ghcide` directly.
71−
72−I was getting this in Windows: `ghcide.exe: ghc: readCreateProcess: does not exist (No such file or directory)`
73−
74−And we figured a hack around for this:
75−
76−VSCode user or workspace settings, add these:
77−
78− "hic.executablePath": "stack",
79− "hic.arguments": "exec ghcide -- --lsp"
80−
81−Since I use stack. Required if you don't have a `ghc` on your path.
82−
83−## Could not find module ...
84−
85−Try adding an explicit `hie.yaml` file and see if that helps.
86−
87−## Ambiguous main module
88−
89−```console
90−$ stack exec ghcide
91−
92−...
93−
94−ghcide: CradleError (ExitFailure 1) ["Failed to parse result of calling stack","","* * * * * * * *","The main module to load is ambiguous. Candidates are: ","1. Package `mypackage' component mypackage:exe:mypackage-exe with main-is file: /home/user/mypackage/app/Main.hs","2. Package `mypackage' component mypackage:exe:otherbin-exe with main-is file: /home/user/mypackage/app/otherbin.hs","You can specify which one to pick by: "," * Specifying targets to stack ghci e.g. stack ghci mypackage:exe:mypackage-exe"," * Specifying what the main is e.g. stack ghci --main-is mypackage:exe:mypackage-exe"," * Choosing from the candidate above [1..2]","* * * * * * * *","","<stdin>: hGetLine: end of file"]
95−```
96−
97−Add a `hie.yaml` file to specify the module, e.g.
98−
99− cradle: {stack: {component: "mypackage:exe:mypackage-exe"}}
100−
101−## Works in `ghcide` but not my editor
102−
103−Does `ghcide` alone work on the console? Did you first enter a Nix shell? Or run `stack exec ghcide`? If so, there are two options:
104−
105−1. Run your editor via the same mechanism, e.g. `stack exec code`.
106−2. Change the extension to use the executable as `stack` and the arguments as `exec -- ghcide --lsp`.
107−
108−## Issues with Nix
109−
110−If you are using packages installed by Nix, then often Nix will set `NIX_GHC_LIBDIR` to say where the libraries are installed. `ghcide` can cope with that. However, sometimes the `ghc` on your shell will actually be a shell script that sets `NIX_GHC_LIBDIR`, which `ghcide` can't find. If that happens, you need to either set `NIX_GHC_LIBDIR` (so `ghcide` can see it) or use a proper [Nix compatible wrapper](https://github.com/hercules-ci/ghcide-nix) over `ghcide`.
111−
112−## ghcide: this operation requires -fexternal-interpreter
113−
114−This can happen if you have a GHC compiled without GHC library support. This seems to be [the case](https://github.com/input-output-hk/haskell.nix/issues/313) with `haskell.nix` at the moment.
115−
116−## Symbol’s value as variable is void: capability
117−
118−As described [here](https://github.com/emacs-lsp/lsp-mode/issues/770#issuecomment-483540119) and [here](https://github.com/emacs-lsp/lsp-mode/issues/517#issuecomment-445448700), the default installation of `lsp-mode`, `lsp-ui`, `lsp-ui-mode` and `lsp-haskell` as described in [ghcide's "Using with Emacs" section](https://github.com/digital-asset/ghcide/#using-with-emacs) may result in the following error message:
119−
120−```
121−Symbol’s value as variable is void: capability
122−```
123−
124−This can be caused by either an old version of the Emacs package `dash`, or a cached `.elc` file for an old version. A fix consists of (re)moving the old package from ~/.emacs.d/elpa/ and installing it again, e.g. via M-x `package-list-packages` RET and M-x `package-install` RET `dash` RET. If this is not enough,
125−
126−```
127−find ~/.emacs.d -name '*.elc' -exec rm {} \;
128−```
129−
130−(which causes recompilation of all bytecode-compiled scripts.)
131−
132−
133−## Docker stack builds
134−
135−You're likely to see `ghcide: (ExitFailure 1,"","")`. Because ghcide can't get at the ghc installed inside Docker, your best bet is to `stack exec ghcide` and make sure `ghcide` is installed within the container. Full details at [issue 221](https://github.com/digital-asset/ghcide/issues/221).
136−
137−## stty error on Windows + Stack
138−
139−If you get an error like:
140−
141−```
142−ghcide.exe: CradleError (ExitFailure 1) ["Failed to parse result of calling stack","'stty' is not recognized as an internal or external command,","operable program or batch file."
143−```
144−
145−Then the workaround from https://github.com/haskell/haskell-ide-engine/issues/1428#issuecomment-547530794 might help.
exe/Arguments.hsdeleted−35
@@ -1,35 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−module Arguments(Arguments(..), getArguments) where
5−
6−import Options.Applicative
7−
8−
9−data Arguments = Arguments
10− {argLSP :: Bool
11− ,argsCwd :: Maybe FilePath
12− ,argFiles :: [FilePath]
13− ,argsVersion :: Bool
14− ,argsShakeProfiling :: Maybe FilePath
15− ,argsTesting :: Bool
16− ,argsThreads :: Int
17− }
18−
19−getArguments :: IO Arguments
20−getArguments = execParser opts
21− where
22− opts = info (arguments <**> helper)
23− ( fullDesc
24− <> progDesc "Used as a test bed to check your IDE will work"
25− <> header "ghcide - the core of a Haskell IDE")
26−
27−arguments :: Parser Arguments
28−arguments = Arguments
29− <$> switch (long "lsp" <> help "Start talking to an LSP server")
30− <*> optional (strOption $ long "cwd" <> metavar "DIR" <> help "Change to this directory")
31− <*> many (argument str (metavar "FILES/DIRS..."))
32− <*> switch (long "version" <> help "Show ghcide and GHC versions")
33− <*> optional (strOption $ long "shake-profiling" <> metavar "DIR" <> help "Dump profiling reports to this directory")
34− <*> switch (long "test" <> help "Enable additional lsp messages used by the testsuite")
35− <*> option auto (short 'j' <> help "Number of threads (0: automatic)" <> metavar "NUM" <> value 0 <> showDefault)
exe/Main.hsdeleted−683
@@ -1,683 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−{-# OPTIONS_GHC -Wno-dodgy-imports #-} -- GHC no longer exports def in GHC 8.6 and above
4−{-# LANGUAGE CPP #-} -- To get precise GHC version
5−{-# LANGUAGE TemplateHaskell #-}
6−{-# LANGUAGE TypeFamilies #-}
7−
8−module Main(main) where
9−
10−import Linker (initDynLinker)
11−import Data.IORef
12−import NameCache
13−import Packages
14−import Module
15−import Arguments
16−import Control.Concurrent.Async
17−import Control.Concurrent.Extra
18−import Control.Exception
19−import Control.Monad.Extra
20−import Control.Monad.IO.Class
21−import Data.Default
22−import Data.Either
23−import Data.Function
24−import Data.List.Extra
25−import Data.Maybe
26−import qualified Data.Text as T
27−import qualified Data.Text.IO as T
28−import Data.Time.Clock (UTCTime)
29−import Data.Version
30−import Development.IDE.Core.Debouncer
31−import Development.IDE.Core.FileStore
32−import Development.IDE.Core.OfInterest
33−import Development.IDE.Core.Service
34−import Development.IDE.Core.Rules
35−import Development.IDE.Core.Shake
36−import Development.IDE.Core.RuleTypes
37−import Development.IDE.LSP.Protocol
38−import Development.IDE.Types.Location
39−import Development.IDE.Types.Diagnostics
40−import Development.IDE.Types.Options
41−import Development.IDE.Types.Logger
42−import Development.IDE.GHC.Util
43−import Development.IDE.Plugin
44−import Development.IDE.Plugin.Completions as Completions
45−import Development.IDE.Plugin.CodeAction as CodeAction
46−import qualified Language.Haskell.LSP.Core as LSP
47−import Language.Haskell.LSP.Messages
48−import Language.Haskell.LSP.Types
49−import Data.Aeson (ToJSON(toJSON))
50−import Development.IDE.LSP.LanguageServer
51−import qualified System.Directory.Extra as IO
52−import System.Environment
53−import System.IO
54−import System.Exit
55−import System.FilePath
56−import System.Directory
57−import System.Time.Extra
58−import HIE.Bios.Environment (addCmdOpts, makeDynFlagsAbsolute)
59−import Paths_ghcide
60−import Development.GitRev
61−import Development.Shake (Action, action)
62−import qualified Data.HashSet as HashSet
63−import qualified Data.HashMap.Strict as HM
64−import qualified Data.Map.Strict as Map
65−import qualified Crypto.Hash.SHA1 as H
66−import qualified Data.ByteString.Char8 as B
67−import Data.ByteString.Base16 (encode)
68−import DynFlags (gopt_set, gopt_unset, updOptLevel, PackageFlag(..), PackageArg(..))
69−import GhcMonad
70−import HscTypes (HscEnv(..), ic_dflags)
71−import GHC hiding (def)
72−import GHC.Check ( VersionCheck(..), makeGhcVersionChecker )
73−import Data.Either.Extra
74−
75−import HIE.Bios.Cradle
76−import HIE.Bios.Types
77−
78−import Utils
79−
80−ghcideVersion :: IO String
81−ghcideVersion = do
82− path <- getExecutablePath
83− let gitHashSection = case $(gitHash) of
84− x | x == "UNKNOWN" -> ""
85− x -> " (GIT hash: " <> x <> ")"
86− return $ "ghcide version: " <> showVersion version
87− <> " (GHC: " <> VERSION_ghc
88− <> ") (PATH: " <> path <> ")"
89− <> gitHashSection
90−
91−main :: IO ()
92−main = do
93− -- WARNING: If you write to stdout before runLanguageServer
94− -- then the language server will not work
95− Arguments{..} <- getArguments
96−
97− if argsVersion then ghcideVersion >>= putStrLn >> exitSuccess
98− else hPutStrLn stderr {- see WARNING above -} =<< ghcideVersion
99−
100− -- lock to avoid overlapping output on stdout
101− lock <- newLock
102− let logger p = Logger $ \pri msg -> when (pri >= p) $ withLock lock $
103− T.putStrLn $ T.pack ("[" ++ upper (show pri) ++ "] ") <> msg
104−
105− whenJust argsCwd IO.setCurrentDirectory
106−
107− dir <- IO.getCurrentDirectory
108− command <- makeLspCommandId "typesignature.add"
109−
110− let plugins = Completions.plugin <> CodeAction.plugin
111− onInitialConfiguration = const $ Right ()
112− onConfigurationChange = const $ Right ()
113− options = def { LSP.executeCommandCommands = Just [command]
114− , LSP.completionTriggerCharacters = Just "."
115− }
116−
117− if argLSP then do
118− t <- offsetTime
119− hPutStrLn stderr "Starting LSP server..."
120− hPutStrLn stderr "If you are seeing this in a terminal, you probably should have run ghcide WITHOUT the --lsp option!"
121− runLanguageServer options (pluginHandler plugins) onInitialConfiguration onConfigurationChange $ \getLspId event vfs caps -> do
122− t <- t
123− hPutStrLn stderr $ "Started LSP server in " ++ showDuration t
124− let options = (defaultIdeOptions $ loadSessionShake dir)
125− { optReportProgress = clientSupportsProgress caps
126− , optShakeProfiling = argsShakeProfiling
127− , optTesting = argsTesting
128− , optThreads = argsThreads
129− }
130− debouncer <- newAsyncDebouncer
131− initialise caps (mainRule >> pluginRules plugins >> action kick)
132− getLspId event (logger minBound) debouncer options vfs
133− else do
134− -- GHC produces messages with UTF8 in them, so make sure the terminal doesn't error
135− hSetEncoding stdout utf8
136− hSetEncoding stderr utf8
137−
138− putStrLn $ "Ghcide setup tester in " ++ dir ++ "."
139− putStrLn "Report bugs at https://github.com/digital-asset/ghcide/issues"
140−
141− putStrLn $ "\nStep 1/4: Finding files to test in " ++ dir
142− files <- expandFiles (argFiles ++ ["." | null argFiles])
143− -- LSP works with absolute file paths, so try and behave similarly
144− files <- nubOrd <$> mapM IO.canonicalizePath files
145− putStrLn $ "Found " ++ show (length files) ++ " files"
146−
147− putStrLn "\nStep 2/4: Looking for hie.yaml files that control setup"
148− cradles <- mapM findCradle files
149− let ucradles = nubOrd cradles
150− let n = length ucradles
151− putStrLn $ "Found " ++ show n ++ " cradle" ++ ['s' | n /= 1]
152− putStrLn "\nStep 3/4: Initializing the IDE"
153− vfs <- makeVFSHandle
154− debouncer <- newAsyncDebouncer
155− ide <- initialise def mainRule (pure $ IdInt 0) (showEvent lock) (logger Info) debouncer (defaultIdeOptions $ loadSessionShake dir) vfs
156−
157− putStrLn "\nStep 4/4: Type checking the files"
158− setFilesOfInterest ide $ HashSet.fromList $ map toNormalizedFilePath' files
159− results <- runActionSync ide $ uses TypeCheck (map toNormalizedFilePath' files)
160− let (worked, failed) = partition fst $ zip (map isJust results) files
161− when (failed /= []) $
162− putStr $ unlines $ "Files that failed:" : map ((++) " * " . snd) failed
163−
164− let files xs = let n = length xs in if n == 1 then "1 file" else show n ++ " files"
165− putStrLn $ "\nCompleted (" ++ files worked ++ " worked, " ++ files failed ++ " failed)"
166− return ()
167−
168−expandFiles :: [FilePath] -> IO [FilePath]
169−expandFiles = concatMapM $ \x -> do
170− b <- IO.doesFileExist x
171− if b then return [x] else do
172− let recurse "." = True
173− recurse x | "." `isPrefixOf` takeFileName x = False -- skip .git etc
174− recurse x = takeFileName x `notElem` ["dist","dist-newstyle"] -- cabal directories
175− files <- filter (\x -> takeExtension x `elem` [".hs",".lhs"]) <$> IO.listFilesInside (return . recurse) x
176− when (null files) $
177− fail $ "Couldn't find any .hs/.lhs files inside directory: " ++ x
178− return files
179−
180−
181−kick :: Action ()
182−kick = do
183− files <- getFilesOfInterest
184− void $ uses TypeCheck $ HashSet.toList files
185−
186−-- | Print an LSP event.
187−showEvent :: Lock -> FromServerMessage -> IO ()
188−showEvent _ (EventFileDiagnostics _ []) = return ()
189−showEvent lock (EventFileDiagnostics (toNormalizedFilePath' -> file) diags) =
190− withLock lock $ T.putStrLn $ showDiagnosticsColored $ map (file,ShowDiag,) diags
191−showEvent lock e = withLock lock $ print e
192−
193−
194−-- | Run the specific cradle on a specific FilePath via hie-bios.
195−cradleToSessionOpts :: Cradle a -> FilePath -> IO (Either [CradleError] ComponentOptions)
196−cradleToSessionOpts cradle file = do
197− let showLine s = putStrLn ("> " ++ s)
198− cradleRes <- runCradle (cradleOptsProg cradle) showLine file
199− case cradleRes of
200− CradleSuccess r -> pure (Right r)
201− CradleFail err -> return (Left [err])
202− -- For the None cradle perhaps we still want to report an Info
203− -- message about the fact that the file is being ignored.
204− CradleNone -> return (Left [])
205−
206−emptyHscEnv :: IO HscEnv
207−emptyHscEnv = do
208− libdir <- getLibdir
209− env <- runGhc (Just libdir) getSession
210− initDynLinker env
211− pure env
212−
213−-- | Convert a target to a list of potential absolute paths.
214−-- A TargetModule can be anywhere listed by the supplied include
215−-- directories
216−-- A target file is a relative path but with a specific prefix so just need
217−-- to canonicalise it.
218−targetToFile :: [FilePath] -> TargetId -> IO [NormalizedFilePath]
219−targetToFile is (TargetModule mod) = do
220− let fps = [i </> moduleNameSlashes mod -<.> ext | ext <- exts, i <- is ]
221− exts = ["hs", "hs-boot", "lhs"]
222− mapM (fmap toNormalizedFilePath' . canonicalizePath) fps
223−targetToFile _ (TargetFile f _) = do
224− f' <- canonicalizePath f
225− return [toNormalizedFilePath' f']
226−
227−setNameCache :: IORef NameCache -> HscEnv -> HscEnv
228−setNameCache nc hsc = hsc { hsc_NC = nc }
229−
230−loadSessionShake :: FilePath -> Action (FilePath -> Action (IdeResult HscEnvEq))
231−loadSessionShake fp = do
232− se <- getShakeExtras
233− IdeOptions{optTesting} <- getIdeOptions
234− res <- liftIO $ loadSession optTesting se fp
235− return (fmap liftIO res)
236−
237−-- | This is the key function which implements multi-component support. All
238−-- components mapping to the same hie.yaml file are mapped to the same
239−-- HscEnv which is updated as new components are discovered.
240−loadSession :: Bool -> ShakeExtras -> FilePath -> IO (FilePath -> IO (IdeResult HscEnvEq))
241−loadSession optTesting ShakeExtras{logger, eventer} dir = do
242− -- Mapping from hie.yaml file to HscEnv, one per hie.yaml file
243− hscEnvs <- newVar Map.empty :: IO (Var HieMap)
244− -- Mapping from a Filepath to HscEnv
245− fileToFlags <- newVar Map.empty :: IO (Var FlagsMap)
246−
247− -- This caches the mapping from Mod.hs -> hie.yaml
248− cradleLoc <- memoIO $ \v -> do
249− res <- findCradle v
250− -- Sometimes we get C:, sometimes we get c:, and sometimes we get a relative path
251− -- try and normalise that
252− -- e.g. see https://github.com/digital-asset/ghcide/issues/126
253− res' <- traverse IO.makeAbsolute res
254− return $ normalise <$> res'
255−
256− -- Create a new HscEnv from a hieYaml root and a set of options
257− -- If the hieYaml file already has an HscEnv, the new component is
258− -- combined with the components in the old HscEnv into a new HscEnv
259− -- which contains the union.
260− let packageSetup :: (Maybe FilePath, NormalizedFilePath, ComponentOptions)
261− -> IO (HscEnv, ComponentInfo, [ComponentInfo])
262− packageSetup (hieYaml, cfp, opts) = do
263− -- Parse DynFlags for the newly discovered component
264− hscEnv <- emptyHscEnv
265− (df, targets) <- evalGhcEnv hscEnv $
266− setOptions opts (hsc_dflags hscEnv)
267− dep_info <- getDependencyInfo (componentDependencies opts ++ maybeToList hieYaml)
268− -- Now lookup to see whether we are combining with an existing HscEnv
269− -- or making a new one. The lookup returns the HscEnv and a list of
270− -- information about other components loaded into the HscEnv
271− -- (unitId, DynFlag, Targets)
272− modifyVar hscEnvs $ \m -> do
273− -- Just deps if there's already an HscEnv
274− -- Nothing is it's the first time we are making an HscEnv
275− let oldDeps = Map.lookup hieYaml m
276− let -- Add the raw information about this component to the list
277− -- We will modify the unitId and DynFlags used for
278− -- compilation but these are the true source of
279− -- information.
280− new_deps = RawComponentInfo (thisInstalledUnitId df) df targets cfp opts dep_info
281− : maybe [] snd oldDeps
282− -- Get all the unit-ids for things in this component
283− inplace = map rawComponentUnitId new_deps
284−
285− new_deps' <- forM new_deps $ \RawComponentInfo{..} -> do
286− -- Remove all inplace dependencies from package flags for
287− -- components in this HscEnv
288− let (df2, uids) = removeInplacePackages inplace rawComponentDynFlags
289− let prefix = show rawComponentUnitId
290− -- See Note [Avoiding bad interface files]
291− processed_df <- setCacheDir logger prefix (sort $ map show uids) opts df2
292− -- The final component information, mostly the same but the DynFlags don't
293− -- contain any packages which are also loaded
294− -- into the same component.
295− pure $ ComponentInfo rawComponentUnitId
296− processed_df
297− uids
298− rawComponentTargets
299− rawComponentFP
300− rawComponentCOptions
301− rawComponentDependencyInfo
302− -- Make a new HscEnv, we have to recompile everything from
303− -- scratch again (for now)
304− -- It's important to keep the same NameCache though for reasons
305− -- that I do not fully understand
306− logInfo logger (T.pack ("Making new HscEnv" ++ show inplace))
307− hscEnv <- case oldDeps of
308− Nothing -> emptyHscEnv
309− Just (old_hsc, _) -> setNameCache (hsc_NC old_hsc) <$> emptyHscEnv
310− newHscEnv <-
311− -- Add the options for the current component to the HscEnv
312− evalGhcEnv hscEnv $ do
313− _ <- setSessionDynFlags df
314− getSession
315− -- Modify the map so the hieYaml now maps to the newly created
316− -- HscEnv
317− -- Returns
318− -- . the new HscEnv so it can be used to modify the
319− -- FilePath -> HscEnv map (fileToFlags)
320− -- . The information for the new component which caused this cache miss
321− -- . The modified information (without -inplace flags) for
322− -- existing packages
323− pure (Map.insert hieYaml (newHscEnv, new_deps) m, (newHscEnv, head new_deps', tail new_deps'))
324−
325− let session :: (Maybe FilePath, NormalizedFilePath, ComponentOptions) -> IO (IdeResult HscEnvEq)
326− session (hieYaml, cfp, opts) = do
327− (hscEnv, new, old_deps) <- packageSetup (hieYaml, cfp, opts)
328− -- Make a map from unit-id to DynFlags, this is used when trying to
329− -- resolve imports. (especially PackageImports)
330− let uids = map (\ci -> (componentUnitId ci, componentDynFlags ci)) (new : old_deps)
331−
332− -- For each component, now make a new HscEnvEq which contains the
333− -- HscEnv for the hie.yaml file but the DynFlags for that component
334−
335− -- New HscEnv for the component in question, returns the new HscEnvEq and
336− -- a mapping from FilePath to the newly created HscEnvEq.
337− let new_cache = newComponentCache logger hscEnv uids
338− (cs, res) <- new_cache new
339− -- Modified cache targets for everything else in the hie.yaml file
340− -- which now uses the same EPS and so on
341− cached_targets <- concatMapM (fmap fst . new_cache) old_deps
342− modifyVar_ fileToFlags $ \var -> do
343− pure $ Map.insert hieYaml (HM.fromList (cs ++ cached_targets)) var
344−
345− return (fst res)
346−
347− let consultCradle :: Maybe FilePath -> FilePath -> IO (IdeResult HscEnvEq)
348− consultCradle hieYaml cfp = do
349− when optTesting $ eventer $ notifyCradleLoaded cfp
350− logInfo logger $ T.pack ("Consulting the cradle for " <> show cfp)
351− cradle <- maybe (loadImplicitCradle $ addTrailingPathSeparator dir) loadCradle hieYaml
352− eopts <- cradleToSessionOpts cradle cfp
353− logDebug logger $ T.pack ("Session loading result: " <> show eopts)
354− case eopts of
355− -- The cradle gave us some options so get to work turning them
356− -- into and HscEnv.
357− Right opts -> do
358− session (hieYaml, toNormalizedFilePath' cfp, opts)
359− -- Failure case, either a cradle error or the none cradle
360− Left err -> do
361− dep_info <- getDependencyInfo (maybeToList hieYaml)
362− let ncfp = toNormalizedFilePath' cfp
363− let res = (map (renderCradleError ncfp) err, Nothing)
364− modifyVar_ fileToFlags $ \var -> do
365− pure $ Map.insertWith HM.union hieYaml (HM.singleton ncfp (res, dep_info)) var
366− return res
367−
368− -- This caches the mapping from hie.yaml + Mod.hs -> [String]
369− let sessionOpts :: (Maybe FilePath, FilePath) -> IO (IdeResult HscEnvEq)
370− sessionOpts (hieYaml, file) = do
371− v <- fromMaybe HM.empty . Map.lookup hieYaml <$> readVar fileToFlags
372− cfp <- canonicalizePath file
373− case HM.lookup (toNormalizedFilePath' cfp) v of
374− Just (opts, old_di) -> do
375− deps_ok <- checkDependencyInfo old_di
376− if not deps_ok
377− then do
378− -- If the dependencies are out of date then clear both caches and start
379− -- again.
380− modifyVar_ fileToFlags (const (return Map.empty))
381− -- Keep the same name cache
382− modifyVar_ hscEnvs (return . Map.adjust (\(h, _) -> (h, [])) hieYaml )
383− consultCradle hieYaml cfp
384− else return opts
385− Nothing -> consultCradle hieYaml cfp
386−
387− dummyAs <- async $ return (error "Uninitialised")
388− runningCradle <- newVar dummyAs :: IO (Var (Async (IdeResult HscEnvEq)))
389− -- The main function which gets options for a file. We only want one of these running
390− -- at a time. Therefore the IORef contains the currently running cradle, if we try
391− -- to get some more options then we wait for the currently running action to finish
392− -- before attempting to do so.
393− let getOptions :: FilePath -> IO (IdeResult HscEnvEq)
394− getOptions file = do
395− hieYaml <- cradleLoc file
396− sessionOpts (hieYaml, file)
397− return $ \file -> do
398− join $ mask_ $ modifyVar runningCradle $ \as -> do
399− -- If the cradle is not finished, then wait for it to finish.
400− void $ wait as
401− as <- async $ getOptions file
402− return (as, wait as)
403−
404−
405−
406−-- | Create a mapping from FilePaths to HscEnvEqs
407−newComponentCache
408− :: Logger
409− -> HscEnv
410− -> [(InstalledUnitId, DynFlags)]
411− -> ComponentInfo
412− -> IO ([(NormalizedFilePath, (IdeResult HscEnvEq, DependencyInfo))], (IdeResult HscEnvEq, DependencyInfo))
413−newComponentCache logger hsc_env uids ci = do
414− let df = componentDynFlags ci
415− let hscEnv' = hsc_env { hsc_dflags = df
416− , hsc_IC = (hsc_IC hsc_env) { ic_dflags = df } }
417−
418− versionMismatch <- checkGhcVersion
419− henv <- case versionMismatch of
420− Just mismatch -> return mismatch
421− Nothing -> newHscEnvEq hscEnv' uids
422− let res = (([], Just henv), componentDependencyInfo ci)
423− logDebug logger ("New Component Cache HscEnvEq: " <> T.pack (show res))
424−
425− let is = importPaths df
426− ctargets <- concatMapM (targetToFile is . targetId) (componentTargets ci)
427− -- A special target for the file which caused this wonderful
428− -- component to be created. In case the cradle doesn't list all the targets for
429− -- the component, in which case things will be horribly broken anyway.
430− -- Otherwise, we will immediately attempt to reload this module which
431− -- causes an infinite loop and high CPU usage.
432− let special_target = (componentFP ci, res)
433− let xs = map (,res) ctargets
434− return (special_target:xs, res)
435−
436−{- Note [Avoiding bad interface files]
437−~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
438−Originally, we set the cache directory for the various components once
439−on the first occurrence of the component.
440−This works fine if these components have no references to each other,
441−but you have components that depend on each other, the interface files are
442−updated for each component.
443−After restarting the session and only opening the component that depended
444−on the other, suddenly the interface files of this component are stale.
445−However, from the point of view of `ghcide`, they do not look stale,
446−thus, not regenerated and the IDE shows weird errors such as:
447−```
448−typecheckIface
449−Declaration for Rep_ClientRunFlags
450−Axiom branches Rep_ClientRunFlags:
451− Failed to load interface for ‘Distribution.Simple.Flag’
452− Use -v to see a list of the files searched for.
453−```
454−and
455−```
456−expectJust checkFamInstConsistency
457−CallStack (from HasCallStack):
458− error, called at compiler\\utils\\Maybes.hs:55:27 in ghc:Maybes
459− expectJust, called at compiler\\typecheck\\FamInst.hs:461:30 in ghc:FamInst
460−```
461−
462−To mitigate this, we set the cache directory for each component dependent
463−on the components of the current `HscEnv`, additionally to the component options
464−of the respective components.
465−Assume two components, c1, c2, where c2 depends on c1, and the options of the
466−respective components are co1, co2.
467−If we want to load component c2, followed by c1, we set the cache directory for
468−each component in this way:
469−
470− * Load component c2
471− * (Cache Directory State)
472− - name of c2 + co2
473− * Load component c1
474− * (Cache Directory State)
475− - name of c2 + name of c1 + co2
476− - name of c2 + name of c1 + co1
477−
478−Overall, we created three cache directories. If we opened c1 first, then we
479−create a fourth cache directory.
480−This makes sure that interface files are always correctly updated.
481−
482−Since this causes a lot of recompilation, we only update the cache-directory,
483−if the dependencies of a component have really changed.
484−E.g. when you load two executables, they can not depend on each other. They
485−should be filtered out, such that we dont have to re-compile everything.
486−-}
487−
488−-- | Set the cache-directory based on the ComponentOptions and a list of
489−-- internal packages.
490−-- For the exact reason, see Note [Avoiding bad interface files].
491−setCacheDir :: MonadIO m => Logger -> String -> [String] -> ComponentOptions -> DynFlags -> m DynFlags
492−setCacheDir logger prefix hscComponents comps dflags = do
493− cacheDir <- liftIO $ getCacheDir prefix (hscComponents ++ componentOptions comps)
494− liftIO $ logInfo logger $ "Using interface files cache dir: " <> T.pack cacheDir
495− pure $ dflags
496− & setHiDir cacheDir
497− & setDefaultHieDir cacheDir
498−
499−
500−renderCradleError :: NormalizedFilePath -> CradleError -> FileDiagnostic
501−renderCradleError nfp (CradleError _ec t) =
502− ideErrorText nfp (T.unlines (map T.pack t))
503−
504−-- See Note [Multi Cradle Dependency Info]
505−type DependencyInfo = Map.Map FilePath (Maybe UTCTime)
506−type HieMap = Map.Map (Maybe FilePath) (HscEnv, [RawComponentInfo])
507−type FlagsMap = Map.Map (Maybe FilePath) (HM.HashMap NormalizedFilePath (IdeResult HscEnvEq, DependencyInfo))
508−
509−-- This is pristine information about a component
510−data RawComponentInfo = RawComponentInfo
511− { rawComponentUnitId :: InstalledUnitId
512− -- | Unprocessed DynFlags. Contains inplace packages such as libraries.
513− -- We do not want to use them unprocessed.
514− , rawComponentDynFlags :: DynFlags
515− -- | All targets of this components.
516− , rawComponentTargets :: [Target]
517− -- | Filepath which caused the creation of this component
518− , rawComponentFP :: NormalizedFilePath
519− -- | Component Options used to load the component.
520− , rawComponentCOptions :: ComponentOptions
521− -- | Maps cradle dependencies, such as `stack.yaml`, or `.cabal` file
522− -- to last modification time. See Note [Multi Cradle Dependency Info].
523− , rawComponentDependencyInfo :: DependencyInfo
524− }
525−
526−-- This is processed information about the component, in particular the dynflags will be modified.
527−data ComponentInfo = ComponentInfo
528− { componentUnitId :: InstalledUnitId
529− -- | Processed DynFlags. Does not contain inplace packages such as local
530− -- libraries. Can be used to actually load this Component.
531− , componentDynFlags :: DynFlags
532− -- | Internal units, such as local libraries, that this component
533− -- is loaded with. These have been extracted from the original
534− -- ComponentOptions.
535− , componentInternalUnits :: [InstalledUnitId]
536− -- | All targets of this components.
537− , componentTargets :: [Target]
538− -- | Filepath which caused the creation of this component
539− , componentFP :: NormalizedFilePath
540− -- | Component Options used to load the component.
541− , componentCOptions :: ComponentOptions
542− -- | Maps cradle dependencies, such as `stack.yaml`, or `.cabal` file
543− -- to last modification time. See Note [Multi Cradle Dependency Info]
544− , componentDependencyInfo :: DependencyInfo
545− }
546−
547−-- | Check if any dependency has been modified lately.
548−checkDependencyInfo :: DependencyInfo -> IO Bool
549−checkDependencyInfo old_di = do
550− di <- getDependencyInfo (Map.keys old_di)
551− return (di == old_di)
552−
553−-- Note [Multi Cradle Dependency Info]
554−-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
555−-- Why do we implement our own file modification tracking here?
556−-- The primary reason is that the custom caching logic is quite complicated and going into shake
557−-- adds even more complexity and more indirection. I did try for about 5 hours to work out how to
558−-- use shake rules rather than IO but eventually gave up.
559−
560−-- | Computes a mapping from a filepath to its latest modification date.
561−-- See Note [Multi Cradle Dependency Info] why we do this ourselves instead
562−-- of letting shake take care of it.
563−getDependencyInfo :: [FilePath] -> IO DependencyInfo
564−getDependencyInfo fs = Map.fromList <$> mapM do_one fs
565−
566− where
567− tryIO :: IO a -> IO (Either IOException a)
568− tryIO = try
569−
570− do_one :: FilePath -> IO (FilePath, Maybe UTCTime)
571− do_one fp = (fp,) . eitherToMaybe <$> tryIO (getModificationTime fp)
572−
573−-- | This function removes all the -package flags which refer to packages we
574−-- are going to deal with ourselves. For example, if a executable depends
575−-- on a library component, then this function will remove the library flag
576−-- from the package flags for the executable
577−--
578−-- There are several places in GHC (for example the call to hptInstances in
579−-- tcRnImports) which assume that all modules in the HPT have the same unit
580−-- ID. Therefore we create a fake one and give them all the same unit id.
581−removeInplacePackages :: [InstalledUnitId] -> DynFlags -> (DynFlags, [InstalledUnitId])
582−removeInplacePackages us df = (df { packageFlags = ps
583− , thisInstalledUnitId = fake_uid }, uids)
584− where
585− (uids, ps) = partitionEithers (map go (packageFlags df))
586− fake_uid = toInstalledUnitId (stringToUnitId "fake_uid")
587− go p@(ExposePackage _ (UnitIdArg u) _) = if toInstalledUnitId u `elem` us
588− then Left (toInstalledUnitId u)
589− else Right p
590− go p = Right p
591−
592−-- | Memoize an IO function, with the characteristics:
593−--
594−-- * If multiple people ask for a result simultaneously, make sure you only compute it once.
595−--
596−-- * If there are exceptions, repeatedly reraise them.
597−--
598−-- * If the caller is aborted (async exception) finish computing it anyway.
599−memoIO :: Ord a => (a -> IO b) -> IO (a -> IO b)
600−memoIO op = do
601− ref <- newVar Map.empty
602− return $ \k -> join $ mask_ $ modifyVar ref $ \mp ->
603− case Map.lookup k mp of
604− Nothing -> do
605− res <- onceFork $ op k
606− return (Map.insert k res mp, res)
607− Just res -> return (mp, res)
608−
609−setOptions :: GhcMonad m => ComponentOptions -> DynFlags -> m (DynFlags, [Target])
610−setOptions (ComponentOptions theOpts compRoot _) dflags = do
611− (dflags', targets) <- addCmdOpts theOpts dflags
612− let dflags'' =
613− -- disabled, generated directly by ghcide instead
614− flip gopt_unset Opt_WriteInterface $
615− -- disabled, generated directly by ghcide instead
616− -- also, it can confuse the interface stale check
617− dontWriteHieFiles $
618− setIgnoreInterfacePragmas $
619− setLinkerOptions $
620− disableOptimisation $
621− makeDynFlagsAbsolute compRoot dflags'
622− -- initPackages parses the -package flags and
623− -- sets up the visibility for each component.
624− (final_df, _) <- liftIO $ initPackages dflags''
625− return (final_df, targets)
626−
627−
628−-- we don't want to generate object code so we compile to bytecode
629−-- (HscInterpreted) which implies LinkInMemory
630−-- HscInterpreted
631−setLinkerOptions :: DynFlags -> DynFlags
632−setLinkerOptions df = df {
633− ghcLink = LinkInMemory
634− , hscTarget = HscNothing
635− , ghcMode = CompManager
636− }
637−
638−setIgnoreInterfacePragmas :: DynFlags -> DynFlags
639−setIgnoreInterfacePragmas df =
640− gopt_set (gopt_set df Opt_IgnoreInterfacePragmas) Opt_IgnoreOptimChanges
641−
642−disableOptimisation :: DynFlags -> DynFlags
643−disableOptimisation df = updOptLevel 0 df
644−
645−setHiDir :: FilePath -> DynFlags -> DynFlags
646−setHiDir f d =
647− -- override user settings to avoid conflicts leading to recompilation
648− d { hiDir = Just f}
649−
650−getCacheDir :: String -> [String] -> IO FilePath
651−getCacheDir prefix opts = IO.getXdgDirectory IO.XdgCache (cacheDir </> prefix ++ "-" ++ opts_hash)
652− where
653− -- Create a unique folder per set of different GHC options, assuming that each different set of
654− -- GHC options will create incompatible interface files.
655− opts_hash = B.unpack $ encode $ H.finalize $ H.updates H.init (map B.pack opts)
656−
657−-- | Sub directory for the cache path
658−cacheDir :: String
659−cacheDir = "ghcide"
660−
661−notifyCradleLoaded :: FilePath -> FromServerMessage
662−notifyCradleLoaded fp =
663− NotCustomServer $
664− NotificationMessage "2.0" (CustomServerMethod cradleLoadedMethod) $
665− toJSON fp
666−
667−cradleLoadedMethod :: T.Text
668−cradleLoadedMethod = "ghcide/cradle/loaded"
669−
670−ghcVersionChecker :: IO VersionCheck
671−ghcVersionChecker = $$(makeGhcVersionChecker (pure <$> getLibdir))
672−
673−checkGhcVersion :: IO (Maybe HscEnvEq)
674−checkGhcVersion = do
675− res <- ghcVersionChecker
676− case res of
677− Failure err -> do
678− putStrLn $ "Error while checking GHC version: " ++ show err
679− return Nothing
680− Mismatch {..} ->
681− return $ Just GhcVersionMismatch {..}
682− _ ->
683− return Nothing
exe/Utils.hsdeleted−9
@@ -1,9 +0,0 @@
1−module Utils (getLibdir) where
2−
3−import qualified GHC.Paths
4−import System.Environment
5−import Data.Maybe
6−
7−-- Set the GHC libdir to the nix libdir if it's present.
8−getLibdir :: IO FilePath
9−getLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"
extension/.gitignoredeleted−4
@@ -1,4 +0,0 @@
1−out
2−node_modules
3−.vscode-test/
4−*.vsix
extension/.vscodeignoredeleted−10
@@ -1,10 +0,0 @@
1−.vscode/**
2−.vscode-test/**
3−out/test/**
4−src/**
5−.gitignore
6−vsc-extension-quickstart.md
7−**/tsconfig.json
8−**/tslint.json
9−**/*.map
10−**/*.ts
extension/README.mddeleted−1
@@ -1 +0,0 @@
1−../README.md
extension/package-lock.jsondeleted−750
@@ -1,750 +0,0 @@
1−{
2− "name": "ghcide",
3− "version": "0.0.2",
4− "lockfileVersion": 1,
5− "requires": true,
6− "dependencies": {
7− "@babel/code-frame": {
8− "version": "7.5.5",
9− "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
10− "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
11− "dev": true,
12− "requires": {
13− "@babel/highlight": "^7.0.0"
14− }
15− },
16− "@babel/highlight": {
17− "version": "7.5.0",
18− "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
19− "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
20− "dev": true,
21− "requires": {
22− "chalk": "^2.0.0",
23− "esutils": "^2.0.2",
24− "js-tokens": "^4.0.0"
25− }
26− },
27− "@types/mocha": {
28− "version": "5.2.7",
29− "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
30− "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
31− "dev": true
32− },
33− "@types/node": {
34− "version": "12.7.11",
35− "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.11.tgz",
36− "integrity": "sha512-Otxmr2rrZLKRYIybtdG/sgeO+tHY20GxeDjcGmUnmmlCWyEnv2a2x1ZXBo3BTec4OiTXMQCiazB8NMBf0iRlFw==",
37− "dev": true
38− },
39− "@types/vscode": {
40− "version": "1.35.0",
41− "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.35.0.tgz",
42− "integrity": "sha512-Iyliuu8Hv4qy4TEaevQzChh9UsTEcuaKdcHXBbvJnoJSF5Td2yNENOrPK+vuOaXJJBhQZb4BNJKOxt6caaQR8A==",
43− "dev": true
44− },
45− "ansi-styles": {
46− "version": "3.2.1",
47− "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
48− "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
49− "dev": true,
50− "requires": {
51− "color-convert": "^1.9.0"
52− }
53− },
54− "argparse": {
55− "version": "1.0.10",
56− "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
57− "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
58− "dev": true,
59− "requires": {
60− "sprintf-js": "~1.0.2"
61− }
62− },
63− "azure-devops-node-api": {
64− "version": "7.2.0",
65− "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-7.2.0.tgz",
66− "integrity": "sha512-pMfGJ6gAQ7LRKTHgiRF+8iaUUeGAI0c8puLaqHLc7B8AR7W6GJLozK9RFeUHFjEGybC9/EB3r67WPd7e46zQ8w==",
67− "dev": true,
68− "requires": {
69− "os": "0.1.1",
70− "tunnel": "0.0.4",
71− "typed-rest-client": "1.2.0",
72− "underscore": "1.8.3"
73− }
74− },
75− "balanced-match": {
76− "version": "1.0.0",
77− "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
78− "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
79− "dev": true
80− },
81− "boolbase": {
82− "version": "1.0.0",
83− "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
84− "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
85− "dev": true
86− },
87− "brace-expansion": {
88− "version": "1.1.11",
89− "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
90− "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
91− "dev": true,
92− "requires": {
93− "balanced-match": "^1.0.0",
94− "concat-map": "0.0.1"
95− }
96− },
97− "buffer-crc32": {
98− "version": "0.2.13",
99− "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
100− "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
101− "dev": true
102− },
103− "builtin-modules": {
104− "version": "1.1.1",
105− "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
106− "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
107− "dev": true
108− },
109− "chalk": {
110− "version": "2.4.2",
111− "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
112− "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
113− "dev": true,
114− "requires": {
115− "ansi-styles": "^3.2.1",
116− "escape-string-regexp": "^1.0.5",
117− "supports-color": "^5.3.0"
118− }
119− },
120− "cheerio": {
121− "version": "1.0.0-rc.3",
122− "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
123− "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==",
124− "dev": true,
125− "requires": {
126− "css-select": "~1.2.0",
127− "dom-serializer": "~0.1.1",
128− "entities": "~1.1.1",
129− "htmlparser2": "^3.9.1",
130− "lodash": "^4.15.0",
131− "parse5": "^3.0.1"
132− }
133− },
134− "color-convert": {
135− "version": "1.9.3",
136− "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
137− "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
138− "dev": true,
139− "requires": {
140− "color-name": "1.1.3"
141− }
142− },
143− "color-name": {
144− "version": "1.1.3",
145− "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
146− "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
147− "dev": true
148− },
149− "commander": {
150− "version": "2.20.1",
151− "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz",
152− "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==",
153− "dev": true
154− },
155− "concat-map": {
156− "version": "0.0.1",
157− "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
158− "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
159− "dev": true
160− },
161− "css-select": {
162− "version": "1.2.0",
163− "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
164− "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
165− "dev": true,
166− "requires": {
167− "boolbase": "~1.0.0",
168− "css-what": "2.1",
169− "domutils": "1.5.1",
170− "nth-check": "~1.0.1"
171− }
172− },
173− "css-what": {
174− "version": "2.1.3",
175− "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
176− "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
177− "dev": true
178− },
179− "denodeify": {
180− "version": "1.2.1",
181− "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
182− "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=",
183− "dev": true
184− },
185− "didyoumean": {
186− "version": "1.2.1",
187− "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz",
188− "integrity": "sha1-6S7f2tplN9SE1zwBcv0eugxJdv8=",
189− "dev": true
190− },
191− "diff": {
192− "version": "4.0.1",
193− "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
194− "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
195− "dev": true
196− },
197− "dom-serializer": {
198− "version": "0.1.1",
199− "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
200− "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
201− "dev": true,
202− "requires": {
203− "domelementtype": "^1.3.0",
204− "entities": "^1.1.1"
205− }
206− },
207− "domelementtype": {
208− "version": "1.3.1",
209− "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
210− "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
211− "dev": true
212− },
213− "domhandler": {
214− "version": "2.4.2",
215− "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
216− "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
217− "dev": true,
218− "requires": {
219− "domelementtype": "1"
220− }
221− },
222− "domutils": {
223− "version": "1.5.1",
224− "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
225− "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
226− "dev": true,
227− "requires": {
228− "dom-serializer": "0",
229− "domelementtype": "1"
230− }
231− },
232− "entities": {
233− "version": "1.1.2",
234− "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
235− "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
236− "dev": true
237− },
238− "escape-string-regexp": {
239− "version": "1.0.5",
240− "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
241− "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
242− "dev": true
243− },
244− "esprima": {
245− "version": "4.0.1",
246− "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
247− "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
248− "dev": true
249− },
250− "esutils": {
251− "version": "2.0.3",
252− "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
253− "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
254− "dev": true
255− },
256− "fd-slicer": {
257− "version": "1.1.0",
258− "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
259− "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
260− "dev": true,
261− "requires": {
262− "pend": "~1.2.0"
263− }
264− },
265− "fs.realpath": {
266− "version": "1.0.0",
267− "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
268− "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
269− "dev": true
270− },
271− "glob": {
272− "version": "7.1.4",
273− "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
274− "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
275− "dev": true,
276− "requires": {
277− "fs.realpath": "^1.0.0",
278− "inflight": "^1.0.4",
279− "inherits": "2",
280− "minimatch": "^3.0.4",
281− "once": "^1.3.0",
282− "path-is-absolute": "^1.0.0"
283− }
284− },
285− "has-flag": {
286− "version": "3.0.0",
287− "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
288− "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
289− "dev": true
290− },
291− "htmlparser2": {
292− "version": "3.10.1",
293− "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
294− "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
295− "dev": true,
296− "requires": {
297− "domelementtype": "^1.3.1",
298− "domhandler": "^2.3.0",
299− "domutils": "^1.5.1",
300− "entities": "^1.1.1",
301− "inherits": "^2.0.1",
302− "readable-stream": "^3.1.1"
303− }
304− },
305− "inflight": {
306− "version": "1.0.6",
307− "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
308− "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
309− "dev": true,
310− "requires": {
311− "once": "^1.3.0",
312− "wrappy": "1"
313− }
314− },
315− "inherits": {
316− "version": "2.0.4",
317− "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
318− "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
319− "dev": true
320− },
321− "js-tokens": {
322− "version": "4.0.0",
323− "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
324− "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
325− "dev": true
326− },
327− "js-yaml": {
328− "version": "3.13.1",
329− "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
330− "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
331− "dev": true,
332− "requires": {
333− "argparse": "^1.0.7",
334− "esprima": "^4.0.0"
335− }
336− },
337− "linkify-it": {
338− "version": "2.2.0",
339− "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
340− "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
341− "dev": true,
342− "requires": {
343− "uc.micro": "^1.0.1"
344− }
345− },
346− "lodash": {
347− "version": "4.17.15",
348− "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
349− "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
350− "dev": true
351− },
352− "markdown-it": {
353− "version": "8.4.2",
354− "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz",
355− "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==",
356− "dev": true,
357− "requires": {
358− "argparse": "^1.0.7",
359− "entities": "~1.1.1",
360− "linkify-it": "^2.0.0",
361− "mdurl": "^1.0.1",
362− "uc.micro": "^1.0.5"
363− }
364− },
365− "mdurl": {
366− "version": "1.0.1",
367− "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
368− "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
369− "dev": true
370− },
371− "mime": {
372− "version": "1.6.0",
373− "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
374− "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
375− "dev": true
376− },
377− "minimatch": {
378− "version": "3.0.4",
379− "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
380− "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
381− "dev": true,
382− "requires": {
383− "brace-expansion": "^1.1.7"
384− }
385− },
386− "minimist": {
387− "version": "0.0.8",
388− "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
389− "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
390− "dev": true
391− },
392− "mkdirp": {
393− "version": "0.5.1",
394− "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
395− "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
396− "dev": true,
397− "requires": {
398− "minimist": "0.0.8"
399− }
400− },
401− "mute-stream": {
402− "version": "0.0.8",
403− "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
404− "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
405− "dev": true
406− },
407− "nth-check": {
408− "version": "1.0.2",
409− "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
410− "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
411− "dev": true,
412− "requires": {
413− "boolbase": "~1.0.0"
414− }
415− },
416− "once": {
417− "version": "1.4.0",
418− "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
419− "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
420− "dev": true,
421− "requires": {
422− "wrappy": "1"
423− }
424− },
425− "os": {
426− "version": "0.1.1",
427− "resolved": "https://registry.npmjs.org/os/-/os-0.1.1.tgz",
428− "integrity": "sha1-IIhF6J4ZOtTZcUdLk5R3NqVtE/M=",
429− "dev": true
430− },
431− "os-homedir": {
432− "version": "1.0.2",
433− "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
434− "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
435− "dev": true
436− },
437− "os-tmpdir": {
438− "version": "1.0.2",
439− "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
440− "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
441− "dev": true
442− },
443− "osenv": {
444− "version": "0.1.5",
445− "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
446− "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
447− "dev": true,
448− "requires": {
449− "os-homedir": "^1.0.0",
450− "os-tmpdir": "^1.0.0"
451− }
452− },
453− "parse-semver": {
454− "version": "1.1.1",
455− "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
456− "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=",
457− "dev": true,
458− "requires": {
459− "semver": "^5.1.0"
460− },
461− "dependencies": {
462− "semver": {
463− "version": "5.7.1",
464− "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
465− "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
466− "dev": true
467− }
468− }
469− },
470− "parse5": {
471− "version": "3.0.3",
472− "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
473− "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
474− "dev": true,
475− "requires": {
476− "@types/node": "*"
477− }
478− },
479− "path-is-absolute": {
480− "version": "1.0.1",
481− "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
482− "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
483− "dev": true
484− },
485− "path-parse": {
486− "version": "1.0.6",
487− "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
488− "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
489− "dev": true
490− },
491− "pend": {
492− "version": "1.2.0",
493− "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
494− "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
495− "dev": true
496− },
497− "read": {
498− "version": "1.0.7",
499− "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
500− "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
501− "dev": true,
502− "requires": {
503− "mute-stream": "~0.0.4"
504− }
505− },
506− "readable-stream": {
507− "version": "3.4.0",
508− "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
509− "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
510− "dev": true,
511− "requires": {
512− "inherits": "^2.0.3",
513− "string_decoder": "^1.1.1",
514− "util-deprecate": "^1.0.1"
515− }
516− },
517− "resolve": {
518− "version": "1.12.0",
519− "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
520− "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
521− "dev": true,
522− "requires": {
523− "path-parse": "^1.0.6"
524− }
525− },
526− "safe-buffer": {
527− "version": "5.2.0",
528− "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
529− "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
530− "dev": true
531− },
532− "semver": {
533− "version": "6.3.0",
534− "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
535− "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
536− },
537− "sprintf-js": {
538− "version": "1.0.3",
539− "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
540− "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
541− "dev": true
542− },
543− "string_decoder": {
544− "version": "1.3.0",
545− "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
546− "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
547− "dev": true,
548− "requires": {
549− "safe-buffer": "~5.2.0"
550− }
551− },
552− "supports-color": {
553− "version": "5.5.0",
554− "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
555− "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
556− "dev": true,
557− "requires": {
558− "has-flag": "^3.0.0"
559− }
560− },
561− "tmp": {
562− "version": "0.0.29",
563− "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz",
564− "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=",
565− "dev": true,
566− "requires": {
567− "os-tmpdir": "~1.0.1"
568− }
569− },
570− "tslib": {
571− "version": "1.10.0",
572− "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
573− "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
574− "dev": true
575− },
576− "tslint": {
577− "version": "5.20.0",
578− "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz",
579− "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==",
580− "dev": true,
581− "requires": {
582− "@babel/code-frame": "^7.0.0",
583− "builtin-modules": "^1.1.1",
584− "chalk": "^2.3.0",
585− "commander": "^2.12.1",
586− "diff": "^4.0.1",
587− "glob": "^7.1.1",
588− "js-yaml": "^3.13.1",
589− "minimatch": "^3.0.4",
590− "mkdirp": "^0.5.1",
591− "resolve": "^1.3.2",
592− "semver": "^5.3.0",
593− "tslib": "^1.8.0",
594− "tsutils": "^2.29.0"
595− },
596− "dependencies": {
597− "semver": {
598− "version": "5.7.1",
599− "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
600− "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
601− "dev": true
602− }
603− }
604− },
605− "tsutils": {
606− "version": "2.29.0",
607− "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
608− "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
609− "dev": true,
610− "requires": {
611− "tslib": "^1.8.1"
612− }
613− },
614− "tunnel": {
615− "version": "0.0.4",
616− "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz",
617− "integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=",
618− "dev": true
619− },
620− "typed-rest-client": {
621− "version": "1.2.0",
622− "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.2.0.tgz",
623− "integrity": "sha512-FrUshzZ1yxH8YwGR29PWWnfksLEILbWJydU7zfIRkyH7kAEzB62uMAl2WY6EyolWpLpVHeJGgQm45/MaruaHpw==",
624− "dev": true,
625− "requires": {
626− "tunnel": "0.0.4",
627− "underscore": "1.8.3"
628− }
629− },
630− "typescript": {
631− "version": "3.6.3",
632− "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
633− "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
634− "dev": true
635− },
636− "uc.micro": {
637− "version": "1.0.6",
638− "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
639− "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
640− "dev": true
641− },
642− "underscore": {
643− "version": "1.8.3",
644− "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
645− "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
646− "dev": true
647− },
648− "url-join": {
649− "version": "1.1.0",
650− "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz",
651− "integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=",
652− "dev": true
653− },
654− "util-deprecate": {
655− "version": "1.0.2",
656− "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
657− "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
658− "dev": true
659− },
660− "vsce": {
661− "version": "1.68.0",
662− "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.68.0.tgz",
663− "integrity": "sha512-yFbRYu4x4GbdQzZdEQQeRJBxgPdummgcUOFHUtnclW8XQl3MTuKgXL3TtI09gb5oq7jE6kdyvBmpBcmDGsmhcQ==",
664− "dev": true,
665− "requires": {
666− "azure-devops-node-api": "^7.2.0",
667− "chalk": "^2.4.2",
668− "cheerio": "^1.0.0-rc.1",
669− "commander": "^2.8.1",
670− "denodeify": "^1.2.1",
671− "didyoumean": "^1.2.1",
672− "glob": "^7.0.6",
673− "lodash": "^4.17.10",
674− "markdown-it": "^8.3.1",
675− "mime": "^1.3.4",
676− "minimatch": "^3.0.3",
677− "osenv": "^0.1.3",
678− "parse-semver": "^1.1.1",
679− "read": "^1.0.7",
680− "semver": "^5.1.0",
681− "tmp": "0.0.29",
682− "typed-rest-client": "1.2.0",
683− "url-join": "^1.1.0",
684− "yauzl": "^2.3.1",
685− "yazl": "^2.2.2"
686− },
687− "dependencies": {
688− "semver": {
689− "version": "5.7.1",
690− "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
691− "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
692− "dev": true
693− }
694− }
695− },
696− "vscode-jsonrpc": {
697− "version": "5.0.0-next.2",
698− "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz",
699− "integrity": "sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg=="
700− },
701− "vscode-languageclient": {
702− "version": "6.0.0-next.1",
703− "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.0.0-next.1.tgz",
704− "integrity": "sha512-eJ9VjLFNINArgRzLbQ11YlWry7dM93GEODkQBXTRfrSypksiO9qSGr4SHhWgxxP26p4FRSpzc/17+N+Egnnchg==",
705− "requires": {
706− "semver": "^6.3.0",
707− "vscode-languageserver-protocol": "^3.15.0-next.9"
708− }
709− },
710− "vscode-languageserver-protocol": {
711− "version": "3.15.0-next.9",
712− "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz",
713− "integrity": "sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g==",
714− "requires": {
715− "vscode-jsonrpc": "^5.0.0-next.2",
716− "vscode-languageserver-types": "^3.15.0-next.5"
717− }
718− },
719− "vscode-languageserver-types": {
720− "version": "3.15.0-next.5",
721− "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz",
722− "integrity": "sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw=="
723− },
724− "wrappy": {
725− "version": "1.0.2",
726− "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
727− "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
728− "dev": true
729− },
730− "yauzl": {
731− "version": "2.10.0",
732− "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
733− "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
734− "dev": true,
735− "requires": {
736− "buffer-crc32": "~0.2.3",
737− "fd-slicer": "~1.1.0"
738− }
739− },
740− "yazl": {
741− "version": "2.5.1",
742− "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
743− "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
744− "dev": true,
745− "requires": {
746− "buffer-crc32": "~0.2.3"
747− }
748− }
749− }
750−}
extension/package.jsondeleted−72
@@ -1,72 +0,0 @@
1−{
2− "name": "ghcide",
3− "displayName": "ghcide",
4− "publisher": "DigitalAssetHoldingsLLC",
5− "repository": {
6− "type": "git",
7− "url": "https://github.com/digital-asset/ghcide.git"
8− },
9− "description": "A simple extension to test out haskell ide core",
10− "version": "0.0.2",
11− "license": "Apache-2.0",
12− "engines": {
13− "vscode": "^1.35.0"
14− },
15− "categories": [
16− "Other"
17− ],
18− "activationEvents": [
19− "onLanguage:haskell"
20− ],
21− "main": "./out/extension.js",
22− "contributes": {
23− "languages": [
24− {
25− "id": "haskell",
26− "extensions": [
27− "hs",
28− "hs-boot",
29− "lhs-boot",
30− "lhs"
31− ]
32− }
33− ],
34− "configuration": {
35− "type": "object",
36− "title": "Haskell IDE Core Configuration",
37− "properties": {
38− "hic.executablePath": {
39− "type": "string",
40− "default": "ghcide",
41− "description": "The location of your ghcide executable"
42− },
43− "hic.arguments": {
44− "type": "string",
45− "default": "--lsp",
46− "description": "The arguments you would like to pass to the executable"
47− }
48− }
49− }
50− },
51− "scripts": {
52− "vscode:prepublish": "npm run compile",
53− "compile": "tsc -p ./",
54− "watch": "tsc -watch -p ./",
55− "test": "npm run compile && node ./node_modules/vscode/bin/test",
56− "vscepackage": "vsce package"
57− },
58− "extensionDependencies": [
59− "justusadam.language-haskell"
60− ],
61− "dependencies": {
62− "vscode-languageclient": "^6.0.0-next.1"
63− },
64− "devDependencies": {
65− "@types/mocha": "^5.2.7",
66− "@types/node": "^12.7.11",
67− "@types/vscode": "1.35.0",
68− "tslint": "^5.12.1",
69− "typescript": "^3.6.3",
70− "vsce": "^1.68.0"
71− }
72−}
extension/src/extension.tsdeleted−45
@@ -1,45 +0,0 @@
1−// Copyright (c) 2019 The DAML Authors. All rights reserved.
2−// SPDX-License-Identifier: Apache-2.0
3−
4−import * as path from 'path';
5−import { workspace, ExtensionContext, window } from 'vscode';
6−
7−import {
8− LanguageClient,
9− LanguageClientOptions,
10− ServerOptions,
11− TransportKind
12−} from 'vscode-languageclient';
13−
14−let client: LanguageClient;
15−
16−export function activate(context: ExtensionContext) {
17− let config = workspace.getConfiguration("hic");
18− let cPath: string = config.get("executablePath") as string;
19− if(cPath === "" || cPath === undefined){
20− window.showErrorMessage("You must specify a hic.executionPath in config");
21− return;
22− }
23− let argString = config.get("arguments") as string;
24−
25− let args : string[] = argString.split(" ");
26−
27− let clientOptions: LanguageClientOptions = {
28− // Register the server for plain text documents
29− documentSelector: ["haskell"]
30− };
31− client = new LanguageClient(
32− 'haskell',
33− 'ghcide',
34− { args: args, command: cPath, options: {cwd: workspace.rootPath }}, clientOptions, true);
35− client.registerProposedFeatures();
36−
37− client.start();
38−}
39−
40−export function deactivate(): Thenable<void> | undefined {
41− if (!client) {
42− return undefined;
43− }
44− return client.stop();
45−}
extension/tsconfig.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "compilerOptions": {
3− "module": "commonjs",
4− "target": "es6",
5− "outDir": "out",
6− "lib": [
7− "es6"
8− ],
9− "sourceMap": true,
10− "rootDir": "src",
11− "strict": true /* enable all strict type-checking options */
12− /* Additional Checks */
13− // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
14− // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
15− // "noUnusedParameters": true, /* Report errors on unused parameters. */
16− },
17− "exclude": [
18− "node_modules",
19− ".vscode-test"
20− ]
21−}
extension/tslint.jsondeleted−15
@@ -1,15 +0,0 @@
1−{
2− "rules": {
3− "no-string-throw": true,
4− "no-unused-expression": true,
5− "no-duplicate-variable": true,
6− "curly": true,
7− "class-name": true,
8− "semicolon": [
9− true,
10− "always"
11− ],
12− "triple-equals": true
13− },
14− "defaultSeverity": "warning"
15−}
fmt.shdeleted−3
@@ -1,3 +0,0 @@
1−#!/usr/bin/env bash
2−set -eou pipefail
3−curl -sSL https://raw.github.com/ndmitchell/hlint/master/misc/run.sh | sh -s . --with-group=extra
ghcide.cabaldeleted−344
@@ -1,344 +0,0 @@
1−cabal-version: 1.20
2−build-type: Simple
3−category: Development
4−name: ghcide
5−version: 0.2.0
6−license: Apache-2.0
7−license-file: LICENSE
8−author: Digital Asset
9−maintainer: Digital Asset
10−copyright: Digital Asset 2018-2020
11−synopsis: The core of an IDE
12−description:
13− A library for building Haskell IDE's on top of the GHC API.
14−homepage: https://github.com/digital-asset/ghcide#readme
15−bug-reports: https://github.com/digital-asset/ghcide/issues
16−tested-with: GHC==8.6.5
17−extra-source-files: include/ghc-api-version.h README.md CHANGELOG.md
18− test/data/hover/*.hs
19− test/data/multi/cabal.project
20− test/data/multi/hie.yaml
21− test/data/multi/a/a.cabal
22− test/data/multi/a/*.hs
23− test/data/multi/b/b.cabal
24− test/data/multi/b/*.hs
25−
26−source-repository head
27− type: git
28− location: https://github.com/digital-asset/ghcide.git
29−
30−flag ghc-lib
31− description: build against ghc-lib instead of the ghc package
32− default: False
33− manual: True
34−
35−library
36− default-language: Haskell2010
37− build-depends:
38− aeson,
39− array,
40− async,
41− base == 4.*,
42− binary,
43− bytestring,
44− containers,
45− data-default,
46− deepseq,
47− directory,
48− extra,
49− fuzzy,
50− filepath,
51− haddock-library >= 1.8,
52− hashable,
53− haskell-lsp-types == 0.22.*,
54− haskell-lsp == 0.22.*,
55− mtl,
56− network-uri,
57− prettyprinter-ansi-terminal,
58− prettyprinter-ansi-terminal,
59− prettyprinter,
60− regex-tdfa >= 1.3.1.0,
61− rope-utf16-splay,
62− safe-exceptions,
63− shake >= 0.18.4,
64− sorted-list,
65− stm,
66− syb,
67− text,
68− time,
69− transformers,
70− unordered-containers >= 0.2.10.0,
71− utf8-string,
72− hslogger
73− if flag(ghc-lib)
74− build-depends:
75− ghc-lib >= 8.8,
76− ghc-lib-parser >= 8.8
77− cpp-options: -DGHC_LIB
78− else
79− build-depends:
80− ghc-boot-th,
81− ghc-boot,
82− ghc >= 8.4
83− if os(windows)
84− build-depends:
85− Win32
86− else
87− build-depends:
88− unix
89− c-sources:
90− cbits/getmodtime.c
91−
92− default-extensions:
93− BangPatterns
94− DeriveFunctor
95− DeriveGeneric
96− GeneralizedNewtypeDeriving
97− LambdaCase
98− NamedFieldPuns
99− OverloadedStrings
100− RecordWildCards
101− ScopedTypeVariables
102− StandaloneDeriving
103− TupleSections
104− TypeApplications
105− ViewPatterns
106−
107− hs-source-dirs:
108− src
109− include-dirs:
110− include
111− exposed-modules:
112− Development.IDE.Compat
113− Development.IDE.Core.Debouncer
114− Development.IDE.Core.FileStore
115− Development.IDE.Core.IdeConfiguration
116− Development.IDE.Core.OfInterest
117− Development.IDE.Core.PositionMapping
118− Development.IDE.Core.Rules
119− Development.IDE.Core.RuleTypes
120− Development.IDE.Core.Service
121− Development.IDE.Core.Shake
122− Development.IDE.GHC.Error
123− Development.IDE.GHC.Util
124− Development.IDE.Import.DependencyInformation
125− Development.IDE.LSP.HoverDefinition
126− Development.IDE.LSP.LanguageServer
127− Development.IDE.LSP.Outline
128− Development.IDE.LSP.Protocol
129− Development.IDE.LSP.Server
130− Development.IDE.Spans.Common
131− Development.IDE.Types.Diagnostics
132− Development.IDE.Types.Location
133− Development.IDE.Types.Logger
134− Development.IDE.Types.Options
135− Development.IDE.Plugin
136− Development.IDE.Plugin.Completions
137− Development.IDE.Plugin.CodeAction
138− other-modules:
139− Development.IDE.Core.Compile
140− Development.IDE.Core.Preprocessor
141− Development.IDE.Core.FileExists
142− Development.IDE.GHC.Compat
143− Development.IDE.GHC.CPP
144− Development.IDE.GHC.Orphans
145− Development.IDE.GHC.Warnings
146− Development.IDE.GHC.WithDynFlags
147− Development.IDE.Import.FindImports
148− Development.IDE.LSP.Notifications
149− Development.IDE.Spans.AtPoint
150− Development.IDE.Spans.Calculate
151− Development.IDE.Spans.Documentation
152− Development.IDE.Spans.Type
153− Development.IDE.Plugin.CodeAction.PositionIndexed
154− Development.IDE.Plugin.CodeAction.Rules
155− Development.IDE.Plugin.CodeAction.RuleTypes
156− Development.IDE.Plugin.Completions.Logic
157− Development.IDE.Plugin.Completions.Types
158− if (impl(ghc > 8.7) && impl(ghc < 8.10)) || flag(ghc-lib)
159− hs-source-dirs: src-ghc88
160− other-modules:
161− Development.IDE.GHC.HieAst
162− if (impl(ghc > 8.9))
163− hs-source-dirs: src-ghc810
164− other-modules:
165− Development.IDE.GHC.HieAst
166− ghc-options: -Wall -Wno-name-shadowing
167−
168−executable ghcide-test-preprocessor
169− default-language: Haskell2010
170− hs-source-dirs: test/preprocessor
171− ghc-options: -Wall -Wno-name-shadowing
172− main-is: Main.hs
173− build-depends:
174− base == 4.*
175−
176−executable ghcide
177− if flag(ghc-lib)
178− buildable: False
179− default-language: Haskell2010
180− hs-source-dirs: exe
181− ghc-options:
182− -threaded
183− -Wall
184− -Wno-name-shadowing
185− -- allow user RTS overrides
186− -rtsopts
187− -- disable idle GC
188− -- disable parallel GC
189− -- increase nursery size
190− "-with-rtsopts=-I0 -qg -A128M"
191− main-is: Main.hs
192− build-depends:
193− time,
194− async,
195− hslogger,
196− aeson,
197− base == 4.*,
198− binary,
199− base16-bytestring >=0.1.1 && <0.2,
200− bytestring,
201− containers,
202− cryptohash-sha1 >=0.11.100 && <0.12,
203− data-default,
204− deepseq,
205− directory,
206− extra,
207− filepath,
208− ghc-check >= 0.3.0.1 && < 0.4,
209− ghc-paths,
210− ghc,
211− gitrev,
212− hashable,
213− haskell-lsp,
214− haskell-lsp-types,
215− hie-bios >= 0.5.0 && < 0.6,
216− ghcide,
217− optparse-applicative,
218− shake,
219− text,
220− unordered-containers
221− other-modules:
222− Utils
223− Arguments
224− Paths_ghcide
225−
226− default-extensions:
227− BangPatterns
228− DeriveFunctor
229− DeriveGeneric
230− GeneralizedNewtypeDeriving
231− LambdaCase
232− NamedFieldPuns
233− OverloadedStrings
234− RecordWildCards
235− ScopedTypeVariables
236− StandaloneDeriving
237− TupleSections
238− TypeApplications
239− ViewPatterns
240−
241−test-suite ghcide-tests
242− if flag(ghc-lib)
243− buildable: False
244− type: exitcode-stdio-1.0
245− default-language: Haskell2010
246− build-tool-depends:
247− ghcide:ghcide,
248− ghcide:ghcide-test-preprocessor
249− build-depends:
250− aeson,
251− base,
252− bytestring,
253− containers,
254− directory,
255− extra,
256− filepath,
257− --------------------------------------------------------------
258− -- The MIN_GHC_API_VERSION macro relies on MIN_VERSION pragmas
259− -- which require depending on ghc. So the tests need to depend
260− -- on ghc if they need to use MIN_GHC_API_VERSION. Maybe a
261− -- better solution can be found, but this is a quick solution
262− -- which works for now.
263− ghc,
264− --------------------------------------------------------------
265− ghcide,
266− ghc-typelits-knownnat,
267− haddock-library,
268− haskell-lsp,
269− haskell-lsp-types,
270− network-uri,
271− lens,
272− lsp-test >= 0.11.0.1 && < 0.12,
273− parser-combinators,
274− QuickCheck,
275− quickcheck-instances,
276− rope-utf16-splay,
277− shake,
278− tasty,
279− tasty-expected-failure,
280− tasty-hunit,
281− tasty-quickcheck,
282− tasty-rerun,
283− text
284− hs-source-dirs: test/cabal test/exe test/src
285− include-dirs: include
286− ghc-options: -threaded -Wall -Wno-name-shadowing
287− main-is: Main.hs
288− other-modules:
289− Development.IDE.Test
290− Development.IDE.Test.Runfiles
291− default-extensions:
292− BangPatterns
293− DeriveFunctor
294− DeriveGeneric
295− GeneralizedNewtypeDeriving
296− LambdaCase
297− NamedFieldPuns
298− OverloadedStrings
299− RecordWildCards
300− ScopedTypeVariables
301− StandaloneDeriving
302− TupleSections
303− TypeApplications
304− ViewPatterns
305−
306−benchmark ghcide-bench
307− type: exitcode-stdio-1.0
308− default-language: Haskell2010
309− build-tool-depends:
310− ghcide:ghcide,
311− ghcide:ghcide-test-preprocessor
312− build-depends:
313− aeson,
314− base,
315− bytestring,
316− containers,
317− directory,
318− extra,
319− filepath,
320− ghcide,
321− lsp-test < 0.12,
322− optparse-applicative,
323− parser-combinators,
324− process,
325− safe-exceptions
326− hs-source-dirs: bench
327− include-dirs: include
328− ghc-options: -threaded -Wall -Wno-name-shadowing
329− main-is: Main.hs
330− other-modules:
331− default-extensions:
332− BangPatterns
333− DeriveFunctor
334− DeriveGeneric
335− GeneralizedNewtypeDeriving
336− LambdaCase
337− NamedFieldPuns
338− OverloadedStrings
339− RecordWildCards
340− ScopedTypeVariables
341− StandaloneDeriving
342− TupleSections
343− TypeApplications
344− ViewPatterns
haskell-ide-core.cabalnew file+118
@@ -0,0 +1,118 @@
1+cabal-version: >= 1.18
2+build-type: Simple
3+name: haskell-ide-core
4+version: 0
5+license: BSD3
6+x-license: BSD3 OR Apache2
7+author: Digital Asset
8+maintainer: Digital Asset
9+copyright: Digital Asset 2018-2019
10+synopsis: The core of an IDE
11+description:
12+ A library for building Haskell IDE's on top of the GHC API.
13+homepage: https://github.com/digital-asset/daml#readme
14+bug-reports: https://github.com/digital-asset/daml/issues
15+tested-with: GHC==8.6.5
16+
17+source-repository head
18+ type: git
19+ location: https://github.com/digital-asset/daml.git
20+
21+library
22+ default-language: Haskell2010
23+ build-depends:
24+ aeson,
25+ base == 4.*,
26+ binary,
27+ bytestring,
28+ containers,
29+ deepseq,
30+ directory,
31+ either,
32+ extra,
33+ filepath,
34+ ghc,
35+ ghc-boot-th,
36+ ghc-boot,
37+ hashable,
38+ haskell-lsp,
39+ haskell-lsp-types,
40+ mtl,
41+ pretty,
42+ safe-exceptions,
43+ shake,
44+ stm,
45+ syb,
46+ text,
47+ time,
48+ prettyprinter,
49+ prettyprinter-ansi-terminal,
50+ transformers,
51+ uniplate,
52+ unordered-containers,
53+ uri-encode
54+
55+ cpp-options: -DGHC_STABLE
56+ default-extensions:
57+ LambdaCase
58+ BangPatterns
59+ DeriveGeneric
60+ RecordWildCards
61+ ScopedTypeVariables
62+ NamedFieldPuns
63+ TupleSections
64+ TypeApplications
65+ ViewPatterns
66+ GeneralizedNewtypeDeriving
67+ StandaloneDeriving
68+
69+ hs-source-dirs:
70+ src
71+ ../../libs-haskell/prettyprinter-syntax/src
72+ exposed-modules:
73+ Development.IDE.Logger
74+ Development.IDE.UtilGHC
75+ Development.IDE.Functions.AtPoint
76+ Development.IDE.Functions.Compile
77+ Development.IDE.Functions.CPP
78+ Development.IDE.Orphans
79+ Development.IDE.Functions.DependencyInformation
80+ Development.IDE.Functions.Documentation
81+ Development.IDE.Functions.FindImports
82+ Development.IDE.Functions.GHCError
83+ Development.IDE.Functions.SpanInfo
84+ Development.IDE.Functions.Warnings
85+ Development.IDE.State.FileStore
86+ Development.IDE.State.Rules
87+ Development.IDE.Compat
88+ Development.IDE.Types.Options
89+ Development.IDE.State.RuleTypes
90+ Development.IDE.State.Service
91+ Development.IDE.State.Shake
92+ Development.IDE.Types.Diagnostics
93+ Development.IDE.Types.Location
94+ Development.IDE.Types.LSP
95+ Development.IDE.Types.SpanInfo
96+ other-modules:
97+ Data.Text.Prettyprint.Doc.Syntax
98+
99+executable ide-demo
100+ default-language: Haskell2010
101+ main-is: Demo.hs
102+ ghc-options: -main-is Demo.main
103+ build-depends:
104+ base == 4.*,
105+ filepath,
106+ containers,
107+ shake,
108+ ghc-paths,
109+ ghc,
110+ extra,
111+ text,
112+ haskell-ide-core
113+
114+ default-extensions:
115+ TupleSections
116+ RecordWildCards
117+
118+ hs-source-dirs: test
hie.yamldeleted−12
@@ -1,12 +0,0 @@
1−cradle:
2− cabal:
3− - path: "./src"
4− component: "ghcide:lib:ghcide"
5− - path: "./exe"
6− component: "ghcide:exe:ghcide"
7− - path: "./test"
8− component: "ghcide:test:ghcide-tests"
9− - path: "./bench"
10− component: "ghcide:benchmark:ghcide-bench"
11− - path: "./test/preprocessor"
12− component: "ghcide:exe:ghcide-test-preprocessor"
img/vscode2.pngdeleted

Binary file not shown.

include/ghc-api-version.hdeleted−10
@@ -1,10 +0,0 @@
1−#ifndef GHC_API_VERSION_H
2−#define GHC_API_VERSION_H
3−
4−#ifdef GHC_LIB
5−#define MIN_GHC_API_VERSION(x,y,z) MIN_VERSION_ghc_lib(x,y,z)
6−#else
7−#define MIN_GHC_API_VERSION(x,y,z) MIN_VERSION_ghc(x,y,z)
8−#endif
9−
10−#endif
install.batdeleted−6
@@ -1,6 +0,0 @@
1−:: Copyright (c) 2019 The DAML Authors. All rights reserved.
2−:: SPDX-License-Identifier: Apache-2.0
3−
4−@REM Install ghcide where cabal install would put it on Windows
5−@REM but avoid checking configure or installing local libraries (faster)
6−ghc Main -o dist\obj\ghcide.exe -XBangPatterns -XDeriveGeneric -XGeneralizedNewtypeDeriving -XLambdaCase -XNamedFieldPuns -XRecordWildCards -XScopedTypeVariables -XStandaloneDeriving -XTupleSections -XTypeApplications -XViewPatterns -package=ghc -DGHC_STABLE -isrc -iexe -outputdir dist\obj && copy dist\obj\ghcide.exe %AppData%\cabal\bin\ghcide.exe
src-ghc810/Development/IDE/GHC/HieAst.hsdeleted−1928
@@ -1,1928 +0,0 @@
1−
2−
3−{-
4−Forked from GHC v8.10.1 to work around the readFile side effect in mkHiefile
5−
6−Main functions for .hie file generation
7−-}
8−{- HLINT ignore -}
9−{-# LANGUAGE OverloadedStrings #-}
10−{-# LANGUAGE FlexibleInstances #-}
11−{-# LANGUAGE UndecidableInstances #-}
12−{-# LANGUAGE FlexibleContexts #-}
13−{-# LANGUAGE TypeSynonymInstances #-}
14−{-# LANGUAGE ScopedTypeVariables #-}
15−{-# LANGUAGE TypeFamilies #-}
16−{-# LANGUAGE TypeApplications #-}
17−{-# LANGUAGE AllowAmbiguousTypes #-}
18−{-# LANGUAGE ViewPatterns #-}
19−{-# LANGUAGE DeriveDataTypeable #-}
20−module Development.IDE.GHC.HieAst ( mkHieFile ) where
21−
22−import GhcPrelude
23−
24−import Avail ( Avails )
25−import Bag ( Bag, bagToList )
26−import BasicTypes
27−import BooleanFormula
28−import Class ( FunDep )
29−import CoreUtils ( exprType )
30−import ConLike ( conLikeName )
31−import Desugar ( deSugarExpr )
32−import FieldLabel
33−import GHC.Hs
34−import HscTypes
35−import Module ( ModuleName, ml_hs_file )
36−import MonadUtils ( concatMapM, liftIO )
37−import Name ( Name, nameSrcSpan, setNameLoc )
38−import NameEnv ( NameEnv, emptyNameEnv, extendNameEnv, lookupNameEnv )
39−import SrcLoc
40−import TcHsSyn ( hsLitType, hsPatType )
41−import Type ( mkVisFunTys, Type )
42−import TysWiredIn ( mkListTy, mkSumTy )
43−import Var ( Id, Var, setVarName, varName, varType )
44−import TcRnTypes
45−import MkIface ( mkIfaceExports )
46−import Panic
47−
48−import HieTypes
49−import HieUtils
50−
51−import qualified Data.Array as A
52−import qualified Data.ByteString as BS
53−import qualified Data.Map as M
54−import qualified Data.Set as S
55−import Data.Data ( Data, Typeable )
56−import Data.List ( foldl1' )
57−import Data.Maybe ( listToMaybe )
58−import Control.Monad.Trans.Reader
59−import Control.Monad.Trans.Class ( lift )
60−
61−{- Note [Updating HieAst for changes in the GHC AST]
62−
63−When updating the code in this file for changes in the GHC AST, you
64−need to pay attention to the following things:
65−
66−1) Symbols (Names/Vars/Modules) in the following categories:
67−
68− a) Symbols that appear in the source file that directly correspond to
69− something the user typed
70− b) Symbols that don't appear in the source, but should be in some sense
71− "visible" to a user, particularly via IDE tooling or the like. This
72− includes things like the names introduced by RecordWildcards (We record
73− all the names introduced by a (..) in HIE files), and will include implicit
74− parameters and evidence variables after one of my pending MRs lands.
75−
76−2) Subtrees that may contain such symbols, or correspond to a SrcSpan in
77− the file. This includes all `Located` things
78−
79−For 1), you need to call `toHie` for one of the following instances
80−
81−instance ToHie (Context (Located Name)) where ...
82−instance ToHie (Context (Located Var)) where ...
83−instance ToHie (IEContext (Located ModuleName)) where ...
84−
85−`Context` is a data type that looks like:
86−
87−data Context a = C ContextInfo a -- Used for names and bindings
88−
89−`ContextInfo` is defined in `HieTypes`, and looks like
90−
91−data ContextInfo
92− = Use -- ^ regular variable
93− | MatchBind
94− | IEThing IEType -- ^ import/export
95− | TyDecl
96− -- | Value binding
97− | ValBind
98− BindType -- ^ whether or not the binding is in an instance
99− Scope -- ^ scope over which the value is bound
100− (Maybe Span) -- ^ span of entire binding
101− ...
102−
103−It is used to annotate symbols in the .hie files with some extra information on
104−the context in which they occur and should be fairly self explanatory. You need
105−to select one that looks appropriate for the symbol usage. In very rare cases,
106−you might need to extend this sum type if none of the cases seem appropriate.
107−
108−So, given a `Located Name` that is just being "used", and not defined at a
109−particular location, you would do the following:
110−
111− toHie $ C Use located_name
112−
113−If you select one that corresponds to a binding site, you will need to
114−provide a `Scope` and a `Span` for your binding. Both of these are basically
115−`SrcSpans`.
116−
117−The `SrcSpan` in the `Scope` is supposed to span over the part of the source
118−where the symbol can be legally allowed to occur. For more details on how to
119−calculate this, see Note [Capturing Scopes and other non local information]
120−in HieAst.
121−
122−The binding `Span` is supposed to be the span of the entire binding for
123−the name.
124−
125−For a function definition `foo`:
126−
127−foo x = x + y
128− where y = x^2
129−
130−The binding `Span` is the span of the entire function definition from `foo x`
131−to `x^2`. For a class definition, this is the span of the entire class, and
132−so on. If this isn't well defined for your bit of syntax (like a variable
133−bound by a lambda), then you can just supply a `Nothing`
134−
135−There is a test that checks that all symbols in the resulting HIE file
136−occur inside their stated `Scope`. This can be turned on by passing the
137−-fvalidate-ide-info flag to ghc along with -fwrite-ide-info to generate the
138−.hie file.
139−
140−You may also want to provide a test in testsuite/test/hiefile that includes
141−a file containing your new construction, and tests that the calculated scope
142−is valid (by using -fvalidate-ide-info)
143−
144−For subtrees in the AST that may contain symbols, the procedure is fairly
145−straightforward. If you are extending the GHC AST, you will need to provide a
146−`ToHie` instance for any new types you may have introduced in the AST.
147−
148−Here are is an extract from the `ToHie` instance for (LHsExpr (GhcPass p)):
149−
150− toHie e@(L mspan oexpr) = concatM $ getTypeNode e : case oexpr of
151− HsVar _ (L _ var) ->
152− [ toHie $ C Use (L mspan var)
153− -- Patch up var location since typechecker removes it
154− ]
155− HsConLikeOut _ con ->
156− [ toHie $ C Use $ L mspan $ conLikeName con
157− ]
158− ...
159− HsApp _ a b ->
160− [ toHie a
161− , toHie b
162− ]
163−
164−If your subtree is `Located` or has a `SrcSpan` available, the output list
165−should contain a HieAst `Node` corresponding to the subtree. You can use
166−either `makeNode` or `getTypeNode` for this purpose, depending on whether it
167−makes sense to assign a `Type` to the subtree. After this, you just need
168−to concatenate the result of calling `toHie` on all subexpressions and
169−appropriately annotated symbols contained in the subtree.
170−
171−The code above from the ToHie instance of `LhsExpr (GhcPass p)` is supposed
172−to work for both the renamed and typechecked source. `getTypeNode` is from
173−the `HasType` class defined in this file, and it has different instances
174−for `GhcTc` and `GhcRn` that allow it to access the type of the expression
175−when given a typechecked AST:
176−
177−class Data a => HasType a where
178− getTypeNode :: a -> HieM [HieAST Type]
179−instance HasType (LHsExpr GhcTc) where
180− getTypeNode e@(L spn e') = ... -- Actually get the type for this expression
181−instance HasType (LHsExpr GhcRn) where
182− getTypeNode (L spn e) = makeNode e spn -- Fallback to a regular `makeNode` without recording the type
183−
184−If your subtree doesn't have a span available, you can omit the `makeNode`
185−call and just recurse directly in to the subexpressions.
186−
187−-}
188−
189−-- These synonyms match those defined in main/GHC.hs
190−type RenamedSource = ( HsGroup GhcRn, [LImportDecl GhcRn]
191− , Maybe [(LIE GhcRn, Avails)]
192− , Maybe LHsDocString )
193−type TypecheckedSource = LHsBinds GhcTc
194−
195−
196−{- Note [Name Remapping]
197−The Typechecker introduces new names for mono names in AbsBinds.
198−We don't care about the distinction between mono and poly bindings,
199−so we replace all occurrences of the mono name with the poly name.
200−-}
201−newtype HieState = HieState
202− { name_remapping :: NameEnv Id
203− }
204−
205−initState :: HieState
206−initState = HieState emptyNameEnv
207−
208−class ModifyState a where -- See Note [Name Remapping]
209− addSubstitution :: a -> a -> HieState -> HieState
210−
211−instance ModifyState Name where
212− addSubstitution _ _ hs = hs
213−
214−instance ModifyState Id where
215− addSubstitution mono poly hs =
216− hs{name_remapping = extendNameEnv (name_remapping hs) (varName mono) poly}
217−
218−modifyState :: ModifyState (IdP p) => [ABExport p] -> HieState -> HieState
219−modifyState = foldr go id
220− where
221− go ABE{abe_poly=poly,abe_mono=mono} f = addSubstitution mono poly . f
222− go _ f = f
223−
224−type HieM = ReaderT HieState Hsc
225−
226−-- | Construct an 'HieFile' from the outputs of the typechecker.
227−mkHieFile :: ModSummary
228− -> TcGblEnv
229− -> RenamedSource
230− -> BS.ByteString -> Hsc HieFile
231−mkHieFile ms ts rs src = do
232− let tc_binds = tcg_binds ts
233− (asts', arr) <- getCompressedAsts tc_binds rs
234− let Just src_file = ml_hs_file $ ms_location ms
235− return $ HieFile
236− { hie_hs_file = src_file
237− , hie_module = ms_mod ms
238− , hie_types = arr
239− , hie_asts = asts'
240− -- mkIfaceExports sorts the AvailInfos for stability
241− , hie_exports = mkIfaceExports (tcg_exports ts)
242− , hie_hs_src = src
243− }
244−
245−getCompressedAsts :: TypecheckedSource -> RenamedSource
246− -> Hsc (HieASTs TypeIndex, A.Array TypeIndex HieTypeFlat)
247−getCompressedAsts ts rs = do
248− asts <- enrichHie ts rs
249− return $ compressTypes asts
250−
251−enrichHie :: TypecheckedSource -> RenamedSource -> Hsc (HieASTs Type)
252−enrichHie ts (hsGrp, imports, exports, _) = flip runReaderT initState $ do
253− tasts <- toHie $ fmap (BC RegularBind ModuleScope) ts
254− rasts <- processGrp hsGrp
255− imps <- toHie $ filter (not . ideclImplicit . unLoc) imports
256− exps <- toHie $ fmap (map $ IEC Export . fst) exports
257− let spanFile children = case children of
258− [] -> mkRealSrcSpan (mkRealSrcLoc "" 1 1) (mkRealSrcLoc "" 1 1)
259− _ -> mkRealSrcSpan (realSrcSpanStart $ nodeSpan $ head children)
260− (realSrcSpanEnd $ nodeSpan $ last children)
261−
262− modulify xs =
263− Node (simpleNodeInfo "Module" "Module") (spanFile xs) xs
264−
265− asts = HieASTs
266− $ resolveTyVarScopes
267− $ M.map (modulify . mergeSortAsts)
268− $ M.fromListWith (++)
269− $ map (\x -> (srcSpanFile (nodeSpan x),[x])) flat_asts
270−
271− flat_asts = concat
272− [ tasts
273− , rasts
274− , imps
275− , exps
276− ]
277− return asts
278− where
279− processGrp grp = concatM
280− [ toHie $ fmap (RS ModuleScope ) hs_valds grp
281− , toHie $ hs_splcds grp
282− , toHie $ hs_tyclds grp
283− , toHie $ hs_derivds grp
284− , toHie $ hs_fixds grp
285− , toHie $ hs_defds grp
286− , toHie $ hs_fords grp
287− , toHie $ hs_warnds grp
288− , toHie $ hs_annds grp
289− , toHie $ hs_ruleds grp
290− ]
291−
292−getRealSpan :: SrcSpan -> Maybe Span
293−getRealSpan (RealSrcSpan sp) = Just sp
294−getRealSpan _ = Nothing
295−
296−grhss_span :: GRHSs p body -> SrcSpan
297−grhss_span (GRHSs _ xs bs) = foldl' combineSrcSpans (getLoc bs) (map getLoc xs)
298−grhss_span (XGRHSs _) = panic "XGRHS has no span"
299−
300−bindingsOnly :: [Context Name] -> [HieAST a]
301−bindingsOnly [] = []
302−bindingsOnly (C c n : xs) = case nameSrcSpan n of
303− RealSrcSpan span -> Node nodeinfo span [] : bindingsOnly xs
304− where nodeinfo = NodeInfo S.empty [] (M.singleton (Right n) info)
305− info = mempty{identInfo = S.singleton c}
306− _ -> bindingsOnly xs
307−
308−concatM :: Monad m => [m [a]] -> m [a]
309−concatM xs = concat <$> sequence xs
310−
311−{- Note [Capturing Scopes and other non local information]
312−toHie is a local tranformation, but scopes of bindings cannot be known locally,
313−hence we have to push the relevant info down into the binding nodes.
314−We use the following types (*Context and *Scoped) to wrap things and
315−carry the required info
316−(Maybe Span) always carries the span of the entire binding, including rhs
317−-}
318−data Context a = C ContextInfo a -- Used for names and bindings
319−
320−data RContext a = RC RecFieldContext a
321−data RFContext a = RFC RecFieldContext (Maybe Span) a
322−-- ^ context for record fields
323−
324−data IEContext a = IEC IEType a
325−-- ^ context for imports/exports
326−
327−data BindContext a = BC BindType Scope a
328−-- ^ context for imports/exports
329−
330−data PatSynFieldContext a = PSC (Maybe Span) a
331−-- ^ context for pattern synonym fields.
332−
333−data SigContext a = SC SigInfo a
334−-- ^ context for type signatures
335−
336−data SigInfo = SI SigType (Maybe Span)
337−
338−data SigType = BindSig | ClassSig | InstSig
339−
340−data RScoped a = RS Scope a
341−-- ^ Scope spans over everything to the right of a, (mostly) not
342−-- including a itself
343−-- (Includes a in a few special cases like recursive do bindings) or
344−-- let/where bindings
345−
346−-- | Pattern scope
347−data PScoped a = PS (Maybe Span)
348− Scope -- ^ use site of the pattern
349− Scope -- ^ pattern to the right of a, not including a
350− a
351− deriving (Typeable, Data) -- Pattern Scope
352−
353−{- Note [TyVar Scopes]
354−Due to -XScopedTypeVariables, type variables can be in scope quite far from
355−their original binding. We resolve the scope of these type variables
356−in a separate pass
357−-}
358−data TScoped a = TS TyVarScope a -- TyVarScope
359−
360−data TVScoped a = TVS TyVarScope Scope a -- TyVarScope
361−-- ^ First scope remains constant
362−-- Second scope is used to build up the scope of a tyvar over
363−-- things to its right, ala RScoped
364−
365−-- | Each element scopes over the elements to the right
366−listScopes :: Scope -> [Located a] -> [RScoped (Located a)]
367−listScopes _ [] = []
368−listScopes rhsScope [pat] = [RS rhsScope pat]
369−listScopes rhsScope (pat : pats) = RS sc pat : pats'
370− where
371− pats'@((RS scope p):_) = listScopes rhsScope pats
372− sc = combineScopes scope $ mkScope $ getLoc p
373−
374−-- | 'listScopes' specialised to 'PScoped' things
375−patScopes
376− :: Maybe Span
377− -> Scope
378− -> Scope
379− -> [LPat (GhcPass p)]
380− -> [PScoped (LPat (GhcPass p))]
381−patScopes rsp useScope patScope xs =
382− map (\(RS sc a) -> PS rsp useScope sc (composeSrcSpan a)) $
383− listScopes patScope (map dL xs)
384−
385−-- | 'listScopes' specialised to 'TVScoped' things
386−tvScopes
387− :: TyVarScope
388− -> Scope
389− -> [LHsTyVarBndr a]
390− -> [TVScoped (LHsTyVarBndr a)]
391−tvScopes tvScope rhsScope xs =
392− map (\(RS sc a)-> TVS tvScope sc a) $ listScopes rhsScope xs
393−
394−{- Note [Scoping Rules for SigPat]
395−Explicitly quantified variables in pattern type signatures are not
396−brought into scope in the rhs, but implicitly quantified variables
397−are (HsWC and HsIB).
398−This is unlike other signatures, where explicitly quantified variables
399−are brought into the RHS Scope
400−For example
401−foo :: forall a. ...;
402−foo = ... -- a is in scope here
403−
404−bar (x :: forall a. a -> a) = ... -- a is not in scope here
405−-- ^ a is in scope here (pattern body)
406−
407−bax (x :: a) = ... -- a is in scope here
408−Because of HsWC and HsIB pass on their scope to their children
409−we must wrap the LHsType in pattern signatures in a
410−Shielded explictly, so that the HsWC/HsIB scope is not passed
411−on the the LHsType
412−-}
413−
414−data Shielded a = SH Scope a -- Ignores its TScope, uses its own scope instead
415−
416−type family ProtectedSig a where
417− ProtectedSig GhcRn = HsWildCardBndrs GhcRn (HsImplicitBndrs
418− GhcRn
419− (Shielded (LHsType GhcRn)))
420− ProtectedSig GhcTc = NoExtField
421−
422−class ProtectSig a where
423− protectSig :: Scope -> LHsSigWcType (NoGhcTc a) -> ProtectedSig a
424−
425−instance (HasLoc a) => HasLoc (Shielded a) where
426− loc (SH _ a) = loc a
427−
428−instance (ToHie (TScoped a)) => ToHie (TScoped (Shielded a)) where
429− toHie (TS _ (SH sc a)) = toHie (TS (ResolvedScopes [sc]) a)
430−
431−instance ProtectSig GhcTc where
432− protectSig _ _ = noExtField
433−
434−instance ProtectSig GhcRn where
435− protectSig sc (HsWC a (HsIB b sig)) =
436− HsWC a (HsIB b (SH sc sig))
437− protectSig _ (HsWC _ (XHsImplicitBndrs nec)) = noExtCon nec
438− protectSig _ (XHsWildCardBndrs nec) = noExtCon nec
439−
440−class HasLoc a where
441− -- ^ defined so that HsImplicitBndrs and HsWildCardBndrs can
442− -- know what their implicit bindings are scoping over
443− loc :: a -> SrcSpan
444−
445−instance HasLoc thing => HasLoc (TScoped thing) where
446− loc (TS _ a) = loc a
447−
448−instance HasLoc thing => HasLoc (PScoped thing) where
449− loc (PS _ _ _ a) = loc a
450−
451−instance HasLoc (LHsQTyVars GhcRn) where
452− loc (HsQTvs _ vs) = loc vs
453− loc _ = noSrcSpan
454−
455−instance HasLoc thing => HasLoc (HsImplicitBndrs a thing) where
456− loc (HsIB _ a) = loc a
457− loc _ = noSrcSpan
458−
459−instance HasLoc thing => HasLoc (HsWildCardBndrs a thing) where
460− loc (HsWC _ a) = loc a
461− loc _ = noSrcSpan
462−
463−instance HasLoc (Located a) where
464− loc (L l _) = l
465−
466−instance HasLoc a => HasLoc [a] where
467− loc [] = noSrcSpan
468− loc xs = foldl1' combineSrcSpans $ map loc xs
469−
470−instance HasLoc a => HasLoc (FamEqn s a) where
471− loc (FamEqn _ a Nothing b _ c) = foldl1' combineSrcSpans [loc a, loc b, loc c]
472− loc (FamEqn _ a (Just tvs) b _ c) = foldl1' combineSrcSpans
473− [loc a, loc tvs, loc b, loc c]
474− loc _ = noSrcSpan
475−instance (HasLoc tm, HasLoc ty) => HasLoc (HsArg tm ty) where
476− loc (HsValArg tm) = loc tm
477− loc (HsTypeArg _ ty) = loc ty
478− loc (HsArgPar sp) = sp
479−
480−instance HasLoc (HsDataDefn GhcRn) where
481− loc def@(HsDataDefn{}) = loc $ dd_cons def
482− -- Only used for data family instances, so we only need rhs
483− -- Most probably the rest will be unhelpful anyway
484− loc _ = noSrcSpan
485−
486−{- Note [Real DataCon Name]
487−The typechecker subtitutes the conLikeWrapId for the name, but we don't want
488−this showing up in the hieFile, so we replace the name in the Id with the
489−original datacon name
490−See also Note [Data Constructor Naming]
491−-}
492−class HasRealDataConName p where
493− getRealDataCon :: XRecordCon p -> Located (IdP p) -> Located (IdP p)
494−
495−instance HasRealDataConName GhcRn where
496− getRealDataCon _ n = n
497−instance HasRealDataConName GhcTc where
498− getRealDataCon RecordConTc{rcon_con_like = con} (L sp var) =
499− L sp (setVarName var (conLikeName con))
500−
501−-- | The main worker class
502−-- See Note [Updating HieAst for changes in the GHC AST] for more information
503−-- on how to add/modify instances for this.
504−class ToHie a where
505− toHie :: a -> HieM [HieAST Type]
506−
507−-- | Used to collect type info
508−class Data a => HasType a where
509− getTypeNode :: a -> HieM [HieAST Type]
510−
511−instance (ToHie a) => ToHie [a] where
512− toHie = concatMapM toHie
513−
514−instance (ToHie a) => ToHie (Bag a) where
515− toHie = toHie . bagToList
516−
517−instance (ToHie a) => ToHie (Maybe a) where
518− toHie = maybe (pure []) toHie
519−
520−instance ToHie (Context (Located NoExtField)) where
521− toHie _ = pure []
522−
523−instance ToHie (TScoped NoExtField) where
524− toHie _ = pure []
525−
526−instance ToHie (IEContext (Located ModuleName)) where
527− toHie (IEC c (L (RealSrcSpan span) mname)) =
528− pure $ [Node (NodeInfo S.empty [] idents) span []]
529− where details = mempty{identInfo = S.singleton (IEThing c)}
530− idents = M.singleton (Left mname) details
531− toHie _ = pure []
532−
533−instance ToHie (Context (Located Var)) where
534− toHie c = case c of
535− C context (L (RealSrcSpan span) name')
536− -> do
537− m <- asks name_remapping
538− let name = case lookupNameEnv m (varName name') of
539− Just var -> var
540− Nothing-> name'
541− pure
542− [Node
543− (NodeInfo S.empty [] $
544− M.singleton (Right $ varName name)
545− (IdentifierDetails (Just $ varType name')
546− (S.singleton context)))
547− span
548− []]
549− _ -> pure []
550−
551−instance ToHie (Context (Located Name)) where
552− toHie c = case c of
553− C context (L (RealSrcSpan span) name') -> do
554− m <- asks name_remapping
555− let name = case lookupNameEnv m name' of
556− Just var -> varName var
557− Nothing -> name'
558− pure
559− [Node
560− (NodeInfo S.empty [] $
561− M.singleton (Right name)
562− (IdentifierDetails Nothing
563− (S.singleton context)))
564− span
565− []]
566− _ -> pure []
567−
568−-- | Dummy instances - never called
569−instance ToHie (TScoped (LHsSigWcType GhcTc)) where
570− toHie _ = pure []
571−instance ToHie (TScoped (LHsWcType GhcTc)) where
572− toHie _ = pure []
573−instance ToHie (SigContext (LSig GhcTc)) where
574− toHie _ = pure []
575−instance ToHie (TScoped Type) where
576− toHie _ = pure []
577−
578−instance HasType (LHsBind GhcRn) where
579− getTypeNode (L spn bind) = makeNode bind spn
580−
581−instance HasType (LHsBind GhcTc) where
582− getTypeNode (L spn bind) = case bind of
583− FunBind{fun_id = name} -> makeTypeNode bind spn (varType $ unLoc name)
584− _ -> makeNode bind spn
585−
586−instance HasType (Located (Pat GhcRn)) where
587− getTypeNode (dL -> L spn pat) = makeNode pat spn
588−
589−instance HasType (Located (Pat GhcTc)) where
590− getTypeNode (dL -> L spn opat) = makeTypeNode opat spn (hsPatType opat)
591−
592−instance HasType (LHsExpr GhcRn) where
593− getTypeNode (L spn e) = makeNode e spn
594−
595−-- | This instance tries to construct 'HieAST' nodes which include the type of
596−-- the expression. It is not yet possible to do this efficiently for all
597−-- expression forms, so we skip filling in the type for those inputs.
598−--
599−-- 'HsApp', for example, doesn't have any type information available directly on
600−-- the node. Our next recourse would be to desugar it into a 'CoreExpr' then
601−-- query the type of that. Yet both the desugaring call and the type query both
602−-- involve recursive calls to the function and argument! This is particularly
603−-- problematic when you realize that the HIE traversal will eventually visit
604−-- those nodes too and ask for their types again.
605−--
606−-- Since the above is quite costly, we just skip cases where computing the
607−-- expression's type is going to be expensive.
608−--
609−-- See #16233
610−instance HasType (LHsExpr GhcTc) where
611− getTypeNode e@(L spn e') = lift $
612− -- Some expression forms have their type immediately available
613− let tyOpt = case e' of
614− HsLit _ l -> Just (hsLitType l)
615− HsOverLit _ o -> Just (overLitType o)
616−
617− HsLam _ (MG { mg_ext = groupTy }) -> Just (matchGroupType groupTy)
618− HsLamCase _ (MG { mg_ext = groupTy }) -> Just (matchGroupType groupTy)
619− HsCase _ _ (MG { mg_ext = groupTy }) -> Just (mg_res_ty groupTy)
620−
621− ExplicitList ty _ _ -> Just (mkListTy ty)
622− ExplicitSum ty _ _ _ -> Just (mkSumTy ty)
623− HsDo ty _ _ -> Just ty
624− HsMultiIf ty _ -> Just ty
625−
626− _ -> Nothing
627−
628− in
629− case tyOpt of
630− Just t -> makeTypeNode e' spn t
631− Nothing
632− | skipDesugaring e' -> fallback
633− | otherwise -> do
634− hs_env <- Hsc $ \e w -> return (e,w)
635− (_,mbe) <- liftIO $ deSugarExpr hs_env e
636− maybe fallback (makeTypeNode e' spn . exprType) mbe
637− where
638− fallback = makeNode e' spn
639−
640− matchGroupType :: MatchGroupTc -> Type
641− matchGroupType (MatchGroupTc args res) = mkVisFunTys args res
642−
643− -- | Skip desugaring of these expressions for performance reasons.
644− --
645− -- See impact on Haddock output (esp. missing type annotations or links)
646− -- before marking more things here as 'False'. See impact on Haddock
647− -- performance before marking more things as 'True'.
648− skipDesugaring :: HsExpr a -> Bool
649− skipDesugaring e = case e of
650− HsVar{} -> False
651− HsUnboundVar{} -> False
652− HsConLikeOut{} -> False
653− HsRecFld{} -> False
654− HsOverLabel{} -> False
655− HsIPVar{} -> False
656− HsWrap{} -> False
657− _ -> True
658−
659−instance ( ToHie (Context (Located (IdP a)))
660− , ToHie (MatchGroup a (LHsExpr a))
661− , ToHie (PScoped (LPat a))
662− , ToHie (GRHSs a (LHsExpr a))
663− , ToHie (LHsExpr a)
664− , ToHie (Located (PatSynBind a a))
665− , HasType (LHsBind a)
666− , ModifyState (IdP a)
667− , Data (HsBind a)
668− ) => ToHie (BindContext (LHsBind a)) where
669− toHie (BC context scope b@(L span bind)) =
670− concatM $ getTypeNode b : case bind of
671− FunBind{fun_id = name, fun_matches = matches} ->
672− [ toHie $ C (ValBind context scope $ getRealSpan span) name
673− , toHie matches
674− ]
675− PatBind{pat_lhs = lhs, pat_rhs = rhs} ->
676− [ toHie $ PS (getRealSpan span) scope NoScope lhs
677− , toHie rhs
678− ]
679− VarBind{var_rhs = expr} ->
680− [ toHie expr
681− ]
682− AbsBinds{abs_exports = xs, abs_binds = binds} ->
683− [ local (modifyState xs) $ -- Note [Name Remapping]
684− toHie $ fmap (BC context scope) binds
685− ]
686− PatSynBind _ psb ->
687− [ toHie $ L span psb -- PatSynBinds only occur at the top level
688− ]
689− XHsBindsLR _ -> []
690−
691−instance ( ToHie (LMatch a body)
692− ) => ToHie (MatchGroup a body) where
693− toHie mg = concatM $ case mg of
694− MG{ mg_alts = (L span alts) , mg_origin = FromSource } ->
695− [ pure $ locOnly span
696− , toHie alts
697− ]
698− MG{} -> []
699− XMatchGroup _ -> []
700−
701−instance ( ToHie (Context (Located (IdP a)))
702− , ToHie (PScoped (LPat a))
703− , ToHie (HsPatSynDir a)
704− ) => ToHie (Located (PatSynBind a a)) where
705− toHie (L sp psb) = concatM $ case psb of
706− PSB{psb_id=var, psb_args=dets, psb_def=pat, psb_dir=dir} ->
707− [ toHie $ C (Decl PatSynDec $ getRealSpan sp) var
708− , toHie $ toBind dets
709− , toHie $ PS Nothing lhsScope NoScope pat
710− , toHie dir
711− ]
712− where
713− lhsScope = combineScopes varScope detScope
714− varScope = mkLScope var
715− detScope = case dets of
716− (PrefixCon args) -> foldr combineScopes NoScope $ map mkLScope args
717− (InfixCon a b) -> combineScopes (mkLScope a) (mkLScope b)
718− (RecCon r) -> foldr go NoScope r
719− go (RecordPatSynField a b) c = combineScopes c
720− $ combineScopes (mkLScope a) (mkLScope b)
721− detSpan = case detScope of
722− LocalScope a -> Just a
723− _ -> Nothing
724− toBind (PrefixCon args) = PrefixCon $ map (C Use) args
725− toBind (InfixCon a b) = InfixCon (C Use a) (C Use b)
726− toBind (RecCon r) = RecCon $ map (PSC detSpan) r
727− XPatSynBind _ -> []
728−
729−instance ( ToHie (MatchGroup a (LHsExpr a))
730− ) => ToHie (HsPatSynDir a) where
731− toHie dir = case dir of
732− ExplicitBidirectional mg -> toHie mg
733− _ -> pure []
734−
735−instance ( a ~ GhcPass p
736− , ToHie body
737− , ToHie (HsMatchContext (NameOrRdrName (IdP a)))
738− , ToHie (PScoped (LPat a))
739− , ToHie (GRHSs a body)
740− , Data (Match a body)
741− ) => ToHie (LMatch (GhcPass p) body) where
742− toHie (L span m ) = concatM $ makeNode m span : case m of
743− Match{m_ctxt=mctx, m_pats = pats, m_grhss = grhss } ->
744− [ toHie mctx
745− , let rhsScope = mkScope $ grhss_span grhss
746− in toHie $ patScopes Nothing rhsScope NoScope pats
747− , toHie grhss
748− ]
749− XMatch _ -> []
750−
751−instance ( ToHie (Context (Located a))
752− ) => ToHie (HsMatchContext a) where
753− toHie (FunRhs{mc_fun=name}) = toHie $ C MatchBind name
754− toHie (StmtCtxt a) = toHie a
755− toHie _ = pure []
756−
757−instance ( ToHie (HsMatchContext a)
758− ) => ToHie (HsStmtContext a) where
759− toHie (PatGuard a) = toHie a
760− toHie (ParStmtCtxt a) = toHie a
761− toHie (TransStmtCtxt a) = toHie a
762− toHie _ = pure []
763−
764−instance ( a ~ GhcPass p
765− , ToHie (Context (Located (IdP a)))
766− , ToHie (RContext (HsRecFields a (PScoped (LPat a))))
767− , ToHie (LHsExpr a)
768− , ToHie (TScoped (LHsSigWcType a))
769− , ProtectSig a
770− , ToHie (TScoped (ProtectedSig a))
771− , HasType (LPat a)
772− , Data (HsSplice a)
773− ) => ToHie (PScoped (Located (Pat (GhcPass p)))) where
774− toHie (PS rsp scope pscope lpat@(dL -> L ospan opat)) =
775− concatM $ getTypeNode lpat : case opat of
776− WildPat _ ->
777− []
778− VarPat _ lname ->
779− [ toHie $ C (PatternBind scope pscope rsp) lname
780− ]
781− LazyPat _ p ->
782− [ toHie $ PS rsp scope pscope p
783− ]
784− AsPat _ lname pat ->
785− [ toHie $ C (PatternBind scope
786− (combineScopes (mkLScope (dL pat)) pscope)
787− rsp)
788− lname
789− , toHie $ PS rsp scope pscope pat
790− ]
791− ParPat _ pat ->
792− [ toHie $ PS rsp scope pscope pat
793− ]
794− BangPat _ pat ->
795− [ toHie $ PS rsp scope pscope pat
796− ]
797− ListPat _ pats ->
798− [ toHie $ patScopes rsp scope pscope pats
799− ]
800− TuplePat _ pats _ ->
801− [ toHie $ patScopes rsp scope pscope pats
802− ]
803− SumPat _ pat _ _ ->
804− [ toHie $ PS rsp scope pscope pat
805− ]
806− ConPatIn c dets ->
807− [ toHie $ C Use c
808− , toHie $ contextify dets
809− ]
810− ConPatOut {pat_con = con, pat_args = dets}->
811− [ toHie $ C Use $ fmap conLikeName con
812− , toHie $ contextify dets
813− ]
814− ViewPat _ expr pat ->
815− [ toHie expr
816− , toHie $ PS rsp scope pscope pat
817− ]
818− SplicePat _ sp ->
819− [ toHie $ L ospan sp
820− ]
821− LitPat _ _ ->
822− []
823− NPat _ _ _ _ ->
824− []
825− NPlusKPat _ n _ _ _ _ ->
826− [ toHie $ C (PatternBind scope pscope rsp) n
827− ]
828− SigPat _ pat sig ->
829− [ toHie $ PS rsp scope pscope pat
830− , let cscope = mkLScope (dL pat) in
831− toHie $ TS (ResolvedScopes [cscope, scope, pscope])
832− (protectSig @a cscope sig)
833− -- See Note [Scoping Rules for SigPat]
834− ]
835− CoPat _ _ _ _ ->
836− []
837− XPat _ -> []
838− where
839− contextify (PrefixCon args) = PrefixCon $ patScopes rsp scope pscope args
840− contextify (InfixCon a b) = InfixCon a' b'
841− where [a', b'] = patScopes rsp scope pscope [a,b]
842− contextify (RecCon r) = RecCon $ RC RecFieldMatch $ contextify_rec r
843− contextify_rec (HsRecFields fds a) = HsRecFields (map go scoped_fds) a
844− where
845− go (RS fscope (L spn (HsRecField lbl pat pun))) =
846− L spn $ HsRecField lbl (PS rsp scope fscope pat) pun
847− scoped_fds = listScopes pscope fds
848−
849−instance ( ToHie body
850− , ToHie (LGRHS a body)
851− , ToHie (RScoped (LHsLocalBinds a))
852− ) => ToHie (GRHSs a body) where
853− toHie grhs = concatM $ case grhs of
854− GRHSs _ grhss binds ->
855− [ toHie grhss
856− , toHie $ RS (mkScope $ grhss_span grhs) binds
857− ]
858− XGRHSs _ -> []
859−
860−instance ( ToHie (Located body)
861− , ToHie (RScoped (GuardLStmt a))
862− , Data (GRHS a (Located body))
863− ) => ToHie (LGRHS a (Located body)) where
864− toHie (L span g) = concatM $ makeNode g span : case g of
865− GRHS _ guards body ->
866− [ toHie $ listScopes (mkLScope body) guards
867− , toHie body
868− ]
869− XGRHS _ -> []
870−
871−instance ( a ~ GhcPass p
872− , ToHie (Context (Located (IdP a)))
873− , HasType (LHsExpr a)
874− , ToHie (PScoped (LPat a))
875− , ToHie (MatchGroup a (LHsExpr a))
876− , ToHie (LGRHS a (LHsExpr a))
877− , ToHie (RContext (HsRecordBinds a))
878− , ToHie (RFContext (Located (AmbiguousFieldOcc a)))
879− , ToHie (ArithSeqInfo a)
880− , ToHie (LHsCmdTop a)
881− , ToHie (RScoped (GuardLStmt a))
882− , ToHie (RScoped (LHsLocalBinds a))
883− , ToHie (TScoped (LHsWcType (NoGhcTc a)))
884− , ToHie (TScoped (LHsSigWcType (NoGhcTc a)))
885− , Data (HsExpr a)
886− , Data (HsSplice a)
887− , Data (HsTupArg a)
888− , Data (AmbiguousFieldOcc a)
889− , (HasRealDataConName a)
890− ) => ToHie (LHsExpr (GhcPass p)) where
891− toHie e@(L mspan oexpr) = concatM $ getTypeNode e : case oexpr of
892− HsVar _ (L _ var) ->
893− [ toHie $ C Use (L mspan var)
894− -- Patch up var location since typechecker removes it
895− ]
896− HsUnboundVar _ _ ->
897− []
898− HsConLikeOut _ con ->
899− [ toHie $ C Use $ L mspan $ conLikeName con
900− ]
901− HsRecFld _ fld ->
902− [ toHie $ RFC RecFieldOcc Nothing (L mspan fld)
903− ]
904− HsOverLabel _ _ _ -> []
905− HsIPVar _ _ -> []
906− HsOverLit _ _ -> []
907− HsLit _ _ -> []
908− HsLam _ mg ->
909− [ toHie mg
910− ]
911− HsLamCase _ mg ->
912− [ toHie mg
913− ]
914− HsApp _ a b ->
915− [ toHie a
916− , toHie b
917− ]
918− HsAppType _ expr sig ->
919− [ toHie expr
920− , toHie $ TS (ResolvedScopes []) sig
921− ]
922− OpApp _ a b c ->
923− [ toHie a
924− , toHie b
925− , toHie c
926− ]
927− NegApp _ a _ ->
928− [ toHie a
929− ]
930− HsPar _ a ->
931− [ toHie a
932− ]
933− SectionL _ a b ->
934− [ toHie a
935− , toHie b
936− ]
937− SectionR _ a b ->
938− [ toHie a
939− , toHie b
940− ]
941− ExplicitTuple _ args _ ->
942− [ toHie args
943− ]
944− ExplicitSum _ _ _ expr ->
945− [ toHie expr
946− ]
947− HsCase _ expr matches ->
948− [ toHie expr
949− , toHie matches
950− ]
951− HsIf _ _ a b c ->
952− [ toHie a
953− , toHie b
954− , toHie c
955− ]
956− HsMultiIf _ grhss ->
957− [ toHie grhss
958− ]
959− HsLet _ binds expr ->
960− [ toHie $ RS (mkLScope expr) binds
961− , toHie expr
962− ]
963− HsDo _ _ (L ispan stmts) ->
964− [ pure $ locOnly ispan
965− , toHie $ listScopes NoScope stmts
966− ]
967− ExplicitList _ _ exprs ->
968− [ toHie exprs
969− ]
970− RecordCon {rcon_ext = mrealcon, rcon_con_name = name, rcon_flds = binds} ->
971− [ toHie $ C Use (getRealDataCon @a mrealcon name)
972− -- See Note [Real DataCon Name]
973− , toHie $ RC RecFieldAssign $ binds
974− ]
975− RecordUpd {rupd_expr = expr, rupd_flds = upds}->
976− [ toHie expr
977− , toHie $ map (RC RecFieldAssign) upds
978− ]
979− ExprWithTySig _ expr sig ->
980− [ toHie expr
981− , toHie $ TS (ResolvedScopes [mkLScope expr]) sig
982− ]
983− ArithSeq _ _ info ->
984− [ toHie info
985− ]
986− HsSCC _ _ _ expr ->
987− [ toHie expr
988− ]
989− HsCoreAnn _ _ _ expr ->
990− [ toHie expr
991− ]
992− HsProc _ pat cmdtop ->
993− [ toHie $ PS Nothing (mkLScope cmdtop) NoScope pat
994− , toHie cmdtop
995− ]
996− HsStatic _ expr ->
997− [ toHie expr
998− ]
999− HsTick _ _ expr ->
1000− [ toHie expr
1001− ]
1002− HsBinTick _ _ _ expr ->
1003− [ toHie expr
1004− ]
1005− HsTickPragma _ _ _ _ expr ->
1006− [ toHie expr
1007− ]
1008− HsWrap _ _ a ->
1009− [ toHie $ L mspan a
1010− ]
1011− HsBracket _ b ->
1012− [ toHie b
1013− ]
1014− HsRnBracketOut _ b p ->
1015− [ toHie b
1016− , toHie p
1017− ]
1018− HsTcBracketOut _ b p ->
1019− [ toHie b
1020− , toHie p
1021− ]
1022− HsSpliceE _ x ->
1023− [ toHie $ L mspan x
1024− ]
1025− XExpr _ -> []
1026−
1027−instance ( a ~ GhcPass p
1028− , ToHie (LHsExpr a)
1029− , Data (HsTupArg a)
1030− ) => ToHie (LHsTupArg (GhcPass p)) where
1031− toHie (L span arg) = concatM $ makeNode arg span : case arg of
1032− Present _ expr ->
1033− [ toHie expr
1034− ]
1035− Missing _ -> []
1036− XTupArg _ -> []
1037−
1038−instance ( a ~ GhcPass p
1039− , ToHie (PScoped (LPat a))
1040− , ToHie (LHsExpr a)
1041− , ToHie (SigContext (LSig a))
1042− , ToHie (RScoped (LHsLocalBinds a))
1043− , ToHie (RScoped (ApplicativeArg a))
1044− , ToHie (Located body)
1045− , Data (StmtLR a a (Located body))
1046− , Data (StmtLR a a (Located (HsExpr a)))
1047− ) => ToHie (RScoped (LStmt (GhcPass p) (Located body))) where
1048− toHie (RS scope (L span stmt)) = concatM $ makeNode stmt span : case stmt of
1049− LastStmt _ body _ _ ->
1050− [ toHie body
1051− ]
1052− BindStmt _ pat body _ _ ->
1053− [ toHie $ PS (getRealSpan $ getLoc body) scope NoScope pat
1054− , toHie body
1055− ]
1056− ApplicativeStmt _ stmts _ ->
1057− [ concatMapM (toHie . RS scope . snd) stmts
1058− ]
1059− BodyStmt _ body _ _ ->
1060− [ toHie body
1061− ]
1062− LetStmt _ binds ->
1063− [ toHie $ RS scope binds
1064− ]
1065− ParStmt _ parstmts _ _ ->
1066− [ concatMapM (\(ParStmtBlock _ stmts _ _) ->
1067− toHie $ listScopes NoScope stmts)
1068− parstmts
1069− ]
1070− TransStmt {trS_stmts = stmts, trS_using = using, trS_by = by} ->
1071− [ toHie $ listScopes scope stmts
1072− , toHie using
1073− , toHie by
1074− ]
1075− RecStmt {recS_stmts = stmts} ->
1076− [ toHie $ map (RS $ combineScopes scope (mkScope span)) stmts
1077− ]
1078− XStmtLR _ -> []
1079−
1080−instance ( ToHie (LHsExpr a)
1081− , ToHie (PScoped (LPat a))
1082− , ToHie (BindContext (LHsBind a))
1083− , ToHie (SigContext (LSig a))
1084− , ToHie (RScoped (HsValBindsLR a a))
1085− , Data (HsLocalBinds a)
1086− ) => ToHie (RScoped (LHsLocalBinds a)) where
1087− toHie (RS scope (L sp binds)) = concatM $ makeNode binds sp : case binds of
1088− EmptyLocalBinds _ -> []
1089− HsIPBinds _ _ -> []
1090− HsValBinds _ valBinds ->
1091− [ toHie $ RS (combineScopes scope $ mkScope sp)
1092− valBinds
1093− ]
1094− XHsLocalBindsLR _ -> []
1095−
1096−instance ( ToHie (BindContext (LHsBind a))
1097− , ToHie (SigContext (LSig a))
1098− , ToHie (RScoped (XXValBindsLR a a))
1099− ) => ToHie (RScoped (HsValBindsLR a a)) where
1100− toHie (RS sc v) = concatM $ case v of
1101− ValBinds _ binds sigs ->
1102− [ toHie $ fmap (BC RegularBind sc) binds
1103− , toHie $ fmap (SC (SI BindSig Nothing)) sigs
1104− ]
1105− XValBindsLR x -> [ toHie $ RS sc x ]
1106−
1107−instance ToHie (RScoped (NHsValBindsLR GhcTc)) where
1108− toHie (RS sc (NValBinds binds sigs)) = concatM $
1109− [ toHie (concatMap (map (BC RegularBind sc) . bagToList . snd) binds)
1110− , toHie $ fmap (SC (SI BindSig Nothing)) sigs
1111− ]
1112−instance ToHie (RScoped (NHsValBindsLR GhcRn)) where
1113− toHie (RS sc (NValBinds binds sigs)) = concatM $
1114− [ toHie (concatMap (map (BC RegularBind sc) . bagToList . snd) binds)
1115− , toHie $ fmap (SC (SI BindSig Nothing)) sigs
1116− ]
1117−
1118−instance ( ToHie (RContext (LHsRecField a arg))
1119− ) => ToHie (RContext (HsRecFields a arg)) where
1120− toHie (RC c (HsRecFields fields _)) = toHie $ map (RC c) fields
1121−
1122−instance ( ToHie (RFContext (Located label))
1123− , ToHie arg
1124− , HasLoc arg
1125− , Data label
1126− , Data arg
1127− ) => ToHie (RContext (LHsRecField' label arg)) where
1128− toHie (RC c (L span recfld)) = concatM $ makeNode recfld span : case recfld of
1129− HsRecField label expr _ ->
1130− [ toHie $ RFC c (getRealSpan $ loc expr) label
1131− , toHie expr
1132− ]
1133−
1134−removeDefSrcSpan :: Name -> Name
1135−removeDefSrcSpan n = setNameLoc n noSrcSpan
1136−
1137−instance ToHie (RFContext (LFieldOcc GhcRn)) where
1138− toHie (RFC c rhs (L nspan f)) = concatM $ case f of
1139− FieldOcc name _ ->
1140− [ toHie $ C (RecField c rhs) (L nspan $ removeDefSrcSpan name)
1141− ]
1142− XFieldOcc _ -> []
1143−
1144−instance ToHie (RFContext (LFieldOcc GhcTc)) where
1145− toHie (RFC c rhs (L nspan f)) = concatM $ case f of
1146− FieldOcc var _ ->
1147− let var' = setVarName var (removeDefSrcSpan $ varName var)
1148− in [ toHie $ C (RecField c rhs) (L nspan var')
1149− ]
1150− XFieldOcc _ -> []
1151−
1152−instance ToHie (RFContext (Located (AmbiguousFieldOcc GhcRn))) where
1153− toHie (RFC c rhs (L nspan afo)) = concatM $ case afo of
1154− Unambiguous name _ ->
1155− [ toHie $ C (RecField c rhs) $ L nspan $ removeDefSrcSpan name
1156− ]
1157− Ambiguous _name _ ->
1158− [ ]
1159− XAmbiguousFieldOcc _ -> []
1160−
1161−instance ToHie (RFContext (Located (AmbiguousFieldOcc GhcTc))) where
1162− toHie (RFC c rhs (L nspan afo)) = concatM $ case afo of
1163− Unambiguous var _ ->
1164− let var' = setVarName var (removeDefSrcSpan $ varName var)
1165− in [ toHie $ C (RecField c rhs) (L nspan var')
1166− ]
1167− Ambiguous var _ ->
1168− let var' = setVarName var (removeDefSrcSpan $ varName var)
1169− in [ toHie $ C (RecField c rhs) (L nspan var')
1170− ]
1171− XAmbiguousFieldOcc _ -> []
1172−
1173−instance ( a ~ GhcPass p
1174− , ToHie (PScoped (LPat a))
1175− , ToHie (BindContext (LHsBind a))
1176− , ToHie (LHsExpr a)
1177− , ToHie (SigContext (LSig a))
1178− , ToHie (RScoped (HsValBindsLR a a))
1179− , Data (StmtLR a a (Located (HsExpr a)))
1180− , Data (HsLocalBinds a)
1181− ) => ToHie (RScoped (ApplicativeArg (GhcPass p))) where
1182− toHie (RS sc (ApplicativeArgOne _ pat expr _ _)) = concatM
1183− [ toHie $ PS Nothing sc NoScope pat
1184− , toHie expr
1185− ]
1186− toHie (RS sc (ApplicativeArgMany _ stmts _ pat)) = concatM
1187− [ toHie $ listScopes NoScope stmts
1188− , toHie $ PS Nothing sc NoScope pat
1189− ]
1190− toHie (RS _ (XApplicativeArg _)) = pure []
1191−
1192−instance (ToHie arg, ToHie rec) => ToHie (HsConDetails arg rec) where
1193− toHie (PrefixCon args) = toHie args
1194− toHie (RecCon rec) = toHie rec
1195− toHie (InfixCon a b) = concatM [ toHie a, toHie b]
1196−
1197−instance ( ToHie (LHsCmd a)
1198− , Data (HsCmdTop a)
1199− ) => ToHie (LHsCmdTop a) where
1200− toHie (L span top) = concatM $ makeNode top span : case top of
1201− HsCmdTop _ cmd ->
1202− [ toHie cmd
1203− ]
1204− XCmdTop _ -> []
1205−
1206−instance ( a ~ GhcPass p
1207− , ToHie (PScoped (LPat a))
1208− , ToHie (BindContext (LHsBind a))
1209− , ToHie (LHsExpr a)
1210− , ToHie (MatchGroup a (LHsCmd a))
1211− , ToHie (SigContext (LSig a))
1212− , ToHie (RScoped (HsValBindsLR a a))
1213− , Data (HsCmd a)
1214− , Data (HsCmdTop a)
1215− , Data (StmtLR a a (Located (HsCmd a)))
1216− , Data (HsLocalBinds a)
1217− , Data (StmtLR a a (Located (HsExpr a)))
1218− ) => ToHie (LHsCmd (GhcPass p)) where
1219− toHie (L span cmd) = concatM $ makeNode cmd span : case cmd of
1220− HsCmdArrApp _ a b _ _ ->
1221− [ toHie a
1222− , toHie b
1223− ]
1224− HsCmdArrForm _ a _ _ cmdtops ->
1225− [ toHie a
1226− , toHie cmdtops
1227− ]
1228− HsCmdApp _ a b ->
1229− [ toHie a
1230− , toHie b
1231− ]
1232− HsCmdLam _ mg ->
1233− [ toHie mg
1234− ]
1235− HsCmdPar _ a ->
1236− [ toHie a
1237− ]
1238− HsCmdCase _ expr alts ->
1239− [ toHie expr
1240− , toHie alts
1241− ]
1242− HsCmdIf _ _ a b c ->
1243− [ toHie a
1244− , toHie b
1245− , toHie c
1246− ]
1247− HsCmdLet _ binds cmd' ->
1248− [ toHie $ RS (mkLScope cmd') binds
1249− , toHie cmd'
1250− ]
1251− HsCmdDo _ (L ispan stmts) ->
1252− [ pure $ locOnly ispan
1253− , toHie $ listScopes NoScope stmts
1254− ]
1255− HsCmdWrap _ _ _ -> []
1256− XCmd _ -> []
1257−
1258−instance ToHie (TyClGroup GhcRn) where
1259− toHie TyClGroup{ group_tyclds = classes
1260− , group_roles = roles
1261− , group_kisigs = sigs
1262− , group_instds = instances } =
1263− concatM
1264− [ toHie classes
1265− , toHie sigs
1266− , toHie roles
1267− , toHie instances
1268− ]
1269− toHie (XTyClGroup _) = pure []
1270−
1271−instance ToHie (LTyClDecl GhcRn) where
1272− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1273− FamDecl {tcdFam = fdecl} ->
1274− [ toHie (L span fdecl)
1275− ]
1276− SynDecl {tcdLName = name, tcdTyVars = vars, tcdRhs = typ} ->
1277− [ toHie $ C (Decl SynDec $ getRealSpan span) name
1278− , toHie $ TS (ResolvedScopes [mkScope $ getLoc typ]) vars
1279− , toHie typ
1280− ]
1281− DataDecl {tcdLName = name, tcdTyVars = vars, tcdDataDefn = defn} ->
1282− [ toHie $ C (Decl DataDec $ getRealSpan span) name
1283− , toHie $ TS (ResolvedScopes [quant_scope, rhs_scope]) vars
1284− , toHie defn
1285− ]
1286− where
1287− quant_scope = mkLScope $ dd_ctxt defn
1288− rhs_scope = sig_sc `combineScopes` con_sc `combineScopes` deriv_sc
1289− sig_sc = maybe NoScope mkLScope $ dd_kindSig defn
1290− con_sc = foldr combineScopes NoScope $ map mkLScope $ dd_cons defn
1291− deriv_sc = mkLScope $ dd_derivs defn
1292− ClassDecl { tcdCtxt = context
1293− , tcdLName = name
1294− , tcdTyVars = vars
1295− , tcdFDs = deps
1296− , tcdSigs = sigs
1297− , tcdMeths = meths
1298− , tcdATs = typs
1299− , tcdATDefs = deftyps
1300− } ->
1301− [ toHie $ C (Decl ClassDec $ getRealSpan span) name
1302− , toHie context
1303− , toHie $ TS (ResolvedScopes [context_scope, rhs_scope]) vars
1304− , toHie deps
1305− , toHie $ map (SC $ SI ClassSig $ getRealSpan span) sigs
1306− , toHie $ fmap (BC InstanceBind ModuleScope) meths
1307− , toHie typs
1308− , concatMapM (pure . locOnly . getLoc) deftyps
1309− , toHie deftyps
1310− ]
1311− where
1312− context_scope = mkLScope context
1313− rhs_scope = foldl1' combineScopes $ map mkScope
1314− [ loc deps, loc sigs, loc (bagToList meths), loc typs, loc deftyps]
1315− XTyClDecl _ -> []
1316−
1317−instance ToHie (LFamilyDecl GhcRn) where
1318− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1319− FamilyDecl _ info name vars _ sig inj ->
1320− [ toHie $ C (Decl FamDec $ getRealSpan span) name
1321− , toHie $ TS (ResolvedScopes [rhsSpan]) vars
1322− , toHie info
1323− , toHie $ RS injSpan sig
1324− , toHie inj
1325− ]
1326− where
1327− rhsSpan = sigSpan `combineScopes` injSpan
1328− sigSpan = mkScope $ getLoc sig
1329− injSpan = maybe NoScope (mkScope . getLoc) inj
1330− XFamilyDecl _ -> []
1331−
1332−instance ToHie (FamilyInfo GhcRn) where
1333− toHie (ClosedTypeFamily (Just eqns)) = concatM $
1334− [ concatMapM (pure . locOnly . getLoc) eqns
1335− , toHie $ map go eqns
1336− ]
1337− where
1338− go (L l ib) = TS (ResolvedScopes [mkScope l]) ib
1339− toHie _ = pure []
1340−
1341−instance ToHie (RScoped (LFamilyResultSig GhcRn)) where
1342− toHie (RS sc (L span sig)) = concatM $ makeNode sig span : case sig of
1343− NoSig _ ->
1344− []
1345− KindSig _ k ->
1346− [ toHie k
1347− ]
1348− TyVarSig _ bndr ->
1349− [ toHie $ TVS (ResolvedScopes [sc]) NoScope bndr
1350− ]
1351− XFamilyResultSig _ -> []
1352−
1353−instance ToHie (Located (FunDep (Located Name))) where
1354− toHie (L span fd@(lhs, rhs)) = concatM $
1355− [ makeNode fd span
1356− , toHie $ map (C Use) lhs
1357− , toHie $ map (C Use) rhs
1358− ]
1359−
1360−instance (ToHie rhs, HasLoc rhs)
1361− => ToHie (TScoped (FamEqn GhcRn rhs)) where
1362− toHie (TS _ f) = toHie f
1363−
1364−instance (ToHie rhs, HasLoc rhs)
1365− => ToHie (FamEqn GhcRn rhs) where
1366− toHie fe@(FamEqn _ var tybndrs pats _ rhs) = concatM $
1367− [ toHie $ C (Decl InstDec $ getRealSpan $ loc fe) var
1368− , toHie $ fmap (tvScopes (ResolvedScopes []) scope) tybndrs
1369− , toHie pats
1370− , toHie rhs
1371− ]
1372− where scope = combineScopes patsScope rhsScope
1373− patsScope = mkScope (loc pats)
1374− rhsScope = mkScope (loc rhs)
1375− toHie (XFamEqn _) = pure []
1376−
1377−instance ToHie (LInjectivityAnn GhcRn) where
1378− toHie (L span ann) = concatM $ makeNode ann span : case ann of
1379− InjectivityAnn lhs rhs ->
1380− [ toHie $ C Use lhs
1381− , toHie $ map (C Use) rhs
1382− ]
1383−
1384−instance ToHie (HsDataDefn GhcRn) where
1385− toHie (HsDataDefn _ _ ctx _ mkind cons derivs) = concatM
1386− [ toHie ctx
1387− , toHie mkind
1388− , toHie cons
1389− , toHie derivs
1390− ]
1391− toHie (XHsDataDefn _) = pure []
1392−
1393−instance ToHie (HsDeriving GhcRn) where
1394− toHie (L span clauses) = concatM
1395− [ pure $ locOnly span
1396− , toHie clauses
1397− ]
1398−
1399−instance ToHie (LHsDerivingClause GhcRn) where
1400− toHie (L span cl) = concatM $ makeNode cl span : case cl of
1401− HsDerivingClause _ strat (L ispan tys) ->
1402− [ toHie strat
1403− , pure $ locOnly ispan
1404− , toHie $ map (TS (ResolvedScopes [])) tys
1405− ]
1406− XHsDerivingClause _ -> []
1407−
1408−instance ToHie (Located (DerivStrategy GhcRn)) where
1409− toHie (L span strat) = concatM $ makeNode strat span : case strat of
1410− StockStrategy -> []
1411− AnyclassStrategy -> []
1412− NewtypeStrategy -> []
1413− ViaStrategy s -> [ toHie $ TS (ResolvedScopes []) s ]
1414−
1415−instance ToHie (Located OverlapMode) where
1416− toHie (L span _) = pure $ locOnly span
1417−
1418−instance ToHie (LConDecl GhcRn) where
1419− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1420− ConDeclGADT { con_names = names, con_qvars = qvars
1421− , con_mb_cxt = ctx, con_args = args, con_res_ty = typ } ->
1422− [ toHie $ map (C (Decl ConDec $ getRealSpan span)) names
1423− , toHie $ TS (ResolvedScopes [ctxScope, rhsScope]) qvars
1424− , toHie ctx
1425− , toHie args
1426− , toHie typ
1427− ]
1428− where
1429− rhsScope = combineScopes argsScope tyScope
1430− ctxScope = maybe NoScope mkLScope ctx
1431− argsScope = condecl_scope args
1432− tyScope = mkLScope typ
1433− ConDeclH98 { con_name = name, con_ex_tvs = qvars
1434− , con_mb_cxt = ctx, con_args = dets } ->
1435− [ toHie $ C (Decl ConDec $ getRealSpan span) name
1436− , toHie $ tvScopes (ResolvedScopes []) rhsScope qvars
1437− , toHie ctx
1438− , toHie dets
1439− ]
1440− where
1441− rhsScope = combineScopes ctxScope argsScope
1442− ctxScope = maybe NoScope mkLScope ctx
1443− argsScope = condecl_scope dets
1444− XConDecl _ -> []
1445− where condecl_scope args = case args of
1446− PrefixCon xs -> foldr combineScopes NoScope $ map mkLScope xs
1447− InfixCon a b -> combineScopes (mkLScope a) (mkLScope b)
1448− RecCon x -> mkLScope x
1449−
1450−instance ToHie (Located [LConDeclField GhcRn]) where
1451− toHie (L span decls) = concatM $
1452− [ pure $ locOnly span
1453− , toHie decls
1454− ]
1455−
1456−instance ( HasLoc thing
1457− , ToHie (TScoped thing)
1458− ) => ToHie (TScoped (HsImplicitBndrs GhcRn thing)) where
1459− toHie (TS sc (HsIB ibrn a)) = concatM $
1460− [ pure $ bindingsOnly $ map (C $ TyVarBind (mkScope span) sc) ibrn
1461− , toHie $ TS sc a
1462− ]
1463− where span = loc a
1464− toHie (TS _ (XHsImplicitBndrs _)) = pure []
1465−
1466−instance ( HasLoc thing
1467− , ToHie (TScoped thing)
1468− ) => ToHie (TScoped (HsWildCardBndrs GhcRn thing)) where
1469− toHie (TS sc (HsWC names a)) = concatM $
1470− [ pure $ bindingsOnly $ map (C $ TyVarBind (mkScope span) sc) names
1471− , toHie $ TS sc a
1472− ]
1473− where span = loc a
1474− toHie (TS _ (XHsWildCardBndrs _)) = pure []
1475−
1476−instance ToHie (LStandaloneKindSig GhcRn) where
1477− toHie (L sp sig) = concatM [makeNode sig sp, toHie sig]
1478−
1479−instance ToHie (StandaloneKindSig GhcRn) where
1480− toHie sig = concatM $ case sig of
1481− StandaloneKindSig _ name typ ->
1482− [ toHie $ C TyDecl name
1483− , toHie $ TS (ResolvedScopes []) typ
1484− ]
1485− XStandaloneKindSig _ -> []
1486−
1487−instance ToHie (SigContext (LSig GhcRn)) where
1488− toHie (SC (SI styp msp) (L sp sig)) = concatM $ makeNode sig sp : case sig of
1489− TypeSig _ names typ ->
1490− [ toHie $ map (C TyDecl) names
1491− , toHie $ TS (UnresolvedScope (map unLoc names) Nothing) typ
1492− ]
1493− PatSynSig _ names typ ->
1494− [ toHie $ map (C TyDecl) names
1495− , toHie $ TS (UnresolvedScope (map unLoc names) Nothing) typ
1496− ]
1497− ClassOpSig _ _ names typ ->
1498− [ case styp of
1499− ClassSig -> toHie $ map (C $ ClassTyDecl $ getRealSpan sp) names
1500− _ -> toHie $ map (C $ TyDecl) names
1501− , toHie $ TS (UnresolvedScope (map unLoc names) msp) typ
1502− ]
1503− IdSig _ _ -> []
1504− FixSig _ fsig ->
1505− [ toHie $ L sp fsig
1506− ]
1507− InlineSig _ name _ ->
1508− [ toHie $ (C Use) name
1509− ]
1510− SpecSig _ name typs _ ->
1511− [ toHie $ (C Use) name
1512− , toHie $ map (TS (ResolvedScopes [])) typs
1513− ]
1514− SpecInstSig _ _ typ ->
1515− [ toHie $ TS (ResolvedScopes []) typ
1516− ]
1517− MinimalSig _ _ form ->
1518− [ toHie form
1519− ]
1520− SCCFunSig _ _ name mtxt ->
1521− [ toHie $ (C Use) name
1522− , pure $ maybe [] (locOnly . getLoc) mtxt
1523− ]
1524− CompleteMatchSig _ _ (L ispan names) typ ->
1525− [ pure $ locOnly ispan
1526− , toHie $ map (C Use) names
1527− , toHie $ fmap (C Use) typ
1528− ]
1529− XSig _ -> []
1530−
1531−instance ToHie (LHsType GhcRn) where
1532− toHie x = toHie $ TS (ResolvedScopes []) x
1533−
1534−instance ToHie (TScoped (LHsType GhcRn)) where
1535− toHie (TS tsc (L span t)) = concatM $ makeNode t span : case t of
1536− HsForAllTy _ _ bndrs body ->
1537− [ toHie $ tvScopes tsc (mkScope $ getLoc body) bndrs
1538− , toHie body
1539− ]
1540− HsQualTy _ ctx body ->
1541− [ toHie ctx
1542− , toHie body
1543− ]
1544− HsTyVar _ _ var ->
1545− [ toHie $ C Use var
1546− ]
1547− HsAppTy _ a b ->
1548− [ toHie a
1549− , toHie b
1550− ]
1551− HsAppKindTy _ ty ki ->
1552− [ toHie ty
1553− , toHie $ TS (ResolvedScopes []) ki
1554− ]
1555− HsFunTy _ a b ->
1556− [ toHie a
1557− , toHie b
1558− ]
1559− HsListTy _ a ->
1560− [ toHie a
1561− ]
1562− HsTupleTy _ _ tys ->
1563− [ toHie tys
1564− ]
1565− HsSumTy _ tys ->
1566− [ toHie tys
1567− ]
1568− HsOpTy _ a op b ->
1569− [ toHie a
1570− , toHie $ C Use op
1571− , toHie b
1572− ]
1573− HsParTy _ a ->
1574− [ toHie a
1575− ]
1576− HsIParamTy _ ip ty ->
1577− [ toHie ip
1578− , toHie ty
1579− ]
1580− HsKindSig _ a b ->
1581− [ toHie a
1582− , toHie b
1583− ]
1584− HsSpliceTy _ a ->
1585− [ toHie $ L span a
1586− ]
1587− HsDocTy _ a _ ->
1588− [ toHie a
1589− ]
1590− HsBangTy _ _ ty ->
1591− [ toHie ty
1592− ]
1593− HsRecTy _ fields ->
1594− [ toHie fields
1595− ]
1596− HsExplicitListTy _ _ tys ->
1597− [ toHie tys
1598− ]
1599− HsExplicitTupleTy _ tys ->
1600− [ toHie tys
1601− ]
1602− HsTyLit _ _ -> []
1603− HsWildCardTy _ -> []
1604− HsStarTy _ _ -> []
1605− XHsType _ -> []
1606−
1607−instance (ToHie tm, ToHie ty) => ToHie (HsArg tm ty) where
1608− toHie (HsValArg tm) = toHie tm
1609− toHie (HsTypeArg _ ty) = toHie ty
1610− toHie (HsArgPar sp) = pure $ locOnly sp
1611−
1612−instance ToHie (TVScoped (LHsTyVarBndr GhcRn)) where
1613− toHie (TVS tsc sc (L span bndr)) = concatM $ makeNode bndr span : case bndr of
1614− UserTyVar _ var ->
1615− [ toHie $ C (TyVarBind sc tsc) var
1616− ]
1617− KindedTyVar _ var kind ->
1618− [ toHie $ C (TyVarBind sc tsc) var
1619− , toHie kind
1620− ]
1621− XTyVarBndr _ -> []
1622−
1623−instance ToHie (TScoped (LHsQTyVars GhcRn)) where
1624− toHie (TS sc (HsQTvs implicits vars)) = concatM $
1625− [ pure $ bindingsOnly bindings
1626− , toHie $ tvScopes sc NoScope vars
1627− ]
1628− where
1629− varLoc = loc vars
1630− bindings = map (C $ TyVarBind (mkScope varLoc) sc) implicits
1631− toHie (TS _ (XLHsQTyVars _)) = pure []
1632−
1633−instance ToHie (LHsContext GhcRn) where
1634− toHie (L span tys) = concatM $
1635− [ pure $ locOnly span
1636− , toHie tys
1637− ]
1638−
1639−instance ToHie (LConDeclField GhcRn) where
1640− toHie (L span field) = concatM $ makeNode field span : case field of
1641− ConDeclField _ fields typ _ ->
1642− [ toHie $ map (RFC RecFieldDecl (getRealSpan $ loc typ)) fields
1643− , toHie typ
1644− ]
1645− XConDeclField _ -> []
1646−
1647−instance ToHie (LHsExpr a) => ToHie (ArithSeqInfo a) where
1648− toHie (From expr) = toHie expr
1649− toHie (FromThen a b) = concatM $
1650− [ toHie a
1651− , toHie b
1652− ]
1653− toHie (FromTo a b) = concatM $
1654− [ toHie a
1655− , toHie b
1656− ]
1657− toHie (FromThenTo a b c) = concatM $
1658− [ toHie a
1659− , toHie b
1660− , toHie c
1661− ]
1662−
1663−instance ToHie (LSpliceDecl GhcRn) where
1664− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1665− SpliceDecl _ splice _ ->
1666− [ toHie splice
1667− ]
1668− XSpliceDecl _ -> []
1669−
1670−instance ToHie (HsBracket a) where
1671− toHie _ = pure []
1672−
1673−instance ToHie PendingRnSplice where
1674− toHie _ = pure []
1675−
1676−instance ToHie PendingTcSplice where
1677− toHie _ = pure []
1678−
1679−instance ToHie (LBooleanFormula (Located Name)) where
1680− toHie (L span form) = concatM $ makeNode form span : case form of
1681− Var a ->
1682− [ toHie $ C Use a
1683− ]
1684− And forms ->
1685− [ toHie forms
1686− ]
1687− Or forms ->
1688− [ toHie forms
1689− ]
1690− Parens f ->
1691− [ toHie f
1692− ]
1693−
1694−instance ToHie (Located HsIPName) where
1695− toHie (L span e) = makeNode e span
1696−
1697−instance ( ToHie (LHsExpr a)
1698− , Data (HsSplice a)
1699− ) => ToHie (Located (HsSplice a)) where
1700− toHie (L span sp) = concatM $ makeNode sp span : case sp of
1701− HsTypedSplice _ _ _ expr ->
1702− [ toHie expr
1703− ]
1704− HsUntypedSplice _ _ _ expr ->
1705− [ toHie expr
1706− ]
1707− HsQuasiQuote _ _ _ ispan _ ->
1708− [ pure $ locOnly ispan
1709− ]
1710− HsSpliced _ _ _ ->
1711− []
1712− HsSplicedT _ ->
1713− []
1714− XSplice _ -> []
1715−
1716−instance ToHie (LRoleAnnotDecl GhcRn) where
1717− toHie (L span annot) = concatM $ makeNode annot span : case annot of
1718− RoleAnnotDecl _ var roles ->
1719− [ toHie $ C Use var
1720− , concatMapM (pure . locOnly . getLoc) roles
1721− ]
1722− XRoleAnnotDecl _ -> []
1723−
1724−instance ToHie (LInstDecl GhcRn) where
1725− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1726− ClsInstD _ d ->
1727− [ toHie $ L span d
1728− ]
1729− DataFamInstD _ d ->
1730− [ toHie $ L span d
1731− ]
1732− TyFamInstD _ d ->
1733− [ toHie $ L span d
1734− ]
1735− XInstDecl _ -> []
1736−
1737−instance ToHie (LClsInstDecl GhcRn) where
1738− toHie (L span decl) = concatM
1739− [ toHie $ TS (ResolvedScopes [mkScope span]) $ cid_poly_ty decl
1740− , toHie $ fmap (BC InstanceBind ModuleScope) $ cid_binds decl
1741− , toHie $ map (SC $ SI InstSig $ getRealSpan span) $ cid_sigs decl
1742− , pure $ concatMap (locOnly . getLoc) $ cid_tyfam_insts decl
1743− , toHie $ cid_tyfam_insts decl
1744− , pure $ concatMap (locOnly . getLoc) $ cid_datafam_insts decl
1745− , toHie $ cid_datafam_insts decl
1746− , toHie $ cid_overlap_mode decl
1747− ]
1748−
1749−instance ToHie (LDataFamInstDecl GhcRn) where
1750− toHie (L sp (DataFamInstDecl d)) = toHie $ TS (ResolvedScopes [mkScope sp]) d
1751−
1752−instance ToHie (LTyFamInstDecl GhcRn) where
1753− toHie (L sp (TyFamInstDecl d)) = toHie $ TS (ResolvedScopes [mkScope sp]) d
1754−
1755−instance ToHie (Context a)
1756− => ToHie (PatSynFieldContext (RecordPatSynField a)) where
1757− toHie (PSC sp (RecordPatSynField a b)) = concatM $
1758− [ toHie $ C (RecField RecFieldDecl sp) a
1759− , toHie $ C Use b
1760− ]
1761−
1762−instance ToHie (LDerivDecl GhcRn) where
1763− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1764− DerivDecl _ typ strat overlap ->
1765− [ toHie $ TS (ResolvedScopes []) typ
1766− , toHie strat
1767− , toHie overlap
1768− ]
1769− XDerivDecl _ -> []
1770−
1771−instance ToHie (LFixitySig GhcRn) where
1772− toHie (L span sig) = concatM $ makeNode sig span : case sig of
1773− FixitySig _ vars _ ->
1774− [ toHie $ map (C Use) vars
1775− ]
1776− XFixitySig _ -> []
1777−
1778−instance ToHie (LDefaultDecl GhcRn) where
1779− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1780− DefaultDecl _ typs ->
1781− [ toHie typs
1782− ]
1783− XDefaultDecl _ -> []
1784−
1785−instance ToHie (LForeignDecl GhcRn) where
1786− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1787− ForeignImport {fd_name = name, fd_sig_ty = sig, fd_fi = fi} ->
1788− [ toHie $ C (ValBind RegularBind ModuleScope $ getRealSpan span) name
1789− , toHie $ TS (ResolvedScopes []) sig
1790− , toHie fi
1791− ]
1792− ForeignExport {fd_name = name, fd_sig_ty = sig, fd_fe = fe} ->
1793− [ toHie $ C Use name
1794− , toHie $ TS (ResolvedScopes []) sig
1795− , toHie fe
1796− ]
1797− XForeignDecl _ -> []
1798−
1799−instance ToHie ForeignImport where
1800− toHie (CImport (L a _) (L b _) _ _ (L c _)) = pure $ concat $
1801− [ locOnly a
1802− , locOnly b
1803− , locOnly c
1804− ]
1805−
1806−instance ToHie ForeignExport where
1807− toHie (CExport (L a _) (L b _)) = pure $ concat $
1808− [ locOnly a
1809− , locOnly b
1810− ]
1811−
1812−instance ToHie (LWarnDecls GhcRn) where
1813− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1814− Warnings _ _ warnings ->
1815− [ toHie warnings
1816− ]
1817− XWarnDecls _ -> []
1818−
1819−instance ToHie (LWarnDecl GhcRn) where
1820− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1821− Warning _ vars _ ->
1822− [ toHie $ map (C Use) vars
1823− ]
1824− XWarnDecl _ -> []
1825−
1826−instance ToHie (LAnnDecl GhcRn) where
1827− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1828− HsAnnotation _ _ prov expr ->
1829− [ toHie prov
1830− , toHie expr
1831− ]
1832− XAnnDecl _ -> []
1833−
1834−instance ToHie (Context (Located a)) => ToHie (AnnProvenance a) where
1835− toHie (ValueAnnProvenance a) = toHie $ C Use a
1836− toHie (TypeAnnProvenance a) = toHie $ C Use a
1837− toHie ModuleAnnProvenance = pure []
1838−
1839−instance ToHie (LRuleDecls GhcRn) where
1840− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1841− HsRules _ _ rules ->
1842− [ toHie rules
1843− ]
1844− XRuleDecls _ -> []
1845−
1846−instance ToHie (LRuleDecl GhcRn) where
1847− toHie (L _ (XRuleDecl _)) = pure []
1848− toHie (L span r@(HsRule _ rname _ tybndrs bndrs exprA exprB)) = concatM
1849− [ makeNode r span
1850− , pure $ locOnly $ getLoc rname
1851− , toHie $ fmap (tvScopes (ResolvedScopes []) scope) tybndrs
1852− , toHie $ map (RS $ mkScope span) bndrs
1853− , toHie exprA
1854− , toHie exprB
1855− ]
1856− where scope = bndrs_sc `combineScopes` exprA_sc `combineScopes` exprB_sc
1857− bndrs_sc = maybe NoScope mkLScope (listToMaybe bndrs)
1858− exprA_sc = mkLScope exprA
1859− exprB_sc = mkLScope exprB
1860−
1861−instance ToHie (RScoped (LRuleBndr GhcRn)) where
1862− toHie (RS sc (L span bndr)) = concatM $ makeNode bndr span : case bndr of
1863− RuleBndr _ var ->
1864− [ toHie $ C (ValBind RegularBind sc Nothing) var
1865− ]
1866− RuleBndrSig _ var typ ->
1867− [ toHie $ C (ValBind RegularBind sc Nothing) var
1868− , toHie $ TS (ResolvedScopes [sc]) typ
1869− ]
1870− XRuleBndr _ -> []
1871−
1872−instance ToHie (LImportDecl GhcRn) where
1873− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1874− ImportDecl { ideclName = name, ideclAs = as, ideclHiding = hidden } ->
1875− [ toHie $ IEC Import name
1876− , toHie $ fmap (IEC ImportAs) as
1877− , maybe (pure []) goIE hidden
1878− ]
1879− XImportDecl _ -> []
1880− where
1881− goIE (hiding, (L sp liens)) = concatM $
1882− [ pure $ locOnly sp
1883− , toHie $ map (IEC c) liens
1884− ]
1885− where
1886− c = if hiding then ImportHiding else Import
1887−
1888−instance ToHie (IEContext (LIE GhcRn)) where
1889− toHie (IEC c (L span ie)) = concatM $ makeNode ie span : case ie of
1890− IEVar _ n ->
1891− [ toHie $ IEC c n
1892− ]
1893− IEThingAbs _ n ->
1894− [ toHie $ IEC c n
1895− ]
1896− IEThingAll _ n ->
1897− [ toHie $ IEC c n
1898− ]
1899− IEThingWith _ n _ ns flds ->
1900− [ toHie $ IEC c n
1901− , toHie $ map (IEC c) ns
1902− , toHie $ map (IEC c) flds
1903− ]
1904− IEModuleContents _ n ->
1905− [ toHie $ IEC c n
1906− ]
1907− IEGroup _ _ _ -> []
1908− IEDoc _ _ -> []
1909− IEDocNamed _ _ -> []
1910− XIE _ -> []
1911−
1912−instance ToHie (IEContext (LIEWrappedName Name)) where
1913− toHie (IEC c (L span iewn)) = concatM $ makeNode iewn span : case iewn of
1914− IEName n ->
1915− [ toHie $ C (IEThing c) n
1916− ]
1917− IEPattern p ->
1918− [ toHie $ C (IEThing c) p
1919− ]
1920− IEType n ->
1921− [ toHie $ C (IEThing c) n
1922− ]
1923−
1924−instance ToHie (IEContext (Located (FieldLbl Name))) where
1925− toHie (IEC c (L span lbl)) = concatM $ makeNode lbl span : case lbl of
1926− FieldLabel _ _ n ->
1927− [ toHie $ C (IEThing c) $ L span n
1928− ]
src-ghc88/Development/IDE/GHC/HieAst.hsdeleted−1789
@@ -1,1789 +0,0 @@
1−
2−{-
3−Forked from GHC v8.8.1 to work around the readFile side effect in mkHiefile
4−
5−Main functions for .hie file generation
6−-}
7−{- HLINT ignore -}
8−{-# LANGUAGE OverloadedStrings #-}
9−{-# LANGUAGE FlexibleInstances #-}
10−{-# LANGUAGE UndecidableInstances #-}
11−{-# LANGUAGE FlexibleContexts #-}
12−{-# LANGUAGE TypeSynonymInstances #-}
13−{-# LANGUAGE ScopedTypeVariables #-}
14−{-# LANGUAGE TypeFamilies #-}
15−{-# LANGUAGE TypeApplications #-}
16−{-# LANGUAGE AllowAmbiguousTypes #-}
17−{-# LANGUAGE ViewPatterns #-}
18−{-# LANGUAGE DeriveDataTypeable #-}
19−module Development.IDE.GHC.HieAst ( mkHieFile ) where
20−
21−import Avail ( Avails )
22−import Bag ( Bag, bagToList )
23−import BasicTypes
24−import BooleanFormula
25−import Class ( FunDep )
26−import CoreUtils ( exprType )
27−import ConLike ( conLikeName )
28−import Desugar ( deSugarExpr )
29−import FieldLabel
30−import HsSyn
31−import HscTypes
32−import Module ( ModuleName, ml_hs_file )
33−import MonadUtils ( concatMapM, liftIO )
34−import Name ( Name, nameSrcSpan, setNameLoc )
35−import SrcLoc
36−import TcHsSyn ( hsLitType, hsPatType )
37−import Type ( mkFunTys, Type )
38−import TysWiredIn ( mkListTy, mkSumTy )
39−import Var ( Id, Var, setVarName, varName, varType )
40−import TcRnTypes
41−import MkIface ( mkIfaceExports )
42−
43−import HieTypes
44−import HieUtils
45−
46−import qualified Data.Array as A
47−import qualified Data.ByteString as BS
48−import qualified Data.Map as M
49−import qualified Data.Set as S
50−import Data.Data ( Data, Typeable )
51−import Data.List (foldl', foldl1' )
52−import Data.Maybe ( listToMaybe )
53−import Control.Monad.Trans.Reader
54−import Control.Monad.Trans.Class ( lift )
55−
56−-- These synonyms match those defined in main/GHC.hs
57−type RenamedSource = ( HsGroup GhcRn, [LImportDecl GhcRn]
58− , Maybe [(LIE GhcRn, Avails)]
59− , Maybe LHsDocString )
60−type TypecheckedSource = LHsBinds GhcTc
61−
62−
63−{- Note [Name Remapping]
64−The Typechecker introduces new names for mono names in AbsBinds.
65−We don't care about the distinction between mono and poly bindings,
66−so we replace all occurrences of the mono name with the poly name.
67−-}
68−newtype HieState = HieState
69− { name_remapping :: M.Map Name Id
70− }
71−
72−initState :: HieState
73−initState = HieState M.empty
74−
75−class ModifyState a where -- See Note [Name Remapping]
76− addSubstitution :: a -> a -> HieState -> HieState
77−
78−instance ModifyState Name where
79− addSubstitution _ _ hs = hs
80−
81−instance ModifyState Id where
82− addSubstitution mono poly hs =
83− hs{name_remapping = M.insert (varName mono) poly (name_remapping hs)}
84−
85−modifyState :: ModifyState (IdP p) => [ABExport p] -> HieState -> HieState
86−modifyState = foldr go id
87− where
88− go ABE{abe_poly=poly,abe_mono=mono} f = addSubstitution mono poly . f
89− go _ f = f
90−
91−type HieM = ReaderT HieState Hsc
92−
93−-- | Construct an 'HieFile' from the outputs of the typechecker.
94−mkHieFile :: ModSummary
95− -> TcGblEnv
96− -> RenamedSource
97− -> BS.ByteString
98− -> Hsc HieFile
99−mkHieFile ms ts rs src = do
100− let tc_binds = tcg_binds ts
101− (asts', arr) <- getCompressedAsts tc_binds rs
102− let Just src_file = ml_hs_file $ ms_location ms
103− return $ HieFile
104− { hie_hs_file = src_file
105− , hie_module = ms_mod ms
106− , hie_types = arr
107− , hie_asts = asts'
108− -- mkIfaceExports sorts the AvailInfos for stability
109− , hie_exports = mkIfaceExports (tcg_exports ts)
110− , hie_hs_src = src
111− }
112−
113−getCompressedAsts :: TypecheckedSource -> RenamedSource
114− -> Hsc (HieASTs TypeIndex, A.Array TypeIndex HieTypeFlat)
115−getCompressedAsts ts rs = do
116− asts <- enrichHie ts rs
117− return $ compressTypes asts
118−
119−enrichHie :: TypecheckedSource -> RenamedSource -> Hsc (HieASTs Type)
120−enrichHie ts (hsGrp, imports, exports, _) = flip runReaderT initState $ do
121− tasts <- toHie $ fmap (BC RegularBind ModuleScope) ts
122− rasts <- processGrp hsGrp
123− imps <- toHie $ filter (not . ideclImplicit . unLoc) imports
124− exps <- toHie $ fmap (map $ IEC Export . fst) exports
125− let spanFile children = case children of
126− [] -> mkRealSrcSpan (mkRealSrcLoc "" 1 1) (mkRealSrcLoc "" 1 1)
127− _ -> mkRealSrcSpan (realSrcSpanStart $ nodeSpan $ head children)
128− (realSrcSpanEnd $ nodeSpan $ last children)
129−
130− modulify xs =
131− Node (simpleNodeInfo "Module" "Module") (spanFile xs) xs
132−
133− asts = HieASTs
134− $ resolveTyVarScopes
135− $ M.map (modulify . mergeSortAsts)
136− $ M.fromListWith (++)
137− $ map (\x -> (srcSpanFile (nodeSpan x),[x])) flat_asts
138−
139− flat_asts = concat
140− [ tasts
141− , rasts
142− , imps
143− , exps
144− ]
145− return asts
146− where
147− processGrp grp = concatM
148− [ toHie $ fmap (RS ModuleScope ) hs_valds grp
149− , toHie $ hs_splcds grp
150− , toHie $ hs_tyclds grp
151− , toHie $ hs_derivds grp
152− , toHie $ hs_fixds grp
153− , toHie $ hs_defds grp
154− , toHie $ hs_fords grp
155− , toHie $ hs_warnds grp
156− , toHie $ hs_annds grp
157− , toHie $ hs_ruleds grp
158− ]
159−
160−getRealSpan :: SrcSpan -> Maybe Span
161−getRealSpan (RealSrcSpan sp) = Just sp
162−getRealSpan _ = Nothing
163−
164−grhss_span :: GRHSs p body -> SrcSpan
165−grhss_span (GRHSs _ xs bs) = foldl' combineSrcSpans (getLoc bs) (map getLoc xs)
166−grhss_span (XGRHSs _) = error "XGRHS has no span"
167−
168−bindingsOnly :: [Context Name] -> [HieAST a]
169−bindingsOnly [] = []
170−bindingsOnly (C c n : xs) = case nameSrcSpan n of
171− RealSrcSpan span -> Node nodeinfo span [] : bindingsOnly xs
172− where nodeinfo = NodeInfo S.empty [] (M.singleton (Right n) info)
173− info = mempty{identInfo = S.singleton c}
174− _ -> bindingsOnly xs
175−
176−concatM :: Monad m => [m [a]] -> m [a]
177−concatM xs = concat <$> sequence xs
178−
179−{- Note [Capturing Scopes and other non local information]
180−toHie is a local tranformation, but scopes of bindings cannot be known locally,
181−hence we have to push the relevant info down into the binding nodes.
182−We use the following types (*Context and *Scoped) to wrap things and
183−carry the required info
184−(Maybe Span) always carries the span of the entire binding, including rhs
185−-}
186−data Context a = C ContextInfo a -- Used for names and bindings
187−
188−data RContext a = RC RecFieldContext a
189−data RFContext a = RFC RecFieldContext (Maybe Span) a
190−-- ^ context for record fields
191−
192−data IEContext a = IEC IEType a
193−-- ^ context for imports/exports
194−
195−data BindContext a = BC BindType Scope a
196−-- ^ context for imports/exports
197−
198−data PatSynFieldContext a = PSC (Maybe Span) a
199−-- ^ context for pattern synonym fields.
200−
201−data SigContext a = SC SigInfo a
202−-- ^ context for type signatures
203−
204−data SigInfo = SI SigType (Maybe Span)
205−
206−data SigType = BindSig | ClassSig | InstSig
207−
208−data RScoped a = RS Scope a
209−-- ^ Scope spans over everything to the right of a, (mostly) not
210−-- including a itself
211−-- (Includes a in a few special cases like recursive do bindings) or
212−-- let/where bindings
213−
214−-- | Pattern scope
215−data PScoped a = PS (Maybe Span)
216− Scope -- ^ use site of the pattern
217− Scope -- ^ pattern to the right of a, not including a
218− a
219− deriving (Typeable, Data) -- Pattern Scope
220−
221−{- Note [TyVar Scopes]
222−Due to -XScopedTypeVariables, type variables can be in scope quite far from
223−their original binding. We resolve the scope of these type variables
224−in a separate pass
225−-}
226−data TScoped a = TS TyVarScope a -- TyVarScope
227−
228−data TVScoped a = TVS TyVarScope Scope a -- TyVarScope
229−-- ^ First scope remains constant
230−-- Second scope is used to build up the scope of a tyvar over
231−-- things to its right, ala RScoped
232−
233−-- | Each element scopes over the elements to the right
234−listScopes :: Scope -> [Located a] -> [RScoped (Located a)]
235−listScopes _ [] = []
236−listScopes rhsScope [pat] = [RS rhsScope pat]
237−listScopes rhsScope (pat : pats) = RS sc pat : pats'
238− where
239− pats'@((RS scope p):_) = listScopes rhsScope pats
240− sc = combineScopes scope $ mkScope $ getLoc p
241−
242−-- | 'listScopes' specialised to 'PScoped' things
243−patScopes
244− :: Maybe Span
245− -> Scope
246− -> Scope
247− -> [LPat (GhcPass p)]
248− -> [PScoped (LPat (GhcPass p))]
249−patScopes rsp useScope patScope xs =
250− map (\(RS sc a) -> PS rsp useScope sc (unLoc a)) $
251− listScopes patScope (map dL xs)
252−
253−-- | 'listScopes' specialised to 'TVScoped' things
254−tvScopes
255− :: TyVarScope
256− -> Scope
257− -> [LHsTyVarBndr a]
258− -> [TVScoped (LHsTyVarBndr a)]
259−tvScopes tvScope rhsScope xs =
260− map (\(RS sc a)-> TVS tvScope sc a) $ listScopes rhsScope xs
261−
262−{- Note [Scoping Rules for SigPat]
263−Explicitly quantified variables in pattern type signatures are not
264−brought into scope in the rhs, but implicitly quantified variables
265−are (HsWC and HsIB).
266−This is unlike other signatures, where explicitly quantified variables
267−are brought into the RHS Scope
268−For example
269−foo :: forall a. ...;
270−foo = ... -- a is in scope here
271−
272−bar (x :: forall a. a -> a) = ... -- a is not in scope here
273−-- ^ a is in scope here (pattern body)
274−
275−bax (x :: a) = ... -- a is in scope here
276−Because of HsWC and HsIB pass on their scope to their children
277−we must wrap the LHsType in pattern signatures in a
278−Shielded explictly, so that the HsWC/HsIB scope is not passed
279−on the the LHsType
280−-}
281−
282−data Shielded a = SH Scope a -- Ignores its TScope, uses its own scope instead
283−
284−type family ProtectedSig a where
285− ProtectedSig GhcRn = HsWildCardBndrs GhcRn (HsImplicitBndrs
286− GhcRn
287− (Shielded (LHsType GhcRn)))
288− ProtectedSig GhcTc = NoExt
289−
290−class ProtectSig a where
291− protectSig :: Scope -> LHsSigWcType (NoGhcTc a) -> ProtectedSig a
292−
293−instance (HasLoc a) => HasLoc (Shielded a) where
294− loc (SH _ a) = loc a
295−
296−instance (ToHie (TScoped a)) => ToHie (TScoped (Shielded a)) where
297− toHie (TS _ (SH sc a)) = toHie (TS (ResolvedScopes [sc]) a)
298−
299−instance ProtectSig GhcTc where
300− protectSig _ _ = NoExt
301−
302−instance ProtectSig GhcRn where
303− protectSig sc (HsWC a (HsIB b sig)) =
304− HsWC a (HsIB b (SH sc sig))
305− protectSig _ _ = error "protectSig not given HsWC (HsIB)"
306−
307−class HasLoc a where
308− -- ^ defined so that HsImplicitBndrs and HsWildCardBndrs can
309− -- know what their implicit bindings are scoping over
310− loc :: a -> SrcSpan
311−
312−instance HasLoc thing => HasLoc (TScoped thing) where
313− loc (TS _ a) = loc a
314−
315−instance HasLoc thing => HasLoc (PScoped thing) where
316− loc (PS _ _ _ a) = loc a
317−
318−instance HasLoc (LHsQTyVars GhcRn) where
319− loc (HsQTvs _ vs) = loc vs
320− loc _ = noSrcSpan
321−
322−instance HasLoc thing => HasLoc (HsImplicitBndrs a thing) where
323− loc (HsIB _ a) = loc a
324− loc _ = noSrcSpan
325−
326−instance HasLoc thing => HasLoc (HsWildCardBndrs a thing) where
327− loc (HsWC _ a) = loc a
328− loc _ = noSrcSpan
329−
330−instance HasLoc (Located a) where
331− loc (L l _) = l
332−
333−instance HasLoc a => HasLoc [a] where
334− loc [] = noSrcSpan
335− loc xs = foldl1' combineSrcSpans $ map loc xs
336−
337−instance (HasLoc a, HasLoc b) => HasLoc (FamEqn s a b) where
338− loc (FamEqn _ a Nothing b _ c) = foldl1' combineSrcSpans [loc a, loc b, loc c]
339− loc (FamEqn _ a (Just tvs) b _ c) = foldl1' combineSrcSpans
340− [loc a, loc tvs, loc b, loc c]
341− loc _ = noSrcSpan
342−instance (HasLoc tm, HasLoc ty) => HasLoc (HsArg tm ty) where
343− loc (HsValArg tm) = loc tm
344− loc (HsTypeArg _ ty) = loc ty
345− loc (HsArgPar sp) = sp
346−
347−instance HasLoc (HsDataDefn GhcRn) where
348− loc def@(HsDataDefn{}) = loc $ dd_cons def
349− -- Only used for data family instances, so we only need rhs
350− -- Most probably the rest will be unhelpful anyway
351− loc _ = noSrcSpan
352−
353−instance HasLoc (Pat (GhcPass a)) where
354− loc (dL -> L l _) = l
355−
356−-- | The main worker class
357−class ToHie a where
358− toHie :: a -> HieM [HieAST Type]
359−
360−-- | Used to collect type info
361−class Data a => HasType a where
362− getTypeNode :: a -> HieM [HieAST Type]
363−
364−instance (ToHie a) => ToHie [a] where
365− toHie = concatMapM toHie
366−
367−instance (ToHie a) => ToHie (Bag a) where
368− toHie = toHie . bagToList
369−
370−instance (ToHie a) => ToHie (Maybe a) where
371− toHie = maybe (pure []) toHie
372−
373−instance ToHie (Context (Located NoExt)) where
374− toHie _ = pure []
375−
376−instance ToHie (TScoped NoExt) where
377− toHie _ = pure []
378−
379−instance ToHie (IEContext (Located ModuleName)) where
380− toHie (IEC c (L (RealSrcSpan span) mname)) =
381− pure $ [Node (NodeInfo S.empty [] idents) span []]
382− where details = mempty{identInfo = S.singleton (IEThing c)}
383− idents = M.singleton (Left mname) details
384− toHie _ = pure []
385−
386−instance ToHie (Context (Located Var)) where
387− toHie c = case c of
388− C context (L (RealSrcSpan span) name')
389− -> do
390− m <- asks name_remapping
391− let name = M.findWithDefault name' (varName name') m
392− pure
393− [Node
394− (NodeInfo S.empty [] $
395− M.singleton (Right $ varName name)
396− (IdentifierDetails (Just $ varType name')
397− (S.singleton context)))
398− span
399− []]
400− _ -> pure []
401−
402−instance ToHie (Context (Located Name)) where
403− toHie c = case c of
404− C context (L (RealSrcSpan span) name') -> do
405− m <- asks name_remapping
406− let name = case M.lookup name' m of
407− Just var -> varName var
408− Nothing -> name'
409− pure
410− [Node
411− (NodeInfo S.empty [] $
412− M.singleton (Right name)
413− (IdentifierDetails Nothing
414− (S.singleton context)))
415− span
416− []]
417− _ -> pure []
418−
419−-- | Dummy instances - never called
420−instance ToHie (TScoped (LHsSigWcType GhcTc)) where
421− toHie _ = pure []
422−instance ToHie (TScoped (LHsWcType GhcTc)) where
423− toHie _ = pure []
424−instance ToHie (SigContext (LSig GhcTc)) where
425− toHie _ = pure []
426−instance ToHie (TScoped Type) where
427− toHie _ = pure []
428−
429−instance HasType (LHsBind GhcRn) where
430− getTypeNode (L spn bind) = makeNode bind spn
431−
432−instance HasType (LHsBind GhcTc) where
433− getTypeNode (L spn bind) = case bind of
434− FunBind{fun_id = name} -> makeTypeNode bind spn (varType $ unLoc name)
435− _ -> makeNode bind spn
436−
437−instance HasType (LPat GhcRn) where
438− getTypeNode (dL -> L spn pat) = makeNode pat spn
439−
440−instance HasType (LPat GhcTc) where
441− getTypeNode (dL -> L spn opat) = makeTypeNode opat spn (hsPatType opat)
442−
443−instance HasType (LHsExpr GhcRn) where
444− getTypeNode (L spn e) = makeNode e spn
445−
446−-- | This instance tries to construct 'HieAST' nodes which include the type of
447−-- the expression. It is not yet possible to do this efficiently for all
448−-- expression forms, so we skip filling in the type for those inputs.
449−--
450−-- 'HsApp', for example, doesn't have any type information available directly on
451−-- the node. Our next recourse would be to desugar it into a 'CoreExpr' then
452−-- query the type of that. Yet both the desugaring call and the type query both
453−-- involve recursive calls to the function and argument! This is particularly
454−-- problematic when you realize that the HIE traversal will eventually visit
455−-- those nodes too and ask for their types again.
456−--
457−-- Since the above is quite costly, we just skip cases where computing the
458−-- expression's type is going to be expensive.
459−--
460−-- See #16233
461−instance HasType (LHsExpr GhcTc) where
462− getTypeNode e@(L spn e') = lift $
463− -- Some expression forms have their type immediately available
464− let tyOpt = case e' of
465− HsLit _ l -> Just (hsLitType l)
466− HsOverLit _ o -> Just (overLitType o)
467−
468− HsLam _ (MG { mg_ext = groupTy }) -> Just (matchGroupType groupTy)
469− HsLamCase _ (MG { mg_ext = groupTy }) -> Just (matchGroupType groupTy)
470− HsCase _ _ (MG { mg_ext = groupTy }) -> Just (mg_res_ty groupTy)
471−
472− ExplicitList ty _ _ -> Just (mkListTy ty)
473− ExplicitSum ty _ _ _ -> Just (mkSumTy ty)
474− HsDo ty _ _ -> Just ty
475− HsMultiIf ty _ -> Just ty
476−
477− _ -> Nothing
478−
479− in
480− case tyOpt of
481− _ | skipDesugaring e' -> fallback
482− | otherwise -> do
483− hs_env <- Hsc $ \e w -> return (e,w)
484− (_,mbe) <- liftIO $ deSugarExpr hs_env e
485− maybe fallback (makeTypeNode e' spn . exprType) mbe
486− where
487− fallback = makeNode e' spn
488−
489− matchGroupType :: MatchGroupTc -> Type
490− matchGroupType (MatchGroupTc args res) = mkFunTys args res
491−
492− -- | Skip desugaring of these expressions for performance reasons.
493− --
494− -- See impact on Haddock output (esp. missing type annotations or links)
495− -- before marking more things here as 'False'. See impact on Haddock
496− -- performance before marking more things as 'True'.
497− skipDesugaring :: HsExpr a -> Bool
498− skipDesugaring e = case e of
499− HsVar{} -> False
500− HsUnboundVar{} -> False
501− HsConLikeOut{} -> False
502− HsRecFld{} -> False
503− HsOverLabel{} -> False
504− HsIPVar{} -> False
505− HsWrap{} -> False
506− _ -> True
507−
508−instance ( ToHie (Context (Located (IdP a)))
509− , ToHie (MatchGroup a (LHsExpr a))
510− , ToHie (PScoped (LPat a))
511− , ToHie (GRHSs a (LHsExpr a))
512− , ToHie (LHsExpr a)
513− , ToHie (Located (PatSynBind a a))
514− , HasType (LHsBind a)
515− , ModifyState (IdP a)
516− , Data (HsBind a)
517− ) => ToHie (BindContext (LHsBind a)) where
518− toHie (BC context scope b@(L span bind)) =
519− concatM $ getTypeNode b : case bind of
520− FunBind{fun_id = name, fun_matches = matches} ->
521− [ toHie $ C (ValBind context scope $ getRealSpan span) name
522− , toHie matches
523− ]
524− PatBind{pat_lhs = lhs, pat_rhs = rhs} ->
525− [ toHie $ PS (getRealSpan span) scope NoScope lhs
526− , toHie rhs
527− ]
528− VarBind{var_rhs = expr} ->
529− [ toHie expr
530− ]
531− AbsBinds{abs_exports = xs, abs_binds = binds} ->
532− [ local (modifyState xs) $ -- Note [Name Remapping]
533− toHie $ fmap (BC context scope) binds
534− ]
535− PatSynBind _ psb ->
536− [ toHie $ L span psb -- PatSynBinds only occur at the top level
537− ]
538− XHsBindsLR _ -> []
539−
540−instance ( ToHie (LMatch a body)
541− ) => ToHie (MatchGroup a body) where
542− toHie mg = concatM $ case mg of
543− MG{ mg_alts = (L span alts) , mg_origin = FromSource } ->
544− [ pure $ locOnly span
545− , toHie alts
546− ]
547− MG{} -> []
548− XMatchGroup _ -> []
549−
550−instance ( ToHie (Context (Located (IdP a)))
551− , ToHie (PScoped (LPat a))
552− , ToHie (HsPatSynDir a)
553− ) => ToHie (Located (PatSynBind a a)) where
554− toHie (L sp psb) = concatM $ case psb of
555− PSB{psb_id=var, psb_args=dets, psb_def=pat, psb_dir=dir} ->
556− [ toHie $ C (Decl PatSynDec $ getRealSpan sp) var
557− , toHie $ toBind dets
558− , toHie $ PS Nothing lhsScope NoScope pat
559− , toHie dir
560− ]
561− where
562− lhsScope = combineScopes varScope detScope
563− varScope = mkLScope var
564− detScope = case dets of
565− (PrefixCon args) -> foldr combineScopes NoScope $ map mkLScope args
566− (InfixCon a b) -> combineScopes (mkLScope a) (mkLScope b)
567− (RecCon r) -> foldr go NoScope r
568− go (RecordPatSynField a b) c = combineScopes c
569− $ combineScopes (mkLScope a) (mkLScope b)
570− detSpan = case detScope of
571− LocalScope a -> Just a
572− _ -> Nothing
573− toBind (PrefixCon args) = PrefixCon $ map (C Use) args
574− toBind (InfixCon a b) = InfixCon (C Use a) (C Use b)
575− toBind (RecCon r) = RecCon $ map (PSC detSpan) r
576− XPatSynBind _ -> []
577−
578−instance ( ToHie (MatchGroup a (LHsExpr a))
579− ) => ToHie (HsPatSynDir a) where
580− toHie dir = case dir of
581− ExplicitBidirectional mg -> toHie mg
582− _ -> pure []
583−
584−instance ( a ~ GhcPass p
585− , ToHie body
586− , ToHie (HsMatchContext (NameOrRdrName (IdP a)))
587− , ToHie (PScoped (LPat a))
588− , ToHie (GRHSs a body)
589− , Data (Match a body)
590− ) => ToHie (LMatch (GhcPass p) body) where
591− toHie (L span m ) = concatM $ makeNode m span : case m of
592− Match{m_ctxt=mctx, m_pats = pats, m_grhss = grhss } ->
593− [ toHie mctx
594− , let rhsScope = mkScope $ grhss_span grhss
595− in toHie $ patScopes Nothing rhsScope NoScope pats
596− , toHie grhss
597− ]
598− XMatch _ -> []
599−
600−instance ( ToHie (Context (Located a))
601− ) => ToHie (HsMatchContext a) where
602− toHie (FunRhs{mc_fun=name}) = toHie $ C MatchBind name
603− toHie (StmtCtxt a) = toHie a
604− toHie _ = pure []
605−
606−instance ( ToHie (HsMatchContext a)
607− ) => ToHie (HsStmtContext a) where
608− toHie (PatGuard a) = toHie a
609− toHie (ParStmtCtxt a) = toHie a
610− toHie (TransStmtCtxt a) = toHie a
611− toHie _ = pure []
612−
613−instance ( a ~ GhcPass p
614− , ToHie (Context (Located (IdP a)))
615− , ToHie (RContext (HsRecFields a (PScoped (LPat a))))
616− , ToHie (LHsExpr a)
617− , ToHie (TScoped (LHsSigWcType a))
618− , ProtectSig a
619− , ToHie (TScoped (ProtectedSig a))
620− , HasType (LPat a)
621− , Data (HsSplice a)
622− ) => ToHie (PScoped (LPat (GhcPass p))) where
623− toHie (PS rsp scope pscope lpat@(dL -> L ospan opat)) =
624− concatM $ getTypeNode lpat : case opat of
625− WildPat _ ->
626− []
627− VarPat _ lname ->
628− [ toHie $ C (PatternBind scope pscope rsp) lname
629− ]
630− LazyPat _ p ->
631− [ toHie $ PS rsp scope pscope p
632− ]
633− AsPat _ lname pat ->
634− [ toHie $ C (PatternBind scope
635− (combineScopes (mkLScope (dL pat)) pscope)
636− rsp)
637− lname
638− , toHie $ PS rsp scope pscope pat
639− ]
640− ParPat _ pat ->
641− [ toHie $ PS rsp scope pscope pat
642− ]
643− BangPat _ pat ->
644− [ toHie $ PS rsp scope pscope pat
645− ]
646− ListPat _ pats ->
647− [ toHie $ patScopes rsp scope pscope pats
648− ]
649− TuplePat _ pats _ ->
650− [ toHie $ patScopes rsp scope pscope pats
651− ]
652− SumPat _ pat _ _ ->
653− [ toHie $ PS rsp scope pscope pat
654− ]
655− ConPatIn c dets ->
656− [ toHie $ C Use c
657− , toHie $ contextify dets
658− ]
659− ConPatOut {pat_con = con, pat_args = dets}->
660− [ toHie $ C Use $ fmap conLikeName con
661− , toHie $ contextify dets
662− ]
663− ViewPat _ expr pat ->
664− [ toHie expr
665− , toHie $ PS rsp scope pscope pat
666− ]
667− SplicePat _ sp ->
668− [ toHie $ L ospan sp
669− ]
670− LitPat _ _ ->
671− []
672− NPat _ _ _ _ ->
673− []
674− NPlusKPat _ n _ _ _ _ ->
675− [ toHie $ C (PatternBind scope pscope rsp) n
676− ]
677− SigPat _ pat sig ->
678− [ toHie $ PS rsp scope pscope pat
679− , let cscope = mkLScope (dL pat) in
680− toHie $ TS (ResolvedScopes [cscope, scope, pscope])
681− (protectSig @a cscope sig)
682− -- See Note [Scoping Rules for SigPat]
683− ]
684− CoPat _ _ _ _ ->
685− []
686− XPat _ -> []
687− where
688− contextify (PrefixCon args) = PrefixCon $ patScopes rsp scope pscope args
689− contextify (InfixCon a b) = InfixCon a' b'
690− where [a', b'] = patScopes rsp scope pscope [a,b]
691− contextify (RecCon r) = RecCon $ RC RecFieldMatch $ contextify_rec r
692− contextify_rec (HsRecFields fds a) = HsRecFields (map go scoped_fds) a
693− where
694− go (RS fscope (L spn (HsRecField lbl pat pun))) =
695− L spn $ HsRecField lbl (PS rsp scope fscope pat) pun
696− scoped_fds = listScopes pscope fds
697−
698−instance ( ToHie body
699− , ToHie (LGRHS a body)
700− , ToHie (RScoped (LHsLocalBinds a))
701− ) => ToHie (GRHSs a body) where
702− toHie grhs = concatM $ case grhs of
703− GRHSs _ grhss binds ->
704− [ toHie grhss
705− , toHie $ RS (mkScope $ grhss_span grhs) binds
706− ]
707− XGRHSs _ -> []
708−
709−instance ( ToHie (Located body)
710− , ToHie (RScoped (GuardLStmt a))
711− , Data (GRHS a (Located body))
712− ) => ToHie (LGRHS a (Located body)) where
713− toHie (L span g) = concatM $ makeNode g span : case g of
714− GRHS _ guards body ->
715− [ toHie $ listScopes (mkLScope body) guards
716− , toHie body
717− ]
718− XGRHS _ -> []
719−
720−instance ( a ~ GhcPass p
721− , ToHie (Context (Located (IdP a)))
722− , HasType (LHsExpr a)
723− , ToHie (PScoped (LPat a))
724− , ToHie (MatchGroup a (LHsExpr a))
725− , ToHie (LGRHS a (LHsExpr a))
726− , ToHie (RContext (HsRecordBinds a))
727− , ToHie (RFContext (Located (AmbiguousFieldOcc a)))
728− , ToHie (ArithSeqInfo a)
729− , ToHie (LHsCmdTop a)
730− , ToHie (RScoped (GuardLStmt a))
731− , ToHie (RScoped (LHsLocalBinds a))
732− , ToHie (TScoped (LHsWcType (NoGhcTc a)))
733− , ToHie (TScoped (LHsSigWcType (NoGhcTc a)))
734− , Data (HsExpr a)
735− , Data (HsSplice a)
736− , Data (HsTupArg a)
737− , Data (AmbiguousFieldOcc a)
738− ) => ToHie (LHsExpr (GhcPass p)) where
739− toHie e@(L mspan oexpr) = concatM $ getTypeNode e : case oexpr of
740− HsVar _ (L _ var) ->
741− [ toHie $ C Use (L mspan var)
742− -- Patch up var location since typechecker removes it
743− ]
744− HsUnboundVar _ _ ->
745− []
746− HsConLikeOut _ con ->
747− [ toHie $ C Use $ L mspan $ conLikeName con
748− ]
749− HsRecFld _ fld ->
750− [ toHie $ RFC RecFieldOcc Nothing (L mspan fld)
751− ]
752− HsOverLabel _ _ _ -> []
753− HsIPVar _ _ -> []
754− HsOverLit _ _ -> []
755− HsLit _ _ -> []
756− HsLam _ mg ->
757− [ toHie mg
758− ]
759− HsLamCase _ mg ->
760− [ toHie mg
761− ]
762− HsApp _ a b ->
763− [ toHie a
764− , toHie b
765− ]
766− HsAppType _ expr sig ->
767− [ toHie expr
768− , toHie $ TS (ResolvedScopes []) sig
769− ]
770− OpApp _ a b c ->
771− [ toHie a
772− , toHie b
773− , toHie c
774− ]
775− NegApp _ a _ ->
776− [ toHie a
777− ]
778− HsPar _ a ->
779− [ toHie a
780− ]
781− SectionL _ a b ->
782− [ toHie a
783− , toHie b
784− ]
785− SectionR _ a b ->
786− [ toHie a
787− , toHie b
788− ]
789− ExplicitTuple _ args _ ->
790− [ toHie args
791− ]
792− ExplicitSum _ _ _ expr ->
793− [ toHie expr
794− ]
795− HsCase _ expr matches ->
796− [ toHie expr
797− , toHie matches
798− ]
799− HsIf _ _ a b c ->
800− [ toHie a
801− , toHie b
802− , toHie c
803− ]
804− HsMultiIf _ grhss ->
805− [ toHie grhss
806− ]
807− HsLet _ binds expr ->
808− [ toHie $ RS (mkLScope expr) binds
809− , toHie expr
810− ]
811− HsDo _ _ (L ispan stmts) ->
812− [ pure $ locOnly ispan
813− , toHie $ listScopes NoScope stmts
814− ]
815− ExplicitList _ _ exprs ->
816− [ toHie exprs
817− ]
818− RecordCon {rcon_con_name = name, rcon_flds = binds}->
819− [ toHie $ C Use name
820− , toHie $ RC RecFieldAssign $ binds
821− ]
822− RecordUpd {rupd_expr = expr, rupd_flds = upds}->
823− [ toHie expr
824− , toHie $ map (RC RecFieldAssign) upds
825− ]
826− ExprWithTySig _ expr sig ->
827− [ toHie expr
828− , toHie $ TS (ResolvedScopes [mkLScope expr]) sig
829− ]
830− ArithSeq _ _ info ->
831− [ toHie info
832− ]
833− HsSCC _ _ _ expr ->
834− [ toHie expr
835− ]
836− HsCoreAnn _ _ _ expr ->
837− [ toHie expr
838− ]
839− HsProc _ pat cmdtop ->
840− [ toHie $ PS Nothing (mkLScope cmdtop) NoScope pat
841− , toHie cmdtop
842− ]
843− HsStatic _ expr ->
844− [ toHie expr
845− ]
846− HsArrApp _ a b _ _ ->
847− [ toHie a
848− , toHie b
849− ]
850− HsArrForm _ expr _ cmds ->
851− [ toHie expr
852− , toHie cmds
853− ]
854− HsTick _ _ expr ->
855− [ toHie expr
856− ]
857− HsBinTick _ _ _ expr ->
858− [ toHie expr
859− ]
860− HsTickPragma _ _ _ _ expr ->
861− [ toHie expr
862− ]
863− HsWrap _ _ a ->
864− [ toHie $ L mspan a
865− ]
866− HsBracket _ b ->
867− [ toHie b
868− ]
869− HsRnBracketOut _ b p ->
870− [ toHie b
871− , toHie p
872− ]
873− HsTcBracketOut _ b p ->
874− [ toHie b
875− , toHie p
876− ]
877− HsSpliceE _ x ->
878− [ toHie $ L mspan x
879− ]
880− EWildPat _ -> []
881− EAsPat _ a b ->
882− [ toHie $ C Use a
883− , toHie b
884− ]
885− EViewPat _ a b ->
886− [ toHie a
887− , toHie b
888− ]
889− ELazyPat _ a ->
890− [ toHie a
891− ]
892− XExpr _ -> []
893−
894−instance ( a ~ GhcPass p
895− , ToHie (LHsExpr a)
896− , Data (HsTupArg a)
897− ) => ToHie (LHsTupArg (GhcPass p)) where
898− toHie (L span arg) = concatM $ makeNode arg span : case arg of
899− Present _ expr ->
900− [ toHie expr
901− ]
902− Missing _ -> []
903− XTupArg _ -> []
904−
905−instance ( a ~ GhcPass p
906− , ToHie (PScoped (LPat a))
907− , ToHie (LHsExpr a)
908− , ToHie (SigContext (LSig a))
909− , ToHie (RScoped (LHsLocalBinds a))
910− , ToHie (RScoped (ApplicativeArg a))
911− , ToHie (Located body)
912− , Data (StmtLR a a (Located body))
913− , Data (StmtLR a a (Located (HsExpr a)))
914− ) => ToHie (RScoped (LStmt (GhcPass p) (Located body))) where
915− toHie (RS scope (L span stmt)) = concatM $ makeNode stmt span : case stmt of
916− LastStmt _ body _ _ ->
917− [ toHie body
918− ]
919− BindStmt _ pat body _ _ ->
920− [ toHie $ PS (getRealSpan $ getLoc body) scope NoScope pat
921− , toHie body
922− ]
923− ApplicativeStmt _ stmts _ ->
924− [ concatMapM (toHie . RS scope . snd) stmts
925− ]
926− BodyStmt _ body _ _ ->
927− [ toHie body
928− ]
929− LetStmt _ binds ->
930− [ toHie $ RS scope binds
931− ]
932− ParStmt _ parstmts _ _ ->
933− [ concatMapM (\(ParStmtBlock _ stmts _ _) ->
934− toHie $ listScopes NoScope stmts)
935− parstmts
936− ]
937− TransStmt {trS_stmts = stmts, trS_using = using, trS_by = by} ->
938− [ toHie $ listScopes scope stmts
939− , toHie using
940− , toHie by
941− ]
942− RecStmt {recS_stmts = stmts} ->
943− [ toHie $ map (RS $ combineScopes scope (mkScope span)) stmts
944− ]
945− XStmtLR _ -> []
946−
947−instance ( ToHie (LHsExpr a)
948− , ToHie (PScoped (LPat a))
949− , ToHie (BindContext (LHsBind a))
950− , ToHie (SigContext (LSig a))
951− , ToHie (RScoped (HsValBindsLR a a))
952− , Data (HsLocalBinds a)
953− ) => ToHie (RScoped (LHsLocalBinds a)) where
954− toHie (RS scope (L sp binds)) = concatM $ makeNode binds sp : case binds of
955− EmptyLocalBinds _ -> []
956− HsIPBinds _ _ -> []
957− HsValBinds _ valBinds ->
958− [ toHie $ RS (combineScopes scope $ mkScope sp)
959− valBinds
960− ]
961− XHsLocalBindsLR _ -> []
962−
963−instance ( ToHie (BindContext (LHsBind a))
964− , ToHie (SigContext (LSig a))
965− , ToHie (RScoped (XXValBindsLR a a))
966− ) => ToHie (RScoped (HsValBindsLR a a)) where
967− toHie (RS sc v) = concatM $ case v of
968− ValBinds _ binds sigs ->
969− [ toHie $ fmap (BC RegularBind sc) binds
970− , toHie $ fmap (SC (SI BindSig Nothing)) sigs
971− ]
972− XValBindsLR x -> [ toHie $ RS sc x ]
973−
974−instance ToHie (RScoped (NHsValBindsLR GhcTc)) where
975− toHie (RS sc (NValBinds binds sigs)) = concatM $
976− [ toHie (concatMap (map (BC RegularBind sc) . bagToList . snd) binds)
977− , toHie $ fmap (SC (SI BindSig Nothing)) sigs
978− ]
979−instance ToHie (RScoped (NHsValBindsLR GhcRn)) where
980− toHie (RS sc (NValBinds binds sigs)) = concatM $
981− [ toHie (concatMap (map (BC RegularBind sc) . bagToList . snd) binds)
982− , toHie $ fmap (SC (SI BindSig Nothing)) sigs
983− ]
984−
985−instance ( ToHie (RContext (LHsRecField a arg))
986− ) => ToHie (RContext (HsRecFields a arg)) where
987− toHie (RC c (HsRecFields fields _)) = toHie $ map (RC c) fields
988−
989−instance ( ToHie (RFContext (Located label))
990− , ToHie arg
991− , HasLoc arg
992− , Data label
993− , Data arg
994− ) => ToHie (RContext (LHsRecField' label arg)) where
995− toHie (RC c (L span recfld)) = concatM $ makeNode recfld span : case recfld of
996− HsRecField label expr _ ->
997− [ toHie $ RFC c (getRealSpan $ loc expr) label
998− , toHie expr
999− ]
1000−
1001−removeDefSrcSpan :: Name -> Name
1002−removeDefSrcSpan n = setNameLoc n noSrcSpan
1003−
1004−instance ToHie (RFContext (LFieldOcc GhcRn)) where
1005− toHie (RFC c rhs (L nspan f)) = concatM $ case f of
1006− FieldOcc name _ ->
1007− [ toHie $ C (RecField c rhs) (L nspan $ removeDefSrcSpan name)
1008− ]
1009− XFieldOcc _ -> []
1010−
1011−instance ToHie (RFContext (LFieldOcc GhcTc)) where
1012− toHie (RFC c rhs (L nspan f)) = concatM $ case f of
1013− FieldOcc var _ ->
1014− let var' = setVarName var (removeDefSrcSpan $ varName var)
1015− in [ toHie $ C (RecField c rhs) (L nspan var')
1016− ]
1017− XFieldOcc _ -> []
1018−
1019−instance ToHie (RFContext (Located (AmbiguousFieldOcc GhcRn))) where
1020− toHie (RFC c rhs (L nspan afo)) = concatM $ case afo of
1021− Unambiguous name _ ->
1022− [ toHie $ C (RecField c rhs) $ L nspan $ removeDefSrcSpan name
1023− ]
1024− Ambiguous _name _ ->
1025− [ ]
1026− XAmbiguousFieldOcc _ -> []
1027−
1028−instance ToHie (RFContext (Located (AmbiguousFieldOcc GhcTc))) where
1029− toHie (RFC c rhs (L nspan afo)) = concatM $ case afo of
1030− Unambiguous var _ ->
1031− let var' = setVarName var (removeDefSrcSpan $ varName var)
1032− in [ toHie $ C (RecField c rhs) (L nspan var')
1033− ]
1034− Ambiguous var _ ->
1035− let var' = setVarName var (removeDefSrcSpan $ varName var)
1036− in [ toHie $ C (RecField c rhs) (L nspan var')
1037− ]
1038− XAmbiguousFieldOcc _ -> []
1039−
1040−instance ( a ~ GhcPass p
1041− , ToHie (PScoped (LPat a))
1042− , ToHie (BindContext (LHsBind a))
1043− , ToHie (LHsExpr a)
1044− , ToHie (SigContext (LSig a))
1045− , ToHie (RScoped (HsValBindsLR a a))
1046− , Data (StmtLR a a (Located (HsExpr a)))
1047− , Data (HsLocalBinds a)
1048− ) => ToHie (RScoped (ApplicativeArg (GhcPass p))) where
1049− toHie (RS sc (ApplicativeArgOne _ pat expr _)) = concatM
1050− [ toHie $ PS Nothing sc NoScope pat
1051− , toHie expr
1052− ]
1053− toHie (RS sc (ApplicativeArgMany _ stmts _ pat)) = concatM
1054− [ toHie $ listScopes NoScope stmts
1055− , toHie $ PS Nothing sc NoScope pat
1056− ]
1057− toHie (RS _ (XApplicativeArg _)) = pure []
1058−
1059−instance (ToHie arg, ToHie rec) => ToHie (HsConDetails arg rec) where
1060− toHie (PrefixCon args) = toHie args
1061− toHie (RecCon rec) = toHie rec
1062− toHie (InfixCon a b) = concatM [ toHie a, toHie b]
1063−
1064−instance ( ToHie (LHsCmd a)
1065− , Data (HsCmdTop a)
1066− ) => ToHie (LHsCmdTop a) where
1067− toHie (L span top) = concatM $ makeNode top span : case top of
1068− HsCmdTop _ cmd ->
1069− [ toHie cmd
1070− ]
1071− XCmdTop _ -> []
1072−
1073−instance ( a ~ GhcPass p
1074− , ToHie (PScoped (LPat a))
1075− , ToHie (BindContext (LHsBind a))
1076− , ToHie (LHsExpr a)
1077− , ToHie (MatchGroup a (LHsCmd a))
1078− , ToHie (SigContext (LSig a))
1079− , ToHie (RScoped (HsValBindsLR a a))
1080− , Data (HsCmd a)
1081− , Data (HsCmdTop a)
1082− , Data (StmtLR a a (Located (HsCmd a)))
1083− , Data (HsLocalBinds a)
1084− , Data (StmtLR a a (Located (HsExpr a)))
1085− ) => ToHie (LHsCmd (GhcPass p)) where
1086− toHie (L span cmd) = concatM $ makeNode cmd span : case cmd of
1087− HsCmdArrApp _ a b _ _ ->
1088− [ toHie a
1089− , toHie b
1090− ]
1091− HsCmdArrForm _ a _ _ cmdtops ->
1092− [ toHie a
1093− , toHie cmdtops
1094− ]
1095− HsCmdApp _ a b ->
1096− [ toHie a
1097− , toHie b
1098− ]
1099− HsCmdLam _ mg ->
1100− [ toHie mg
1101− ]
1102− HsCmdPar _ a ->
1103− [ toHie a
1104− ]
1105− HsCmdCase _ expr alts ->
1106− [ toHie expr
1107− , toHie alts
1108− ]
1109− HsCmdIf _ _ a b c ->
1110− [ toHie a
1111− , toHie b
1112− , toHie c
1113− ]
1114− HsCmdLet _ binds cmd' ->
1115− [ toHie $ RS (mkLScope cmd') binds
1116− , toHie cmd'
1117− ]
1118− HsCmdDo _ (L ispan stmts) ->
1119− [ pure $ locOnly ispan
1120− , toHie $ listScopes NoScope stmts
1121− ]
1122− HsCmdWrap _ _ _ -> []
1123− XCmd _ -> []
1124−
1125−instance ToHie (TyClGroup GhcRn) where
1126− toHie (TyClGroup _ classes roles instances) = concatM
1127− [ toHie classes
1128− , toHie roles
1129− , toHie instances
1130− ]
1131− toHie (XTyClGroup _) = pure []
1132−
1133−instance ToHie (LTyClDecl GhcRn) where
1134− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1135− FamDecl {tcdFam = fdecl} ->
1136− [ toHie (L span fdecl)
1137− ]
1138− SynDecl {tcdLName = name, tcdTyVars = vars, tcdRhs = typ} ->
1139− [ toHie $ C (Decl SynDec $ getRealSpan span) name
1140− , toHie $ TS (ResolvedScopes [mkScope $ getLoc typ]) vars
1141− , toHie typ
1142− ]
1143− DataDecl {tcdLName = name, tcdTyVars = vars, tcdDataDefn = defn} ->
1144− [ toHie $ C (Decl DataDec $ getRealSpan span) name
1145− , toHie $ TS (ResolvedScopes [quant_scope, rhs_scope]) vars
1146− , toHie defn
1147− ]
1148− where
1149− quant_scope = mkLScope $ dd_ctxt defn
1150− rhs_scope = sig_sc `combineScopes` con_sc `combineScopes` deriv_sc
1151− sig_sc = maybe NoScope mkLScope $ dd_kindSig defn
1152− con_sc = foldr combineScopes NoScope $ map mkLScope $ dd_cons defn
1153− deriv_sc = mkLScope $ dd_derivs defn
1154− ClassDecl { tcdCtxt = context
1155− , tcdLName = name
1156− , tcdTyVars = vars
1157− , tcdFDs = deps
1158− , tcdSigs = sigs
1159− , tcdMeths = meths
1160− , tcdATs = typs
1161− , tcdATDefs = deftyps
1162− } ->
1163− [ toHie $ C (Decl ClassDec $ getRealSpan span) name
1164− , toHie context
1165− , toHie $ TS (ResolvedScopes [context_scope, rhs_scope]) vars
1166− , toHie deps
1167− , toHie $ map (SC $ SI ClassSig $ getRealSpan span) sigs
1168− , toHie $ fmap (BC InstanceBind ModuleScope) meths
1169− , toHie typs
1170− , concatMapM (pure . locOnly . getLoc) deftyps
1171− , toHie $ map (go . unLoc) deftyps
1172− ]
1173− where
1174− context_scope = mkLScope context
1175− rhs_scope = foldl1' combineScopes $ map mkScope
1176− [ loc deps, loc sigs, loc (bagToList meths), loc typs, loc deftyps]
1177−
1178− go :: TyFamDefltEqn GhcRn
1179− -> FamEqn GhcRn (TScoped (LHsQTyVars GhcRn)) (LHsType GhcRn)
1180− go (FamEqn a var bndrs pat b rhs) =
1181− FamEqn a var bndrs (TS (ResolvedScopes [mkLScope rhs]) pat) b rhs
1182− go (XFamEqn NoExt) = XFamEqn NoExt
1183− XTyClDecl _ -> []
1184−
1185−instance ToHie (LFamilyDecl GhcRn) where
1186− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1187− FamilyDecl _ info name vars _ sig inj ->
1188− [ toHie $ C (Decl FamDec $ getRealSpan span) name
1189− , toHie $ TS (ResolvedScopes [rhsSpan]) vars
1190− , toHie info
1191− , toHie $ RS injSpan sig
1192− , toHie inj
1193− ]
1194− where
1195− rhsSpan = sigSpan `combineScopes` injSpan
1196− sigSpan = mkScope $ getLoc sig
1197− injSpan = maybe NoScope (mkScope . getLoc) inj
1198− XFamilyDecl _ -> []
1199−
1200−instance ToHie (FamilyInfo GhcRn) where
1201− toHie (ClosedTypeFamily (Just eqns)) = concatM $
1202− [ concatMapM (pure . locOnly . getLoc) eqns
1203− , toHie $ map go eqns
1204− ]
1205− where
1206− go (L l ib) = TS (ResolvedScopes [mkScope l]) ib
1207− toHie _ = pure []
1208−
1209−instance ToHie (RScoped (LFamilyResultSig GhcRn)) where
1210− toHie (RS sc (L span sig)) = concatM $ makeNode sig span : case sig of
1211− NoSig _ ->
1212− []
1213− KindSig _ k ->
1214− [ toHie k
1215− ]
1216− TyVarSig _ bndr ->
1217− [ toHie $ TVS (ResolvedScopes [sc]) NoScope bndr
1218− ]
1219− XFamilyResultSig _ -> []
1220−
1221−instance ToHie (Located (FunDep (Located Name))) where
1222− toHie (L span fd@(lhs, rhs)) = concatM $
1223− [ makeNode fd span
1224− , toHie $ map (C Use) lhs
1225− , toHie $ map (C Use) rhs
1226− ]
1227−
1228−instance (ToHie pats, ToHie rhs, HasLoc pats, HasLoc rhs)
1229− => ToHie (TScoped (FamEqn GhcRn pats rhs)) where
1230− toHie (TS _ f) = toHie f
1231−
1232−instance ( ToHie pats
1233− , ToHie rhs
1234− , HasLoc pats
1235− , HasLoc rhs
1236− ) => ToHie (FamEqn GhcRn pats rhs) where
1237− toHie fe@(FamEqn _ var tybndrs pats _ rhs) = concatM $
1238− [ toHie $ C (Decl InstDec $ getRealSpan $ loc fe) var
1239− , toHie $ fmap (tvScopes (ResolvedScopes []) scope) tybndrs
1240− , toHie pats
1241− , toHie rhs
1242− ]
1243− where scope = combineScopes patsScope rhsScope
1244− patsScope = mkScope (loc pats)
1245− rhsScope = mkScope (loc rhs)
1246− toHie (XFamEqn _) = pure []
1247−
1248−instance ToHie (LInjectivityAnn GhcRn) where
1249− toHie (L span ann) = concatM $ makeNode ann span : case ann of
1250− InjectivityAnn lhs rhs ->
1251− [ toHie $ C Use lhs
1252− , toHie $ map (C Use) rhs
1253− ]
1254−
1255−instance ToHie (HsDataDefn GhcRn) where
1256− toHie (HsDataDefn _ _ ctx _ mkind cons derivs) = concatM
1257− [ toHie ctx
1258− , toHie mkind
1259− , toHie cons
1260− , toHie derivs
1261− ]
1262− toHie (XHsDataDefn _) = pure []
1263−
1264−instance ToHie (HsDeriving GhcRn) where
1265− toHie (L span clauses) = concatM
1266− [ pure $ locOnly span
1267− , toHie clauses
1268− ]
1269−
1270−instance ToHie (LHsDerivingClause GhcRn) where
1271− toHie (L span cl) = concatM $ makeNode cl span : case cl of
1272− HsDerivingClause _ strat (L ispan tys) ->
1273− [ toHie strat
1274− , pure $ locOnly ispan
1275− , toHie $ map (TS (ResolvedScopes [])) tys
1276− ]
1277− XHsDerivingClause _ -> []
1278−
1279−instance ToHie (Located (DerivStrategy GhcRn)) where
1280− toHie (L span strat) = concatM $ makeNode strat span : case strat of
1281− StockStrategy -> []
1282− AnyclassStrategy -> []
1283− NewtypeStrategy -> []
1284− ViaStrategy s -> [ toHie $ TS (ResolvedScopes []) s ]
1285−
1286−instance ToHie (Located OverlapMode) where
1287− toHie (L span _) = pure $ locOnly span
1288−
1289−instance ToHie (LConDecl GhcRn) where
1290− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1291− ConDeclGADT { con_names = names, con_qvars = qvars
1292− , con_mb_cxt = ctx, con_args = args, con_res_ty = typ } ->
1293− [ toHie $ map (C (Decl ConDec $ getRealSpan span)) names
1294− , toHie $ TS (ResolvedScopes [ctxScope, rhsScope]) qvars
1295− , toHie ctx
1296− , toHie args
1297− , toHie typ
1298− ]
1299− where
1300− rhsScope = combineScopes argsScope tyScope
1301− ctxScope = maybe NoScope mkLScope ctx
1302− argsScope = condecl_scope args
1303− tyScope = mkLScope typ
1304− ConDeclH98 { con_name = name, con_ex_tvs = qvars
1305− , con_mb_cxt = ctx, con_args = dets } ->
1306− [ toHie $ C (Decl ConDec $ getRealSpan span) name
1307− , toHie $ tvScopes (ResolvedScopes []) rhsScope qvars
1308− , toHie ctx
1309− , toHie dets
1310− ]
1311− where
1312− rhsScope = combineScopes ctxScope argsScope
1313− ctxScope = maybe NoScope mkLScope ctx
1314− argsScope = condecl_scope dets
1315− XConDecl _ -> []
1316− where condecl_scope args = case args of
1317− PrefixCon xs -> foldr combineScopes NoScope $ map mkLScope xs
1318− InfixCon a b -> combineScopes (mkLScope a) (mkLScope b)
1319− RecCon x -> mkLScope x
1320−
1321−instance ToHie (Located [LConDeclField GhcRn]) where
1322− toHie (L span decls) = concatM $
1323− [ pure $ locOnly span
1324− , toHie decls
1325− ]
1326−
1327−instance ( HasLoc thing
1328− , ToHie (TScoped thing)
1329− ) => ToHie (TScoped (HsImplicitBndrs GhcRn thing)) where
1330− toHie (TS sc (HsIB ibrn a)) = concatM $
1331− [ pure $ bindingsOnly $ map (C $ TyVarBind (mkScope span) sc) ibrn
1332− , toHie $ TS sc a
1333− ]
1334− where span = loc a
1335− toHie (TS _ (XHsImplicitBndrs _)) = pure []
1336−
1337−instance ( HasLoc thing
1338− , ToHie (TScoped thing)
1339− ) => ToHie (TScoped (HsWildCardBndrs GhcRn thing)) where
1340− toHie (TS sc (HsWC names a)) = concatM $
1341− [ pure $ bindingsOnly $ map (C $ TyVarBind (mkScope span) sc) names
1342− , toHie $ TS sc a
1343− ]
1344− where span = loc a
1345− toHie (TS _ (XHsWildCardBndrs _)) = pure []
1346−
1347−instance ToHie (SigContext (LSig GhcRn)) where
1348− toHie (SC (SI styp msp) (L sp sig)) = concatM $ makeNode sig sp : case sig of
1349− TypeSig _ names typ ->
1350− [ toHie $ map (C TyDecl) names
1351− , toHie $ TS (UnresolvedScope (map unLoc names) Nothing) typ
1352− ]
1353− PatSynSig _ names typ ->
1354− [ toHie $ map (C TyDecl) names
1355− , toHie $ TS (UnresolvedScope (map unLoc names) Nothing) typ
1356− ]
1357− ClassOpSig _ _ names typ ->
1358− [ case styp of
1359− ClassSig -> toHie $ map (C $ ClassTyDecl $ getRealSpan sp) names
1360− _ -> toHie $ map (C $ TyDecl) names
1361− , toHie $ TS (UnresolvedScope (map unLoc names) msp) typ
1362− ]
1363− IdSig _ _ -> []
1364− FixSig _ fsig ->
1365− [ toHie $ L sp fsig
1366− ]
1367− InlineSig _ name _ ->
1368− [ toHie $ (C Use) name
1369− ]
1370− SpecSig _ name typs _ ->
1371− [ toHie $ (C Use) name
1372− , toHie $ map (TS (ResolvedScopes [])) typs
1373− ]
1374− SpecInstSig _ _ typ ->
1375− [ toHie $ TS (ResolvedScopes []) typ
1376− ]
1377− MinimalSig _ _ form ->
1378− [ toHie form
1379− ]
1380− SCCFunSig _ _ name mtxt ->
1381− [ toHie $ (C Use) name
1382− , pure $ maybe [] (locOnly . getLoc) mtxt
1383− ]
1384− CompleteMatchSig _ _ (L ispan names) typ ->
1385− [ pure $ locOnly ispan
1386− , toHie $ map (C Use) names
1387− , toHie $ fmap (C Use) typ
1388− ]
1389− XSig _ -> []
1390−
1391−instance ToHie (LHsType GhcRn) where
1392− toHie x = toHie $ TS (ResolvedScopes []) x
1393−
1394−instance ToHie (TScoped (LHsType GhcRn)) where
1395− toHie (TS tsc (L span t)) = concatM $ makeNode t span : case t of
1396− HsForAllTy _ bndrs body ->
1397− [ toHie $ tvScopes tsc (mkScope $ getLoc body) bndrs
1398− , toHie body
1399− ]
1400− HsQualTy _ ctx body ->
1401− [ toHie ctx
1402− , toHie body
1403− ]
1404− HsTyVar _ _ var ->
1405− [ toHie $ C Use var
1406− ]
1407− HsAppTy _ a b ->
1408− [ toHie a
1409− , toHie b
1410− ]
1411− HsAppKindTy _ ty ki ->
1412− [ toHie ty
1413− , toHie $ TS (ResolvedScopes []) ki
1414− ]
1415− HsFunTy _ a b ->
1416− [ toHie a
1417− , toHie b
1418− ]
1419− HsListTy _ a ->
1420− [ toHie a
1421− ]
1422− HsTupleTy _ _ tys ->
1423− [ toHie tys
1424− ]
1425− HsSumTy _ tys ->
1426− [ toHie tys
1427− ]
1428− HsOpTy _ a op b ->
1429− [ toHie a
1430− , toHie $ C Use op
1431− , toHie b
1432− ]
1433− HsParTy _ a ->
1434− [ toHie a
1435− ]
1436− HsIParamTy _ ip ty ->
1437− [ toHie ip
1438− , toHie ty
1439− ]
1440− HsKindSig _ a b ->
1441− [ toHie a
1442− , toHie b
1443− ]
1444− HsSpliceTy _ a ->
1445− [ toHie $ L span a
1446− ]
1447− HsDocTy _ a _ ->
1448− [ toHie a
1449− ]
1450− HsBangTy _ _ ty ->
1451− [ toHie ty
1452− ]
1453− HsRecTy _ fields ->
1454− [ toHie fields
1455− ]
1456− HsExplicitListTy _ _ tys ->
1457− [ toHie tys
1458− ]
1459− HsExplicitTupleTy _ tys ->
1460− [ toHie tys
1461− ]
1462− HsTyLit _ _ -> []
1463− HsWildCardTy _ -> []
1464− HsStarTy _ _ -> []
1465− XHsType _ -> []
1466−
1467−instance (ToHie tm, ToHie ty) => ToHie (HsArg tm ty) where
1468− toHie (HsValArg tm) = toHie tm
1469− toHie (HsTypeArg _ ty) = toHie ty
1470− toHie (HsArgPar sp) = pure $ locOnly sp
1471−
1472−instance ToHie (TVScoped (LHsTyVarBndr GhcRn)) where
1473− toHie (TVS tsc sc (L span bndr)) = concatM $ makeNode bndr span : case bndr of
1474− UserTyVar _ var ->
1475− [ toHie $ C (TyVarBind sc tsc) var
1476− ]
1477− KindedTyVar _ var kind ->
1478− [ toHie $ C (TyVarBind sc tsc) var
1479− , toHie kind
1480− ]
1481− XTyVarBndr _ -> []
1482−
1483−instance ToHie (TScoped (LHsQTyVars GhcRn)) where
1484− toHie (TS sc (HsQTvs (HsQTvsRn implicits _) vars)) = concatM $
1485− [ pure $ bindingsOnly bindings
1486− , toHie $ tvScopes sc NoScope vars
1487− ]
1488− where
1489− varLoc = loc vars
1490− bindings = map (C $ TyVarBind (mkScope varLoc) sc) implicits
1491− toHie (TS _ (XLHsQTyVars _)) = pure []
1492−
1493−instance ToHie (LHsContext GhcRn) where
1494− toHie (L span tys) = concatM $
1495− [ pure $ locOnly span
1496− , toHie tys
1497− ]
1498−
1499−instance ToHie (LConDeclField GhcRn) where
1500− toHie (L span field) = concatM $ makeNode field span : case field of
1501− ConDeclField _ fields typ _ ->
1502− [ toHie $ map (RFC RecFieldDecl (getRealSpan $ loc typ)) fields
1503− , toHie typ
1504− ]
1505− XConDeclField _ -> []
1506−
1507−instance ToHie (LHsExpr a) => ToHie (ArithSeqInfo a) where
1508− toHie (From expr) = toHie expr
1509− toHie (FromThen a b) = concatM $
1510− [ toHie a
1511− , toHie b
1512− ]
1513− toHie (FromTo a b) = concatM $
1514− [ toHie a
1515− , toHie b
1516− ]
1517− toHie (FromThenTo a b c) = concatM $
1518− [ toHie a
1519− , toHie b
1520− , toHie c
1521− ]
1522−
1523−instance ToHie (LSpliceDecl GhcRn) where
1524− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1525− SpliceDecl _ splice _ ->
1526− [ toHie splice
1527− ]
1528− XSpliceDecl _ -> []
1529−
1530−instance ToHie (HsBracket a) where
1531− toHie _ = pure []
1532−
1533−instance ToHie PendingRnSplice where
1534− toHie _ = pure []
1535−
1536−instance ToHie PendingTcSplice where
1537− toHie _ = pure []
1538−
1539−instance ToHie (LBooleanFormula (Located Name)) where
1540− toHie (L span form) = concatM $ makeNode form span : case form of
1541− Var a ->
1542− [ toHie $ C Use a
1543− ]
1544− And forms ->
1545− [ toHie forms
1546− ]
1547− Or forms ->
1548− [ toHie forms
1549− ]
1550− Parens f ->
1551− [ toHie f
1552− ]
1553−
1554−instance ToHie (Located HsIPName) where
1555− toHie (L span e) = makeNode e span
1556−
1557−instance ( ToHie (LHsExpr a)
1558− , Data (HsSplice a)
1559− ) => ToHie (Located (HsSplice a)) where
1560− toHie (L span sp) = concatM $ makeNode sp span : case sp of
1561− HsTypedSplice _ _ _ expr ->
1562− [ toHie expr
1563− ]
1564− HsUntypedSplice _ _ _ expr ->
1565− [ toHie expr
1566− ]
1567− HsQuasiQuote _ _ _ ispan _ ->
1568− [ pure $ locOnly ispan
1569− ]
1570− HsSpliced _ _ _ ->
1571− []
1572− HsSplicedT _ ->
1573− []
1574− XSplice _ -> []
1575−
1576−instance ToHie (LRoleAnnotDecl GhcRn) where
1577− toHie (L span annot) = concatM $ makeNode annot span : case annot of
1578− RoleAnnotDecl _ var roles ->
1579− [ toHie $ C Use var
1580− , concatMapM (pure . locOnly . getLoc) roles
1581− ]
1582− XRoleAnnotDecl _ -> []
1583−
1584−instance ToHie (LInstDecl GhcRn) where
1585− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1586− ClsInstD _ d ->
1587− [ toHie $ L span d
1588− ]
1589− DataFamInstD _ d ->
1590− [ toHie $ L span d
1591− ]
1592− TyFamInstD _ d ->
1593− [ toHie $ L span d
1594− ]
1595− XInstDecl _ -> []
1596−
1597−instance ToHie (LClsInstDecl GhcRn) where
1598− toHie (L span decl) = concatM
1599− [ toHie $ TS (ResolvedScopes [mkScope span]) $ cid_poly_ty decl
1600− , toHie $ fmap (BC InstanceBind ModuleScope) $ cid_binds decl
1601− , toHie $ map (SC $ SI InstSig $ getRealSpan span) $ cid_sigs decl
1602− , pure $ concatMap (locOnly . getLoc) $ cid_tyfam_insts decl
1603− , toHie $ cid_tyfam_insts decl
1604− , pure $ concatMap (locOnly . getLoc) $ cid_datafam_insts decl
1605− , toHie $ cid_datafam_insts decl
1606− , toHie $ cid_overlap_mode decl
1607− ]
1608−
1609−instance ToHie (LDataFamInstDecl GhcRn) where
1610− toHie (L sp (DataFamInstDecl d)) = toHie $ TS (ResolvedScopes [mkScope sp]) d
1611−
1612−instance ToHie (LTyFamInstDecl GhcRn) where
1613− toHie (L sp (TyFamInstDecl d)) = toHie $ TS (ResolvedScopes [mkScope sp]) d
1614−
1615−instance ToHie (Context a)
1616− => ToHie (PatSynFieldContext (RecordPatSynField a)) where
1617− toHie (PSC sp (RecordPatSynField a b)) = concatM $
1618− [ toHie $ C (RecField RecFieldDecl sp) a
1619− , toHie $ C Use b
1620− ]
1621−
1622−instance ToHie (LDerivDecl GhcRn) where
1623− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1624− DerivDecl _ typ strat overlap ->
1625− [ toHie $ TS (ResolvedScopes []) typ
1626− , toHie strat
1627− , toHie overlap
1628− ]
1629− XDerivDecl _ -> []
1630−
1631−instance ToHie (LFixitySig GhcRn) where
1632− toHie (L span sig) = concatM $ makeNode sig span : case sig of
1633− FixitySig _ vars _ ->
1634− [ toHie $ map (C Use) vars
1635− ]
1636− XFixitySig _ -> []
1637−
1638−instance ToHie (LDefaultDecl GhcRn) where
1639− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1640− DefaultDecl _ typs ->
1641− [ toHie typs
1642− ]
1643− XDefaultDecl _ -> []
1644−
1645−instance ToHie (LForeignDecl GhcRn) where
1646− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1647− ForeignImport {fd_name = name, fd_sig_ty = sig, fd_fi = fi} ->
1648− [ toHie $ C (ValBind RegularBind ModuleScope $ getRealSpan span) name
1649− , toHie $ TS (ResolvedScopes []) sig
1650− , toHie fi
1651− ]
1652− ForeignExport {fd_name = name, fd_sig_ty = sig, fd_fe = fe} ->
1653− [ toHie $ C Use name
1654− , toHie $ TS (ResolvedScopes []) sig
1655− , toHie fe
1656− ]
1657− XForeignDecl _ -> []
1658−
1659−instance ToHie ForeignImport where
1660− toHie (CImport (L a _) (L b _) _ _ (L c _)) = pure $ concat $
1661− [ locOnly a
1662− , locOnly b
1663− , locOnly c
1664− ]
1665−
1666−instance ToHie ForeignExport where
1667− toHie (CExport (L a _) (L b _)) = pure $ concat $
1668− [ locOnly a
1669− , locOnly b
1670− ]
1671−
1672−instance ToHie (LWarnDecls GhcRn) where
1673− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1674− Warnings _ _ warnings ->
1675− [ toHie warnings
1676− ]
1677− XWarnDecls _ -> []
1678−
1679−instance ToHie (LWarnDecl GhcRn) where
1680− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1681− Warning _ vars _ ->
1682− [ toHie $ map (C Use) vars
1683− ]
1684− XWarnDecl _ -> []
1685−
1686−instance ToHie (LAnnDecl GhcRn) where
1687− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1688− HsAnnotation _ _ prov expr ->
1689− [ toHie prov
1690− , toHie expr
1691− ]
1692− XAnnDecl _ -> []
1693−
1694−instance ToHie (Context (Located a)) => ToHie (AnnProvenance a) where
1695− toHie (ValueAnnProvenance a) = toHie $ C Use a
1696− toHie (TypeAnnProvenance a) = toHie $ C Use a
1697− toHie ModuleAnnProvenance = pure []
1698−
1699−instance ToHie (LRuleDecls GhcRn) where
1700− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1701− HsRules _ _ rules ->
1702− [ toHie rules
1703− ]
1704− XRuleDecls _ -> []
1705−
1706−instance ToHie (LRuleDecl GhcRn) where
1707− toHie (L _ (XRuleDecl _)) = pure []
1708− toHie (L span r@(HsRule _ rname _ tybndrs bndrs exprA exprB)) = concatM
1709− [ makeNode r span
1710− , pure $ locOnly $ getLoc rname
1711− , toHie $ fmap (tvScopes (ResolvedScopes []) scope) tybndrs
1712− , toHie $ map (RS $ mkScope span) bndrs
1713− , toHie exprA
1714− , toHie exprB
1715− ]
1716− where scope = bndrs_sc `combineScopes` exprA_sc `combineScopes` exprB_sc
1717− bndrs_sc = maybe NoScope mkLScope (listToMaybe bndrs)
1718− exprA_sc = mkLScope exprA
1719− exprB_sc = mkLScope exprB
1720−
1721−instance ToHie (RScoped (LRuleBndr GhcRn)) where
1722− toHie (RS sc (L span bndr)) = concatM $ makeNode bndr span : case bndr of
1723− RuleBndr _ var ->
1724− [ toHie $ C (ValBind RegularBind sc Nothing) var
1725− ]
1726− RuleBndrSig _ var typ ->
1727− [ toHie $ C (ValBind RegularBind sc Nothing) var
1728− , toHie $ TS (ResolvedScopes [sc]) typ
1729− ]
1730− XRuleBndr _ -> []
1731−
1732−instance ToHie (LImportDecl GhcRn) where
1733− toHie (L span decl) = concatM $ makeNode decl span : case decl of
1734− ImportDecl { ideclName = name, ideclAs = as, ideclHiding = hidden } ->
1735− [ toHie $ IEC Import name
1736− , toHie $ fmap (IEC ImportAs) as
1737− , maybe (pure []) goIE hidden
1738− ]
1739− XImportDecl _ -> []
1740− where
1741− goIE (hiding, (L sp liens)) = concatM $
1742− [ pure $ locOnly sp
1743− , toHie $ map (IEC c) liens
1744− ]
1745− where
1746− c = if hiding then ImportHiding else Import
1747−
1748−instance ToHie (IEContext (LIE GhcRn)) where
1749− toHie (IEC c (L span ie)) = concatM $ makeNode ie span : case ie of
1750− IEVar _ n ->
1751− [ toHie $ IEC c n
1752− ]
1753− IEThingAbs _ n ->
1754− [ toHie $ IEC c n
1755− ]
1756− IEThingAll _ n ->
1757− [ toHie $ IEC c n
1758− ]
1759− IEThingWith _ n _ ns flds ->
1760− [ toHie $ IEC c n
1761− , toHie $ map (IEC c) ns
1762− , toHie $ map (IEC c) flds
1763− ]
1764− IEModuleContents _ n ->
1765− [ toHie $ IEC c n
1766− ]
1767− IEGroup _ _ _ -> []
1768− IEDoc _ _ -> []
1769− IEDocNamed _ _ -> []
1770− XIE _ -> []
1771−
1772−instance ToHie (IEContext (LIEWrappedName Name)) where
1773− toHie (IEC c (L span iewn)) = concatM $ makeNode iewn span : case iewn of
1774− IEName n ->
1775− [ toHie $ C (IEThing c) n
1776− ]
1777− IEPattern p ->
1778− [ toHie $ C (IEThing c) p
1779− ]
1780− IEType n ->
1781− [ toHie $ C (IEThing c) n
1782− ]
1783−
1784−instance ToHie (IEContext (Located (FieldLbl Name))) where
1785− toHie (IEC c (L span lbl)) = concatM $ makeNode lbl span : case lbl of
1786− FieldLabel _ _ n ->
1787− [ toHie $ C (IEThing c) $ L span n
1788− ]
1789−
src/Development/IDE/Compat.hs+30−11
@@ -1,19 +1,38 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
14{-# LANGUAGE CPP #-}
2−module Development.IDE.Compat
3− (
4− getProcessID
5+
6+-- | Attempt at hiding the GHC version differences we can.
7+module Development.IDE.Compat(
8+ HieFile(..),
9+ mkHieFile,
10+ writeHieFile,
11+ readHieFile
512 ) where
613
7−#ifdef mingw32_HOST_OS
14+#ifndef GHC_STABLE
15+import HieBin
16+import HieAst
17+import HieTypes
18+#else
819
9−import qualified System.Win32.Process as P (getCurrentProcessId)
10−getProcessID :: IO Int
11−getProcessID = fromIntegral <$> P.getCurrentProcessId
20+import GHC
21+import GhcPlugins
22+import NameCache
23+import Avail
24+import TcRnTypes
1225
13−#else
1426
15−import qualified System.Posix.Process as P (getProcessID)
16−getProcessID :: IO Int
17−getProcessID = fromIntegral <$> P.getProcessID
27+mkHieFile :: ModSummary -> TcGblEnv -> RenamedSource -> Hsc HieFile
28+mkHieFile _ _ _ = return (HieFile () [])
29+
30+writeHieFile :: FilePath -> HieFile -> IO ()
31+writeHieFile _ _ = return ()
32+
33+readHieFile :: NameCache -> FilePath -> IO (HieFile, ())
34+readHieFile _ _ = return (HieFile () [], ())
35+
36+data HieFile = HieFile {hie_module :: (), hie_exports :: [AvailInfo]}
1837
1938#endif
src/Development/IDE/Core/Compile.hsdeleted−598
@@ -1,598 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE RankNTypes #-}
5−{-# LANGUAGE CPP #-}
6−#include "ghc-api-version.h"
7−
8−-- | Based on https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/API.
9−-- Given a list of paths to find libraries, and a file to compile, produce a list of 'CoreModule' values.
10−module Development.IDE.Core.Compile
11− ( TcModuleResult(..)
12− , RunSimplifier(..)
13− , compileModule
14− , parseModule
15− , typecheckModule
16− , computePackageDeps
17− , addRelativeImport
18− , mkTcModuleResult
19− , generateByteCode
20− , generateAndWriteHieFile
21− , generateAndWriteHiFile
22− , getModSummaryFromImports
23− , loadHieFile
24− , loadInterface
25− , loadDepModule
26− , loadModuleHome
27− ) where
28−
29−import Development.IDE.Core.RuleTypes
30−import Development.IDE.Core.Preprocessor
31−import Development.IDE.Core.Shake
32−import Development.IDE.GHC.Error
33−import Development.IDE.GHC.Warnings
34−import Development.IDE.Types.Diagnostics
35−import Development.IDE.GHC.Orphans()
36−import Development.IDE.GHC.Util
37−import qualified GHC.LanguageExtensions.Type as GHC
38−import Development.IDE.Types.Options
39−import Development.IDE.Types.Location
40−import Outputable
41−
42−#if MIN_GHC_API_VERSION(8,6,0)
43−import DynamicLoading (initializePlugins)
44−#endif
45−
46−import GHC hiding (parseModule, typecheckModule)
47−import qualified Parser
48−import Lexer
49−#if MIN_GHC_API_VERSION(8,10,0)
50−#else
51−import ErrUtils
52−#endif
53−
54−import Finder
55−import qualified Development.IDE.GHC.Compat as GHC
56−import qualified Development.IDE.GHC.Compat as Compat
57−import GhcMonad
58−import GhcPlugins as GHC hiding (fst3, (<>))
59−import qualified HeaderInfo as Hdr
60−import HscMain (hscInteractive, hscSimplify)
61−import LoadIface (readIface)
62−import qualified Maybes
63−import MkIface
64−import NameCache
65−import StringBuffer as SB
66−import TcRnMonad (initIfaceLoad, tcg_th_coreplugins)
67−import TcIface (typecheckIface)
68−import TidyPgm
69−
70−import Control.Exception.Safe
71−import Control.Monad.Extra
72−import Control.Monad.Except
73−import Control.Monad.Trans.Except
74−import Data.Bifunctor (first, second)
75−import qualified Data.Text as T
76−import Data.IORef
77−import Data.List.Extra
78−import Data.Maybe
79−import qualified Data.Map.Strict as Map
80−import System.FilePath
81−import System.Directory
82−import System.IO.Extra
83−import Data.Either.Extra (maybeToEither)
84−import Control.DeepSeq (rnf)
85−import Control.Exception (evaluate)
86−import Exception (ExceptionMonad)
87−
88−
89−-- | Given a string buffer, return the string (after preprocessing) and the 'ParsedModule'.
90−parseModule
91− :: IdeOptions
92− -> HscEnv
93− -> [PackageName]
94− -> FilePath
95− -> Maybe SB.StringBuffer
96− -> IO (IdeResult (StringBuffer, ParsedModule))
97−parseModule IdeOptions{..} env comp_pkgs filename mbContents =
98− fmap (either (, Nothing) id) $
99− evalGhcEnv env $ runExceptT $ do
100− (contents, dflags) <- preprocessor filename mbContents
101− (diag, modu) <- parseFileContents optPreprocessor dflags comp_pkgs filename contents
102− return (diag, Just (contents, modu))
103−
104−
105−-- | Given a package identifier, what packages does it depend on
106−computePackageDeps
107− :: HscEnv
108− -> InstalledUnitId
109− -> IO (Either [FileDiagnostic] [InstalledUnitId])
110−computePackageDeps env pkg = do
111− let dflags = hsc_dflags env
112− case lookupInstalledPackage dflags pkg of
113− Nothing -> return $ Left [ideErrorText (toNormalizedFilePath' noFilePath) $
114− T.pack $ "unknown package: " ++ show pkg]
115− Just pkgInfo -> return $ Right $ depends pkgInfo
116−
117−typecheckModule :: IdeDefer
118− -> HscEnv
119− -> [(ModSummary, (ModIface, Maybe Linkable))]
120− -> ParsedModule
121− -> IO (IdeResult (HscEnv, TcModuleResult))
122−typecheckModule (IdeDefer defer) hsc depsIn pm = do
123− fmap (either (, Nothing) (second Just . sequence) . sequence) $
124− runGhcEnv hsc $
125− catchSrcErrors "typecheck" $ do
126− -- Currently GetDependencies returns things in topological order so A comes before B if A imports B.
127− -- We need to reverse this as GHC gets very unhappy otherwise and complains about broken interfaces.
128− -- Long-term we might just want to change the order returned by GetDependencies
129− let deps = reverse depsIn
130−
131− setupFinderCache (map fst deps)
132−
133− let modSummary = pm_mod_summary pm
134− dflags = ms_hspp_opts modSummary
135−
136− mapM_ (uncurry loadDepModule . snd) deps
137− modSummary' <- initPlugins modSummary
138− (warnings, tcm) <- withWarnings "typecheck" $ \tweak ->
139− GHC.typecheckModule $ enableTopLevelWarnings
140− $ demoteIfDefer pm{pm_mod_summary = tweak modSummary'}
141− tcm2 <- mkTcModuleResult tcm
142− let errorPipeline = unDefer . hideDiag dflags
143− return (map errorPipeline warnings, tcm2)
144− where
145− demoteIfDefer = if defer then demoteTypeErrorsToWarnings else id
146−
147−initPlugins :: GhcMonad m => ModSummary -> m ModSummary
148−initPlugins modSummary = do
149−#if MIN_GHC_API_VERSION(8,6,0)
150− session <- getSession
151− dflags <- liftIO $ initializePlugins session (ms_hspp_opts modSummary)
152− return modSummary{ms_hspp_opts = dflags}
153−#else
154− return modSummary
155−#endif
156−
157−-- | Whether we should run the -O0 simplifier when generating core.
158−--
159−-- This is required for template Haskell to work but we disable this in DAML.
160−-- See #256
161−newtype RunSimplifier = RunSimplifier Bool
162−
163−-- | Compile a single type-checked module to a 'CoreModule' value, or
164−-- provide errors.
165−compileModule
166− :: RunSimplifier
167− -> HscEnv
168− -> [(ModSummary, HomeModInfo)]
169− -> TcModuleResult
170− -> IO (IdeResult (SafeHaskellMode, CgGuts, ModDetails))
171−compileModule (RunSimplifier simplify) packageState deps tmr =
172− fmap (either (, Nothing) (second Just)) $
173− evalGhcEnv packageState $
174− catchSrcErrors "compile" $ do
175− setupEnv (deps ++ [(tmrModSummary tmr, tmrModInfo tmr)])
176−
177− let tm = tmrModule tmr
178− session <- getSession
179− (warnings,desugar) <- withWarnings "compile" $ \tweak -> do
180− let pm = tm_parsed_module tm
181− let pm' = pm{pm_mod_summary = tweak $ pm_mod_summary pm}
182− let tm' = tm{tm_parsed_module = pm'}
183− GHC.dm_core_module <$> GHC.desugarModule tm'
184− let tc_result = fst (tm_internals_ (tmrModule tmr))
185− desugared_guts <-
186− if simplify
187− then do
188− plugins <- liftIO $ readIORef (tcg_th_coreplugins tc_result)
189− liftIO $ hscSimplify session plugins desugar
190− else pure desugar
191− -- give variables unique OccNames
192− (guts, details) <- liftIO $ tidyProgram session desugared_guts
193− return (map snd warnings, (mg_safe_haskell desugar, guts, details))
194−
195−generateByteCode :: HscEnv -> [(ModSummary, HomeModInfo)] -> TcModuleResult -> CgGuts -> IO (IdeResult Linkable)
196−generateByteCode hscEnv deps tmr guts =
197− fmap (either (, Nothing) (second Just)) $
198− evalGhcEnv hscEnv $
199− catchSrcErrors "bytecode" $ do
200− setupEnv (deps ++ [(tmrModSummary tmr, tmrModInfo tmr)])
201− session <- getSession
202− (warnings, (_, bytecode, sptEntries)) <- withWarnings "bytecode" $ \tweak ->
203−#if MIN_GHC_API_VERSION(8,10,0)
204− liftIO $ hscInteractive session guts (GHC.ms_location $ tweak $ GHC.pm_mod_summary $ GHC.tm_parsed_module $ tmrModule tmr)
205−#else
206− liftIO $ hscInteractive session guts (tweak $ GHC.pm_mod_summary $ GHC.tm_parsed_module $ tmrModule tmr)
207−#endif
208− let summary = pm_mod_summary $ tm_parsed_module $ tmrModule tmr
209− let unlinked = BCOs bytecode sptEntries
210− let linkable = LM (ms_hs_date summary) (ms_mod summary) [unlinked]
211− pure (map snd warnings, linkable)
212−
213−demoteTypeErrorsToWarnings :: ParsedModule -> ParsedModule
214−demoteTypeErrorsToWarnings =
215− (update_pm_mod_summary . update_hspp_opts) demoteTEsToWarns where
216−
217− demoteTEsToWarns :: DynFlags -> DynFlags
218− -- convert the errors into warnings, and also check the warnings are enabled
219− demoteTEsToWarns = (`wopt_set` Opt_WarnDeferredTypeErrors)
220− . (`wopt_set` Opt_WarnTypedHoles)
221− . (`wopt_set` Opt_WarnDeferredOutOfScopeVariables)
222− . (`gopt_set` Opt_DeferTypeErrors)
223− . (`gopt_set` Opt_DeferTypedHoles)
224− . (`gopt_set` Opt_DeferOutOfScopeVariables)
225−
226−enableTopLevelWarnings :: ParsedModule -> ParsedModule
227−enableTopLevelWarnings =
228− (update_pm_mod_summary . update_hspp_opts)
229− ((`wopt_set` Opt_WarnMissingPatternSynonymSignatures) .
230− (`wopt_set` Opt_WarnMissingSignatures))
231− -- the line below would show also warnings for let bindings without signature
232− -- ((`wopt_set` Opt_WarnMissingSignatures) . (`wopt_set` Opt_WarnMissingLocalSignatures)))
233−
234−update_hspp_opts :: (DynFlags -> DynFlags) -> ModSummary -> ModSummary
235−update_hspp_opts up ms = ms{ms_hspp_opts = up $ ms_hspp_opts ms}
236−
237−update_pm_mod_summary :: (ModSummary -> ModSummary) -> ParsedModule -> ParsedModule
238−update_pm_mod_summary up pm =
239− pm{pm_mod_summary = up $ pm_mod_summary pm}
240−
241−unDefer :: (WarnReason, FileDiagnostic) -> FileDiagnostic
242−unDefer (Reason Opt_WarnDeferredTypeErrors , fd) = upgradeWarningToError fd
243−unDefer (Reason Opt_WarnTypedHoles , fd) = upgradeWarningToError fd
244−unDefer (Reason Opt_WarnDeferredOutOfScopeVariables, fd) = upgradeWarningToError fd
245−unDefer ( _ , fd) = fd
246−
247−upgradeWarningToError :: FileDiagnostic -> FileDiagnostic
248−upgradeWarningToError (nfp, sh, fd) =
249− (nfp, sh, fd{_severity = Just DsError, _message = warn2err $ _message fd}) where
250− warn2err :: T.Text -> T.Text
251− warn2err = T.intercalate ": error:" . T.splitOn ": warning:"
252−
253−hideDiag :: DynFlags -> (WarnReason, FileDiagnostic) -> (WarnReason, FileDiagnostic)
254−hideDiag originalFlags (Reason warning, (nfp, _sh, fd))
255− | not (wopt warning originalFlags) = (Reason warning, (nfp, HideDiag, fd))
256−hideDiag _originalFlags t = t
257−
258−addRelativeImport :: NormalizedFilePath -> ModuleName -> DynFlags -> DynFlags
259−addRelativeImport fp modu dflags = dflags
260− {importPaths = nubOrd $ maybeToList (moduleImportPath fp modu) ++ importPaths dflags}
261−
262−mkTcModuleResult
263− :: GhcMonad m
264− => TypecheckedModule
265− -> m TcModuleResult
266−mkTcModuleResult tcm = do
267− session <- getSession
268− let sf = modInfoSafe (tm_checked_module_info tcm)
269−#if MIN_GHC_API_VERSION(8,10,0)
270− iface <- liftIO $ mkIfaceTc session sf details tcGblEnv
271−#else
272− (iface, _) <- liftIO $ mkIfaceTc session Nothing sf details tcGblEnv
273−#endif
274− let mod_info = HomeModInfo iface details Nothing
275− return $ TcModuleResult tcm mod_info
276− where
277− (tcGblEnv, details) = tm_internals_ tcm
278−
279−atomicFileWrite :: FilePath -> (FilePath -> IO a) -> IO ()
280−atomicFileWrite targetPath write = do
281− let dir = takeDirectory targetPath
282− createDirectoryIfMissing True dir
283− (tempFilePath, cleanUp) <- newTempFileWithin dir
284− (write tempFilePath >> renameFile tempFilePath targetPath) `onException` cleanUp
285−
286−generateAndWriteHieFile :: HscEnv -> TypecheckedModule -> IO [FileDiagnostic]
287−generateAndWriteHieFile hscEnv tcm =
288− handleGenerationErrors dflags "extended interface generation" $ do
289− case tm_renamed_source tcm of
290− Just rnsrc -> do
291− hf <- runHsc hscEnv $
292− GHC.mkHieFile mod_summary (fst $ tm_internals_ tcm) rnsrc ""
293− atomicFileWrite targetPath $ flip GHC.writeHieFile hf
294− _ ->
295− return ()
296− where
297− dflags = hsc_dflags hscEnv
298− mod_summary = pm_mod_summary $ tm_parsed_module tcm
299− mod_location = ms_location mod_summary
300− targetPath = Compat.ml_hie_file mod_location
301−
302−generateAndWriteHiFile :: HscEnv -> TcModuleResult -> IO [FileDiagnostic]
303−generateAndWriteHiFile hscEnv tc =
304− handleGenerationErrors dflags "interface generation" $ do
305− atomicFileWrite targetPath $ \fp ->
306− writeIfaceFile dflags fp modIface
307− where
308− modIface = hm_iface $ tmrModInfo tc
309− modSummary = tmrModSummary tc
310− targetPath = withBootSuffix $ ml_hi_file $ ms_location $ tmrModSummary tc
311− withBootSuffix = case ms_hsc_src modSummary of
312− HsBootFile -> addBootSuffix
313− _ -> id
314− dflags = hsc_dflags hscEnv
315−
316−handleGenerationErrors :: DynFlags -> T.Text -> IO () -> IO [FileDiagnostic]
317−handleGenerationErrors dflags source action =
318− action >> return [] `catches`
319− [ Handler $ return . diagFromGhcException source dflags
320− , Handler $ return . diagFromString source DsError (noSpan "<internal>")
321− . (("Error during " ++ T.unpack source) ++) . show @SomeException
322− ]
323−
324−
325−-- | Setup the environment that GHC needs according to our
326−-- best understanding (!)
327−--
328−-- This involves setting up the finder cache and populating the
329−-- HPT.
330−setupEnv :: GhcMonad m => [(ModSummary, HomeModInfo)] -> m ()
331−setupEnv tms = do
332− setupFinderCache (map fst tms)
333− -- load dependent modules, which must be in topological order.
334− modifySession $ \e ->
335− foldl' (\e (_, hmi) -> loadModuleHome hmi e) e tms
336−
337−-- | Initialise the finder cache, dependencies should be topologically
338−-- sorted.
339−setupFinderCache :: GhcMonad m => [ModSummary] -> m ()
340−setupFinderCache mss = do
341− session <- getSession
342−
343− -- set the target and module graph in the session
344− let graph = mkModuleGraph mss
345− setSession session { hsc_mod_graph = graph }
346−
347− -- Make modules available for others that import them,
348− -- by putting them in the finder cache.
349− let ims = map (InstalledModule (thisInstalledUnitId $ hsc_dflags session) . moduleName . ms_mod) mss
350− ifrs = zipWith (\ms -> InstalledFound (ms_location ms)) mss ims
351− -- We have to create a new IORef here instead of modifying the existing IORef as
352− -- it is shared between concurrent compilations.
353− prevFinderCache <- liftIO $ readIORef $ hsc_FC session
354− let newFinderCache =
355− foldl'
356− (\fc (im, ifr) -> GHC.extendInstalledModuleEnv fc im ifr) prevFinderCache
357− $ zip ims ifrs
358− newFinderCacheVar <- liftIO $ newIORef $! newFinderCache
359− modifySession $ \s -> s { hsc_FC = newFinderCacheVar }
360−
361−
362−-- | Load a module, quickly. Input doesn't need to be desugared.
363−-- A module must be loaded before dependent modules can be typechecked.
364−-- This variant of loadModuleHome will *never* cause recompilation, it just
365−-- modifies the session.
366−--
367−-- The order modules are loaded is important when there are hs-boot files.
368−-- In particular you should make sure to load the .hs version of a file after the
369−-- .hs-boot version.
370−loadModuleHome
371− :: HomeModInfo
372− -> HscEnv
373− -> HscEnv
374−loadModuleHome mod_info e =
375− e { hsc_HPT = addToHpt (hsc_HPT e) mod_name mod_info }
376− where
377− mod_name = moduleName $ mi_module $ hm_iface mod_info
378−
379−-- | Load module interface.
380−loadDepModuleIO :: ModIface -> Maybe Linkable -> HscEnv -> IO HscEnv
381−loadDepModuleIO iface linkable hsc = do
382− details <- liftIO $ fixIO $ \details -> do
383− let hsc' = hsc { hsc_HPT = addToHpt (hsc_HPT hsc) mod (HomeModInfo iface details linkable) }
384− initIfaceLoad hsc' (typecheckIface iface)
385− let mod_info = HomeModInfo iface details linkable
386− return $ loadModuleHome mod_info hsc
387− where
388− mod = moduleName $ mi_module iface
389−
390−loadDepModule :: GhcMonad m => ModIface -> Maybe Linkable -> m ()
391−loadDepModule iface linkable = do
392− e <- getSession
393− e' <- liftIO $ loadDepModuleIO iface linkable e
394− setSession e'
395−
396−-- | GhcMonad function to chase imports of a module given as a StringBuffer. Returns given module's
397−-- name and its imports.
398−getImportsParsed :: DynFlags ->
399− GHC.ParsedSource ->
400− Either [FileDiagnostic] (GHC.ModuleName, [(Bool, (Maybe FastString, Located GHC.ModuleName))])
401−getImportsParsed dflags (L loc parsed) = do
402− let modName = maybe (GHC.mkModuleName "Main") GHC.unLoc $ GHC.hsmodName parsed
403−
404− -- most of these corner cases are also present in https://hackage.haskell.org/package/ghc-8.6.1/docs/src/HeaderInfo.html#getImports
405− -- but we want to avoid parsing the module twice
406− let implicit_prelude = xopt GHC.ImplicitPrelude dflags
407− implicit_imports = Hdr.mkPrelImports modName loc implicit_prelude $ GHC.hsmodImports parsed
408−
409− -- filter out imports that come from packages
410− return (modName, [(ideclSource i, (fmap sl_fs $ ideclPkgQual i, ideclName i))
411− | i <- map GHC.unLoc $ implicit_imports ++ GHC.hsmodImports parsed
412− , GHC.moduleNameString (GHC.unLoc $ ideclName i) /= "GHC.Prim"
413− ])
414−
415−-- | Produce a module summary from a StringBuffer.
416−getModSummaryFromBuffer
417− :: GhcMonad m
418− => FilePath
419− -> DynFlags
420− -> GHC.ParsedSource
421− -> ExceptT [FileDiagnostic] m ModSummary
422−getModSummaryFromBuffer fp dflags parsed = do
423− (modName, imports) <- liftEither $ getImportsParsed dflags parsed
424−
425− modLoc <- liftIO $ mkHomeModLocation dflags modName fp
426− let InstalledUnitId unitId = thisInstalledUnitId dflags
427− return $ ModSummary
428− { ms_mod = mkModule (fsToUnitId unitId) modName
429− , ms_location = modLoc
430− , ms_hs_date = error "Rules should not depend on ms_hs_date"
431− -- When we are working with a virtual file we do not have a file date.
432− -- To avoid silent issues where something is not processed because the date
433− -- has not changed, we make sure that things blow up if they depend on the
434− -- date.
435− , ms_textual_imps = [imp | (False, imp) <- imports]
436− , ms_hspp_file = fp
437− , ms_hspp_opts = dflags
438− , ms_hspp_buf = Nothing
439−
440− -- defaults:
441− , ms_hsc_src = sourceType
442− , ms_obj_date = Nothing
443− , ms_iface_date = Nothing
444−#if MIN_GHC_API_VERSION(8,8,0)
445− , ms_hie_date = Nothing
446−#endif
447− , ms_srcimps = [imp | (True, imp) <- imports]
448− , ms_parsed_mod = Nothing
449− }
450− where
451− sourceType = if "-boot" `isSuffixOf` takeExtension fp then HsBootFile else HsSrcFile
452−
453−-- | Given a buffer, env and filepath, produce a module summary by parsing only the imports.
454−-- Runs preprocessors as needed.
455−getModSummaryFromImports
456− :: (HasDynFlags m, ExceptionMonad m, MonadIO m)
457− => FilePath
458− -> Maybe SB.StringBuffer
459− -> ExceptT [FileDiagnostic] m ModSummary
460−getModSummaryFromImports fp contents = do
461− (contents, dflags) <- preprocessor fp contents
462− (srcImports, textualImports, L _ moduleName) <-
463− ExceptT $ liftIO $ first (diagFromErrMsgs "parser" dflags) <$> GHC.getHeaderImports dflags contents fp fp
464−
465− -- Force bits that might keep the string buffer and DynFlags alive unnecessarily
466− liftIO $ evaluate $ rnf srcImports
467− liftIO $ evaluate $ rnf textualImports
468−
469− modLoc <- liftIO $ mkHomeModLocation dflags moduleName fp
470−
471− let mod = mkModule (thisPackage dflags) moduleName
472− sourceType = if "-boot" `isSuffixOf` takeExtension fp then HsBootFile else HsSrcFile
473− summary =
474− ModSummary
475− { ms_mod = mod
476−#if MIN_GHC_API_VERSION(8,8,0)
477− , ms_hie_date = Nothing
478−#endif
479− , ms_hs_date = error "Rules should not depend on ms_hs_date"
480− -- When we are working with a virtual file we do not have a file date.
481− -- To avoid silent issues where something is not processed because the date
482− -- has not changed, we make sure that things blow up if they depend on the date.
483− , ms_hsc_src = sourceType
484− , ms_hspp_buf = Nothing
485− , ms_hspp_file = fp
486− , ms_hspp_opts = dflags
487− , ms_iface_date = Nothing
488− , ms_location = modLoc
489− , ms_obj_date = Nothing
490− , ms_parsed_mod = Nothing
491− , ms_srcimps = srcImports
492− , ms_textual_imps = textualImports
493− }
494− return summary
495−
496−
497−-- | Given a buffer, flags, and file path, produce a
498−-- parsed module (or errors) and any parse warnings. Does not run any preprocessors
499−parseFileContents
500− :: GhcMonad m
501− => (GHC.ParsedSource -> IdePreprocessedSource)
502− -> DynFlags -- ^ flags to use
503− -> [PackageName] -- ^ The package imports to ignore
504− -> FilePath -- ^ the filename (for source locations)
505− -> SB.StringBuffer -- ^ Haskell module source text (full Unicode is supported)
506− -> ExceptT [FileDiagnostic] m ([FileDiagnostic], ParsedModule)
507−parseFileContents customPreprocessor dflags comp_pkgs filename contents = do
508− let loc = mkRealSrcLoc (mkFastString filename) 1 1
509− case unP Parser.parseModule (mkPState dflags contents loc) of
510−#if MIN_GHC_API_VERSION(8,10,0)
511− PFailed pst -> throwE $ diagFromErrMsgs "parser" dflags $ getErrorMessages pst dflags
512−#else
513− PFailed _ locErr msgErr ->
514− throwE $ diagFromErrMsg "parser" dflags $ mkPlainErrMsg dflags locErr msgErr
515−#endif
516− POk pst rdr_module ->
517− let hpm_annotations =
518− (Map.fromListWith (++) $ annotations pst,
519− Map.fromList ((noSrcSpan,comment_q pst)
520− :annotations_comments pst))
521− (warns, errs) = getMessages pst dflags
522− in
523− do
524− -- Just because we got a `POk`, it doesn't mean there
525− -- weren't errors! To clarify, the GHC parser
526− -- distinguishes between fatal and non-fatal
527− -- errors. Non-fatal errors are the sort that don't
528− -- prevent parsing from continuing (that is, a parse
529− -- tree can still be produced despite the error so that
530− -- further errors/warnings can be collected). Fatal
531− -- errors are those from which a parse tree just can't
532− -- be produced.
533− unless (null errs) $
534− throwE $ diagFromErrMsgs "parser" dflags $ snd $ getMessages pst dflags
535−
536− -- Ok, we got here. It's safe to continue.
537− let IdePreprocessedSource preproc_warns errs parsed = customPreprocessor rdr_module
538− unless (null errs) $ throwE $ diagFromStrings "parser" DsError errs
539− let parsed' = removePackageImports comp_pkgs parsed
540− let preproc_warnings = diagFromStrings "parser" DsWarning preproc_warns
541− ms <- getModSummaryFromBuffer filename dflags parsed'
542− let pm =
543− ParsedModule {
544− pm_mod_summary = ms
545− , pm_parsed_source = parsed'
546− , pm_extra_src_files=[] -- src imports not allowed
547− , pm_annotations = hpm_annotations
548− }
549− warnings = diagFromErrMsgs "parser" dflags warns
550− pure (warnings ++ preproc_warnings, pm)
551−
552−
553−-- | After parsing the module remove all package imports referring to
554−-- these packages as we have already dealt with what they map to.
555−removePackageImports :: [PackageName] -> GHC.ParsedSource -> GHC.ParsedSource
556−removePackageImports pkgs (L l h@HsModule {hsmodImports} ) = L l (h { hsmodImports = imports' })
557− where
558− imports' = map do_one_import hsmodImports
559− do_one_import (L l i@ImportDecl{ideclPkgQual}) =
560− case PackageName . sl_fs <$> ideclPkgQual of
561− Just pn | pn `elem` pkgs -> L l (i { ideclPkgQual = Nothing })
562− _ -> L l i
563−#if MIN_GHC_API_VERSION(8,6,0)
564− do_one_import l = l
565−#endif
566−
567−loadHieFile :: FilePath -> IO GHC.HieFile
568−loadHieFile f = do
569− u <- mkSplitUniqSupply 'a'
570− let nameCache = initNameCache u []
571− fmap (GHC.hie_file_result . fst) $ GHC.readHieFile nameCache f
572−
573−-- | Retuns an up-to-date module interface if available.
574−-- Assumes file exists.
575−-- Requires the 'HscEnv' to be set up with dependencies
576−loadInterface
577− :: HscEnv
578− -> ModSummary
579− -> [HiFileResult]
580− -> IO (Either String ModIface)
581−loadInterface session ms deps = do
582− let hiFile = case ms_hsc_src ms of
583− HsBootFile -> addBootSuffix (ml_hi_file $ ms_location ms)
584− _ -> ml_hi_file $ ms_location ms
585− r <- initIfaceLoad session $ readIface (ms_mod ms) hiFile
586− case r of
587− Maybes.Succeeded iface -> do
588− session' <- foldM (\e d -> loadDepModuleIO (hirModIface d) Nothing e) session deps
589− (reason, iface') <- checkOldIface session' ms SourceUnmodified (Just iface)
590− return $ maybeToEither (showReason reason) iface'
591− Maybes.Failed err -> do
592− let errMsg = showSDoc (hsc_dflags session) err
593− return $ Left errMsg
594−
595−showReason :: RecompileRequired -> String
596−showReason MustCompile = "Stale"
597−showReason (RecompBecause reason) = "Stale (" ++ reason ++ ")"
598−showReason UpToDate = "Up to date"
src/Development/IDE/Core/Debouncer.hsdeleted−52
@@ -1,52 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−module Development.IDE.Core.Debouncer
5− ( Debouncer
6− , registerEvent
7− , newAsyncDebouncer
8− , noopDebouncer
9− ) where
10−
11−import Control.Concurrent.Extra
12−import Control.Concurrent.Async
13−import Control.Exception
14−import Control.Monad.Extra
15−import Data.Hashable
16−import Data.HashMap.Strict (HashMap)
17−import qualified Data.HashMap.Strict as Map
18−import System.Time.Extra
19−
20−-- | A debouncer can be used to avoid triggering many events
21−-- (e.g. diagnostics) for the same key (e.g. the same file)
22−-- within a short timeframe. This is accomplished
23−-- by delaying each event for a given time. If another event
24−-- is registered for the same key within that timeframe,
25−-- only the new event will fire.
26−--
27−-- We abstract over the debouncer used so we an use a proper debouncer in the IDE but disable
28−-- debouncing in the DAML CLI compiler.
29−newtype Debouncer k = Debouncer { registerEvent :: Seconds -> k -> IO () -> IO () }
30−
31−-- | Debouncer used in the IDE that delays events as expected.
32−newAsyncDebouncer :: (Eq k, Hashable k) => IO (Debouncer k)
33−newAsyncDebouncer = Debouncer . asyncRegisterEvent <$> newVar Map.empty
34−
35−-- | Register an event that will fire after the given delay if no other event
36−-- for the same key gets registered until then.
37−--
38−-- If there is a pending event for the same key, the pending event will be killed.
39−-- Events are run unmasked so it is up to the user of `registerEvent`
40−-- to mask if required.
41−asyncRegisterEvent :: (Eq k, Hashable k) => Var (HashMap k (Async ())) -> Seconds -> k -> IO () -> IO ()
42−asyncRegisterEvent d delay k fire = modifyVar_ d $ \m -> mask_ $ do
43− whenJust (Map.lookup k m) cancel
44− a <- asyncWithUnmask $ \unmask -> unmask $ do
45− sleep delay
46− fire
47− modifyVar_ d (pure . Map.delete k)
48− pure $ Map.insert k a m
49−
50−-- | Debouncer used in the DAML CLI compiler that emits events immediately.
51−noopDebouncer :: Debouncer k
52−noopDebouncer = Debouncer $ \_ _ a -> a
src/Development/IDE/Core/FileExists.hsdeleted−181
@@ -1,181 +0,0 @@
1−{-# LANGUAGE OverloadedLists #-}
2−{-# LANGUAGE TypeFamilies #-}
3−{-# LANGUAGE UndecidableInstances #-}
4−module Development.IDE.Core.FileExists
5− ( fileExistsRules
6− , modifyFileExists
7− , getFileExists
8− )
9−where
10−
11−import Control.Concurrent.Extra
12−import Control.Exception
13−import Control.Monad.Extra
14−import qualified Data.Aeson as A
15−import Data.Binary
16−import qualified Data.ByteString as BS
17−import Data.HashMap.Strict (HashMap)
18−import qualified Data.HashMap.Strict as HashMap
19−import Data.Maybe
20−import qualified Data.Text as T
21−import Development.IDE.Core.FileStore
22−import Development.IDE.Core.IdeConfiguration
23−import Development.IDE.Core.Shake
24−import Development.IDE.Types.Location
25−import Development.IDE.Types.Logger
26−import Development.Shake
27−import Development.Shake.Classes
28−import GHC.Generics
29−import Language.Haskell.LSP.Messages
30−import Language.Haskell.LSP.Types
31−import Language.Haskell.LSP.Types.Capabilities
32−import qualified System.Directory as Dir
33−
34−-- | A map for tracking the file existence
35−type FileExistsMap = (HashMap NormalizedFilePath Bool)
36−
37−-- | A wrapper around a mutable 'FileExistsMap'
38−newtype FileExistsMapVar = FileExistsMapVar (Var FileExistsMap)
39−
40−instance IsIdeGlobal FileExistsMapVar
41−
42−-- | Grab the current global value of 'FileExistsMap' without acquiring a dependency
43−getFileExistsMapUntracked :: Action FileExistsMap
44−getFileExistsMapUntracked = do
45− FileExistsMapVar v <- getIdeGlobalAction
46− liftIO $ readVar v
47−
48−-- | Modify the global store of file exists
49−modifyFileExistsAction :: (FileExistsMap -> IO FileExistsMap) -> Action ()
50−modifyFileExistsAction f = do
51− FileExistsMapVar var <- getIdeGlobalAction
52− liftIO $ modifyVar_ var f
53−
54−-- | Modify the global store of file exists
55−modifyFileExists :: IdeState -> [(NormalizedFilePath, Bool)] -> IO ()
56−modifyFileExists state changes = do
57− FileExistsMapVar var <- getIdeGlobalState state
58− changesMap <- evaluate $ HashMap.fromList changes
59−
60− -- Masked to ensure that the previous values are flushed together with the map update
61− mask $ \_ -> do
62− -- update the map
63− modifyVar_ var $ evaluate . HashMap.union changesMap
64− -- flush previous values
65− mapM_ (deleteValue state GetFileExists . fst) changes
66−
67−-------------------------------------------------------------------------------------
68−
69−type instance RuleResult GetFileExists = Bool
70−
71−data GetFileExists = GetFileExists
72− deriving (Eq, Show, Typeable, Generic)
73−
74−instance NFData GetFileExists
75−instance Hashable GetFileExists
76−instance Binary GetFileExists
77−
78−-- | Returns True if the file exists
79−-- Note that a file is not considered to exist unless it is saved to disk.
80−-- In particular, VFS existence is not enough.
81−-- Consider the following example:
82−-- 1. The file @A.hs@ containing the line @import B@ is added to the files of interest
83−-- Since @B.hs@ is neither open nor exists, GetLocatedImports finds Nothing
84−-- 2. The editor creates a new buffer @B.hs@
85−-- Unless the editor also sends a @DidChangeWatchedFile@ event, ghcide will not pick it up
86−-- Most editors, e.g. VSCode, only send the event when the file is saved to disk.
87−getFileExists :: NormalizedFilePath -> Action Bool
88−getFileExists fp = use_ GetFileExists fp
89−
90−-- | Installs the 'getFileExists' rules.
91−-- Provides a fast implementation if client supports dynamic watched files.
92−-- Creates a global state as a side effect in that case.
93−fileExistsRules :: IO LspId -> ClientCapabilities -> VFSHandle -> Rules ()
94−fileExistsRules getLspId ClientCapabilities{_workspace} vfs = do
95− -- Create the global always, although it should only be used if we have fast rules.
96− -- But there's a chance someone will send unexpected notifications anyway,
97− -- e.g. https://github.com/digital-asset/ghcide/issues/599
98− addIdeGlobal . FileExistsMapVar =<< liftIO (newVar [])
99− case () of
100− _ | Just WorkspaceClientCapabilities{_didChangeWatchedFiles} <- _workspace
101− , Just DidChangeWatchedFilesClientCapabilities{_dynamicRegistration} <- _didChangeWatchedFiles
102− , Just True <- _dynamicRegistration
103− -> fileExistsRulesFast getLspId vfs
104− | otherwise -> do
105− logger <- logger <$> getShakeExtrasRules
106− liftIO $ logDebug logger "Warning: Client does not support watched files. Falling back to OS polling"
107− fileExistsRulesSlow vfs
108−
109−-- Requires an lsp client that provides WatchedFiles notifications.
110−fileExistsRulesFast :: IO LspId -> VFSHandle -> Rules ()
111−fileExistsRulesFast getLspId vfs =
112− defineEarlyCutoff $ \GetFileExists file -> do
113− isWf <- isWorkspaceFile file
114− if isWf
115− then fileExistsFast getLspId vfs file
116− else fileExistsSlow vfs file
117−
118−fileExistsFast :: IO LspId -> VFSHandle -> NormalizedFilePath -> Action (Maybe BS.ByteString, ([a], Maybe Bool))
119−fileExistsFast getLspId vfs file = do
120− fileExistsMap <- getFileExistsMapUntracked
121− let mbFilesWatched = HashMap.lookup file fileExistsMap
122− case mbFilesWatched of
123− Just fv -> pure (summarizeExists fv, ([], Just fv))
124− Nothing -> do
125− exist <- liftIO $ getFileExistsVFS vfs file
126− ShakeExtras { eventer } <- getShakeExtras
127−
128− -- add a listener for VFS Create/Delete file events,
129− -- taking the FileExistsMap lock to prevent race conditions
130− -- that would lead to multiple listeners for the same path
131− modifyFileExistsAction $ \x -> do
132− case HashMap.alterF (,Just exist) file x of
133− (Nothing, x') -> do
134− -- if the listener addition fails, we never recover. This is a bug.
135− addListener eventer file
136− return x'
137− (Just _, _) ->
138− -- if the key was already there, do nothing
139− return x
140−
141− pure (summarizeExists exist, ([], Just exist))
142− where
143− addListener eventer fp = do
144− reqId <- getLspId
145− let
146− req = RequestMessage "2.0" reqId ClientRegisterCapability regParams
147− fpAsId = T.pack $ fromNormalizedFilePath fp
148− regParams = RegistrationParams (List [registration])
149− registration = Registration fpAsId
150− WorkspaceDidChangeWatchedFiles
151− (Just (A.toJSON regOptions))
152− regOptions =
153− DidChangeWatchedFilesRegistrationOptions { _watchers = List [watcher] }
154− watchKind = WatchKind { _watchCreate = True, _watchChange = False, _watchDelete = True}
155− watcher = FileSystemWatcher { _globPattern = fromNormalizedFilePath fp
156− , _kind = Just watchKind
157− }
158−
159− eventer $ ReqRegisterCapability req
160−
161−summarizeExists :: Bool -> Maybe BS.ByteString
162−summarizeExists x = Just $ if x then BS.singleton 1 else BS.empty
163−
164−fileExistsRulesSlow:: VFSHandle -> Rules ()
165−fileExistsRulesSlow vfs =
166− defineEarlyCutoff $ \GetFileExists file -> fileExistsSlow vfs file
167−
168−fileExistsSlow :: VFSHandle -> NormalizedFilePath -> Action (Maybe BS.ByteString, ([a], Maybe Bool))
169−fileExistsSlow vfs file = do
170− alwaysRerun
171− exist <- liftIO $ getFileExistsVFS vfs file
172− pure (summarizeExists exist, ([], Just exist))
173−
174−getFileExistsVFS :: VFSHandle -> NormalizedFilePath -> IO Bool
175−getFileExistsVFS vfs file = do
176− -- we deliberately and intentionally wrap the file as an FilePath WITHOUT mkAbsolute
177− -- so that if the file doesn't exist, is on a shared drive that is unmounted etc we get a properly
178− -- cached 'No' rather than an exception in the wrong place
179− handle (\(_ :: IOException) -> return False) $
180− (isJust <$> getVirtualFile vfs (filePathToUri' file)) ||^
181− Dir.doesFileExist (fromNormalizedFilePath file)
src/Development/IDE/Core/FileStore.hsdeleted−187
@@ -1,187 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE TypeFamilies #-}
5−
6−module Development.IDE.Core.FileStore(
7− getFileContents,
8− getVirtualFile,
9− setBufferModified,
10− setSomethingModified,
11− fileStoreRules,
12− VFSHandle,
13− makeVFSHandle,
14− makeLSPVFSHandle
15− ) where
16−
17−import Development.IDE.GHC.Orphans()
18−import Development.IDE.Core.Shake
19−import Control.Concurrent.Extra
20−import qualified Data.Map.Strict as Map
21−import Data.Maybe
22−import qualified Data.Text as T
23−import Control.Monad.Extra
24−import Development.Shake
25−import Development.Shake.Classes
26−import Control.Exception
27−import GHC.Generics
28−import Data.Either.Extra
29−import System.IO.Error
30−import qualified Data.ByteString.Char8 as BS
31−import Development.IDE.Types.Diagnostics
32−import Development.IDE.Types.Location
33−import qualified Data.Rope.UTF16 as Rope
34−
35−#ifdef mingw32_HOST_OS
36−import Data.Time
37−import qualified System.Directory as Dir
38−#else
39−import Foreign.Ptr
40−import Foreign.C.String
41−import Foreign.C.Types
42−import Foreign.Marshal (alloca)
43−import Foreign.Storable
44−import qualified System.Posix.Error as Posix
45−#endif
46−
47−import Language.Haskell.LSP.Core
48−import Language.Haskell.LSP.VFS
49−
50−-- | haskell-lsp manages the VFS internally and automatically so we cannot use
51−-- the builtin VFS without spawning up an LSP server. To be able to test things
52−-- like `setBufferModified` we abstract over the VFS implementation.
53−data VFSHandle = VFSHandle
54− { getVirtualFile :: NormalizedUri -> IO (Maybe VirtualFile)
55− -- ^ get the contents of a virtual file
56− , setVirtualFileContents :: Maybe (NormalizedUri -> Maybe T.Text -> IO ())
57− -- ^ set a specific file to a value. If Nothing then we are ignoring these
58− -- signals anyway so can just say something was modified
59− }
60−
61−instance IsIdeGlobal VFSHandle
62−
63−makeVFSHandle :: IO VFSHandle
64−makeVFSHandle = do
65− vfsVar <- newVar (1, Map.empty)
66− pure VFSHandle
67− { getVirtualFile = \uri -> do
68− (_nextVersion, vfs) <- readVar vfsVar
69− pure $ Map.lookup uri vfs
70− , setVirtualFileContents = Just $ \uri content ->
71− modifyVar_ vfsVar $ \(nextVersion, vfs) -> pure $ (nextVersion + 1, ) $
72− case content of
73− Nothing -> Map.delete uri vfs
74− -- The second version number is only used in persistFileVFS which we do not use so we set it to 0.
75− Just content -> Map.insert uri (VirtualFile nextVersion 0 (Rope.fromText content)) vfs
76− }
77−
78−makeLSPVFSHandle :: LspFuncs c -> VFSHandle
79−makeLSPVFSHandle lspFuncs = VFSHandle
80− { getVirtualFile = getVirtualFileFunc lspFuncs
81− , setVirtualFileContents = Nothing
82− }
83−
84−
85−-- | Get the contents of a file, either dirty (if the buffer is modified) or Nothing to mean use from disk.
86−type instance RuleResult GetFileContents = (FileVersion, Maybe T.Text)
87−
88−data GetFileContents = GetFileContents
89− deriving (Eq, Show, Generic)
90−instance Hashable GetFileContents
91−instance NFData GetFileContents
92−instance Binary GetFileContents
93−
94−getModificationTimeRule :: VFSHandle -> Rules ()
95−getModificationTimeRule vfs =
96− defineEarlyCutoff $ \GetModificationTime file -> do
97− let file' = fromNormalizedFilePath file
98− let wrap time@(l,s) = (Just $ BS.pack $ show time, ([], Just $ ModificationTime l s))
99− alwaysRerun
100− mbVirtual <- liftIO $ getVirtualFile vfs $ filePathToUri' file
101− case mbVirtual of
102− Just (virtualFileVersion -> ver) ->
103− pure (Just $ BS.pack $ show ver, ([], Just $ VFSVersion ver))
104− Nothing -> liftIO $ fmap wrap (getModTime file')
105− `catch` \(e :: IOException) -> do
106− let err | isDoesNotExistError e = "File does not exist: " ++ file'
107− | otherwise = "IO error while reading " ++ file' ++ ", " ++ displayException e
108− return (Nothing, ([ideErrorText file $ T.pack err], Nothing))
109− where
110− -- Dir.getModificationTime is surprisingly slow since it performs
111− -- a ton of conversions. Since we do not actually care about
112− -- the format of the time, we can get away with something cheaper.
113− -- For now, we only try to do this on Unix systems where it seems to get the
114− -- time spent checking file modifications (which happens on every change)
115− -- from > 0.5s to ~0.15s.
116− -- We might also want to try speeding this up on Windows at some point.
117− -- TODO leverage DidChangeWatchedFile lsp notifications on clients that
118− -- support them, as done for GetFileExists
119− getModTime :: FilePath -> IO (Int,Int)
120− getModTime f =
121−#ifdef mingw32_HOST_OS
122− do time <- Dir.getModificationTime f
123− let !day = fromInteger $ toModifiedJulianDay $ utctDay time
124− !dayTime = fromInteger $ diffTimeToPicoseconds $ utctDayTime time
125− pure (day, dayTime)
126−#else
127− withCString f $ \f' ->
128− alloca $ \secPtr ->
129− alloca $ \nsecPtr -> do
130− Posix.throwErrnoPathIfMinus1Retry_ "getmodtime" f $ c_getModTime f' secPtr nsecPtr
131− sec <- peek secPtr
132− nsec <- peek nsecPtr
133− pure (fromEnum sec, fromIntegral nsec)
134−
135−-- Sadly even unix’s getFileStatus + modificationTimeHiRes is still about twice as slow
136−-- as doing the FFI call ourselves :(.
137−foreign import ccall "getmodtime" c_getModTime :: CString -> Ptr CTime -> Ptr CLong -> IO Int
138−#endif
139−
140−getFileContentsRule :: VFSHandle -> Rules ()
141−getFileContentsRule vfs =
142− define $ \GetFileContents file -> do
143− -- need to depend on modification time to introduce a dependency with Cutoff
144− time <- use_ GetModificationTime file
145− res <- liftIO $ ideTryIOException file $ do
146− mbVirtual <- getVirtualFile vfs $ filePathToUri' file
147− pure $ Rope.toText . _text <$> mbVirtual
148− case res of
149− Left err -> return ([err], Nothing)
150− Right contents -> return ([], Just (time, contents))
151−
152−ideTryIOException :: NormalizedFilePath -> IO a -> IO (Either FileDiagnostic a)
153−ideTryIOException fp act =
154− mapLeft
155− (\(e :: IOException) -> ideErrorText fp $ T.pack $ show e)
156− <$> try act
157−
158−
159−getFileContents :: NormalizedFilePath -> Action (FileVersion, Maybe T.Text)
160−getFileContents = use_ GetFileContents
161−
162−fileStoreRules :: VFSHandle -> Rules ()
163−fileStoreRules vfs = do
164− addIdeGlobal vfs
165− getModificationTimeRule vfs
166− getFileContentsRule vfs
167−
168−
169−-- | Notify the compiler service that a particular file has been modified.
170−-- Use 'Nothing' to say the file is no longer in the virtual file system
171−-- but should be sourced from disk, or 'Just' to give its new value.
172−setBufferModified :: IdeState -> NormalizedFilePath -> Maybe T.Text -> IO ()
173−setBufferModified state absFile contents = do
174− VFSHandle{..} <- getIdeGlobalState state
175− whenJust setVirtualFileContents $ \set ->
176− set (filePathToUri' absFile) contents
177− void $ shakeRun state []
178−
179−-- | Note that some buffer somewhere has been modified, but don't say what.
180−-- Only valid if the virtual file system was initialised by LSP, as that
181−-- independently tracks which files are modified.
182−setSomethingModified :: IdeState -> IO ()
183−setSomethingModified state = do
184− VFSHandle{..} <- getIdeGlobalState state
185− when (isJust setVirtualFileContents) $
186− fail "setSomethingModified can't be called on this type of VFSHandle"
187− void $ shakeRun state []
src/Development/IDE/Core/IdeConfiguration.hsdeleted−71
@@ -1,71 +0,0 @@
1−{-# LANGUAGE DuplicateRecordFields #-}
2−module Development.IDE.Core.IdeConfiguration
3− ( IdeConfiguration(..)
4− , registerIdeConfiguration
5− , parseConfiguration
6− , parseWorkspaceFolder
7− , isWorkspaceFile
8− , modifyWorkspaceFolders
9− )
10−where
11−
12−import Control.Concurrent.Extra
13−import Control.Monad
14−import Data.HashSet (HashSet, singleton)
15−import Data.Text (Text, isPrefixOf)
16−import Development.IDE.Core.Shake
17−import Development.IDE.Types.Location
18−import Development.Shake
19−import Language.Haskell.LSP.Types
20−import System.FilePath (isRelative)
21−
22−-- | Lsp client relevant configuration details
23−data IdeConfiguration = IdeConfiguration
24− { workspaceFolders :: HashSet NormalizedUri
25− }
26− deriving (Show)
27−
28−newtype IdeConfigurationVar = IdeConfigurationVar {unIdeConfigurationRef :: Var IdeConfiguration}
29−
30−instance IsIdeGlobal IdeConfigurationVar
31−
32−registerIdeConfiguration :: ShakeExtras -> IdeConfiguration -> IO ()
33−registerIdeConfiguration extras =
34− addIdeGlobalExtras extras . IdeConfigurationVar <=< newVar
35−
36−getIdeConfiguration :: Action IdeConfiguration
37−getIdeConfiguration =
38− getIdeGlobalAction >>= liftIO . readVar . unIdeConfigurationRef
39−
40−parseConfiguration :: InitializeParams -> IdeConfiguration
41−parseConfiguration InitializeParams {..} =
42− IdeConfiguration { .. }
43− where
44− workspaceFolders =
45− foldMap (singleton . toNormalizedUri) _rootUri
46− <> (foldMap . foldMap)
47− (singleton . parseWorkspaceFolder)
48− _workspaceFolders
49−
50−parseWorkspaceFolder :: WorkspaceFolder -> NormalizedUri
51−parseWorkspaceFolder =
52− toNormalizedUri . Uri . (_uri :: WorkspaceFolder -> Text)
53−
54−modifyWorkspaceFolders
55− :: IdeState -> (HashSet NormalizedUri -> HashSet NormalizedUri) -> IO ()
56−modifyWorkspaceFolders ide f = do
57− IdeConfigurationVar var <- getIdeGlobalState ide
58− IdeConfiguration ws <- readVar var
59− writeVar var (IdeConfiguration (f ws))
60−
61−isWorkspaceFile :: NormalizedFilePath -> Action Bool
62−isWorkspaceFile file =
63− if isRelative (fromNormalizedFilePath file)
64− then return True
65− else do
66− IdeConfiguration {..} <- getIdeConfiguration
67− let toText = getUri . fromNormalizedUri
68− return $
69− any
70− (\root -> toText root `isPrefixOf` toText (filePathToUri' file))
71− workspaceFolders
src/Development/IDE/Core/OfInterest.hsdeleted−82
@@ -1,82 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE TypeFamilies #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−
7−-- | Utilities and state for the files of interest - those which are currently
8−-- open in the editor. The useful function is 'getFilesOfInterest'.
9−module Development.IDE.Core.OfInterest(
10− ofInterestRules,
11− getFilesOfInterest, setFilesOfInterest, modifyFilesOfInterest,
12− ) where
13−
14−import Control.Concurrent.Extra
15−import Data.Binary
16−import Data.Hashable
17−import Control.DeepSeq
18−import GHC.Generics
19−import Data.Typeable
20−import qualified Data.ByteString.UTF8 as BS
21−import Control.Exception
22−import Data.HashSet (HashSet)
23−import qualified Data.HashSet as HashSet
24−import qualified Data.Text as T
25−import Data.Tuple.Extra
26−import Data.Functor
27−import Development.Shake
28−
29−import Development.IDE.Types.Location
30−import Development.IDE.Types.Logger
31−import Development.IDE.Core.Shake
32−
33−
34−newtype OfInterestVar = OfInterestVar (Var (HashSet NormalizedFilePath))
35−instance IsIdeGlobal OfInterestVar
36−
37−type instance RuleResult GetFilesOfInterest = HashSet NormalizedFilePath
38−
39−data GetFilesOfInterest = GetFilesOfInterest
40− deriving (Eq, Show, Typeable, Generic)
41−instance Hashable GetFilesOfInterest
42−instance NFData GetFilesOfInterest
43−instance Binary GetFilesOfInterest
44−
45−
46−-- | The rule that initialises the files of interest state.
47−ofInterestRules :: Rules ()
48−ofInterestRules = do
49− addIdeGlobal . OfInterestVar =<< liftIO (newVar HashSet.empty)
50− defineEarlyCutoff $ \GetFilesOfInterest _file -> assert (null $ fromNormalizedFilePath _file) $ do
51− alwaysRerun
52− filesOfInterest <- getFilesOfInterestUntracked
53− pure (Just $ BS.fromString $ show filesOfInterest, ([], Just filesOfInterest))
54−
55−
56−-- | Get the files that are open in the IDE.
57−getFilesOfInterest :: Action (HashSet NormalizedFilePath)
58−getFilesOfInterest = useNoFile_ GetFilesOfInterest
59−
60−
61−
62−------------------------------------------------------------
63−-- Exposed API
64−
65−-- | Set the files-of-interest - not usually necessary or advisable.
66−-- The LSP client will keep this information up to date.
67−setFilesOfInterest :: IdeState -> HashSet NormalizedFilePath -> IO ()
68−setFilesOfInterest state files = modifyFilesOfInterest state (const files)
69−
70−getFilesOfInterestUntracked :: Action (HashSet NormalizedFilePath)
71−getFilesOfInterestUntracked = do
72− OfInterestVar var <- getIdeGlobalAction
73− liftIO $ readVar var
74−
75−-- | Modify the files-of-interest - not usually necessary or advisable.
76−-- The LSP client will keep this information up to date.
77−modifyFilesOfInterest :: IdeState -> (HashSet NormalizedFilePath -> HashSet NormalizedFilePath) -> IO ()
78−modifyFilesOfInterest state f = do
79− OfInterestVar var <- getIdeGlobalState state
80− files <- modifyVar var $ pure . dupe . f
81− logDebug (ideLogger state) $ "Set files of interest to: " <> T.pack (show $ HashSet.toList files)
82− void $ shakeRun state []
src/Development/IDE/Core/PositionMapping.hsdeleted−122
@@ -1,122 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−module Development.IDE.Core.PositionMapping
4− ( PositionMapping(..)
5− , fromCurrentPosition
6− , toCurrentPosition
7− , PositionDelta(..)
8− , addDelta
9− , mkDelta
10− , toCurrentRange
11− , fromCurrentRange
12− , applyChange
13− , zeroMapping
14− -- toCurrent and fromCurrent are mainly exposed for testing
15− , toCurrent
16− , fromCurrent
17− ) where
18−
19−import Control.Monad
20−import qualified Data.Text as T
21−import Language.Haskell.LSP.Types
22−import Data.List
23−
24−-- The position delta is the difference between two versions
25−data PositionDelta = PositionDelta
26− { toDelta :: !(Position -> Maybe Position)
27− , fromDelta :: !(Position -> Maybe Position)
28− }
29−
30−fromCurrentPosition :: PositionMapping -> Position -> Maybe Position
31−fromCurrentPosition (PositionMapping pm) = fromDelta pm
32−
33−toCurrentPosition :: PositionMapping -> Position -> Maybe Position
34−toCurrentPosition (PositionMapping pm) = toDelta pm
35−
36−-- A position mapping is the difference from the current version to
37−-- a specific version
38−newtype PositionMapping = PositionMapping PositionDelta
39−
40−
41−toCurrentRange :: PositionMapping -> Range -> Maybe Range
42−toCurrentRange mapping (Range a b) =
43− Range <$> toCurrentPosition mapping a <*> toCurrentPosition mapping b
44−
45−fromCurrentRange :: PositionMapping -> Range -> Maybe Range
46−fromCurrentRange mapping (Range a b) =
47− Range <$> fromCurrentPosition mapping a <*> fromCurrentPosition mapping b
48−
49−zeroMapping :: PositionMapping
50−zeroMapping = PositionMapping idDelta
51−
52−-- | Compose two position mappings. Composes in the same way as function
53−-- composition (ie the second argument is applyed to the position first).
54−composeDelta :: PositionDelta
55− -> PositionDelta
56− -> PositionDelta
57−composeDelta (PositionDelta to1 from1) (PositionDelta to2 from2) =
58− PositionDelta (to1 <=< to2)
59− (from1 >=> from2)
60−
61−idDelta :: PositionDelta
62−idDelta = PositionDelta Just Just
63−
64−-- | Convert a set of changes into a delta from k to k + 1
65−mkDelta :: [TextDocumentContentChangeEvent] -> PositionDelta
66−mkDelta cs = foldl' applyChange idDelta cs
67−
68−-- | Add a new delta onto a Mapping k n to make a Mapping (k - 1) n
69−addDelta :: PositionDelta -> PositionMapping -> PositionMapping
70−addDelta delta (PositionMapping pm) = PositionMapping (composeDelta delta pm)
71−
72−applyChange :: PositionDelta -> TextDocumentContentChangeEvent -> PositionDelta
73−applyChange PositionDelta{..} (TextDocumentContentChangeEvent (Just r) _ t) = PositionDelta
74− { toDelta = toCurrent r t <=< toDelta
75− , fromDelta = fromDelta <=< fromCurrent r t
76− }
77−applyChange posMapping _ = posMapping
78−
79−toCurrent :: Range -> T.Text -> Position -> Maybe Position
80−toCurrent (Range (Position startLine startColumn) (Position endLine endColumn)) t (Position line column)
81− | line < startLine || line == startLine && column < startColumn =
82− -- Position is before the change and thereby unchanged.
83− Just $ Position line column
84− | line > endLine || line == endLine && column >= endColumn =
85− -- Position is after the change so increase line and column number
86− -- as necessary.
87− Just $ Position (line + lineDiff) newColumn
88− | otherwise = Nothing
89− -- Position is in the region that was changed.
90− where
91− lineDiff = linesNew - linesOld
92− linesNew = T.count "\n" t
93− linesOld = endLine - startLine
94− newEndColumn
95− | linesNew == 0 = startColumn + T.length t
96− | otherwise = T.length $ T.takeWhileEnd (/= '\n') t
97− newColumn
98− | line == endLine = column + newEndColumn - endColumn
99− | otherwise = column
100−
101−fromCurrent :: Range -> T.Text -> Position -> Maybe Position
102−fromCurrent (Range (Position startLine startColumn) (Position endLine endColumn)) t (Position line column)
103− | line < startLine || line == startLine && column < startColumn =
104− -- Position is before the change and thereby unchanged
105− Just $ Position line column
106− | line > newEndLine || line == newEndLine && column >= newEndColumn =
107− -- Position is after the change so increase line and column number
108− -- as necessary.
109− Just $ Position (line - lineDiff) newColumn
110− | otherwise = Nothing
111− -- Position is in the region that was changed.
112− where
113− lineDiff = linesNew - linesOld
114− linesNew = T.count "\n" t
115− linesOld = endLine - startLine
116− newEndLine = endLine + lineDiff
117− newEndColumn
118− | linesNew == 0 = startColumn + T.length t
119− | otherwise = T.length $ T.takeWhileEnd (/= '\n') t
120− newColumn
121− | line == newEndLine = column - (newEndColumn - endColumn)
122− | otherwise = column
src/Development/IDE/Core/Preprocessor.hsdeleted−230
@@ -1,230 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−module Development.IDE.Core.Preprocessor
5− ( preprocessor
6− ) where
7−
8−import Development.IDE.GHC.CPP
9−import Development.IDE.GHC.Orphans()
10−import Development.IDE.GHC.Compat
11−import GhcMonad
12−import StringBuffer as SB
13−
14−import Data.List.Extra
15−import System.FilePath
16−import System.IO.Extra
17−import Data.Char
18−import DynFlags
19−import qualified HeaderInfo as Hdr
20−import Development.IDE.Types.Diagnostics
21−import Development.IDE.Types.Location
22−import Development.IDE.GHC.Error
23−import SysTools (Option (..), runUnlit, runPp)
24−import Control.Monad.Trans.Except
25−import qualified GHC.LanguageExtensions as LangExt
26−import Data.Maybe
27−import Control.Exception.Safe (catch, throw)
28−import Data.IORef (IORef, modifyIORef, newIORef, readIORef)
29−import Data.Text (Text)
30−import qualified Data.Text as T
31−import Outputable (showSDoc)
32−import Control.DeepSeq (NFData(rnf))
33−import Control.Exception (evaluate)
34−import Control.Monad.IO.Class (MonadIO)
35−import Exception (ExceptionMonad)
36−
37−
38−-- | Given a file and some contents, apply any necessary preprocessors,
39−-- e.g. unlit/cpp. Return the resulting buffer and the DynFlags it implies.
40−preprocessor :: (ExceptionMonad m, HasDynFlags m, MonadIO m) => FilePath -> Maybe StringBuffer -> ExceptT [FileDiagnostic] m (StringBuffer, DynFlags)
41−preprocessor filename mbContents = do
42− -- Perform unlit
43− (isOnDisk, contents) <-
44− if isLiterate filename then do
45− dflags <- getDynFlags
46− newcontent <- liftIO $ runLhs dflags filename mbContents
47− return (False, newcontent)
48− else do
49− contents <- liftIO $ maybe (hGetStringBuffer filename) return mbContents
50− let isOnDisk = isNothing mbContents
51− return (isOnDisk, contents)
52−
53− -- Perform cpp
54− dflags <- ExceptT $ parsePragmasIntoDynFlags filename contents
55− (isOnDisk, contents, dflags) <-
56− if not $ xopt LangExt.Cpp dflags then
57− return (isOnDisk, contents, dflags)
58− else do
59− cppLogs <- liftIO $ newIORef []
60− contents <- ExceptT
61− $ liftIO
62− $ (Right <$> (runCpp dflags {log_action = logAction cppLogs} filename
63− $ if isOnDisk then Nothing else Just contents))
64− `catch`
65− ( \(e :: GhcException) -> do
66− logs <- readIORef cppLogs
67− case diagsFromCPPLogs filename (reverse logs) of
68− [] -> throw e
69− diags -> return $ Left diags
70− )
71− dflags <- ExceptT $ parsePragmasIntoDynFlags filename contents
72− return (False, contents, dflags)
73−
74− -- Perform preprocessor
75− if not $ gopt Opt_Pp dflags then
76− return (contents, dflags)
77− else do
78− contents <- liftIO $ runPreprocessor dflags filename $ if isOnDisk then Nothing else Just contents
79− dflags <- ExceptT $ parsePragmasIntoDynFlags filename contents
80− return (contents, dflags)
81− where
82− logAction :: IORef [CPPLog] -> LogAction
83− logAction cppLogs dflags _reason severity srcSpan _style msg = do
84− let log = CPPLog severity srcSpan $ T.pack $ showSDoc dflags msg
85− modifyIORef cppLogs (log :)
86−
87−
88−data CPPLog = CPPLog Severity SrcSpan Text
89− deriving (Show)
90−
91−
92−data CPPDiag
93− = CPPDiag
94− { cdRange :: Range,
95− cdSeverity :: Maybe DiagnosticSeverity,
96− cdMessage :: [Text]
97− }
98− deriving (Show)
99−
100−
101−diagsFromCPPLogs :: FilePath -> [CPPLog] -> [FileDiagnostic]
102−diagsFromCPPLogs filename logs =
103− map (\d -> (toNormalizedFilePath' filename, ShowDiag, cppDiagToDiagnostic d)) $
104− go [] logs
105− where
106− -- On errors, CPP calls logAction with a real span for the initial log and
107− -- then additional informational logs with `UnhelpfulSpan`. Collect those
108− -- informational log messages and attaches them to the initial log message.
109− go :: [CPPDiag] -> [CPPLog] -> [CPPDiag]
110− go acc [] = reverse $ map (\d -> d {cdMessage = reverse $ cdMessage d}) acc
111− go acc (CPPLog sev span@(RealSrcSpan _) msg : logs) =
112− let diag = CPPDiag (srcSpanToRange span) (toDSeverity sev) [msg]
113− in go (diag : acc) logs
114− go (diag : diags) (CPPLog _sev (UnhelpfulSpan _) msg : logs) =
115− go (diag {cdMessage = msg : cdMessage diag} : diags) logs
116− go [] (CPPLog _sev (UnhelpfulSpan _) _msg : logs) = go [] logs
117− cppDiagToDiagnostic :: CPPDiag -> Diagnostic
118− cppDiagToDiagnostic d =
119− Diagnostic
120− { _range = cdRange d,
121− _severity = cdSeverity d,
122− _code = Nothing,
123− _source = Just "CPP",
124− _message = T.unlines $ cdMessage d,
125− _relatedInformation = Nothing,
126− _tags = Nothing
127− }
128−
129−
130−isLiterate :: FilePath -> Bool
131−isLiterate x = takeExtension x `elem` [".lhs",".lhs-boot"]
132−
133−
134−-- | This reads the pragma information directly from the provided buffer.
135−parsePragmasIntoDynFlags
136− :: (ExceptionMonad m, HasDynFlags m, MonadIO m)
137− => FilePath
138− -> SB.StringBuffer
139− -> m (Either [FileDiagnostic] DynFlags)
140−parsePragmasIntoDynFlags fp contents = catchSrcErrors "pragmas" $ do
141− dflags0 <- getDynFlags
142− let opts = Hdr.getOptions dflags0 contents fp
143−
144− -- Force bits that might keep the dflags and stringBuffer alive unnecessarily
145− liftIO $ evaluate $ rnf opts
146−
147− (dflags, _, _) <- parseDynamicFilePragma dflags0 opts
148− return dflags
149−
150−
151−-- | Run (unlit) literate haskell preprocessor on a file, or buffer if set
152−runLhs :: DynFlags -> FilePath -> Maybe SB.StringBuffer -> IO SB.StringBuffer
153−runLhs dflags filename contents = withTempDir $ \dir -> do
154− let fout = dir </> takeFileName filename <.> "unlit"
155− filesrc <- case contents of
156− Nothing -> return filename
157− Just cnts -> do
158− let fsrc = dir </> takeFileName filename <.> "literate"
159− withBinaryFile fsrc WriteMode $ \h ->
160− hPutStringBuffer h cnts
161− return fsrc
162− unlit filesrc fout
163− SB.hGetStringBuffer fout
164− where
165− unlit filein fileout = SysTools.runUnlit dflags (args filein fileout)
166− args filein fileout = [
167− SysTools.Option "-h"
168− , SysTools.Option (escape filename) -- name this file
169− , SysTools.FileOption "" filein -- input file
170− , SysTools.FileOption "" fileout ] -- output file
171− -- taken from ghc's DriverPipeline.hs
172− escape ('\\':cs) = '\\':'\\': escape cs
173− escape ('\"':cs) = '\\':'\"': escape cs
174− escape ('\'':cs) = '\\':'\'': escape cs
175− escape (c:cs) = c : escape cs
176− escape [] = []
177−
178−-- | Run CPP on a file
179−runCpp :: DynFlags -> FilePath -> Maybe SB.StringBuffer -> IO SB.StringBuffer
180−runCpp dflags filename contents = withTempDir $ \dir -> do
181− let out = dir </> takeFileName filename <.> "out"
182− dflags <- pure $ addOptP "-D__GHCIDE__" dflags
183−
184− case contents of
185− Nothing -> do
186− -- Happy case, file is not modified, so run CPP on it in-place
187− -- which also makes things like relative #include files work
188− -- and means location information is correct
189− doCpp dflags True filename out
190− liftIO $ SB.hGetStringBuffer out
191−
192− Just contents -> do
193− -- Sad path, we have to create a version of the path in a temp dir
194− -- __FILE__ macro is wrong, ignoring that for now (likely not a real issue)
195−
196− -- Relative includes aren't going to work, so we fix that by adding to the include path.
197− dflags <- return $ addIncludePathsQuote (takeDirectory filename) dflags
198−
199− -- Location information is wrong, so we fix that by patching it afterwards.
200− let inp = dir </> "___GHCIDE_MAGIC___"
201− withBinaryFile inp WriteMode $ \h ->
202− hPutStringBuffer h contents
203− doCpp dflags True inp out
204−
205− -- Fix up the filename in lines like:
206− -- # 1 "C:/Temp/extra-dir-914611385186/___GHCIDE_MAGIC___"
207− let tweak x
208− | Just x <- stripPrefix "# " x
209− , "___GHCIDE_MAGIC___" `isInfixOf` x
210− , let num = takeWhile (not . isSpace) x
211− -- important to use /, and never \ for paths, even on Windows, since then C escapes them
212− -- and GHC gets all confused
213− = "# " <> num <> " \"" <> map (\x -> if isPathSeparator x then '/' else x) filename <> "\""
214− | otherwise = x
215− stringToStringBuffer . unlines . map tweak . lines <$> readFileUTF8' out
216−
217−
218−-- | Run a preprocessor on a file
219−runPreprocessor :: DynFlags -> FilePath -> Maybe SB.StringBuffer -> IO SB.StringBuffer
220−runPreprocessor dflags filename contents = withTempDir $ \dir -> do
221− let out = dir </> takeFileName filename <.> "out"
222− inp <- case contents of
223− Nothing -> return filename
224− Just contents -> do
225− let inp = dir </> takeFileName filename <.> "hs"
226− withBinaryFile inp WriteMode $ \h ->
227− hPutStringBuffer h contents
228− return inp
229− runPp dflags [SysTools.Option filename, SysTools.Option inp, SysTools.FileOption "" out]
230− SB.hGetStringBuffer out
src/Development/IDE/Core/Rules.hsdeleted−671
@@ -1,671 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE CPP #-}
5−{-# LANGUAGE TypeFamilies #-}
6−{-# LANGUAGE FlexibleInstances #-}
7−{-# LANGUAGE DuplicateRecordFields #-}
8−#include "ghc-api-version.h"
9−
10−-- | A Shake implementation of the compiler service, built
11−-- using the "Shaker" abstraction layer for in-memory use.
12−--
13−module Development.IDE.Core.Rules(
14− IdeState, GetDependencies(..), GetParsedModule(..), TransitiveDependencies(..),
15− Priority(..), GhcSessionIO(..), GhcSessionFun(..),
16− priorityTypeCheck,
17− priorityGenerateCore,
18− priorityFilesOfInterest,
19− runAction, useE, useNoFileE, usesE,
20− toIdeResult, defineNoFile,
21− mainRule,
22− getAtPoint,
23− getDefinition,
24− getDependencies,
25− getParsedModule,
26− generateCore,
27− ) where
28−
29−import Fingerprint
30−
31−import Data.Binary hiding (get, put)
32−import Data.Bifunctor (first, second)
33−import Control.Monad.Extra
34−import Control.Monad.Trans.Class
35−import Control.Monad.Trans.Maybe
36−import Development.IDE.Core.Compile
37−import Development.IDE.Core.OfInterest
38−import Development.IDE.Types.Options
39−import Development.IDE.Spans.Calculate
40−import Development.IDE.Import.DependencyInformation
41−import Development.IDE.Import.FindImports
42−import Development.IDE.Core.FileExists
43−import Development.IDE.Core.FileStore (getFileContents)
44−import Development.IDE.Types.Diagnostics
45−import Development.IDE.Types.Location
46−import Development.IDE.GHC.Compat hiding (parseModule, typecheckModule)
47−import Development.IDE.GHC.Util
48−import Development.IDE.GHC.WithDynFlags
49−import Data.Either.Extra
50−import Data.Maybe
51−import Data.Foldable
52−import qualified Data.IntMap.Strict as IntMap
53−import Data.IntMap.Strict (IntMap)
54−import Data.List
55−import Data.Ord
56−import qualified Data.Set as Set
57−import qualified Data.Text as T
58−import Development.IDE.GHC.Error
59−import Development.Shake hiding (Diagnostic)
60−import Development.IDE.Core.RuleTypes
61−import Development.IDE.Spans.Type
62−import qualified Data.ByteString.Char8 as BS
63−
64−import qualified GHC.LanguageExtensions as LangExt
65−import HscTypes
66−import PackageConfig
67−import DynFlags (gopt_set, xopt)
68−import GHC.Generics(Generic)
69−
70−import qualified Development.IDE.Spans.AtPoint as AtPoint
71−import Development.IDE.Core.Service
72−import Development.IDE.Core.Shake
73−import Development.Shake.Classes hiding (get, put)
74−import Control.Monad.Trans.Except (runExceptT)
75−import Data.ByteString (ByteString)
76−import Control.Concurrent.Async (concurrently)
77−
78−import Control.Monad.State
79−
80−-- | This is useful for rules to convert rules that can only produce errors or
81−-- a result into the more general IdeResult type that supports producing
82−-- warnings while also producing a result.
83−toIdeResult :: Either [FileDiagnostic] v -> IdeResult v
84−toIdeResult = either (, Nothing) (([],) . Just)
85−
86−-- | useE is useful to implement functions that aren’t rules but need shortcircuiting
87−-- e.g. getDefinition.
88−useE :: IdeRule k v => k -> NormalizedFilePath -> MaybeT Action v
89−useE k = MaybeT . use k
90−
91−useNoFileE :: IdeRule k v => k -> MaybeT Action v
92−useNoFileE k = useE k emptyFilePath
93−
94−usesE :: IdeRule k v => k -> [NormalizedFilePath] -> MaybeT Action [v]
95−usesE k = MaybeT . fmap sequence . uses k
96−
97−defineNoFile :: IdeRule k v => (k -> Action v) -> Rules ()
98−defineNoFile f = define $ \k file -> do
99− if file == emptyFilePath then do res <- f k; return ([], Just res) else
100− fail $ "Rule " ++ show k ++ " should always be called with the empty string for a file"
101−
102−
103−------------------------------------------------------------
104−-- Exposed API
105−
106−-- | Get all transitive file dependencies of a given module.
107−-- Does not include the file itself.
108−getDependencies :: NormalizedFilePath -> Action (Maybe [NormalizedFilePath])
109−getDependencies file = fmap transitiveModuleDeps <$> use GetDependencies file
110−
111−-- | Try to get hover text for the name under point.
112−getAtPoint :: NormalizedFilePath -> Position -> Action (Maybe (Maybe Range, [T.Text]))
113−getAtPoint file pos = fmap join $ runMaybeT $ do
114− opts <- lift getIdeOptions
115− spans <- useE GetSpanInfo file
116− return $ AtPoint.atPoint opts spans pos
117−
118−-- | Goto Definition.
119−getDefinition :: NormalizedFilePath -> Position -> Action (Maybe Location)
120−getDefinition file pos = fmap join $ runMaybeT $ do
121− opts <- lift getIdeOptions
122− spans <- useE GetSpanInfo file
123− lift $ AtPoint.gotoDefinition (getHieFile file) opts (spansExprs spans) pos
124−
125−getHieFile
126− :: NormalizedFilePath -- ^ file we're editing
127− -> Module -- ^ module dep we want info for
128− -> Action (Maybe (HieFile, FilePath)) -- ^ hie stuff for the module
129−getHieFile file mod = do
130− TransitiveDependencies {transitiveNamedModuleDeps} <- use_ GetDependencies file
131− case find (\x -> nmdModuleName x == moduleName mod) transitiveNamedModuleDeps of
132− Just NamedModuleDep{nmdFilePath=nfp} -> do
133− let modPath = fromNormalizedFilePath nfp
134− (_diags, hieFile) <- getHomeHieFile nfp
135− return $ (, modPath) <$> hieFile
136− _ -> getPackageHieFile mod file
137−
138−
139−getHomeHieFile :: NormalizedFilePath -> Action ([a], Maybe HieFile)
140−getHomeHieFile f = do
141− ms <- use_ GetModSummary f
142− let normal_hie_f = toNormalizedFilePath' hie_f
143− hie_f = ml_hie_file $ ms_location ms
144− mbHieTimestamp <- use GetModificationTime normal_hie_f
145− srcTimestamp <- use_ GetModificationTime f
146− let isUpToDate
147− | Just d <- mbHieTimestamp = comparing modificationTime d srcTimestamp == GT
148− | otherwise = False
149−
150− unless isUpToDate $
151− void $ use_ TypeCheck f
152−
153− hf <- liftIO $ whenMaybe isUpToDate (loadHieFile hie_f)
154− return ([], hf)
155−
156−getPackageHieFile :: Module -- ^ Package Module to load .hie file for
157− -> NormalizedFilePath -- ^ Path of home module importing the package module
158− -> Action (Maybe (HieFile, FilePath))
159−getPackageHieFile mod file = do
160− pkgState <- hscEnv <$> use_ GhcSession file
161− IdeOptions {..} <- getIdeOptions
162− let unitId = moduleUnitId mod
163− case lookupPackageConfig unitId pkgState of
164− Just pkgConfig -> do
165− -- 'optLocateHieFile' returns Nothing if the file does not exist
166− hieFile <- liftIO $ optLocateHieFile optPkgLocationOpts pkgConfig mod
167− path <- liftIO $ optLocateSrcFile optPkgLocationOpts pkgConfig mod
168− case (hieFile, path) of
169− (Just hiePath, Just modPath) ->
170− -- deliberately loaded outside the Shake graph
171− -- to avoid dependencies on non-workspace files
172− liftIO $ Just . (, modPath) <$> loadHieFile hiePath
173− _ -> return Nothing
174− _ -> return Nothing
175−
176−-- | Parse the contents of a daml file.
177−getParsedModule :: NormalizedFilePath -> Action (Maybe ParsedModule)
178−getParsedModule file = use GetParsedModule file
179−
180−------------------------------------------------------------
181−-- Rules
182−-- These typically go from key to value and are oracles.
183−
184−priorityTypeCheck :: Priority
185−priorityTypeCheck = Priority 0
186−
187−priorityGenerateCore :: Priority
188−priorityGenerateCore = Priority (-1)
189−
190−priorityFilesOfInterest :: Priority
191−priorityFilesOfInterest = Priority (-2)
192−
193−getParsedModuleRule :: Rules ()
194−getParsedModuleRule = defineEarlyCutoff $ \GetParsedModule file -> do
195− sess <- use_ GhcSession file
196− let hsc = hscEnv sess
197− -- These packages are used when removing PackageImports from a
198− -- parsed module
199− comp_pkgs = mapMaybe (fmap fst . mkImportDirs (hsc_dflags hsc)) (deps sess)
200− opt <- getIdeOptions
201− (_, contents) <- getFileContents file
202−
203− let dflags = hsc_dflags hsc
204− mainParse = getParsedModuleDefinition hsc opt comp_pkgs file contents
205−
206− -- Parse again (if necessary) to capture Haddock parse errors
207− if gopt Opt_Haddock dflags
208− then
209− liftIO mainParse
210− else do
211− let hscHaddock = hsc{hsc_dflags = gopt_set dflags Opt_Haddock}
212− haddockParse = do
213− (_, (!diagsHaddock, _)) <-
214− getParsedModuleDefinition hscHaddock opt comp_pkgs file contents
215− return diagsHaddock
216−
217− ((fingerPrint, (diags, res)), diagsHaddock) <-
218− -- parse twice, with and without Haddocks, concurrently
219− -- we cannot ignore Haddock parse errors because files of
220− -- non-interest are always parsed with Haddocks
221− liftIO $ concurrently mainParse haddockParse
222−
223− return (fingerPrint, (mergeDiagnostics diags diagsHaddock, res))
224−
225−getParsedModuleDefinition :: HscEnv -> IdeOptions -> [PackageName] -> NormalizedFilePath -> Maybe T.Text -> IO (Maybe ByteString, ([FileDiagnostic], Maybe ParsedModule))
226−getParsedModuleDefinition packageState opt comp_pkgs file contents = do
227− (diag, res) <- parseModule opt packageState comp_pkgs (fromNormalizedFilePath file) (fmap textToStringBuffer contents)
228− case res of
229− Nothing -> pure (Nothing, (diag, Nothing))
230− Just (contents, modu) -> do
231− mbFingerprint <- if isNothing $ optShakeFiles opt
232− then pure Nothing
233− else Just . fingerprintToBS <$> fingerprintFromStringBuffer contents
234− pure (mbFingerprint, (diag, Just modu))
235−
236−getLocatedImportsRule :: Rules ()
237−getLocatedImportsRule =
238− define $ \GetLocatedImports file -> do
239− ms <- use_ GetModSummary file
240− let imports = [(False, imp) | imp <- ms_textual_imps ms] ++ [(True, imp) | imp <- ms_srcimps ms]
241− env_eq <- use_ GhcSession file
242− let env = hscEnv env_eq
243− let import_dirs = deps env_eq
244− let dflags = addRelativeImport file (moduleName $ ms_mod ms) $ hsc_dflags env
245− opt <- getIdeOptions
246− (diags, imports') <- fmap unzip $ forM imports $ \(isSource, (mbPkgName, modName)) -> do
247− diagOrImp <- locateModule dflags import_dirs (optExtensions opt) getFileExists modName mbPkgName isSource
248− case diagOrImp of
249− Left diags -> pure (diags, Left (modName, Nothing))
250− Right (FileImport path) -> pure ([], Left (modName, Just path))
251− Right (PackageImport pkgId) -> liftIO $ do
252− diagsOrPkgDeps <- computePackageDeps env pkgId
253− case diagsOrPkgDeps of
254− Left diags -> pure (diags, Right Nothing)
255− Right pkgIds -> pure ([], Right $ Just $ pkgId : pkgIds)
256− let (moduleImports, pkgImports) = partitionEithers imports'
257− case sequence pkgImports of
258− Nothing -> pure (concat diags, Nothing)
259− Just pkgImports -> pure (concat diags, Just (moduleImports, Set.fromList $ concat pkgImports))
260−
261−type RawDepM a = StateT (RawDependencyInformation, IntMap ArtifactsLocation) Action a
262−
263−execRawDepM :: Monad m => StateT (RawDependencyInformation, IntMap a1) m a2 -> m (RawDependencyInformation, IntMap a1)
264−execRawDepM act =
265− execStateT act
266− ( RawDependencyInformation IntMap.empty emptyPathIdMap IntMap.empty
267− , IntMap.empty
268− )
269−
270−-- | Given a target file path, construct the raw dependency results by following
271−-- imports recursively.
272−rawDependencyInformation :: [NormalizedFilePath] -> Action RawDependencyInformation
273−rawDependencyInformation fs = do
274− (rdi, ss) <- execRawDepM (mapM_ go fs)
275− let bm = IntMap.foldrWithKey (updateBootMap rdi) IntMap.empty ss
276− return (rdi { rawBootMap = bm })
277− where
278− go :: NormalizedFilePath -- ^ Current module being processed
279− -> StateT (RawDependencyInformation, IntMap ArtifactsLocation) Action FilePathId
280− go f = do
281− -- First check to see if we have already processed the FilePath
282− -- If we have, just return its Id but don't update any of the state.
283− -- Otherwise, we need to process its imports.
284− checkAlreadyProcessed f $ do
285− al <- lift $ modSummaryToArtifactsLocation f <$> use_ GetModSummary f
286− -- Get a fresh FilePathId for the new file
287− fId <- getFreshFid al
288− -- Adding an edge to the bootmap so we can make sure to
289− -- insert boot nodes before the real files.
290− addBootMap al fId
291− -- Try to parse the imports of the file
292− importsOrErr <- lift $ use GetLocatedImports f
293− case importsOrErr of
294− Nothing -> do
295− -- File doesn't parse so add the module as a failure into the
296− -- dependency information, continue processing the other
297− -- elements in the queue
298− modifyRawDepInfo (insertImport fId (Left ModuleParseError))
299− return fId
300− Just (modImports, pkgImports) -> do
301− -- Get NFPs of the imports which have corresponding files
302− -- Imports either come locally from a file or from a package.
303− let (no_file, with_file) = splitImports modImports
304− (mns, ls) = unzip with_file
305− -- Recursively process all the imports we just learnt about
306− -- and get back a list of their FilePathIds
307− fids <- mapM (go . artifactFilePath) ls
308− -- Associate together the ModuleName with the FilePathId
309− let moduleImports' = map (,Nothing) no_file ++ zip mns (map Just fids)
310− -- Insert into the map the information about this modules
311− -- imports.
312− modifyRawDepInfo $ insertImport fId (Right $ ModuleImports moduleImports' pkgImports)
313− return fId
314−
315−
316− checkAlreadyProcessed :: NormalizedFilePath -> RawDepM FilePathId -> RawDepM FilePathId
317− checkAlreadyProcessed nfp k = do
318− (rawDepInfo, _) <- get
319− maybe k return (lookupPathToId (rawPathIdMap rawDepInfo) nfp)
320−
321− modifyRawDepInfo :: (RawDependencyInformation -> RawDependencyInformation) -> RawDepM ()
322− modifyRawDepInfo f = modify (first f)
323−
324− addBootMap :: ArtifactsLocation -> FilePathId -> RawDepM ()
325− addBootMap al fId =
326− modify (\(rd, ss) -> (rd, if isBootLocation al
327− then IntMap.insert (getFilePathId fId) al ss
328− else ss))
329−
330− getFreshFid :: ArtifactsLocation -> RawDepM FilePathId
331− getFreshFid al = do
332− (rawDepInfo, ss) <- get
333− let (fId, path_map) = getPathId al (rawPathIdMap rawDepInfo)
334− -- Insert the File into the bootmap if it's a boot module
335− let rawDepInfo' = rawDepInfo { rawPathIdMap = path_map }
336− put (rawDepInfo', ss)
337− return fId
338−
339− -- Split in (package imports, local imports)
340− splitImports :: [(Located ModuleName, Maybe ArtifactsLocation)]
341− -> ([Located ModuleName], [(Located ModuleName, ArtifactsLocation)])
342− splitImports = foldr splitImportsLoop ([],[])
343−
344− splitImportsLoop (imp, Nothing) (ns, ls) = (imp:ns, ls)
345− splitImportsLoop (imp, Just artifact) (ns, ls) = (ns, (imp,artifact) : ls)
346−
347− updateBootMap pm boot_mod_id ArtifactsLocation{..} bm =
348− if not artifactIsSource
349− then
350− let msource_mod_id = lookupPathToId (rawPathIdMap pm) (toNormalizedFilePath' $ dropBootSuffix artifactModLocation)
351− in case msource_mod_id of
352− Just source_mod_id -> insertBootId source_mod_id (FilePathId boot_mod_id) bm
353− Nothing -> bm
354− else bm
355−
356− dropBootSuffix :: ModLocation -> FilePath
357− dropBootSuffix (ModLocation (Just hs_src) _ _) = reverse . drop (length @[] "-boot") . reverse $ hs_src
358− dropBootSuffix _ = error "dropBootSuffix"
359−
360−getDependencyInformationRule :: Rules ()
361−getDependencyInformationRule =
362− define $ \GetDependencyInformation file -> do
363− rawDepInfo <- rawDependencyInformation [file]
364− pure ([], Just $ processDependencyInformation rawDepInfo)
365−
366−reportImportCyclesRule :: Rules ()
367−reportImportCyclesRule =
368− define $ \ReportImportCycles file -> fmap (\errs -> if null errs then ([], Just ()) else (errs, Nothing)) $ do
369− DependencyInformation{..} <- use_ GetDependencyInformation file
370− let fileId = pathToId depPathIdMap file
371− case IntMap.lookup (getFilePathId fileId) depErrorNodes of
372− Nothing -> pure []
373− Just errs -> do
374− let cycles = mapMaybe (cycleErrorInFile fileId) (toList errs)
375− -- Convert cycles of files into cycles of module names
376− forM cycles $ \(imp, files) -> do
377− modNames <- forM files $ \fileId -> do
378− let file = idToPath depPathIdMap fileId
379− getModuleName file
380− pure $ toDiag imp $ sort modNames
381− where cycleErrorInFile f (PartOfCycle imp fs)
382− | f `elem` fs = Just (imp, fs)
383− cycleErrorInFile _ _ = Nothing
384− toDiag imp mods = (fp , ShowDiag , ) $ Diagnostic
385− { _range = (_range :: Location -> Range) loc
386− , _severity = Just DsError
387− , _source = Just "Import cycle detection"
388− , _message = "Cyclic module dependency between " <> showCycle mods
389− , _code = Nothing
390− , _relatedInformation = Nothing
391− , _tags = Nothing
392− }
393− where loc = srcSpanToLocation (getLoc imp)
394− fp = toNormalizedFilePath' $ srcSpanToFilename (getLoc imp)
395− getModuleName file = do
396− ms <- use_ GetModSummary file
397− pure (moduleNameString . moduleName . ms_mod $ ms)
398− showCycle mods = T.intercalate ", " (map T.pack mods)
399−
400−-- returns all transitive dependencies in topological order.
401−-- NOTE: result does not include the argument file.
402−getDependenciesRule :: Rules ()
403−getDependenciesRule =
404− defineEarlyCutoff $ \GetDependencies file -> do
405− depInfo <- use_ GetDependencyInformation file
406− let allFiles = reachableModules depInfo
407− _ <- uses_ ReportImportCycles allFiles
408− opts <- getIdeOptions
409− let mbFingerprints = map (fingerprintString . fromNormalizedFilePath) allFiles <$ optShakeFiles opts
410− return (fingerprintToBS . fingerprintFingerprints <$> mbFingerprints, ([], transitiveDeps depInfo file))
411−
412−-- Source SpanInfo is used by AtPoint and Goto Definition.
413−getSpanInfoRule :: Rules ()
414−getSpanInfoRule =
415− define $ \GetSpanInfo file -> do
416− tc <- use_ TypeCheck file
417− packageState <- hscEnv <$> use_ GhcSession file
418− deps <- maybe (TransitiveDependencies [] [] []) fst <$> useWithStale GetDependencies file
419− let tdeps = transitiveModuleDeps deps
420−
421−-- When possible, rely on the haddocks embedded in our interface files
422−-- This creates problems on ghc-lib, see comment on 'getDocumentationTryGhc'
423−#if MIN_GHC_API_VERSION(8,6,0) && !defined(GHC_LIB)
424− let parsedDeps = []
425−#else
426− parsedDeps <- uses_ GetParsedModule tdeps
427−#endif
428−
429− ifaces <- uses_ GetModIface tdeps
430− (fileImports, _) <- use_ GetLocatedImports file
431− let imports = second (fmap artifactFilePath) <$> fileImports
432− x <- liftIO $ getSrcSpanInfos packageState imports tc parsedDeps (map hirModIface ifaces)
433− return ([], Just x)
434−
435−-- Typechecks a module.
436−typeCheckRule :: Rules ()
437−typeCheckRule = define $ \TypeCheck file -> do
438− pm <- use_ GetParsedModule file
439− -- do not generate interface files as this rule is called
440− -- for files of interest on every keystroke
441− typeCheckRuleDefinition file pm SkipGenerationOfInterfaceFiles
442−
443−data GenerateInterfaceFiles
444− = DoGenerateInterfaceFiles
445− | SkipGenerationOfInterfaceFiles
446− deriving (Show)
447−
448−-- This is factored out so it can be directly called from the GetModIface
449−-- rule. Directly calling this rule means that on the initial load we can
450−-- garbage collect all the intermediate typechecked modules rather than
451−-- retain the information forever in the shake graph.
452−typeCheckRuleDefinition
453− :: NormalizedFilePath -- ^ Path to source file
454− -> ParsedModule
455− -> GenerateInterfaceFiles -- ^ Should generate .hi and .hie files ?
456− -> Action (IdeResult TcModuleResult)
457−typeCheckRuleDefinition file pm generateArtifacts = do
458− deps <- use_ GetDependencies file
459− hsc <- hscEnv <$> use_ GhcSession file
460− -- Figure out whether we need TemplateHaskell or QuasiQuotes support
461− let graph_needs_th_qq = needsTemplateHaskellOrQQ $ hsc_mod_graph hsc
462− file_uses_th_qq = uses_th_qq $ ms_hspp_opts (pm_mod_summary pm)
463− any_uses_th_qq = graph_needs_th_qq || file_uses_th_qq
464− mirs <- uses_ GetModIface (transitiveModuleDeps deps)
465− bytecodes <- if any_uses_th_qq
466− then -- If we use TH or QQ, we must obtain the bytecode
467− fmap Just <$> uses_ GenerateByteCode (transitiveModuleDeps deps)
468− else
469− pure $ repeat Nothing
470−
471− setPriority priorityTypeCheck
472− IdeOptions { optDefer = defer } <- getIdeOptions
473−
474− addUsageDependencies $ liftIO $ do
475− res <- typecheckModule defer hsc (zipWith unpack mirs bytecodes) pm
476− case res of
477− (diags, Just (hsc,tcm)) | DoGenerateInterfaceFiles <- generateArtifacts -> do
478− diagsHie <- generateAndWriteHieFile hsc (tmrModule tcm)
479− diagsHi <- generateAndWriteHiFile hsc tcm
480− return (diags <> diagsHi <> diagsHie, Just tcm)
481− (diags, res) ->
482− return (diags, snd <$> res)
483− where
484− unpack HiFileResult{..} bc = (hirModSummary, (hirModIface, bc))
485− uses_th_qq dflags =
486− xopt LangExt.TemplateHaskell dflags || xopt LangExt.QuasiQuotes dflags
487−
488− addUsageDependencies :: Action (a, Maybe TcModuleResult) -> Action (a, Maybe TcModuleResult)
489− addUsageDependencies a = do
490− r@(_, mtc) <- a
491− forM_ mtc $ \tc -> do
492− let used_files = mapMaybe udep (mi_usages (hm_iface (tmrModInfo tc)))
493− udep (UsageFile fp _h) = Just fp
494− udep _ = Nothing
495− -- Add a dependency on these files which are added by things like
496− -- qAddDependentFile
497− void $ uses_ GetModificationTime (map toNormalizedFilePath' used_files)
498− return r
499−
500−
501−generateCore :: RunSimplifier -> NormalizedFilePath -> Action (IdeResult (SafeHaskellMode, CgGuts, ModDetails))
502−generateCore runSimplifier file = do
503− deps <- use_ GetDependencies file
504− (tm:tms) <- uses_ TypeCheck (file:transitiveModuleDeps deps)
505− setPriority priorityGenerateCore
506− packageState <- hscEnv <$> use_ GhcSession file
507− liftIO $ compileModule runSimplifier packageState [(tmrModSummary x, tmrModInfo x) | x <- tms] tm
508−
509−generateCoreRule :: Rules ()
510−generateCoreRule =
511− define $ \GenerateCore -> generateCore (RunSimplifier True)
512−
513−generateByteCodeRule :: Rules ()
514−generateByteCodeRule =
515− define $ \GenerateByteCode file -> do
516− deps <- use_ GetDependencies file
517− (tm : tms) <- uses_ TypeCheck (file: transitiveModuleDeps deps)
518− session <- hscEnv <$> use_ GhcSession file
519− (_, guts, _) <- use_ GenerateCore file
520− liftIO $ generateByteCode session [(tmrModSummary x, tmrModInfo x) | x <- tms] tm guts
521−
522−-- A local rule type to get caching. We want to use newCache, but it has
523−-- thread killed exception issues, so we lift it to a full rule.
524−-- https://github.com/digital-asset/daml/pull/2808#issuecomment-529639547
525−type instance RuleResult GhcSessionIO = GhcSessionFun
526−
527−data GhcSessionIO = GhcSessionIO deriving (Eq, Show, Typeable, Generic)
528−instance Hashable GhcSessionIO
529−instance NFData GhcSessionIO
530−instance Binary GhcSessionIO
531−
532−newtype GhcSessionFun = GhcSessionFun (FilePath -> Action (IdeResult HscEnvEq))
533−instance Show GhcSessionFun where show _ = "GhcSessionFun"
534−instance NFData GhcSessionFun where rnf !_ = ()
535−
536−
537−loadGhcSession :: Rules ()
538−loadGhcSession = do
539− defineNoFile $ \GhcSessionIO -> do
540− opts <- getIdeOptions
541− GhcSessionFun <$> optGhcSession opts
542− -- This function should always be rerun because it consults a cache to
543− -- see what HscEnv needs to be used for the file, which can change.
544− -- However, it should also cut-off early if it's the same HscEnv as
545− -- last time
546− defineEarlyCutoff $ \GhcSession file -> do
547− GhcSessionFun fun <- useNoFile_ GhcSessionIO
548− alwaysRerun
549− val <- fun $ fromNormalizedFilePath file
550−
551− -- TODO: What was this doing before?
552− opts <- getIdeOptions
553− let cutoffHash =
554− case optShakeFiles opts of
555− -- optShakeFiles is only set in the DAML case.
556− -- https://github.com/digital-asset/ghcide/pull/522#discussion_r428622915
557− Just {} -> ""
558− -- Hash the HscEnvEq returned so cutoff if it didn't change
559− -- from last time
560− Nothing -> BS.pack (show (hash (snd val)))
561− return (Just cutoffHash, val)
562−
563−getHiFileRule :: Rules ()
564−getHiFileRule = defineEarlyCutoff $ \GetHiFile f -> do
565− -- get all dependencies interface files, to check for freshness
566− (deps,_) <- use_ GetLocatedImports f
567− depHis <- traverse (use GetHiFile) (mapMaybe (fmap artifactFilePath . snd) deps)
568−
569− ms <- use_ GetModSummary f
570− let hiFile = toNormalizedFilePath'
571− $ case ms_hsc_src ms of
572− HsBootFile -> addBootSuffix (ml_hi_file $ ms_location ms)
573− _ -> ml_hi_file $ ms_location ms
574−
575− case sequence depHis of
576− Nothing -> pure (Nothing, ([], Nothing))
577− Just deps -> do
578− gotHiFile <- getFileExists hiFile
579− if not gotHiFile
580− then pure (Nothing, ([], Nothing))
581− else do
582− hiVersion <- use_ GetModificationTime hiFile
583− modVersion <- use_ GetModificationTime f
584− let sourceModified = modificationTime hiVersion < modificationTime modVersion
585− if sourceModified
586− then do
587− pure (Nothing, ([], Nothing))
588− else do
589− session <- hscEnv <$> use_ GhcSession f
590− r <- liftIO $ loadInterface session ms deps
591− case r of
592− Right iface -> do
593− let result = HiFileResult ms iface
594− return (Just (fingerprintToBS (getModuleHash iface)), ([], Just result))
595− Left err -> do
596− let diag = ideErrorWithSource (Just "interface file loading") (Just DsError) f . T.pack $ err
597− return (Nothing, (pure diag, Nothing))
598−
599−getModSummaryRule :: Rules ()
600−getModSummaryRule = define $ \GetModSummary f -> do
601− dflags <- hsc_dflags . hscEnv <$> use_ GhcSession f
602− (_, mFileContent) <- getFileContents f
603− modS <- liftIO $ evalWithDynFlags dflags $ runExceptT $
604− getModSummaryFromImports (fromNormalizedFilePath f) (textToStringBuffer <$> mFileContent)
605− return $ either (,Nothing) (([], ) . Just) modS
606−
607−getModIfaceRule :: Rules ()
608−getModIfaceRule = define $ \GetModIface f -> do
609− fileOfInterest <- use_ IsFileOfInterest f
610− let useHiFile =
611− -- Never load interface files for files of interest
612− not fileOfInterest
613− mbHiFile <- if useHiFile then use GetHiFile f else return Nothing
614− case mbHiFile of
615− Just x ->
616− return ([], Just x)
617− Nothing
618− | fileOfInterest -> do
619− -- For files of interest only, create a Shake dependency on typecheck
620− tmr <- use TypeCheck f
621− return ([], extract tmr)
622− | otherwise -> do
623− -- the interface file does not exist or is out of date.
624− -- Invoke typechecking directly to update it without incurring a dependency
625− -- on the parsed module and the typecheck rules
626− sess <- use_ GhcSession f
627− let hsc = hscEnv sess
628− -- After parsing the module remove all package imports referring to
629− -- these packages as we have already dealt with what they map to.
630− comp_pkgs = mapMaybe (fmap fst . mkImportDirs (hsc_dflags hsc)) (deps sess)
631− opt <- getIdeOptions
632− (_, contents) <- getFileContents f
633− -- Embed --haddocks in the interface file
634− hsc <- pure hsc{hsc_dflags = gopt_set (hsc_dflags hsc) Opt_Haddock}
635− (_, (diags, mb_pm)) <- liftIO $ getParsedModuleDefinition hsc opt comp_pkgs f contents
636− case mb_pm of
637− Nothing -> return (diags, Nothing)
638− Just pm -> do
639− (diags', tmr) <- typeCheckRuleDefinition f pm DoGenerateInterfaceFiles
640− -- Bang pattern is important to avoid leaking 'tmr'
641− let !res = extract tmr
642− return (diags <> diags', res)
643− where
644− extract Nothing = Nothing
645− extract (Just tmr) =
646− -- Bang patterns are important to force the inner fields
647− Just $! HiFileResult (tmrModSummary tmr) (hm_iface $ tmrModInfo tmr)
648−
649−isFileOfInterestRule :: Rules ()
650−isFileOfInterestRule = defineEarlyCutoff $ \IsFileOfInterest f -> do
651− filesOfInterest <- getFilesOfInterest
652− let res = f `elem` filesOfInterest
653− return (Just (if res then "1" else ""), ([], Just res))
654−
655−-- | A rule that wires per-file rules together
656−mainRule :: Rules ()
657−mainRule = do
658− getParsedModuleRule
659− getLocatedImportsRule
660− getDependencyInformationRule
661− reportImportCyclesRule
662− getDependenciesRule
663− typeCheckRule
664− getSpanInfoRule
665− generateCoreRule
666− generateByteCodeRule
667− loadGhcSession
668− getHiFileRule
669− getModIfaceRule
670− isFileOfInterestRule
671− getModSummaryRule
src/Development/IDE/Core/Service.hsdeleted−107
@@ -1,107 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE TypeFamilies #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−
7−-- | A Shake implementation of the compiler service, built
8−-- using the "Shaker" abstraction layer for in-memory use.
9−--
10−module Development.IDE.Core.Service(
11− getIdeOptions,
12− IdeState, initialise, shutdown,
13− runAction,
14− runActionSync,
15− writeProfile,
16− getDiagnostics, unsafeClearDiagnostics,
17− ideLogger,
18− updatePositionMapping,
19− ) where
20−
21−import Control.Concurrent.Extra
22−import Control.Concurrent.Async
23−import Data.Maybe
24−import Development.IDE.Types.Options (IdeOptions(..))
25−import Control.Monad
26−import Development.IDE.Core.Debouncer
27−import Development.IDE.Core.FileStore (VFSHandle, fileStoreRules)
28−import Development.IDE.Core.FileExists (fileExistsRules)
29−import Development.IDE.Core.OfInterest
30−import Development.IDE.Types.Logger
31−import Development.Shake
32−import Data.Either.Extra
33−import qualified Language.Haskell.LSP.Messages as LSP
34−import qualified Language.Haskell.LSP.Types as LSP
35−import qualified Language.Haskell.LSP.Types.Capabilities as LSP
36−
37−import Development.IDE.Core.Shake
38−
39−
40−
41−newtype GlobalIdeOptions = GlobalIdeOptions IdeOptions
42−instance IsIdeGlobal GlobalIdeOptions
43−
44−------------------------------------------------------------
45−-- Exposed API
46−
47−-- | Initialise the Compiler Service.
48−initialise :: LSP.ClientCapabilities
49− -> Rules ()
50− -> IO LSP.LspId
51− -> (LSP.FromServerMessage -> IO ())
52− -> Logger
53− -> Debouncer LSP.NormalizedUri
54− -> IdeOptions
55− -> VFSHandle
56− -> IO IdeState
57−initialise caps mainRule getLspId toDiags logger debouncer options vfs =
58− shakeOpen
59− getLspId
60− toDiags
61− logger
62− debouncer
63− (optShakeProfiling options)
64− (optReportProgress options)
65− shakeOptions
66− { shakeThreads = optThreads options
67− , shakeFiles = fromMaybe "/dev/null" (optShakeFiles options)
68− } $ do
69− addIdeGlobal $ GlobalIdeOptions options
70− fileStoreRules vfs
71− ofInterestRules
72− fileExistsRules getLspId caps vfs
73− mainRule
74−
75−writeProfile :: IdeState -> FilePath -> IO ()
76−writeProfile = shakeProfile
77−
78−-- | Shutdown the Compiler Service.
79−shutdown :: IdeState -> IO ()
80−shutdown = shakeShut
81−
82−-- This will return as soon as the result of the action is
83−-- available. There might still be other rules running at this point,
84−-- e.g., the ofInterestRule.
85−runAction :: IdeState -> Action a -> IO a
86−runAction ide action = do
87− bar <- newBarrier
88− res <- shakeRun ide [do v <- action; liftIO $ signalBarrier bar v; return v]
89− -- shakeRun might throw an exception (either through action or a default rule),
90− -- in which case action may not complete successfully, and signalBarrier might not be called.
91− -- Therefore we wait for either res (which propagates the exception) or the barrier.
92− -- Importantly, if the barrier does finish, cancelling res only kills waiting for the result,
93− -- it doesn't kill the actual work
94− fmap fromEither $ race (head <$> res) $ waitBarrier bar
95−
96−
97−-- | `runActionSync` is similar to `runAction` but it will
98−-- wait for all rules (so in particular the `ofInterestRule`) to
99−-- finish running. This is mainly useful in tests, where you want
100−-- to wait for all rules to fire so you can check diagnostics.
101−runActionSync :: IdeState -> Action a -> IO a
102−runActionSync s act = fmap head $ join $ shakeRun s [act]
103−
104−getIdeOptions :: Action IdeOptions
105−getIdeOptions = do
106− GlobalIdeOptions x <- getIdeGlobalAction
107− return x
src/Development/IDE/Core/Shake.hsdeleted−849
@@ -1,849 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE ExistentialQuantification #-}
5−{-# LANGUAGE TypeFamilies #-}
6−{-# LANGUAGE ConstraintKinds #-}
7−
8−-- | A Shake implementation of the compiler service.
9−--
10−-- There are two primary locations where data lives, and both of
11−-- these contain much the same data:
12−--
13−-- * The Shake database (inside 'shakeDb') stores a map of shake keys
14−-- to shake values. In our case, these are all of type 'Q' to 'A'.
15−-- During a single run all the values in the Shake database are consistent
16−-- so are used in conjunction with each other, e.g. in 'uses'.
17−--
18−-- * The 'Values' type stores a map of keys to values. These values are
19−-- always stored as real Haskell values, whereas Shake serialises all 'A' values
20−-- between runs. To deserialise a Shake value, we just consult Values.
21−module Development.IDE.Core.Shake(
22− IdeState, shakeExtras,
23− ShakeExtras(..), getShakeExtras, getShakeExtrasRules,
24− IdeRule, IdeResult, GetModificationTime(..),
25− shakeOpen, shakeShut,
26− shakeRun,
27− shakeProfile,
28− use, useWithStale, useNoFile, uses, usesWithStale,
29− use_, useNoFile_, uses_,
30− define, defineEarlyCutoff, defineOnDisk, needOnDisk, needOnDisks,
31− getDiagnostics, unsafeClearDiagnostics,
32− getHiddenDiagnostics,
33− IsIdeGlobal, addIdeGlobal, addIdeGlobalExtras, getIdeGlobalState, getIdeGlobalAction,
34− garbageCollect,
35− setPriority,
36− sendEvent,
37− ideLogger,
38− actionLogger,
39− FileVersion(..), modificationTime,
40− Priority(..),
41− updatePositionMapping,
42− deleteValue,
43− OnDiskRule(..),
44− ) where
45−
46−import Development.Shake hiding (ShakeValue, doesFileExist)
47−import Development.Shake.Database
48−import Development.Shake.Classes
49−import Development.Shake.Rule
50−import qualified Data.HashMap.Strict as HMap
51−import qualified Data.Map.Strict as Map
52−import qualified Data.ByteString.Char8 as BS
53−import Data.Dynamic
54−import Data.Maybe
55−import Data.Map.Strict (Map)
56−import Data.List.Extra (partition, takeEnd)
57−import qualified Data.Set as Set
58−import qualified Data.Text as T
59−import Data.Traversable (for)
60−import Data.Tuple.Extra
61−import Data.Unique
62−import Development.IDE.Core.Debouncer
63−import Development.IDE.Core.PositionMapping
64−import Development.IDE.Types.Logger hiding (Priority)
65−import Language.Haskell.LSP.Diagnostics
66−import qualified Data.SortedList as SL
67−import Development.IDE.Types.Diagnostics
68−import Development.IDE.Types.Location
69−import Development.IDE.Types.Options
70−import Control.Concurrent.Async
71−import Control.Concurrent.Extra
72−import Control.Exception.Extra
73−import Control.DeepSeq
74−import System.Time.Extra
75−import Data.Typeable
76−import qualified Language.Haskell.LSP.Messages as LSP
77−import qualified Language.Haskell.LSP.Types as LSP
78−import System.FilePath hiding (makeRelative)
79−import qualified Development.Shake as Shake
80−import Control.Monad.Extra
81−import Data.Time
82−import GHC.Generics
83−import System.IO.Unsafe
84−import Numeric.Extra
85−import Language.Haskell.LSP.Types
86−
87−
88−-- information we stash inside the shakeExtra field
89−data ShakeExtras = ShakeExtras
90− {eventer :: LSP.FromServerMessage -> IO ()
91− ,debouncer :: Debouncer NormalizedUri
92− ,logger :: Logger
93− ,globals :: Var (HMap.HashMap TypeRep Dynamic)
94− ,state :: Var Values
95− ,diagnostics :: Var DiagnosticStore
96− ,hiddenDiagnostics :: Var DiagnosticStore
97− ,publishedDiagnostics :: Var (HMap.HashMap NormalizedUri [Diagnostic])
98− -- ^ This represents the set of diagnostics that we have published.
99− -- Due to debouncing not every change might get published.
100− ,positionMapping :: Var (HMap.HashMap NormalizedUri (Map TextDocumentVersion (PositionDelta, PositionMapping)))
101− -- ^ Map from a text document version to a PositionMapping that describes how to map
102− -- positions in a version of that document to positions in the latest version
103− -- First mapping is delta from previous version and second one is an
104− -- accumlation of all previous mappings.
105− ,inProgress :: Var (HMap.HashMap NormalizedFilePath Int)
106− -- ^ How many rules are running for each file
107− }
108−
109−getShakeExtras :: Action ShakeExtras
110−getShakeExtras = do
111− Just x <- getShakeExtra @ShakeExtras
112− return x
113−
114−getShakeExtrasRules :: Rules ShakeExtras
115−getShakeExtrasRules = do
116− Just x <- getShakeExtraRules @ShakeExtras
117− return x
118−
119−class Typeable a => IsIdeGlobal a where
120−
121−addIdeGlobal :: IsIdeGlobal a => a -> Rules ()
122−addIdeGlobal x = do
123− extras <- getShakeExtrasRules
124− liftIO $ addIdeGlobalExtras extras x
125−
126−addIdeGlobalExtras :: IsIdeGlobal a => ShakeExtras -> a -> IO ()
127−addIdeGlobalExtras ShakeExtras{globals} x@(typeOf -> ty) =
128− liftIO $ modifyVar_ globals $ \mp -> case HMap.lookup ty mp of
129− Just _ -> errorIO $ "Internal error, addIdeGlobalExtras, got the same type twice for " ++ show ty
130− Nothing -> return $! HMap.insert ty (toDyn x) mp
131−
132−
133−getIdeGlobalExtras :: forall a . IsIdeGlobal a => ShakeExtras -> IO a
134−getIdeGlobalExtras ShakeExtras{globals} = do
135− let typ = typeRep (Proxy :: Proxy a)
136− x <- HMap.lookup (typeRep (Proxy :: Proxy a)) <$> readVar globals
137− case x of
138− Just x
139− | Just x <- fromDynamic x -> pure x
140− | otherwise -> errorIO $ "Internal error, getIdeGlobalExtras, wrong type for " ++ show typ ++ " (got " ++ show (dynTypeRep x) ++ ")"
141− Nothing -> errorIO $ "Internal error, getIdeGlobalExtras, no entry for " ++ show typ
142−
143−getIdeGlobalAction :: forall a . IsIdeGlobal a => Action a
144−getIdeGlobalAction = liftIO . getIdeGlobalExtras =<< getShakeExtras
145−
146−getIdeGlobalState :: forall a . IsIdeGlobal a => IdeState -> IO a
147−getIdeGlobalState = getIdeGlobalExtras . shakeExtras
148−
149−
150−-- | The state of the all values.
151−type Values = HMap.HashMap (NormalizedFilePath, Key) (Value Dynamic)
152−
153−-- | Key type
154−data Key = forall k . (Typeable k, Hashable k, Eq k, Show k) => Key k
155−
156−instance Show Key where
157− show (Key k) = show k
158−
159−instance Eq Key where
160− Key k1 == Key k2 | Just k2' <- cast k2 = k1 == k2'
161− | otherwise = False
162−
163−instance Hashable Key where
164− hashWithSalt salt (Key key) = hashWithSalt salt (typeOf key, key)
165−
166−-- | The result of an IDE operation. Warnings and errors are in the Diagnostic,
167−-- and a value is in the Maybe. For operations that throw an error you
168−-- expect a non-empty list of diagnostics, at least one of which is an error,
169−-- and a Nothing. For operations that succeed you expect perhaps some warnings
170−-- and a Just. For operations that depend on other failing operations you may
171−-- get empty diagnostics and a Nothing, to indicate this phase throws no fresh
172−-- errors but still failed.
173−--
174−
175−data Value v
176− = Succeeded TextDocumentVersion v
177− | Stale TextDocumentVersion v
178− | Failed
179− deriving (Functor, Generic, Show)
180−
181−instance NFData v => NFData (Value v)
182−
183−-- | Convert a Value to a Maybe. This will only return `Just` for
184−-- up2date results not for stale values.
185−currentValue :: Value v -> Maybe v
186−currentValue (Succeeded _ v) = Just v
187−currentValue (Stale _ _) = Nothing
188−currentValue Failed = Nothing
189−
190−-- | Return the most recent, potentially stale, value and a PositionMapping
191−-- for the version of that value.
192−lastValue :: NormalizedFilePath -> Value v -> Action (Maybe (v, PositionMapping))
193−lastValue file v = do
194− ShakeExtras{positionMapping} <- getShakeExtras
195− allMappings <- liftIO $ readVar positionMapping
196− pure $ case v of
197− Succeeded ver v -> Just (v, mappingForVersion allMappings file ver)
198− Stale ver v -> Just (v, mappingForVersion allMappings file ver)
199− Failed -> Nothing
200−
201−valueVersion :: Value v -> Maybe TextDocumentVersion
202−valueVersion = \case
203− Succeeded ver _ -> Just ver
204− Stale ver _ -> Just ver
205− Failed -> Nothing
206−
207−mappingForVersion
208− :: HMap.HashMap NormalizedUri (Map TextDocumentVersion (a, PositionMapping))
209− -> NormalizedFilePath
210− -> TextDocumentVersion
211− -> PositionMapping
212−mappingForVersion allMappings file ver =
213− maybe zeroMapping snd $
214− Map.lookup ver =<<
215− HMap.lookup (filePathToUri' file) allMappings
216−
217−type IdeRule k v =
218− ( Shake.RuleResult k ~ v
219− , Shake.ShakeValue k
220− , Show v
221− , Typeable v
222− , NFData v
223− )
224−
225−-- | A Shake database plus persistent store. Can be thought of as storing
226−-- mappings from @(FilePath, k)@ to @RuleResult k@.
227−data IdeState = IdeState
228− {shakeDb :: ShakeDatabase
229− ,shakeAbort :: MVar (IO ()) -- close whoever was running last
230− ,shakeClose :: IO ()
231− ,shakeExtras :: ShakeExtras
232− ,shakeProfileDir :: Maybe FilePath
233− }
234−
235−
236−-- This is debugging code that generates a series of profiles, if the Boolean is true
237−shakeRunDatabaseProfile :: Maybe FilePath -> ShakeDatabase -> [Action a] -> IO ([a], Maybe FilePath)
238−shakeRunDatabaseProfile mbProfileDir shakeDb acts = do
239− (time, (res,_)) <- duration $ shakeRunDatabase shakeDb acts
240− proFile <- for mbProfileDir $ \dir -> do
241− count <- modifyVar profileCounter $ \x -> let !y = x+1 in return (y,y)
242− let file = "ide-" ++ profileStartTime ++ "-" ++ takeEnd 5 ("0000" ++ show count) ++ "-" ++ showDP 2 time <.> "html"
243− shakeProfileDatabase shakeDb $ dir </> file
244− return (dir </> file)
245− return (res, proFile)
246−
247−{-# NOINLINE profileStartTime #-}
248−profileStartTime :: String
249−profileStartTime = unsafePerformIO $ formatTime defaultTimeLocale "%Y%m%d-%H%M%S" <$> getCurrentTime
250−
251−{-# NOINLINE profileCounter #-}
252−profileCounter :: Var Int
253−profileCounter = unsafePerformIO $ newVar 0
254−
255−setValues :: IdeRule k v
256− => Var Values
257− -> k
258− -> NormalizedFilePath
259− -> Value v
260− -> IO ()
261−setValues state key file val = modifyVar_ state $ \vals -> do
262− -- Force to make sure the old HashMap is not retained
263− evaluate $ HMap.insert (file, Key key) (fmap toDyn val) vals
264−
265−-- | Delete the value stored for a given ide build key
266−deleteValue
267− :: (Typeable k, Hashable k, Eq k, Show k)
268− => IdeState
269− -> k
270− -> NormalizedFilePath
271− -> IO ()
272−deleteValue IdeState{shakeExtras = ShakeExtras{state}} key file = modifyVar_ state $ \vals ->
273− evaluate $ HMap.delete (file, Key key) vals
274−
275−-- | We return Nothing if the rule has not run and Just Failed if it has failed to produce a value.
276−getValues :: forall k v. IdeRule k v => Var Values -> k -> NormalizedFilePath -> IO (Maybe (Value v))
277−getValues state key file = do
278− vs <- readVar state
279− case HMap.lookup (file, Key key) vs of
280− Nothing -> pure Nothing
281− Just v -> do
282− let r = fmap (fromJust . fromDynamic @v) v
283− -- Force to make sure we do not retain a reference to the HashMap
284− -- and we blow up immediately if the fromJust should fail
285− -- (which would be an internal error).
286− evaluate (r `seqValue` Just r)
287−
288−-- | Seq the result stored in the Shake value. This only
289−-- evaluates the value to WHNF not NF. We take care of the latter
290−-- elsewhere and doing it twice is expensive.
291−seqValue :: Value v -> b -> b
292−seqValue v b = case v of
293− Succeeded ver v -> rnf ver `seq` v `seq` b
294− Stale ver v -> rnf ver `seq` v `seq` b
295− Failed -> b
296−
297−-- | Open a 'IdeState', should be shut using 'shakeShut'.
298−shakeOpen :: IO LSP.LspId
299− -> (LSP.FromServerMessage -> IO ()) -- ^ diagnostic handler
300− -> Logger
301− -> Debouncer NormalizedUri
302− -> Maybe FilePath
303− -> IdeReportProgress
304− -> ShakeOptions
305− -> Rules ()
306− -> IO IdeState
307−shakeOpen getLspId eventer logger debouncer shakeProfileDir (IdeReportProgress reportProgress) opts rules = do
308− inProgress <- newVar HMap.empty
309− shakeExtras <- do
310− globals <- newVar HMap.empty
311− state <- newVar HMap.empty
312− diagnostics <- newVar mempty
313− hiddenDiagnostics <- newVar mempty
314− publishedDiagnostics <- newVar mempty
315− positionMapping <- newVar HMap.empty
316− pure ShakeExtras{..}
317− (shakeDb, shakeClose) <-
318− shakeOpenDatabase
319− opts
320− { shakeExtra = addShakeExtra shakeExtras $ shakeExtra opts
321− -- we don't actually use the progress value, but Shake conveniently spawns/kills this thread whenever
322− -- we call into Shake, so abuse it for that purpose
323− , shakeProgress = const $ if reportProgress then lspShakeProgress getLspId eventer inProgress else pure ()
324− }
325− rules
326− shakeAbort <- newMVar $ return ()
327− shakeDb <- shakeDb
328− return IdeState{..}
329−
330−lspShakeProgress :: Hashable a => IO LSP.LspId -> (LSP.FromServerMessage -> IO ()) -> Var (HMap.HashMap a Int) -> IO ()
331−lspShakeProgress getLspId sendMsg inProgress = do
332− -- first sleep a bit, so we only show progress messages if it's going to take
333− -- a "noticable amount of time" (we often expect a thread kill to arrive before the sleep finishes)
334− sleep 0.1
335− lspId <- getLspId
336− u <- ProgressTextToken . T.pack . show . hashUnique <$> newUnique
337− sendMsg $ LSP.ReqWorkDoneProgressCreate $ LSP.fmServerWorkDoneProgressCreateRequest
338− lspId $ LSP.WorkDoneProgressCreateParams
339− { _token = u }
340− bracket_ (start u) (stop u) (loop u Nothing)
341− where
342− start id = sendMsg $ LSP.NotWorkDoneProgressBegin $ LSP.fmServerWorkDoneProgressBeginNotification
343− LSP.ProgressParams
344− { _token = id
345− , _value = WorkDoneProgressBeginParams
346− { _title = "Processing"
347− , _cancellable = Nothing
348− , _message = Nothing
349− , _percentage = Nothing
350− }
351− }
352− stop id = sendMsg $ LSP.NotWorkDoneProgressEnd $ LSP.fmServerWorkDoneProgressEndNotification
353− LSP.ProgressParams
354− { _token = id
355− , _value = WorkDoneProgressEndParams
356− { _message = Nothing
357− }
358− }
359− sample = 0.1
360− loop id prev = do
361− sleep sample
362− current <- readVar inProgress
363− let done = length $ filter (== 0) $ HMap.elems current
364− let todo = HMap.size current
365− let next = Just $ T.pack $ show done <> "/" <> show todo
366− when (next /= prev) $
367− sendMsg $ LSP.NotWorkDoneProgressReport $ LSP.fmServerWorkDoneProgressReportNotification
368− LSP.ProgressParams
369− { _token = id
370− , _value = LSP.WorkDoneProgressReportParams
371− { _cancellable = Nothing
372− , _message = next
373− , _percentage = Nothing
374− }
375− }
376− loop id next
377−
378−shakeProfile :: IdeState -> FilePath -> IO ()
379−shakeProfile IdeState{..} = shakeProfileDatabase shakeDb
380−
381−shakeShut :: IdeState -> IO ()
382−shakeShut IdeState{..} = withMVar shakeAbort $ \stop -> do
383− -- Shake gets unhappy if you try to close when there is a running
384− -- request so we first abort that.
385− stop
386− shakeClose
387−
388−-- | This is a variant of withMVar where the first argument is run unmasked and if it throws
389−-- an exception, the previous value is restored while the second argument is executed masked.
390−withMVar' :: MVar a -> (a -> IO ()) -> IO (a, c) -> IO c
391−withMVar' var unmasked masked = mask $ \restore -> do
392− a <- takeMVar var
393− restore (unmasked a) `onException` putMVar var a
394− (a', c) <- masked
395− putMVar var a'
396− pure c
397−
398−-- | Spawn immediately. If you are already inside a call to shakeRun that will be aborted with an exception.
399−shakeRun :: IdeState -> [Action a] -> IO (IO [a])
400−shakeRun IdeState{shakeExtras=ShakeExtras{..}, ..} acts =
401− withMVar'
402− shakeAbort
403− (\stop -> do
404− (stopTime,_) <- duration stop
405− logDebug logger $ T.pack $ "Starting shakeRun (aborting the previous one took " ++ showDuration stopTime ++ ")"
406− )
407− -- It is crucial to be masked here, otherwise we can get killed
408− -- between spawning the new thread and updating shakeAbort.
409− -- See https://github.com/digital-asset/ghcide/issues/79
410− (do
411− start <- offsetTime
412− aThread <- asyncWithUnmask $ \restore -> do
413− res <- try (restore $ shakeRunDatabaseProfile shakeProfileDir shakeDb acts)
414− runTime <- start
415− let res' = case res of
416− Left e -> "exception: " <> displayException e
417− Right _ -> "completed"
418− profile = case res of
419− Right (_, Just fp) ->
420− let link = case filePathToUri' $ toNormalizedFilePath' fp of
421− NormalizedUri _ x -> x
422− in ", profile saved at " <> T.unpack link
423− _ -> ""
424− let logMsg = logDebug logger $ T.pack $
425− "Finishing shakeRun (took " ++ showDuration runTime ++ ", " ++ res' ++ profile ++ ")"
426− return (fst <$> res, logMsg)
427− let wrapUp (res, _) = do
428− either (throwIO @SomeException) return res
429− _ <- async $ do
430− (_, logMsg) <- wait aThread
431− logMsg
432− pure (cancel aThread, wrapUp =<< wait aThread))
433−
434−getDiagnostics :: IdeState -> IO [FileDiagnostic]
435−getDiagnostics IdeState{shakeExtras = ShakeExtras{diagnostics}} = do
436− val <- readVar diagnostics
437− return $ getAllDiagnostics val
438−
439−getHiddenDiagnostics :: IdeState -> IO [FileDiagnostic]
440−getHiddenDiagnostics IdeState{shakeExtras = ShakeExtras{hiddenDiagnostics}} = do
441− val <- readVar hiddenDiagnostics
442− return $ getAllDiagnostics val
443−
444−-- | FIXME: This function is temporary! Only required because the files of interest doesn't work
445−unsafeClearDiagnostics :: IdeState -> IO ()
446−unsafeClearDiagnostics IdeState{shakeExtras = ShakeExtras{diagnostics}} =
447− writeVar diagnostics mempty
448−
449−-- | Clear the results for all files that do not match the given predicate.
450−garbageCollect :: (NormalizedFilePath -> Bool) -> Action ()
451−garbageCollect keep = do
452− ShakeExtras{state, diagnostics,hiddenDiagnostics,publishedDiagnostics,positionMapping} <- getShakeExtras
453− liftIO $
454− do newState <- modifyVar state $ \values -> do
455− values <- evaluate $ HMap.filterWithKey (\(file, _) _ -> keep file) values
456− return $! dupe values
457− modifyVar_ diagnostics $ \diags -> return $! filterDiagnostics keep diags
458− modifyVar_ hiddenDiagnostics $ \hdiags -> return $! filterDiagnostics keep hdiags
459− modifyVar_ publishedDiagnostics $ \diags -> return $! HMap.filterWithKey (\uri _ -> keep (fromUri uri)) diags
460− let versionsForFile =
461− HMap.fromListWith Set.union $
462− mapMaybe (\((file, _key), v) -> (filePathToUri' file,) . Set.singleton <$> valueVersion v) $
463− HMap.toList newState
464− modifyVar_ positionMapping $ \mappings -> return $! filterVersionMap versionsForFile mappings
465−define
466− :: IdeRule k v
467− => (k -> NormalizedFilePath -> Action (IdeResult v)) -> Rules ()
468−define op = defineEarlyCutoff $ \k v -> (Nothing,) <$> op k v
469−
470−use :: IdeRule k v
471− => k -> NormalizedFilePath -> Action (Maybe v)
472−use key file = head <$> uses key [file]
473−
474−useWithStale :: IdeRule k v
475− => k -> NormalizedFilePath -> Action (Maybe (v, PositionMapping))
476−useWithStale key file = head <$> usesWithStale key [file]
477−
478−useNoFile :: IdeRule k v => k -> Action (Maybe v)
479−useNoFile key = use key emptyFilePath
480−
481−use_ :: IdeRule k v => k -> NormalizedFilePath -> Action v
482−use_ key file = head <$> uses_ key [file]
483−
484−useNoFile_ :: IdeRule k v => k -> Action v
485−useNoFile_ key = use_ key emptyFilePath
486−
487−uses_ :: IdeRule k v => k -> [NormalizedFilePath] -> Action [v]
488−uses_ key files = do
489− res <- uses key files
490− case sequence res of
491− Nothing -> liftIO $ throwIO $ BadDependency (show key)
492− Just v -> return v
493−
494−
495−-- | When we depend on something that reported an error, and we fail as a direct result, throw BadDependency
496−-- which short-circuits the rest of the action
497−data BadDependency = BadDependency String deriving Show
498−instance Exception BadDependency
499−
500−isBadDependency :: SomeException -> Bool
501−isBadDependency x
502− | Just (x :: ShakeException) <- fromException x = isBadDependency $ shakeExceptionInner x
503− | Just (_ :: BadDependency) <- fromException x = True
504− | otherwise = False
505−
506−newtype Q k = Q (k, NormalizedFilePath)
507− deriving (Eq,Hashable,NFData, Generic)
508−
509−instance Binary k => Binary (Q k)
510−
511−instance Show k => Show (Q k) where
512− show (Q (k, file)) = show k ++ "; " ++ fromNormalizedFilePath file
513−
514−-- | Invariant: the 'v' must be in normal form (fully evaluated).
515−-- Otherwise we keep repeatedly 'rnf'ing values taken from the Shake database
516−newtype A v = A (Value v)
517− deriving Show
518−
519−instance NFData (A v) where rnf (A v) = v `seq` ()
520−
521−-- In the Shake database we only store one type of key/result pairs,
522−-- namely Q (question) / A (answer).
523−type instance RuleResult (Q k) = A (RuleResult k)
524−
525−
526−-- | Return up2date results. Stale results will be ignored.
527−uses :: IdeRule k v
528− => k -> [NormalizedFilePath] -> Action [Maybe v]
529−uses key files = map (\(A value) -> currentValue value) <$> apply (map (Q . (key,)) files)
530−
531−-- | Return the last computed result which might be stale.
532−usesWithStale :: IdeRule k v
533− => k -> [NormalizedFilePath] -> Action [Maybe (v, PositionMapping)]
534−usesWithStale key files = do
535− values <- map (\(A value) -> value) <$> apply (map (Q . (key,)) files)
536− zipWithM lastValue files values
537−
538−
539−withProgress :: (Eq a, Hashable a) => Var (HMap.HashMap a Int) -> a -> Action b -> Action b
540−withProgress var file = actionBracket (f succ) (const $ f pred) . const
541− -- This functions are deliberately eta-expanded to avoid space leaks.
542− -- Do not remove the eta-expansion without profiling a session with at
543− -- least 1000 modifications.
544− where f shift = modifyVar_ var $ \x -> evaluate $ HMap.alter (\x -> Just $! shift (fromMaybe 0 x)) file x
545−
546−
547−defineEarlyCutoff
548− :: IdeRule k v
549− => (k -> NormalizedFilePath -> Action (Maybe BS.ByteString, IdeResult v))
550− -> Rules ()
551−defineEarlyCutoff op = addBuiltinRule noLint noIdentity $ \(Q (key, file)) (old :: Maybe BS.ByteString) mode -> do
552− extras@ShakeExtras{state, inProgress} <- getShakeExtras
553− -- don't do progress for GetFileExists, as there are lots of non-nodes for just that one key
554− (if show key == "GetFileExists" then id else withProgress inProgress file) $ do
555− val <- case old of
556− Just old | mode == RunDependenciesSame -> do
557− v <- liftIO $ getValues state key file
558− case v of
559− -- No changes in the dependencies and we have
560− -- an existing result.
561− Just v -> return $ Just $ RunResult ChangedNothing old $ A v
562− _ -> return Nothing
563− _ -> return Nothing
564− case val of
565− Just res -> return res
566− Nothing -> do
567− (bs, (diags, res)) <- actionCatch
568− (do v <- op key file; liftIO $ evaluate $ force v) $
569− \(e :: SomeException) -> pure (Nothing, ([ideErrorText file $ T.pack $ show e | not $ isBadDependency e],Nothing))
570− modTime <- liftIO $ (currentValue =<<) <$> getValues state GetModificationTime file
571− (bs, res) <- case res of
572− Nothing -> do
573− staleV <- liftIO $ getValues state key file
574− pure $ case staleV of
575− Nothing -> (toShakeValue ShakeResult bs, Failed)
576− Just v -> case v of
577− Succeeded ver v -> (toShakeValue ShakeStale bs, Stale ver v)
578− Stale ver v -> (toShakeValue ShakeStale bs, Stale ver v)
579− Failed -> (toShakeValue ShakeResult bs, Failed)
580− Just v -> pure (maybe ShakeNoCutoff ShakeResult bs, Succeeded (vfsVersion =<< modTime) v)
581− liftIO $ setValues state key file res
582− updateFileDiagnostics file (Key key) extras $ map (\(_,y,z) -> (y,z)) diags
583− let eq = case (bs, fmap decodeShakeValue old) of
584− (ShakeResult a, Just (ShakeResult b)) -> a == b
585− (ShakeStale a, Just (ShakeStale b)) -> a == b
586− -- If we do not have a previous result
587− -- or we got ShakeNoCutoff we always return False.
588− _ -> False
589− return $ RunResult
590− (if eq then ChangedRecomputeSame else ChangedRecomputeDiff)
591− (encodeShakeValue bs) $
592− A res
593−
594−
595−-- | Rule type, input file
596−data QDisk k = QDisk k NormalizedFilePath
597− deriving (Eq, Generic)
598−
599−instance Hashable k => Hashable (QDisk k)
600−
601−instance NFData k => NFData (QDisk k)
602−
603−instance Binary k => Binary (QDisk k)
604−
605−instance Show k => Show (QDisk k) where
606− show (QDisk k file) =
607− show k ++ "; " ++ fromNormalizedFilePath file
608−
609−type instance RuleResult (QDisk k) = Bool
610−
611−data OnDiskRule = OnDiskRule
612− { getHash :: Action BS.ByteString
613− -- This is used to figure out if the state on disk corresponds to the state in the Shake
614− -- database and we can therefore avoid rerunning. Often this can just be the file hash but
615− -- in some cases we can be more aggressive, e.g., for GHC interface files this can be the ABI hash which
616− -- is more stable than the hash of the interface file.
617− -- An empty bytestring indicates that the state on disk is invalid, e.g., files are missing.
618− -- We do not use a Maybe since we have to deal with encoding things into a ByteString anyway in the Shake DB.
619− , runRule :: Action (IdeResult BS.ByteString)
620− -- The actual rule code which produces the new hash (or Nothing if the rule failed) and the diagnostics.
621− }
622−
623−-- This is used by the DAML compiler for incremental builds. Right now this is not used by
624−-- ghcide itself but that might change in the future.
625−-- The reason why this code lives in ghcide and in particular in this module is that it depends quite heavily on
626−-- the internals of this module that we do not want to expose.
627−defineOnDisk
628− :: (Shake.ShakeValue k, RuleResult k ~ ())
629− => (k -> NormalizedFilePath -> OnDiskRule)
630− -> Rules ()
631−defineOnDisk act = addBuiltinRule noLint noIdentity $
632− \(QDisk key file) (mbOld :: Maybe BS.ByteString) mode -> do
633− extras <- getShakeExtras
634− let OnDiskRule{..} = act key file
635− let validateHash h
636− | BS.null h = Nothing
637− | otherwise = Just h
638− let runAct = actionCatch runRule $
639− \(e :: SomeException) -> pure ([ideErrorText file $ T.pack $ displayException e | not $ isBadDependency e], Nothing)
640− case mbOld of
641− Nothing -> do
642− (diags, mbHash) <- runAct
643− updateFileDiagnostics file (Key key) extras $ map (\(_,y,z) -> (y,z)) diags
644− pure $ RunResult ChangedRecomputeDiff (fromMaybe "" mbHash) (isJust mbHash)
645− Just old -> do
646− current <- validateHash <$> (actionCatch getHash $ \(_ :: SomeException) -> pure "")
647− if mode == RunDependenciesSame && Just old == current && not (BS.null old)
648− then
649− -- None of our dependencies changed, we’ve had a successful run before and
650− -- the state on disk matches the state in the Shake database.
651− pure $ RunResult ChangedNothing (fromMaybe "" current) (isJust current)
652− else do
653− (diags, mbHash) <- runAct
654− updateFileDiagnostics file (Key key) extras $ map (\(_,y,z) -> (y,z)) diags
655− let change
656− | mbHash == Just old = ChangedRecomputeSame
657− | otherwise = ChangedRecomputeDiff
658− pure $ RunResult change (fromMaybe "" mbHash) (isJust mbHash)
659−
660−needOnDisk :: (Shake.ShakeValue k, RuleResult k ~ ()) => k -> NormalizedFilePath -> Action ()
661−needOnDisk k file = do
662− successfull <- apply1 (QDisk k file)
663− liftIO $ unless successfull $ throwIO $ BadDependency (show k)
664−
665−needOnDisks :: (Shake.ShakeValue k, RuleResult k ~ ()) => k -> [NormalizedFilePath] -> Action ()
666−needOnDisks k files = do
667− successfulls <- apply $ map (QDisk k) files
668− liftIO $ unless (and successfulls) $ throwIO $ BadDependency (show k)
669−
670−toShakeValue :: (BS.ByteString -> ShakeValue) -> Maybe BS.ByteString -> ShakeValue
671−toShakeValue = maybe ShakeNoCutoff
672−
673−data ShakeValue
674− = ShakeNoCutoff
675− -- ^ This is what we use when we get Nothing from
676− -- a rule.
677− | ShakeResult !BS.ByteString
678− -- ^ This is used both for `Failed`
679− -- as well as `Succeeded`.
680− | ShakeStale !BS.ByteString
681− deriving (Generic, Show)
682−
683−instance NFData ShakeValue
684−
685−encodeShakeValue :: ShakeValue -> BS.ByteString
686−encodeShakeValue = \case
687− ShakeNoCutoff -> BS.empty
688− ShakeResult r -> BS.cons 'r' r
689− ShakeStale r -> BS.cons 's' r
690−
691−decodeShakeValue :: BS.ByteString -> ShakeValue
692−decodeShakeValue bs = case BS.uncons bs of
693− Nothing -> ShakeNoCutoff
694− Just (x, xs)
695− | x == 'r' -> ShakeResult xs
696− | x == 's' -> ShakeStale xs
697− | otherwise -> error $ "Failed to parse shake value " <> show bs
698−
699−
700−updateFileDiagnostics ::
701− NormalizedFilePath
702− -> Key
703− -> ShakeExtras
704− -> [(ShowDiagnostic,Diagnostic)] -- ^ current results
705− -> Action ()
706−updateFileDiagnostics fp k ShakeExtras{diagnostics, hiddenDiagnostics, publishedDiagnostics, state, debouncer, eventer} current = liftIO $ do
707− modTime <- (currentValue =<<) <$> getValues state GetModificationTime fp
708− let (currentShown, currentHidden) = partition ((== ShowDiag) . fst) current
709− mask_ $ do
710− -- Mask async exceptions to ensure that updated diagnostics are always
711− -- published. Otherwise, we might never publish certain diagnostics if
712− -- an exception strikes between modifyVar but before
713− -- publishDiagnosticsNotification.
714− newDiags <- modifyVar diagnostics $ \old -> do
715− let newDiagsStore = setStageDiagnostics fp (vfsVersion =<< modTime)
716− (T.pack $ show k) (map snd currentShown) old
717− let newDiags = getFileDiagnostics fp newDiagsStore
718− _ <- evaluate newDiagsStore
719− _ <- evaluate newDiags
720− pure (newDiagsStore, newDiags)
721− modifyVar_ hiddenDiagnostics $ \old -> do
722− let newDiagsStore = setStageDiagnostics fp (vfsVersion =<< modTime)
723− (T.pack $ show k) (map snd currentHidden) old
724− let newDiags = getFileDiagnostics fp newDiagsStore
725− _ <- evaluate newDiagsStore
726− _ <- evaluate newDiags
727− return newDiagsStore
728− let uri = filePathToUri' fp
729− let delay = if null newDiags then 0.1 else 0
730− registerEvent debouncer delay uri $ do
731− mask_ $ modifyVar_ publishedDiagnostics $ \published -> do
732− let lastPublish = HMap.lookupDefault [] uri published
733− when (lastPublish /= newDiags) $
734− eventer $ publishDiagnosticsNotification (fromNormalizedUri uri) newDiags
735− pure $! HMap.insert uri newDiags published
736−
737−publishDiagnosticsNotification :: Uri -> [Diagnostic] -> LSP.FromServerMessage
738−publishDiagnosticsNotification uri diags =
739− LSP.NotPublishDiagnostics $
740− LSP.NotificationMessage "2.0" LSP.TextDocumentPublishDiagnostics $
741− LSP.PublishDiagnosticsParams uri (List diags)
742−
743−newtype Priority = Priority Double
744−
745−setPriority :: Priority -> Action ()
746−setPriority (Priority p) = reschedule p
747−
748−sendEvent :: LSP.FromServerMessage -> Action ()
749−sendEvent e = do
750− ShakeExtras{eventer} <- getShakeExtras
751− liftIO $ eventer e
752−
753−ideLogger :: IdeState -> Logger
754−ideLogger IdeState{shakeExtras=ShakeExtras{logger}} = logger
755−
756−actionLogger :: Action Logger
757−actionLogger = do
758− ShakeExtras{logger} <- getShakeExtras
759− return logger
760−
761−
762−data GetModificationTime = GetModificationTime
763− deriving (Eq, Show, Generic)
764−instance Hashable GetModificationTime
765−instance NFData GetModificationTime
766−instance Binary GetModificationTime
767−
768−-- | Get the modification time of a file.
769−type instance RuleResult GetModificationTime = FileVersion
770−
771−data FileVersion
772− = VFSVersion !Int
773− | ModificationTime
774− !Int -- ^ Large unit (platform dependent, do not make assumptions)
775− !Int -- ^ Small unit (platform dependent, do not make assumptions)
776− deriving (Show, Generic)
777−
778−instance NFData FileVersion
779−
780−vfsVersion :: FileVersion -> Maybe Int
781−vfsVersion (VFSVersion i) = Just i
782−vfsVersion ModificationTime{} = Nothing
783−
784−modificationTime :: FileVersion -> Maybe (Int, Int)
785−modificationTime VFSVersion{} = Nothing
786−modificationTime (ModificationTime large small) = Just (large, small)
787−
788−getDiagnosticsFromStore :: StoreItem -> [Diagnostic]
789−getDiagnosticsFromStore (StoreItem _ diags) = concatMap SL.fromSortedList $ Map.elems diags
790−
791−
792−-- | Sets the diagnostics for a file and compilation step
793−-- if you want to clear the diagnostics call this with an empty list
794−setStageDiagnostics
795− :: NormalizedFilePath
796− -> TextDocumentVersion -- ^ the time that the file these diagnostics originate from was last edited
797− -> T.Text
798− -> [LSP.Diagnostic]
799− -> DiagnosticStore
800− -> DiagnosticStore
801−setStageDiagnostics fp timeM stage diags ds =
802− updateDiagnostics ds uri timeM diagsBySource
803− where
804− diagsBySource = Map.singleton (Just stage) (SL.toSortedList diags)
805− uri = filePathToUri' fp
806−
807−getAllDiagnostics ::
808− DiagnosticStore ->
809− [FileDiagnostic]
810−getAllDiagnostics =
811− concatMap (\(k,v) -> map (fromUri k,ShowDiag,) $ getDiagnosticsFromStore v) . HMap.toList
812−
813−getFileDiagnostics ::
814− NormalizedFilePath ->
815− DiagnosticStore ->
816− [LSP.Diagnostic]
817−getFileDiagnostics fp ds =
818− maybe [] getDiagnosticsFromStore $
819− HMap.lookup (filePathToUri' fp) ds
820−
821−filterDiagnostics ::
822− (NormalizedFilePath -> Bool) ->
823− DiagnosticStore ->
824− DiagnosticStore
825−filterDiagnostics keep =
826− HMap.filterWithKey (\uri _ -> maybe True (keep . toNormalizedFilePath') $ uriToFilePath' $ fromNormalizedUri uri)
827−
828−filterVersionMap
829− :: HMap.HashMap NormalizedUri (Set.Set TextDocumentVersion)
830− -> HMap.HashMap NormalizedUri (Map TextDocumentVersion a)
831− -> HMap.HashMap NormalizedUri (Map TextDocumentVersion a)
832−filterVersionMap =
833− HMap.intersectionWith $ \versionsToKeep versionMap -> Map.restrictKeys versionMap versionsToKeep
834−
835−updatePositionMapping :: IdeState -> VersionedTextDocumentIdentifier -> List TextDocumentContentChangeEvent -> IO ()
836−updatePositionMapping IdeState{shakeExtras = ShakeExtras{positionMapping}} VersionedTextDocumentIdentifier{..} (List changes) = do
837− modifyVar_ positionMapping $ \allMappings -> do
838− let uri = toNormalizedUri _uri
839− let mappingForUri = HMap.lookupDefault Map.empty uri allMappings
840− let (_, updatedMapping) =
841− -- Very important to use mapAccum here so that the tails of
842− -- each mapping can be shared, otherwise quadratic space is
843− -- used which is evident in long running sessions.
844− Map.mapAccumRWithKey (\acc _k (delta, _) -> let new = addDelta delta acc in (new, (delta, acc)))
845− zeroMapping
846− (Map.insert _version (shared_change, zeroMapping) mappingForUri)
847− pure $! HMap.insert uri updatedMapping allMappings
848− where
849− shared_change = mkDelta changes
src/Development/IDE/Functions/AtPoint.hsnew file+139
@@ -0,0 +1,139 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE OverloadedStrings #-}
5+-- | Gives information about symbols at a given point in DAML files.
6+-- These are all pure functions that should execute quickly.
7+module Development.IDE.Functions.AtPoint (
8+ atPoint
9+ , gotoDefinition
10+ ) where
11+
12+import Development.IDE.Functions.Documentation
13+import Development.IDE.Functions.GHCError
14+import Development.IDE.Orphans()
15+
16+-- DAML compiler and infrastructure
17+import Development.Shake
18+import Development.IDE.UtilGHC
19+import Development.IDE.Compat
20+import Development.IDE.State.Shake
21+import Development.IDE.State.RuleTypes
22+import Development.IDE.Types.Diagnostics
23+import Development.IDE.Types.LSP
24+import Development.IDE.Types.Options
25+import Development.IDE.Types.SpanInfo as SpanInfo
26+
27+-- GHC API imports
28+import Avail
29+import GHC
30+import DynFlags
31+import FastString
32+import Name
33+import Outputable hiding ((<>))
34+
35+import Control.Monad.Extra
36+import Control.Monad.Trans.Maybe
37+import Data.Maybe
38+import Data.List
39+import qualified Data.Text as T
40+
41+-- | Locate the definition of the name at a given position.
42+gotoDefinition
43+ :: IdeOptions
44+ -> HscEnv
45+ -> [SpanInfo]
46+ -> Position
47+ -> Action (Maybe Location)
48+gotoDefinition ideOpts pkgState srcSpans pos =
49+ listToMaybe <$> locationsAtPoint ideOpts pkgState pos srcSpans
50+
51+-- | Synopsis for the name at a given position.
52+atPoint
53+ :: [TypecheckedModule]
54+ -> [SpanInfo]
55+ -> Position
56+ -> Maybe (Maybe Range, [HoverText])
57+atPoint tcs srcSpans pos = do
58+ SpanInfo{..} <- listToMaybe $ orderSpans $ spansAtPoint pos srcSpans
59+ ty <- spaninfoType
60+ let mbName = getNameM spaninfoSource
61+ mbDefinedAt = HoverHeading . ("Defined " <>) . T.pack . showSDocUnsafe . pprNameDefnLoc <$> mbName
62+ mbDocs = fmap (\name -> getDocumentation name tcs) mbName
63+ docInfo = maybe [] (map HoverMarkdown . docHeaders) mbDocs
64+ range = Range
65+ (Position spaninfoStartLine spaninfoStartCol)
66+ (Position spaninfoEndLine spaninfoEndCol)
67+ typeSig = HoverDamlCode $ case mbName of
68+ Nothing -> ": " <> showName ty
69+ Just name ->
70+ let modulePrefix = maybe "" (<> ".") (getModuleNameAsText name)
71+ in modulePrefix <> showName name <> "\n : " <> showName ty
72+ hoverInfo = docInfo <> [typeSig] <> maybeToList mbDefinedAt
73+ return (Just range, hoverInfo)
74+ where
75+ -- NOTE(RJR): This is a bit hacky.
76+ -- We don't want to show the user type signatures generated from Eq and Show
77+ -- instances, as they do not appear in the source program.
78+ -- However the user could have written an `==` or `show` function directly,
79+ -- in which case we still want to show information for that.
80+ -- Hence we just move such information later in the list of spans.
81+ orderSpans :: [SpanInfo] -> [SpanInfo]
82+ orderSpans = uncurry (++) . partition (not . isTypeclassDeclSpan)
83+ isTypeclassDeclSpan :: SpanInfo -> Bool
84+ isTypeclassDeclSpan spanInfo =
85+ case getNameM (spaninfoSource spanInfo) of
86+ Just name -> any (`isInfixOf` show name) ["==", "showsPrec"]
87+ Nothing -> False
88+
89+locationsAtPoint :: IdeOptions -> HscEnv -> Position -> [SpanInfo] -> Action [Location]
90+locationsAtPoint IdeOptions{..} pkgState pos =
91+ fmap (map srcSpanToLocation) .
92+ mapMaybeM (getSpan . spaninfoSource) .
93+ spansAtPoint pos
94+ where getSpan :: SpanSource -> Action (Maybe SrcSpan)
95+ getSpan NoSource = pure Nothing
96+ getSpan (Span sp) = pure $ Just sp
97+ getSpan (Named name) = case nameSrcSpan name of
98+ sp@(RealSrcSpan _) -> pure $ Just sp
99+ UnhelpfulSpan _ -> runMaybeT $ do
100+ -- This case usually arises when the definition is in an external package.
101+ -- In this case the interface files contain garbage source spans
102+ -- so we instead read the .hie files to get useful source spans.
103+ let mod = nameModule name
104+ let unitId = moduleUnitId mod
105+ pkgConfig <- MaybeT $ pure $ lookupPackageConfig unitId pkgState
106+ hiePath <- MaybeT $ liftIO $ optLocateHieFile optPkgLocationOpts pkgConfig mod
107+ hieFile <- MaybeT $ use (GetHieFile hiePath) ""
108+ avail <- MaybeT $ pure $ listToMaybe (filterAvails (eqName name) $ hie_exports hieFile)
109+ srcPath <- MaybeT $ liftIO $ optLocateSrcFile optPkgLocationOpts pkgConfig mod
110+ -- The location will point to the source file used during compilation.
111+ -- This file might no longer exists and even if it does the path will be relative
112+ -- to the compilation directory which we don’t know.
113+ let span = setFileName srcPath $ nameSrcSpan $ availName avail
114+ pure span
115+ -- We ignore uniques and source spans and only compare the name and the module.
116+ eqName :: Name -> Name -> Bool
117+ eqName n n' = nameOccName n == nameOccName n' && nameModule n == nameModule n'
118+ setFileName f (RealSrcSpan span) = RealSrcSpan (span { srcSpanFile = mkFastString f })
119+ setFileName _ span@(UnhelpfulSpan _) = span
120+
121+spansAtPoint :: Position -> [SpanInfo] -> [SpanInfo]
122+spansAtPoint pos = filter atp where
123+ line = _line pos + 1
124+ cha = _character pos + 1
125+ atp SpanInfo{..} = spaninfoStartLine <= line
126+ && spaninfoEndLine >= line
127+ && spaninfoStartCol <= cha
128+ && spaninfoEndCol >= cha
129+
130+showName :: Outputable a => a -> T.Text
131+showName = T.pack . prettyprint
132+ where
133+ prettyprint x = renderWithStyle unsafeGlobalDynFlags (ppr x) style
134+ style = mkUserStyle unsafeGlobalDynFlags neverQualify AllTheWay
135+
136+getModuleNameAsText :: Name -> Maybe T.Text
137+getModuleNameAsText n = do
138+ m <- nameModule_maybe n
139+ return . T.pack . moduleNameString $ moduleName m
src/Development/IDE/GHC/CPP.hs → src/Development/IDE/Functions/CPP.hsrenamed+10−52
@@ -1,15 +1,12 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
44-- Copied from https://github.com/ghc/ghc/blob/master/compiler/main/DriverPipeline.hs on 14 May 2019
5−-- Requested to be exposed at https://gitlab.haskell.org/ghc/ghc/merge_requests/944.
6−-- Update the above MR got merged to master on 31 May 2019. When it becomes avialable to ghc-lib, this file can be removed.
7−
5+-- Requested to be exposed at https://gitlab.haskell.org/ghc/ghc/merge_requests/944
86{- HLINT ignore -} -- since copied from upstream
97
108{-# LANGUAGE CPP, NamedFieldPuns, NondecreasingIndentation, BangPatterns, MultiWayIf #-}
119{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
12−#include "ghc-api-version.h"
1310
1411-----------------------------------------------------------------------------
1512--
@@ -19,30 +16,18 @@
1916--
2017-----------------------------------------------------------------------------
2118
22−module Development.IDE.GHC.CPP(doCpp, addOptP)
23−where
19+module Development.IDE.Functions.CPP(doCpp) where
2420
25−import Development.IDE.GHC.Compat
2621import Packages
2722import SysTools
2823import Module
2924import DynFlags
3025import Panic
3126import FileCleanup
32−#if MIN_GHC_API_VERSION(8,8,2)
33−import LlvmCodeGen (llvmVersionList)
34−#elif MIN_GHC_API_VERSION(8,8,0)
35−import LlvmCodeGen (LlvmVersion (..))
36−#endif
37−#if MIN_GHC_API_VERSION (8,10,0)
38−import Fingerprint
39−import ToolSettings
40−#endif
4127
4228import System.Directory
4329import System.FilePath
4430import Control.Monad
45−import System.Info
4631import Data.List ( intercalate )
4732import Data.Maybe
4833import Data.Version
@@ -64,19 +49,17 @@ doCpp dflags raw input_fn output_fn = do
6449 let verbFlags = getVerbFlags dflags
6550
6651 let cpp_prog args | raw = SysTools.runCpp dflags args
67−#if MIN_GHC_API_VERSION(8,10,0)
68− | otherwise = SysTools.runCc Nothing
69−#else
7052 | otherwise = SysTools.runCc
53+#ifndef GHC_STABLE
54+ Nothing
7155#endif
7256 dflags (SysTools.Option "-E" : args)
7357
74− let target_defs =
75− -- NEIL: Patched to use System.Info instead of constants from CPP
76− [ "-D" ++ os ++ "_BUILD_OS",
77− "-D" ++ arch ++ "_BUILD_ARCH",
78− "-D" ++ os ++ "_HOST_OS",
79− "-D" ++ arch ++ "_HOST_ARCH" ]
58+ let target_defs = [] {-
59+ [ "-D" ++ HOST_OS ++ "_BUILD_OS",
60+ "-D" ++ HOST_ARCH ++ "_BUILD_ARCH",
61+ "-D" ++ TARGET_OS ++ "_HOST_OS",
62+ "-D" ++ TARGET_ARCH ++ "_HOST_ARCH" ] -}
8063 -- remember, in code we *compile*, the HOST is the same our TARGET,
8164 -- and BUILD is the same as our HOST.
8265
@@ -148,16 +131,7 @@ getBackendDefs :: DynFlags -> IO [String]
148131getBackendDefs dflags | hscTarget dflags == HscLlvm = do
149132 llvmVer <- figureLlvmVersion dflags
150133 return $ case llvmVer of
151−#if MIN_GHC_API_VERSION(8,8,2)
152− Just v
153− | [m] <- llvmVersionList v -> [ "-D__GLASGOW_HASKELL_LLVM__=" ++ format (m, 0) ]
154− | m:n:_ <- llvmVersionList v -> [ "-D__GLASGOW_HASKELL_LLVM__=" ++ format (m, n) ]
155−#elif MIN_GHC_API_VERSION(8,8,0)
156− Just (LlvmVersion n) -> [ "-D__GLASGOW_HASKELL_LLVM__=" ++ format (n,0) ]
157− Just (LlvmVersionOld m n) -> [ "-D__GLASGOW_HASKELL_LLVM__=" ++ format (m,n) ]
158−#else
159134 Just n -> [ "-D__GLASGOW_HASKELL_LLVM__=" ++ format n ]
160−#endif
161135 _ -> []
162136 where
163137 format (major, minor)
@@ -167,22 +141,6 @@ getBackendDefs dflags | hscTarget dflags == HscLlvm = do
167141getBackendDefs _ =
168142 return []
169143
170−addOptP :: String -> DynFlags -> DynFlags
171−#if MIN_GHC_API_VERSION (8,10,0)
172−addOptP f = alterToolSettings $ \s -> s
173− { toolSettings_opt_P = f : toolSettings_opt_P s
174− , toolSettings_opt_P_fingerprint = fingerprintStrings (f : toolSettings_opt_P s)
175− }
176− where
177− fingerprintStrings ss = fingerprintFingerprints $ map fingerprintString ss
178− alterToolSettings f dynFlags = dynFlags { toolSettings = f (toolSettings dynFlags) }
179−#else
180−addOptP opt = onSettings (onOptP (opt:))
181− where
182− onSettings f x = x{settings = f $ settings x}
183− onOptP f x = x{sOpt_P = f $ sOpt_P x}
184−#endif
185−
186144-- ---------------------------------------------------------------------------
187145-- Macros (cribbed from Cabal)
188146
src/Development/IDE/Functions/Compile.hsnew file+455
@@ -0,0 +1,455 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE RankNTypes #-}
6+{-# LANGUAGE CPP #-}
7+
8+-- | Based on https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/API.
9+-- Given a list of paths to find libraries, and a file to compile, produce a list of 'CoreModule' values.
10+module Development.IDE.Functions.Compile
11+ ( GhcModule(..)
12+ , TcModuleResult(..)
13+ , LoadPackageResult(..)
14+ , getGhcDynFlags
15+ , compileModule
16+ , getSrcSpanInfos
17+ , parseModule
18+ , typecheckModule
19+ , loadPackage
20+ , computePackageDeps
21+ ) where
22+
23+import Development.IDE.Functions.Warnings
24+import Development.IDE.Functions.CPP
25+import Development.IDE.Types.Diagnostics
26+import qualified Development.IDE.Functions.FindImports as FindImports
27+import Development.IDE.Functions.GHCError
28+import Development.IDE.Functions.SpanInfo
29+import Development.IDE.UtilGHC
30+import Development.IDE.Compat
31+import Development.IDE.Types.Options
32+
33+import GHC hiding (parseModule, typecheckModule)
34+import qualified Parser
35+import Lexer
36+import Bag
37+
38+import qualified GHC
39+import Panic
40+import GhcMonad
41+import GhcPlugins as GHC hiding (fst3, (<>))
42+import qualified HeaderInfo as Hdr
43+import MkIface
44+import NameCache
45+import StringBuffer as SB
46+import TidyPgm
47+import qualified GHC.LanguageExtensions as LangExt
48+
49+import Control.DeepSeq
50+import Control.Exception as E
51+import Control.Monad
52+import qualified Control.Monad.Trans.Except as Ex
53+import Data.IORef
54+import Data.List.Extra
55+import Data.Maybe
56+import Data.Tuple.Extra
57+import qualified Data.Map.Strict as Map
58+import Data.Time
59+import Development.IDE.Types.SpanInfo
60+import GHC.Generics (Generic)
61+import System.FilePath
62+import System.Directory
63+import System.IO.Extra
64+
65+
66+-- | 'CoreModule' together with some additional information required for the
67+-- conversion to DAML-LF.
68+data GhcModule = GhcModule
69+ { gmPath :: Maybe FilePath
70+ , gmCore :: CoreModule
71+ }
72+ deriving (Generic, Show)
73+
74+instance NFData GhcModule
75+
76+-- | Contains the typechecked module and the OrigNameCache entry for
77+-- that module.
78+data TcModuleResult = TcModuleResult
79+ { tmrModule :: TypecheckedModule
80+ , tmrModInfo :: HomeModInfo
81+ , tmrOccEnvName :: OccEnv Name
82+ }
83+
84+-- | Contains the result of loading an interface. In particular the delta to the name cache.
85+data LoadPackageResult = LoadPackageResult
86+ { lprInstalledUnitId :: InstalledUnitId
87+ , lprModuleEnv :: ModuleEnv (OccEnv Name)
88+ , lprEps :: ExternalPackageState
89+ }
90+
91+-- | Get source span info, used for e.g. AtPoint and Goto Definition.
92+getSrcSpanInfos
93+ :: IdeOptions
94+ -> ParsedModule
95+ -> HscEnv
96+ -> [(Located ModuleName, Maybe FilePath)]
97+ -> TcModuleResult
98+ -> IO [SpanInfo]
99+getSrcSpanInfos opt mod env imports tc =
100+ runGhcSession opt (Just mod) env
101+ . getSpanInfo imports
102+ $ tmrModule tc
103+
104+
105+-- | Given a string buffer, return a pre-processed @ParsedModule@.
106+parseModule
107+ :: IdeOptions
108+ -> HscEnv
109+ -> FilePath
110+ -> (UTCTime, SB.StringBuffer)
111+ -> IO ([FileDiagnostic], Maybe ParsedModule)
112+parseModule opt@IdeOptions{..} packageState file =
113+ fmap (either (, Nothing) (second Just)) . Ex.runExceptT .
114+ -- We need packages since imports fail to resolve otherwise.
115+ runGhcSessionExcept opt Nothing packageState . parseFileContents optPreprocessor file
116+
117+computePackageDeps ::
118+ IdeOptions -> HscEnv -> InstalledUnitId -> IO (Either [FileDiagnostic] [InstalledUnitId])
119+computePackageDeps opts packageState iuid =
120+ Ex.runExceptT $
121+ runGhcSessionExcept opts Nothing packageState $
122+ catchSrcErrors $ do
123+ dflags <- hsc_dflags <$> getSession
124+ liftIO $ depends <$> getPackage dflags iuid
125+
126+getPackage :: DynFlags -> InstalledUnitId -> IO PackageConfig
127+getPackage dflags p =
128+ case lookupInstalledPackage dflags p of
129+ Nothing -> E.throwIO $ CmdLineError (missingPackageMsg p)
130+ Just pkg -> return pkg
131+ where
132+ missingPackageMsg p = showSDoc dflags $ text "unknown package:" <+> ppr p
133+
134+-- | Typecheck a single module using the supplied dependencies and packages.
135+typecheckModule
136+ :: IdeOptions
137+ -> ParsedModule
138+ -> HscEnv
139+ -> [TcModuleResult]
140+ -> ParsedModule
141+ -> IO ([FileDiagnostic], Maybe TcModuleResult)
142+typecheckModule opt mod packageState deps pm =
143+ fmap (either (, Nothing) (second Just)) $ Ex.runExceptT $
144+ runGhcSessionExcept opt (Just mod) packageState $
145+ catchSrcErrors $ do
146+ setupEnv deps
147+ (warnings, tcm) <- withWarnings "Typechecker" $ \tweak ->
148+ GHC.typecheckModule pm{pm_mod_summary = tweak $ pm_mod_summary pm}
149+ tcm2 <- mkTcModuleResult (WriteInterface $ optWriteIface opt) tcm
150+ return (warnings, tcm2)
151+
152+-- | Load a pkg and populate the name cache and external package state.
153+loadPackage ::
154+ IdeOptions
155+ -> HscEnv
156+ -> InstalledUnitId
157+ -> IO (Either [FileDiagnostic] LoadPackageResult)
158+loadPackage opt packageState p =
159+ Ex.runExceptT $
160+ runGhcSessionExcept opt Nothing packageState $
161+ catchSrcErrors $ do
162+ setupEnv []
163+ -- this populates the namecache and external package state
164+ session <- getSession
165+ modEnv <- nsNames <$> liftIO (readIORef $ hsc_NC session)
166+ eps <- liftIO (readIORef $ hsc_EPS session)
167+ pure $ LoadPackageResult p modEnv eps
168+
169+-- | Compile a single type-checked module to a 'CoreModule' value, or
170+-- provide errors.
171+compileModule
172+ :: IdeOptions
173+ -> ParsedModule
174+ -> HscEnv
175+ -> [TcModuleResult]
176+ -> TcModuleResult
177+ -> IO ([FileDiagnostic], Maybe GhcModule)
178+compileModule opt mod packageState deps tmr =
179+ fmap (either (, Nothing) (second Just)) $ Ex.runExceptT $
180+ runGhcSessionExcept opt (Just mod) packageState $
181+ catchSrcErrors $ do
182+ setupEnv (deps ++ [tmr])
183+
184+ let tm = tmrModule tmr
185+ session <- getSession
186+ (warnings,desugar) <- withWarnings "Desugarer" $ \tweak -> do
187+ let pm = tm_parsed_module tm
188+ let pm' = pm{pm_mod_summary = tweak $ pm_mod_summary pm}
189+ let tm' = tm{tm_parsed_module = pm'}
190+ GHC.dm_core_module <$> GHC.desugarModule tm'
191+
192+ -- give variables unique OccNames
193+ (tidy, details) <- liftIO $ tidyProgram session desugar
194+
195+ let path = ml_hs_file $ ms_location $ pm_mod_summary $ tm_parsed_module tm
196+ let core = CoreModule
197+ (cg_module tidy)
198+ (md_types details)
199+ (cg_binds tidy)
200+ (mg_safe_haskell desugar)
201+
202+ return (warnings, GhcModule path core)
203+
204+-- | Evaluate a GHC session using a new environment constructed with
205+-- the supplied options.
206+runGhcSessionExcept
207+ :: IdeOptions
208+ -> Maybe ParsedModule
209+ -> HscEnv
210+ -> Ex.ExceptT e Ghc a
211+ -> Ex.ExceptT e IO a
212+runGhcSessionExcept opts mbMod pkg m =
213+ Ex.ExceptT $ runGhcSession opts mbMod pkg $ Ex.runExceptT m
214+
215+
216+getGhcDynFlags :: IdeOptions -> ParsedModule -> HscEnv -> IO DynFlags
217+getGhcDynFlags opts mod pkg = runGhcSession opts (Just mod) pkg getSessionDynFlags
218+
219+-- | Evaluate a GHC session using a new environment constructed with
220+-- the supplied options.
221+runGhcSession
222+ :: IdeOptions
223+ -> Maybe ParsedModule
224+ -> HscEnv
225+ -> Ghc a
226+ -> IO a
227+runGhcSession IdeOptions{..} modu env act = runGhcEnv env $ do
228+ modifyDynFlags $ \x -> x
229+ {importPaths = nubOrd $ maybeToList (moduleImportPaths =<< modu) ++ importPaths x}
230+ act
231+
232+
233+moduleImportPaths :: GHC.ParsedModule -> Maybe FilePath
234+moduleImportPaths pm
235+ | rootModDir == "." = Just rootPathDir
236+ | otherwise = dropTrailingPathSeparator <$> stripSuffix rootModDir rootPathDir
237+ where
238+ ms = GHC.pm_mod_summary pm
239+ file = GHC.ms_hspp_file ms
240+ mod' = GHC.ms_mod ms
241+ rootPathDir = takeDirectory file
242+ rootModDir = takeDirectory . moduleNameSlashes . GHC.moduleName $ mod'
243+
244+
245+newtype WriteInterface = WriteInterface Bool
246+
247+mkTcModuleResult
248+ :: GhcMonad m
249+ => WriteInterface
250+ -> TypecheckedModule
251+ -> m TcModuleResult
252+mkTcModuleResult (WriteInterface writeIface) tcm = do
253+ session <- getSession
254+ nc <- liftIO $ readIORef (hsc_NC session)
255+ (iface,_) <- liftIO $ mkIfaceTc session Nothing Sf_None details tcGblEnv
256+ liftIO $ when writeIface $ do
257+ let path = ".interfaces" </> file tcm
258+ createDirectoryIfMissing True (takeDirectory path)
259+ writeIfaceFile (hsc_dflags session) (replaceExtension path ".hi") iface
260+ -- For now, we write .hie files whenever we write .hi files which roughly corresponds to
261+ -- when we are building a package. It should be easily decoupable if that turns out to be
262+ -- useful.
263+ hieFile <- runHsc session $ mkHieFile (tcModSummary tcm) tcGblEnv (fromJust $ renamedSource tcm)
264+ writeHieFile (replaceExtension path ".hie") hieFile
265+ let mod_info = HomeModInfo iface details Nothing
266+ origNc = nsNames nc
267+ case lookupModuleEnv origNc (tcmModule tcm) of
268+ Nothing -> panic err
269+ Just occ -> return $ TcModuleResult tcm mod_info occ
270+ where
271+ file = ms_hspp_file . tcModSummary
272+ tcmModule = ms_mod . tcModSummary
273+ (tcGblEnv, details) = tm_internals_ tcm
274+ err = "Internal error : module not found in NameCache :" <>
275+ moduleNameString (moduleName $ tcmModule tcm)
276+
277+tcModSummary :: TypecheckedModule -> ModSummary
278+tcModSummary = pm_mod_summary . tm_parsed_module
279+
280+-- | Setup the environment that GHC needs according to our
281+-- best understanding (!)
282+setupEnv :: GhcMonad m => [TcModuleResult] -> m ()
283+setupEnv tms = do
284+ session <- getSession
285+
286+ let mss = map (pm_mod_summary . tm_parsed_module . tmrModule) tms
287+
288+ -- set the target and module graph in the session
289+ let graph = mkModuleGraph mss
290+ setSession session { hsc_mod_graph = graph }
291+
292+ -- Make modules available for others that import them,
293+ -- by putting them in the finder cache.
294+ let ims = map (InstalledModule (thisInstalledUnitId $ hsc_dflags session) . moduleName . ms_mod) mss
295+ ifrs = zipWith (\ms -> InstalledFound (ms_location ms)) mss ims
296+ liftIO $ modifyIORef (hsc_FC session) $ \fc ->
297+ foldl' (\fc (im, ifr) -> GHC.extendInstalledModuleEnv fc im ifr) fc
298+ $ zip ims ifrs
299+
300+ -- load dependent modules, which must be in topological order.
301+ mapM_ loadModuleHome tms
302+
303+
304+-- | Load a module, quickly. Input doesn't need to be desugared.
305+-- A module must be loaded before dependent modules can be typechecked.
306+-- This variant of loadModuleHome will *never* cause recompilation, it just
307+-- modifies the session.
308+loadModuleHome
309+ :: (GhcMonad m)
310+ => TcModuleResult
311+ -> m ()
312+loadModuleHome tmr = modifySession $ \e ->
313+ e { hsc_HPT = addToHpt (hsc_HPT e) mod mod_info }
314+ where
315+ ms = pm_mod_summary . tm_parsed_module . tmrModule $ tmr
316+ mod_info = tmrModInfo tmr
317+ mod = ms_mod_name ms
318+
319+-- | Produce a module summary from a StringBuffer.
320+getModSummaryFromBuffer
321+ :: GhcMonad m
322+ => FilePath
323+ -> (SB.StringBuffer, UTCTime)
324+ -> DynFlags
325+ -> GHC.ParsedSource
326+ -> Ex.ExceptT [FileDiagnostic] m ModSummary
327+getModSummaryFromBuffer fp (contents, fileDate) dflags parsed = do
328+ (modName, imports) <- FindImports.getImportsParsed dflags parsed
329+
330+ let modLoc = ModLocation
331+ { ml_hs_file = Just fp
332+ , ml_hi_file = replaceExtension fp "hi"
333+ , ml_obj_file = replaceExtension fp "o"
334+#ifndef GHC_STABLE
335+ , ml_hie_file = replaceExtension fp "hie"
336+#endif
337+ -- This does not consider the dflags configuration
338+ -- (-osuf and -hisuf, object and hi dir.s).
339+ -- However, we anyway don't want to generate them.
340+ }
341+ InstalledUnitId unitId = thisInstalledUnitId dflags
342+ return $ ModSummary
343+ { ms_mod = mkModule (fsToUnitId unitId) modName
344+ , ms_location = modLoc
345+ , ms_hs_date = fileDate
346+ , ms_textual_imps = imports
347+ , ms_hspp_file = fp
348+ , ms_hspp_opts = dflags
349+ , ms_hspp_buf = Just contents
350+
351+ -- defaults:
352+ , ms_hsc_src = HsSrcFile
353+ , ms_obj_date = Nothing
354+ , ms_iface_date = Nothing
355+#ifndef GHC_STABLE
356+ , ms_hie_date = Nothing
357+#endif
358+ , ms_srcimps = [] -- source imports are not allowed
359+ , ms_parsed_mod = Nothing
360+ }
361+
362+-- | Given a buffer, flags, file path and module summary, produce a
363+-- parsed module (or errors) and any parse warnings.
364+parseFileContents
365+ :: GhcMonad m
366+ => (GHC.ParsedSource -> ([(GHC.SrcSpan, String)], GHC.ParsedSource))
367+ -> FilePath -- ^ the filename (for source locations)
368+ -> (UTCTime, SB.StringBuffer) -- ^ Haskell module source text (full Unicode is supported)
369+ -> Ex.ExceptT [FileDiagnostic] m ([FileDiagnostic], ParsedModule)
370+parseFileContents preprocessor filename (time, contents) = do
371+ let loc = mkRealSrcLoc (mkFastString filename) 1 1
372+ dflags <- parsePragmasIntoDynFlags filename contents
373+
374+ (contents, dflags) <-
375+ if not $ xopt LangExt.Cpp dflags then
376+ return (contents, dflags)
377+ else do
378+ contents <- liftIO $ withTempDir $ \dir -> do
379+ let inp = dir </> takeFileName filename
380+ let out = dir </> takeFileName filename <.> "out"
381+ let f x = if SB.atEnd x then Nothing else Just $ SB.nextChar x
382+ liftIO $ writeFileUTF8 inp (unfoldr f contents)
383+ doCpp dflags True inp out
384+ liftIO $ SB.hGetStringBuffer out
385+ dflags <- parsePragmasIntoDynFlags filename contents
386+ return (contents, dflags)
387+
388+ case unP Parser.parseModule (mkPState dflags contents loc) of
389+#ifdef GHC_STABLE
390+ PFailed _ locErr msgErr ->
391+ Ex.throwE $ mkErrorDoc dflags locErr msgErr
392+#else
393+ PFailed s ->
394+ -- A fatal parse error was encountered.
395+ Ex.throwE $ toDiagnostics dflags $ snd $ getMessages s dflags
396+#endif
397+ POk pst rdr_module ->
398+ let hpm_annotations =
399+ (Map.fromListWith (++) $ annotations pst,
400+ Map.fromList ((noSrcSpan,comment_q pst)
401+ :annotations_comments pst))
402+ (warns, errs) = getMessages pst dflags
403+ in
404+ do
405+ -- Just because we got a `POk`, it doesn't mean there
406+ -- weren't errors! To clarify, the GHC parser
407+ -- distinguishes between fatal and non-fatal
408+ -- errors. Non-fatal errors are the sort that don't
409+ -- prevent parsing from continuing (that is, a parse
410+ -- tree can still be produced despite the error so that
411+ -- further errors/warnings can be collected). Fatal
412+ -- errors are those from which a parse tree just can't
413+ -- be produced.
414+ unless (null errs) $
415+ Ex.throwE $ toDiagnostics dflags $ snd $ getMessages pst dflags
416+
417+ -- Ok, we got here. It's safe to continue.
418+ let (errs, parsed) = preprocessor rdr_module
419+ unless (null errs) $ Ex.throwE $ mkErrors dflags errs
420+ ms <- getModSummaryFromBuffer filename (contents, time) dflags parsed
421+ let pm =
422+ ParsedModule {
423+ pm_mod_summary = ms
424+ , pm_parsed_source = parsed
425+ , pm_extra_src_files=[] -- src imports not allowed
426+ , pm_annotations = hpm_annotations
427+ }
428+ warnings = mapMaybe (mkDiag dflags "Parser") $ bagToList warns
429+ pure (warnings, pm)
430+
431+
432+-- | This reads the pragma information directly from the provided buffer.
433+parsePragmasIntoDynFlags
434+ :: GhcMonad m
435+ => FilePath
436+ -> SB.StringBuffer
437+ -> Ex.ExceptT [FileDiagnostic] m DynFlags
438+parsePragmasIntoDynFlags fp contents = catchSrcErrors $ do
439+ dflags0 <- getSessionDynFlags
440+ let opts = Hdr.getOptions dflags0 contents fp
441+ (dflags, _, _) <- parseDynamicFilePragma dflags0 opts
442+ return dflags
443+
444+-- | Run something in a Ghc monad and catch the errors (SourceErrors and
445+-- compiler-internal exceptions like Panic or InstallationError).
446+catchSrcErrors :: GhcMonad m => m a -> Ex.ExceptT [FileDiagnostic] m a
447+catchSrcErrors ghcM = do
448+ dflags <- getDynFlags
449+ Ex.ExceptT $
450+ handleGhcException (ghcExceptionToDiagnostics dflags) $
451+ handleSourceError (sourceErrorToDiagnostics dflags) $
452+ Right <$> ghcM
453+ where
454+ ghcExceptionToDiagnostics dflags = return . Left . mkErrorsGhcException dflags
455+ sourceErrorToDiagnostics dflags = return . Left . toDiagnostics dflags . srcErrorMessages
src/Development/IDE/Functions/DependencyInformation.hsnew file+210
@@ -0,0 +1,210 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+module Development.IDE.Functions.DependencyInformation
5+ ( DependencyInformation(..)
6+ , RawDependencyInformation(..)
7+ , NodeError(..)
8+ , ModuleParseError(..)
9+ , TransitiveDependencies(..)
10+ , processDependencyInformation
11+ , transitiveDeps
12+ ) where
13+
14+import Control.DeepSeq
15+import Data.Bifunctor
16+import Development.IDE.Orphans()
17+import Data.Either
18+import Data.Foldable
19+import Data.Graph
20+import Data.List.NonEmpty (NonEmpty(..), nonEmpty)
21+import qualified Data.List.NonEmpty as NonEmpty
22+import Data.Map (Map)
23+import qualified Data.Map.Strict as MS
24+import qualified Data.Map.Lazy as ML
25+import Data.Maybe
26+import Data.Set (Set)
27+import qualified Data.Set as Set
28+import Data.Tuple.Extra (fst3)
29+import GHC.Generics (Generic)
30+
31+import Development.IDE.Types.Diagnostics
32+import Development.IDE.UtilGHC ()
33+
34+import GHC
35+import Module
36+
37+-- | Unprocessed results that we get from following all imports recursively starting from a module.
38+data RawDependencyInformation = RawDependencyInformation
39+ { moduleDependencies :: Map FilePath (Either ModuleParseError [(Located ModuleName, Maybe FilePath)])
40+ , pkgDependencies :: Map FilePath (Set InstalledUnitId)
41+ -- ^ Transitive dependencies on pkgs of this file, i.e. immidiate package dependencies and the
42+ -- transitive package dependencies of those packages.
43+ }
44+
45+data DependencyInformation =
46+ DependencyInformation
47+ { depErrorNodes :: Map FilePath (NonEmpty NodeError)
48+ -- ^ Nodes that cannot be processed correctly.
49+ , depModuleDeps :: Map FilePath (Set FilePath)
50+ -- ^ For a non-error node, this contains the set of module immediate dependencies
51+ -- in the same package.
52+ , depPkgDeps :: Map FilePath (Set InstalledUnitId)
53+ -- ^ For a non-error node, this contains the set of immediate pkg deps.
54+ } deriving (Show, Generic)
55+
56+instance NFData DependencyInformation
57+
58+-- | This does not contain the actual parse error as that is already reported by GetParsedModule.
59+data ModuleParseError = ModuleParseError
60+ deriving (Show, Generic)
61+
62+instance NFData ModuleParseError
63+
64+-- | Error when trying to locate a module.
65+data LocateError = LocateError [Diagnostic]
66+ deriving (Eq, Show, Generic)
67+
68+instance NFData LocateError
69+
70+-- | An error attached to a node in the dependency graph.
71+data NodeError
72+ = PartOfCycle (Located ModuleName) [FilePath]
73+ -- ^ This module is part of an import cycle. The module name corresponds
74+ -- to the import that enters the cycle starting from this module.
75+ -- The list of filepaths represents the elements
76+ -- in the cycle in unspecified order.
77+ | FailedToLocateImport (Located ModuleName)
78+ -- ^ This module has an import that couldn’t be located.
79+ | ParseError ModuleParseError
80+ | ParentOfErrorNode (Located ModuleName)
81+ -- ^ This module is the parent of a module that cannot be
82+ -- processed (either it cannot be parsed, is part of a cycle
83+ -- or the parent of another error node).
84+ deriving (Show, Generic)
85+
86+instance NFData NodeError where
87+ rnf (PartOfCycle m fs) = m `seq` rnf fs
88+ rnf (FailedToLocateImport m) = m `seq` ()
89+ rnf (ParseError e) = rnf e
90+ rnf (ParentOfErrorNode m) = m `seq` ()
91+
92+-- | A processed node in the dependency graph. If there was any error
93+-- during processing the node or any of its dependencies, this is an
94+-- `ErrorNode`. Otherwise it is a `SuccessNode`.
95+data NodeResult
96+ = ErrorNode (NonEmpty NodeError)
97+ | SuccessNode [(Located ModuleName, FilePath)]
98+ deriving Show
99+
100+partitionNodeResults :: [(a, NodeResult)] -> ([(a, NonEmpty NodeError)], [(a, [(Located ModuleName, FilePath)])])
101+partitionNodeResults = partitionEithers . map f
102+ where f (a, ErrorNode errs) = Left (a, errs)
103+ f (a, SuccessNode imps) = Right (a, imps)
104+
105+instance Semigroup NodeResult where
106+ ErrorNode errs <> ErrorNode errs' = ErrorNode (errs <> errs')
107+ ErrorNode errs <> SuccessNode _ = ErrorNode errs
108+ SuccessNode _ <> ErrorNode errs = ErrorNode errs
109+ SuccessNode a <> SuccessNode _ = SuccessNode a
110+
111+processDependencyInformation :: RawDependencyInformation -> DependencyInformation
112+processDependencyInformation rawResults =
113+ DependencyInformation
114+ { depErrorNodes = MS.mapMaybe errorNode resultGraph
115+ , depModuleDeps = moduleDeps
116+ , depPkgDeps = pkgDependencies rawResults
117+ }
118+ where resultGraph = buildResultGraph rawResults
119+ successEdges :: [(FilePath, FilePath, [FilePath])]
120+ successEdges = map (\(k,ks) -> (k,k,ks)) $ MS.toList $
121+ MS.map (map snd) $ MS.mapMaybe successNode resultGraph
122+ moduleDeps =
123+ MS.fromList $ map (\(_, v, vs) -> (v, Set.fromList vs)) successEdges
124+ errorNode (ErrorNode errs) = Just errs
125+ errorNode _ = Nothing
126+ successNode (SuccessNode fs) = Just fs
127+ successNode _ = Nothing
128+
129+-- | Given a dependency graph, buildResultGraph detects and propagates errors in that graph as follows:
130+-- 1. Mark each node that is part of an import cycle as an error node.
131+-- 2. Mark each node that has a parse error as an error node.
132+-- 3. Mark each node whose immediate children could not be located as an error.
133+-- 4. Recursively propagate errors to parents if they are not already error nodes.
134+buildResultGraph :: RawDependencyInformation -> Map FilePath NodeResult
135+buildResultGraph g = propagatedErrors
136+ where
137+ sccs = stronglyConnComp (graphEdges g)
138+ (_, cycles) = partitionSCC sccs
139+ cycleErrors :: Map FilePath NodeResult
140+ cycleErrors = MS.unionsWith (<>) $ map errorsForCycle cycles
141+ errorsForCycle :: [FilePath] -> Map FilePath NodeResult
142+ errorsForCycle files =
143+ MS.fromListWith (<>) (concatMap (cycleErrorsForFile files) files)
144+ cycleErrorsForFile :: [FilePath] -> FilePath -> [(FilePath,NodeResult)]
145+ cycleErrorsForFile cycle f =
146+ let entryPoints = mapMaybe (findImport f) cycle
147+ in map (\imp -> (f, ErrorNode (PartOfCycle imp cycle :| []))) entryPoints
148+ otherErrors = MS.map otherErrorsForFile (moduleDependencies g)
149+ otherErrorsForFile :: Either ModuleParseError [(Located ModuleName, Maybe FilePath)] -> NodeResult
150+ otherErrorsForFile (Left err) = ErrorNode (ParseError err :| [])
151+ otherErrorsForFile (Right imports) =
152+ let toEither (imp, Nothing) = Left imp
153+ toEither (imp, Just path) = Right (imp, path)
154+ (errs, imports') = partitionEithers (map toEither imports)
155+ in case nonEmpty errs of
156+ Nothing -> SuccessNode imports'
157+ Just errs' -> ErrorNode (NonEmpty.map FailedToLocateImport errs')
158+
159+ unpropagatedErrors = MS.unionWith (<>) cycleErrors otherErrors
160+ -- The recursion here is fine since we use a lazy map and
161+ -- we only recurse on SuccessNodes. In particular, we do not recurse
162+ -- on nodes that are part of a cycle as they are already marked as
163+ -- error nodes.
164+ propagatedErrors =
165+ ML.map propagate unpropagatedErrors
166+ propagate :: NodeResult -> NodeResult
167+ propagate n@(ErrorNode _) = n
168+ propagate n@(SuccessNode imps) =
169+ let results = map (\(imp, dep) -> (imp, propagatedErrors MS.! dep)) imps
170+ (errs, _) = partitionNodeResults results
171+ in case nonEmpty errs of
172+ Nothing -> n
173+ Just errs' -> ErrorNode (NonEmpty.map (ParentOfErrorNode . fst) errs')
174+ findImport :: FilePath -> FilePath -> Maybe (Located ModuleName)
175+ findImport file importedFile =
176+ case moduleDependencies g MS.! file of
177+ Left _ -> error "Tried to call findImport on a module with a parse error"
178+ Right imports ->
179+ fmap fst $ find (\(_, resolvedImp) -> resolvedImp == Just importedFile) imports
180+
181+graphEdges :: RawDependencyInformation -> [(FilePath, FilePath, [FilePath])]
182+graphEdges g =
183+ map (\(k, ks) -> (k, k, ks)) $ MS.toList $ MS.map deps $ moduleDependencies g
184+ where deps :: Either e [(i, Maybe FilePath)] -> [FilePath]
185+ deps (Left _) = []
186+ deps (Right imports) = mapMaybe snd imports
187+
188+partitionSCC :: [SCC a] -> ([a], [[a]])
189+partitionSCC (CyclicSCC xs:rest) = second (xs:) $ partitionSCC rest
190+partitionSCC (AcyclicSCC x:rest) = first (x:) $ partitionSCC rest
191+partitionSCC [] = ([], [])
192+
193+transitiveDeps :: DependencyInformation -> FilePath -> Maybe TransitiveDependencies
194+transitiveDeps DependencyInformation{..} f = do
195+ reachableVs <- Set.delete f . Set.fromList . map (fst3 . fromVertex) . reachable g <$> toVertex f
196+ let transitiveModuleDeps = filter (\v -> v `Set.member` reachableVs) $ map (fst3 . fromVertex) vs
197+ let transitivePkgDeps = Set.toList $ foldMap (\f -> MS.findWithDefault Set.empty f depPkgDeps) (f : transitiveModuleDeps)
198+ pure $ TransitiveDependencies {..}
199+ where (g, fromVertex, toVertex) = graphFromEdges (map (\(f, fs) -> (f, f, Set.toList fs)) $ MS.toList depModuleDeps)
200+ vs = topSort g
201+
202+data TransitiveDependencies = TransitiveDependencies
203+ { transitiveModuleDeps :: [FilePath]
204+ -- ^ Transitive module dependencies in topological order.
205+ -- The module itself is not included.
206+ , transitivePkgDeps :: [InstalledUnitId]
207+ -- ^ Transitive pkg dependencies in unspecified order.
208+ } deriving (Eq, Show, Generic)
209+
210+instance NFData TransitiveDependencies
src/Development/IDE/Spans/Documentation.hs → src/Development/IDE/Functions/Documentation.hsrenamed+23−51
@@ -1,12 +1,9 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
4−{-# LANGUAGE CPP #-}
5−#include "ghc-api-version.h"
6−
7−module Development.IDE.Spans.Documentation (
4+module Development.IDE.Functions.Documentation (
85 getDocumentation
9− , getDocumentationTryGhc
6+ , docHeaders
107 ) where
118
129import Control.Monad
@@ -14,35 +11,17 @@ import Data.List.Extra
1411import qualified Data.Map as M
1512import Data.Maybe
1613import qualified Data.Text as T
17−import Development.IDE.GHC.Compat
18−import Development.IDE.GHC.Error
19−import Development.IDE.Spans.Common
14+import Development.IDE.Functions.GHCError
15+import Development.IDE.Functions.SpanInfo
2016import FastString
17+import GHC
2118import SrcLoc
2219
2320
24−getDocumentationTryGhc
25− :: GhcMonad m
26− => [ParsedModule]
27− -> Name
28− -> m SpanDoc
29−-- getDocs goes through the GHCi codepaths which cause problems on ghc-lib.
30−-- See https://github.com/digital-asset/daml/issues/4152 for more details.
31−#if MIN_GHC_API_VERSION(8,6,0) && !defined(GHC_LIB)
32−getDocumentationTryGhc sources name = do
33− res <- catchSrcErrors "docs" $ getDocs name
34− case res of
35− Right (Right (Just docs, _)) -> return $ SpanDocString docs
36− _ -> return $ SpanDocText $ getDocumentation sources name
37−#else
38−getDocumentationTryGhc sources name = do
39− return $ SpanDocText $ getDocumentation sources name
40−#endif
41−
4221getDocumentation
43− :: [ParsedModule] -- ^ All of the possible modules it could be defined in.
44− -> Name -- ^ The name you want documentation for.
45− -> [T.Text]
22+ :: Name -- ^ The name you want documentation for.
23+ -> [TypecheckedModule] -- ^ All of the possible modules it could be defined in.
24+ -> [RealLocated AnnotationComment]
4625-- This finds any documentation between the name you want
4726-- documentation for and the one before it. This is only an
4827-- approximately correct algorithm and there are easily constructed
@@ -50,18 +29,17 @@ getDocumentation
5029-- may be edge cases where it is very wrong).
5130-- TODO : Build a version of GHC exactprint to extract this information
5231-- more accurately.
53−getDocumentation sources targetName = fromMaybe [] $ do
32+getDocumentation targetName tcs = fromMaybe [] $ do
5433 -- Find the module the target is defined in.
5534 targetNameSpan <- realSpan $ nameSrcSpan targetName
5635 tc <-
57− find ((==) (Just $ srcSpanFile targetNameSpan) . annotationFileName)
58− $ reverse sources -- TODO : Is reversing the list here really neccessary?
59−
60− -- Top level names bound by the module
61− let bs = [ n | let L _ HsModule{hsmodDecls} = pm_parsed_source tc
62− , L _ (ValD hsbind) <- hsmodDecls
63− , Just n <- [name_of_bind hsbind]
64− ]
36+ listToMaybe
37+ $ filter ((==) (Just $ srcSpanFile targetNameSpan) . annotationFileName)
38+ $ reverse tcs -- TODO : Is reversing the list here really neccessary?
39+ -- Names bound by the module (we want to exclude non-"top-level"
40+ -- bindings but unfortunately we get all here).
41+ let bs = mapMaybe name_of_bind
42+ (listifyAllSpans (tm_typechecked_source tc) :: [LHsBind GhcTc])
6543 -- Sort the names' source spans.
6644 let sortedSpans = sortedNameSpans bs
6745 -- Now go ahead and extract the docs.
@@ -74,7 +52,6 @@ getDocumentation sources targetName = fromMaybe [] $ do
7452 -- Annoyingly "-- |" documentation isn't annotated with a location,
7553 -- so you have to pull it out from the elements.
7654 pure
77− $ docHeaders
7855 $ filter (\(L target _) -> isBetween target prevNameSpan targetNameSpan)
7956 $ mapMaybe (\(L l v) -> L <$> realSpan l <*> pure v)
8057 $ join
@@ -83,16 +60,16 @@ getDocumentation sources targetName = fromMaybe [] $ do
8360 where
8461 -- Get the name bound by a binding. We only concern ourselves with
8562 -- @FunBind@ (which covers functions and variables).
86− name_of_bind :: HsBind GhcPs -> Maybe (Located RdrName)
87− name_of_bind FunBind {fun_id} = Just fun_id
63+ name_of_bind :: LHsBind GhcTc -> Maybe Name
64+ name_of_bind (L _ FunBind {fun_id}) = Just (getName (unLoc fun_id))
8865 name_of_bind _ = Nothing
8966 -- Get source spans from names, discard unhelpful spans, remove
9067 -- duplicates and sort.
91− sortedNameSpans :: [Located RdrName] -> [RealSrcSpan]
92− sortedNameSpans ls = nubSort (mapMaybe (realSpan . getLoc) ls)
68+ sortedNameSpans :: [Name] -> [RealSrcSpan]
69+ sortedNameSpans ls = nubSort (mapMaybe (realSpan . nameSrcSpan) ls)
9370 isBetween target before after = before <= target && target <= after
94− ann = snd . pm_annotations
95− annotationFileName :: ParsedModule -> Maybe FastString
71+ ann = snd . pm_annotations . tm_parsed_module
72+ annotationFileName :: TypecheckedModule -> Maybe FastString
9673 annotationFileName = fmap srcSpanFile . listToMaybe . realSpans . ann
9774 realSpans :: M.Map SrcSpan [Located a] -> [RealSrcSpan]
9875 realSpans =
@@ -106,10 +83,5 @@ docHeaders :: [RealLocated AnnotationComment]
10683docHeaders = mapMaybe (\(L _ x) -> wrk x)
10784 where
10885 wrk = \case
109− -- When `Opt_Haddock` is enabled.
11086 AnnDocCommentNext s -> Just $ T.pack s
111− -- When `Opt_KeepRawTokenStream` enabled.
112− AnnLineComment s -> if "-- |" `isPrefixOf` s
113− then Just $ T.pack s
114− else Nothing
11587 _ -> Nothing
src/Development/IDE/Functions/FindImports.hsnew file+148
@@ -0,0 +1,148 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE OverloadedStrings #-}
5+
6+module Development.IDE.Functions.FindImports
7+ ( getImportsParsed
8+ , locateModule
9+ , Import(..)
10+ ) where
11+
12+import Development.IDE.Functions.GHCError as ErrUtils
13+import Development.IDE.Orphans()
14+-- GHC imports
15+import BasicTypes (StringLiteral(..))
16+import DynFlags
17+import FastString
18+import GHC
19+import qualified HeaderInfo as Hdr
20+import qualified Module as M
21+import qualified GHC.LanguageExtensions.Type as GHC
22+import Packages
23+import Outputable (showSDoc, ppr, pprPanic)
24+import Finder
25+
26+-- standard imports
27+import Control.Monad.Extra
28+import Control.Monad.IO.Class
29+import qualified Control.Monad.Trans.Except as Ex
30+import System.FilePath
31+
32+data Import
33+ = FileImport FilePath
34+ | PackageImport M.InstalledUnitId
35+ deriving (Show)
36+
37+-- | GhcMonad function to chase imports of a module given as a StringBuffer. Returns given module's
38+-- name and its imports.
39+getImportsParsed :: Monad m =>
40+ DynFlags ->
41+ GHC.ParsedSource ->
42+ Ex.ExceptT [FileDiagnostic] m
43+ (M.ModuleName, [(Maybe FastString, Located M.ModuleName)])
44+getImportsParsed dflags (L loc parsed) = do
45+ let modName = maybe (GHC.mkModuleName "Main") GHC.unLoc $ GHC.hsmodName parsed
46+
47+ -- refuse source imports
48+ let srcImports = filter (ideclSource . GHC.unLoc) $ GHC.hsmodImports parsed
49+ when (not $ null srcImports) $ Ex.throwE $
50+ concat
51+ [ mkErrors dflags [(mloc, "Illegal source import of " <> GHC.moduleNameString (GHC.unLoc $ GHC.ideclName i))]
52+ | L mloc i <- srcImports ]
53+
54+ -- most of these corner cases are also present in https://hackage.haskell.org/package/ghc-8.6.1/docs/src/HeaderInfo.html#getImports
55+ -- but we want to avoid parsing the module twice
56+ let implicit_prelude = xopt GHC.ImplicitPrelude dflags
57+ implicit_imports = Hdr.mkPrelImports modName loc implicit_prelude $ GHC.hsmodImports parsed
58+
59+ -- filter out imports that come from packages
60+ return (modName, [(fmap sl_fs $ ideclPkgQual i, ideclName i)
61+ | i <- map GHC.unLoc $ implicit_imports ++ GHC.hsmodImports parsed
62+ , GHC.moduleNameString (GHC.unLoc $ ideclName i) /= "GHC.Prim"
63+ ])
64+
65+
66+-- | locate a module in the file system. Where we go from *daml to Haskell
67+locateModuleFile :: MonadIO m
68+ => DynFlags
69+ -> [String]
70+ -> (FilePath -> m Bool)
71+ -> ModuleName
72+ -> m (Maybe FilePath)
73+locateModuleFile dflags exts doesExist modName = do
74+ let candidates = [ prefix </> M.moduleNameSlashes modName <.> ext | prefix <- importPaths dflags, ext <- exts]
75+ findM doesExist candidates
76+
77+-- | locate a module in either the file system or the package database. Where we go from *daml to
78+-- Haskell
79+locateModule
80+ :: MonadIO m
81+ => DynFlags
82+ -> [String]
83+ -> (FilePath -> m Bool)
84+ -> Located ModuleName
85+ -> Maybe FastString
86+ -> m (Either [FileDiagnostic] Import)
87+locateModule dflags exts doesExist modName mbPkgName = do
88+ case mbPkgName of
89+ -- if a package name is given we only go look for a package
90+ Just _pkgName -> lookupInPackageDB dflags
91+ Nothing -> do
92+ -- first try to find the module as a file. If we can't find it try to find it in the package
93+ -- database.
94+ mbFile <- locateModuleFile dflags exts doesExist $ unLoc modName
95+ case mbFile of
96+ Nothing -> lookupInPackageDB dflags
97+ Just file -> return $ Right $ FileImport file
98+ where
99+ lookupInPackageDB dfs =
100+ case lookupModuleWithSuggestions dfs (unLoc modName) mbPkgName of
101+ LookupFound _m pkgConfig -> return $ Right $ PackageImport $ unitId pkgConfig
102+ reason -> return $ Left $ notFoundErr dfs modName reason
103+
104+-- | Don't call this on a found module.
105+notFoundErr :: DynFlags -> Located M.ModuleName -> LookupResult -> [FileDiagnostic]
106+notFoundErr dfs modName reason =
107+ mkError' $ ppr' $ cannotFindModule dfs modName0 $ lookupToFindResult reason
108+ where
109+ mkError' = mkError dfs (getLoc modName)
110+ modName0 = unLoc modName
111+ ppr' = showSDoc dfs
112+ -- We convert the lookup result to a find result to reuse GHC's cannotFindMoudle pretty printer.
113+ lookupToFindResult =
114+ \case
115+ LookupFound _m _pkgConfig ->
116+ pprPanic "Impossible: called lookupToFind on found module." (ppr modName0)
117+ LookupMultiple rs -> (FoundMultiple rs)
118+ LookupHidden pkg_hiddens mod_hiddens ->
119+ (NotFound
120+ { fr_paths = []
121+ , fr_pkg = Nothing
122+ , fr_pkgs_hidden = map (moduleUnitId . fst) pkg_hiddens
123+ , fr_mods_hidden = map (moduleUnitId . fst) mod_hiddens
124+ , fr_unusables = []
125+ , fr_suggestions = []
126+ })
127+ LookupUnusable unusable ->
128+ let unusables' = map get_unusable unusable
129+ get_unusable (m, ModUnusable r) = (moduleUnitId m, r)
130+ get_unusable (_, r) =
131+ pprPanic "findLookupResult: unexpected origin" (ppr r)
132+ in (NotFound
133+ { fr_paths = []
134+ , fr_pkg = Nothing
135+ , fr_pkgs_hidden = []
136+ , fr_mods_hidden = []
137+ , fr_unusables = unusables'
138+ , fr_suggestions = []
139+ })
140+ LookupNotFound suggest ->
141+ (NotFound
142+ { fr_paths = []
143+ , fr_pkg = Nothing
144+ , fr_pkgs_hidden = []
145+ , fr_mods_hidden = []
146+ , fr_unusables = []
147+ , fr_suggestions = suggest
148+ })
src/Development/IDE/Functions/GHCError.hsnew file+165
@@ -0,0 +1,165 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+{-# LANGUAGE DuplicateRecordFields #-}
4+module Development.IDE.Functions.GHCError
5+ ( mkDiag
6+ , toDiagnostics
7+ , srcSpanToLocation
8+ , srcSpanToFilename
9+
10+ -- * Producing GHC ErrorMessages
11+ , mkErrors
12+ , mkError
13+ , mkErrorDoc
14+ , mkErrorsGhcException
15+
16+ -- * Handling errors in the GHC monad (SourceError, ErrorMessages)
17+ , Diagnostic
18+ , FileDiagnostic
19+ , ErrorMessages -- included in module export below
20+ , ErrMsg
21+ , errMsgSpan
22+ , errMsgSeverity
23+ , mkPlainErrMsg
24+
25+ -- * utilities working with 'ErrMsg' and 'ErrorMessages'
26+ , zeroSpan
27+ , realSpan
28+ , noSpan
29+ ) where
30+
31+import Development.IDE.Types.Diagnostics as D
32+import qualified Data.Text as T
33+import Development.IDE.Orphans()
34+import qualified FastString as FS
35+import GHC
36+import Bag
37+import Data.Maybe
38+import ErrUtils
39+import SrcLoc
40+import qualified Outputable as Out
41+import qualified Language.Haskell.LSP.Types as LSP
42+
43+
44+
45+toDiagnostics :: DynFlags -> ErrorMessages -> [FileDiagnostic]
46+toDiagnostics dflags = mapMaybe (mkDiag dflags $ T.pack "Compiler") . bagToList
47+
48+
49+mkDiag :: DynFlags -> T.Text -> ErrMsg -> Maybe FileDiagnostic
50+mkDiag dflags src e =
51+ case toDSeverity $ errMsgSeverity e of
52+ Nothing -> Nothing
53+ Just bSeverity ->
54+ Just $ (srcSpanToFilename $ errMsgSpan e,)
55+ Diagnostic
56+ { _range = srcSpanToRange $ errMsgSpan e
57+ , _severity = Just bSeverity
58+ , _source = Just src
59+ , _message = T.pack $ Out.showSDoc dflags (ErrUtils.pprLocErrMsg e)
60+ , _code = Nothing
61+ , _relatedInformation = Nothing
62+ }
63+
64+-- | Convert a GHC SrcSpan to a DAML compiler Range
65+srcSpanToRange :: SrcSpan -> Range
66+srcSpanToRange (UnhelpfulSpan _) = noRange
67+srcSpanToRange (RealSrcSpan real) = realSrcSpanToRange real
68+
69+realSrcSpanToRange :: RealSrcSpan -> Range
70+realSrcSpanToRange real =
71+ Range (Position (srcSpanStartLine real - 1) (srcSpanStartCol real - 1))
72+ (Position (srcSpanEndLine real - 1) (srcSpanEndCol real - 1))
73+
74+-- | Extract a file name from a GHC SrcSpan (use message for unhelpful ones)
75+-- FIXME This may not be an _absolute_ file name, needs fixing.
76+srcSpanToFilename :: SrcSpan -> FilePath
77+srcSpanToFilename (UnhelpfulSpan fs) = FS.unpackFS fs
78+srcSpanToFilename (RealSrcSpan real) = FS.unpackFS $ srcSpanFile real
79+
80+srcSpanToLocation :: SrcSpan -> Location
81+srcSpanToLocation src =
82+ Location (LSP.filePathToUri $ srcSpanToFilename src) (srcSpanToRange src)
83+
84+-- | Convert a GHC severity to a DAML compiler Severity. Severities below
85+-- "Warning" level are dropped (returning Nothing).
86+toDSeverity :: GHC.Severity -> Maybe D.DiagnosticSeverity
87+toDSeverity SevOutput = Nothing
88+toDSeverity SevInteractive = Nothing
89+toDSeverity SevDump = Nothing
90+toDSeverity SevInfo = Just DsInfo
91+toDSeverity SevWarning = Just DsWarning
92+toDSeverity SevError = Just DsError
93+toDSeverity SevFatal = Just DsError
94+
95+
96+-- | Produce a bag of GHC-style errors (@ErrorMessages@) from the given
97+-- (optional) locations and message strings.
98+mkErrors :: DynFlags -> [(SrcSpan, String)] -> [FileDiagnostic]
99+mkErrors dflags = concatMap (uncurry $ mkError dflags)
100+
101+-- | Produce a GHC-style error from a source span and a message.
102+mkError :: DynFlags -> SrcSpan -> String -> [FileDiagnostic]
103+mkError dflags sp = toDiagnostics dflags . Bag.listToBag . pure . mkPlainErrMsg dflags sp . Out.text
104+
105+-- | Produce a GHC-style error from a source span and a message.
106+mkErrorDoc :: DynFlags -> SrcSpan -> Out.SDoc -> [FileDiagnostic]
107+mkErrorDoc dflags sp = toDiagnostics dflags . Bag.listToBag . pure . mkPlainErrMsg dflags sp
108+
109+
110+-- | Produces an "unhelpful" source span with the given string.
111+noSpan :: String -> SrcSpan
112+noSpan = UnhelpfulSpan . FS.fsLit
113+
114+
115+-- | creates a span with zero length in the filename of the argument passed
116+zeroSpan :: FS.FastString -- ^ file path of span
117+ -> RealSrcSpan
118+zeroSpan file = realSrcLocSpan (mkRealSrcLoc file 1 1)
119+
120+realSpan :: SrcSpan
121+ -> Maybe RealSrcSpan
122+realSpan = \case
123+ RealSrcSpan r -> Just r
124+ UnhelpfulSpan _ -> Nothing
125+
126+
127+mkErrorsGhcException :: DynFlags -> GhcException -> [FileDiagnostic]
128+mkErrorsGhcException dflags exc = mkErrors dflags [(noSpan "<Internal>", showGHCE dflags exc)]
129+
130+showGHCE :: DynFlags -> GhcException -> String
131+showGHCE dflags exc = case exc of
132+ Signal n
133+ -> "Signal: " <> show n
134+
135+ Panic s
136+ -> unwords ["Compilation Issue:", s, "\n", requestReport]
137+ PprPanic s sdoc
138+ -> unlines ["Compilation Issue", s,""
139+ , Out.showSDoc dflags sdoc
140+ , requestReport ]
141+
142+ Sorry s
143+ -> "Unsupported feature: " <> s
144+ PprSorry s sdoc
145+ -> unlines ["Unsupported feature: ", s,""
146+ , Out.showSDoc dflags sdoc]
147+
148+
149+ ---------- errors below should not happen at all --------
150+ InstallationError str
151+ -> "Installation error: " <> str
152+
153+ UsageError str -- should never happen
154+ -> unlines ["Unexpected usage error", str]
155+
156+ CmdLineError str
157+ -> unlines ["Unexpected usage error", str]
158+
159+ ProgramError str
160+ -> "Program error: " <> str
161+ PprProgramError str sdoc ->
162+ unlines ["Program error:", str,""
163+ , Out.showSDoc dflags sdoc]
164+ where
165+ requestReport = "Please report this bug to the compiler authors."
src/Development/IDE/Functions/SpanInfo.hsnew file+134
@@ -0,0 +1,134 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+-- ORIGINALLY COPIED FROM https://github.com/commercialhaskell/intero
5+
6+{-# LANGUAGE RankNTypes #-}
7+
8+-- | Get information on modules, identifiers, etc.
9+
10+module Development.IDE.Functions.SpanInfo(getSpanInfo,listifyAllSpans) where
11+
12+import ConLike
13+import Control.Monad
14+import qualified CoreUtils
15+import Data.Data
16+import qualified Data.Generics
17+import Data.List
18+import Data.Maybe
19+import DataCon
20+import Desugar
21+import GHC
22+import GhcMonad
23+import FastString (mkFastString)
24+import Development.IDE.Types.SpanInfo
25+import Development.IDE.Functions.GHCError (zeroSpan)
26+import Prelude hiding (mod)
27+import TcHsSyn
28+import Var
29+
30+-- | Get ALL source spans in the module.
31+getSpanInfo :: GhcMonad m
32+ => [(Located ModuleName, Maybe FilePath)] -- ^ imports
33+ -> TypecheckedModule
34+ -> m [SpanInfo]
35+getSpanInfo mods tcm =
36+ do let tcs = tm_typechecked_source tcm
37+ bs = listifyAllSpans tcs :: [LHsBind GhcTc]
38+ es = listifyAllSpans tcs :: [LHsExpr GhcTc]
39+ ps = listifyAllSpans' tcs :: [Pat GhcTc]
40+ bts <- mapM (getTypeLHsBind tcm) bs -- binds
41+ ets <- mapM (getTypeLHsExpr tcm) es -- expressions
42+ pts <- mapM (getTypeLPat tcm) ps -- patterns
43+ let imports = importInfo mods
44+ let exprs = imports ++ concat bts ++ catMaybes (ets ++ pts)
45+ return (mapMaybe toSpanInfo (sortBy cmp exprs))
46+ where cmp (_,a,_) (_,b,_)
47+ | a `isSubspanOf` b = LT
48+ | b `isSubspanOf` a = GT
49+ | otherwise = EQ
50+
51+-- | Get the name and type of a binding.
52+getTypeLHsBind :: (GhcMonad m)
53+ => TypecheckedModule
54+ -> LHsBind GhcTc
55+ -> m [(SpanSource, SrcSpan, Maybe Type)]
56+getTypeLHsBind _ (L _spn FunBind{fun_id = pid,fun_matches = MG _ _ _typ}) =
57+ return [(Named $ getName (unLoc pid), getLoc pid, Just (varType (unLoc pid)))]
58+getTypeLHsBind _ _ = return []
59+
60+-- | Get the name and type of an expression.
61+getTypeLHsExpr :: (GhcMonad m)
62+ => TypecheckedModule
63+ -> LHsExpr GhcTc
64+ -> m (Maybe (SpanSource, SrcSpan, Maybe Type))
65+getTypeLHsExpr _ e = do
66+ hs_env <- getSession
67+ (_, mbe) <- liftIO (deSugarExpr hs_env e)
68+ return $
69+ case mbe of
70+ Just expr ->
71+ Just (getSpanSource (unLoc e), getLoc e, Just (CoreUtils.exprType expr))
72+ Nothing -> Nothing
73+ where
74+ getSpanSource :: HsExpr GhcTc -> SpanSource
75+ getSpanSource (HsVar _ (L _ i)) = Named (getName i)
76+ getSpanSource (HsConLikeOut _ (RealDataCon dc)) = Named (dataConName dc)
77+ getSpanSource RecordCon {rcon_con_name} = Named (getName rcon_con_name)
78+ getSpanSource (HsWrap _ _ xpr) = getSpanSource xpr
79+ getSpanSource (HsPar _ xpr) = getSpanSource (unLoc xpr)
80+ getSpanSource _ = NoSource
81+
82+-- | Get the name and type of a pattern.
83+getTypeLPat :: (GhcMonad m)
84+ => TypecheckedModule
85+ -> Pat GhcTc
86+ -> m (Maybe (SpanSource, SrcSpan, Maybe Type))
87+getTypeLPat _ pat =
88+ let (src, spn) = getSpanSource pat in
89+ return $ Just (src, spn, Just (hsPatType pat))
90+ where
91+ getSpanSource :: Pat GhcTc -> (SpanSource, SrcSpan)
92+ getSpanSource (VarPat _ (L spn vid)) = (Named (getName vid), spn)
93+ getSpanSource (ConPatOut (L spn (RealDataCon dc)) _ _ _ _ _ _) =
94+ (Named (dataConName dc), spn)
95+ getSpanSource _ = (NoSource, noSrcSpan)
96+
97+importInfo :: [(Located ModuleName, Maybe FilePath)]
98+ -> [(SpanSource, SrcSpan, Maybe Type)]
99+importInfo = mapMaybe (uncurry wrk) where
100+ wrk :: Located ModuleName -> Maybe FilePath -> Maybe (SpanSource, SrcSpan, Maybe Type)
101+ wrk modName = \case
102+ Nothing -> Nothing
103+ Just afp -> Just (afpToSpanSource afp, getLoc modName, Nothing)
104+
105+ -- TODO make this point to the module name
106+ afpToSpanSource :: FilePath -> SpanSource
107+ afpToSpanSource afp = Span $ RealSrcSpan $ zeroSpan $ mkFastString afp
108+
109+-- | Get ALL source spans in the source.
110+listifyAllSpans :: Typeable a
111+ => TypecheckedSource -> [Located a]
112+listifyAllSpans tcs =
113+ Data.Generics.listify p tcs
114+ where p (L spn _) = isGoodSrcSpan spn
115+-- This is a version of `listifyAllSpans` specialized on picking out
116+-- patterns. It comes about since GHC now defines `type LPat p = Pat
117+-- p` (no top-level locations).
118+listifyAllSpans' :: Typeable a
119+ => TypecheckedSource -> [Pat a]
120+listifyAllSpans' tcs = Data.Generics.listify (const True) tcs
121+
122+
123+-- | Pretty print the types into a 'SpanInfo'.
124+toSpanInfo :: (SpanSource, SrcSpan, Maybe Type) -> Maybe SpanInfo
125+toSpanInfo (name,mspan,typ) =
126+ case mspan of
127+ RealSrcSpan spn ->
128+ Just (SpanInfo (srcSpanStartLine spn)
129+ (srcSpanStartCol spn - 1)
130+ (srcSpanEndLine spn)
131+ (srcSpanEndCol spn - 1)
132+ typ
133+ name)
134+ _ -> Nothing
src/Development/IDE/GHC/Warnings.hs → src/Development/IDE/Functions/Warnings.hsrenamed+13−13
@@ -1,19 +1,20 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
4−module Development.IDE.GHC.Warnings(withWarnings) where
4+module Development.IDE.Functions.Warnings(withWarnings) where
55
6−import GhcMonad
76import ErrUtils
7+import GhcMonad
88import GhcPlugins as GHC hiding (Var)
99
10+import qualified Data.Text as T
11+import Data.Maybe
1012import Control.Concurrent.Extra
1113import Control.Monad.Extra
12−import qualified Data.Text as T
1314
1415import Development.IDE.Types.Diagnostics
15−import Development.IDE.GHC.Util
16−import Development.IDE.GHC.Error
16+import Development.IDE.UtilGHC
17+import Development.IDE.Functions.GHCError
1718
1819
1920-- | Take a GHC monadic action (e.g. @typecheckModule pm@ for some
@@ -25,19 +26,18 @@ import Development.IDE.GHC.Error
2526-- https://github.com/ghc/ghc/blob/5f1d949ab9e09b8d95319633854b7959df06eb58/compiler/main/GHC.hs#L623-L640
2627-- which basically says that log_action is taken from the ModSummary when GHC feels like it.
2728-- The given argument lets you refresh a ModSummary log_action
28−withWarnings :: GhcMonad m => T.Text -> ((ModSummary -> ModSummary) -> m a) -> m ([(WarnReason, FileDiagnostic)], a)
29−withWarnings diagSource action = do
29+withWarnings :: GhcMonad m => T.Text -> ((ModSummary -> ModSummary) -> m a) -> m ([FileDiagnostic], a)
30+withWarnings phase action = do
3031 warnings <- liftIO $ newVar []
3132 oldFlags <- getDynFlags
32− let newAction :: DynFlags -> WarnReason -> Severity -> SrcSpan -> PprStyle -> SDoc -> IO ()
33− newAction dynFlags wr _ loc style msg = do
34− let wr_d = fmap (wr,) $ diagFromErrMsg diagSource dynFlags $ mkWarnMsg dynFlags loc (queryQual style) msg
35− modifyVar_ warnings $ return . (wr_d:)
33+ let newAction dynFlags _ _ loc _ msg = do
34+ let d = mkDiag dynFlags phase $ mkPlainWarnMsg dynFlags loc msg
35+ modifyVar_ warnings $ return . (d:)
3636 setLogAction newAction
3737 res <- action $ \x -> x{ms_hspp_opts = (ms_hspp_opts x){log_action = newAction}}
3838 setLogAction $ log_action oldFlags
3939 warns <- liftIO $ readVar warnings
40− return (reverse $ concat warns, res)
40+ return (reverse $ catMaybes warns, res)
4141
4242setLogAction :: GhcMonad m => LogAction -> m ()
4343setLogAction act = void $ modifyDynFlags $ \dyn -> dyn{log_action = act}
src/Development/IDE/GHC/Compat.hsdeleted−309
@@ -1,309 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE CPP #-}
5−{-# LANGUAGE PatternSynonyms #-}
6−#include "ghc-api-version.h"
7−
8−-- | Attempt at hiding the GHC version differences we can.
9−module Development.IDE.GHC.Compat(
10− getHeaderImports,
11− HieFileResult(..),
12− HieFile,
13− hieExportNames,
14− hie_module,
15− mkHieFile,
16− writeHieFile,
17− readHieFile,
18− supportsHieFiles,
19− setDefaultHieDir,
20− dontWriteHieFiles,
21−#if !MIN_GHC_API_VERSION(8,8,0)
22− ml_hie_file,
23−#endif
24− hPutStringBuffer,
25− includePathsGlobal,
26− includePathsQuote,
27− addIncludePathsQuote,
28− getModuleHash,
29− getPackageName,
30− pattern DerivD,
31− pattern ForD,
32− pattern InstD,
33− pattern TyClD,
34− pattern ValD,
35− pattern ClassOpSig,
36− pattern IEThingAll,
37− pattern IEThingWith,
38− GHC.ModLocation,
39− Module.addBootSuffix,
40− pattern ModLocation,
41− getConArgs,
42−
43− module GHC
44− ) where
45−
46−import StringBuffer
47−import DynFlags
48−import FieldLabel
49−import Fingerprint (Fingerprint)
50−import qualified Module
51−import Packages
52−
53−import qualified GHC
54−import GHC hiding (
55− ClassOpSig, DerivD, ForD, IEThingAll, IEThingWith, InstD, TyClD, ValD, ModLocation
56−#if MIN_GHC_API_VERSION(8,6,0)
57− , getConArgs
58−#endif
59− )
60−import qualified HeaderInfo as Hdr
61−import Avail
62−import ErrUtils (ErrorMessages)
63−import FastString (FastString)
64−
65−#if MIN_GHC_API_VERSION(8,10,0)
66−import HscTypes (mi_mod_hash)
67−#endif
68−
69−#if MIN_GHC_API_VERSION(8,8,0)
70−import Control.Applicative ((<|>))
71−import Development.IDE.GHC.HieAst (mkHieFile)
72−import HieBin
73−import HieTypes
74−
75−supportsHieFiles :: Bool
76−supportsHieFiles = True
77−
78−hieExportNames :: HieFile -> [(SrcSpan, Name)]
79−hieExportNames = nameListFromAvails . hie_exports
80−
81−#else
82−
83−#if MIN_GHC_API_VERSION(8,6,0)
84−import BinIface
85−import Data.IORef
86−import IfaceEnv
87−#endif
88−
89−import Binary
90−import Control.Exception (catch)
91−import Data.ByteString (ByteString)
92−import GhcPlugins hiding (ModLocation)
93−import NameCache
94−import TcRnTypes
95−import System.IO
96−import Foreign.ForeignPtr
97−import MkIface
98−
99−
100−hPutStringBuffer :: Handle -> StringBuffer -> IO ()
101−hPutStringBuffer hdl (StringBuffer buf len cur)
102− = withForeignPtr (plusForeignPtr buf cur) $ \ptr ->
103− hPutBuf hdl ptr len
104−
105−#endif
106−
107−#if !MIN_GHC_API_VERSION(8,6,0)
108−includePathsGlobal, includePathsQuote :: [String] -> [String]
109−includePathsGlobal = id
110−includePathsQuote = const []
111−#endif
112−
113−
114−addIncludePathsQuote :: FilePath -> DynFlags -> DynFlags
115−#if MIN_GHC_API_VERSION(8,6,0)
116−addIncludePathsQuote path x = x{includePaths = f $ includePaths x}
117− where f i = i{includePathsQuote = path : includePathsQuote i}
118−#else
119−addIncludePathsQuote path x = x{includePaths = path : includePaths x}
120−#endif
121−
122−pattern DerivD :: DerivDecl p -> HsDecl p
123−pattern DerivD x <-
124−#if MIN_GHC_API_VERSION(8,6,0)
125− GHC.DerivD _ x
126−#else
127− GHC.DerivD x
128−#endif
129−
130−pattern ForD :: ForeignDecl p -> HsDecl p
131−pattern ForD x <-
132−#if MIN_GHC_API_VERSION(8,6,0)
133− GHC.ForD _ x
134−#else
135− GHC.ForD x
136−#endif
137−
138−pattern ValD :: HsBind p -> HsDecl p
139−pattern ValD x <-
140−#if MIN_GHC_API_VERSION(8,6,0)
141− GHC.ValD _ x
142−#else
143− GHC.ValD x
144−#endif
145−
146−pattern InstD :: InstDecl p -> HsDecl p
147−pattern InstD x <-
148−#if MIN_GHC_API_VERSION(8,6,0)
149− GHC.InstD _ x
150−#else
151− GHC.InstD x
152−#endif
153−
154−pattern TyClD :: TyClDecl p -> HsDecl p
155−pattern TyClD x <-
156−#if MIN_GHC_API_VERSION(8,6,0)
157− GHC.TyClD _ x
158−#else
159− GHC.TyClD x
160−#endif
161−
162−pattern ClassOpSig :: Bool -> [Located (IdP pass)] -> LHsSigType pass -> Sig pass
163−pattern ClassOpSig a b c <-
164−#if MIN_GHC_API_VERSION(8,6,0)
165− GHC.ClassOpSig _ a b c
166−#else
167− GHC.ClassOpSig a b c
168−#endif
169−
170−pattern IEThingWith :: LIEWrappedName (IdP pass) -> IEWildcard -> [LIEWrappedName (IdP pass)] -> [Located (FieldLbl (IdP pass))] -> IE pass
171−pattern IEThingWith a b c d <-
172−#if MIN_GHC_API_VERSION(8,6,0)
173− GHC.IEThingWith _ a b c d
174−#else
175− GHC.IEThingWith a b c d
176−#endif
177−
178−pattern ModLocation :: Maybe FilePath -> FilePath -> FilePath -> GHC.ModLocation
179−pattern ModLocation a b c <-
180−#if MIN_GHC_API_VERSION(8,8,0)
181− GHC.ModLocation a b c _ where ModLocation a b c = GHC.ModLocation a b c ""
182−#else
183− GHC.ModLocation a b c where ModLocation a b c = GHC.ModLocation a b c
184−#endif
185−
186−pattern IEThingAll :: LIEWrappedName (IdP pass) -> IE pass
187−pattern IEThingAll a <-
188−#if MIN_GHC_API_VERSION(8,6,0)
189− GHC.IEThingAll _ a
190−#else
191− GHC.IEThingAll a
192−#endif
193−
194−setDefaultHieDir :: FilePath -> DynFlags -> DynFlags
195−setDefaultHieDir _f d =
196−#if MIN_GHC_API_VERSION(8,8,0)
197− d { hieDir = hieDir d <|> Just _f}
198−#else
199− d
200−#endif
201−
202−dontWriteHieFiles :: DynFlags -> DynFlags
203−dontWriteHieFiles d =
204−#if MIN_GHC_API_VERSION(8,8,0)
205− gopt_unset d Opt_WriteHie
206−#else
207− d
208−#endif
209−
210−nameListFromAvails :: [AvailInfo] -> [(SrcSpan, Name)]
211−nameListFromAvails as =
212− map (\n -> (nameSrcSpan n, n)) (concatMap availNames as)
213−
214−#if !MIN_GHC_API_VERSION(8,8,0)
215−-- Reimplementations of functions for HIE files for GHC 8.6
216−
217−mkHieFile :: ModSummary -> TcGblEnv -> RenamedSource -> ByteString -> Hsc HieFile
218−mkHieFile ms ts _ _ = return (HieFile (ms_mod ms) es)
219− where
220− es = nameListFromAvails (mkIfaceExports (tcg_exports ts))
221−
222−ml_hie_file :: GHC.ModLocation -> FilePath
223−ml_hie_file ml = ml_hi_file ml ++ ".hie"
224−
225−data HieFile = HieFile {hie_module :: Module, hie_exports :: [(SrcSpan, Name)]}
226−
227−hieExportNames :: HieFile -> [(SrcSpan, Name)]
228−hieExportNames = hie_exports
229−
230−instance Binary HieFile where
231− put_ bh (HieFile m es) = do
232− put_ bh m
233− put_ bh es
234−
235− get bh = do
236− mod <- get bh
237− es <- get bh
238− return (HieFile mod es)
239−
240−data HieFileResult = HieFileResult { hie_file_result :: HieFile }
241−
242−writeHieFile :: FilePath -> HieFile -> IO ()
243−readHieFile :: NameCache -> FilePath -> IO (HieFileResult, ())
244−supportsHieFiles :: Bool
245−
246−#if MIN_GHC_API_VERSION(8,6,0)
247−
248−writeHieFile fp hie = do
249− bh <- openBinMem (1024 * 1024)
250− putWithUserData (const $ return ()) bh hie
251− writeBinMem bh fp
252−
253−readHieFile nc fp = do
254− bh <- readBinMem fp
255− nc' <- newIORef nc
256− hie_file <- getWithUserData (NCU (atomicModifyIORef' nc')) bh
257− return (HieFileResult hie_file, ())
258−
259−supportsHieFiles = True
260−
261−#else
262−
263−supportsHieFiles = False
264−
265−writeHieFile _ _ = return ()
266−
267−readHieFile _ _ = return undefined
268−
269−#endif
270−
271−#endif
272−
273−getHeaderImports
274− :: DynFlags
275− -> StringBuffer
276− -> FilePath
277− -> FilePath
278− -> IO
279− ( Either
280− ErrorMessages
281− ( [(Maybe FastString, Located ModuleName)]
282− , [(Maybe FastString, Located ModuleName)]
283− , Located ModuleName
284− )
285− )
286−#if MIN_GHC_API_VERSION(8,8,0)
287−getHeaderImports = Hdr.getImports
288−#else
289−getHeaderImports a b c d =
290− catch (Right <$> Hdr.getImports a b c d)
291− (return . Left . srcErrorMessages)
292−#endif
293−
294−getModuleHash :: ModIface -> Fingerprint
295−#if MIN_GHC_API_VERSION(8,10,0)
296−getModuleHash = mi_mod_hash . mi_final_exts
297−#else
298−getModuleHash = mi_mod_hash
299−#endif
300−
301−getConArgs :: ConDecl pass -> HsConDeclDetails pass
302−#if MIN_GHC_API_VERSION(8,6,0)
303−getConArgs = GHC.getConArgs
304−#else
305−getConArgs = GHC.getConDetails
306−#endif
307−
308−getPackageName :: DynFlags -> Module.InstalledUnitId -> Maybe PackageName
309−getPackageName dfs i = packageName <$> lookupPackage dfs (Module.DefiniteUnitId (Module.DefUnitId i))
src/Development/IDE/GHC/Error.hsdeleted−202
@@ -1,202 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−module Development.IDE.GHC.Error
4− (
5− -- * Producing Diagnostic values
6− diagFromErrMsgs
7− , diagFromErrMsg
8− , diagFromString
9− , diagFromStrings
10− , diagFromGhcException
11− , catchSrcErrors
12− , mergeDiagnostics
13−
14− -- * utilities working with spans
15− , srcSpanToLocation
16− , srcSpanToRange
17− , srcSpanToFilename
18− , zeroSpan
19− , realSpan
20− , isInsideSrcSpan
21− , noSpan
22−
23− -- * utilities working with severities
24− , toDSeverity
25− ) where
26−
27−import Development.IDE.Types.Diagnostics as D
28−import qualified Data.Text as T
29−import Development.IDE.Types.Location
30−import Development.IDE.GHC.Orphans()
31−import qualified FastString as FS
32−import GHC
33−import Bag
34−import DynFlags
35−import HscTypes
36−import Panic
37−import ErrUtils
38−import SrcLoc
39−import qualified Outputable as Out
40−import Exception (ExceptionMonad)
41−
42−
43−
44−diagFromText :: T.Text -> D.DiagnosticSeverity -> SrcSpan -> T.Text -> FileDiagnostic
45−diagFromText diagSource sev loc msg = (toNormalizedFilePath' $ srcSpanToFilename loc,ShowDiag,)
46− Diagnostic
47− { _range = srcSpanToRange loc
48− , _severity = Just sev
49− , _source = Just diagSource -- not shown in the IDE, but useful for ghcide developers
50− , _message = msg
51− , _code = Nothing
52− , _relatedInformation = Nothing
53− , _tags = Nothing
54− }
55−
56−-- | Produce a GHC-style error from a source span and a message.
57−diagFromErrMsg :: T.Text -> DynFlags -> ErrMsg -> [FileDiagnostic]
58−diagFromErrMsg diagSource dflags e =
59− [ diagFromText diagSource sev (errMsgSpan e) $ T.pack $ Out.showSDoc dflags $
60− ErrUtils.formatErrDoc dflags $ ErrUtils.errMsgDoc e
61− | Just sev <- [toDSeverity $ errMsgSeverity e]]
62−
63−
64−diagFromErrMsgs :: T.Text -> DynFlags -> Bag ErrMsg -> [FileDiagnostic]
65−diagFromErrMsgs diagSource dflags = concatMap (diagFromErrMsg diagSource dflags) . bagToList
66−
67−-- | Merges two sorted lists of diagnostics, removing duplicates.
68−-- Assumes all the diagnostics are for the same file.
69−mergeDiagnostics :: [FileDiagnostic] -> [FileDiagnostic] -> [FileDiagnostic]
70−mergeDiagnostics aa [] = aa
71−mergeDiagnostics [] bb = bb
72−mergeDiagnostics (a@(_,_,ad@Diagnostic{_range = ar}):aa) (b@(_,_,bd@Diagnostic{_range=br}):bb)
73− | ar < br
74− = a : mergeDiagnostics aa (b:bb)
75− | br < ar
76− = b : mergeDiagnostics (a:aa) bb
77− | _severity ad == _severity bd
78− && _source ad == _source bd
79− && _message ad == _message bd
80− && _code ad == _code bd
81− && _relatedInformation ad == _relatedInformation bd
82− && _tags ad == _tags bd
83− = a : mergeDiagnostics aa bb
84− | otherwise
85− = a : b : mergeDiagnostics aa bb
86−
87−-- | Convert a GHC SrcSpan to a DAML compiler Range
88−srcSpanToRange :: SrcSpan -> Range
89−srcSpanToRange (UnhelpfulSpan _) = noRange
90−srcSpanToRange (RealSrcSpan real) = realSrcSpanToRange real
91−
92−realSrcSpanToRange :: RealSrcSpan -> Range
93−realSrcSpanToRange real =
94− Range (Position (srcSpanStartLine real - 1) (srcSpanStartCol real - 1))
95− (Position (srcSpanEndLine real - 1) (srcSpanEndCol real - 1))
96−
97−-- | Extract a file name from a GHC SrcSpan (use message for unhelpful ones)
98−-- FIXME This may not be an _absolute_ file name, needs fixing.
99−srcSpanToFilename :: SrcSpan -> FilePath
100−srcSpanToFilename (UnhelpfulSpan fs) = FS.unpackFS fs
101−srcSpanToFilename (RealSrcSpan real) = FS.unpackFS $ srcSpanFile real
102−
103−srcSpanToLocation :: SrcSpan -> Location
104−srcSpanToLocation src =
105− -- important that the URI's we produce have been properly normalized, otherwise they point at weird places in VS Code
106− Location (fromNormalizedUri $ filePathToUri' $ toNormalizedFilePath' $ srcSpanToFilename src) (srcSpanToRange src)
107−
108−isInsideSrcSpan :: Position -> SrcSpan -> Bool
109−p `isInsideSrcSpan` r = sp <= p && p <= ep
110− where Range sp ep = srcSpanToRange r
111−
112−-- | Convert a GHC severity to a DAML compiler Severity. Severities below
113−-- "Warning" level are dropped (returning Nothing).
114−toDSeverity :: GHC.Severity -> Maybe D.DiagnosticSeverity
115−toDSeverity SevOutput = Nothing
116−toDSeverity SevInteractive = Nothing
117−toDSeverity SevDump = Nothing
118−toDSeverity SevInfo = Just DsInfo
119−toDSeverity SevWarning = Just DsWarning
120−toDSeverity SevError = Just DsError
121−toDSeverity SevFatal = Just DsError
122−
123−
124−-- | Produce a bag of GHC-style errors (@ErrorMessages@) from the given
125−-- (optional) locations and message strings.
126−diagFromStrings :: T.Text -> D.DiagnosticSeverity -> [(SrcSpan, String)] -> [FileDiagnostic]
127−diagFromStrings diagSource sev = concatMap (uncurry (diagFromString diagSource sev))
128−
129−-- | Produce a GHC-style error from a source span and a message.
130−diagFromString :: T.Text -> D.DiagnosticSeverity -> SrcSpan -> String -> [FileDiagnostic]
131−diagFromString diagSource sev sp x = [diagFromText diagSource sev sp $ T.pack x]
132−
133−
134−-- | Produces an "unhelpful" source span with the given string.
135−noSpan :: String -> SrcSpan
136−noSpan = UnhelpfulSpan . FS.fsLit
137−
138−
139−-- | creates a span with zero length in the filename of the argument passed
140−zeroSpan :: FS.FastString -- ^ file path of span
141− -> RealSrcSpan
142−zeroSpan file = realSrcLocSpan (mkRealSrcLoc file 1 1)
143−
144−realSpan :: SrcSpan
145− -> Maybe RealSrcSpan
146−realSpan = \case
147− RealSrcSpan r -> Just r
148− UnhelpfulSpan _ -> Nothing
149−
150−
151−-- | Run something in a Ghc monad and catch the errors (SourceErrors and
152−-- compiler-internal exceptions like Panic or InstallationError).
153−catchSrcErrors :: (HasDynFlags m, ExceptionMonad m) => T.Text -> m a -> m (Either [FileDiagnostic] a)
154−catchSrcErrors fromWhere ghcM = do
155− dflags <- getDynFlags
156− handleGhcException (ghcExceptionToDiagnostics dflags) $
157− handleSourceError (sourceErrorToDiagnostics dflags) $
158− Right <$> ghcM
159− where
160− ghcExceptionToDiagnostics dflags = return . Left . diagFromGhcException fromWhere dflags
161− sourceErrorToDiagnostics dflags = return . Left . diagFromErrMsgs fromWhere dflags . srcErrorMessages
162−
163−
164−diagFromGhcException :: T.Text -> DynFlags -> GhcException -> [FileDiagnostic]
165−diagFromGhcException diagSource dflags exc = diagFromString diagSource DsError (noSpan "<Internal>") (showGHCE dflags exc)
166−
167−showGHCE :: DynFlags -> GhcException -> String
168−showGHCE dflags exc = case exc of
169− Signal n
170− -> "Signal: " <> show n
171−
172− Panic s
173− -> unwords ["Compilation Issue:", s, "\n", requestReport]
174− PprPanic s sdoc
175− -> unlines ["Compilation Issue", s,""
176− , Out.showSDoc dflags sdoc
177− , requestReport ]
178−
179− Sorry s
180− -> "Unsupported feature: " <> s
181− PprSorry s sdoc
182− -> unlines ["Unsupported feature: ", s,""
183− , Out.showSDoc dflags sdoc]
184−
185−
186− ---------- errors below should not happen at all --------
187− InstallationError str
188− -> "Installation error: " <> str
189−
190− UsageError str -- should never happen
191− -> unlines ["Unexpected usage error", str]
192−
193− CmdLineError str
194− -> unlines ["Unexpected usage error", str]
195−
196− ProgramError str
197− -> "Program error: " <> str
198− PprProgramError str sdoc ->
199− unlines ["Program error:", str,""
200− , Out.showSDoc dflags sdoc]
201− where
202− requestReport = "Please report this bug to the compiler authors."
src/Development/IDE/GHC/Orphans.hsdeleted−72
@@ -1,72 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE CPP #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# OPTIONS_GHC -Wno-orphans #-}
7−#include "ghc-api-version.h"
8−
9−-- | Orphan instances for GHC.
10−-- Note that the 'NFData' instances may not be law abiding.
11−module Development.IDE.GHC.Orphans() where
12−
13−import GHC
14−import GhcPlugins
15−import Development.IDE.GHC.Compat
16−import qualified StringBuffer as SB
17−import Control.DeepSeq
18−import Data.Hashable
19−import Development.IDE.GHC.Util
20−
21−
22−-- Orphan instances for types from the GHC API.
23−instance Show CoreModule where show = prettyPrint
24−instance NFData CoreModule where rnf = rwhnf
25−instance Show CgGuts where show = prettyPrint . cg_module
26−instance NFData CgGuts where rnf = rwhnf
27−instance Show ModDetails where show = const "<moddetails>"
28−instance NFData ModDetails where rnf = rwhnf
29−instance NFData SafeHaskellMode where rnf = rwhnf
30−instance Show Linkable where show = prettyPrint
31−instance NFData Linkable where rnf = rwhnf
32−
33−instance Show InstalledUnitId where
34− show = installedUnitIdString
35−
36−instance NFData InstalledUnitId where rnf = rwhnf . installedUnitIdFS
37−
38−instance NFData SB.StringBuffer where rnf = rwhnf
39−
40−instance Show Module where
41− show = moduleNameString . moduleName
42−
43−instance Show (GenLocated SrcSpan ModuleName) where show = prettyPrint
44−
45−instance (NFData l, NFData e) => NFData (GenLocated l e) where
46− rnf (L l e) = rnf l `seq` rnf e
47−
48−instance Show ModSummary where
49− show = show . ms_mod
50−
51−instance Show ParsedModule where
52− show = show . pm_mod_summary
53−
54−instance NFData ModSummary where
55− rnf = rwhnf
56−
57−#if !MIN_GHC_API_VERSION(8,10,0)
58−instance NFData FastString where
59− rnf = rwhnf
60−#endif
61−
62−instance NFData ParsedModule where
63− rnf = rwhnf
64−
65−instance Hashable InstalledUnitId where
66− hashWithSalt salt = hashWithSalt salt . installedUnitIdString
67−
68−instance Show HieFile where
69− show = show . hie_module
70−
71−instance NFData HieFile where
72− rnf = rwhnf
src/Development/IDE/GHC/Util.hsdeleted−315
@@ -1,315 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−-- | General utility functions, mostly focused around GHC operations.
5−module Development.IDE.GHC.Util(
6− -- * HcsEnv and environment
7− HscEnvEq(GhcVersionMismatch, compileTime, runTime), hscEnv, newHscEnvEq,
8− modifyDynFlags,
9− evalGhcEnv,
10− runGhcEnv,
11− deps,
12− -- * GHC wrappers
13− prettyPrint,
14− printRdrName,
15− printName,
16− ParseResult(..), runParser,
17− lookupPackageConfig,
18− textToStringBuffer,
19− stringBufferToByteString,
20− moduleImportPath,
21− cgGutsToCoreModule,
22− fingerprintToBS,
23− fingerprintFromStringBuffer,
24− -- * General utilities
25− readFileUtf8,
26− hDuplicateTo',
27− setDefaultHieDir,
28− dontWriteHieFiles
29− ) where
30−
31−import Control.Concurrent
32−import Data.List.Extra
33−import Data.ByteString.Internal (ByteString(..))
34−import Data.Maybe
35−import Data.Typeable
36−import qualified Data.ByteString.Internal as BS
37−import Fingerprint
38−import GhcMonad
39−import Control.Exception
40−import Data.IORef
41−import Data.Version (showVersion, Version)
42−import FileCleanup
43−import Foreign.Ptr
44−import Foreign.ForeignPtr
45−import Foreign.Storable
46−import GHC.IO.BufferedIO (BufferedIO)
47−import GHC.IO.Device as IODevice
48−import GHC.IO.Encoding
49−import GHC.IO.Exception
50−import GHC.IO.Handle.Types
51−import GHC.IO.Handle.Internals
52−import Data.Unique
53−import Development.Shake.Classes
54−import qualified Data.Text as T
55−import qualified Data.Text.Encoding as T
56−import qualified Data.Text.Encoding.Error as T
57−import qualified Data.ByteString as BS
58−import Lexer
59−import StringBuffer
60−import System.FilePath
61−import HscTypes (cg_binds, md_types, cg_module, ModDetails, CgGuts, ic_dflags, hsc_IC, HscEnv(hsc_dflags))
62−import PackageConfig (PackageConfig)
63−import Outputable (showSDocUnsafe, ppr, showSDoc, Outputable)
64−import Packages (getPackageConfigMap, lookupPackage')
65−import SrcLoc (mkRealSrcLoc)
66−import FastString (mkFastString)
67−import DynFlags (emptyFilesToClean, unsafeGlobalDynFlags)
68−import Module (moduleNameSlashes, InstalledUnitId)
69−import OccName (parenSymOcc)
70−import RdrName (nameRdrName, rdrNameOcc)
71−
72−import Development.IDE.GHC.Compat as GHC
73−import Development.IDE.Types.Location
74−
75−
76−----------------------------------------------------------------------
77−-- GHC setup
78−
79−-- | Used to modify dyn flags in preference to calling 'setSessionDynFlags',
80−-- since that function also reloads packages (which is very slow).
81−modifyDynFlags :: GhcMonad m => (DynFlags -> DynFlags) -> m ()
82−modifyDynFlags f = do
83− newFlags <- f <$> getSessionDynFlags
84− -- We do not use setSessionDynFlags here since we handle package
85− -- initialization separately.
86− modifySession $ \h ->
87− h { hsc_dflags = newFlags, hsc_IC = (hsc_IC h) {ic_dflags = newFlags} }
88−
89−-- | Given a 'UnitId' try and find the associated 'PackageConfig' in the environment.
90−lookupPackageConfig :: UnitId -> HscEnv -> Maybe PackageConfig
91−lookupPackageConfig unitId env =
92− lookupPackage' False pkgConfigMap unitId
93− where
94− pkgConfigMap =
95− -- For some weird reason, the GHC API does not provide a way to get the PackageConfigMap
96− -- from PackageState so we have to wrap it in DynFlags first.
97− getPackageConfigMap $ hsc_dflags env
98−
99−
100−-- | Convert from the @text@ package to the @GHC@ 'StringBuffer'.
101−-- Currently implemented somewhat inefficiently (if it ever comes up in a profile).
102−textToStringBuffer :: T.Text -> StringBuffer
103−textToStringBuffer = stringToStringBuffer . T.unpack
104−
105−runParser :: DynFlags -> String -> P a -> ParseResult a
106−runParser flags str parser = unP parser parseState
107− where
108− filename = "<interactive>"
109− location = mkRealSrcLoc (mkFastString filename) 1 1
110− buffer = stringToStringBuffer str
111− parseState = mkPState flags buffer location
112−
113−stringBufferToByteString :: StringBuffer -> ByteString
114−stringBufferToByteString StringBuffer{..} = PS buf cur len
115−
116−-- | Pretty print a GHC value using 'unsafeGlobalDynFlags '.
117−prettyPrint :: Outputable a => a -> String
118−prettyPrint = showSDoc unsafeGlobalDynFlags . ppr
119−
120−-- | Pretty print a 'RdrName' wrapping operators in parens
121−printRdrName :: RdrName -> String
122−printRdrName name = showSDocUnsafe $ parenSymOcc rn (ppr rn)
123− where
124− rn = rdrNameOcc name
125−
126−-- | Pretty print a 'Name' wrapping operators in parens
127−printName :: Name -> String
128−printName = printRdrName . nameRdrName
129−
130−-- | Run a 'Ghc' monad value using an existing 'HscEnv'. Sets up and tears down all the required
131−-- pieces, but designed to be more efficient than a standard 'runGhc'.
132−evalGhcEnv :: HscEnv -> Ghc b -> IO b
133−evalGhcEnv env act = snd <$> runGhcEnv env act
134−
135−-- | Run a 'Ghc' monad value using an existing 'HscEnv'. Sets up and tears down all the required
136−-- pieces, but designed to be more efficient than a standard 'runGhc'.
137−runGhcEnv :: HscEnv -> Ghc a -> IO (HscEnv, a)
138−runGhcEnv env act = do
139− filesToClean <- newIORef emptyFilesToClean
140− dirsToClean <- newIORef mempty
141− let dflags = (hsc_dflags env){filesToClean=filesToClean, dirsToClean=dirsToClean, useUnicode=True}
142− ref <- newIORef env{hsc_dflags=dflags}
143− res <- unGhc act (Session ref) `finally` do
144− cleanTempFiles dflags
145− cleanTempDirs dflags
146− (,res) <$> readIORef ref
147−
148−-- | Given a module location, and its parse tree, figure out what is the include directory implied by it.
149−-- For example, given the file @\/usr\/\Test\/Foo\/Bar.hs@ with the module name @Foo.Bar@ the directory
150−-- @\/usr\/Test@ should be on the include path to find sibling modules.
151−moduleImportPath :: NormalizedFilePath -> GHC.ModuleName -> Maybe FilePath
152−-- The call to takeDirectory is required since DAML does not require that
153−-- the file name matches the module name in the last component.
154−-- Once that has changed we can get rid of this.
155−moduleImportPath (takeDirectory . fromNormalizedFilePath -> pathDir) mn
156− -- This happens for single-component modules since takeDirectory "A" == "."
157− | modDir == "." = Just pathDir
158− | otherwise = dropTrailingPathSeparator <$> stripSuffix modDir pathDir
159− where
160− -- A for module A.B
161− modDir =
162− takeDirectory $
163− fromNormalizedFilePath $ toNormalizedFilePath' $
164− moduleNameSlashes mn
165−
166−-- | An 'HscEnv' with equality. Two values are considered equal
167−-- if they are created with the same call to 'newHscEnvEq'.
168−data HscEnvEq
169− = HscEnvEq !Unique !HscEnv
170− [(InstalledUnitId, DynFlags)] -- In memory components for this HscEnv
171− -- This is only used at the moment for the import dirs in
172− -- the DynFlags
173− | GhcVersionMismatch { compileTime :: !Version
174− , runTime :: !Version
175− }
176−
177−-- | Unwrap an 'HsEnvEq'.
178−hscEnv :: HscEnvEq -> HscEnv
179−hscEnv = either error id . hscEnv'
180−
181−hscEnv' :: HscEnvEq -> Either String HscEnv
182−hscEnv' (HscEnvEq _ x _) = Right x
183−hscEnv' GhcVersionMismatch{..} = Left $
184− unwords
185− ["ghcide compiled against GHC"
186− ,showVersion compileTime
187− ,"but currently using"
188− ,showVersion runTime
189− ,". This is unsupported, ghcide must be compiled with the same GHC version as the project."
190− ]
191−
192−deps :: HscEnvEq -> [(InstalledUnitId, DynFlags)]
193−deps (HscEnvEq _ _ u) = u
194−deps GhcVersionMismatch{} = []
195−
196−-- | Wrap an 'HscEnv' into an 'HscEnvEq'.
197−newHscEnvEq :: HscEnv -> [(InstalledUnitId, DynFlags)] -> IO HscEnvEq
198−newHscEnvEq e uids = do u <- newUnique; return $ HscEnvEq u e uids
199−
200−instance Show HscEnvEq where
201− show (HscEnvEq a _ _) = "HscEnvEq " ++ show (hashUnique a)
202− show GhcVersionMismatch{..} = "GhcVersionMismatch " <> show (compileTime, runTime)
203−
204−instance Eq HscEnvEq where
205− HscEnvEq a _ _ == HscEnvEq b _ _ = a == b
206− GhcVersionMismatch a b == GhcVersionMismatch c d = a == c && b == d
207− _ == _ = False
208−
209−instance NFData HscEnvEq where
210− rnf (HscEnvEq a b c) = rnf (hashUnique a) `seq` b `seq` c `seq` ()
211− rnf GhcVersionMismatch{} = rnf runTime
212−
213−instance Hashable HscEnvEq where
214− hashWithSalt s (HscEnvEq a _b _c) = hashWithSalt s a
215− hashWithSalt salt GhcVersionMismatch{..} = hashWithSalt salt (compileTime, runTime)
216−
217−-- Fake instance needed to persuade Shake to accept this type as a key.
218−-- No harm done as ghcide never persists these keys currently
219−instance Binary HscEnvEq where
220− put _ = error "not really"
221− get = error "not really"
222−
223−-- | Read a UTF8 file, with lenient decoding, so it will never raise a decoding error.
224−readFileUtf8 :: FilePath -> IO T.Text
225−readFileUtf8 f = T.decodeUtf8With T.lenientDecode <$> BS.readFile f
226−
227−-- | Convert from a 'CgGuts' to a 'CoreModule'.
228−cgGutsToCoreModule :: SafeHaskellMode -> CgGuts -> ModDetails -> CoreModule
229−cgGutsToCoreModule safeMode guts modDetails = CoreModule
230− (cg_module guts)
231− (md_types modDetails)
232− (cg_binds guts)
233− safeMode
234−
235−-- | Convert a 'Fingerprint' to a 'ByteString' by copying the byte across.
236−-- Will produce an 8 byte unreadable ByteString.
237−fingerprintToBS :: Fingerprint -> BS.ByteString
238−fingerprintToBS (Fingerprint a b) = BS.unsafeCreate 8 $ \ptr -> do
239− ptr <- pure $ castPtr ptr
240− pokeElemOff ptr 0 a
241− pokeElemOff ptr 1 b
242−
243−-- | Take the 'Fingerprint' of a 'StringBuffer'.
244−fingerprintFromStringBuffer :: StringBuffer -> IO Fingerprint
245−fingerprintFromStringBuffer (StringBuffer buf len cur) =
246− withForeignPtr buf $ \ptr -> fingerprintData (ptr `plusPtr` cur) len
247−
248−
249−-- | A slightly modified version of 'hDuplicateTo' from GHC.
250−-- Importantly, it avoids the bug listed in https://gitlab.haskell.org/ghc/ghc/merge_requests/2318.
251−hDuplicateTo' :: Handle -> Handle -> IO ()
252−hDuplicateTo' h1@(FileHandle path m1) h2@(FileHandle _ m2) = do
253− withHandle__' "hDuplicateTo" h2 m2 $ \h2_ -> do
254− -- The implementation in base has this call to hClose_help.
255− -- _ <- hClose_help h2_
256− -- hClose_help does two things:
257− -- 1. It flushes the buffer, we replicate this here
258− _ <- flushWriteBuffer h2_ `catch` \(_ :: IOException) -> pure ()
259− -- 2. It closes the handle. This is redundant since dup2 takes care of that
260− -- but even worse it is actively harmful! Once the handle has been closed
261− -- another thread is free to reallocate it. This leads to dup2 failing with EBUSY
262− -- if it happens just in the right moment.
263− withHandle_' "hDuplicateTo" h1 m1 $ \h1_ -> do
264− dupHandleTo path h1 Nothing h2_ h1_ (Just handleFinalizer)
265−hDuplicateTo' h1@(DuplexHandle path r1 w1) h2@(DuplexHandle _ r2 w2) = do
266− withHandle__' "hDuplicateTo" h2 w2 $ \w2_ -> do
267− _ <- hClose_help w2_
268− withHandle_' "hDuplicateTo" h1 w1 $ \w1_ -> do
269− dupHandleTo path h1 Nothing w2_ w1_ (Just handleFinalizer)
270− withHandle__' "hDuplicateTo" h2 r2 $ \r2_ -> do
271− _ <- hClose_help r2_
272− withHandle_' "hDuplicateTo" h1 r1 $ \r1_ -> do
273− dupHandleTo path h1 (Just w1) r2_ r1_ Nothing
274−hDuplicateTo' h1 _ =
275− ioe_dupHandlesNotCompatible h1
276−
277−-- | This is copied unmodified from GHC since it is not exposed.
278−dupHandleTo :: FilePath
279− -> Handle
280− -> Maybe (MVar Handle__)
281− -> Handle__
282− -> Handle__
283− -> Maybe HandleFinalizer
284− -> IO Handle__
285−dupHandleTo filepath h other_side
286− _hto_@Handle__{haDevice=devTo}
287− h_@Handle__{haDevice=dev} mb_finalizer = do
288− flushBuffer h_
289− case cast devTo of
290− Nothing -> ioe_dupHandlesNotCompatible h
291− Just dev' -> do
292− _ <- IODevice.dup2 dev dev'
293− FileHandle _ m <- dupHandle_ dev' filepath other_side h_ mb_finalizer
294− takeMVar m
295−
296−-- | This is copied unmodified from GHC since it is not exposed.
297−-- Note the beautiful inline comment!
298−dupHandle_ :: (IODevice dev, BufferedIO dev, Typeable dev) => dev
299− -> FilePath
300− -> Maybe (MVar Handle__)
301− -> Handle__
302− -> Maybe HandleFinalizer
303− -> IO Handle
304−dupHandle_ new_dev filepath other_side _h_@Handle__{..} mb_finalizer = do
305− -- XXX wrong!
306− mb_codec <- if isJust haEncoder then fmap Just getLocaleEncoding else return Nothing
307− mkHandle new_dev filepath haType True{-buffered-} mb_codec
308− NewlineMode { inputNL = haInputNL, outputNL = haOutputNL }
309− mb_finalizer other_side
310−
311−-- | This is copied unmodified from GHC since it is not exposed.
312−ioe_dupHandlesNotCompatible :: Handle -> IO a
313−ioe_dupHandlesNotCompatible h =
314− ioException (IOError (Just h) IllegalOperation "hDuplicateTo"
315− "handles are incompatible" Nothing Nothing)
src/Development/IDE/GHC/WithDynFlags.hsdeleted−30
@@ -1,30 +0,0 @@
1−module Development.IDE.GHC.WithDynFlags
2−( WithDynFlags
3−, evalWithDynFlags
4−) where
5−
6−import Control.Monad.Trans.Reader (ask, ReaderT(..))
7−import GHC (DynFlags)
8−import Control.Monad.IO.Class (MonadIO)
9−import Exception (ExceptionMonad(..))
10−import Control.Monad.Trans.Class (MonadTrans(..))
11−import GhcPlugins (HasDynFlags(..))
12−
13−-- | A monad transformer implementing the 'HasDynFlags' effect
14−newtype WithDynFlags m a = WithDynFlags {withDynFlags :: ReaderT DynFlags m a}
15− deriving (Applicative, Functor, Monad, MonadIO, MonadTrans)
16−
17−evalWithDynFlags :: DynFlags -> WithDynFlags m a -> m a
18−evalWithDynFlags dflags = flip runReaderT dflags . withDynFlags
19−
20−instance Monad m => HasDynFlags (WithDynFlags m) where
21− getDynFlags = WithDynFlags ask
22−
23−instance ExceptionMonad m => ExceptionMonad (WithDynFlags m) where
24− gmask f = WithDynFlags $ ReaderT $ \env ->
25− gmask $ \restore ->
26− let restore' = lift . restore . flip runReaderT env . withDynFlags
27− in runReaderT (withDynFlags $ f restore') env
28−
29− gcatch (WithDynFlags act) handle = WithDynFlags $ ReaderT $ \env ->
30− gcatch (runReaderT act env) (flip runReaderT env . withDynFlags . handle)
src/Development/IDE/Import/DependencyInformation.hsdeleted−376
@@ -1,376 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−module Development.IDE.Import.DependencyInformation
5− ( DependencyInformation(..)
6− , ModuleImports(..)
7− , RawDependencyInformation(..)
8− , NodeError(..)
9− , ModuleParseError(..)
10− , TransitiveDependencies(..)
11− , FilePathId(..)
12− , NamedModuleDep(..)
13−
14− , PathIdMap
15− , emptyPathIdMap
16− , getPathId
17− , lookupPathToId
18− , insertImport
19− , pathToId
20− , idToPath
21− , reachableModules
22− , processDependencyInformation
23− , transitiveDeps
24−
25− , BootIdMap
26− , insertBootId
27− ) where
28−
29−import Control.DeepSeq
30−import Data.Bifunctor
31−import Data.Coerce
32−import Data.List
33−import Data.Tuple.Extra hiding (first, second)
34−import Development.IDE.GHC.Orphans()
35−import Data.Either
36−import Data.Graph
37−import Data.HashMap.Strict (HashMap)
38−import qualified Data.HashMap.Strict as HMS
39−import Data.List.NonEmpty (NonEmpty(..), nonEmpty)
40−import qualified Data.List.NonEmpty as NonEmpty
41−import Data.IntMap (IntMap)
42−import qualified Data.IntMap.Strict as IntMap
43−import qualified Data.IntMap.Lazy as IntMapLazy
44−import Data.IntSet (IntSet)
45−import qualified Data.IntSet as IntSet
46−import Data.Maybe
47−import Data.Set (Set)
48−import qualified Data.Set as Set
49−import GHC.Generics (Generic)
50−
51−import Development.IDE.Types.Diagnostics
52−import Development.IDE.Types.Location
53−import Development.IDE.Import.FindImports (ArtifactsLocation(..))
54−
55−import GHC
56−import Module
57−
58−-- | The imports for a given module.
59−data ModuleImports = ModuleImports
60− { moduleImports :: ![(Located ModuleName, Maybe FilePathId)]
61− -- ^ Imports of a module in the current package and the file path of
62− -- that module on disk (if we found it)
63− , packageImports :: !(Set InstalledUnitId)
64− -- ^ Transitive package dependencies unioned for all imports.
65− } deriving Show
66−
67−-- | For processing dependency information, we need lots of maps and sets of
68−-- filepaths. Comparing Strings is really slow, so we work with IntMap/IntSet
69−-- instead and only convert at the edges.
70−newtype FilePathId = FilePathId { getFilePathId :: Int }
71− deriving (Show, NFData, Eq, Ord)
72−
73−-- | Map from 'FilePathId'
74−type FilePathIdMap = IntMap
75−
76−-- | Set of 'FilePathId's
77−type FilePathIdSet = IntSet
78−
79−data PathIdMap = PathIdMap
80− { idToPathMap :: !(FilePathIdMap ArtifactsLocation)
81− , pathToIdMap :: !(HashMap NormalizedFilePath FilePathId)
82− }
83− deriving (Show, Generic)
84−
85−instance NFData PathIdMap
86−
87−emptyPathIdMap :: PathIdMap
88−emptyPathIdMap = PathIdMap IntMap.empty HMS.empty
89−
90−getPathId :: ArtifactsLocation -> PathIdMap -> (FilePathId, PathIdMap)
91−getPathId path m@PathIdMap{..} =
92− case HMS.lookup (artifactFilePath path) pathToIdMap of
93− Nothing ->
94− let !newId = FilePathId $ HMS.size pathToIdMap
95− in (newId, insertPathId path newId m)
96− Just id -> (id, m)
97−
98−insertPathId :: ArtifactsLocation -> FilePathId -> PathIdMap -> PathIdMap
99−insertPathId path id PathIdMap{..} =
100− PathIdMap (IntMap.insert (getFilePathId id) path idToPathMap) (HMS.insert (artifactFilePath path) id pathToIdMap)
101−
102−insertImport :: FilePathId -> Either ModuleParseError ModuleImports -> RawDependencyInformation -> RawDependencyInformation
103−insertImport (FilePathId k) v rawDepInfo = rawDepInfo { rawImports = IntMap.insert k v (rawImports rawDepInfo) }
104−
105−pathToId :: PathIdMap -> NormalizedFilePath -> FilePathId
106−pathToId PathIdMap{pathToIdMap} path = pathToIdMap HMS.! path
107−
108−lookupPathToId :: PathIdMap -> NormalizedFilePath -> Maybe FilePathId
109−lookupPathToId PathIdMap{pathToIdMap} path = HMS.lookup path pathToIdMap
110−
111−idToPath :: PathIdMap -> FilePathId -> NormalizedFilePath
112−idToPath pathIdMap filePathId = artifactFilePath $ idToModLocation pathIdMap filePathId
113−
114−idToModLocation :: PathIdMap -> FilePathId -> ArtifactsLocation
115−idToModLocation PathIdMap{idToPathMap} (FilePathId id) = idToPathMap IntMap.! id
116−
117−type BootIdMap = FilePathIdMap FilePathId
118−
119−insertBootId :: FilePathId -> FilePathId -> BootIdMap -> BootIdMap
120−insertBootId k = IntMap.insert (getFilePathId k)
121−
122−-- | Unprocessed results that we find by following imports recursively.
123−data RawDependencyInformation = RawDependencyInformation
124− { rawImports :: !(FilePathIdMap (Either ModuleParseError ModuleImports))
125− , rawPathIdMap :: !PathIdMap
126− -- The rawBootMap maps the FilePathId of a hs-boot file to its
127− -- corresponding hs file. It is used when topologically sorting as we
128− -- need to add edges between .hs-boot and .hs so that the .hs files
129− -- appear later in the sort.
130− , rawBootMap :: !BootIdMap
131− } deriving Show
132−
133−pkgDependencies :: RawDependencyInformation -> FilePathIdMap (Set InstalledUnitId)
134−pkgDependencies RawDependencyInformation{..} =
135− IntMap.map (either (const Set.empty) packageImports) rawImports
136−
137−data DependencyInformation =
138− DependencyInformation
139− { depErrorNodes :: !(FilePathIdMap (NonEmpty NodeError))
140− -- ^ Nodes that cannot be processed correctly.
141− , depModuleNames :: !(FilePathIdMap ShowableModuleName)
142− , depModuleDeps :: !(FilePathIdMap FilePathIdSet)
143− -- ^ For a non-error node, this contains the set of module immediate dependencies
144− -- in the same package.
145− , depPkgDeps :: !(FilePathIdMap (Set InstalledUnitId))
146− -- ^ For a non-error node, this contains the set of immediate pkg deps.
147− , depPathIdMap :: !PathIdMap
148− -- ^ Map from FilePath to FilePathId
149− , depBootMap :: !BootIdMap
150− -- ^ Map from hs-boot file to the corresponding hs file
151− } deriving (Show, Generic)
152−
153−newtype ShowableModuleName =
154− ShowableModuleName {showableModuleName :: ModuleName}
155− deriving NFData
156−
157−instance Show ShowableModuleName where show = moduleNameString . showableModuleName
158−
159−reachableModules :: DependencyInformation -> [NormalizedFilePath]
160−reachableModules DependencyInformation{..} =
161− map (idToPath depPathIdMap . FilePathId) $ IntMap.keys depErrorNodes <> IntMap.keys depModuleDeps
162−
163−instance NFData DependencyInformation
164−
165−-- | This does not contain the actual parse error as that is already reported by GetParsedModule.
166−data ModuleParseError = ModuleParseError
167− deriving (Show, Generic)
168−
169−instance NFData ModuleParseError
170−
171−-- | Error when trying to locate a module.
172−data LocateError = LocateError [Diagnostic]
173− deriving (Eq, Show, Generic)
174−
175−instance NFData LocateError
176−
177−-- | An error attached to a node in the dependency graph.
178−data NodeError
179− = PartOfCycle (Located ModuleName) [FilePathId]
180− -- ^ This module is part of an import cycle. The module name corresponds
181− -- to the import that enters the cycle starting from this module.
182− -- The list of filepaths represents the elements
183− -- in the cycle in unspecified order.
184− | FailedToLocateImport (Located ModuleName)
185− -- ^ This module has an import that couldn’t be located.
186− | ParseError ModuleParseError
187− | ParentOfErrorNode (Located ModuleName)
188− -- ^ This module is the parent of a module that cannot be
189− -- processed (either it cannot be parsed, is part of a cycle
190− -- or the parent of another error node).
191− deriving (Show, Generic)
192−
193−instance NFData NodeError where
194− rnf (PartOfCycle m fs) = m `seq` rnf fs
195− rnf (FailedToLocateImport m) = m `seq` ()
196− rnf (ParseError e) = rnf e
197− rnf (ParentOfErrorNode m) = m `seq` ()
198−
199−-- | A processed node in the dependency graph. If there was any error
200−-- during processing the node or any of its dependencies, this is an
201−-- `ErrorNode`. Otherwise it is a `SuccessNode`.
202−data NodeResult
203− = ErrorNode (NonEmpty NodeError)
204− | SuccessNode [(Located ModuleName, FilePathId)]
205− deriving Show
206−
207−partitionNodeResults
208− :: [(a, NodeResult)]
209− -> ([(a, NonEmpty NodeError)], [(a, [(Located ModuleName, FilePathId)])])
210−partitionNodeResults = partitionEithers . map f
211− where f (a, ErrorNode errs) = Left (a, errs)
212− f (a, SuccessNode imps) = Right (a, imps)
213−
214−instance Semigroup NodeResult where
215− ErrorNode errs <> ErrorNode errs' = ErrorNode (errs <> errs')
216− ErrorNode errs <> SuccessNode _ = ErrorNode errs
217− SuccessNode _ <> ErrorNode errs = ErrorNode errs
218− SuccessNode a <> SuccessNode _ = SuccessNode a
219−
220−processDependencyInformation :: RawDependencyInformation -> DependencyInformation
221−processDependencyInformation rawDepInfo@RawDependencyInformation{..} =
222− DependencyInformation
223− { depErrorNodes = IntMap.fromList errorNodes
224− , depModuleDeps = moduleDeps
225− , depModuleNames = IntMap.fromList $ coerce moduleNames
226− , depPkgDeps = pkgDependencies rawDepInfo
227− , depPathIdMap = rawPathIdMap
228− , depBootMap = rawBootMap
229− }
230− where resultGraph = buildResultGraph rawImports
231− (errorNodes, successNodes) = partitionNodeResults $ IntMap.toList resultGraph
232− moduleNames :: [(FilePathId, ModuleName)]
233− moduleNames =
234− [ (fId, modName) | (_, imports) <- successNodes, (L _ modName, fId) <- imports]
235− successEdges :: [(FilePathId, FilePathId, [FilePathId])]
236− successEdges =
237− map
238− (\(file, imports) -> (FilePathId file, FilePathId file, map snd imports))
239− successNodes
240− moduleDeps =
241− IntMap.fromList $
242− map (\(_, FilePathId v, vs) -> (v, IntSet.fromList $ coerce vs))
243− successEdges
244−
245−-- | Given a dependency graph, buildResultGraph detects and propagates errors in that graph as follows:
246−-- 1. Mark each node that is part of an import cycle as an error node.
247−-- 2. Mark each node that has a parse error as an error node.
248−-- 3. Mark each node whose immediate children could not be located as an error.
249−-- 4. Recursively propagate errors to parents if they are not already error nodes.
250−buildResultGraph :: FilePathIdMap (Either ModuleParseError ModuleImports) -> FilePathIdMap NodeResult
251−buildResultGraph g = propagatedErrors
252− where
253− sccs = stronglyConnComp (graphEdges g)
254− (_, cycles) = partitionSCC sccs
255− cycleErrors :: IntMap NodeResult
256− cycleErrors = IntMap.unionsWith (<>) $ map errorsForCycle cycles
257− errorsForCycle :: [FilePathId] -> IntMap NodeResult
258− errorsForCycle files =
259− IntMap.fromListWith (<>) $ coerce $ concatMap (cycleErrorsForFile files) files
260− cycleErrorsForFile :: [FilePathId] -> FilePathId -> [(FilePathId,NodeResult)]
261− cycleErrorsForFile cycle f =
262− let entryPoints = mapMaybe (findImport f) cycle
263− in map (\imp -> (f, ErrorNode (PartOfCycle imp cycle :| []))) entryPoints
264− otherErrors = IntMap.map otherErrorsForFile g
265− otherErrorsForFile :: Either ModuleParseError ModuleImports -> NodeResult
266− otherErrorsForFile (Left err) = ErrorNode (ParseError err :| [])
267− otherErrorsForFile (Right ModuleImports{moduleImports}) =
268− let toEither (imp, Nothing) = Left imp
269− toEither (imp, Just path) = Right (imp, path)
270− (errs, imports') = partitionEithers (map toEither moduleImports)
271− in case nonEmpty errs of
272− Nothing -> SuccessNode imports'
273− Just errs' -> ErrorNode (NonEmpty.map FailedToLocateImport errs')
274−
275− unpropagatedErrors = IntMap.unionWith (<>) cycleErrors otherErrors
276− -- The recursion here is fine since we use a lazy map and
277− -- we only recurse on SuccessNodes. In particular, we do not recurse
278− -- on nodes that are part of a cycle as they are already marked as
279− -- error nodes.
280− propagatedErrors =
281− IntMapLazy.map propagate unpropagatedErrors
282− propagate :: NodeResult -> NodeResult
283− propagate n@(ErrorNode _) = n
284− propagate n@(SuccessNode imps) =
285− let results = map (\(imp, FilePathId dep) -> (imp, propagatedErrors IntMap.! dep)) imps
286− (errs, _) = partitionNodeResults results
287− in case nonEmpty errs of
288− Nothing -> n
289− Just errs' -> ErrorNode (NonEmpty.map (ParentOfErrorNode . fst) errs')
290− findImport :: FilePathId -> FilePathId -> Maybe (Located ModuleName)
291− findImport (FilePathId file) importedFile =
292− case g IntMap.! file of
293− Left _ -> error "Tried to call findImport on a module with a parse error"
294− Right ModuleImports{moduleImports} ->
295− fmap fst $ find (\(_, resolvedImp) -> resolvedImp == Just importedFile) moduleImports
296−
297−graphEdges :: FilePathIdMap (Either ModuleParseError ModuleImports) -> [(FilePathId, FilePathId, [FilePathId])]
298−graphEdges g =
299− map (\(k, v) -> (FilePathId k, FilePathId k, deps v)) $ IntMap.toList g
300− where deps :: Either e ModuleImports -> [FilePathId]
301− deps (Left _) = []
302− deps (Right ModuleImports{moduleImports}) = mapMaybe snd moduleImports
303−
304−partitionSCC :: [SCC a] -> ([a], [[a]])
305−partitionSCC (CyclicSCC xs:rest) = second (xs:) $ partitionSCC rest
306−partitionSCC (AcyclicSCC x:rest) = first (x:) $ partitionSCC rest
307−partitionSCC [] = ([], [])
308−
309−
310−transitiveDeps :: DependencyInformation -> NormalizedFilePath -> Maybe TransitiveDependencies
311−transitiveDeps DependencyInformation{..} file = do
312− let !fileId = pathToId depPathIdMap file
313− reachableVs <-
314− -- Delete the starting node
315− IntSet.delete (getFilePathId fileId) .
316− IntSet.fromList . map (fst3 . fromVertex) .
317− reachable g <$> toVertex (getFilePathId fileId)
318− let transitiveModuleDepIds =
319− filter (\v -> v `IntSet.member` reachableVs) $ map (fst3 . fromVertex) vs
320− let transitivePkgDeps =
321− Set.toList $ Set.unions $
322− map (\f -> IntMap.findWithDefault Set.empty f depPkgDeps) $
323− getFilePathId fileId : transitiveModuleDepIds
324− let transitiveModuleDeps =
325− map (idToPath depPathIdMap . FilePathId) transitiveModuleDepIds
326− let transitiveNamedModuleDeps =
327− [ NamedModuleDep (idToPath depPathIdMap (FilePathId fid)) mn artifactModLocation
328− | (fid, ShowableModuleName mn) <- IntMap.toList depModuleNames
329− , let ArtifactsLocation{artifactModLocation} = idToPathMap depPathIdMap IntMap.! fid
330− ]
331− pure TransitiveDependencies {..}
332− where
333− (g, fromVertex, toVertex) = graphFromEdges edges
334− edges = map (\(f, fs) -> (f, f, IntSet.toList fs ++ boot_edge f)) $ IntMap.toList depModuleDeps
335−
336− -- Need to add an edge between the .hs and .hs-boot file if it exists
337− -- so the .hs file gets loaded after the .hs-boot file and the right
338− -- stuff ends up in the HPT. If you don't have this check then GHC will
339− -- fail to work with ghcide.
340− boot_edge f = [getFilePathId f' | Just f' <- [IntMap.lookup f depBootMap]]
341−
342− vs = topSort g
343−
344−data TransitiveDependencies = TransitiveDependencies
345− { transitiveModuleDeps :: [NormalizedFilePath]
346− -- ^ Transitive module dependencies in topological order.
347− -- The module itself is not included.
348− , transitiveNamedModuleDeps :: [NamedModuleDep]
349− -- ^ Transitive module dependencies in topological order.
350− -- The module itself is not included.
351− , transitivePkgDeps :: [InstalledUnitId]
352− -- ^ Transitive pkg dependencies in unspecified order.
353− } deriving (Eq, Show, Generic)
354−
355−instance NFData TransitiveDependencies
356−
357−data NamedModuleDep = NamedModuleDep {
358− nmdFilePath :: !NormalizedFilePath,
359− nmdModuleName :: !ModuleName,
360− nmdModLocation :: !ModLocation
361− }
362− deriving Generic
363−
364−instance Eq NamedModuleDep where
365− a == b = nmdFilePath a == nmdFilePath b
366−
367−instance NFData NamedModuleDep where
368− rnf NamedModuleDep{..} =
369− rnf nmdFilePath `seq`
370− rnf nmdModuleName `seq`
371− -- 'ModLocation' lacks an 'NFData' instance
372− rwhnf nmdModLocation
373−
374−instance Show NamedModuleDep where
375− show NamedModuleDep{..} = show nmdFilePath
376−
src/Development/IDE/Import/FindImports.hsdeleted−179
@@ -1,179 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE CPP #-}
5−#include "ghc-api-version.h"
6−
7−module Development.IDE.Import.FindImports
8− ( locateModule
9− , Import(..)
10− , ArtifactsLocation(..)
11− , modSummaryToArtifactsLocation
12− , isBootLocation
13− , mkImportDirs
14− ) where
15−
16−import Development.IDE.GHC.Error as ErrUtils
17−import Development.IDE.GHC.Orphans()
18−import Development.IDE.Types.Diagnostics
19−import Development.IDE.Types.Location
20−import Development.IDE.GHC.Compat
21−-- GHC imports
22−import FastString
23−import qualified Module as M
24−import Packages
25−import Outputable (showSDoc, ppr, pprPanic)
26−import Finder
27−import Control.DeepSeq
28−
29−-- standard imports
30−import Control.Monad.Extra
31−import Control.Monad.IO.Class
32−import System.FilePath
33−import DriverPhases
34−import Data.Maybe
35−
36−data Import
37− = FileImport !ArtifactsLocation
38− | PackageImport !M.InstalledUnitId
39− deriving (Show)
40−
41−data ArtifactsLocation = ArtifactsLocation
42− { artifactFilePath :: !NormalizedFilePath
43− , artifactModLocation :: !ModLocation
44− , artifactIsSource :: !Bool -- ^ True if a module is a source input
45− }
46− deriving (Show)
47−
48−instance NFData ArtifactsLocation where
49− rnf ArtifactsLocation{..} = rnf artifactFilePath `seq` rwhnf artifactModLocation `seq` rnf artifactIsSource
50−
51−isBootLocation :: ArtifactsLocation -> Bool
52−isBootLocation = not . artifactIsSource
53−
54−instance NFData Import where
55− rnf (FileImport x) = rnf x
56− rnf (PackageImport x) = rnf x
57−
58−modSummaryToArtifactsLocation :: NormalizedFilePath -> ModSummary -> ArtifactsLocation
59−modSummaryToArtifactsLocation nfp ms = ArtifactsLocation nfp (ms_location ms) (isSource (ms_hsc_src ms))
60− where
61− isSource HsSrcFile = True
62− isSource _ = False
63−
64−
65−-- | locate a module in the file system. Where we go from *daml to Haskell
66−locateModuleFile :: MonadIO m
67− => [[FilePath]]
68− -> [String]
69− -> (NormalizedFilePath -> m Bool)
70− -> Bool
71− -> ModuleName
72− -> m (Maybe NormalizedFilePath)
73−locateModuleFile import_dirss exts doesExist isSource modName = do
74− let candidates import_dirs =
75− [ toNormalizedFilePath' (prefix </> M.moduleNameSlashes modName <.> maybeBoot ext)
76− | prefix <- import_dirs , ext <- exts]
77− findM doesExist (concatMap candidates import_dirss)
78− where
79− maybeBoot ext
80− | isSource = ext ++ "-boot"
81− | otherwise = ext
82−
83−-- | This function is used to map a package name to a set of import paths.
84−-- It only returns Just for unit-ids which are possible to import into the
85−-- current module. In particular, it will return Nothing for 'main' components
86−-- as they can never be imported into another package.
87−mkImportDirs :: DynFlags -> (M.InstalledUnitId, DynFlags) -> Maybe (PackageName, [FilePath])
88−mkImportDirs df (i, DynFlags{importPaths}) = (, importPaths) <$> getPackageName df i
89−
90−-- | locate a module in either the file system or the package database. Where we go from *daml to
91−-- Haskell
92−locateModule
93− :: MonadIO m
94− => DynFlags
95− -> [(M.InstalledUnitId, DynFlags)] -- Sets import directories to look in
96− -> [String]
97− -> (NormalizedFilePath -> m Bool)
98− -> Located ModuleName
99− -> Maybe FastString
100− -> Bool
101− -> m (Either [FileDiagnostic] Import)
102−locateModule dflags comp_info exts doesExist modName mbPkgName isSource = do
103− case mbPkgName of
104− -- "this" means that we should only look in the current package
105− Just "this" -> do
106− lookupLocal [importPaths dflags]
107− -- if a package name is given we only go look for a package
108− Just pkgName
109− | Just dirs <- lookup (PackageName pkgName) import_paths
110− -> lookupLocal [dirs]
111− | otherwise -> lookupInPackageDB dflags
112− Nothing -> do
113− -- first try to find the module as a file. If we can't find it try to find it in the package
114− -- database.
115− -- Here the importPaths for the current modules are added to the front of the import paths from the other components.
116− -- This is particularly important for Paths_* modules which get generated for every component but unless you use it in
117− -- each component will end up being found in the wrong place and cause a multi-cradle match failure.
118− mbFile <- locateModuleFile (importPaths dflags : map snd import_paths) exts doesExist isSource $ unLoc modName
119− case mbFile of
120− Nothing -> lookupInPackageDB dflags
121− Just file -> toModLocation file
122− where
123− import_paths = mapMaybe (mkImportDirs dflags) comp_info
124− toModLocation file = liftIO $ do
125− loc <- mkHomeModLocation dflags (unLoc modName) (fromNormalizedFilePath file)
126− return $ Right $ FileImport $ ArtifactsLocation file loc (not isSource)
127−
128− lookupLocal dirs = do
129− mbFile <- locateModuleFile dirs exts doesExist isSource $ unLoc modName
130− case mbFile of
131− Nothing -> return $ Left $ notFoundErr dflags modName $ LookupNotFound []
132− Just file -> toModLocation file
133−
134− lookupInPackageDB dfs =
135− case lookupModuleWithSuggestions dfs (unLoc modName) mbPkgName of
136− LookupFound _m pkgConfig -> return $ Right $ PackageImport $ unitId pkgConfig
137− reason -> return $ Left $ notFoundErr dfs modName reason
138−
139−-- | Don't call this on a found module.
140−notFoundErr :: DynFlags -> Located M.ModuleName -> LookupResult -> [FileDiagnostic]
141−notFoundErr dfs modName reason =
142− mkError' $ ppr' $ cannotFindModule dfs modName0 $ lookupToFindResult reason
143− where
144− mkError' = diagFromString "not found" DsError (getLoc modName)
145− modName0 = unLoc modName
146− ppr' = showSDoc dfs
147− -- We convert the lookup result to a find result to reuse GHC's cannotFindMoudle pretty printer.
148− lookupToFindResult =
149− \case
150− LookupFound _m _pkgConfig ->
151− pprPanic "Impossible: called lookupToFind on found module." (ppr modName0)
152− LookupMultiple rs -> FoundMultiple rs
153− LookupHidden pkg_hiddens mod_hiddens ->
154− notFound
155− { fr_pkgs_hidden = map (moduleUnitId . fst) pkg_hiddens
156− , fr_mods_hidden = map (moduleUnitId . fst) mod_hiddens
157− }
158−#if MIN_GHC_API_VERSION(8,6,0)
159− LookupUnusable unusable ->
160− let unusables' = map get_unusable unusable
161− get_unusable (m, ModUnusable r) = (moduleUnitId m, r)
162− get_unusable (_, r) =
163− pprPanic "findLookupResult: unexpected origin" (ppr r)
164− in notFound {fr_unusables = unusables'}
165−#endif
166− LookupNotFound suggest ->
167− notFound {fr_suggestions = suggest}
168−
169−notFound :: FindResult
170−notFound = NotFound
171− { fr_paths = []
172− , fr_pkg = Nothing
173− , fr_pkgs_hidden = []
174− , fr_mods_hidden = []
175−#if MIN_GHC_API_VERSION(8,6,0)
176− , fr_unusables = []
177−#endif
178− , fr_suggestions = []
179− }
src/Development/IDE/LSP/HoverDefinition.hsdeleted−62
@@ -1,62 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−
5−-- | Display information on hover.
6−module Development.IDE.LSP.HoverDefinition
7− ( setHandlersHover
8− , setHandlersDefinition
9− -- * For haskell-language-server
10− , hover
11− , gotoDefinition
12− ) where
13−
14−import Development.IDE.Core.Rules
15−import Development.IDE.Core.Service
16−import Development.IDE.LSP.Server
17−import Development.IDE.Types.Location
18−import Development.IDE.Types.Logger
19−import Development.Shake
20−import qualified Language.Haskell.LSP.Core as LSP
21−import Language.Haskell.LSP.Messages
22−import Language.Haskell.LSP.Types
23−
24−import qualified Data.Text as T
25−
26−gotoDefinition :: IdeState -> TextDocumentPositionParams -> IO (Either ResponseError LocationResponseParams)
27−hover :: IdeState -> TextDocumentPositionParams -> IO (Either ResponseError (Maybe Hover))
28−gotoDefinition = request "Definition" getDefinition (MultiLoc []) SingleLoc
29−hover = request "Hover" getAtPoint Nothing foundHover
30−
31−foundHover :: (Maybe Range, [T.Text]) -> Maybe Hover
32−foundHover (mbRange, contents) =
33− Just $ Hover (HoverContents $ MarkupContent MkMarkdown $ T.intercalate sectionSeparator contents) mbRange
34−
35−setHandlersDefinition, setHandlersHover :: PartialHandlers c
36−setHandlersDefinition = PartialHandlers $ \WithMessage{..} x ->
37− return x{LSP.definitionHandler = withResponse RspDefinition $ const gotoDefinition}
38−setHandlersHover = PartialHandlers $ \WithMessage{..} x ->
39− return x{LSP.hoverHandler = withResponse RspHover $ const hover}
40−
41−-- | Respond to and log a hover or go-to-definition request
42−request
43− :: T.Text
44− -> (NormalizedFilePath -> Position -> Action (Maybe a))
45− -> b
46− -> (a -> b)
47− -> IdeState
48− -> TextDocumentPositionParams
49− -> IO (Either ResponseError b)
50−request label getResults notFound found ide (TextDocumentPositionParams (TextDocumentIdentifier uri) pos _) = do
51− mbResult <- case uriToFilePath' uri of
52− Just path -> logAndRunRequest label getResults ide pos path
53− Nothing -> pure Nothing
54− pure $ Right $ maybe notFound found mbResult
55−
56−logAndRunRequest :: T.Text -> (NormalizedFilePath -> Position -> Action b) -> IdeState -> Position -> String -> IO b
57−logAndRunRequest label getResults ide pos path = do
58− let filePath = toNormalizedFilePath' path
59− logInfo (ideLogger ide) $
60− label <> " request at position " <> T.pack (showPosition pos) <>
61− " in file: " <> T.pack path
62− runAction ide $ getResults filePath pos
src/Development/IDE/LSP/LanguageServer.hsdeleted−236
@@ -1,236 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE ExistentialQuantification #-}
5−
6−-- WARNING: A copy of DA.Daml.LanguageServer, try to keep them in sync
7−-- This version removes the daml: handling
8−module Development.IDE.LSP.LanguageServer
9− ( runLanguageServer
10− ) where
11−
12−import Language.Haskell.LSP.Types
13−import Language.Haskell.LSP.Types.Capabilities
14−import Development.IDE.LSP.Server
15−import qualified Development.IDE.GHC.Util as Ghcide
16−import qualified Language.Haskell.LSP.Control as LSP
17−import qualified Language.Haskell.LSP.Core as LSP
18−import Control.Concurrent.Chan
19−import Control.Concurrent.Extra
20−import Control.Concurrent.Async
21−import Control.Concurrent.STM
22−import Control.Exception.Safe
23−import Data.Default
24−import Data.Maybe
25−import qualified Data.Set as Set
26−import qualified Data.Text as T
27−import GHC.IO.Handle (hDuplicate)
28−import System.IO
29−import Control.Monad.Extra
30−
31−import Development.IDE.Core.IdeConfiguration
32−import Development.IDE.Core.Shake
33−import Development.IDE.LSP.HoverDefinition
34−import Development.IDE.LSP.Notifications
35−import Development.IDE.LSP.Outline
36−import Development.IDE.Types.Logger
37−import Development.IDE.Core.FileStore
38−import Language.Haskell.LSP.Core (LspFuncs(..))
39−import Language.Haskell.LSP.Messages
40−
41−runLanguageServer
42− :: forall config. (Show config)
43− => LSP.Options
44− -> PartialHandlers config
45− -> (InitializeRequest -> Either T.Text config)
46− -> (DidChangeConfigurationNotification -> Either T.Text config)
47− -> (IO LspId -> (FromServerMessage -> IO ()) -> VFSHandle -> ClientCapabilities -> IO IdeState)
48− -> IO ()
49−runLanguageServer options userHandlers onInitialConfig onConfigChange getIdeState = do
50− -- Move stdout to another file descriptor and duplicate stderr
51− -- to stdout. This guards against stray prints from corrupting the JSON-RPC
52− -- message stream.
53− newStdout <- hDuplicate stdout
54− stderr `Ghcide.hDuplicateTo'` stdout
55− hSetBuffering stderr NoBuffering
56− hSetBuffering stdout NoBuffering
57−
58− -- Print out a single space to assert that the above redirection works.
59− -- This is interleaved with the logger, hence we just print a space here in
60− -- order not to mess up the output too much. Verified that this breaks
61− -- the language server tests without the redirection.
62− putStr " " >> hFlush stdout
63−
64− -- Send everything over a channel, since you need to wait until after initialise before
65− -- LspFuncs is available
66− clientMsgChan :: Chan (Message config) <- newChan
67−
68− -- These barriers are signaled when the threads reading from these chans exit.
69− -- This should not happen but if it does, we will make sure that the whole server
70− -- dies and can be restarted instead of losing threads silently.
71− clientMsgBarrier <- newBarrier
72−
73− -- The set of requests ids that we have received but not finished processing
74− pendingRequests <- newTVarIO Set.empty
75− -- The set of requests that have been cancelled and are also in pendingRequests
76− cancelledRequests <- newTVarIO Set.empty
77−
78− let withResponse wrap f = Just $ \r@RequestMessage{_id} -> do
79− atomically $ modifyTVar pendingRequests (Set.insert _id)
80− writeChan clientMsgChan $ Response r wrap f
81− let withNotification old f = Just $ \r -> writeChan clientMsgChan $ Notification r (\lsp ide x -> f lsp ide x >> whenJust old ($ r))
82− let withResponseAndRequest wrap wrapNewReq f = Just $ \r@RequestMessage{_id} -> do
83− atomically $ modifyTVar pendingRequests (Set.insert _id)
84− writeChan clientMsgChan $ ResponseAndRequest r wrap wrapNewReq f
85− let withInitialize f = Just $ \r -> writeChan clientMsgChan $ InitialParams r (\lsp ide x -> f lsp ide x)
86− let cancelRequest reqId = atomically $ do
87− queued <- readTVar pendingRequests
88− -- We want to avoid that the list of cancelled requests
89− -- keeps growing if we receive cancellations for requests
90− -- that do not exist or have already been processed.
91− when (reqId `elem` queued) $
92− modifyTVar cancelledRequests (Set.insert reqId)
93− let clearReqId reqId = atomically $ do
94− modifyTVar pendingRequests (Set.delete reqId)
95− modifyTVar cancelledRequests (Set.delete reqId)
96− -- We implement request cancellation by racing waitForCancel against
97− -- the actual request handler.
98− let waitForCancel reqId = atomically $ do
99− cancelled <- readTVar cancelledRequests
100− unless (reqId `Set.member` cancelled) retry
101− let PartialHandlers parts =
102− initializeRequestHandler <>
103− setHandlersIgnore <> -- least important
104− setHandlersDefinition <> setHandlersHover <>
105− setHandlersOutline <>
106− userHandlers <>
107− setHandlersNotifications <> -- absolutely critical, join them with user notifications
108− cancelHandler cancelRequest
109− -- Cancel requests are special since they need to be handled
110− -- out of order to be useful. Existing handlers are run afterwards.
111− handlers <- parts WithMessage{withResponse, withNotification, withResponseAndRequest, withInitialize} def
112−
113− let initializeCallbacks = LSP.InitializeCallbacks
114− { LSP.onInitialConfiguration = onInitialConfig
115− , LSP.onConfigurationChange = onConfigChange
116− , LSP.onStartup = handleInit (signalBarrier clientMsgBarrier ()) clearReqId waitForCancel clientMsgChan
117− }
118−
119− void $ waitAnyCancel =<< traverse async
120− [ void $ LSP.runWithHandles
121− stdin
122− newStdout
123− initializeCallbacks
124− handlers
125− (modifyOptions options)
126− Nothing
127− , void $ waitBarrier clientMsgBarrier
128− ]
129− where
130− handleInit :: IO () -> (LspId -> IO ()) -> (LspId -> IO ()) -> Chan (Message config) -> LSP.LspFuncs config -> IO (Maybe err)
131− handleInit exitClientMsg clearReqId waitForCancel clientMsgChan lspFuncs@LSP.LspFuncs{..} = do
132−
133− ide <- getIdeState getNextReqId sendFunc (makeLSPVFSHandle lspFuncs) clientCapabilities
134−
135− _ <- flip forkFinally (const exitClientMsg) $ forever $ do
136− msg <- readChan clientMsgChan
137− case msg of
138− Notification x@NotificationMessage{_params} act -> do
139− catch (act lspFuncs ide _params) $ \(e :: SomeException) ->
140− logError (ideLogger ide) $ T.pack $
141− "Unexpected exception on notification, please report!\n" ++
142− "Message: " ++ show x ++ "\n" ++
143− "Exception: " ++ show e
144− Response x@RequestMessage{_id, _params} wrap act ->
145− checkCancelled ide clearReqId waitForCancel lspFuncs wrap act x _id _params $
146− \case
147− Left e -> sendFunc $ wrap $ ResponseMessage "2.0" (responseId _id) (Left e)
148− Right r -> sendFunc $ wrap $ ResponseMessage "2.0" (responseId _id) (Right r)
149− ResponseAndRequest x@RequestMessage{_id, _params} wrap wrapNewReq act ->
150− checkCancelled ide clearReqId waitForCancel lspFuncs wrap act x _id _params $
151− \(res, newReq) -> do
152− case res of
153− Left e -> sendFunc $ wrap $ ResponseMessage "2.0" (responseId _id) (Left e)
154− Right r -> sendFunc $ wrap $ ResponseMessage "2.0" (responseId _id) (Right r)
155− whenJust newReq $ \(rm, newReqParams) -> do
156− reqId <- getNextReqId
157− sendFunc $ wrapNewReq $ RequestMessage "2.0" reqId rm newReqParams
158− InitialParams x@RequestMessage{_id, _params} act -> do
159− catch (act lspFuncs ide _params) $ \(e :: SomeException) ->
160− logError (ideLogger ide) $ T.pack $
161− "Unexpected exception on InitializeRequest handler, please report!\n" ++
162− "Message: " ++ show x ++ "\n" ++
163− "Exception: " ++ show e
164− pure Nothing
165−
166− checkCancelled ide clearReqId waitForCancel lspFuncs@LSP.LspFuncs{..} wrap act msg _id _params k =
167− flip finally (clearReqId _id) $
168− catch (do
169− -- We could optimize this by first checking if the id
170− -- is in the cancelled set. However, this is unlikely to be a
171− -- bottleneck and the additional check might hide
172− -- issues with async exceptions that need to be fixed.
173− cancelOrRes <- race (waitForCancel _id) $ act lspFuncs ide _params
174− case cancelOrRes of
175− Left () -> do
176− logDebug (ideLogger ide) $ T.pack $
177− "Cancelled request " <> show _id
178− sendFunc $ wrap $ ResponseMessage "2.0" (responseId _id) $ Left
179− $ ResponseError RequestCancelled "" Nothing
180− Right res -> k res
181− ) $ \(e :: SomeException) -> do
182− logError (ideLogger ide) $ T.pack $
183− "Unexpected exception on request, please report!\n" ++
184− "Message: " ++ show msg ++ "\n" ++
185− "Exception: " ++ show e
186− sendFunc $ wrap $ ResponseMessage "2.0" (responseId _id) $ Left
187− $ ResponseError InternalError (T.pack $ show e) Nothing
188−
189−initializeRequestHandler :: PartialHandlers config
190−initializeRequestHandler = PartialHandlers $ \WithMessage{..} x -> return x{
191− LSP.initializeRequestHandler = withInitialize initHandler
192− }
193−
194−initHandler
195− :: LSP.LspFuncs c
196− -> IdeState
197− -> InitializeParams
198− -> IO ()
199−initHandler _ ide params = registerIdeConfiguration (shakeExtras ide) (parseConfiguration params)
200−
201−-- | Things that get sent to us, but we don't deal with.
202−-- Set them to avoid a warning in VS Code output.
203−setHandlersIgnore :: PartialHandlers config
204−setHandlersIgnore = PartialHandlers $ \_ x -> return x
205− {LSP.initializedHandler = none
206− ,LSP.responseHandler = none
207− }
208− where none = Just $ const $ return ()
209−
210−cancelHandler :: (LspId -> IO ()) -> PartialHandlers config
211−cancelHandler cancelRequest = PartialHandlers $ \_ x -> return x
212− {LSP.cancelNotificationHandler = Just $ \msg@NotificationMessage {_params = CancelParams {_id}} -> do
213− cancelRequest _id
214− whenJust (LSP.cancelNotificationHandler x) ($ msg)
215− }
216−
217−
218−-- | A message that we need to deal with - the pieces are split up with existentials to gain additional type safety
219−-- and defer precise processing until later (allows us to keep at a higher level of abstraction slightly longer)
220−data Message c
221− = forall m req resp . (Show m, Show req) => Response (RequestMessage m req resp) (ResponseMessage resp -> FromServerMessage) (LSP.LspFuncs c -> IdeState -> req -> IO (Either ResponseError resp))
222− -- | Used for cases in which we need to send not only a response,
223− -- but also an additional request to the client.
224− -- For example, 'executeCommand' may generate an 'applyWorkspaceEdit' request.
225− | forall m rm req resp newReqParams newReqBody . (Show m, Show rm, Show req) => ResponseAndRequest (RequestMessage m req resp) (ResponseMessage resp -> FromServerMessage) (RequestMessage rm newReqParams newReqBody -> FromServerMessage) (LSP.LspFuncs c -> IdeState -> req -> IO (Either ResponseError resp, Maybe (rm, newReqParams)))
226− | forall m req . (Show m, Show req) => Notification (NotificationMessage m req) (LSP.LspFuncs c -> IdeState -> req -> IO ())
227− -- | Used for the InitializeRequest only, where the response is generated by the LSP core handler.
228− | InitialParams InitializeRequest (LSP.LspFuncs c -> IdeState -> InitializeParams -> IO ())
229−
230−modifyOptions :: LSP.Options -> LSP.Options
231−modifyOptions x = x{ LSP.textDocumentSync = Just $ tweakTDS origTDS
232− }
233− where
234− tweakTDS tds = tds{_openClose=Just True, _change=Just TdSyncIncremental, _save=Just $ SaveOptions Nothing}
235− origTDS = fromMaybe tdsDefault $ LSP.textDocumentSync x
236− tdsDefault = TextDocumentSyncOptions Nothing Nothing Nothing Nothing Nothing
src/Development/IDE/LSP/Notifications.hsdeleted−81
@@ -1,81 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE DuplicateRecordFields #-}
5−{-# LANGUAGE RankNTypes #-}
6−
7−module Development.IDE.LSP.Notifications
8− ( setHandlersNotifications
9− ) where
10−
11−import Development.IDE.LSP.Server
12−import qualified Language.Haskell.LSP.Core as LSP
13−import Language.Haskell.LSP.Types
14−import qualified Language.Haskell.LSP.Types as LSP
15−
16−import Development.IDE.Core.IdeConfiguration
17−import Development.IDE.Core.Service
18−import Development.IDE.Types.Location
19−import Development.IDE.Types.Logger
20−
21−import Control.Monad.Extra
22−import Data.Foldable as F
23−import Data.Maybe
24−import qualified Data.HashSet as S
25−import qualified Data.Text as Text
26−
27−import Development.IDE.Core.FileStore (setSomethingModified)
28−import Development.IDE.Core.FileExists (modifyFileExists)
29−import Development.IDE.Core.OfInterest
30−
31−
32−whenUriFile :: Uri -> (NormalizedFilePath -> IO ()) -> IO ()
33−whenUriFile uri act = whenJust (LSP.uriToFilePath uri) $ act . toNormalizedFilePath'
34−
35−setHandlersNotifications :: PartialHandlers c
36−setHandlersNotifications = PartialHandlers $ \WithMessage{..} x -> return x
37− {LSP.didOpenTextDocumentNotificationHandler = withNotification (LSP.didOpenTextDocumentNotificationHandler x) $
38− \_ ide (DidOpenTextDocumentParams TextDocumentItem{_uri,_version}) -> do
39− updatePositionMapping ide (VersionedTextDocumentIdentifier _uri (Just _version)) (List [])
40− whenUriFile _uri $ \file -> do
41− modifyFilesOfInterest ide (S.insert file)
42− logInfo (ideLogger ide) $ "Opened text document: " <> getUri _uri
43−
44− ,LSP.didChangeTextDocumentNotificationHandler = withNotification (LSP.didChangeTextDocumentNotificationHandler x) $
45− \_ ide (DidChangeTextDocumentParams identifier@VersionedTextDocumentIdentifier{_uri} changes) -> do
46− updatePositionMapping ide identifier changes
47− setSomethingModified ide
48− logInfo (ideLogger ide) $ "Modified text document: " <> getUri _uri
49−
50− ,LSP.didSaveTextDocumentNotificationHandler = withNotification (LSP.didSaveTextDocumentNotificationHandler x) $
51− \_ ide (DidSaveTextDocumentParams TextDocumentIdentifier{_uri}) -> do
52− setSomethingModified ide
53− logInfo (ideLogger ide) $ "Saved text document: " <> getUri _uri
54−
55− ,LSP.didCloseTextDocumentNotificationHandler = withNotification (LSP.didCloseTextDocumentNotificationHandler x) $
56− \_ ide (DidCloseTextDocumentParams TextDocumentIdentifier{_uri}) -> do
57− whenUriFile _uri $ \file -> do
58− modifyFilesOfInterest ide (S.delete file)
59− logInfo (ideLogger ide) $ "Closed text document: " <> getUri _uri
60− ,LSP.didChangeWatchedFilesNotificationHandler = withNotification (LSP.didChangeWatchedFilesNotificationHandler x) $
61− \_ ide (DidChangeWatchedFilesParams fileEvents) -> do
62− let events =
63− mapMaybe
64− (\(FileEvent uri ev) ->
65− (, ev /= FcDeleted) . toNormalizedFilePath'
66− <$> LSP.uriToFilePath uri
67− )
68− ( F.toList fileEvents )
69− let msg = Text.pack $ show events
70− logInfo (ideLogger ide) $ "Files created or deleted: " <> msg
71− modifyFileExists ide events
72− setSomethingModified ide
73−
74− ,LSP.didChangeWorkspaceFoldersNotificationHandler = withNotification (LSP.didChangeWorkspaceFoldersNotificationHandler x) $
75− \_ ide (DidChangeWorkspaceFoldersParams events) -> do
76− let add = S.union
77− substract = flip S.difference
78− modifyWorkspaceFolders ide
79− $ add (foldMap (S.singleton . parseWorkspaceFolder) (_added events))
80− . substract (foldMap (S.singleton . parseWorkspaceFolder) (_removed events))
81− }
src/Development/IDE/LSP/Outline.hsdeleted−234
@@ -1,234 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DuplicateRecordFields #-}
3−#include "ghc-api-version.h"
4−
5−module Development.IDE.LSP.Outline
6− ( setHandlersOutline
7− -- * For haskell-language-server
8− , moduleOutline
9− )
10−where
11−
12−import qualified Language.Haskell.LSP.Core as LSP
13−import Language.Haskell.LSP.Messages
14−import Language.Haskell.LSP.Types
15−import Data.Functor
16−import Data.Generics
17−import Data.Maybe
18−import Data.Text ( Text
19− , pack
20− )
21−import qualified Data.Text as T
22−import Development.IDE.Core.Rules
23−import Development.IDE.Core.Shake
24−import Development.IDE.GHC.Compat
25−import Development.IDE.GHC.Error ( srcSpanToRange )
26−import Development.IDE.LSP.Server
27−import Development.IDE.Types.Location
28−import Outputable ( Outputable
29− , ppr
30− , showSDocUnsafe
31− )
32−
33−setHandlersOutline :: PartialHandlers c
34−setHandlersOutline = PartialHandlers $ \WithMessage {..} x -> return x
35− { LSP.documentSymbolHandler = withResponse RspDocumentSymbols moduleOutline
36− }
37−
38−moduleOutline
39− :: LSP.LspFuncs c -> IdeState -> DocumentSymbolParams -> IO (Either ResponseError DSResult)
40−moduleOutline _lsp ideState DocumentSymbolParams { _textDocument = TextDocumentIdentifier uri }
41− = case uriToFilePath uri of
42− Just (toNormalizedFilePath' -> fp) -> do
43− mb_decls <- runAction ideState $ use GetParsedModule fp
44− pure $ Right $ case mb_decls of
45− Nothing -> DSDocumentSymbols (List [])
46− Just ParsedModule { pm_parsed_source = L _ltop HsModule { hsmodName, hsmodDecls, hsmodImports } }
47− -> let
48− declSymbols = mapMaybe documentSymbolForDecl hsmodDecls
49− moduleSymbol = hsmodName <&> \(L l m) ->
50− (defDocumentSymbol l :: DocumentSymbol)
51− { _name = pprText m
52− , _kind = SkFile
53− , _range = Range (Position 0 0) (Position maxBound 0) -- _ltop is 0 0 0 0
54− }
55− importSymbols = maybe [] pure $
56− documentSymbolForImportSummary
57− (mapMaybe documentSymbolForImport hsmodImports)
58− allSymbols = case moduleSymbol of
59− Nothing -> importSymbols <> declSymbols
60− Just x ->
61− [ x { _children = Just (List (importSymbols <> declSymbols))
62− }
63− ]
64− in
65− DSDocumentSymbols (List allSymbols)
66−
67−
68− Nothing -> pure $ Right $ DSDocumentSymbols (List [])
69−
70−documentSymbolForDecl :: Located (HsDecl GhcPs) -> Maybe DocumentSymbol
71−documentSymbolForDecl (L l (TyClD FamDecl { tcdFam = FamilyDecl { fdLName = L _ n, fdInfo, fdTyVars } }))
72− = Just (defDocumentSymbol l :: DocumentSymbol)
73− { _name = showRdrName n
74− <> (case pprText fdTyVars of
75− "" -> ""
76− t -> " " <> t
77− )
78− , _detail = Just $ pprText fdInfo
79− , _kind = SkClass
80− }
81−documentSymbolForDecl (L l (TyClD ClassDecl { tcdLName = L _ name, tcdSigs, tcdTyVars }))
82− = Just (defDocumentSymbol l :: DocumentSymbol)
83− { _name = showRdrName name
84− <> (case pprText tcdTyVars of
85− "" -> ""
86− t -> " " <> t
87− )
88− , _kind = SkClass
89− , _detail = Just "class"
90− , _children =
91− Just $ List
92− [ (defDocumentSymbol l :: DocumentSymbol)
93− { _name = showRdrName n
94− , _kind = SkMethod
95− , _selectionRange = srcSpanToRange l'
96− }
97− | L l (ClassOpSig False names _) <- tcdSigs
98− , L l' n <- names
99− ]
100− }
101−documentSymbolForDecl (L l (TyClD DataDecl { tcdLName = L _ name, tcdDataDefn = HsDataDefn { dd_cons } }))
102− = Just (defDocumentSymbol l :: DocumentSymbol)
103− { _name = showRdrName name
104− , _kind = SkStruct
105− , _children =
106− Just $ List
107− [ (defDocumentSymbol l :: DocumentSymbol)
108− { _name = showRdrName n
109− , _kind = SkConstructor
110− , _selectionRange = srcSpanToRange l'
111− , _children = conArgRecordFields (getConArgs x)
112− }
113− | L l x <- dd_cons
114− , L l' n <- getConNames x
115− ]
116− }
117− where
118− -- | Extract the record fields of a constructor
119− conArgRecordFields (RecCon (L _ lcdfs)) = Just $ List
120− [ (defDocumentSymbol l :: DocumentSymbol)
121− { _name = showRdrName n
122− , _kind = SkField
123− }
124− | L _ cdf <- lcdfs
125− , L l n <- rdrNameFieldOcc . unLoc <$> cd_fld_names cdf
126− ]
127− conArgRecordFields _ = Nothing
128−documentSymbolForDecl (L l (TyClD SynDecl { tcdLName = L l' n })) = Just
129− (defDocumentSymbol l :: DocumentSymbol) { _name = showRdrName n
130− , _kind = SkTypeParameter
131− , _selectionRange = srcSpanToRange l'
132− }
133−documentSymbolForDecl (L l (InstD ClsInstD { cid_inst = ClsInstDecl { cid_poly_ty } }))
134− = Just (defDocumentSymbol l :: DocumentSymbol) { _name = pprText cid_poly_ty
135− , _kind = SkInterface
136− }
137−documentSymbolForDecl (L l (InstD DataFamInstD { dfid_inst = DataFamInstDecl HsIB { hsib_body = FamEqn { feqn_tycon, feqn_pats } } }))
138− = Just (defDocumentSymbol l :: DocumentSymbol)
139− { _name = showRdrName (unLoc feqn_tycon) <> " " <> T.unwords
140− (map pprText feqn_pats)
141− , _kind = SkInterface
142− }
143−documentSymbolForDecl (L l (InstD TyFamInstD { tfid_inst = TyFamInstDecl HsIB { hsib_body = FamEqn { feqn_tycon, feqn_pats } } }))
144− = Just (defDocumentSymbol l :: DocumentSymbol)
145− { _name = showRdrName (unLoc feqn_tycon) <> " " <> T.unwords
146− (map pprText feqn_pats)
147− , _kind = SkInterface
148− }
149−documentSymbolForDecl (L l (DerivD DerivDecl { deriv_type })) =
150− gfindtype deriv_type <&> \(L (_ :: SrcSpan) name) ->
151− (defDocumentSymbol l :: DocumentSymbol) { _name = pprText @(HsType GhcPs)
152− name
153− , _kind = SkInterface
154− }
155−documentSymbolForDecl (L l (ValD FunBind{fun_id = L _ name})) = Just
156− (defDocumentSymbol l :: DocumentSymbol)
157− { _name = showRdrName name
158− , _kind = SkFunction
159− }
160−documentSymbolForDecl (L l (ValD PatBind{pat_lhs})) = Just
161− (defDocumentSymbol l :: DocumentSymbol)
162− { _name = pprText pat_lhs
163− , _kind = SkFunction
164− }
165−
166−documentSymbolForDecl (L l (ForD x)) = Just
167− (defDocumentSymbol l :: DocumentSymbol)
168− { _name = case x of
169− ForeignImport{} -> name
170− ForeignExport{} -> name
171−#if MIN_GHC_API_VERSION(8,6,0)
172− XForeignDecl{} -> "?"
173−#endif
174− , _kind = SkObject
175− , _detail = case x of
176− ForeignImport{} -> Just "import"
177− ForeignExport{} -> Just "export"
178−#if MIN_GHC_API_VERSION(8,6,0)
179− XForeignDecl{} -> Nothing
180−#endif
181− }
182− where name = showRdrName $ unLoc $ fd_name x
183−
184−documentSymbolForDecl _ = Nothing
185−
186−-- | Wrap the Document imports into a hierarchical outline for
187−-- a better overview of symbols in scope.
188−-- If there are no imports, then no hierarchy will be created.
189−documentSymbolForImportSummary :: [DocumentSymbol] -> Maybe DocumentSymbol
190−documentSymbolForImportSummary [] = Nothing
191−documentSymbolForImportSummary importSymbols =
192− let
193− -- safe because if we have no ranges then we don't take this branch
194− mergeRanges xs = Range (minimum $ map _start xs) (maximum $ map _end xs)
195− importRange = mergeRanges $ map (_range :: DocumentSymbol -> Range) importSymbols
196− in
197− Just (defDocumentSymbol empty :: DocumentSymbol)
198− { _name = "imports"
199− , _kind = SkModule
200− , _children = Just (List importSymbols)
201− , _range = importRange
202− , _selectionRange = importRange
203− }
204−
205−documentSymbolForImport :: Located (ImportDecl GhcPs) -> Maybe DocumentSymbol
206−documentSymbolForImport (L l ImportDecl { ideclName, ideclQualified }) = Just
207− (defDocumentSymbol l :: DocumentSymbol)
208− { _name = "import " <> pprText ideclName
209− , _kind = SkModule
210−#if MIN_GHC_API_VERSION(8,10,0)
211− , _detail = case ideclQualified of { NotQualified -> Nothing; _ -> Just "qualified" }
212−#else
213− , _detail = if ideclQualified then Just "qualified" else Nothing
214−#endif
215− }
216−#if MIN_GHC_API_VERSION(8,6,0)
217−documentSymbolForImport (L _ XImportDecl {}) = Nothing
218−#endif
219−
220−defDocumentSymbol :: SrcSpan -> DocumentSymbol
221−defDocumentSymbol l = DocumentSymbol { .. } where
222− _detail = Nothing
223− _deprecated = Nothing
224− _name = ""
225− _kind = SkUnknown 0
226− _range = srcSpanToRange l
227− _selectionRange = srcSpanToRange l
228− _children = Nothing
229−
230−showRdrName :: RdrName -> Text
231−showRdrName = pprText
232−
233−pprText :: Outputable a => a -> Text
234−pprText = pack . showSDocUnsafe . ppr
src/Development/IDE/LSP/Protocol.hsdeleted−23
@@ -1,23 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−{-# LANGUAGE PatternSynonyms #-}
4−
5−module Development.IDE.LSP.Protocol
6− ( pattern EventFileDiagnostics
7− ) where
8−
9−import Development.IDE.Types.Diagnostics
10−import Development.IDE.Types.Location
11−import Language.Haskell.LSP.Messages
12−import Language.Haskell.LSP.Types
13−
14−----------------------------------------------------------------------------------------------------
15−-- Pretty printing
16−----------------------------------------------------------------------------------------------------
17−
18−-- | Pattern synonym to make it a bit more convenient to match on diagnostics
19−-- in things like damlc test.
20−pattern EventFileDiagnostics :: FilePath -> [Diagnostic] -> FromServerMessage
21−pattern EventFileDiagnostics fp diags <-
22− NotPublishDiagnostics
23− (NotificationMessage _ _ (PublishDiagnosticsParams (uriToFilePath' -> Just fp) (List diags)))
src/Development/IDE/LSP/Server.hsdeleted−47
@@ -1,47 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE DuplicateRecordFields #-}
5−{-# LANGUAGE RankNTypes #-}
6−module Development.IDE.LSP.Server
7− ( WithMessage(..)
8− , PartialHandlers(..)
9− ) where
10−
11−
12−import Data.Default
13−
14−import Language.Haskell.LSP.Types
15−import qualified Language.Haskell.LSP.Core as LSP
16−import qualified Language.Haskell.LSP.Messages as LSP
17−import Development.IDE.Core.Service
18−
19−data WithMessage c = WithMessage
20− {withResponse :: forall m req resp . (Show m, Show req) =>
21− (ResponseMessage resp -> LSP.FromServerMessage) -> -- how to wrap a response
22− (LSP.LspFuncs c -> IdeState -> req -> IO (Either ResponseError resp)) -> -- actual work
23− Maybe (LSP.Handler (RequestMessage m req resp))
24− ,withNotification :: forall m req . (Show m, Show req) =>
25− Maybe (LSP.Handler (NotificationMessage m req)) -> -- old notification handler
26− (LSP.LspFuncs c -> IdeState -> req -> IO ()) -> -- actual work
27− Maybe (LSP.Handler (NotificationMessage m req))
28− ,withResponseAndRequest :: forall m rm req resp newReqParams newReqBody .
29− (Show m, Show rm, Show req, Show newReqParams, Show newReqBody) =>
30− (ResponseMessage resp -> LSP.FromServerMessage) -> -- how to wrap a response
31− (RequestMessage rm newReqParams newReqBody -> LSP.FromServerMessage) -> -- how to wrap the additional req
32− (LSP.LspFuncs c -> IdeState -> req -> IO (Either ResponseError resp, Maybe (rm, newReqParams))) -> -- actual work
33− Maybe (LSP.Handler (RequestMessage m req resp))
34− , withInitialize :: (LSP.LspFuncs c -> IdeState -> InitializeParams -> IO ())
35− -> Maybe (LSP.Handler InitializeRequest)
36− }
37−
38−newtype PartialHandlers c = PartialHandlers (WithMessage c -> LSP.Handlers -> IO LSP.Handlers)
39−
40−instance Default (PartialHandlers c) where
41− def = PartialHandlers $ \_ x -> pure x
42−
43−instance Semigroup (PartialHandlers c) where
44− PartialHandlers a <> PartialHandlers b = PartialHandlers $ \w x -> a w x >>= b w
45−
46−instance Monoid (PartialHandlers c) where
47− mempty = def
src/Development/IDE/Logger.hsnew file+26
@@ -0,0 +1,26 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE RankNTypes #-}
5+-- | This is a compatibility module that abstracts over the
6+-- concrete choice of logging framework so users can plug in whatever
7+-- framework they want to.
8+module Development.IDE.Logger
9+ ( Handle(..)
10+ , makeOneHandle
11+ , makeNopHandle
12+ ) where
13+
14+import qualified Data.Text as T
15+import GHC.Stack
16+
17+data Handle = Handle {
18+ logSeriousError :: HasCallStack => T.Text -> IO ()
19+ , logDebug :: HasCallStack => T.Text -> IO ()
20+ }
21+
22+makeNopHandle :: Handle
23+makeNopHandle = makeOneHandle $ const $ pure ()
24+
25+makeOneHandle :: (HasCallStack => T.Text -> IO ()) -> Handle
26+makeOneHandle x = Handle x x
src/Development/IDE/Orphans.hsnew file+40
@@ -0,0 +1,40 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# OPTIONS_GHC -Wno-orphans #-}
6+
7+-- | Orphan instances for GHC.
8+-- Note that the 'NFData' instances may not be law abiding.
9+module Development.IDE.Orphans() where
10+
11+import GHC hiding (convertLit)
12+import GhcPlugins as GHC hiding (fst3, (<>))
13+import qualified StringBuffer as SB
14+import Control.DeepSeq
15+import Development.IDE.UtilGHC
16+
17+
18+-- Orphan instances for types from the GHC API.
19+instance Show CoreModule where show = prettyPrint
20+instance NFData CoreModule where rnf = rwhnf
21+
22+
23+instance Show InstalledUnitId where
24+ show = installedUnitIdString
25+
26+instance NFData InstalledUnitId where rnf = rwhnf
27+
28+instance NFData SB.StringBuffer where rnf = rwhnf
29+
30+instance Show Module where
31+ show = moduleNameString . moduleName
32+
33+instance Show RdrName where show = prettyPrint
34+instance Show ComponentId where show = prettyPrint
35+instance Show SourcePackageId where show = prettyPrint
36+instance Show ModuleName where show = prettyPrint
37+instance Show (GenLocated SrcSpan ModuleName) where show = prettyPrint
38+instance Show PackageName where show = prettyPrint
39+instance Show PackageState where show _ = "PackageState"
40+instance Show Name where show = prettyPrint
src/Development/IDE/Plugin.hsdeleted−60
@@ -1,60 +0,0 @@
1−
2−module Development.IDE.Plugin(Plugin(..), codeActionPlugin, codeActionPluginWithRules,makeLspCommandId,getPid) where
3−
4−import Data.Default
5−import qualified Data.Text as T
6−import Development.Shake
7−import Development.IDE.LSP.Server
8−
9−import Language.Haskell.LSP.Types
10−import Development.IDE.Compat
11−import Development.IDE.Core.Rules
12−import qualified Language.Haskell.LSP.Core as LSP
13−import Language.Haskell.LSP.Messages
14−
15−
16−data Plugin c = Plugin
17− {pluginRules :: Rules ()
18− ,pluginHandler :: PartialHandlers c
19− }
20−
21−instance Default (Plugin c) where
22− def = Plugin mempty def
23−
24−instance Semigroup (Plugin c) where
25− Plugin x1 y1 <> Plugin x2 y2 = Plugin (x1<>x2) (y1<>y2)
26−
27−instance Monoid (Plugin c) where
28− mempty = def
29−
30−
31−codeActionPlugin :: (LSP.LspFuncs c -> IdeState -> TextDocumentIdentifier -> Range -> CodeActionContext -> IO (Either ResponseError [CAResult])) -> Plugin c
32−codeActionPlugin = codeActionPluginWithRules mempty
33−
34−codeActionPluginWithRules :: Rules () -> (LSP.LspFuncs c -> IdeState -> TextDocumentIdentifier -> Range -> CodeActionContext -> IO (Either ResponseError [CAResult])) -> Plugin c
35−codeActionPluginWithRules rr f = Plugin rr $ PartialHandlers $ \WithMessage{..} x -> return x{
36− LSP.codeActionHandler = withResponse RspCodeAction g
37− }
38− where
39− g lsp state (CodeActionParams a b c _) = fmap List <$> f lsp state a b c
40−
41−-- | Prefix to uniquely identify commands sent to the client. This
42−-- has two parts
43−--
44−-- - A representation of the process id to make sure that a client has
45−-- unique commands if it is running multiple servers, since some
46−-- clients have a global command table and get confused otherwise.
47−--
48−-- - A string to identify ghcide, to ease integration into
49−-- haskell-language-server, which routes commands to plugins based
50−-- on that.
51−makeLspCommandId :: T.Text -> IO T.Text
52−makeLspCommandId command = do
53− pid <- getPid
54− return $ pid <> ":ghcide:" <> command
55−
56−-- | Get the operating system process id for the running server
57−-- instance. This should be the same for the lifetime of the instance,
58−-- and different from that of any other currently running instance.
59−getPid :: IO T.Text
60−getPid = T.pack . show <$> getProcessID
src/Development/IDE/Plugin/CodeAction.hsdeleted−570
@@ -1,570 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE DuplicateRecordFields #-}
5−{-# LANGUAGE CPP #-}
6−#include "ghc-api-version.h"
7−
8−-- | Go to the definition of a variable.
9−module Development.IDE.Plugin.CodeAction
10− (
11− plugin
12−
13− -- * For haskell-language-server
14− , codeAction
15− , codeLens
16− , rulePackageExports
17− , executeAddSignatureCommand
18− ) where
19−
20−import Language.Haskell.LSP.Types
21−import Control.Monad (join)
22−import Development.IDE.Plugin
23−import Development.IDE.GHC.Compat
24−import Development.IDE.Core.Rules
25−import Development.IDE.Core.RuleTypes
26−import Development.IDE.Core.Service
27−import Development.IDE.Core.Shake
28−import Development.IDE.GHC.Error
29−import Development.IDE.GHC.Util
30−import Development.IDE.LSP.Server
31−import Development.IDE.Plugin.CodeAction.PositionIndexed
32−import Development.IDE.Plugin.CodeAction.RuleTypes
33−import Development.IDE.Plugin.CodeAction.Rules
34−import Development.IDE.Types.Location
35−import Development.IDE.Types.Options
36−import Development.Shake (Rules)
37−import qualified Data.HashMap.Strict as Map
38−import qualified Language.Haskell.LSP.Core as LSP
39−import Language.Haskell.LSP.VFS
40−import Language.Haskell.LSP.Messages
41−import qualified Data.Rope.UTF16 as Rope
42−import Data.Aeson.Types (toJSON, fromJSON, Value(..), Result(..))
43−import Control.Monad.Trans.Maybe
44−import Data.Char
45−import Data.Maybe
46−import Data.List.Extra
47−import qualified Data.Text as T
48−import Data.Tuple.Extra ((&&&))
49−import HscTypes
50−import Parser
51−import Text.Regex.TDFA ((=~), (=~~))
52−import Text.Regex.TDFA.Text()
53−import Outputable (ppr, showSDocUnsafe)
54−import DynFlags (xFlags, FlagSpec(..))
55−import GHC.LanguageExtensions.Type (Extension)
56−
57−plugin :: Plugin c
58−plugin = codeActionPluginWithRules rules codeAction <> Plugin mempty setHandlersCodeLens
59−
60−rules :: Rules ()
61−rules = rulePackageExports
62−
63−-- | Generate code actions.
64−codeAction
65− :: LSP.LspFuncs c
66− -> IdeState
67− -> TextDocumentIdentifier
68− -> Range
69− -> CodeActionContext
70− -> IO (Either ResponseError [CAResult])
71−codeAction lsp state (TextDocumentIdentifier uri) _range CodeActionContext{_diagnostics=List xs} = do
72− -- disable logging as its quite verbose
73− -- logInfo (ideLogger ide) $ T.pack $ "Code action req: " ++ show arg
74− contents <- LSP.getVirtualFileFunc lsp $ toNormalizedUri uri
75− let text = Rope.toText . (_text :: VirtualFile -> Rope.Rope) <$> contents
76− mbFile = toNormalizedFilePath' <$> uriToFilePath uri
77− (ideOptions, parsedModule, join -> env) <- runAction state $
78− (,,) <$> getIdeOptions
79− <*> getParsedModule `traverse` mbFile
80− <*> use GhcSession `traverse` mbFile
81− pkgExports <- runAction state $ (useNoFile_ . PackageExports) `traverse` env
82− let dflags = hsc_dflags . hscEnv <$> env
83− pure $ Right
84− [ CACodeAction $ CodeAction title (Just CodeActionQuickFix) (Just $ List [x]) (Just edit) Nothing
85− | x <- xs, (title, tedit) <- suggestAction dflags (fromMaybe mempty pkgExports) ideOptions ( join parsedModule ) text x
86− , let edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing
87− ]
88−
89−-- | Generate code lenses.
90−codeLens
91− :: LSP.LspFuncs c
92− -> IdeState
93− -> CodeLensParams
94− -> IO (Either ResponseError (List CodeLens))
95−codeLens _lsp ideState CodeLensParams{_textDocument=TextDocumentIdentifier uri} = do
96− commandId <- makeLspCommandId "typesignature.add"
97− fmap (Right . List) $ case uriToFilePath' uri of
98− Just (toNormalizedFilePath' -> filePath) -> do
99− _ <- runAction ideState $ runMaybeT $ useE TypeCheck filePath
100− diag <- getDiagnostics ideState
101− hDiag <- getHiddenDiagnostics ideState
102− pure
103− [ CodeLens _range (Just (Command title commandId (Just $ List [toJSON edit]))) Nothing
104− | (dFile, _, dDiag@Diagnostic{_range=_range}) <- diag ++ hDiag
105− , dFile == filePath
106− , (title, tedit) <- suggestSignature False dDiag
107− , let edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing
108− ]
109− Nothing -> pure []
110−
111−-- | Execute the "typesignature.add" command.
112−executeAddSignatureCommand
113− :: LSP.LspFuncs c
114− -> IdeState
115− -> ExecuteCommandParams
116− -> IO (Either ResponseError Value, Maybe (ServerMethod, ApplyWorkspaceEditParams))
117−executeAddSignatureCommand _lsp _ideState ExecuteCommandParams{..}
118− -- _command is prefixed with a process ID, because certain clients
119− -- have a global command registry, and all commands must be
120− -- unique. And there can be more than one ghcide instance running
121− -- at a time against the same client.
122− | T.isSuffixOf "typesignature.add" _command
123− , Just (List [edit]) <- _arguments
124− , Success wedit <- fromJSON edit
125− = return (Right Null, Just (WorkspaceApplyEdit, ApplyWorkspaceEditParams wedit))
126− | otherwise
127− = return (Right Null, Nothing)
128−
129−suggestAction
130− :: Maybe DynFlags
131− -> PackageExportsMap
132− -> IdeOptions
133− -> Maybe ParsedModule
134− -> Maybe T.Text
135− -> Diagnostic
136− -> [(T.Text, [TextEdit])]
137−suggestAction dflags packageExports ideOptions parsedModule text diag = concat
138− [ suggestAddExtension diag
139− , suggestExtendImport dflags text diag
140− , suggestFillHole diag
141− , suggestFillTypeWildcard diag
142− , suggestFixConstructorImport text diag
143− , suggestModuleTypo diag
144− , suggestReplaceIdentifier text diag
145− , suggestSignature True diag
146− ] ++ concat
147− [ suggestNewDefinition ideOptions pm text diag
148− ++ suggestRemoveRedundantImport pm text diag
149− ++ suggestNewImport packageExports pm diag
150− | Just pm <- [parsedModule]]
151−
152−
153−suggestRemoveRedundantImport :: ParsedModule -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
154−suggestRemoveRedundantImport ParsedModule{pm_parsed_source = L _ HsModule{hsmodImports}} contents Diagnostic{_range=_range,..}
155−-- The qualified import of ‘many’ from module ‘Control.Applicative’ is redundant
156− | Just [_, bindings] <- matchRegex _message "The( qualified)? import of ‘([^’]*)’ from module [^ ]* is redundant"
157− , Just (L _ impDecl) <- find (\(L l _) -> srcSpanToRange l == _range ) hsmodImports
158− , Just c <- contents
159− , ranges <- map (rangesForBinding impDecl . T.unpack) (T.splitOn ", " bindings)
160− , ranges' <- extendAllToIncludeCommaIfPossible (indexedByPosition $ T.unpack c) (concat ranges)
161− , not (null ranges')
162− = [( "Remove " <> bindings <> " from import" , [ TextEdit r "" | r <- ranges' ] )]
163−
164−-- File.hs:16:1: warning:
165−-- The import of `Data.List' is redundant
166−-- except perhaps to import instances from `Data.List'
167−-- To import instances alone, use: import Data.List()
168− | _message =~ ("The( qualified)? import of [^ ]* is redundant" :: String)
169− = [("Remove import", [TextEdit (extendToWholeLineIfPossible contents _range) ""])]
170− | otherwise = []
171−
172−suggestReplaceIdentifier :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
173−suggestReplaceIdentifier contents Diagnostic{_range=_range,..}
174−-- File.hs:52:41: error:
175−-- * Variable not in scope:
176−-- suggestAcion :: Maybe T.Text -> Range -> Range
177−-- * Perhaps you meant ‘suggestAction’ (line 83)
178−-- File.hs:94:37: error:
179−-- Not in scope: ‘T.isPrfixOf’
180−-- Perhaps you meant one of these:
181−-- ‘T.isPrefixOf’ (imported from Data.Text),
182−-- ‘T.isInfixOf’ (imported from Data.Text),
183−-- ‘T.isSuffixOf’ (imported from Data.Text)
184−-- Module ‘Data.Text’ does not export ‘isPrfixOf’.
185− | renameSuggestions@(_:_) <- extractRenamableTerms _message
186− = [ ("Replace with ‘" <> name <> "’", [mkRenameEdit contents _range name]) | name <- renameSuggestions ]
187− | otherwise = []
188−
189−suggestNewDefinition :: IdeOptions -> ParsedModule -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
190−suggestNewDefinition ideOptions parsedModule contents Diagnostic{_message, _range}
191−-- * Variable not in scope:
192−-- suggestAcion :: Maybe T.Text -> Range -> Range
193− | Just [name, typ] <- matchRegex message "Variable not in scope: ([^ ]+) :: ([^*•]+)"
194− = newDefinitionAction ideOptions parsedModule _range name typ
195− | Just [name, typ] <- matchRegex message "Found hole: _([^ ]+) :: ([^*•]+) Or perhaps"
196− , [(label, newDefinitionEdits)] <- newDefinitionAction ideOptions parsedModule _range name typ
197− = [(label, mkRenameEdit contents _range name : newDefinitionEdits)]
198− | otherwise = []
199− where
200− message = unifySpaces _message
201−
202−newDefinitionAction :: IdeOptions -> ParsedModule -> Range -> T.Text -> T.Text -> [(T.Text, [TextEdit])]
203−newDefinitionAction IdeOptions{..} parsedModule Range{_start} name typ
204− | Range _ lastLineP : _ <-
205− [ srcSpanToRange l
206− | (L l _) <- hsmodDecls
207− , _start `isInsideSrcSpan` l]
208− , nextLineP <- Position{ _line = _line lastLineP + 1, _character = 0}
209− = [ ("Define " <> sig
210− , [TextEdit (Range nextLineP nextLineP) (T.unlines ["", sig, name <> " = error \"not implemented\""])]
211− )]
212− | otherwise = []
213− where
214− colon = if optNewColonConvention then " : " else " :: "
215− sig = name <> colon <> T.dropWhileEnd isSpace typ
216− ParsedModule{pm_parsed_source = L _ HsModule{hsmodDecls}} = parsedModule
217−
218−
219−suggestFillTypeWildcard :: Diagnostic -> [(T.Text, [TextEdit])]
220−suggestFillTypeWildcard Diagnostic{_range=_range,..}
221−-- Foo.hs:3:8: error:
222−-- * Found type wildcard `_' standing for `p -> p1 -> p'
223−
224− | "Found type wildcard" `T.isInfixOf` _message
225− , " standing for " `T.isInfixOf` _message
226− , typeSignature <- extractWildCardTypeSignature _message
227− = [("Use type signature: ‘" <> typeSignature <> "’", [TextEdit _range typeSignature])]
228− | otherwise = []
229−
230−suggestAddExtension :: Diagnostic -> [(T.Text, [TextEdit])]
231−suggestAddExtension Diagnostic{_range=_range,..}
232−-- File.hs:22:8: error:
233−-- Illegal lambda-case (use -XLambdaCase)
234−-- File.hs:22:6: error:
235−-- Illegal view pattern: x -> foo
236−-- Use ViewPatterns to enable view patterns
237−-- File.hs:26:8: error:
238−-- Illegal `..' in record pattern
239−-- Use RecordWildCards to permit this
240−-- File.hs:53:28: error:
241−-- Illegal tuple section: use TupleSections
242−-- File.hs:238:29: error:
243−-- * Can't make a derived instance of `Data FSATrace':
244−-- You need DeriveDataTypeable to derive an instance for this class
245−-- * In the data declaration for `FSATrace'
246−-- C:\Neil\shake\src\Development\Shake\Command.hs:515:31: error:
247−-- * Illegal equational constraint a ~ ()
248−-- (Use GADTs or TypeFamilies to permit this)
249−-- * In the context: a ~ ()
250−-- While checking an instance declaration
251−-- In the instance declaration for `Unit (m a)'
252− | exts@(_:_) <- filter (`Map.member` ghcExtensions) $ T.split (not . isAlpha) $ T.replace "-X" "" _message
253− = [("Add " <> x <> " extension", [TextEdit (Range (Position 0 0) (Position 0 0)) $ "{-# LANGUAGE " <> x <> " #-}\n"]) | x <- exts]
254− | otherwise = []
255−
256−-- | All the GHC extensions
257−ghcExtensions :: Map.HashMap T.Text Extension
258−ghcExtensions = Map.fromList . map ( ( T.pack . flagSpecName ) &&& flagSpecFlag ) $ xFlags
259−
260−suggestModuleTypo :: Diagnostic -> [(T.Text, [TextEdit])]
261−suggestModuleTypo Diagnostic{_range=_range,..}
262−-- src/Development/IDE/Core/Compile.hs:58:1: error:
263−-- Could not find module ‘Data.Cha’
264−-- Perhaps you meant Data.Char (from base-4.12.0.0)
265− | "Could not find module" `T.isInfixOf` _message
266− , "Perhaps you meant" `T.isInfixOf` _message = let
267− findSuggestedModules = map (head . T.words) . drop 2 . T.lines
268− proposeModule mod = ("replace with " <> mod, [TextEdit _range mod])
269− in map proposeModule $ nubOrd $ findSuggestedModules _message
270− | otherwise = []
271−
272−suggestFillHole :: Diagnostic -> [(T.Text, [TextEdit])]
273−suggestFillHole Diagnostic{_range=_range,..}
274−-- ...Development/IDE/LSP/CodeAction.hs:103:9: warning:
275−-- * Found hole: _ :: Int -> String
276−-- * In the expression: _
277−-- In the expression: _ a
278−-- In an equation for ‘foo’: foo a = _ a
279−-- * Relevant bindings include
280−-- a :: Int
281−-- (bound at ...Development/IDE/LSP/CodeAction.hs:103:5)
282−-- foo :: Int -> String
283−-- (bound at ...Development/IDE/LSP/CodeAction.hs:103:1)
284−-- Valid hole fits include
285−-- foo :: Int -> String
286−-- (bound at ...Development/IDE/LSP/CodeAction.hs:103:1)
287−-- show :: forall a. Show a => a -> String
288−-- with show @Int
289−-- (imported from ‘Prelude’ at ...Development/IDE/LSP/CodeAction.hs:7:8-37
290−-- (and originally defined in ‘GHC.Show’))
291−-- mempty :: forall a. Monoid a => a
292−-- with mempty @(Int -> String)
293−-- (imported from ‘Prelude’ at ...Development/IDE/LSP/CodeAction.hs:7:8-37
294−-- (and originally defined in ‘GHC.Base’)) (lsp-ui)
295−
296− | topOfHoleFitsMarker `T.isInfixOf` _message = let
297− findSuggestedHoleFits :: T.Text -> [T.Text]
298− findSuggestedHoleFits = extractFitNames . selectLinesWithFits . dropPreceding . T.lines
299− proposeHoleFit name = ("replace hole `" <> holeName <> "` with " <> name, [TextEdit _range name])
300− holeName = T.strip $ last $ T.splitOn ":" $ head . T.splitOn "::" $ head $ filter ("Found hole" `T.isInfixOf`) $ T.lines _message
301− dropPreceding = dropWhile (not . (topOfHoleFitsMarker `T.isInfixOf`))
302− selectLinesWithFits = filter ("::" `T.isInfixOf`)
303− extractFitNames = map (T.strip . head . T.splitOn " :: ")
304− in map proposeHoleFit $ nubOrd $ findSuggestedHoleFits _message
305−
306− | otherwise = []
307−
308−suggestExtendImport :: Maybe DynFlags -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
309−suggestExtendImport (Just dflags) contents Diagnostic{_range=_range,..}
310− | Just [binding, mod, srcspan] <-
311− matchRegex _message
312− "Perhaps you want to add ‘([^’]*)’ to the import list in the import of ‘([^’]*)’ *\\((.*)\\).$"
313− , Just c <- contents
314− , POk _ (L _ name) <- runParser dflags (T.unpack binding) parseIdentifier
315− = let range = case [ x | (x,"") <- readSrcSpan (T.unpack srcspan)] of
316− [s] -> let x = srcSpanToRange s
317− in x{_end = (_end x){_character = succ (_character (_end x))}}
318− _ -> error "bug in srcspan parser"
319− importLine = textInRange range c
320− in [("Add " <> binding <> " to the import list of " <> mod
321− , [TextEdit range (addBindingToImportList (T.pack $ printRdrName name) importLine)])]
322− | otherwise = []
323−suggestExtendImport Nothing _ _ = []
324−
325−suggestFixConstructorImport :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
326−suggestFixConstructorImport _ Diagnostic{_range=_range,..}
327− -- ‘Success’ is a data constructor of ‘Result’
328− -- To import it use
329− -- import Data.Aeson.Types( Result( Success ) )
330− -- or
331− -- import Data.Aeson.Types( Result(..) ) (lsp-ui)
332− | Just [constructor, typ] <-
333− matchRegex _message
334− "‘([^’]*)’ is a data constructor of ‘([^’]*)’ To import it use"
335− = let fixedImport = typ <> "(" <> constructor <> ")"
336− in [("Fix import of " <> fixedImport, [TextEdit _range fixedImport])]
337− | otherwise = []
338−
339−suggestSignature :: Bool -> Diagnostic -> [(T.Text, [TextEdit])]
340−suggestSignature isQuickFix Diagnostic{_range=_range@Range{..},..}
341− | _message =~
342− ("(Top-level binding|Polymorphic local binding|Pattern synonym) with no type signature" :: T.Text) = let
343− signature = removeInitialForAll
344− $ T.takeWhile (\x -> x/='*' && x/='•')
345− $ T.strip $ unifySpaces $ last $ T.splitOn "type signature: " $ filterNewlines _message
346− startOfLine = Position (_line _start) startCharacter
347− beforeLine = Range startOfLine startOfLine
348− title = if isQuickFix then "add signature: " <> signature else signature
349− action = TextEdit beforeLine $ signature <> "\n" <> T.replicate startCharacter " "
350− in [(title, [action])]
351− where removeInitialForAll :: T.Text -> T.Text
352− removeInitialForAll (T.breakOnEnd " :: " -> (nm, ty))
353− | "forall" `T.isPrefixOf` ty = nm <> T.drop 2 (snd (T.breakOn "." ty))
354− | otherwise = nm <> ty
355− startCharacter
356− | "Polymorphic local binding" `T.isPrefixOf` _message
357− = _character _start
358− | otherwise
359− = 0
360−
361−suggestSignature _ _ = []
362−
363−-------------------------------------------------------------------------------------------------
364−
365−suggestNewImport :: PackageExportsMap -> ParsedModule -> Diagnostic -> [(T.Text, [TextEdit])]
366−suggestNewImport packageExportsMap ParsedModule {pm_parsed_source = L _ HsModule {..}} Diagnostic{_message}
367− | msg <- unifySpaces _message
368− , Just name <- extractNotInScopeName msg
369− , Just insertLine <- case hsmodImports of
370− [] -> case srcSpanStart $ getLoc (head hsmodDecls) of
371− RealSrcLoc s -> Just $ srcLocLine s - 1
372− _ -> Nothing
373− _ -> case srcSpanEnd $ getLoc (last hsmodImports) of
374− RealSrcLoc s -> Just $ srcLocLine s
375− _ -> Nothing
376− , insertPos <- Position insertLine 0
377− , extendImportSuggestions <- matchRegex msg
378− "Perhaps you want to add ‘[^’]*’ to the import list in the import of ‘([^’]*)’"
379− = [(imp, [TextEdit (Range insertPos insertPos) (imp <> "\n")])
380− | imp <- constructNewImportSuggestions packageExportsMap name extendImportSuggestions
381− ]
382−suggestNewImport _ _ _ = []
383−
384−constructNewImportSuggestions
385− :: PackageExportsMap -> NotInScope -> Maybe [T.Text] -> [T.Text]
386−constructNewImportSuggestions exportsMap thingMissing notTheseModules = nubOrd
387− [ renderNewImport identInfo m
388− | (identInfo, m) <- fromMaybe [] $ Map.lookup name exportsMap
389− , canUseIdent thingMissing identInfo
390− , m `notElem` fromMaybe [] notTheseModules
391− ]
392− where
393− renderNewImport identInfo m
394− | Just q <- qual = "import qualified " <> m <> " as " <> q
395− | otherwise = "import " <> m <> " (" <> importWhat identInfo <> ")"
396−
397− (qual, name) = case T.splitOn "." (notInScope thingMissing) of
398− [n] -> (Nothing, n)
399− segments -> (Just (T.concat $ init segments), last segments)
400− importWhat IdentInfo {parent, rendered}
401− | Just p <- parent = p <> "(" <> rendered <> ")"
402− | otherwise = rendered
403−
404−canUseIdent :: NotInScope -> IdentInfo -> Bool
405−canUseIdent NotInScopeDataConstructor{} = isDatacon
406−canUseIdent _ = const True
407−
408−data NotInScope
409− = NotInScopeDataConstructor T.Text
410− | NotInScopeTypeConstructorOrClass T.Text
411− | NotInScopeThing T.Text
412− deriving Show
413−
414−notInScope :: NotInScope -> T.Text
415−notInScope (NotInScopeDataConstructor t) = t
416−notInScope (NotInScopeTypeConstructorOrClass t) = t
417−notInScope (NotInScopeThing t) = t
418−
419−extractNotInScopeName :: T.Text -> Maybe NotInScope
420−extractNotInScopeName x
421− | Just [name] <- matchRegex x "Data constructor not in scope: ([^ ]+)"
422− = Just $ NotInScopeDataConstructor name
423− | Just [name] <- matchRegex x "Not in scope: data constructor [^‘]*‘([^’]*)’"
424− = Just $ NotInScopeDataConstructor name
425− | Just [name] <- matchRegex x "ot in scope: type constructor or class [^‘]*‘([^’]*)’"
426− = Just $ NotInScopeTypeConstructorOrClass name
427− | Just [name] <- matchRegex x "ot in scope: \\(([^‘ ]+)\\)"
428− = Just $ NotInScopeThing name
429− | Just [name] <- matchRegex x "ot in scope: ([^‘ ]+)"
430− = Just $ NotInScopeThing name
431− | Just [name] <- matchRegex x "ot in scope:[^‘]*‘([^’]*)’"
432− = Just $ NotInScopeThing name
433− | otherwise
434− = Nothing
435−
436−-------------------------------------------------------------------------------------------------
437−
438−topOfHoleFitsMarker :: T.Text
439−topOfHoleFitsMarker =
440−#if MIN_GHC_API_VERSION(8,6,0)
441− "Valid hole fits include"
442−#else
443− "Valid substitutions include"
444−#endif
445−
446−mkRenameEdit :: Maybe T.Text -> Range -> T.Text -> TextEdit
447−mkRenameEdit contents range name =
448− if maybeIsInfixFunction == Just True
449− then TextEdit range ("`" <> name <> "`")
450− else TextEdit range name
451− where
452− maybeIsInfixFunction = do
453− curr <- textInRange range <$> contents
454− pure $ "`" `T.isPrefixOf` curr && "`" `T.isSuffixOf` curr
455−
456−extractWildCardTypeSignature :: T.Text -> T.Text
457−extractWildCardTypeSignature =
458− -- inferring when parens are actually needed around the type signature would
459− -- require understanding both the precedence of the context of the _ and of
460− -- the signature itself. Inserting them unconditionally is ugly but safe.
461− ("(" `T.append`) . (`T.append` ")") .
462− T.takeWhile (/='’') . T.dropWhile (=='‘') . T.dropWhile (/='‘') .
463− snd . T.breakOnEnd "standing for "
464−
465−extractRenamableTerms :: T.Text -> [T.Text]
466−extractRenamableTerms msg
467− -- Account for both "Variable not in scope" and "Not in scope"
468− | "ot in scope:" `T.isInfixOf` msg = extractSuggestions msg
469− | otherwise = []
470− where
471− extractSuggestions = map getEnclosed
472− . concatMap singleSuggestions
473− . filter isKnownSymbol
474− . T.lines
475− singleSuggestions = T.splitOn "), " -- Each suggestion is comma delimited
476− isKnownSymbol t = " (imported from" `T.isInfixOf` t || " (line " `T.isInfixOf` t
477− getEnclosed = T.dropWhile (== '‘')
478− . T.dropWhileEnd (== '’')
479− . T.dropAround (\c -> c /= '‘' && c /= '’')
480−
481−-- | If a range takes up a whole line (it begins at the start of the line and there's only whitespace
482−-- between the end of the range and the next newline), extend the range to take up the whole line.
483−extendToWholeLineIfPossible :: Maybe T.Text -> Range -> Range
484−extendToWholeLineIfPossible contents range@Range{..} =
485− let newlineAfter = maybe False (T.isPrefixOf "\n" . T.dropWhile (\x -> isSpace x && x /= '\n') . snd . splitTextAtPosition _end) contents
486− extend = newlineAfter && _character _start == 0 -- takes up an entire line, so remove the whole line
487− in if extend then Range _start (Position (_line _end + 1) 0) else range
488−
489−splitTextAtPosition :: Position -> T.Text -> (T.Text, T.Text)
490−splitTextAtPosition (Position row col) x
491− | (preRow, mid:postRow) <- splitAt row $ T.splitOn "\n" x
492− , (preCol, postCol) <- T.splitAt col mid
493− = (T.intercalate "\n" $ preRow ++ [preCol], T.intercalate "\n" $ postCol : postRow)
494− | otherwise = (x, T.empty)
495−
496−-- | Returns [start .. end[
497−textInRange :: Range -> T.Text -> T.Text
498−textInRange (Range (Position startRow startCol) (Position endRow endCol)) text =
499− case compare startRow endRow of
500− LT ->
501− let (linesInRangeBeforeEndLine, endLineAndFurtherLines) = splitAt (endRow - startRow) linesBeginningWithStartLine
502− (textInRangeInFirstLine, linesBetween) = case linesInRangeBeforeEndLine of
503− [] -> ("", [])
504− firstLine:linesInBetween -> (T.drop startCol firstLine, linesInBetween)
505− maybeTextInRangeInEndLine = T.take endCol <$> listToMaybe endLineAndFurtherLines
506− in T.intercalate "\n" (textInRangeInFirstLine : linesBetween ++ maybeToList maybeTextInRangeInEndLine)
507− EQ ->
508− let line = fromMaybe "" (listToMaybe linesBeginningWithStartLine)
509− in T.take (endCol - startCol) (T.drop startCol line)
510− GT -> ""
511− where
512− linesBeginningWithStartLine = drop startRow (T.splitOn "\n" text)
513−
514−-- | Returns the ranges for a binding in an import declaration
515−rangesForBinding :: ImportDecl GhcPs -> String -> [Range]
516−rangesForBinding ImportDecl{ideclHiding = Just (False, L _ lies)} b =
517− concatMap (map srcSpanToRange . rangesForBinding' b') lies
518− where
519− b' = wrapOperatorInParens (unqualify b)
520−
521− wrapOperatorInParens x = if isAlpha (head x) then x else "(" <> x <> ")"
522−
523− unqualify x = snd $ breakOnEnd "." x
524−
525−rangesForBinding _ _ = []
526−
527−rangesForBinding' :: String -> LIE GhcPs -> [SrcSpan]
528−rangesForBinding' b (L l x@IEVar{}) | showSDocUnsafe (ppr x) == b = [l]
529−rangesForBinding' b (L l x@IEThingAbs{}) | showSDocUnsafe (ppr x) == b = [l]
530−rangesForBinding' b (L l (IEThingAll x)) | showSDocUnsafe (ppr x) == b = [l]
531−rangesForBinding' b (L l (IEThingWith thing _ inners labels))
532− | showSDocUnsafe (ppr thing) == b = [l]
533− | otherwise =
534− [ l' | L l' x <- inners, showSDocUnsafe (ppr x) == b] ++
535− [ l' | L l' x <- labels, showSDocUnsafe (ppr x) == b]
536−rangesForBinding' _ _ = []
537−
538−-- | Extends an import list with a new binding.
539−-- Assumes an import statement of the form:
540−-- import (qualified) A (..) ..
541−-- Places the new binding first, preserving whitespace.
542−-- Copes with multi-line import lists
543−addBindingToImportList :: T.Text -> T.Text -> T.Text
544−addBindingToImportList binding importLine = case T.breakOn "(" importLine of
545− (pre, T.uncons -> Just (_, rest)) ->
546− case T.uncons (T.dropWhile isSpace rest) of
547− Just (')', _) -> T.concat [pre, "(", binding, rest]
548− _ -> T.concat [pre, "(", binding, ", ", rest]
549− _ ->
550− error
551− $ "importLine does not have the expected structure: "
552− <> T.unpack importLine
553−
554−-- | Returns Just (the submatches) for the first capture, or Nothing.
555−matchRegex :: T.Text -> T.Text -> Maybe [T.Text]
556−matchRegex message regex = case unifySpaces message =~~ regex of
557− Just (_ :: T.Text, _ :: T.Text, _ :: T.Text, bindings) -> Just bindings
558− Nothing -> Nothing
559−
560−setHandlersCodeLens :: PartialHandlers c
561−setHandlersCodeLens = PartialHandlers $ \WithMessage{..} x -> return x{
562− LSP.codeLensHandler = withResponse RspCodeLens codeLens,
563− LSP.executeCommandHandler = withResponseAndRequest RspExecuteCommand ReqApplyWorkspaceEdit executeAddSignatureCommand
564− }
565−
566−filterNewlines :: T.Text -> T.Text
567−filterNewlines = T.concat . T.lines
568−
569−unifySpaces :: T.Text -> T.Text
570−unifySpaces = T.unwords . T.words
src/Development/IDE/Plugin/CodeAction/PositionIndexed.hsdeleted−112
@@ -1,112 +0,0 @@
1−-- | Position indexed streams of characters
2−module Development.IDE.Plugin.CodeAction.PositionIndexed
3− ( PositionIndexed
4− , PositionIndexedString
5− , indexedByPosition
6− , indexedByPositionStartingFrom
7− , extendAllToIncludeCommaIfPossible
8− , mergeRanges
9− )
10−where
11−
12−import Data.Char
13−import Data.List
14−import Language.Haskell.LSP.Types
15−
16−type PositionIndexed a = [(Position, a)]
17−
18−type PositionIndexedString = PositionIndexed Char
19−
20−-- | Add position indexing to a String.
21−--
22−-- > indexedByPositionStartingFrom (0,0) "hey\n ho" ≡
23−-- > [ ((0,0),'h')
24−-- > , ((0,1),'e')
25−-- > , ((0,2),'y')
26−-- > , ((0,3),'\n')
27−-- > , ((1,0),' ')
28−-- > , ((1,1),'h')
29−-- > , ((1,2),'o')
30−-- > ]
31−indexedByPositionStartingFrom :: Position -> String -> PositionIndexedString
32−indexedByPositionStartingFrom initialPos = unfoldr f . (initialPos, ) where
33− f (_, []) = Nothing
34− f (p@(Position l _), '\n' : rest) =
35− Just ((p, '\n'), (Position (l + 1) 0, rest))
36− f (p@(Position l c), x : rest) = Just ((p, x), (Position l (c + 1), rest))
37−
38−-- | Add position indexing to a String.
39−--
40−-- > indexedByPosition = indexedByPositionStartingFrom (Position 0 0)
41−indexedByPosition :: String -> PositionIndexedString
42−indexedByPosition = indexedByPositionStartingFrom (Position 0 0)
43−
44−-- | Returns a tuple (before, contents, after) if the range is present.
45−-- The range is present only if both its start and end positions are present
46−unconsRange
47− :: Range
48− -> PositionIndexed a
49− -> Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
50−unconsRange Range {..} indexedString
51− | (before, rest@(_ : _)) <- span ((/= _start) . fst) indexedString
52− , (mid, after@(_ : _)) <- span ((/= _end) . fst) rest
53− = Just (before, mid, after)
54− | otherwise
55− = Nothing
56−
57−-- | Strips out all the positions included in the range.
58−-- Returns 'Nothing' if the start or end of the range are not included in the input.
59−stripRange :: Range -> PositionIndexed a -> Maybe (PositionIndexed a)
60−stripRange r s = case unconsRange r s of
61− Just (b, _, a) -> Just (b ++ a)
62− Nothing -> Nothing
63−
64−-- | Returns the smallest possible set of disjoint ranges that is equivalent to the input.
65−-- Assumes input ranges are sorted on the start positions.
66−mergeRanges :: [Range] -> [Range]
67−mergeRanges (r : r' : rest)
68− |
69− -- r' is contained in r
70− _end r > _end r' = mergeRanges (r : rest)
71− |
72− -- r and r' are overlapping
73− _end r > _start r' = mergeRanges (r { _end = _end r' } : rest)
74−
75− | otherwise = r : mergeRanges (r' : rest)
76−mergeRanges other = other
77−
78−-- | Returns a sorted list of ranges with extended selections including preceding or trailing commas
79−--
80−-- @
81−-- a, |b|, c ===> a|, b|, c
82−-- a, b, |c| ===> a, b|, c|
83−-- a, |b|, |c| ===> a|, b||, c|
84−-- @
85−extendAllToIncludeCommaIfPossible :: PositionIndexedString -> [Range] -> [Range]
86−extendAllToIncludeCommaIfPossible indexedString =
87− mergeRanges . go indexedString . sortOn _start
88− where
89− go _ [] = []
90− go input (r : rr)
91− | r' : _ <- extendToIncludeCommaIfPossible input r
92− , Just input' <- stripRange r' input
93− = r' : go input' rr
94− | otherwise
95− = go input rr
96−
97−extendToIncludeCommaIfPossible :: PositionIndexedString -> Range -> [Range]
98−extendToIncludeCommaIfPossible indexedString range
99− | Just (before, _, after) <- unconsRange range indexedString
100− , after' <- dropWhile (isSpace . snd) after
101− , before' <- dropWhile (isSpace . snd) (reverse before)
102− =
103− -- a, |b|, c ===> a|, b|, c
104− [ range { _start = start' } | (start', ',') : _ <- [before'] ]
105− ++
106− -- a, |b|, c ===> a, |b, |c
107− [ range { _end = end' }
108− | (_, ',') : rest <- [after']
109− , let (end', _) : _ = dropWhile (isSpace . snd) rest
110− ]
111− | otherwise
112− = [range]
src/Development/IDE/Plugin/CodeAction/RuleTypes.hsdeleted−61
@@ -1,61 +0,0 @@
1−{-# LANGUAGE TypeFamilies #-}
2−module Development.IDE.Plugin.CodeAction.RuleTypes
3− (PackageExports(..), PackageExportsMap
4− ,IdentInfo(..)
5− ,mkIdentInfos
6− ) where
7−
8−import Avail (AvailInfo(..))
9−import Data.Hashable (Hashable)
10−import Control.DeepSeq (NFData)
11−import Data.Binary (Binary)
12−import Data.Text (pack, Text)
13−import Development.IDE.GHC.Util
14−import Development.Shake (RuleResult)
15−import Data.HashMap.Strict (HashMap)
16−import Data.Typeable (Typeable)
17−import GHC.Generics (Generic)
18−import Name
19−import FieldLabel (flSelector)
20−
21−type Identifier = Text
22−type ModuleName = Text
23−
24−data IdentInfo = IdentInfo
25− { name :: !Identifier
26− , rendered :: Text
27− , parent :: !(Maybe Text)
28− , isDatacon :: !Bool
29− }
30− deriving (Eq, Generic, Show)
31−
32−instance NFData IdentInfo
33−
34−mkIdentInfos :: AvailInfo -> [IdentInfo]
35−mkIdentInfos (Avail n) =
36− [IdentInfo (pack (prettyPrint n)) (pack (printName n)) Nothing (isDataConName n)]
37−mkIdentInfos (AvailTC parent (n:nn) flds)
38− -- Following the GHC convention that parent == n if parent is exported
39− | n == parent
40− = [ IdentInfo (pack (prettyPrint n)) (pack (printName n)) (Just $! parentP) True
41− | n <- nn ++ map flSelector flds
42− ] ++
43− [ IdentInfo (pack (prettyPrint n)) (pack (printName n)) Nothing False]
44− where
45− parentP = pack $ prettyPrint parent
46−
47−mkIdentInfos (AvailTC _ nn flds)
48− = [ IdentInfo (pack (prettyPrint n)) (pack (printName n)) Nothing True
49− | n <- nn ++ map flSelector flds
50− ]
51−
52−-- Rule type for caching Package Exports
53−type instance RuleResult PackageExports = PackageExportsMap
54−type PackageExportsMap = HashMap Identifier [(IdentInfo,ModuleName)]
55−
56−newtype PackageExports = PackageExports HscEnvEq
57− deriving (Eq, Show, Typeable, Generic)
58−
59−instance Hashable PackageExports
60−instance NFData PackageExports
61−instance Binary PackageExports
src/Development/IDE/Plugin/CodeAction/Rules.hsdeleted−61
@@ -1,61 +0,0 @@
1−module Development.IDE.Plugin.CodeAction.Rules
2− ( rulePackageExports
3− )
4−where
5−
6−import Data.HashMap.Strict ( fromListWith )
7−import Data.Text ( Text
8− , pack
9− )
10−import Data.Traversable ( forM )
11−import Development.IDE.Core.Rules
12−import Development.IDE.GHC.Util
13−import Development.IDE.Plugin.CodeAction.RuleTypes
14−import Development.Shake
15−import GHC ( DynFlags(pkgState) )
16−import HscTypes ( IfaceExport
17− , hsc_dflags
18− , mi_exports
19− )
20−import LoadIface
21−import Maybes
22−import Module ( Module(..)
23− , ModuleName
24− , moduleNameString
25− )
26−import Packages ( explicitPackages
27− , exposedModules
28− , packageConfigId
29− )
30−import TcRnMonad ( WhereFrom(ImportByUser)
31− , initIfaceLoad
32− )
33−
34−rulePackageExports :: Rules ()
35−rulePackageExports = defineNoFile $ \(PackageExports session) -> do
36− let env = hscEnv session
37− pkgst = pkgState (hsc_dflags env)
38− depends = explicitPackages pkgst
39− targets =
40− [ (pkg, mn)
41− | d <- depends
42− , Just pkg <- [lookupPackageConfig d env]
43− , (mn, _) <- exposedModules pkg
44− ]
45−
46− results <- forM targets $ \(pkg, mn) -> do
47− modIface <- liftIO $ initIfaceLoad env $ loadInterface
48− ""
49− (Module (packageConfigId pkg) mn)
50− (ImportByUser False)
51− case modIface of
52− Failed _err -> return mempty
53− Succeeded mi -> do
54− let avails = mi_exports mi
55− return $ concatMap (unpackAvail mn) avails
56− return $ fromListWith (++) $ concat results
57−
58−unpackAvail :: ModuleName -> IfaceExport -> [(Text, [(IdentInfo, Text)])]
59−unpackAvail mod =
60− map (\id@IdentInfo {..} -> (name, [(id, pack $ moduleNameString mod)]))
61− . mkIdentInfos
src/Development/IDE/Plugin/Completions.hsdeleted−103
@@ -1,103 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE TypeFamilies #-}
3−#include "ghc-api-version.h"
4−
5−module Development.IDE.Plugin.Completions(plugin) where
6−
7−import Control.Applicative
8−import Language.Haskell.LSP.Messages
9−import Language.Haskell.LSP.Types
10−import qualified Language.Haskell.LSP.Core as LSP
11−import qualified Language.Haskell.LSP.VFS as VFS
12−import Language.Haskell.LSP.Types.Capabilities
13−import Development.Shake.Classes
14−import Development.Shake
15−import GHC.Generics
16−
17−import Development.IDE.Plugin
18−import Development.IDE.Core.Service
19−import Development.IDE.Plugin.Completions.Logic
20−import Development.IDE.Types.Location
21−import Development.IDE.Core.PositionMapping
22−import Development.IDE.Core.RuleTypes
23−import Development.IDE.Core.Shake
24−import Development.IDE.GHC.Util
25−import Development.IDE.LSP.Server
26−
27−#if !MIN_GHC_API_VERSION(8,6,0) || defined(GHC_LIB)
28−import Data.Maybe
29−import Development.IDE.Import.DependencyInformation
30−#endif
31−
32−plugin :: Plugin c
33−plugin = Plugin produceCompletions setHandlersCompletion
34−
35−produceCompletions :: Rules ()
36−produceCompletions =
37− define $ \ProduceCompletions file -> do
38−
39−-- When possible, rely on the haddocks embedded in our interface files
40−-- This creates problems on ghc-lib, see comment on 'getDocumentationTryGhc'
41−#if MIN_GHC_API_VERSION(8,6,0) && !defined(GHC_LIB)
42− let parsedDeps = []
43−#else
44− deps <- maybe (TransitiveDependencies [] [] []) fst <$> useWithStale GetDependencies file
45− parsedDeps <- mapMaybe (fmap fst) <$> usesWithStale GetParsedModule (transitiveModuleDeps deps)
46−#endif
47− tm <- fmap fst <$> useWithStale TypeCheck file
48− packageState <- fmap (hscEnv . fst) <$> useWithStale GhcSession file
49− case (tm, packageState) of
50− (Just tm', Just packageState') -> do
51− cdata <- liftIO $ cacheDataProducer packageState'
52− (tmrModule tm') parsedDeps
53− return ([], Just cdata)
54− _ -> return ([], Nothing)
55−
56−
57−-- | Produce completions info for a file
58−type instance RuleResult ProduceCompletions = CachedCompletions
59−
60−data ProduceCompletions = ProduceCompletions
61− deriving (Eq, Show, Typeable, Generic)
62−instance Hashable ProduceCompletions
63−instance NFData ProduceCompletions
64−instance Binary ProduceCompletions
65−
66−
67−-- | Generate code actions.
68−getCompletionsLSP
69− :: LSP.LspFuncs c
70− -> IdeState
71− -> CompletionParams
72− -> IO (Either ResponseError CompletionResponseResult)
73−getCompletionsLSP lsp ide
74− CompletionParams{_textDocument=TextDocumentIdentifier uri
75− ,_position=position
76− ,_context=completionContext} = do
77− contents <- LSP.getVirtualFileFunc lsp $ toNormalizedUri uri
78− fmap Right $ case (contents, uriToFilePath' uri) of
79− (Just cnts, Just path) -> do
80− let npath = toNormalizedFilePath' path
81− (ideOpts, compls) <- runAction ide $ do
82− opts <- getIdeOptions
83− compls <- useWithStale ProduceCompletions npath
84− pm <- useWithStale GetParsedModule npath
85− pure (opts, liftA2 (,) compls pm)
86− case compls of
87− Just ((cci', _), (pm, mapping)) -> do
88− let !position' = fromCurrentPosition mapping position
89− pfix <- maybe (return Nothing) (flip VFS.getCompletionPrefix cnts) position'
90− case (pfix, completionContext) of
91− (Just (VFS.PosPrefixInfo _ "" _ _), Just CompletionContext { _triggerCharacter = Just "."})
92− -> return (Completions $ List [])
93− (Just pfix', _) -> do
94− let fakeClientCapabilities = ClientCapabilities Nothing Nothing Nothing Nothing
95− Completions . List <$> getCompletions ideOpts cci' pm pfix' fakeClientCapabilities (WithSnippets True)
96− _ -> return (Completions $ List [])
97− _ -> return (Completions $ List [])
98− _ -> return (Completions $ List [])
99−
100−setHandlersCompletion :: PartialHandlers c
101−setHandlersCompletion = PartialHandlers $ \WithMessage{..} x -> return x{
102− LSP.completionHandler = withResponse RspCompletion getCompletionsLSP
103− }
src/Development/IDE/Plugin/Completions/Logic.hsdeleted−530
@@ -1,530 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−#include "ghc-api-version.h"
3−-- Mostly taken from "haskell-ide-engine"
4−module Development.IDE.Plugin.Completions.Logic (
5− CachedCompletions
6−, cacheDataProducer
7−, WithSnippets(..)
8−,getCompletions
9−) where
10−
11−import Control.Applicative
12−import Data.Char (isSpace, isUpper)
13−import Data.Generics
14−import Data.List.Extra as List hiding (stripPrefix)
15−import qualified Data.Map as Map
16−import Data.Maybe (fromMaybe, mapMaybe)
17−import qualified Data.Text as T
18−import qualified Text.Fuzzy as Fuzzy
19−
20−import GHC
21−import HscTypes
22−import Name
23−import RdrName
24−import TcRnTypes
25−import Type
26−import Var
27−import Packages
28−import DynFlags
29−#if MIN_GHC_API_VERSION(8,10,0)
30−import Predicate (isDictTy)
31−import GHC.Platform
32−import Pair
33−import Coercion
34−#endif
35−
36−import Language.Haskell.LSP.Types
37−import Language.Haskell.LSP.Types.Capabilities
38−import qualified Language.Haskell.LSP.VFS as VFS
39−import Development.IDE.Plugin.Completions.Types
40−import Development.IDE.Spans.Documentation
41−import Development.IDE.GHC.Error
42−import Development.IDE.Types.Options
43−import Development.IDE.Spans.Common
44−import Development.IDE.GHC.Util
45−
46−-- From haskell-ide-engine/hie-plugin-api/Haskell/Ide/Engine/Context.hs
47−
48−-- | A context of a declaration in the program
49−-- e.g. is the declaration a type declaration or a value declaration
50−-- Used for determining which code completions to show
51−-- TODO: expand this with more contexts like classes or instances for
52−-- smarter code completion
53−data Context = TypeContext
54− | ValueContext
55− | ModuleContext String -- ^ module context with module name
56− | ImportContext String -- ^ import context with module name
57− | ImportListContext String -- ^ import list context with module name
58− | ImportHidingContext String -- ^ import hiding context with module name
59− | ExportContext -- ^ List of exported identifiers from the current module
60− deriving (Show, Eq)
61−
62−-- | Generates a map of where the context is a type and where the context is a value
63−-- i.e. where are the value decls and the type decls
64−getCContext :: Position -> ParsedModule -> Maybe Context
65−getCContext pos pm
66− | Just (L r modName) <- moduleHeader
67− , pos `isInsideSrcSpan` r
68− = Just (ModuleContext (moduleNameString modName))
69−
70− | Just (L r _) <- exportList
71− , pos `isInsideSrcSpan` r
72− = Just ExportContext
73−
74− | Just ctx <- something (Nothing `mkQ` go `extQ` goInline) decl
75− = Just ctx
76−
77− | Just ctx <- something (Nothing `mkQ` importGo) imports
78− = Just ctx
79−
80− | otherwise
81− = Nothing
82−
83− where decl = hsmodDecls $ unLoc $ pm_parsed_source pm
84− moduleHeader = hsmodName $ unLoc $ pm_parsed_source pm
85− exportList = hsmodExports $ unLoc $ pm_parsed_source pm
86− imports = hsmodImports $ unLoc $ pm_parsed_source pm
87−
88− go :: LHsDecl GhcPs -> Maybe Context
89− go (L r SigD {})
90− | pos `isInsideSrcSpan` r = Just TypeContext
91− | otherwise = Nothing
92− go (L r GHC.ValD {})
93− | pos `isInsideSrcSpan` r = Just ValueContext
94− | otherwise = Nothing
95− go _ = Nothing
96−
97− goInline :: GHC.LHsType GhcPs -> Maybe Context
98− goInline (GHC.L r _)
99− | pos `isInsideSrcSpan` r = Just TypeContext
100− goInline _ = Nothing
101−
102− importGo :: GHC.LImportDecl GhcPs -> Maybe Context
103− importGo (L r impDecl)
104− | pos `isInsideSrcSpan` r
105− = importInline importModuleName (ideclHiding impDecl)
106− <|> Just (ImportContext importModuleName)
107−
108− | otherwise = Nothing
109− where importModuleName = moduleNameString $ unLoc $ ideclName impDecl
110−
111− importInline :: String -> Maybe (Bool, GHC.Located [LIE GhcPs]) -> Maybe Context
112− importInline modName (Just (True, L r _))
113− | pos `isInsideSrcSpan` r = Just $ ImportHidingContext modName
114− | otherwise = Nothing
115− importInline modName (Just (False, L r _))
116− | pos `isInsideSrcSpan` r = Just $ ImportListContext modName
117− | otherwise = Nothing
118− importInline _ _ = Nothing
119−
120−occNameToComKind :: Maybe T.Text -> OccName -> CompletionItemKind
121−occNameToComKind ty oc
122− | isVarOcc oc = case occNameString oc of
123− i:_ | isUpper i -> CiConstructor
124− _ -> CiFunction
125− | isTcOcc oc = case ty of
126− Just t
127− | "Constraint" `T.isSuffixOf` t
128− -> CiClass
129− _ -> CiStruct
130− | isDataOcc oc = CiConstructor
131− | otherwise = CiVariable
132−
133−mkCompl :: IdeOptions -> CompItem -> CompletionItem
134−mkCompl IdeOptions{..} CI{origName,importedFrom,thingType,label,isInfix,docs} =
135− CompletionItem label kind (List []) ((colon <>) <$> typeText)
136− (Just $ CompletionDocMarkup $ MarkupContent MkMarkdown $ T.intercalate sectionSeparator docs')
137− Nothing Nothing Nothing Nothing (Just insertText) (Just Snippet)
138− Nothing Nothing Nothing Nothing Nothing
139− where kind = Just $ occNameToComKind typeText $ occName origName
140− insertText = case isInfix of
141− Nothing -> case getArgText <$> thingType of
142− Nothing -> label
143− Just argText -> label <> " " <> argText
144− Just LeftSide -> label <> "`"
145−
146− Just Surrounded -> label
147− typeText
148− | Just t <- thingType = Just . stripForall $ T.pack (showGhc t)
149− | otherwise = Nothing
150− docs' = ("*Defined in '" <> importedFrom <> "'*\n") : spanDocToMarkdown docs
151− colon = if optNewColonConvention then ": " else ":: "
152−
153−stripForall :: T.Text -> T.Text
154−stripForall t
155− | T.isPrefixOf "forall" t =
156− -- We drop 2 to remove the '.' and the space after it
157− T.drop 2 (T.dropWhile (/= '.') t)
158− | otherwise = t
159−
160−getArgText :: Type -> T.Text
161−getArgText typ = argText
162− where
163− argTypes = getArgs typ
164− argText :: T.Text
165− argText = mconcat $ List.intersperse " " $ zipWithFrom snippet 1 argTypes
166− snippet :: Int -> Type -> T.Text
167− snippet i t = T.pack $ "${" <> show i <> ":" <> showGhc t <> "}"
168− getArgs :: Type -> [Type]
169− getArgs t
170− | isPredTy t = []
171− | isDictTy t = []
172− | isForAllTy t = getArgs $ snd (splitForAllTys t)
173− | isFunTy t =
174− let (args, ret) = splitFunTys t
175− in if isForAllTy ret
176− then getArgs ret
177− else Prelude.filter (not . isDictTy) args
178− | isPiTy t = getArgs $ snd (splitPiTys t)
179−#if MIN_GHC_API_VERSION(8,10,0)
180− | Just (Pair _ t) <- coercionKind <$> isCoercionTy_maybe t
181− = getArgs t
182−#else
183− | isCoercionTy t = maybe [] (getArgs . snd) (splitCoercionType_maybe t)
184−#endif
185− | otherwise = []
186−
187−mkModCompl :: T.Text -> CompletionItem
188−mkModCompl label =
189− CompletionItem label (Just CiModule) (List []) Nothing
190− Nothing Nothing Nothing Nothing Nothing Nothing Nothing
191− Nothing Nothing Nothing Nothing Nothing
192−
193−mkImportCompl :: T.Text -> T.Text -> CompletionItem
194−mkImportCompl enteredQual label =
195− CompletionItem m (Just CiModule) (List []) (Just label)
196− Nothing Nothing Nothing Nothing Nothing Nothing Nothing
197− Nothing Nothing Nothing Nothing Nothing
198− where
199− m = fromMaybe "" (T.stripPrefix enteredQual label)
200−
201−mkExtCompl :: T.Text -> CompletionItem
202−mkExtCompl label =
203− CompletionItem label (Just CiKeyword) (List []) Nothing
204− Nothing Nothing Nothing Nothing Nothing Nothing Nothing
205− Nothing Nothing Nothing Nothing Nothing
206−
207−mkPragmaCompl :: T.Text -> T.Text -> CompletionItem
208−mkPragmaCompl label insertText =
209− CompletionItem label (Just CiKeyword) (List []) Nothing
210− Nothing Nothing Nothing Nothing Nothing (Just insertText) (Just Snippet)
211− Nothing Nothing Nothing Nothing Nothing
212−
213−cacheDataProducer :: HscEnv -> TypecheckedModule -> [ParsedModule] -> IO CachedCompletions
214−cacheDataProducer packageState tm deps = do
215− let parsedMod = tm_parsed_module tm
216− dflags = hsc_dflags packageState
217− curMod = moduleName $ ms_mod $ pm_mod_summary parsedMod
218− Just (_,limports,_,_) = tm_renamed_source tm
219−
220− iDeclToModName :: ImportDecl name -> ModuleName
221− iDeclToModName = unLoc . ideclName
222−
223− showModName :: ModuleName -> T.Text
224− showModName = T.pack . moduleNameString
225−
226− asNamespace :: ImportDecl name -> ModuleName
227− asNamespace imp = maybe (iDeclToModName imp) GHC.unLoc (ideclAs imp)
228− -- Full canonical names of imported modules
229− importDeclerations = map unLoc limports
230−
231− -- The list of all importable Modules from all packages
232− moduleNames = map showModName (listVisibleModuleNames dflags)
233−
234− -- The given namespaces for the imported modules (ie. full name, or alias if used)
235− allModNamesAsNS = map (showModName . asNamespace) importDeclerations
236−
237− typeEnv = tcg_type_env $ fst $ tm_internals_ tm
238− rdrEnv = tcg_rdr_env $ fst $ tm_internals_ tm
239− rdrElts = globalRdrEnvElts rdrEnv
240−
241− foldMapM :: (Foldable f, Monad m, Monoid b) => (a -> m b) -> f a -> m b
242− foldMapM f xs = foldr step return xs mempty where
243− step x r z = f x >>= \y -> r $! z `mappend` y
244−
245− getCompls :: [GlobalRdrElt] -> IO ([CompItem],QualCompls)
246− getCompls = foldMapM getComplsForOne
247−
248− getComplsForOne :: GlobalRdrElt -> IO ([CompItem],QualCompls)
249− getComplsForOne (GRE n _ True _) =
250− case lookupTypeEnv typeEnv n of
251− Just tt -> case safeTyThingId tt of
252− Just var -> (\x -> ([x],mempty)) <$> varToCompl var
253− Nothing -> (\x -> ([x],mempty)) <$> toCompItem curMod n
254− Nothing -> (\x -> ([x],mempty)) <$> toCompItem curMod n
255− getComplsForOne (GRE n _ False prov) =
256− flip foldMapM (map is_decl prov) $ \spec -> do
257− compItem <- toCompItem (is_mod spec) n
258− let unqual
259− | is_qual spec = []
260− | otherwise = [compItem]
261− qual
262− | is_qual spec = Map.singleton asMod [compItem]
263− | otherwise = Map.fromList [(asMod,[compItem]),(origMod,[compItem])]
264− asMod = showModName (is_as spec)
265− origMod = showModName (is_mod spec)
266− return (unqual,QualCompls qual)
267−
268− varToCompl :: Var -> IO CompItem
269− varToCompl var = do
270− let typ = Just $ varType var
271− name = Var.varName var
272− label = T.pack $ showGhc name
273− docs <- evalGhcEnv packageState $ getDocumentationTryGhc (tm_parsed_module tm : deps) name
274− return $ CI name (showModName curMod) typ label Nothing docs
275−
276− toCompItem :: ModuleName -> Name -> IO CompItem
277− toCompItem mn n = do
278− docs <- evalGhcEnv packageState $ getDocumentationTryGhc (tm_parsed_module tm : deps) n
279−-- lookupName uses runInteractiveHsc, i.e., GHCi stuff which does not work with GHCi
280−-- and leads to fun errors like "Cannot continue after interface file error".
281−#ifdef GHC_LIB
282− let ty = Right Nothing
283−#else
284− ty <- evalGhcEnv packageState $ catchSrcErrors "completion" $ do
285− name' <- lookupName n
286− return $ name' >>= safeTyThingType
287−#endif
288− return $ CI n (showModName mn) (either (const Nothing) id ty) (T.pack $ showGhc n) Nothing docs
289−
290− (unquals,quals) <- getCompls rdrElts
291−
292− return $ CC
293− { allModNamesAsNS = allModNamesAsNS
294− , unqualCompls = unquals
295− , qualCompls = quals
296− , importableModules = moduleNames
297− }
298−
299−newtype WithSnippets = WithSnippets Bool
300−
301−toggleSnippets :: ClientCapabilities -> WithSnippets -> CompletionItem -> CompletionItem
302−toggleSnippets ClientCapabilities { _textDocument } (WithSnippets with) x
303− | with && supported = x
304− | otherwise = x { _insertTextFormat = Just PlainText
305− , _insertText = Nothing
306− }
307− where supported = Just True == (_textDocument >>= _completion >>= _completionItem >>= _snippetSupport)
308−
309−-- | Returns the cached completions for the given module and position.
310−getCompletions :: IdeOptions -> CachedCompletions -> ParsedModule -> VFS.PosPrefixInfo -> ClientCapabilities -> WithSnippets -> IO [CompletionItem]
311−getCompletions ideOpts CC { allModNamesAsNS, unqualCompls, qualCompls, importableModules }
312− pm prefixInfo caps withSnippets = do
313− let VFS.PosPrefixInfo { VFS.fullLine, VFS.prefixModule, VFS.prefixText } = prefixInfo
314− enteredQual = if T.null prefixModule then "" else prefixModule <> "."
315− fullPrefix = enteredQual <> prefixText
316−
317− {- correct the position by moving 'foo :: Int -> String -> '
318− ^
319− to 'foo :: Int -> String -> '
320− ^
321− -}
322− pos =
323− let Position l c = VFS.cursorPos prefixInfo
324− typeStuff = [isSpace, (`elem` (">-." :: String))]
325− stripTypeStuff = T.dropWhileEnd (\x -> any (\f -> f x) typeStuff)
326− -- if oldPos points to
327− -- foo -> bar -> baz
328− -- ^
329− -- Then only take the line up to there, discard '-> bar -> baz'
330− partialLine = T.take c fullLine
331− -- drop characters used when writing incomplete type sigs
332− -- like '-> '
333− d = T.length fullLine - T.length (stripTypeStuff partialLine)
334− in Position l (c - d)
335−
336− filtModNameCompls =
337− map mkModCompl
338− $ mapMaybe (T.stripPrefix enteredQual)
339− $ Fuzzy.simpleFilter fullPrefix allModNamesAsNS
340−
341− filtCompls = map Fuzzy.original $ Fuzzy.filter prefixText ctxCompls "" "" label False
342− where
343− isTypeCompl = isTcOcc . occName . origName
344− -- completions specific to the current context
345− ctxCompls' = case getCContext pos pm of
346− Nothing -> compls
347− Just TypeContext -> filter isTypeCompl compls
348− Just ValueContext -> filter (not . isTypeCompl) compls
349− Just _ -> filter (not . isTypeCompl) compls
350− -- Add whether the text to insert has backticks
351− ctxCompls = map (\comp -> comp { isInfix = infixCompls }) ctxCompls'
352−
353− infixCompls :: Maybe Backtick
354− infixCompls = isUsedAsInfix fullLine prefixModule prefixText (VFS.cursorPos prefixInfo)
355−
356− compls = if T.null prefixModule
357− then unqualCompls
358− else Map.findWithDefault [] prefixModule $ getQualCompls qualCompls
359−
360− filtListWith f list =
361− [ f label
362− | label <- Fuzzy.simpleFilter fullPrefix list
363− , enteredQual `T.isPrefixOf` label
364− ]
365−
366− filtListWithSnippet f list suffix =
367− [ toggleSnippets caps withSnippets (f label (snippet <> suffix))
368− | (snippet, label) <- list
369− , Fuzzy.test fullPrefix label
370− ]
371−
372− filtImportCompls = filtListWith (mkImportCompl enteredQual) importableModules
373− filtPragmaCompls = filtListWithSnippet mkPragmaCompl validPragmas
374− filtOptsCompls = filtListWith mkExtCompl
375− filtKeywordCompls
376− | T.null prefixModule = filtListWith mkExtCompl (optKeywords ideOpts)
377− | otherwise = []
378−
379− stripLeading :: Char -> String -> String
380− stripLeading _ [] = []
381− stripLeading c (s:ss)
382− | s == c = ss
383− | otherwise = s:ss
384−
385− result
386− | "import " `T.isPrefixOf` fullLine
387− = filtImportCompls
388− | "{-# language" `T.isPrefixOf` T.toLower fullLine
389− = filtOptsCompls languagesAndExts
390− | "{-# options_ghc" `T.isPrefixOf` T.toLower fullLine
391− = filtOptsCompls (map (T.pack . stripLeading '-') $ flagsForCompletion False)
392− | "{-# " `T.isPrefixOf` fullLine
393− = filtPragmaCompls (pragmaSuffix fullLine)
394− | otherwise
395− = filtModNameCompls ++ map (toggleSnippets caps withSnippets
396− . mkCompl ideOpts . stripAutoGenerated) filtCompls
397− ++ filtKeywordCompls
398−
399− return result
400−
401−-- The supported languages and extensions
402−languagesAndExts :: [T.Text]
403−#if MIN_GHC_API_VERSION(8,10,0)
404−languagesAndExts = map T.pack $ DynFlags.supportedLanguagesAndExtensions ( PlatformMini ArchUnknown OSUnknown )
405−#else
406−languagesAndExts = map T.pack DynFlags.supportedLanguagesAndExtensions
407−#endif
408−
409−-- ---------------------------------------------------------------------
410−-- helper functions for pragmas
411−-- ---------------------------------------------------------------------
412−
413−validPragmas :: [(T.Text, T.Text)]
414−validPragmas =
415− [ ("LANGUAGE ${1:extension}" , "LANGUAGE")
416− , ("OPTIONS_GHC -${1:option}" , "OPTIONS_GHC")
417− , ("INLINE ${1:function}" , "INLINE")
418− , ("NOINLINE ${1:function}" , "NOINLINE")
419− , ("INLINABLE ${1:function}" , "INLINABLE")
420− , ("WARNING ${1:message}" , "WARNING")
421− , ("DEPRECATED ${1:message}" , "DEPRECATED")
422− , ("ANN ${1:annotation}" , "ANN")
423− , ("RULES" , "RULES")
424− , ("SPECIALIZE ${1:function}" , "SPECIALIZE")
425− , ("SPECIALIZE INLINE ${1:function}", "SPECIALIZE INLINE")
426− ]
427−
428−pragmaSuffix :: T.Text -> T.Text
429−pragmaSuffix fullLine
430− | "}" `T.isSuffixOf` fullLine = mempty
431− | otherwise = " #-}"
432−
433−-- ---------------------------------------------------------------------
434−-- helper functions for infix backticks
435−-- ---------------------------------------------------------------------
436−
437−hasTrailingBacktick :: T.Text -> Position -> Bool
438−hasTrailingBacktick line Position { _character }
439− | T.length line > _character = (line `T.index` _character) == '`'
440− | otherwise = False
441−
442−isUsedAsInfix :: T.Text -> T.Text -> T.Text -> Position -> Maybe Backtick
443−isUsedAsInfix line prefixMod prefixText pos
444− | hasClosingBacktick && hasOpeningBacktick = Just Surrounded
445− | hasOpeningBacktick = Just LeftSide
446− | otherwise = Nothing
447− where
448− hasOpeningBacktick = openingBacktick line prefixMod prefixText pos
449− hasClosingBacktick = hasTrailingBacktick line pos
450−
451−openingBacktick :: T.Text -> T.Text -> T.Text -> Position -> Bool
452−openingBacktick line prefixModule prefixText Position { _character }
453− | backtickIndex < 0 = False
454− | otherwise = (line `T.index` backtickIndex) == '`'
455− where
456− backtickIndex :: Int
457− backtickIndex =
458− let
459− prefixLength = T.length prefixText
460− moduleLength = if prefixModule == ""
461− then 0
462− else T.length prefixModule + 1 {- Because of "." -}
463− in
464− -- Points to the first letter of either the module or prefix text
465− _character - (prefixLength + moduleLength) - 1
466−
467−
468−-- ---------------------------------------------------------------------
469−
470−-- | Under certain circumstance GHC generates some extra stuff that we
471−-- don't want in the autocompleted symbols
472−stripAutoGenerated :: CompItem -> CompItem
473−stripAutoGenerated ci =
474− ci {label = stripPrefix (label ci)}
475− {- When e.g. DuplicateRecordFields is enabled, compiler generates
476− names like "$sel:accessor:One" and "$sel:accessor:Two" to disambiguate record selectors
477− https://ghc.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields/DuplicateRecordFields#Implementation
478− -}
479−
480−-- TODO: Turn this into an alex lexer that discards prefixes as if they were whitespace.
481−
482−stripPrefix :: T.Text -> T.Text
483−stripPrefix name = T.takeWhile (/=':') $ go prefixes
484− where
485− go [] = name
486− go (p:ps)
487− | T.isPrefixOf p name = T.drop (T.length p) name
488− | otherwise = go ps
489−
490−-- | Prefixes that can occur in a GHC OccName
491−prefixes :: [T.Text]
492−prefixes =
493− [
494− -- long ones
495− "$con2tag_"
496− , "$tag2con_"
497− , "$maxtag_"
498−
499− -- four chars
500− , "$sel:"
501− , "$tc'"
502−
503− -- three chars
504− , "$dm"
505− , "$co"
506− , "$tc"
507− , "$cp"
508− , "$fx"
509−
510− -- two chars
511− , "$W"
512− , "$w"
513− , "$m"
514− , "$b"
515− , "$c"
516− , "$d"
517− , "$i"
518− , "$s"
519− , "$f"
520− , "$r"
521− , "C:"
522− , "N:"
523− , "D:"
524− , "$p"
525− , "$L"
526− , "$f"
527− , "$t"
528− , "$c"
529− , "$m"
530− ]
src/Development/IDE/Plugin/Completions/Types.hsdeleted−58
@@ -1,58 +0,0 @@
1−module Development.IDE.Plugin.Completions.Types (
2− module Development.IDE.Plugin.Completions.Types
3−) where
4−
5−import Control.DeepSeq
6−import qualified Data.Map as Map
7−import qualified Data.Text as T
8−import GHC
9−
10−import Development.IDE.Spans.Common
11−
12−-- From haskell-ide-engine/src/Haskell/Ide/Engine/LSP/Completions.hs
13−
14−data Backtick = Surrounded | LeftSide deriving Show
15−data CompItem = CI
16− { origName :: Name -- ^ Original name, such as Maybe, //, or find.
17− , importedFrom :: T.Text -- ^ From where this item is imported from.
18− , thingType :: Maybe Type -- ^ Available type information.
19− , label :: T.Text -- ^ Label to display to the user.
20− , isInfix :: Maybe Backtick -- ^ Did the completion happen
21− -- in the context of an infix notation.
22− , docs :: SpanDoc -- ^ Available documentation.
23− }
24−instance Show CompItem where
25− show CI { .. } = "CompItem { origName = \"" ++ showGhc origName ++ "\""
26− ++ ", importedFrom = " ++ show importedFrom
27− ++ ", thingType = " ++ show (fmap showGhc thingType)
28− ++ ", label = " ++ show label
29− ++ ", isInfix = " ++ show isInfix
30− ++ ", docs = " ++ show docs
31− ++ " } "
32−instance Eq CompItem where
33− ci1 == ci2 = origName ci1 == origName ci2
34−instance Ord CompItem where
35− compare ci1 ci2 = origName ci1 `compare` origName ci2
36−
37−-- Associates a module's qualifier with its members
38−newtype QualCompls
39− = QualCompls { getQualCompls :: Map.Map T.Text [CompItem] }
40− deriving Show
41−instance Semigroup QualCompls where
42− (QualCompls a) <> (QualCompls b) = QualCompls $ Map.unionWith (++) a b
43−instance Monoid QualCompls where
44− mempty = QualCompls Map.empty
45− mappend = (Prelude.<>)
46−
47−-- | End result of the completions
48−data CachedCompletions = CC
49− { allModNamesAsNS :: [T.Text] -- ^ All module names in scope.
50− -- Prelude is a single module
51− , unqualCompls :: [CompItem] -- ^ All Possible completion items
52− , qualCompls :: QualCompls -- ^ Completion items associated to
53− -- to a specific module name.
54− , importableModules :: [T.Text] -- ^ All modules that may be imported.
55− } deriving Show
56−
57−instance NFData CachedCompletions where
58− rnf = rwhnf
src/Development/IDE/Spans/AtPoint.hsdeleted−178
@@ -1,178 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−-- | Gives information about symbols at a given point in DAML files.
5−-- These are all pure functions that should execute quickly.
6−module Development.IDE.Spans.AtPoint (
7− atPoint
8− , gotoDefinition
9− ) where
10−
11−import Development.IDE.GHC.Error
12−import Development.IDE.GHC.Orphans()
13−import Development.IDE.Types.Location
14−
15−-- DAML compiler and infrastructure
16−import Development.IDE.GHC.Compat
17−import Development.IDE.Types.Options
18−import Development.IDE.Spans.Type as SpanInfo
19−import Development.IDE.Spans.Common (spanDocToMarkdown)
20−
21−-- GHC API imports
22−import DynFlags
23−import FastString
24−import Name
25−import Outputable hiding ((<>))
26−import SrcLoc
27−import Type
28−import VarSet
29−
30−import Control.Monad.Extra
31−import Control.Monad.Trans.Maybe
32−import Control.Monad.IO.Class
33−import Data.Maybe
34−import Data.List
35−import qualified Data.Text as T
36−
37−-- | Locate the definition of the name at a given position.
38−gotoDefinition
39− :: MonadIO m
40− => (Module -> m (Maybe (HieFile, FilePath)))
41− -> IdeOptions
42− -> [SpanInfo]
43− -> Position
44− -> m (Maybe Location)
45−gotoDefinition getHieFile ideOpts srcSpans pos =
46− listToMaybe <$> locationsAtPoint getHieFile ideOpts pos srcSpans
47−
48−-- | Synopsis for the name at a given position.
49−atPoint
50− :: IdeOptions
51− -> SpansInfo
52− -> Position
53− -> Maybe (Maybe Range, [T.Text])
54−atPoint IdeOptions{..} (SpansInfo srcSpans cntsSpans) pos = do
55− firstSpan <- listToMaybe $ deEmpasizeGeneratedEqShow $ spansAtPoint pos srcSpans
56− let constraintsAtPoint = mapMaybe spaninfoType (spansAtPoint pos cntsSpans)
57− return (Just (range firstSpan), hoverInfo firstSpan constraintsAtPoint)
58− where
59− -- Hover info for types, classes, type variables
60− hoverInfo SpanInfo{spaninfoType = Nothing , spaninfoDocs = docs , ..} _ =
61− (wrapLanguageSyntax <$> name) <> location <> spanDocToMarkdown docs
62− where
63− name = [maybe shouldNotHappen showName mbName]
64− location = [maybe shouldNotHappen definedAt mbName]
65− shouldNotHappen = "ghcide: did not expect a type level component without a name"
66− mbName = getNameM spaninfoSource
67−
68− -- Hover info for values/data
69− hoverInfo SpanInfo{spaninfoType = (Just typ), spaninfoDocs = docs , ..} cnts =
70− (wrapLanguageSyntax <$> nameOrSource) <> location <> spanDocToMarkdown docs
71− where
72− mbName = getNameM spaninfoSource
73− expr = case spaninfoSource of
74− Named n -> qualifyNameIfPossible n
75− Lit l -> crop $ T.pack l
76− _ -> ""
77− nameOrSource = [expr <> "\n" <> typeAnnotation]
78− qualifyNameIfPossible name' = modulePrefix <> showName name'
79− where modulePrefix = maybe "" (<> ".") (getModuleNameAsText name')
80− location = [maybe "" definedAt mbName]
81−
82− thisFVs = tyCoVarsOfType typ
83− constraintsOverFVs = filter (\cnt -> not (tyCoVarsOfType cnt `disjointVarSet` thisFVs)) cnts
84− constraintsT = T.intercalate ", " (map showName constraintsOverFVs)
85−
86− typeAnnotation = case constraintsOverFVs of
87− [] -> colon <> showName typ
88− [_] -> colon <> constraintsT <> "\n=> " <> showName typ
89− _ -> colon <> "(" <> constraintsT <> ")\n=> " <> showName typ
90−
91− definedAt name = "*Defined " <> T.pack (showSDocUnsafe $ pprNameDefnLoc name) <> "*\n"
92−
93− crop txt
94− | T.length txt > 50 = T.take 46 txt <> " ..."
95− | otherwise = txt
96−
97− range SpanInfo{..} = Range
98− (Position spaninfoStartLine spaninfoStartCol)
99− (Position spaninfoEndLine spaninfoEndCol)
100−
101− colon = if optNewColonConvention then ": " else ":: "
102− wrapLanguageSyntax x = T.unlines [ "```" <> T.pack optLanguageSyntax, x, "```"]
103−
104− -- NOTE(RJR): This is a bit hacky.
105− -- We don't want to show the user type signatures generated from Eq and Show
106− -- instances, as they do not appear in the source program.
107− -- However the user could have written an `==` or `show` function directly,
108− -- in which case we still want to show information for that.
109− -- Hence we just move such information later in the list of spans.
110− deEmpasizeGeneratedEqShow :: [SpanInfo] -> [SpanInfo]
111− deEmpasizeGeneratedEqShow = uncurry (++) . partition (not . isTypeclassDeclSpan)
112− isTypeclassDeclSpan :: SpanInfo -> Bool
113− isTypeclassDeclSpan spanInfo =
114− case getNameM (spaninfoSource spanInfo) of
115− Just name -> any (`isInfixOf` getOccString name) ["==", "showsPrec"]
116− Nothing -> False
117−
118−locationsAtPoint
119− :: forall m
120− . MonadIO m
121− => (Module -> m (Maybe (HieFile, FilePath)))
122− -> IdeOptions
123− -> Position
124− -> [SpanInfo]
125− -> m [Location]
126−locationsAtPoint getHieFile _ideOptions pos =
127− fmap (map srcSpanToLocation) . mapMaybeM (getSpan . spaninfoSource) . spansAtPoint pos
128− where getSpan :: SpanSource -> m (Maybe SrcSpan)
129− getSpan NoSource = pure Nothing
130− getSpan (SpanS sp) = pure $ Just sp
131− getSpan (Lit _) = pure Nothing
132− getSpan (Named name) = case nameSrcSpan name of
133− sp@(RealSrcSpan _) -> pure $ Just sp
134− sp@(UnhelpfulSpan _) -> runMaybeT $ do
135− guard (sp /= wiredInSrcSpan)
136− -- This case usually arises when the definition is in an external package (DAML only).
137− -- In this case the interface files contain garbage source spans
138− -- so we instead read the .hie files to get useful source spans.
139− mod <- MaybeT $ return $ nameModule_maybe name
140− (hieFile, srcPath) <- MaybeT $ getHieFile mod
141− avail <- MaybeT $ pure $ find (eqName name . snd) $ hieExportNames hieFile
142− -- The location will point to the source file used during compilation.
143− -- This file might no longer exists and even if it does the path will be relative
144− -- to the compilation directory which we don’t know.
145− let span = setFileName srcPath $ fst avail
146− pure span
147− -- We ignore uniques and source spans and only compare the name and the module.
148− eqName :: Name -> Name -> Bool
149− eqName n n' = nameOccName n == nameOccName n' && nameModule_maybe n == nameModule_maybe n'
150− setFileName f (RealSrcSpan span) = RealSrcSpan (span { srcSpanFile = mkFastString f })
151− setFileName _ span@(UnhelpfulSpan _) = span
152−
153−-- | Filter out spans which do not enclose a given point
154−spansAtPoint :: Position -> [SpanInfo] -> [SpanInfo]
155−spansAtPoint pos = filter atp where
156− line = _line pos
157− cha = _character pos
158− atp SpanInfo{..} =
159− startsBeforePosition && endsAfterPosition
160− where
161− startLineCmp = compare spaninfoStartLine line
162− endLineCmp = compare spaninfoEndLine line
163−
164− startsBeforePosition = startLineCmp == LT || (startLineCmp == EQ && spaninfoStartCol <= cha)
165− -- The end col points to the column after the
166− -- last character so we use > instead of >=
167− endsAfterPosition = endLineCmp == GT || (endLineCmp == EQ && spaninfoEndCol > cha)
168−
169−showName :: Outputable a => a -> T.Text
170−showName = T.pack . prettyprint
171− where
172− prettyprint x = renderWithStyle unsafeGlobalDynFlags (ppr x) style
173− style = mkUserStyle unsafeGlobalDynFlags neverQualify AllTheWay
174−
175−getModuleNameAsText :: Name -> Maybe T.Text
176−getModuleNameAsText n = do
177− m <- nameModule_maybe n
178− return . T.pack . moduleNameString $ moduleName m
src/Development/IDE/Spans/Calculate.hsdeleted−273
@@ -1,273 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−-- ORIGINALLY COPIED FROM https://github.com/commercialhaskell/intero
5−
6−{-# LANGUAGE CPP #-}
7−{-# LANGUAGE RankNTypes #-}
8−#include "ghc-api-version.h"
9−
10−-- | Get information on modules, identifiers, etc.
11−
12−module Development.IDE.Spans.Calculate(getSrcSpanInfos) where
13−
14−import ConLike
15−import Control.Monad
16−import qualified CoreUtils
17−import Data.List
18−import Data.Maybe
19−import DataCon
20−import Desugar
21−import GHC
22−import GhcMonad
23−import HscTypes
24−import FastString (mkFastString)
25−import OccName
26−import Development.IDE.Types.Location
27−import Development.IDE.Spans.Type
28−#ifdef GHC_LIB
29−import Development.IDE.GHC.Error (zeroSpan)
30−#else
31−import Development.IDE.GHC.Error (zeroSpan, catchSrcErrors)
32−#endif
33−import Prelude hiding (mod)
34−import TcHsSyn
35−import Var
36−import Development.IDE.Core.Compile
37−import qualified Development.IDE.GHC.Compat as Compat
38−import Development.IDE.GHC.Util
39−import Development.IDE.Spans.Common
40−import Development.IDE.Spans.Documentation
41−
42−-- A lot of things gained an extra X argument in GHC 8.6, which we mostly ignore
43−-- this U ignores that arg in 8.6, but is hidden in 8.4
44−#if MIN_GHC_API_VERSION(8,6,0)
45−#define U _
46−#else
47−#define U
48−#endif
49−
50−-- | Get source span info, used for e.g. AtPoint and Goto Definition.
51−getSrcSpanInfos
52− :: HscEnv
53− -> [(Located ModuleName, Maybe NormalizedFilePath)] -- ^ Dependencies in topological order
54− -> TcModuleResult
55− -> [ParsedModule] -- ^ Dependencies parsed, optional
56− -> [ModIface] -- ^ Dependencies module interfaces, required
57− -> IO SpansInfo
58−getSrcSpanInfos env imports tc parsedDeps deps =
59− evalGhcEnv env $
60− getSpanInfo imports (tmrModule tc) parsedDeps deps
61−
62−-- | Get ALL source spans in the module.
63−getSpanInfo :: GhcMonad m
64− => [(Located ModuleName, Maybe NormalizedFilePath)] -- ^ imports
65− -> TypecheckedModule
66− -> [ParsedModule]
67− -> [ModIface]
68− -> m SpansInfo
69−getSpanInfo mods tcm@TypecheckedModule{..} parsedDeps deps =
70− do let tcs = tm_typechecked_source
71− bs = listifyAllSpans tcs :: [LHsBind GhcTc]
72− es = listifyAllSpans tcs :: [LHsExpr GhcTc]
73− ps = listifyAllSpans' tcs :: [Pat GhcTc]
74− ts = listifyAllSpans tm_renamed_source :: [LHsType GhcRn]
75− allModules = tm_parsed_module : parsedDeps
76− funBinds = funBindMap tm_parsed_module
77−
78− -- Load all modules in HPT to make their interface documentation available
79− mapM_ (`loadDepModule` Nothing) (reverse deps)
80− forM_ (modInfoIface tm_checked_module_info) $ \modIface ->
81− modifySession (loadModuleHome $ HomeModInfo modIface (snd tm_internals_) Nothing)
82−
83− bts <- mapM (getTypeLHsBind allModules funBinds) bs -- binds
84− ets <- mapM (getTypeLHsExpr allModules) es -- expressions
85− pts <- mapM (getTypeLPat allModules) ps -- patterns
86− tts <- mapM (getLHsType allModules) ts -- types
87− let imports = importInfo mods
88− let exports = getExports tcm
89− let exprs = addEmptyInfo exports ++ addEmptyInfo imports ++ concat bts ++ concat tts ++ catMaybes (ets ++ pts)
90− let constraints = map constraintToInfo (concatMap getConstraintsLHsBind bs)
91− return $ SpansInfo (mapMaybe toSpanInfo (sortBy cmp exprs))
92− (mapMaybe toSpanInfo (sortBy cmp constraints))
93− where cmp (_,a,_,_) (_,b,_,_)
94− | a `isSubspanOf` b = LT
95− | b `isSubspanOf` a = GT
96− | otherwise = compare (srcSpanStart a) (srcSpanStart b)
97−
98− addEmptyInfo = map (\(a,b) -> (a,b,Nothing,emptySpanDoc))
99− constraintToInfo (sp, ty) = (SpanS sp, sp, Just ty, emptySpanDoc)
100−
101−-- | The locations in the typechecked module are slightly messed up in some cases (e.g. HsMatchContext always
102−-- points to the first match) whereas the parsed module has the correct locations.
103−-- Therefore we build up a map from OccName to the corresponding definition in the parsed module
104−-- to lookup precise locations for things like multi-clause function definitions.
105−--
106−-- For now this only contains FunBinds.
107−funBindMap :: ParsedModule -> OccEnv (HsBind GhcPs)
108−funBindMap pm = mkOccEnv $ [ (occName $ unLoc f, bnd) | L _ (Compat.ValD bnd@FunBind{fun_id = f}) <- hsmodDecls $ unLoc $ pm_parsed_source pm ]
109−
110−getExports :: TypecheckedModule -> [(SpanSource, SrcSpan)]
111−getExports m
112− | Just (_, _, Just exports, _) <- renamedSource m =
113− [ (Named $ unLoc n, getLoc n)
114− | (e, _) <- exports
115− , n <- ieLNames $ unLoc e
116− ]
117−getExports _ = []
118−
119−-- | Variant of GHC's ieNames that produces LIdP instead of IdP
120−ieLNames :: IE pass -> [Located (IdP pass)]
121−ieLNames (IEVar U n ) = [ieLWrappedName n]
122−ieLNames (IEThingAbs U n ) = [ieLWrappedName n]
123−ieLNames (IEThingAll U n ) = [ieLWrappedName n]
124−ieLNames (IEThingWith U n _ ns _) = ieLWrappedName n : map ieLWrappedName ns
125−ieLNames _ = []
126−
127−-- | Get the name and type of a binding.
128−getTypeLHsBind :: (GhcMonad m)
129− => [ParsedModule]
130− -> OccEnv (HsBind GhcPs)
131− -> LHsBind GhcTc
132− -> m [(SpanSource, SrcSpan, Maybe Type, SpanDoc)]
133−getTypeLHsBind deps funBinds (L _spn FunBind{fun_id = pid})
134− | Just FunBind {fun_matches = MG{mg_alts=L _ matches}} <- lookupOccEnv funBinds (occName $ unLoc pid) = do
135− let name = getName (unLoc pid)
136− docs <- getDocumentationTryGhc deps name
137− return [(Named name, getLoc mc_fun, Just (varType (unLoc pid)), docs) | match <- matches, FunRhs{mc_fun = mc_fun} <- [m_ctxt $ unLoc match] ]
138−-- In theory this shouldn’t ever fail but if it does, we can at least show the first clause.
139−getTypeLHsBind deps _ (L _spn FunBind{fun_id = pid,fun_matches = MG{}}) = do
140− let name = getName (unLoc pid)
141− docs <- getDocumentationTryGhc deps name
142− return [(Named name, getLoc pid, Just (varType (unLoc pid)), docs)]
143−getTypeLHsBind _ _ _ = return []
144−
145−-- | Get information about constraints
146−getConstraintsLHsBind :: LHsBind GhcTc
147− -> [(SrcSpan, Type)]
148−getConstraintsLHsBind (L spn AbsBinds { abs_ev_vars = vars })
149− = map (\v -> (spn, varType v)) vars
150−getConstraintsLHsBind _ = []
151−
152−-- | Get the name and type of an expression.
153−getTypeLHsExpr :: (GhcMonad m)
154− => [ParsedModule]
155− -> LHsExpr GhcTc
156− -> m (Maybe (SpanSource, SrcSpan, Maybe Type, SpanDoc))
157−getTypeLHsExpr deps e = do
158− hs_env <- getSession
159− (_, mbe) <- liftIO (deSugarExpr hs_env e)
160− case mbe of
161− Just expr -> do
162− let ss = getSpanSource (unLoc e)
163− docs <- case ss of
164− Named n -> getDocumentationTryGhc deps n
165− _ -> return emptySpanDoc
166− return $ Just (ss, getLoc e, Just (CoreUtils.exprType expr), docs)
167− Nothing -> return Nothing
168− where
169− getSpanSource :: HsExpr GhcTc -> SpanSource
170− getSpanSource xpr | isLit xpr = Lit (showGhc xpr)
171− getSpanSource (HsVar U (L _ i)) = Named (getName i)
172− getSpanSource (HsConLikeOut U (RealDataCon dc)) = Named (dataConName dc)
173− getSpanSource RecordCon {rcon_con_name} = Named (getName rcon_con_name)
174− getSpanSource (HsWrap U _ xpr) = getSpanSource xpr
175− getSpanSource (HsPar U xpr) = getSpanSource (unLoc xpr)
176− getSpanSource _ = NoSource
177−
178− isLit :: HsExpr GhcTc -> Bool
179− isLit (HsLit U _) = True
180− isLit (HsOverLit U _) = True
181− isLit (ExplicitTuple U args _) = all (isTupLit . unLoc) args
182−#if MIN_GHC_API_VERSION(8,6,0)
183− isLit (ExplicitSum U _ _ xpr) = isLitChild (unLoc xpr)
184− isLit (ExplicitList U _ xprs) = all (isLitChild . unLoc) xprs
185−#else
186− isLit (ExplicitSum _ _ xpr _) = isLitChild (unLoc xpr)
187− isLit (ExplicitList _ _ xprs) = all (isLitChild . unLoc) xprs
188−#endif
189− isLit _ = False
190−
191− isTupLit (Present U xpr) = isLitChild (unLoc xpr)
192− isTupLit _ = False
193−
194− -- We need special treatment for children so things like [(1)] are still treated
195− -- as a list literal while not treating (1) as a literal.
196− isLitChild (HsWrap U _ xpr) = isLitChild xpr
197− isLitChild (HsPar U xpr) = isLitChild (unLoc xpr)
198−#if MIN_GHC_API_VERSION(8,8,0)
199− isLitChild (ExprWithTySig U xpr _) = isLitChild (unLoc xpr)
200−#elif MIN_GHC_API_VERSION(8,6,0)
201− isLitChild (ExprWithTySig U xpr) = isLitChild (unLoc xpr)
202−#else
203− isLitChild (ExprWithTySigOut xpr _) = isLitChild (unLoc xpr)
204− isLitChild (ExprWithTySig xpr _) = isLitChild (unLoc xpr)
205−#endif
206− isLitChild e = isLit e
207−
208−-- | Get the name and type of a pattern.
209−getTypeLPat :: (GhcMonad m)
210− => [ParsedModule]
211− -> Pat GhcTc
212− -> m (Maybe (SpanSource, SrcSpan, Maybe Type, SpanDoc))
213−getTypeLPat deps pat = do
214− let (src, spn) = getSpanSource pat
215− docs <- case src of
216− Named n -> getDocumentationTryGhc deps n
217− _ -> return emptySpanDoc
218− return $ Just (src, spn, Just (hsPatType pat), docs)
219− where
220− getSpanSource :: Pat GhcTc -> (SpanSource, SrcSpan)
221− getSpanSource (VarPat U (L spn vid)) = (Named (getName vid), spn)
222− getSpanSource (ConPatOut (L spn (RealDataCon dc)) _ _ _ _ _ _) =
223− (Named (dataConName dc), spn)
224− getSpanSource _ = (NoSource, noSrcSpan)
225−
226−getLHsType
227− :: GhcMonad m
228− => [ParsedModule]
229− -> LHsType GhcRn
230− -> m [(SpanSource, SrcSpan, Maybe Type, SpanDoc)]
231−getLHsType deps (L spn (HsTyVar U _ v)) = do
232− let n = unLoc v
233− docs <- getDocumentationTryGhc deps n
234−#ifdef GHC_LIB
235− let ty = Right Nothing
236−#else
237− ty <- catchSrcErrors "completion" $ do
238− name' <- lookupName n
239− return $ name' >>= safeTyThingType
240−#endif
241− let ty' = case ty of
242− Right (Just x) -> Just x
243− _ -> Nothing
244− pure [(Named n, spn, ty', docs)]
245−getLHsType _ _ = pure []
246−
247−importInfo :: [(Located ModuleName, Maybe NormalizedFilePath)]
248− -> [(SpanSource, SrcSpan)]
249−importInfo = mapMaybe (uncurry wrk) where
250− wrk :: Located ModuleName -> Maybe NormalizedFilePath -> Maybe (SpanSource, SrcSpan)
251− wrk modName = \case
252− Nothing -> Nothing
253− Just fp -> Just (fpToSpanSource $ fromNormalizedFilePath fp, getLoc modName)
254−
255− -- TODO make this point to the module name
256− fpToSpanSource :: FilePath -> SpanSource
257− fpToSpanSource fp = SpanS $ RealSrcSpan $ zeroSpan $ mkFastString fp
258−
259−-- | Pretty print the types into a 'SpanInfo'.
260−toSpanInfo :: (SpanSource, SrcSpan, Maybe Type, SpanDoc) -> Maybe SpanInfo
261−toSpanInfo (name,mspan,typ,docs) =
262− case mspan of
263− RealSrcSpan spn ->
264− -- GHC’s line and column numbers are 1-based while LSP’s line and column
265− -- numbers are 0-based.
266− Just (SpanInfo (srcSpanStartLine spn - 1)
267− (srcSpanStartCol spn - 1)
268− (srcSpanEndLine spn - 1)
269− (srcSpanEndCol spn - 1)
270− typ
271− name
272− docs)
273− _ -> Nothing
src/Development/IDE/Spans/Common.hsdeleted−162
@@ -1,162 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−#include "ghc-api-version.h"
3−
4−module Development.IDE.Spans.Common (
5− showGhc
6−, listifyAllSpans
7−, listifyAllSpans'
8−, safeTyThingId
9−#ifndef GHC_LIB
10−, safeTyThingType
11−#endif
12−, SpanDoc(..)
13−, emptySpanDoc
14−, spanDocToMarkdown
15−, spanDocToMarkdownForTest
16−) where
17−
18−import Data.Data
19−import qualified Data.Generics
20−import qualified Data.Text as T
21−import Data.List.Extra
22−
23−import GHC
24−import Outputable
25−import DynFlags
26−import ConLike
27−import DataCon
28−#ifndef GHC_LIB
29−import Var
30−#endif
31−
32−import qualified Documentation.Haddock.Parser as H
33−import qualified Documentation.Haddock.Types as H
34−
35−showGhc :: Outputable a => a -> String
36−showGhc = showPpr unsafeGlobalDynFlags
37−
38−-- | Get ALL source spans in the source.
39−listifyAllSpans :: (Typeable a, Data m) => m -> [Located a]
40−listifyAllSpans tcs =
41− Data.Generics.listify p tcs
42− where p (L spn _) = isGoodSrcSpan spn
43−-- This is a version of `listifyAllSpans` specialized on picking out
44−-- patterns. It comes about since GHC now defines `type LPat p = Pat
45−-- p` (no top-level locations).
46−listifyAllSpans' :: Typeable a
47− => TypecheckedSource -> [Pat a]
48−listifyAllSpans' tcs = Data.Generics.listify (const True) tcs
49−
50−#ifndef GHC_LIB
51−-- From haskell-ide-engine/src/Haskell/Ide/Engine/Support/HieExtras.hs
52−safeTyThingType :: TyThing -> Maybe Type
53−safeTyThingType thing
54− | Just i <- safeTyThingId thing = Just (varType i)
55−safeTyThingType (ATyCon tycon) = Just (tyConKind tycon)
56−safeTyThingType _ = Nothing
57−#endif
58−
59−safeTyThingId :: TyThing -> Maybe Id
60−safeTyThingId (AnId i) = Just i
61−safeTyThingId (AConLike (RealDataCon dc)) = Just $ dataConWrapId dc
62−safeTyThingId _ = Nothing
63−
64−-- Possible documentation for an element in the code
65−data SpanDoc
66− = SpanDocString HsDocString
67− | SpanDocText [T.Text]
68− deriving Show
69−
70−emptySpanDoc :: SpanDoc
71−emptySpanDoc = SpanDocText []
72−
73−spanDocToMarkdown :: SpanDoc -> [T.Text]
74−#if MIN_GHC_API_VERSION(8,6,0)
75−spanDocToMarkdown (SpanDocString docs)
76− = [T.pack $ haddockToMarkdown $ H.toRegular $ H._doc $ H.parseParas Nothing $ unpackHDS docs]
77−#else
78−spanDocToMarkdown (SpanDocString _)
79− = []
80−#endif
81−spanDocToMarkdown (SpanDocText txt) = txt
82−
83−spanDocToMarkdownForTest :: String -> String
84−spanDocToMarkdownForTest
85− = haddockToMarkdown . H.toRegular . H._doc . H.parseParas Nothing
86−
87−-- Simple (and a bit hacky) conversion from Haddock markup to Markdown
88−haddockToMarkdown
89− :: H.DocH String String -> String
90−
91−haddockToMarkdown H.DocEmpty
92− = ""
93−haddockToMarkdown (H.DocAppend d1 d2)
94− = haddockToMarkdown d1 ++ " " ++ haddockToMarkdown d2
95−haddockToMarkdown (H.DocString s)
96− = s
97−haddockToMarkdown (H.DocParagraph p)
98− = "\n\n" ++ haddockToMarkdown p
99−haddockToMarkdown (H.DocIdentifier i)
100− = "`" ++ i ++ "`"
101−haddockToMarkdown (H.DocIdentifierUnchecked i)
102− = "`" ++ i ++ "`"
103−haddockToMarkdown (H.DocModule i)
104− = "`" ++ i ++ "`"
105−haddockToMarkdown (H.DocWarning w)
106− = haddockToMarkdown w
107−haddockToMarkdown (H.DocEmphasis d)
108− = "*" ++ haddockToMarkdown d ++ "*"
109−haddockToMarkdown (H.DocBold d)
110− = "**" ++ haddockToMarkdown d ++ "**"
111−haddockToMarkdown (H.DocMonospaced d)
112− = "`" ++ escapeBackticks (haddockToMarkdown d) ++ "`"
113− where
114− escapeBackticks "" = ""
115− escapeBackticks ('`':ss) = '\\':'`':escapeBackticks ss
116− escapeBackticks (s :ss) = s:escapeBackticks ss
117−haddockToMarkdown (H.DocCodeBlock d)
118− = "\n```haskell\n" ++ haddockToMarkdown d ++ "\n```\n"
119−haddockToMarkdown (H.DocExamples es)
120− = "\n```haskell\n" ++ unlines (map exampleToMarkdown es) ++ "\n```\n"
121− where
122− exampleToMarkdown (H.Example expr result)
123− = ">>> " ++ expr ++ "\n" ++ unlines result
124−haddockToMarkdown (H.DocHyperlink (H.Hyperlink url Nothing))
125− = "<" ++ url ++ ">"
126−haddockToMarkdown (H.DocHyperlink (H.Hyperlink url (Just label)))
127− = "[" ++ haddockToMarkdown label ++ "](" ++ url ++ ")"
128−haddockToMarkdown (H.DocPic (H.Picture url Nothing))
129− = "![](" ++ url ++ ")"
130−haddockToMarkdown (H.DocPic (H.Picture url (Just label)))
131− = "![" ++ label ++ "](" ++ url ++ ")"
132−haddockToMarkdown (H.DocAName aname)
133− = "[" ++ aname ++ "]:"
134−haddockToMarkdown (H.DocHeader (H.Header level title))
135− = replicate level '#' ++ " " ++ haddockToMarkdown title
136−
137−haddockToMarkdown (H.DocUnorderedList things)
138− = '\n' : (unlines $ map (("+ " ++) . trimStart . splitForList . haddockToMarkdown) things)
139−haddockToMarkdown (H.DocOrderedList things)
140− = '\n' : (unlines $ map (("1. " ++) . trimStart . splitForList . haddockToMarkdown) things)
141−haddockToMarkdown (H.DocDefList things)
142− = '\n' : (unlines $ map (\(term, defn) -> "+ **" ++ haddockToMarkdown term ++ "**: " ++ haddockToMarkdown defn) things)
143−
144−-- we cannot render math by default
145−haddockToMarkdown (H.DocMathInline _)
146− = "*cannot render inline math formula*"
147−haddockToMarkdown (H.DocMathDisplay _)
148− = "\n\n*cannot render display math formula*\n\n"
149−
150−-- TODO: render tables
151−haddockToMarkdown (H.DocTable _t)
152− = "\n\n*tables are not yet supported*\n\n"
153−
154−-- things I don't really know how to handle
155−haddockToMarkdown (H.DocProperty _)
156− = "" -- don't really know what to do
157−
158−splitForList :: String -> String
159−splitForList s
160− = case lines s of
161− [] -> ""
162− (first:rest) -> unlines $ first : map ((" " ++) . trimStart) rest
src/Development/IDE/State/FileStore.hsnew file+153
@@ -0,0 +1,153 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE TypeFamilies #-}
5+
6+module Development.IDE.State.FileStore(
7+ getFileExists, getFileContents,
8+ setBufferModified,
9+ fileStoreRules
10+ ) where
11+
12+
13+
14+import StringBuffer
15+import Development.IDE.Orphans()
16+
17+import qualified Data.Map.Strict as Map
18+import qualified Data.Text as T
19+import Data.Time.Clock
20+import Control.Monad.Extra
21+import qualified System.Directory as Dir
22+import Development.Shake
23+import Development.Shake.Classes
24+import Development.IDE.State.Shake
25+import Control.Concurrent.Extra
26+import Control.Exception
27+import GHC.Generics
28+import System.IO.Error
29+import qualified Data.ByteString.Char8 as BS
30+import qualified StringBuffer as SB
31+import Development.IDE.Types.Diagnostics
32+import Data.Time
33+
34+
35+-- This module stores the changed files in memory, and answers file system questions
36+-- from either the memory changes OR the file system itself
37+
38+type DirtyFiles = Map.Map FilePath (UTCTime, StringBuffer) -- when it was modified, it's current value
39+
40+-- Store the DirtyFiles globally, so we can get at it through setBufferModified
41+newtype GlobalDirtyFiles = GlobalDirtyFiles (Var DirtyFiles)
42+instance IsIdeGlobal GlobalDirtyFiles
43+
44+
45+
46+-- | Get the modification time of a file.
47+type instance RuleResult GetModificationTime = UTCTime
48+
49+-- | Get the contents of a file, either dirty (if the buffer is modified) or from disk.
50+type instance RuleResult GetFileContents = (UTCTime, StringBuffer)
51+
52+-- | Does the file exist.
53+type instance RuleResult GetFileExists = Bool
54+
55+
56+data GetFileExists = GetFileExists
57+ deriving (Eq, Show, Generic)
58+instance Hashable GetFileExists
59+instance NFData GetFileExists
60+
61+data GetModificationTime = GetModificationTime
62+ deriving (Eq, Show, Generic)
63+instance Hashable GetModificationTime
64+instance NFData GetModificationTime
65+
66+data GetFileContents = GetFileContents
67+ deriving (Eq, Show, Generic)
68+instance Hashable GetFileContents
69+instance NFData GetFileContents
70+
71+
72+getFileExistsRule :: Var DirtyFiles -> Rules ()
73+getFileExistsRule dirty =
74+ defineEarlyCutoff $ \GetFileExists file -> do
75+ alwaysRerun
76+ res <- liftIO $ handle (\(_ :: IOException) -> return False) $
77+ (Map.member file <$> readVar dirty) ||^
78+ Dir.doesFileExist file
79+ return (Just $ if res then BS.singleton '1' else BS.empty, ([], Just res))
80+
81+
82+showTimePrecise :: UTCTime -> String
83+showTimePrecise UTCTime{..} = show (toModifiedJulianDay utctDay, diffTimeToPicoseconds utctDayTime)
84+
85+getModificationTimeRule :: Var DirtyFiles -> Rules ()
86+getModificationTimeRule dirty =
87+ defineEarlyCutoff $ \GetModificationTime file -> do
88+ let wrap time = (Just $ BS.pack $ showTimePrecise time, ([], Just time))
89+ alwaysRerun
90+ mp <- liftIO $ readVar dirty
91+ case Map.lookup file mp of
92+ Just (time, _) -> return $ wrap time
93+ Nothing -> liftIO $ fmap wrap (Dir.getModificationTime file) `catch` \(e :: IOException) -> do
94+ let err | isDoesNotExistError e = "File does not exist: " ++ file
95+ | otherwise = "IO error while reading " ++ file ++ ", " ++ displayException e
96+ return (Nothing, ([ideErrorText file $ T.pack err], Nothing))
97+
98+
99+getFileContentsRule :: Var DirtyFiles -> Rules ()
100+getFileContentsRule dirty =
101+ define $ \GetFileContents file -> do
102+ -- need to depend on modification time to introduce a dependency with Cutoff
103+ time <- use_ GetModificationTime file
104+ res <- liftIO $ ideTryIOException file $ do
105+ mp <- readVar dirty
106+ case Map.lookup file mp of
107+ Just (_, contents) -> return contents
108+ Nothing -> hGetStringBuffer file
109+ case res of
110+ Left err -> return ([err], Nothing)
111+ Right contents -> return ([], Just (time, contents))
112+
113+
114+getFileContents :: FilePath -> Action (UTCTime, StringBuffer)
115+getFileContents = use_ GetFileContents
116+
117+getFileExists :: FilePath -> Action Bool
118+getFileExists =
119+ -- we deliberately and intentionally wrap the file as an FilePath WITHOUT mkAbsolute
120+ -- so that if the file doesn't exist, is on a shared drive that is unmounted etc we get a properly
121+ -- cached 'No' rather than an exception in the wrong place
122+ use_ GetFileExists
123+
124+
125+fileStoreRules :: Rules ()
126+fileStoreRules = do
127+ dirty <- liftIO $ newVar Map.empty
128+ addIdeGlobal $ GlobalDirtyFiles dirty
129+ getModificationTimeRule dirty
130+ getFileContentsRule dirty
131+ getFileExistsRule dirty
132+
133+
134+strictPair :: a -> b -> (a, b)
135+strictPair !a !b = (a,b)
136+
137+
138+-- | Notify the compiler service of a modified buffer
139+setBufferModified :: IdeState -> FilePath -> (Maybe T.Text, UTCTime) -> IO ()
140+setBufferModified state absFile (mcontents, !time) = do
141+ GlobalDirtyFiles envDirtyFiles <- getIdeGlobalState state
142+ -- update vars synchronously
143+ modifyVar_ envDirtyFiles $ evaluate . case mcontents of
144+ Nothing -> Map.delete absFile
145+ Just contents -> Map.insert absFile $ strictPair time $ textToStringBuffer contents
146+
147+ -- run shake to update results regarding the files of interest
148+ void $ shakeRun state []
149+
150+
151+-- would be nice to do this more efficiently...
152+textToStringBuffer :: T.Text -> SB.StringBuffer
153+textToStringBuffer = SB.stringToStringBuffer . T.unpack
src/Development/IDE/Core/RuleTypes.hs → src/Development/IDE/State/RuleTypes.hsrenamed+80−92
@@ -1,38 +1,41 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
44{-# LANGUAGE FlexibleInstances #-}
55{-# LANGUAGE TypeFamilies #-}
6+{-# OPTIONS_GHC -Wno-orphans #-}
67
78-- | A Shake implementation of the compiler service, built
89-- using the "Shaker" abstraction layer for in-memory use.
910--
10−module Development.IDE.Core.RuleTypes(
11− module Development.IDE.Core.RuleTypes
11+module Development.IDE.State.RuleTypes(
12+ module Development.IDE.State.RuleTypes
1213 ) where
1314
1415import Control.DeepSeq
15−import Data.Binary
16−import Development.IDE.Import.DependencyInformation
17−import Development.IDE.GHC.Util
16+import Development.IDE.Functions.Compile (TcModuleResult, GhcModule, LoadPackageResult(..))
17+import qualified Development.IDE.Functions.Compile as Compile
18+import Development.IDE.Functions.FindImports (Import(..))
19+import Development.IDE.Functions.DependencyInformation
1820import Data.Hashable
1921import Data.Typeable
20−import qualified Data.Set as S
21−import Development.Shake
22+import Development.Shake hiding (Env, newCache)
2223import GHC.Generics (Generic)
2324
2425import GHC
25−import Module (InstalledUnitId)
26−import HscTypes (CgGuts, Linkable, HomeModInfo, ModDetails)
26+import Development.IDE.Compat
27+import Module
2728
28−import Development.IDE.Spans.Type
29−import Development.IDE.Import.FindImports (ArtifactsLocation)
29+import Development.IDE.Types.SpanInfo
3030
3131
3232-- NOTATION
3333-- Foo+ means Foo for the dependencies
3434-- Foo* means Foo for me and Foo+
3535
36+-- | Kick off things
37+type instance RuleResult OfInterest = ()
38+
3639-- | The parse tree for the file using GetFileContents
3740type instance RuleResult GetParsedModule = ParsedModule
3841
@@ -45,150 +48,135 @@ type instance RuleResult GetDependencyInformation = DependencyInformation
4548-- This rule is also responsible for calling ReportImportCycles for each file in the transitive closure.
4649type instance RuleResult GetDependencies = TransitiveDependencies
4750
48−-- | Contains the typechecked module and the OrigNameCache entry for
49−-- that module.
50−data TcModuleResult = TcModuleResult
51− { tmrModule :: TypecheckedModule
52− , tmrModInfo :: HomeModInfo
53− }
54−instance Show TcModuleResult where
55− show = show . pm_mod_summary . tm_parsed_module . tmrModule
56−
57−instance NFData TcModuleResult where
58− rnf = rwhnf
59−
60−tmrModSummary :: TcModuleResult -> ModSummary
61−tmrModSummary = pm_mod_summary . tm_parsed_module . tmrModule
62−
63−data HiFileResult = HiFileResult
64− { hirModSummary :: !ModSummary
65− -- Bang patterns here are important to stop the result retaining
66− -- a reference to a typechecked module
67− , hirModIface :: !ModIface
68− }
69−
70−instance NFData HiFileResult where
71− rnf = rwhnf
72−
73−instance Show HiFileResult where
74− show = show . hirModSummary
75−
7651-- | The type checked version of this file, requires TypeCheck+
7752type instance RuleResult TypeCheck = TcModuleResult
7853
7954-- | Information about what spans occur where, requires TypeCheck
80−type instance RuleResult GetSpanInfo = SpansInfo
55+type instance RuleResult GetSpanInfo = [SpanInfo]
8156
8257-- | Convert to Core, requires TypeCheck*
83−type instance RuleResult GenerateCore = (SafeHaskellMode, CgGuts, ModDetails)
84−
85−-- | Generate byte code for template haskell.
86−type instance RuleResult GenerateByteCode = Linkable
58+type instance RuleResult GenerateCore = GhcModule
8759
8860-- | A GHC session that we reuse.
89−type instance RuleResult GhcSession = HscEnvEq
61+type instance RuleResult GhcSession = HscEnv
9062
91−-- | Resolve the imports in a module to the file path of a module
92−-- in the same package or the package id of another package.
93−type instance RuleResult GetLocatedImports = ([(Located ModuleName, Maybe ArtifactsLocation)], S.Set InstalledUnitId)
63+-- | Resolve the imports in a module to the list of either external packages or absolute file paths
64+-- for modules in the same package.
65+type instance RuleResult GetLocatedImports = [(Located ModuleName, Maybe Import)]
9466
9567-- | This rule is used to report import cycles. It depends on GetDependencyInformation.
9668-- We cannot report the cycles directly from GetDependencyInformation since
9769-- we can only report diagnostics for the current file.
9870type instance RuleResult ReportImportCycles = ()
9971
100−-- | Read the module interface file
101−type instance RuleResult GetHiFile = HiFileResult
102−
103−-- | Get a module interface, either from an interface file or a typechecked module
104−type instance RuleResult GetModIface = HiFileResult
72+-- | Read the given HIE file.
73+type instance RuleResult GetHieFile = HieFile
10574
106−type instance RuleResult IsFileOfInterest = Bool
10775
108−-- | Generate a ModSummary that has enough information to be used to get .hi and .hie files.
109−-- without needing to parse the entire source
110−type instance RuleResult GetModSummary = ModSummary
76+data OfInterest = OfInterest
77+ deriving (Eq, Show, Typeable, Generic)
78+instance Hashable OfInterest
79+instance NFData OfInterest
11180
11281data GetParsedModule = GetParsedModule
11382 deriving (Eq, Show, Typeable, Generic)
11483instance Hashable GetParsedModule
11584instance NFData GetParsedModule
116−instance Binary GetParsedModule
11785
11886data GetLocatedImports = GetLocatedImports
11987 deriving (Eq, Show, Typeable, Generic)
12088instance Hashable GetLocatedImports
12189instance NFData GetLocatedImports
122−instance Binary GetLocatedImports
12390
12491data GetDependencyInformation = GetDependencyInformation
12592 deriving (Eq, Show, Typeable, Generic)
12693instance Hashable GetDependencyInformation
12794instance NFData GetDependencyInformation
128−instance Binary GetDependencyInformation
12995
13096data ReportImportCycles = ReportImportCycles
13197 deriving (Eq, Show, Typeable, Generic)
13298instance Hashable ReportImportCycles
13399instance NFData ReportImportCycles
134−instance Binary ReportImportCycles
135100
136101data GetDependencies = GetDependencies
137102 deriving (Eq, Show, Typeable, Generic)
138103instance Hashable GetDependencies
139104instance NFData GetDependencies
140−instance Binary GetDependencies
141105
142106data TypeCheck = TypeCheck
143107 deriving (Eq, Show, Typeable, Generic)
144108instance Hashable TypeCheck
145109instance NFData TypeCheck
146−instance Binary TypeCheck
147110
148111data GetSpanInfo = GetSpanInfo
149112 deriving (Eq, Show, Typeable, Generic)
150113instance Hashable GetSpanInfo
151114instance NFData GetSpanInfo
152−instance Binary GetSpanInfo
153115
154116data GenerateCore = GenerateCore
155117 deriving (Eq, Show, Typeable, Generic)
156118instance Hashable GenerateCore
157119instance NFData GenerateCore
158−instance Binary GenerateCore
159−
160−data GenerateByteCode = GenerateByteCode
161− deriving (Eq, Show, Typeable, Generic)
162−instance Hashable GenerateByteCode
163−instance NFData GenerateByteCode
164−instance Binary GenerateByteCode
165120
166121data GhcSession = GhcSession
167122 deriving (Eq, Show, Typeable, Generic)
168123instance Hashable GhcSession
169124instance NFData GhcSession
170−instance Binary GhcSession
171125
172−data GetHiFile = GetHiFile
126+-- Note that we embed the filepath here instead of using the filepath associated with Shake keys.
127+-- Otherwise we will garbage collect the result since files in package dependencies will not be declared reachable.
128+data GetHieFile = GetHieFile FilePath
173129 deriving (Eq, Show, Typeable, Generic)
174−instance Hashable GetHiFile
175−instance NFData GetHiFile
176−instance Binary GetHiFile
130+instance Hashable GetHieFile
131+instance NFData GetHieFile
177132
178−data GetModIface = GetModIface
179− deriving (Eq, Show, Typeable, Generic)
180−instance Hashable GetModIface
181−instance NFData GetModIface
182−instance Binary GetModIface
133+------------------------------------------------------------
134+-- Orphan Instances
183135
184−data IsFileOfInterest = IsFileOfInterest
185− deriving (Eq, Show, Typeable, Generic)
186−instance Hashable IsFileOfInterest
187−instance NFData IsFileOfInterest
188−instance Binary IsFileOfInterest
136+instance NFData (GenLocated SrcSpan ModuleName) where
137+ rnf = rwhnf
189138
190−data GetModSummary = GetModSummary
191− deriving (Eq, Show, Typeable, Generic)
192−instance Hashable GetModSummary
193−instance NFData GetModSummary
194−instance Binary GetModSummary
139+instance Show TcModuleResult where
140+ show = show . pm_mod_summary . tm_parsed_module . Compile.tmrModule
141+
142+instance NFData TcModuleResult where
143+ rnf = rwhnf
144+
145+instance Show ModSummary where
146+ show = show . ms_mod
147+
148+instance Show ParsedModule where
149+ show = show . pm_mod_summary
150+
151+instance NFData ModSummary where
152+ rnf = rwhnf
153+
154+instance Show HscEnv where
155+ show _ = "HscEnv"
156+
157+instance NFData HscEnv where
158+ rnf = rwhnf
159+
160+instance NFData ParsedModule where
161+ rnf = rwhnf
162+
163+instance NFData SpanInfo where
164+ rnf = rwhnf
165+
166+instance NFData Import where
167+ rnf = rwhnf
168+
169+instance Hashable InstalledUnitId where
170+ hashWithSalt salt = hashWithSalt salt . installedUnitIdString
171+
172+instance Show LoadPackageResult where
173+ show = installedUnitIdString . lprInstalledUnitId
174+
175+instance NFData LoadPackageResult where
176+ rnf = rwhnf
177+
178+instance Show HieFile where
179+ show = show . hie_module
180+
181+instance NFData HieFile where
182+ rnf = rwhnf
src/Development/IDE/State/Rules.hsnew file+336
@@ -0,0 +1,336 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE FlexibleInstances #-}
7+{-# LANGUAGE DuplicateRecordFields #-}
8+
9+-- | A Shake implementation of the compiler service, built
10+-- using the "Shaker" abstraction layer for in-memory use.
11+--
12+module Development.IDE.State.Rules(
13+ IdeState, GetDependencies(..), GetParsedModule(..), TransitiveDependencies(..),
14+ Priority(..),
15+ runAction, runActions, useE, usesE,
16+ toIdeResultNew, defineNoFile,
17+ mainRule,
18+ getGhcCore,
19+ getAtPoint,
20+ getDefinition,
21+ getDependencies,
22+ getDalfDependencies,
23+ fileFromParsedModule
24+ ) where
25+
26+import Control.Monad.Except
27+import Control.Monad.Extra (whenJust)
28+import qualified Development.IDE.Functions.Compile as Compile
29+import qualified Development.IDE.Types.Options as Compile
30+import Development.IDE.Functions.DependencyInformation
31+import Development.IDE.Functions.FindImports
32+import Development.IDE.State.FileStore
33+import Development.IDE.Types.Diagnostics as Base
34+import Data.Bifunctor
35+import Data.Either.Extra
36+import Data.Maybe
37+import Data.Foldable
38+import qualified Data.Map.Strict as Map
39+import qualified Data.Set as Set
40+import qualified Data.Text as T
41+import Development.IDE.Functions.GHCError
42+import Development.Shake hiding (Diagnostic, Env, newCache)
43+import Development.IDE.Types.LSP as Compiler
44+import Development.IDE.State.RuleTypes
45+
46+import GHC
47+import Development.IDE.Compat
48+import UniqSupply
49+import Module as M
50+import NameCache
51+
52+import qualified Development.IDE.Functions.AtPoint as AtPoint
53+import Development.IDE.State.Service
54+import Development.IDE.State.Shake
55+
56+-- LEGACY STUFF ON THE OLD STYLE
57+
58+toIdeResultNew :: Either [FileDiagnostic] v -> IdeResult v
59+toIdeResultNew = either (, Nothing) (([],) . Just)
60+
61+-- Convert to a legacy Ide result but dropping dependencies
62+toIdeResultSilent :: Maybe v -> Either [FileDiagnostic] v
63+toIdeResultSilent val = maybe (Left []) Right val
64+
65+
66+defineNoFile :: IdeRule k v => (k -> Action v) -> Rules ()
67+defineNoFile f = define $ \k file -> do
68+ if file == "" then do res <- f k; return ([], Just res) else
69+ fail $ "Rule " ++ show k ++ " should always be called with the empty string for a file"
70+
71+
72+------------------------------------------------------------
73+-- Exposed API
74+
75+
76+-- | Get GHC Core for the supplied file.
77+getGhcCore :: FilePath -> Action (Maybe [CoreModule])
78+getGhcCore file = eitherToMaybe <$> runExceptT (coresForFile file)
79+
80+-- | Generate the GHC Core for the supplied file and its dependencies.
81+coresForFile :: FilePath -> ExceptT [FileDiagnostic] Action [CoreModule]
82+coresForFile file = do
83+ files <- transitiveModuleDeps <$> useE GetDependencies file
84+ pms <- usesE GetParsedModule $ files ++ [file]
85+ fs <- liftIO
86+ . mapM fileFromParsedModule
87+ $ pms
88+ cores <- usesE GenerateCore fs
89+ pure (map Compile.gmCore cores)
90+
91+
92+
93+-- | Get all transitive file dependencies of a given module.
94+-- Does not include the file itself.
95+getDependencies :: FilePath -> Action (Maybe [FilePath])
96+getDependencies file =
97+ eitherToMaybe <$>
98+ (runExceptT $ transitiveModuleDeps <$> useE GetDependencies file)
99+
100+getDalfDependencies :: FilePath -> Action (Maybe [InstalledUnitId])
101+getDalfDependencies file =
102+ eitherToMaybe <$>
103+ (runExceptT $ transitivePkgDeps <$> useE GetDependencies file)
104+
105+-- | Documentation at point.
106+getAtPoint :: FilePath -> Position -> Action (Maybe (Maybe Range, [HoverText]))
107+getAtPoint file pos = do
108+ fmap (either (const Nothing) id) . runExceptT $ getAtPointForFile file pos
109+
110+-- | Goto Definition.
111+getDefinition :: FilePath -> Position -> Action (Maybe Location)
112+getDefinition file pos = do
113+ fmap (either (const Nothing) id) . runExceptT $ getDefinitionForFile file pos
114+
115+
116+------------------------------------------------------------
117+-- Internal Actions
118+
119+useE
120+ :: IdeRule k v
121+ => k -> FilePath -> ExceptT [FileDiagnostic] Action v
122+useE k = ExceptT . fmap toIdeResultSilent . use k
123+
124+-- picks the first error
125+usesE
126+ :: IdeRule k v
127+ => k -> [FilePath] -> ExceptT [FileDiagnostic] Action [v]
128+usesE k = ExceptT . fmap (mapM toIdeResultSilent) . uses k
129+
130+-- | Try to get hover text for the name under point.
131+getAtPointForFile
132+ :: FilePath
133+ -> Position
134+ -> ExceptT [FileDiagnostic] Action (Maybe (Maybe Range, [HoverText]))
135+getAtPointForFile file pos = do
136+ files <- transitiveModuleDeps <$> useE GetDependencies file
137+ tms <- usesE TypeCheck (file : files)
138+ spans <- useE GetSpanInfo file
139+ return $ AtPoint.atPoint (map Compile.tmrModule tms) spans pos
140+
141+getDefinitionForFile :: FilePath -> Position -> ExceptT [FileDiagnostic] Action (Maybe Location)
142+getDefinitionForFile file pos = do
143+ spans <- useE GetSpanInfo file
144+ pkgState <- useE GhcSession ""
145+ opts <- lift getOpts
146+ lift $ AtPoint.gotoDefinition opts pkgState spans pos
147+
148+getOpts :: Action Compile.IdeOptions
149+getOpts = envOptions <$> getServiceEnv
150+
151+------------------------------------------------------------
152+-- Rules
153+-- These typically go from key to value and are oracles.
154+
155+-- TODO (MK) This should be independent of DAML or move out of haskell-ide-core.
156+-- | We build artefacts based on the following high-to-low priority order.
157+data Priority
158+ = PriorityTypeCheck
159+ | PriorityGenerateDalf
160+ | PriorityFilesOfInterest
161+ deriving (Eq, Ord, Show, Enum)
162+
163+
164+getParsedModuleRule :: Rules ()
165+getParsedModuleRule =
166+ define $ \GetParsedModule file -> do
167+ contents <- getFileContents file
168+ packageState <- use_ GhcSession ""
169+ opt <- getOpts
170+ liftIO $ Compile.parseModule opt packageState file contents
171+
172+getLocatedImportsRule :: Rules ()
173+getLocatedImportsRule =
174+ define $ \GetLocatedImports file -> do
175+ pm <- use_ GetParsedModule file
176+ let ms = pm_mod_summary pm
177+ let imports = ms_textual_imps ms
178+ packageState <- use_ GhcSession ""
179+ opt <- getOpts
180+ dflags <- liftIO $ Compile.getGhcDynFlags opt pm packageState
181+ xs <- forM imports $ \(mbPkgName, modName) ->
182+ (modName, ) <$> locateModule dflags (Compile.optExtensions opt) getFileExists modName mbPkgName
183+ return (concat $ lefts $ map snd xs, Just $ map (second eitherToMaybe) xs)
184+
185+
186+-- | Given a target file path, construct the raw dependency results by following
187+-- imports recursively.
188+rawDependencyInformation :: FilePath -> ExceptT [FileDiagnostic] Action RawDependencyInformation
189+rawDependencyInformation f = go (Set.singleton f) Map.empty Map.empty
190+ where go fs !modGraph !pkgs =
191+ case Set.minView fs of
192+ Nothing -> pure (RawDependencyInformation modGraph pkgs)
193+ Just (f, fs) -> do
194+ importsOrErr <- lift $ use GetLocatedImports f
195+ case importsOrErr of
196+ Nothing ->
197+ let modGraph' = Map.insert f (Left ModuleParseError) modGraph
198+ in go fs modGraph' pkgs
199+ Just imports -> do
200+ packageState <- lift $ use_ GhcSession ""
201+ opt <- lift getOpts
202+ modOrPkgImports <- forM imports $ \imp -> do
203+ case imp of
204+ (_modName, Just (PackageImport pkg)) -> do
205+ pkgs <- ExceptT $ liftIO $ Compile.computePackageDeps opt packageState pkg
206+ pure $ Right $ pkg:pkgs
207+ (modName, Just (FileImport absFile)) -> pure $ Left (modName, Just absFile)
208+ (modName, Nothing) -> pure $ Left (modName, Nothing)
209+ let (modImports, pkgImports) = partitionEithers modOrPkgImports
210+ let newFiles = Set.fromList (mapMaybe snd modImports) Set.\\ Map.keysSet modGraph
211+ modGraph' = Map.insert f (Right modImports) modGraph
212+ pkgs' = Map.insert f (Set.fromList $ concat pkgImports) pkgs
213+ go (fs `Set.union` newFiles) modGraph' pkgs'
214+
215+getDependencyInformationRule :: Rules ()
216+getDependencyInformationRule =
217+ define $ \GetDependencyInformation file -> fmap toIdeResultNew $ runExceptT $ do
218+ rawDepInfo <- rawDependencyInformation file
219+ pure $ processDependencyInformation rawDepInfo
220+
221+reportImportCyclesRule :: Rules ()
222+reportImportCyclesRule =
223+ define $ \ReportImportCycles file -> fmap toIdeResultNew $ runExceptT $ do
224+ DependencyInformation{..} <- useE GetDependencyInformation file
225+ whenJust (Map.lookup file depErrorNodes) $ \errs -> do
226+ let cycles = mapMaybe (cycleErrorInFile file) (toList errs)
227+ when (not $ null cycles) $ do
228+ -- Convert cycles of files into cycles of module names
229+ diags <- forM cycles $ \(imp, files) -> do
230+ modNames <- mapM getModuleName files
231+ pure $ toDiag imp modNames
232+ throwError diags
233+ where cycleErrorInFile f (PartOfCycle imp fs)
234+ | f `elem` fs = Just (imp, fs)
235+ cycleErrorInFile _ _ = Nothing
236+ toDiag imp mods = (fp ,) $ Diagnostic
237+ { _range = (_range :: Location -> Range) loc
238+ , _severity = Just DsError
239+ , _source = Just "Import cycle detection"
240+ , _message = "Cyclic module dependency between " <> showCycle mods
241+ , _code = Nothing
242+ , _relatedInformation = Nothing
243+ }
244+ where loc = srcSpanToLocation (getLoc imp)
245+ fp = srcSpanToFilename (getLoc imp)
246+ getModuleName file = do
247+ pm <- useE GetParsedModule file
248+ pure (moduleNameString . moduleName . ms_mod $ pm_mod_summary pm)
249+ showCycle mods = T.intercalate ", " (map T.pack mods)
250+
251+-- returns all transitive dependencies in topological order.
252+-- NOTE: result does not include the argument file.
253+getDependenciesRule :: Rules ()
254+getDependenciesRule =
255+ define $ \GetDependencies file -> do
256+ depInfo@DependencyInformation{..} <- use_ GetDependencyInformation file
257+ let allFiles = Map.keys depModuleDeps <> Map.keys depErrorNodes
258+ _ <- uses_ ReportImportCycles allFiles
259+ return ([], transitiveDeps depInfo file)
260+
261+-- Source SpanInfo is used by AtPoint and Goto Definition.
262+getSpanInfoRule :: Rules ()
263+getSpanInfoRule =
264+ define $ \GetSpanInfo file -> do
265+ pm <- use_ GetParsedModule file
266+ tc <- use_ TypeCheck file
267+ imports <- use_ GetLocatedImports file
268+ packageState <- use_ GhcSession ""
269+ opt <- getOpts
270+ x <- liftIO $ Compile.getSrcSpanInfos opt pm packageState (fileImports imports) tc
271+ return ([], Just x)
272+
273+-- Typechecks a module.
274+typeCheckRule :: Rules ()
275+typeCheckRule =
276+ define $ \TypeCheck file -> do
277+ pm <- use_ GetParsedModule file
278+ deps <- use_ GetDependencies file
279+ tms <- uses_ TypeCheck (transitiveModuleDeps deps)
280+ setPriority PriorityTypeCheck
281+ packageState <- use_ GhcSession ""
282+ opt <- getOpts
283+ liftIO $ Compile.typecheckModule opt pm packageState tms pm
284+
285+
286+generateCoreRule :: Rules ()
287+generateCoreRule =
288+ define $ \GenerateCore file -> do
289+ deps <- use_ GetDependencies file
290+ (tm:tms) <- uses_ TypeCheck (file:transitiveModuleDeps deps)
291+ let pm = tm_parsed_module . Compile.tmrModule $ tm
292+ setPriority PriorityGenerateDalf
293+ packageState <- use_ GhcSession ""
294+ opt <- getOpts
295+ liftIO $ Compile.compileModule opt pm packageState tms tm
296+
297+loadGhcSession :: Rules ()
298+loadGhcSession =
299+ defineNoFile $ \GhcSession -> do
300+ opts <- envOptions <$> getServiceEnv
301+ Compile.optGhcSession opts
302+
303+
304+getHieFileRule :: Rules ()
305+getHieFileRule =
306+ defineNoFile $ \(GetHieFile f) -> do
307+ u <- liftIO $ mkSplitUniqSupply 'a'
308+ let nameCache = initNameCache u []
309+ liftIO $ fmap fst $ readHieFile nameCache f
310+
311+-- | A rule that wires per-file rules together
312+mainRule :: Rules ()
313+mainRule = do
314+ getParsedModuleRule
315+ getLocatedImportsRule
316+ getDependencyInformationRule
317+ reportImportCyclesRule
318+ getDependenciesRule
319+ typeCheckRule
320+ getSpanInfoRule
321+ generateCoreRule
322+ loadGhcSession
323+ getHieFileRule
324+
325+------------------------------------------------------------
326+
327+fileFromParsedModule :: ParsedModule -> IO FilePath
328+fileFromParsedModule = pure . ms_hspp_file . pm_mod_summary
329+
330+fileImports ::
331+ [(Located ModuleName, Maybe Import)]
332+ -> [(Located ModuleName, Maybe FilePath)]
333+fileImports = mapMaybe $ \case
334+ (modName, Nothing) -> Just (modName, Nothing)
335+ (modName, Just (FileImport absFile)) -> Just (modName, Just absFile)
336+ (_modName, Just (PackageImport _pkg)) -> Nothing
src/Development/IDE/State/Service.hsnew file+120
@@ -0,0 +1,120 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE FlexibleInstances #-}
7+
8+-- | A Shake implementation of the compiler service, built
9+-- using the "Shaker" abstraction layer for in-memory use.
10+--
11+module Development.IDE.State.Service(
12+ Env(..),
13+ getServiceEnv,
14+ IdeState, initialise, shutdown,
15+ runAction, runActions,
16+ setFilesOfInterest,
17+ writeProfile,
18+ getDiagnostics, unsafeClearDiagnostics,
19+ logDebug, logSeriousError
20+ ) where
21+
22+import Control.Concurrent.Extra
23+import Control.Monad.Except
24+import Development.IDE.Types.Options (IdeOptions(..))
25+import Development.IDE.State.FileStore
26+import qualified Development.IDE.Logger as Logger
27+import Data.Maybe
28+import Data.Set (Set)
29+import qualified Data.Set as Set
30+import Development.IDE.Functions.GHCError
31+import Development.Shake hiding (Diagnostic, Env, newCache)
32+import Development.IDE.Types.LSP as Compiler
33+
34+import UniqSupply
35+
36+import Development.IDE.State.Shake
37+
38+
39+-- | Environment threaded through the Shake actions.
40+data Env = Env
41+ { envOptions :: IdeOptions
42+ -- ^ Compiler options.
43+ , envOfInterestVar :: Var (Set FilePath)
44+ -- ^ The files of interest.
45+ , envUniqSupplyVar :: Var UniqSupply
46+ -- ^ The unique supply of names used by the compiler.
47+ }
48+instance IsIdeGlobal Env
49+
50+
51+mkEnv :: IdeOptions -> IO Env
52+mkEnv options = do
53+ ofInterestVar <- newVar Set.empty
54+ uniqSupplyVar <- mkSplitUniqSupply 'a' >>= newVar
55+ return Env
56+ { envOptions = options
57+ , envOfInterestVar = ofInterestVar
58+ , envUniqSupplyVar = uniqSupplyVar
59+ }
60+
61+getDiagnostics :: IdeState -> IO [FileDiagnostic]
62+getDiagnostics = getAllDiagnostics
63+
64+unsafeClearDiagnostics :: IdeState -> IO ()
65+unsafeClearDiagnostics = unsafeClearAllDiagnostics
66+
67+
68+------------------------------------------------------------
69+-- Exposed API
70+
71+-- | Initialise the Compiler Service.
72+initialise :: Rules ()
73+ -> Maybe (Event -> IO ())
74+ -> Logger.Handle
75+ -> IdeOptions
76+ -> IO IdeState
77+initialise mainRule toDiags logger options =
78+ shakeOpen
79+ (fromMaybe (const $ pure ()) toDiags)
80+ logger
81+ (setProfiling options $
82+ shakeOptions { shakeThreads = optThreads options
83+ , shakeFiles = "/dev/null"
84+ }) $ do
85+ addIdeGlobal =<< liftIO (mkEnv options)
86+ fileStoreRules
87+ mainRule
88+
89+writeProfile :: IdeState -> FilePath -> IO ()
90+writeProfile = shakeProfile
91+
92+setProfiling :: IdeOptions -> ShakeOptions -> ShakeOptions
93+setProfiling opts shakeOpts =
94+ maybe shakeOpts (\p -> shakeOpts { shakeReport = [p], shakeTimings = True }) (optShakeProfiling opts)
95+
96+-- | Shutdown the Compiler Service.
97+shutdown :: IdeState -> IO ()
98+shutdown = shakeShut
99+
100+-- | Run a single action using the supplied service.
101+runAction :: IdeState -> Action a -> IO a
102+runAction service action = head <$> runActions service [action]
103+
104+-- | Run a list of actions in parallel using the supplied service.
105+runActions :: IdeState -> [Action a] -> IO [a]
106+runActions x = join . shakeRun x
107+
108+
109+-- | Set the files-of-interest which will be built and kept-up-to-date.
110+setFilesOfInterest :: IdeState -> Set FilePath -> IO ()
111+setFilesOfInterest state files = do
112+ Env{..} <- getIdeGlobalState state
113+ -- update vars synchronously
114+ modifyVar_ envOfInterestVar $ const $ return files
115+
116+ -- run shake to update results regarding the files of interest
117+ void $ shakeRun state []
118+
119+getServiceEnv :: Action Env
120+getServiceEnv = getIdeGlobalAction
src/Development/IDE/State/Shake.hsnew file+426
@@ -0,0 +1,426 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# LANGUAGE ExistentialQuantification #-}
5+{-# LANGUAGE TypeFamilies #-}
6+{-# LANGUAGE ConstraintKinds #-}
7+{-# LANGUAGE DuplicateRecordFields #-}
8+{-# LANGUAGE OverloadedStrings #-}
9+
10+-- | A Shake implementation of the compiler service.
11+--
12+-- There are two primary locations where data lives, and both of
13+-- these contain much the same data:
14+--
15+-- * The Shake database (inside 'shakeDb') stores a map of shake keys
16+-- to shake values. In our case, these are all of type 'Q' to 'A'.
17+-- During a single run all the values in the Shake database are consistent
18+-- so are used in conjunction with each other, e.g. in 'uses'.
19+--
20+-- * The 'Values' type stores a map of keys to values. These values are
21+-- always stored as real Haskell values, whereas Shake serialises all 'A' values
22+-- between runs. To deserialise a Shake value, we just consult Values.
23+-- Additionally, Values can be used in an inconsistent way, for example
24+-- useStale.
25+module Development.IDE.State.Shake(
26+ IdeState,
27+ IdeRule, IdeResult,
28+ shakeOpen, shakeShut,
29+ shakeRun,
30+ shakeProfile,
31+ useStale,
32+ use, uses,
33+ use_, uses_,
34+ define, defineEarlyCutoff,
35+ getAllDiagnostics, unsafeClearAllDiagnostics,
36+ reportSeriousError, reportSeriousErrorDie,
37+ IsIdeGlobal, addIdeGlobal, getIdeGlobalState, getIdeGlobalAction,
38+ garbageCollect,
39+ setPriority,
40+ sendEvent,
41+ Development.IDE.State.Shake.logDebug,
42+ Development.IDE.State.Shake.logSeriousError,
43+ ) where
44+
45+import Development.Shake
46+import Development.Shake.Database
47+import Development.Shake.Classes
48+import Development.Shake.Rule
49+import qualified Data.HashMap.Strict as Map
50+import qualified Data.ByteString.Char8 as BS
51+import Data.Dynamic
52+import Data.Maybe
53+import Data.Either
54+import Data.List.Extra
55+import qualified Data.Text as T
56+import Development.IDE.Logger as Logger
57+import Development.IDE.Types.LSP
58+import Development.IDE.Types.Diagnostics
59+import Control.Concurrent.Extra
60+import Control.Exception
61+import Control.DeepSeq
62+import System.Time.Extra
63+import Data.Typeable
64+import Data.Tuple.Extra
65+import System.Directory
66+import System.FilePath
67+import qualified Development.Shake as Shake
68+import Control.Monad.Extra
69+import qualified Data.Set as Set
70+import Data.Time
71+import System.IO.Unsafe
72+import Numeric.Extra
73+
74+
75+
76+-- information we stash inside the shakeExtra field
77+data ShakeExtras = ShakeExtras
78+ {eventer :: Event -> IO ()
79+ ,logger :: Logger.Handle
80+ ,globals :: Var (Map.HashMap TypeRep Dynamic)
81+ ,state :: Var Values
82+ }
83+
84+getShakeExtras :: Action ShakeExtras
85+getShakeExtras = do
86+ Just x <- getShakeExtra @ShakeExtras
87+ return x
88+
89+getShakeExtrasRules :: Rules ShakeExtras
90+getShakeExtrasRules = do
91+ Just x <- getShakeExtraRules @ShakeExtras
92+ return x
93+
94+
95+
96+class Typeable a => IsIdeGlobal a where
97+
98+addIdeGlobal :: IsIdeGlobal a => a -> Rules ()
99+addIdeGlobal x@(typeOf -> ty) = do
100+ ShakeExtras{globals} <- getShakeExtrasRules
101+ liftIO $ modifyVar_ globals $ \mp -> case Map.lookup ty mp of
102+ Just _ -> error $ "Can't addIdeGlobal twice on the same type, got " ++ show ty
103+ Nothing -> return $! Map.insert ty (toDyn x) mp
104+
105+
106+getIdeGlobalExtras :: forall a . IsIdeGlobal a => ShakeExtras -> IO a
107+getIdeGlobalExtras ShakeExtras{globals} = do
108+ Just x <- Map.lookup (typeRep (Proxy :: Proxy a)) <$> readVar globals
109+ return $ fromDyn x $ error "Serious error, corrupt globals"
110+
111+getIdeGlobalAction :: forall a . IsIdeGlobal a => Action a
112+getIdeGlobalAction = liftIO . getIdeGlobalExtras =<< getShakeExtras
113+
114+getIdeGlobalState :: forall a . IsIdeGlobal a => IdeState -> IO a
115+getIdeGlobalState = getIdeGlobalExtras . shakeExtras
116+
117+
118+-- | The state of the all values - nested so you can easily find all errors at a given file.
119+type Values =
120+ Map.HashMap FilePath
121+ (Map.HashMap Key
122+ (IdeResult Dynamic)
123+ )
124+
125+
126+-- | Key type
127+data Key = forall k . (Typeable k, Hashable k, Eq k, Show k) => Key k
128+
129+instance Show Key where
130+ show (Key k) = show k
131+
132+instance Eq Key where
133+ Key k1 == Key k2 | Just k2' <- cast k2 = k1 == k2'
134+ | otherwise = False
135+
136+instance Hashable Key where
137+ hashWithSalt salt (Key key) = hashWithSalt salt key
138+
139+-- | The result of an IDE operation. Warnings and errors are in the Diagnostic,
140+-- and a value is in the Maybe. For operations that throw an error you
141+-- expect a non-empty list of diagnostics, at least one of which is an error,
142+-- and a Nothing. For operations that succeed you expect perhaps some warnings
143+-- and a Just. For operations that depend on other failing operations you may
144+-- get empty diagnostics and a Nothing, to indicate this phase throws no fresh
145+-- errors but still failed.
146+--
147+-- A rule on a file should only return diagnostics for that given file. It should
148+-- not propagate diagnostic errors through multiple phases.
149+type IdeResult v = ([FileDiagnostic], Maybe v)
150+
151+type IdeRule k v =
152+ ( Shake.RuleResult k ~ v
153+ , Show k
154+ , Typeable k
155+ , NFData k
156+ , Hashable k
157+ , Eq k
158+ , Show v
159+ , Typeable v
160+ , NFData v
161+ )
162+
163+
164+-- | A Shake database plus persistent store. Can be thought of as storing
165+-- mappings from @(FilePath, k)@ to @RuleResult k@.
166+data IdeState = IdeState
167+ {shakeDb :: ShakeDatabase
168+ ,shakeAbort :: Var (IO ()) -- close whoever was running last
169+ ,shakeClose :: IO ()
170+ ,shakeExtras :: ShakeExtras
171+ }
172+
173+
174+profileDir :: Maybe FilePath
175+profileDir = Nothing -- set to Just the directory you want profile reports to appear in
176+
177+
178+-- This is debugging code that generates a series of profiles, if the Boolean is true
179+shakeRunDatabaseProfile :: ShakeDatabase -> [Action a] -> IO [a]
180+shakeRunDatabaseProfile shakeDb acts = do
181+ (time, (res,_)) <- duration $ shakeRunDatabase shakeDb acts
182+ whenJust profileDir $ \dir -> do
183+ count <- modifyVar profileCounter $ \x -> let y = x+1 in return (y,y)
184+ let file = "ide-" ++ profileStartTime ++ "-" ++ takeEnd 5 ("0000" ++ show count) ++ "-" ++ showDP 2 time <.> "html"
185+ shakeProfileDatabase shakeDb $ dir </> file
186+ return res
187+ where
188+
189+{-# NOINLINE profileStartTime #-}
190+profileStartTime :: String
191+profileStartTime = unsafePerformIO $ formatTime defaultTimeLocale "%Y%m%d-%H%M%S" <$> getCurrentTime
192+
193+{-# NOINLINE profileCounter #-}
194+profileCounter :: Var Int
195+profileCounter = unsafePerformIO $ newVar 0
196+
197+setValues :: IdeRule k v
198+ => Var Values
199+ -> k
200+ -> FilePath
201+ -> IdeResult v
202+ -> IO (Maybe [FileDiagnostic], [FileDiagnostic]) -- ^ (before, after)
203+setValues state key file val = modifyVar state $ \inVal -> do
204+ let k = Key key
205+ outVal = Map.insertWith Map.union file (Map.singleton k $ second (fmap toDyn) val) inVal
206+ f = concatMap fst . Map.elems
207+ return (outVal, (f <$> Map.lookup file inVal, f $ outVal Map.! file))
208+
209+-- | The outer Maybe is Nothing if this function hasn't been computed before
210+-- the inner Maybe is Nothing if the result of the previous computation failed to produce
211+-- a value
212+getValues :: forall k v. IdeRule k v => Var Values -> k -> FilePath -> IO (Maybe (Maybe v))
213+getValues state key file = do
214+ vs <- readVar state
215+ return $ do
216+ f <- Map.lookup file vs
217+ v <- Map.lookup (Key key) f
218+ pure $ fmap (fromJust . fromDynamic @v) $ snd v
219+
220+-- | Open a 'IdeState', should be shut using 'shakeShut'.
221+shakeOpen :: (Event -> IO ()) -- ^ diagnostic handler
222+ -> Logger.Handle
223+ -> ShakeOptions
224+ -> Rules ()
225+ -> IO IdeState
226+shakeOpen diags shakeLogger opts rules = do
227+ shakeExtras <- ShakeExtras diags shakeLogger <$> newVar Map.empty <*> newVar Map.empty
228+ (shakeDb, shakeClose) <- shakeOpenDatabase opts{shakeExtra = addShakeExtra shakeExtras $ shakeExtra opts} rules
229+ shakeAbort <- newVar $ return ()
230+ shakeDb <- shakeDb
231+ return IdeState{..}
232+
233+shakeProfile :: IdeState -> FilePath -> IO ()
234+shakeProfile IdeState{..} = shakeProfileDatabase shakeDb
235+
236+shakeShut :: IdeState -> IO ()
237+shakeShut = shakeClose
238+
239+-- | Spawn immediately, add an action to collect the results syncronously.
240+-- If you are already inside a call to shakeRun that will be aborted with an exception.
241+shakeRun :: IdeState -> [Action a] -> IO (IO [a])
242+-- FIXME: If there is already a shakeRun queued up and waiting to send me a kill, I should probably
243+-- not even start, which would make issues with async exceptions less problematic.
244+shakeRun IdeState{shakeExtras=ShakeExtras{..}, ..} acts = modifyVar shakeAbort $ \stop -> do
245+ (stopTime,_) <- duration stop
246+ Logger.logDebug logger $ T.pack $ "Starting shakeRun (aborting the previous one took " ++ showDuration stopTime ++ ")"
247+ bar <- newBarrier
248+ start <- offsetTime
249+ thread <- forkFinally (shakeRunDatabaseProfile shakeDb acts) $ \res -> do
250+ signalBarrier bar res
251+ runTime <- start
252+ Logger.logDebug logger $ T.pack $
253+ "Finishing shakeRun (took " ++ showDuration runTime ++ ", " ++ (if isLeft res then "exception" else "completed") ++ ")"
254+ -- important: we send an async exception to the thread, then wait for it to die, before continuing
255+ return (do killThread thread; void $ waitBarrier bar, either throwIO return =<< waitBarrier bar)
256+
257+-- | Use the last stale value, if it's ever been computed.
258+useStale
259+ :: IdeRule k v
260+ => IdeState -> k -> FilePath -> IO (Maybe v)
261+useStale IdeState{shakeExtras=ShakeExtras{state}} k fp =
262+ join <$> getValues state k fp
263+
264+
265+getAllDiagnostics :: IdeState -> IO [FileDiagnostic]
266+getAllDiagnostics IdeState{shakeExtras = ShakeExtras{state}} = do
267+ val <- readVar state
268+ return $ concatMap (concatMap fst . Map.elems) $ Map.elems val
269+
270+-- | FIXME: This function is temporary! Only required because the files of interest doesn't work
271+unsafeClearAllDiagnostics :: IdeState -> IO ()
272+unsafeClearAllDiagnostics IdeState{shakeExtras = ShakeExtras{state}} = modifyVar_ state $
273+ return . Map.map (Map.map (\(_, x) -> ([], x)))
274+
275+-- | Clear the results for all files that do not match the given predicate.
276+garbageCollect :: (FilePath -> Bool) -> Action ()
277+garbageCollect keep = do
278+ ShakeExtras{state} <- getShakeExtras
279+ liftIO $ modifyVar_ state $ return . Map.filterWithKey (\file _ -> keep file)
280+
281+define
282+ :: IdeRule k v
283+ => (k -> FilePath -> Action (IdeResult v)) -> Rules ()
284+define op = defineEarlyCutoff $ \k v -> (Nothing,) <$> op k v
285+
286+use :: IdeRule k v
287+ => k -> FilePath -> Action (Maybe v)
288+use key file = head <$> uses key [file]
289+
290+use_ :: IdeRule k v => k -> FilePath -> Action v
291+use_ key file = head <$> uses_ key [file]
292+
293+uses_ :: IdeRule k v => k -> [FilePath] -> Action [v]
294+uses_ key files = do
295+ res <- uses key files
296+ case sequence res of
297+ Nothing -> liftIO $ throwIO BadDependency
298+ Just v -> return v
299+
300+reportSeriousError :: String -> Action ()
301+reportSeriousError t = do
302+ ShakeExtras{logger} <- getShakeExtras
303+ liftIO $ Logger.logSeriousError logger $ T.pack t
304+
305+reportSeriousErrorDie :: String -> Action a
306+reportSeriousErrorDie t = do
307+ ShakeExtras{logger} <- getShakeExtras
308+ liftIO $ Logger.logSeriousError logger $ T.pack t
309+ fail t
310+
311+
312+-- | When we depend on something that reported an error, and we fail as a direct result, throw BadDependency
313+-- which short-circuits the rest of the action
314+data BadDependency = BadDependency deriving Show
315+instance Exception BadDependency
316+
317+isBadDependency :: SomeException -> Bool
318+isBadDependency x
319+ | Just (x :: ShakeException) <- fromException x = isBadDependency $ shakeExceptionInner x
320+ | Just (_ :: BadDependency) <- fromException x = True
321+ | otherwise = False
322+
323+
324+newtype Q k = Q (k, FilePath)
325+ deriving (Eq,Hashable,NFData)
326+
327+-- Using Database we don't need Binary instances for keys
328+instance Binary (Q k) where
329+ put _ = return ()
330+ get = fail "Binary.get not defined for type Development.IDE.State.Shake.Q"
331+
332+instance Show k => Show (Q k) where
333+ show (Q (k, file)) = show k ++ "; " ++ file
334+
335+-- | Invariant: the 'v' must be in normal form (fully evaluated).
336+-- Otherwise we keep repeatedly 'rnf'ing values taken from the Shake database
337+data A v = A (Maybe v) (Maybe BS.ByteString)
338+ deriving Show
339+
340+instance NFData (A v) where rnf (A v x) = v `seq` rnf x
341+
342+-- In the Shake database we only store one type of key/result pairs,
343+-- namely Q (question) / A (answer).
344+type instance RuleResult (Q k) = A (RuleResult k)
345+
346+
347+-- | Compute the value
348+uses :: IdeRule k v
349+ => k -> [FilePath] -> Action [Maybe v]
350+uses key files = map (\(A value _) -> value) <$> apply (map (Q . (key,)) files)
351+
352+defineEarlyCutoff
353+ :: IdeRule k v
354+ => (k -> FilePath -> Action (Maybe BS.ByteString, IdeResult v))
355+ -> Rules ()
356+defineEarlyCutoff op = addBuiltinRule noLint noIdentity $ \(Q (key, file)) old mode -> do
357+ ShakeExtras{state} <- getShakeExtras
358+ val <- case old of
359+ Just old | mode == RunDependenciesSame -> do
360+ v <- liftIO $ getValues state key file
361+ case v of
362+ Just v -> return $ Just $ RunResult ChangedNothing old $ A v (unwrap old)
363+ _ -> return Nothing
364+ _ -> return Nothing
365+ case val of
366+ Just res -> return res
367+ Nothing -> do
368+ (bs, res) <- actionCatch
369+ (do v <- op key file; liftIO $ evaluate $ force v) $
370+ \(e :: SomeException) -> pure (Nothing, ([ideErrorText file $ T.pack $ show e | not $ isBadDependency e],Nothing))
371+ res <- return $ first (map $ \(_,d) -> (file,d)) res
372+
373+ (before, after) <- liftIO $ setValues state key file res
374+ updateFileDiagnostics file before after
375+ let eq = case (bs, fmap unwrap old) of
376+ (Just a, Just (Just b)) -> a == b
377+ _ -> False
378+ return $ RunResult
379+ (if eq then ChangedRecomputeSame else ChangedRecomputeDiff)
380+ (wrap bs)
381+ $ A (snd res) bs
382+ where
383+ wrap = maybe BS.empty (BS.cons '_')
384+ unwrap x = if BS.null x then Nothing else Just $ BS.tail x
385+
386+
387+updateFileDiagnostics ::
388+ FilePath
389+ -> Maybe [FileDiagnostic] -- ^ previous results for this file
390+ -> [FileDiagnostic] -- ^ current results
391+ -> Action ()
392+updateFileDiagnostics afp previousAll currentAll = do
393+ -- TODO (MK) We canonicalize to make sure that the two files agree on use of
394+ -- / and \ and other shenanigans.
395+ -- Once we have finished the migration to haskell-lsp we should make sure that
396+ -- this is no longer necessary.
397+ afp' <- liftIO $ canonicalizePath afp
398+ let filtM diags = do
399+ diags' <-
400+ filterM
401+ (\x -> fmap (== afp') (canonicalizePath $ fst x))
402+ diags
403+ pure (Set.fromList diags')
404+ previous <- liftIO $ traverse filtM previousAll
405+ current <- liftIO $ filtM currentAll
406+ when (Just current /= previous) $
407+ sendEvent $ EventFileDiagnostics $ (afp, map snd $ Set.toList current)
408+
409+
410+setPriority :: (Enum a) => a -> Action ()
411+setPriority p =
412+ deprioritize (fromIntegral . negate $ fromEnum p)
413+
414+sendEvent :: Event -> Action ()
415+sendEvent e = do
416+ ShakeExtras{eventer} <- getShakeExtras
417+ liftIO $ eventer e
418+
419+-- | bit of an odd signature because we're trying to remove priority
420+sl :: (Handle -> T.Text -> IO ()) -> IdeState -> T.Text -> IO ()
421+sl f IdeState{shakeExtras=ShakeExtras{logger}} p = f logger p
422+
423+logDebug, logSeriousError
424+ :: IdeState -> T.Text -> IO ()
425+logDebug = sl Logger.logDebug
426+logSeriousError = sl Logger.logSeriousError
src/Development/IDE/Types/Diagnostics.hs+128−84
@@ -1,74 +1,126 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
4−
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE DuplicateRecordFields #-}
7+{-# LANGUAGE BlockArguments #-}
58module Development.IDE.Types.Diagnostics (
69 LSP.Diagnostic(..),
7− ShowDiagnostic(..),
10+ FileDiagnostics,
811 FileDiagnostic,
9− IdeResult,
12+ Location(..),
13+ Range(..),
1014 LSP.DiagnosticSeverity(..),
15+ Position(..),
1116 DiagnosticStore,
17+ DiagnosticRelatedInformation(..),
1218 List(..),
19+ StoreItem(..),
20+ Uri(..),
21+ noLocation,
22+ noRange,
23+ noFilePath,
1324 ideErrorText,
14− ideErrorWithSource,
25+ ideErrorPretty,
26+ errorDiag,
27+ ideTryIOException,
1528 showDiagnostics,
1629 showDiagnosticsColored,
30+ prettyDiagnosticStore,
31+ defDiagnostic,
32+ addDiagnostics,
33+ filterSeriousErrors,
34+ filePathToUri,
35+ getDiagnosticsFromStore
1736 ) where
1837
19−import Control.DeepSeq
38+import Control.Exception
39+import Data.Either.Combinators
2040import Data.Maybe as Maybe
41+import Data.Foldable
42+import qualified Data.Map as Map
2143import qualified Data.Text as T
22−import Data.Text.Prettyprint.Doc
23−import Language.Haskell.LSP.Types as LSP (DiagnosticSource,
44+import Data.Text.Prettyprint.Doc.Syntax
45+import qualified Text.PrettyPrint.Annotated.HughesPJClass as Pretty
46+import Language.Haskell.LSP.Types as LSP (
2447 DiagnosticSeverity(..)
2548 , Diagnostic(..)
49+ , filePathToUri
50+ , uriToFilePath
2651 , List(..)
52+ , DiagnosticRelatedInformation(..)
53+ , Uri(..)
2754 )
2855import Language.Haskell.LSP.Diagnostics
29−import Data.Text.Prettyprint.Doc.Render.Text
30−import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Terminal
31−import Data.Text.Prettyprint.Doc.Render.Terminal (Color(..), color)
3256
3357import Development.IDE.Types.Location
3458
35−-- A rule on a file should only return diagnostics for that given file. It should
36−-- not propagate diagnostic errors through multiple phases.
37−type IdeResult v = ([FileDiagnostic], Maybe v)
38−
39−ideErrorText :: NormalizedFilePath -> T.Text -> FileDiagnostic
40−ideErrorText = ideErrorWithSource (Just "compiler") (Just DsError)
41−
42−ideErrorWithSource
43− :: Maybe DiagnosticSource
44− -> Maybe DiagnosticSeverity
45− -> a
46− -> T.Text
47− -> (a, ShowDiagnostic, Diagnostic)
48−ideErrorWithSource source sev fp msg = (fp, ShowDiag, LSP.Diagnostic {
49− _range = noRange,
50− _severity = sev,
51− _code = Nothing,
52− _source = source,
53− _message = msg,
54− _relatedInformation = Nothing,
55− _tags = Nothing
56− })
57−
58−-- | Defines whether a particular diagnostic should be reported
59−-- back to the user.
60−--
61−-- One important use case is "missing signature" code lenses,
62−-- for which we need to enable the corresponding warning during
63−-- type checking. However, we do not want to show the warning
64−-- unless the programmer asks for it (#261).
65−data ShowDiagnostic
66− = ShowDiag -- ^ Report back to the user
67− | HideDiag -- ^ Hide from user
68− deriving (Eq, Ord, Show)
69−
70−instance NFData ShowDiagnostic where
71− rnf = rwhnf
59+ideErrorText :: FilePath -> T.Text -> FileDiagnostic
60+ideErrorText fp = errorDiag fp "Ide Error"
61+
62+ideErrorPretty :: Pretty.Pretty e => FilePath -> e -> FileDiagnostic
63+ideErrorPretty fp = ideErrorText fp . T.pack . Pretty.prettyShow
64+
65+errorDiag :: FilePath -> T.Text -> T.Text -> FileDiagnostic
66+errorDiag fp src msg =
67+ (fp, diagnostic noRange LSP.DsError src msg)
68+
69+-- | This is for compatibility with our old diagnostic type
70+diagnostic :: Range
71+ -> LSP.DiagnosticSeverity
72+ -> T.Text -- ^ source
73+ -> T.Text -- ^ message
74+ -> LSP.Diagnostic
75+diagnostic rng sev src msg
76+ = LSP.Diagnostic {
77+ _range = rng,
78+ _severity = Just sev,
79+ _code = Nothing,
80+ _source = Just src,
81+ _message = msg,
82+ _relatedInformation = Nothing
83+ }
84+
85+-- | Any optional field is instantiated to Nothing
86+defDiagnostic ::
87+ Range ->
88+ T.Text -> -- ^ error message
89+ LSP.Diagnostic
90+defDiagnostic _range _message = LSP.Diagnostic {
91+ _range
92+ , _message
93+ , _severity = Nothing
94+ , _code = Nothing
95+ , _source = Nothing
96+ , _relatedInformation = Nothing
97+ }
98+
99+filterSeriousErrors ::
100+ FilePath ->
101+ [LSP.Diagnostic] ->
102+ [LSP.Diagnostic]
103+filterSeriousErrors fp =
104+ filter (maybe False hasSeriousErrors . LSP._relatedInformation)
105+ where
106+ hasSeriousErrors :: List DiagnosticRelatedInformation -> Bool
107+ hasSeriousErrors (List a) = any ((/=) uri . _uri . _location) a
108+ uri = LSP.filePathToUri fp
109+
110+addDiagnostics ::
111+ FilePath ->
112+ [LSP.Diagnostic] ->
113+ DiagnosticStore -> DiagnosticStore
114+addDiagnostics fp diags ds =
115+ updateDiagnostics
116+ ds
117+ (LSP.filePathToUri fp)
118+ Nothing $
119+ partitionBySource diags
120+
121+ideTryIOException :: FilePath -> IO a -> IO (Either FileDiagnostic a)
122+ideTryIOException fp act =
123+ mapLeft (\(e :: IOException) -> ideErrorText fp $ T.pack $ show e) <$> try act
72124
73125-- | Human readable diagnostics for a specific file.
74126--
@@ -76,9 +128,10 @@ instance NFData ShowDiagnostic where
76128-- along with the related source location so that we can display the error
77129-- on either the console or in the IDE at the right source location.
78130--
79−type FileDiagnostic = (NormalizedFilePath, ShowDiagnostic, Diagnostic)
131+type FileDiagnostics = (FilePath, [Diagnostic])
132+type FileDiagnostic = (FilePath, Diagnostic)
80133
81−prettyRange :: Range -> Doc Terminal.AnsiStyle
134+prettyRange :: Range -> Doc SyntaxClass
82135prettyRange Range{..} = f _start <> "-" <> f _end
83136 where f Position{..} = pretty (_line+1) <> colon <> pretty _character
84137
@@ -92,51 +145,42 @@ showDiagnosticsColored :: [FileDiagnostic] -> T.Text
92145showDiagnosticsColored = srenderColored . prettyDiagnostics
93146
94147
95−prettyDiagnostics :: [FileDiagnostic] -> Doc Terminal.AnsiStyle
148+prettyDiagnostics :: [FileDiagnostic] -> Doc SyntaxClass
96149prettyDiagnostics = vcat . map prettyDiagnostic
97150
98−prettyDiagnostic :: FileDiagnostic -> Doc Terminal.AnsiStyle
99−prettyDiagnostic (fp, sh, LSP.Diagnostic{..}) =
151+prettyDiagnostic :: FileDiagnostic -> Doc SyntaxClass
152+prettyDiagnostic (fp, LSP.Diagnostic{..}) =
100153 vcat
101− [ slabel_ "File: " $ pretty (fromNormalizedFilePath fp)
102− , slabel_ "Hidden: " $ if sh == ShowDiag then "no" else "yes"
154+ [ slabel_ "File: " $ pretty fp
103155 , slabel_ "Range: " $ prettyRange _range
104156 , slabel_ "Source: " $ pretty _source
105157 , slabel_ "Severity:" $ pretty $ show sev
106158 , slabel_ "Message: "
107159 $ case sev of
108− LSP.DsError -> annotate $ color Red
109− LSP.DsWarning -> annotate $ color Yellow
110− LSP.DsInfo -> annotate $ color Blue
111− LSP.DsHint -> annotate $ color Magenta
160+ LSP.DsError -> annotate ErrorSC
161+ LSP.DsWarning -> annotate WarningSC
162+ LSP.DsInfo -> annotate InfoSC
163+ LSP.DsHint -> annotate HintSC
112164 $ stringParagraphs _message
165+ , slabel_ "Code:" $ pretty _code
113166 ]
114167 where
115168 sev = fromMaybe LSP.DsError _severity
116169
170+prettyDiagnosticStore :: DiagnosticStore -> Doc SyntaxClass
171+prettyDiagnosticStore ds =
172+ vcat $
173+ map (\(uri, diags) -> prettyFileDiagnostics (fromMaybe noFilePath $ uriToFilePath uri, diags)) $
174+ Map.assocs $
175+ Map.map getDiagnosticsFromStore ds
176+
177+prettyFileDiagnostics :: FileDiagnostics -> Doc SyntaxClass
178+prettyFileDiagnostics (filePath, diags) =
179+ slabel_ "Compiler error in" $ vcat
180+ [ slabel_ "File:" $ pretty filePath
181+ , slabel_ "Errors:" $ vcat $ map (prettyDiagnostic . (filePath,)) diags
182+ ]
117183
118−-- | Label a document.
119−slabel_ :: String -> Doc a -> Doc a
120−slabel_ t d = nest 2 $ sep [pretty t, d]
121−
122−-- | The layout options used for the SDK assistant.
123−cliLayout ::
124− Int
125− -- ^ Rendering width of the pretty printer.
126− -> LayoutOptions
127−cliLayout renderWidth = LayoutOptions
128− { layoutPageWidth = AvailablePerLine renderWidth 0.9
129− }
130−
131−-- | Render without any syntax annotations
132−srenderPlain :: Doc ann -> T.Text
133−srenderPlain = renderStrict . layoutSmart (cliLayout defaultTermWidth)
134−
135−-- | Render a 'Document' as an ANSII colored string.
136−srenderColored :: Doc Terminal.AnsiStyle -> T.Text
137−srenderColored =
138− Terminal.renderStrict .
139− layoutSmart defaultLayoutOptions { layoutPageWidth = AvailablePerLine 100 1.0 }
140−
141−defaultTermWidth :: Int
142−defaultTermWidth = 80
184+getDiagnosticsFromStore :: StoreItem -> [Diagnostic]
185+getDiagnosticsFromStore (StoreItem _ diags) =
186+ toList =<< Map.elems diags
src/Development/IDE/Types/LSP.hsnew file+61
@@ -0,0 +1,61 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+module Development.IDE.Types.LSP
5+ ( HoverText(..)
6+ , Event(..)
7+ , VirtualResource(..)
8+ , getHoverTextContent
9+ ) where
10+
11+import Control.DeepSeq
12+import qualified Data.Text as T
13+import GHC.Generics
14+
15+import Development.IDE.Types.Diagnostics
16+
17+-- | Different types of content we can show on hover.
18+data HoverText
19+ = HoverHeading !T.Text
20+ -- ^ A header that explains the content below it.
21+ | HoverDamlCode !T.Text
22+ -- ^ Highlighted DAML-Code
23+ | HoverMarkdown !T.Text
24+ -- ^ Markdown text.
25+ deriving Show
26+
27+getHoverTextContent :: HoverText -> T.Text
28+getHoverTextContent = \case
29+ HoverHeading t -> t
30+ HoverDamlCode t -> t
31+ HoverMarkdown t -> t
32+
33+-- | Virtual resources
34+data VirtualResource = VRScenario
35+ { vrScenarioFile :: !FilePath
36+ , vrScenarioName :: !T.Text
37+ } deriving (Eq, Ord, Read, Show, Generic)
38+ -- ^ VRScenario identifies a scenario in a given file.
39+ -- This virtual resource is associated with the HTML result of
40+ -- interpreting the corresponding scenario.
41+
42+instance NFData VirtualResource
43+
44+-- | Compiler service events
45+data Event
46+ = EventFileDiagnostics !FileDiagnostics
47+ -- ^ @EventFileDiagnostics fileDiagnostics@
48+ -- How many validations have we finished of how many total
49+ -- together with new file diagnostics for a given file.
50+ | EventVirtualResourceChanged !VirtualResource T.Text
51+ -- ^ @EventVirtualResourceChanged resource contents@ a virtual
52+ -- resource @resource@ changed to @contents
53+ -- NOTE(JM,MH): Keep the contents lazy as we rely on it in
54+ -- 'manageOpenVRs'.
55+ | EventFileValidation Int Int
56+ -- ^ @EventFileValidation finishedValidations totalValidations @
57+ -- How many validations have we finished of how many total.
58+ | EventFatalError !T.Text
59+ -- ^ @EventFatalError reason@: A fatal error occurred in the compiler and
60+ -- the compiler cannot continue.
61+ deriving Show
src/Development/IDE/Types/Location.hs+59−93
@@ -1,68 +1,32 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
4+{-# LANGUAGE OverloadedStrings #-}
45
56-- | Types and functions for working with source code locations.
67module Development.IDE.Types.Location
7− ( Location(..)
8+ ( genLocation
9+ , inRange
10+ , inRangeClosed
11+ , isGenLocation
12+ , Location(..)
13+ , appendLocation
14+ , noLocation
815 , noFilePath
916 , noRange
1017 , Position(..)
11− , showPosition
1218 , Range(..)
13− , LSP.Uri(..)
14− , LSP.NormalizedUri
15− , LSP.toNormalizedUri
16− , LSP.fromNormalizedUri
17− , LSP.NormalizedFilePath
18− , fromUri
19− , emptyFilePath
20− , emptyPathUri
21− , toNormalizedFilePath'
22− , LSP.fromNormalizedFilePath
23− , filePathToUri'
24− , uriToFilePath'
25− , readSrcSpan
19+ , appendRange
2620 ) where
2721
28−import Control.Applicative
29−import Language.Haskell.LSP.Types (Location(..), Range(..), Position(..))
30−import Control.Monad
31−import Data.Hashable (Hashable(hash))
32−import Data.String
33−import FastString
34−import qualified Language.Haskell.LSP.Types as LSP
35−import SrcLoc as GHC
36−import Text.ParserCombinators.ReadP as ReadP
37−import Data.Maybe (fromMaybe)
38−
39−toNormalizedFilePath' :: FilePath -> LSP.NormalizedFilePath
40−-- We want to keep empty paths instead of normalising them to "."
41−toNormalizedFilePath' "" = emptyFilePath
42−toNormalizedFilePath' fp = LSP.toNormalizedFilePath fp
43−
44−emptyFilePath :: LSP.NormalizedFilePath
45−emptyFilePath = LSP.NormalizedFilePath emptyPathUri ""
46−
47−-- | We use an empty string as a filepath when we don’t have a file.
48−-- However, haskell-lsp doesn’t support that in uriToFilePath and given
49−-- that it is not a valid filepath it does not make sense to upstream a fix.
50−-- So we have our own wrapper here that supports empty filepaths.
51−uriToFilePath' :: LSP.Uri -> Maybe FilePath
52−uriToFilePath' uri
53− | uri == LSP.fromNormalizedUri emptyPathUri = Just ""
54− | otherwise = LSP.uriToFilePath uri
55−
56−emptyPathUri :: LSP.NormalizedUri
57−emptyPathUri =
58− let s = "file://"
59− in LSP.NormalizedUri (hash s) s
60−
61−filePathToUri' :: LSP.NormalizedFilePath -> LSP.NormalizedUri
62−filePathToUri' = LSP.normalizedFilePathToUri
63−
64−fromUri :: LSP.NormalizedUri -> LSP.NormalizedFilePath
65−fromUri = fromMaybe (toNormalizedFilePath' noFilePath) . LSP.uriToNormalizedFilePath
22+import Language.Haskell.LSP.Types (Location(..), Range(..), Position(..), Uri(..), filePathToUri)
23+
24+-- | A dummy location to use when location information is missing.
25+noLocation :: Location
26+noLocation = Location
27+ { _uri = filePathToUri noFilePath
28+ , _range = noRange
29+ }
6630
6731noFilePath :: FilePath
6832noFilePath = "<unknown>"
@@ -71,42 +35,44 @@ noFilePath = "<unknown>"
7135noRange :: Range
7236noRange = Range (Position 0 0) (Position 100000 0)
7337
74−showPosition :: Position -> String
75−showPosition Position{..} = show (_line + 1) ++ ":" ++ show (_character + 1)
76−
77−-- | Parser for the GHC output format
78−readSrcSpan :: ReadS SrcSpan
79−readSrcSpan = readP_to_S (singleLineSrcSpanP <|> multiLineSrcSpanP)
80− where
81− singleLineSrcSpanP, multiLineSrcSpanP :: ReadP SrcSpan
82− singleLineSrcSpanP = do
83− fp <- filePathP
84− l <- readS_to_P reads <* char ':'
85− c0 <- readS_to_P reads
86− c1 <- (char '-' *> readS_to_P reads) <|> pure c0
87− let from = mkSrcLoc fp l c0
88− to = mkSrcLoc fp l c1
89− return $ mkSrcSpan from to
90−
91− multiLineSrcSpanP = do
92− fp <- filePathP
93− s <- parensP (srcLocP fp)
94− void $ char '-'
95− e <- parensP (srcLocP fp)
96− return $ mkSrcSpan s e
97−
98− parensP :: ReadP a -> ReadP a
99− parensP = between (char '(') (char ')')
100−
101− filePathP :: ReadP FastString
102− filePathP = fromString <$> (readFilePath <* char ':') <|> pure ""
103−
104− srcLocP :: FastString -> ReadP SrcLoc
105− srcLocP fp = do
106− l <- readS_to_P reads
107− void $ char ','
108− c <- readS_to_P reads
109− return $ mkSrcLoc fp l c
110−
111− readFilePath :: ReadP FilePath
112− readFilePath = some ReadP.get
38+
39+-- | A dummy location to use when location information is not present because
40+-- the code was generated.
41+genLocation :: Location
42+genLocation = Location
43+ { _uri = Uri "<generated>"
44+ , _range = Range (Position 0 0) (Position 0 0)
45+ }
46+
47+
48+-- | Is a location generated.
49+isGenLocation :: Location -> Bool
50+isGenLocation x = _uri x == Uri "<generated>"
51+
52+
53+-- | Check if a position is inside a range.
54+-- Our definition states that the start of the range is included, but not the end.
55+inRange :: Position -> Range -> Bool
56+inRange pos (Range start end) = start <= pos && pos < end
57+
58+
59+-- | Check if a position is inside a range, including the end.
60+-- Both start and end of the range are included.
61+inRangeClosed :: Position -> Range -> Bool
62+inRangeClosed pos (Range start end) = start <= pos && pos <= end
63+
64+
65+-- | Produce a new range where the minimum position is the min of both,
66+-- and the maximum position is the max of both.
67+appendRange :: Range -> Range -> Range
68+appendRange r1 r2
69+ = Range { _start = min (_start r1) (_start r2)
70+ , _end = max (_end r1) (_end r2) }
71+
72+
73+-- | Produce a new location where the ranges are the appended and we choose
74+-- the file path of the second.
75+appendLocation :: Location -> Location -> Location
76+appendLocation l1 l2
77+ = Location { _uri = _uri l2
78+ , _range = appendRange (_range l1) (_range l2) }
src/Development/IDE/Types/Logger.hsdeleted−54
@@ -1,54 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−{-# LANGUAGE RankNTypes #-}
5−-- | This is a compatibility module that abstracts over the
6−-- concrete choice of logging framework so users can plug in whatever
7−-- framework they want to.
8−module Development.IDE.Types.Logger
9− ( Priority(..)
10− , Logger(..)
11− , logError, logWarning, logInfo, logDebug, logTelemetry
12− , noLogging
13− ) where
14−
15−import qualified Data.Text as T
16−
17−
18−data Priority
19−-- Don't change the ordering of this type or you will mess up the Ord
20−-- instance
21− = Telemetry -- ^ Events that are useful for gathering user metrics.
22− | Debug -- ^ Verbose debug logging.
23− | Info -- ^ Useful information in case an error has to be understood.
24− | Warning
25− -- ^ These error messages should not occur in a expected usage, and
26− -- should be investigated.
27− | Error -- ^ Such log messages must never occur in expected usage.
28− deriving (Eq, Show, Ord, Enum, Bounded)
29−
30−
31−-- | Note that this is logging actions _of the program_, not of the user.
32−-- You shouldn't call warning/error if the user has caused an error, only
33−-- if our code has gone wrong and is itself erroneous (e.g. we threw an exception).
34−data Logger = Logger {logPriority :: Priority -> T.Text -> IO ()}
35−
36−
37−logError :: Logger -> T.Text -> IO ()
38−logError x = logPriority x Error
39−
40−logWarning :: Logger -> T.Text -> IO ()
41−logWarning x = logPriority x Warning
42−
43−logInfo :: Logger -> T.Text -> IO ()
44−logInfo x = logPriority x Info
45−
46−logDebug :: Logger -> T.Text -> IO ()
47−logDebug x = logPriority x Debug
48−
49−logTelemetry :: Logger -> T.Text -> IO ()
50−logTelemetry x = logPriority x Telemetry
51−
52−
53−noLogging :: Logger
54−noLogging = Logger $ \_ _ -> return ()
src/Development/IDE/Types/Options.hs+7−99
@@ -1,4 +1,4 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
44{-# LANGUAGE RankNTypes #-}
@@ -6,95 +6,27 @@
66-- | Options
77module Development.IDE.Types.Options
88 ( IdeOptions(..)
9− , IdePreprocessedSource(..)
10− , IdeReportProgress(..)
11− , IdeDefer(..)
12− , clientSupportsProgress
139 , IdePkgLocationOptions(..)
14− , defaultIdeOptions
15− , IdeResult
1610 ) where
1711
1812import Development.Shake
19−import Development.IDE.GHC.Util
2013import GHC hiding (parseModule, typecheckModule)
2114import GhcPlugins as GHC hiding (fst3, (<>))
22−import qualified Language.Haskell.LSP.Types.Capabilities as LSP
23−import qualified Data.Text as T
24−import Development.IDE.Types.Diagnostics
15+
2516
2617data IdeOptions = IdeOptions
27− { optPreprocessor :: GHC.ParsedSource -> IdePreprocessedSource
28− -- ^ Preprocessor to run over all parsed source trees, generating a list of warnings
29− -- and a list of errors, along with a new parse tree.
30− , optGhcSession :: Action (FilePath -> Action (IdeResult HscEnvEq))
31− -- ^ Setup a GHC session for a given file, e.g. @Foo.hs@.
32− -- For the same 'ComponentOptions' from hie-bios, the resulting function will be applied once per file.
33− -- It is desirable that many files get the same 'HscEnvEq', so that more IDE features work.
18+ { optPreprocessor :: GHC.ParsedSource -> ([(GHC.SrcSpan, String)], GHC.ParsedSource)
19+ , optGhcSession :: Action HscEnv
20+ -- ^ Setup a GHC session using a given package state. If a `ParsedModule` is supplied,
21+ -- the import path should be setup for that module.
3422 , optPkgLocationOpts :: IdePkgLocationOptions
35− -- ^ How to locate source and @.hie@ files given a module name.
23+ , optWriteIface :: Bool
3624 , optExtensions :: [String]
37− -- ^ File extensions to search for code, defaults to Haskell sources (including @.hs@)
3825
3926 , optThreads :: Int
40− -- ^ Number of threads to use. Use 0 for number of threads on the machine.
41− , optShakeFiles :: Maybe FilePath
42− -- ^ Directory where the shake database should be stored. For ghcide this is always set to `Nothing` for now
43− -- meaning we keep everything in memory but the daml CLI compiler uses this for incremental builds.
4427 , optShakeProfiling :: Maybe FilePath
45− -- ^ Set to 'Just' to create a directory of profiling reports.
46− , optTesting :: Bool
47− -- ^ Whether to enable additional lsp messages used by the test suite for checking invariants
48− , optReportProgress :: IdeReportProgress
49− -- ^ Whether to report progress during long operations.
50− , optLanguageSyntax :: String
51− -- ^ the ```language to use
52− , optNewColonConvention :: Bool
53− -- ^ whether to use new colon convention
54− , optKeywords :: [T.Text]
55− -- ^ keywords used for completions. These are customizable
56− -- since DAML has a different set of keywords than Haskell.
57− , optDefer :: IdeDefer
58− -- ^ Whether to defer type errors, typed holes and out of scope
59− -- variables. Deferral allows the IDE to continue to provide
60− -- features such as diagnostics and go-to-definition, in
61− -- situations in which they would become unavailable because of
62− -- the presence of type errors, holes or unbound variables.
63− }
64−
65−data IdePreprocessedSource = IdePreprocessedSource
66− { preprocWarnings :: [(GHC.SrcSpan, String)]
67− -- ^ Warnings emitted by the preprocessor.
68− , preprocErrors :: [(GHC.SrcSpan, String)]
69− -- ^ Errors emitted by the preprocessor.
70− , preprocSource :: GHC.ParsedSource
71− -- ^ New parse tree emitted by the preprocessor.
7228 }
7329
74−newtype IdeReportProgress = IdeReportProgress Bool
75−newtype IdeDefer = IdeDefer Bool
76−
77−clientSupportsProgress :: LSP.ClientCapabilities -> IdeReportProgress
78−clientSupportsProgress caps = IdeReportProgress $ Just True ==
79− (LSP._workDoneProgress =<< LSP._window (caps :: LSP.ClientCapabilities))
80−
81−defaultIdeOptions :: Action (FilePath -> Action (IdeResult HscEnvEq)) -> IdeOptions
82−defaultIdeOptions session = IdeOptions
83− {optPreprocessor = IdePreprocessedSource [] []
84− ,optGhcSession = session
85− ,optExtensions = ["hs", "lhs"]
86− ,optPkgLocationOpts = defaultIdePkgLocationOptions
87− ,optThreads = 0
88− ,optShakeFiles = Nothing
89− ,optShakeProfiling = Nothing
90− ,optReportProgress = IdeReportProgress False
91− ,optLanguageSyntax = "haskell"
92− ,optNewColonConvention = False
93− ,optKeywords = haskellKeywords
94− ,optDefer = IdeDefer True
95− ,optTesting = False
96− }
97−
9830
9931-- | The set of options used to locate files belonging to external packages.
10032data IdePkgLocationOptions = IdePkgLocationOptions
@@ -106,27 +38,3 @@ data IdePkgLocationOptions = IdePkgLocationOptions
10638 -- used to lookup settings like importDirs. For DAML, we place them in the package DB.
10739 -- For cabal this could point somewhere in ~/.cabal/packages.
10840 }
109−
110−defaultIdePkgLocationOptions :: IdePkgLocationOptions
111−defaultIdePkgLocationOptions = IdePkgLocationOptions f f
112− where f _ _ = return Nothing
113−
114−-- | From https://wiki.haskell.org/Keywords
115−haskellKeywords :: [T.Text]
116−haskellKeywords =
117− [ "as"
118− , "case", "of"
119− , "class", "instance", "type"
120− , "data", "family", "newtype"
121− , "default"
122− , "deriving"
123− , "do", "mdo", "proc", "rec"
124− , "forall"
125− , "foreign"
126− , "hiding"
127− , "if", "then", "else"
128− , "import", "qualified", "hiding"
129− , "infix", "infixl", "infixr"
130− , "let", "in", "where"
131− , "module"
132− ]
src/Development/IDE/Spans/Type.hs → src/Development/IDE/Types/SpanInfo.hsrenamed+20−34
@@ -1,77 +1,63 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
33
44-- ORIGINALLY COPIED FROM https://github.com/commercialhaskell/intero
55
66-- | Types used separate to GHCi vanilla.
77
8−module Development.IDE.Spans.Type(
9− SpansInfo(..)
10− , SpanInfo(..)
8+module Development.IDE.Types.SpanInfo(
9+ SpanInfo(..)
1110 , SpanSource(..)
1211 , getNameM
12+ , getSrcSpan
1313 ) where
1414
1515import GHC
16−import Control.DeepSeq
16+import Data.Maybe
1717import OccName
18−import Development.IDE.GHC.Util
19−import Development.IDE.Spans.Common
2018
21−data SpansInfo =
22− SpansInfo { spansExprs :: [SpanInfo]
23− , spansConstraints :: [SpanInfo] }
24− deriving Show
25−
26−instance NFData SpansInfo where
27− rnf (SpansInfo e c) = liftRnf rnf e `seq` liftRnf rnf c
2819
2920-- | Type of some span of source code. Most of these fields are
3021-- unboxed but Haddock doesn't show that.
3122data SpanInfo =
3223 SpanInfo {spaninfoStartLine :: {-# UNPACK #-} !Int
33− -- ^ Start line of the span, zero-based.
24+ -- ^ Start line of the span.
3425 ,spaninfoStartCol :: {-# UNPACK #-} !Int
35− -- ^ Start column of the span, zero-based.
26+ -- ^ Start column of the span.
3627 ,spaninfoEndLine :: {-# UNPACK #-} !Int
37− -- ^ End line of the span (absolute), zero-based.
28+ -- ^ End line of the span (absolute).
3829 ,spaninfoEndCol :: {-# UNPACK #-} !Int
39− -- ^ End column of the span (absolute), zero-based.
30+ -- ^ End column of the span (absolute).
4031 ,spaninfoType :: !(Maybe Type)
41− -- ^ A pretty-printed representation for the type.
32+ -- ^ A pretty-printed representation fo the type.
4233 ,spaninfoSource :: !SpanSource
4334 -- ^ The actutal 'Name' associated with the span, if
4435 -- any. This can be useful for accessing a variety of
4536 -- information about the identifier such as module,
4637 -- locality, definition location, etc.
47− ,spaninfoDocs :: !SpanDoc
48− -- ^ Documentation for the element
4938 }
5039instance Show SpanInfo where
51− show (SpanInfo sl sc el ec t n docs) =
52− unwords ["(SpanInfo", show sl, show sc, show el, show ec
53− , show $ maybe "NoType" prettyPrint t, "(" <> show n <> "))"
54− , "docs(" <> show docs <> ")"]
55−
56−instance NFData SpanInfo where
57− rnf = rwhnf
58−
40+ show (SpanInfo sl sc el ec t n) = show [show sl, show sc, show el, show ec, show $ isJust t, show n]
5941
6042-- we don't always get a name out so sometimes manually annotating source is more appropriate
6143data SpanSource = Named Name
62− | SpanS SrcSpan
63− | Lit String
44+ | Span SrcSpan
6445 | NoSource
6546 deriving (Eq)
6647
6748instance Show SpanSource where
6849 show = \case
6950 Named n -> "Named " ++ occNameString (occName n)
70− SpanS sp -> "Span " ++ show sp
71− Lit lit -> "Lit " ++ lit
51+ Span sp -> "Span " ++ show sp
7252 NoSource -> "NoSource"
7353
7454getNameM :: SpanSource -> Maybe Name
7555getNameM = \case
7656 Named name -> Just name
77− _ -> Nothing
57+ _ -> Nothing
58+
59+getSrcSpan :: SpanSource -> Maybe SrcSpan
60+getSrcSpan = \case
61+ NoSource -> Nothing
62+ Span sp -> Just sp
63+ Named name -> Just $ nameSrcSpan name
src/Development/IDE/UtilGHC.hsnew file+86
@@ -0,0 +1,86 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+{-# OPTIONS_GHC -Wno-missing-fields #-} -- to enable prettyPrint
5+{-# LANGUAGE CPP #-}
6+
7+-- | GHC utility functions. Importantly, code using our GHC should never:
8+--
9+-- * Call runGhc, use runGhcFast instead. It's faster and doesn't require config we don't have.
10+--
11+-- * Call setSessionDynFlags, use modifyDynFlags instead. It's faster and avoids loading packages.
12+module Development.IDE.UtilGHC(
13+ lookupPackageConfig,
14+ modifyDynFlags,
15+ fakeDynFlags,
16+ prettyPrint,
17+ runGhcEnv
18+ ) where
19+
20+import Config
21+import Fingerprint
22+import GHC
23+import GhcMonad
24+import GhcPlugins
25+import Platform
26+import Data.IORef
27+import Control.Exception
28+import FileCleanup
29+
30+----------------------------------------------------------------------
31+-- GHC setup
32+
33+modifyDynFlags :: GhcMonad m => (DynFlags -> DynFlags) -> m ()
34+modifyDynFlags f = do
35+ newFlags <- f <$> getSessionDynFlags
36+ -- We do not use setSessionDynFlags here since we handle package
37+ -- initialization separately.
38+ modifySession $ \h ->
39+ h { hsc_dflags = newFlags, hsc_IC = (hsc_IC h) {ic_dflags = newFlags} }
40+
41+lookupPackageConfig :: UnitId -> HscEnv -> Maybe PackageConfig
42+lookupPackageConfig unitId env =
43+ lookupPackage' False pkgConfigMap unitId
44+ where
45+ pkgConfigMap =
46+ -- For some weird reason, the GHC API does not provide a way to get the PackageConfigMap
47+ -- from PackageState so we have to wrap it in DynFlags first.
48+ getPackageConfigMap $ hsc_dflags env
49+
50+
51+
52+prettyPrint :: Outputable a => a -> String
53+prettyPrint = showSDoc fakeDynFlags . ppr
54+
55+runGhcEnv :: HscEnv -> Ghc a -> IO a
56+runGhcEnv env act = do
57+ filesToClean <- newIORef emptyFilesToClean
58+ dirsToClean <- newIORef mempty
59+ let dflags = (hsc_dflags env){filesToClean=filesToClean, dirsToClean=dirsToClean}
60+ ref <- newIORef env{hsc_dflags=dflags}
61+ unGhc act (Session ref) `finally` do
62+ cleanTempFiles dflags
63+ cleanTempDirs dflags
64+
65+
66+-- Fake DynFlags which are mostly undefined, but define enough to do a little bit
67+fakeDynFlags :: DynFlags
68+fakeDynFlags = defaultDynFlags settings ([], [])
69+ where
70+ settings = Settings
71+ {sTargetPlatform = Platform
72+ {platformWordSize = 8
73+ ,platformOS = OSUnknown
74+ ,platformUnregisterised = True
75+ }
76+ ,sPlatformConstants = PlatformConstants
77+ {pc_DYNAMIC_BY_DEFAULT = False
78+ ,pc_WORD_SIZE = 8
79+ }
80+#ifndef GHC_STABLE
81+ ,sIntegerLibraryType = IntegerSimple
82+#endif
83+ ,sProjectVersion = cProjectVersion
84+ ,sProgramName = "ghc"
85+ ,sOpt_P_fingerprint = fingerprint0
86+ }
stack-ghc-lib.yamldeleted−24
@@ -1,24 +0,0 @@
1−resolver: nightly-2019-09-16
2−packages:
3−- .
4−extra-deps:
5−- haskell-lsp-0.22.0.0
6−- haskell-lsp-types-0.22.0.0
7−- lsp-test-0.10.3.0
8−- hie-bios-0.5.0
9−- ghc-lib-parser-8.8.1
10−- ghc-lib-8.8.1
11−- fuzzy-0.1.0.0
12−- shake-0.18.5
13−- regex-base-0.94.0.0
14−- regex-tdfa-1.3.1.0
15−- haddock-library-1.8.0
16−- ghc-check-0.3.0.1
17−nix:
18− packages: [zlib]
19−flags:
20− ghcide:
21− ghc-lib: True
22−ghc-options:
23− ghc-lib-parser: -O0
24− ghc-lib: -O0
stack.yaml+1−17
@@ -1,19 +1,3 @@
1−resolver: nightly-2019-09-21
1+resolver: nightly-2019-05-20
22packages:
33- .
4−extra-deps:
5−- haskell-lsp-0.22.0.0
6−- haskell-lsp-types-0.22.0.0
7−- lsp-test-0.11.0.1
8−- hie-bios-0.5.0
9−- fuzzy-0.1.0.0
10−- regex-pcre-builtin-0.95.1.1.8.43
11−- regex-base-0.94.0.0
12−- regex-tdfa-1.3.1.0
13−- shake-0.18.5
14−- parser-combinators-1.2.1
15−- haddock-library-1.8.0
16−- tasty-rerun-1.1.17
17−- ghc-check-0.3.0.1
18−nix:
19− packages: [zlib]
stack810.yamldeleted−18
@@ -1,18 +0,0 @@
1−resolver: nightly-2020-02-13
2−compiler: ghc-8.10.1
3−allow-newer: true
4−packages:
5−- .
6−extra-deps:
7−- haskell-lsp-0.22.0.0
8−- haskell-lsp-types-0.22.0.0
9−- lsp-test-0.11.0.1
10−- ghc-check-0.3.0.1
11−- hie-bios-0.5.0
12−
13−# for ghc-8.10
14−- Cabal-3.2.0.0
15−- lens-4.19.1
16−
17−nix:
18− packages: [zlib]
stack84.yamldeleted−33
@@ -1,33 +0,0 @@
1−resolver: lts-12.26
2−packages:
3−- .
4−
5−extra-deps:
6−- aeson-1.4.6.0
7−- base-orphans-0.8.2
8−- haskell-lsp-0.22.0.0
9−- haskell-lsp-types-0.22.0.0
10−- lsp-test-0.11.0.1
11−- rope-utf16-splay-0.3.1.0
12−- filepattern-0.1.1
13−- js-dgtable-0.5.2
14−- hie-bios-0.5.0
15−- fuzzy-0.1.0.0
16−- shake-0.18.5
17−- time-compat-1.9.2.2
18−- regex-base-0.94.0.0
19−- regex-tdfa-1.3.1.0
20−- parser-combinators-1.2.1
21−- haddock-library-1.8.0
22−- unordered-containers-0.2.10.0
23−- file-embed-0.0.11.2
24−- heaps-0.3.6.1
25−- ghc-check-0.3.0.1
26−# For tasty-retun
27−- ansi-terminal-0.10.3
28−- ansi-wl-pprint-0.6.9
29−- tasty-1.2.3
30−- tasty-rerun-1.1.17
31−
32−nix:
33− packages: [zlib]
stack88.yamldeleted−11
@@ -1,11 +0,0 @@
1−resolver: nightly-2020-02-13
2−packages:
3−- .
4−extra-deps:
5−- haskell-lsp-0.22.0.0
6−- haskell-lsp-types-0.22.0.0
7−- lsp-test-0.11.0.1
8−- ghc-check-0.3.0.1
9−- hie-bios-0.5.0
10−nix:
11− packages: [zlib]
test/Demo.hsnew file+104
@@ -0,0 +1,104 @@
1+-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+-- SPDX-License-Identifier: Apache-2.0
3+
4+module Demo(main) where
5+
6+import Control.Concurrent.Extra
7+import Control.Monad
8+import System.Time.Extra
9+import Development.IDE.State.Service
10+import Development.IDE.State.Rules
11+import Development.IDE.State.Shake
12+import Development.IDE.State.RuleTypes
13+import Development.IDE.Types.Diagnostics
14+import Development.IDE.Types.Options
15+import Development.IDE.Logger
16+import qualified Data.Text.IO as T
17+import System.Environment
18+import Data.List
19+import Data.Maybe
20+import System.FilePath
21+import Data.Tuple.Extra
22+import System.IO.Extra
23+import Development.IDE.Types.LSP
24+import Development.Shake hiding (Env)
25+import qualified Data.Set as Set
26+
27+import CmdLineParser
28+import DynFlags
29+import Panic
30+import GHC
31+import GHC.Paths
32+
33+
34+main :: IO ()
35+main = do
36+ (ghcOptions, files) <- getCmdLine
37+
38+ -- lock to avoid overlapping output on stdout
39+ lock <- newLock
40+
41+ ide <- initialise
42+ mainRule
43+ (Just $ showEvent lock)
44+ (makeOneHandle $ withLock lock . T.putStrLn)
45+ IdeOptions
46+ {optPreprocessor = (,) []
47+ ,optWriteIface = False
48+ ,optGhcSession = liftIO $ newSession ghcOptions
49+ ,optExtensions = ["hs"]
50+ ,optPkgLocationOpts = error "optPkgLocationOpts not implemented yet"
51+ ,optThreads = 0
52+ ,optShakeProfiling = Nothing -- Just "output.html"
53+ }
54+ setFilesOfInterest ide $ Set.fromList files
55+ _ <- runAction ide $ uses_ TypeCheck files
56+ -- shake now writes an async message that it is completed with timing info,
57+ -- so we sleep briefly to wait for it to have been written
58+ sleep 0.01
59+ putStrLn "Done"
60+
61+
62+-- | Print an LSP event.
63+showEvent :: Lock -> Event -> IO ()
64+showEvent _ (EventFileDiagnostics (_, [])) = return ()
65+showEvent lock (EventFileDiagnostics (file, diags)) =
66+ withLock lock $ T.putStrLn $ showDiagnosticsColored $ map (file,) diags
67+showEvent lock e = withLock lock $ print e
68+
69+
70+-- | Create a GHC session that will be subsequently reused.
71+newSession :: [String] -> IO HscEnv
72+newSession flags = runGhc (Just libdir) $ do
73+ damlDFlags <- getSessionDynFlags
74+ (dflags', leftover, warns) <- parseDynamicFlagsCmdLine damlDFlags $ map noLoc flags
75+
76+ let leftoverError = CmdLineError $
77+ (unlines . ("Unable to parse custom flags:":) . map unLoc) leftover
78+ unless (null leftover) $ liftIO $ throwGhcExceptionIO leftoverError
79+
80+ unless (null warns) $
81+ liftIO $ putStrLn $ unlines $ "Warnings:" : map (unLoc . warnMsg) warns
82+
83+ _ <- setSessionDynFlags dflags'
84+ getSession
85+
86+
87+-- | Convert the command line into GHC options and files to load.
88+getCmdLine :: IO ([String], [FilePath])
89+getCmdLine = do
90+ args <- getArgs
91+ args <- return $ if null args then [".ghci"] else args
92+ let (flags, files) = partition ("-" `isPrefixOf`) args
93+ let (ghci, hs) = partition ((==) ".ghci" . takeExtension) files
94+ (flags, files) <- both concat . unzip . ((flags,hs):) <$> mapM readGhci ghci
95+ when (null files) $
96+ fail "Expected some files to load, but didn't find any"
97+ return (flags, files)
98+
99+readGhci :: FilePath -> IO ([String], [FilePath])
100+readGhci file = do
101+ xs <- lines <$> readFileUTF8' file
102+ let flags = concatMap words $ mapMaybe (stripPrefix ":set ") xs
103+ let files = concatMap words $ mapMaybe (stripPrefix ":load ") xs
104+ return (flags, files)
test/cabal/Development/IDE/Test/Runfiles.hsdeleted−9
@@ -1,9 +0,0 @@
1−-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2−-- SPDX-License-Identifier: Apache-2.0
3−
4−module Development.IDE.Test.Runfiles
5− ( locateGhcideExecutable
6− ) where
7−
8−locateGhcideExecutable :: IO FilePath
9−locateGhcideExecutable = pure "ghcide"
test/data/hover/Bar.hsdeleted−3
@@ -1,3 +0,0 @@
1−module Bar (Bar(..)) where
2−
3−data Bar = Bar
test/data/hover/Foo.hsdeleted−5
@@ -1,5 +0,0 @@
1−module Foo (Bar, foo) where
2−
3−import Bar
4−
5−foo = Bar
test/data/hover/GotoHover.hsdeleted−57
@@ -1,57 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{- HLINT ignore -}
3−module Testing ( module Testing ) where
4−import Data.Text (Text, pack)
5−import Foo (Bar, foo)
6−
7−
8−data TypeConstructor = DataConstructor
9− { fff :: Text
10− , ggg :: Int }
11−aaa :: TypeConstructor
12−aaa = DataConstructor
13− { fff = "dfgy"
14− , ggg = 832
15− }
16−bbb :: TypeConstructor
17−bbb = DataConstructor "mjgp" 2994
18−ccc :: (Text, Int)
19−ccc = (fff bbb, ggg aaa)
20−ddd :: Num a => a -> a -> a
21−ddd vv ww = vv +! ww
22−a +! b = a - b
23−hhh (Just a) (><) = a >< a
24−iii a b = a `b` a
25−jjj s = pack $ s <> s
26−class MyClass a where
27− method :: a -> Int
28−instance MyClass Int where
29− method = succ
30−kkk :: MyClass a => Int -> a -> Int
31−kkk n c = n + method c
32−
33−doBind :: Maybe ()
34−doBind = do unwrapped <- Just ()
35− return unwrapped
36−
37−listCompBind :: [Char]
38−listCompBind = [ succ c | c <- "ptfx" ]
39−
40−multipleClause :: Bool -> Char
41−multipleClause True = 't'
42−multipleClause False = 'f'
43−
44−-- | Recognizable docs: kpqz
45−documented :: Monad m => Either Int (m a)
46−documented = Left 7518
47−
48−listOfInt = [ 8391 :: Int, 6268 ]
49−
50−outer :: Bool
51−outer = undefined where
52−
53− inner :: Char
54− inner = undefined
55−
56−imported :: Bar
57−imported = foo
test/data/multi/a/A.hsdeleted−3
@@ -1,3 +0,0 @@
1−module A(foo) where
2−
3−foo = ()
test/data/multi/a/a.cabaldeleted−9
@@ -1,9 +0,0 @@
1−name: a
2−version: 1.0.0
3−build-type: Simple
4−cabal-version: >= 1.2
5−
6−library
7− build-depends: base
8− exposed-modules: A
9− hs-source-dirs: .
test/data/multi/b/B.hsdeleted−3
@@ -1,3 +0,0 @@
1−module B(module B) where
2−import A
3−qux = foo
test/data/multi/b/b.cabaldeleted−9
@@ -1,9 +0,0 @@
1−name: b
2−version: 1.0.0
3−build-type: Simple
4−cabal-version: >= 1.2
5−
6−library
7− build-depends: base, a
8− exposed-modules: B
9− hs-source-dirs: .
test/data/multi/cabal.projectdeleted−1
@@ -1 +0,0 @@
1−packages: a b
test/data/multi/hie.yamldeleted−6
@@ -1,6 +0,0 @@
1−cradle:
2− cabal:
3− - path: "./a"
4− component: "lib:a"
5− - path: "./b"
6− component: "lib:b"
test/exe/Main.hsdeleted−2496

This diff is too big to show here.

test/manual/lhs/Bird.lhsdeleted−19

This diff is too big to show here.

test/manual/lhs/Main.hsdeleted−12

This diff is too big to show here.

test/manual/lhs/Test.lhsdeleted−36

This diff is too big to show here.

test/preprocessor/Main.hsdeleted−10

This diff is too big to show here.

test/src/Development/IDE/Test.hsdeleted−111

This diff is too big to show here.