about summary refs log blame commit diff
path: root/third_party/bazel/rules_haskell/haskell/lint.bzl
blob: 1ee7d47a2e11e6f778159790d9682db55cb1e81c (plain) (tree)








































































































































                                                                                   
"""Linting"""

load(
    "@io_tweag_rules_haskell//haskell:providers.bzl",
    "HaskellInfo",
    "HaskellLibraryInfo",
    "HaskellLintInfo",
)
load(":private/context.bzl", "haskell_context", "render_env")
load(":private/packages.bzl", "expose_packages", "pkg_info_to_compile_flags")
load(
    ":private/path_utils.bzl",
    "target_unique_name",
)
load(":providers.bzl", "get_libs_for_ghc_linker")
load(":private/set.bzl", "set")

def _collect_lint_logs(deps):
    lint_logs = set.empty()
    for dep in deps:
        if HaskellLintInfo in dep:
            set.mutable_union(lint_logs, dep[HaskellLintInfo].outputs)
    return lint_logs

def _haskell_lint_rule_impl(ctx):
    return [DefaultInfo(
        files = set.to_depset(_collect_lint_logs(ctx.attr.deps)),
    )]

def _haskell_lint_aspect_impl(target, ctx):
    hs = haskell_context(ctx, ctx.rule.attr)

    if HaskellInfo not in target:
        return []

    hs_info = target[HaskellInfo]
    lib_info = target[HaskellLibraryInfo] if HaskellLibraryInfo in target else None

    args = ctx.actions.args()

    args.add_all([
        "-O0",
        "-v0",
        "-fno-code",
        "-Wall",
        "-Werror",
        "-Wcompat",
        "-Wincomplete-record-updates",
        "-Wincomplete-uni-patterns",
        "-Wredundant-constraints",
        "-Wnoncanonical-monad-instances",
        "--make",
    ])

    args.add_all(pkg_info_to_compile_flags(expose_packages(
        hs_info,
        lib_info,
        use_direct = False,
        use_my_pkg_id = None,
        custom_package_databases = None,
        version = ctx.rule.attr.version,
    )))

    sources = set.to_list(hs_info.source_files)

    args.add_all(sources)

    lint_log = ctx.actions.declare_file(
        target_unique_name(hs, "lint-log"),
    )

    # Transitive library dependencies for runtime.
    (library_deps, ld_library_deps, _ghc_env) = get_libs_for_ghc_linker(
        hs,
        hs_info.transitive_cc_dependencies,
    )

    ctx.actions.run_shell(
        inputs = depset(transitive = [
            depset(sources),
            set.to_depset(hs_info.package_databases),
            set.to_depset(hs_info.interface_dirs),
            set.to_depset(hs_info.dynamic_libraries),
            depset(library_deps),
            depset(ld_library_deps),
            depset([hs.tools.ghc]),
        ]),
        outputs = [lint_log],
        mnemonic = "HaskellLint",
        progress_message = "HaskellLint {}".format(ctx.label),
        command = """
        {env}
        {ghc} "$@" > {output} 2>&1 || rc=$? && cat {output} && exit $rc
        """.format(
            ghc = hs.tools.ghc.path,
            output = lint_log.path,
            # XXX Workaround
            # https://github.com/bazelbuild/bazel/issues/5980.
            env = render_env(hs.env),
        ),
        arguments = [args],
        use_default_shell_env = True,
    )

    lint_info = HaskellLintInfo(outputs = set.singleton(lint_log))
    output_files = OutputGroupInfo(default = [lint_log])

    return [lint_info, output_files]

haskell_lint_aspect = aspect(
    _haskell_lint_aspect_impl,
    attr_aspects = ["deps"],
    toolchains = ["@io_tweag_rules_haskell//haskell:toolchain"],
)

haskell_lint = rule(
    _haskell_lint_rule_impl,
    attrs = {
        "deps": attr.label_list(
            aspects = [haskell_lint_aspect],
            doc = "List of Haskell targets to lint.",
        ),
    },
    toolchains = ["@io_tweag_rules_haskell//haskell:toolchain"],
)
"""Check source code of targets in `deps` using a restrictive set of GHC
flags.

The following flags will be used:

* `-Wall`
* `-Werror`
* `-Wcompat`
* `-Wincomplete-record-updates`
* `-Wincomplete-uni-patterns`
* `-Wredundant-constraints`
"""