### Leiningen User Profile Eastwood Configuration Source: https://github.com/jonase/eastwood/blob/master/README.md Defines an example `:eastwood` configuration within a user's `profiles.clj` file, specifying plugins, linters to exclude, and debug settings. This configuration serves as a lower-priority source for Eastwood options. ```clojure {:user {:plugins [[jonase/eastwood "1.4.3"]] :eastwood {:exclude-linters [:unlimited-use] :debug [:time]} }} ``` -------------------------------- ### Install Bleeding-Edge Eastwood for Development Source: https://github.com/jonase/eastwood/blob/master/README.md This command-line snippet provides instructions for Eastwood developers to install the bleeding-edge version of the linter into their local Maven repository. This allows testing the latest changes before official releases. After installation, the plugin needs to be added to the user's Leiningen profiles. ```sh $ cd path/to/eastwood $ lein with-profile -user,-dev,+eastwood-plugin install ``` -------------------------------- ### Leiningen Project Dev Profile Eastwood Configuration Source: https://github.com/jonase/eastwood/blob/master/README.md Illustrates an example `:eastwood` configuration within a project's `project.clj` file, specifically in the `:dev` profile. This configuration has higher priority and can override or combine with options from lower-priority profiles. ```clojure :profiles {:dev {:eastwood {:exclude-linters [:wrong-arity :bad-arglists] :debug [:progress] :warning-format :map-v2 }}} ``` -------------------------------- ### Transitive Dependencies of tools.analyzer.jvm (0.1.0-beta13) Source: https://github.com/jonase/eastwood/blob/master/copy-deps-scripts/README.md Illustrates the transitive dependencies of `tools.analyzer.jvm` version `0.1.0-beta13`, which previously caused conflicts when Eastwood directly depended on it. This example highlights the problem that the copied-dependency strategy aims to solve. ```Leiningen [org.clojure/tools.analyzer.jvm "0.1.0-beta13"] [org.clojure/core.memoize "0.5.6"] [org.clojure/core.cache "0.6.3"] [org.clojure/data.priority-map "0.0.2"] [org.ow2.asm/asm-all "4.1"] ``` -------------------------------- ### Eastwood REPL Options Map Default Adjustments Source: https://github.com/jonase/eastwood/blob/master/README.md Describes the default values and special handling for keys in the options map when Eastwood is started from a REPL, applied before user-supplied options. These adjustments ensure proper functionality and relative file paths for warnings. ```APIDOC Eastwood Options Map Defaults: :cwd: The full path to the current working directory. Used to make reported file names relative. :linters: Default value of all linters documented to be enabled by default. :namespaces: Default value of `[:source-paths :test-paths]`. :source-paths: A list of all directories on the Java classpath. This is a special case applied only if neither `:source-paths` nor `:test-paths` are present in the supplied options map. :callback: A default message callback function that formats and prints all callback data to `*out*` or the writer specified by the `:out` key. ``` -------------------------------- ### Eastwood Linter: Identifying Deprecated Clojure Vars and Java Members Source: https://github.com/jonase/eastwood/blob/master/README.md This linter warns about the use of deprecated Clojure Vars and Java instance methods, static fields, static methods, and constructors. Warnings depend on the JDK version. Clojure vars are deprecated if they have `:deprecated` metadata. An example of `clojure.core/replicate` is provided. ```Clojure (defn replicate "DEPRECATED: Use 'repeat' instead. Returns a lazy seq of n xs." {:added "1.0" :deprecated "1.3"} [n x] (take n (repeat x))) ``` -------------------------------- ### Suspicious `clojure.test/is` with Misplaced Parentheses Source: https://github.com/jonase/eastwood/blob/master/README.md Demonstrates how extra parentheses around the first argument of `is` can lead to an unintended evaluation, making the test always pass. Provides the incorrect and corrected `clojure` code examples. ```clojure (is (= #{"josh"}) (get-names x)) ``` ```clojure (is (= #{"josh"} (get-names x))) ``` -------------------------------- ### Correct Java Class Type Hints on Clojure Vars Source: https://github.com/jonase/eastwood/blob/master/README.md Provides examples of correctly applying Java class type hints to Clojure Vars. This includes using both fully qualified class names (e.g., `^java.util.LinkedList`) and non-fully qualified names (e.g., `^LinkedList`) when the class has been imported. These hints are effective for Java interop and do not cause the same issues as incorrect primitive hints. ```Clojure ;; Correct Java class type hints on Vars (def ^Integer my-int -2) (defn ^Boolean positive? [x] (> x 0)) (defn ^java.util.LinkedList ll [coll] (java.util.LinkedList. coll)) ;; For type tags on the Var name, you may even avoid fully qualifying ;; the name, as long as you have imported the class. Unlike some ;; examples below with type tags on the argument vector, this does not ;; cause problems for Clojure. (defn ^LinkedList l2 [coll] (java.util.LinkedList. coll)) ``` -------------------------------- ### Clojure: Enforcing Naming Conventions for Dynamic Vars (`:non-dynamic-earmuffs`) Source: https://github.com/jonase/eastwood/blob/master/README.md Details the `:non-dynamic-earmuffs` linter, which enforces the 'earmuff' naming convention (`*var*`) for `^:dynamic` vars in Clojure. It provides examples of correct and incorrect usage, emphasizing that dynamic vars should be earmuffed and non-dynamic vars should not, to clearly indicate their dynamic nature. ```Clojure (def foo 42) ``` ```Clojure (def ^:dynamic foo 42) ``` ```Clojure (def *foo* 42) ``` ```Clojure (def ^:dynamic *foo* 42) ``` -------------------------------- ### Clojure: Lazy Sequence Evaluation and Unused Return Values Source: https://github.com/jonase/eastwood/blob/master/README.md Explains how lazy functions like `map` behave when their return values are not consumed. The first example shows REPL forcing evaluation, while the second demonstrates that `print` is not called if the lazy sequence returned by `map` is discarded, highlighting a common source of bugs. ```Clojure user=> (map print [1 2 3 4]) (1234nil nil nil nil) ;; The call to foo1 below will never call print, because nothing is ;; forcing the evaluation of the return value of the lazy function map user=> (defn foo1 [coll] #_=> (map print coll) #_=> (count coll)) #'user/foo1 user=> (foo1 [1 2 3 4]) 4 ``` -------------------------------- ### Disable Deprecation Warnings for Specific Symbols in Eastwood Source: https://github.com/jonase/eastwood/blob/master/README.md This Clojure example shows how to configure Eastwood to ignore `:deprecations` warnings for symbols matching a specific regular expression. This is useful for legacy projects where marking old code as deprecated without breaking the build is desired. ```Clojure (disable-warning {:linter :deprecations :symbol-matches #{#"^#'my\.old\.project\.*"}}) ``` -------------------------------- ### Clojure: `extend-protocol` with `Class/forName` causing `:wrong-tag` warnings Source: https://github.com/jonase/eastwood/blob/master/README.md Illustrates scenarios where using `(Class/forName "[D")` as a type in `extend-protocol` leads to invalid, ignored type tags and reflection. Eastwood issues `:wrong-tag` warnings in these cases, even with explicit type hints like `^doubles`. The final example shows how to correctly use the `extend` function to avoid both reflection and warnings. ```clojure (defprotocol PGetElem (get-elem [m idx])) ;; This will cause reflection on the aget call, because m has an ;; invalid, ignored type tag of (Class/forName "[D"). Eastwood will ;; give a :wrong-tag warning on m. (extend-protocol PGetElem (Class/forName "[D") (get-elem [m idx] (aget m idx))) ``` ```clojure ;; This also causes reflection on the aget call, because the ^doubles ;; type tag is replaced by the invalid, ignored type tag when ;; extend-protocol is macroexpanded. Eastwood will give a :wrong-tag ;; warning on m. (extend-protocol PGetElem (Class/forName "[D") (get-elem [^doubles m idx] (aget m idx))) ``` ```clojure ;; No reflection here, because the valid type hint ^doubles is inside ;; of the aget call, where extend-protocol does not overwrite it. ;; Eastwood will give a :wrong-tag warning on m. (extend-protocol PGetElem (Class/forName "[D") (get-elem [m idx] (aget ^doubles m idx))) ``` ```clojure ;; You will always get an Eastwood :wrong-tag warning if you use a ;; run-time evaluated expression as a type in extend-protocol or ;; extend-type. You can suppress Eastwood's warning, or instead use ;; the function extend. ;; This is the only version that both (a) avoids reflection, and (b) ;; Eastwood will not warn about. It calls the function extend, and ;; uses a correct type tag ^doubles on the first argument. You could ;; also put the type tag inside of the aget call if you prefer. (extend (Class/forName "[D") PGetElem {:get-elem (fn ([^doubles m idx] (aget m idx)))}) ``` -------------------------------- ### Configure Eastwood Debug Options via Leiningen Source: https://github.com/jonase/eastwood/blob/master/README.md This Leiningen command demonstrates how to run Eastwood with specific debug options. The `:debug` key accepts a list or vector of keywords to enable various debug messages during linting. These options are primarily for tracking down errors within Eastwood itself, not for general application debugging. Available debug options include: * `:all` - Enable all debug messages and show the initial list of namespaces. * `:options` - Print the contents of the options map at various startup steps. May be useful to debug where options are coming from. * `:config` - Print the names of Eastwood config files just before they are read. * `:time` - Print messages about the elapsed time taken during analysis, and for each individual linter. * `:forms` - Print the forms as read, before they are analyzed. * `:forms-pprint` - Like `:forms` except pretty-print the forms. * `:ast` - Print ASTs as forms are analyzed and `eval`d. These can be quite long. * `:progress` - Show a brief debug message after each top-level form is read. * `:compare-forms` - Print all forms as read to a file `forms-read.txt`, all forms after being analyzed to a file `forms-analyzed.txt`, and all forms after being read, analyzed into an AST, and converted back into a form from the AST, to a file `forms-emitted.txt`. * `:ns` - Print the initial set of namespaces loaded into the Clojure run-time at the beginning of each file being linted. * `:var-info` - Print some info about Vars that exist in various namespaces, and how many of them have data describing them in Eastwood's `var-info.edn` resource file, and how many do not. Useful when new releases of Clojure are made that add new Vars, to determine which ones Eastwood does not know about yet. ```Leiningen lein eastwood "{:exclude-linters [:unlimited-use] :debug [:options :ns]}" ``` -------------------------------- ### Eastwood Configuration Options and Behavior Control Source: https://github.com/jonase/eastwood/blob/master/changes.md Documentation for various top-level configuration options in Eastwood, including controlling core.async exception handling, ignoring specific faults, and enabling linter parallelism. ```APIDOC Option: :abort-on-core-async-exceptions? Description: When set to `true`, reverts to old behavior of aborting on exceptions from clojure.core.async/go macro analysis. Defaults to `false` (omit exceptions). ``` ```APIDOC Option: :ignored-faults Description: Allows specifying a list of faults to be ignored by Eastwood. See documentation for usage details. ``` ```APIDOC Option: :parallelism? Description: Controls analysis/evaluation parallelism. Linter parallelism is thread-safe and is now the default behavior. ``` -------------------------------- ### Run Eastwood Linter via Clojure CLI Source: https://github.com/jonase/eastwood/blob/master/README.md This command demonstrates how to execute the Eastwood linter using the Clojure CLI. It leverages the `:test` and `:eastwood` aliases defined in `deps.edn` to run the linting process. Ensure all relevant `deps.edn` aliases are enabled for proper analysis. ```Shell clojure -M:test:eastwood ``` -------------------------------- ### Run Eastwood Linting from Clojure REPL Source: https://github.com/jonase/eastwood/blob/master/README.md This Clojure snippet demonstrates how to invoke Eastwood's linting functions, `eastwood` and `lint`, directly from a REPL. It shows how to require the `eastwood.lint` namespace and pass configuration options like `:source-paths` and `:test-paths` to specify the code to be analyzed. ```Clojure (require '[eastwood.lint :as e]) ;; Replace the values of :source-paths and :test-paths with whatever ;; is appropriate for your project. You may omit them, and then the ;; default behavior is to search all directories in your Java ;; classpath, and their subdirectories recursively, for Clojure source ;; files. (e/eastwood {:source-paths ["src"] :test-paths ["test"]}) (e/with-memoization-bindings (e/lint {:source-paths ["src"] :test-paths ["test"]})) ``` -------------------------------- ### Programmatic Use of `eastwood.lint/eastwood` API Source: https://github.com/jonase/eastwood/blob/master/changes.md Describes new return keys available when invoking `eastwood.lint/eastwood` programmatically, allowing for better distinction of failure reasons. ```APIDOC Function: eastwood.lint/eastwood New Return Key: :some-errors Description: Indicates if Eastwood failed due to errors, akin to the existing `:some-warnings` key. ``` -------------------------------- ### Run Eastwood from Leiningen Command Line Source: https://github.com/jonase/eastwood/blob/master/README.md Execute this command from your project's root directory to run Eastwood with its default set of lint warnings. It will analyze all Clojure files in your project's source and test paths. ```Shell lein eastwood ``` -------------------------------- ### Run Eastwood Linter for Clojure Projects Source: https://github.com/jonase/eastwood/blob/master/README.md This command executes the Eastwood linter on all namespaces within the project's source and test paths. It's the default way to lint an entire Leiningen project. ```bash $ lein eastwood ``` -------------------------------- ### Tagging a New Release Version with Git Source: https://github.com/jonase/eastwood/blob/master/doc/README-creating-new-release.md This command demonstrates how to create an annotated Git tag for a new release version. The tag includes the version number and a descriptive message, which is useful for tracking releases in the repository history. ```Shell % git tag -a v1.4.3 -m "1.4.3" ``` -------------------------------- ### Eastwood Linter Namespace and Path Configuration Options Source: https://github.com/jonase/eastwood/blob/master/README.md This section details the available options for controlling which namespaces and source/test paths Eastwood lints. These options allow fine-grained control over the scope of the linting process. ```APIDOC :namespaces: Vector of namespaces to lint. - A keyword :source-paths will be replaced with a list of namespaces in your Leiningen :source-paths and their subdirectories. - Similarly for a keyword :test-paths. - Default: [:source-paths :test-paths] if not specified. :exclude-namespaces: Vector of namespaces to exclude. - :source-paths and :test-paths may be used here. - Default: empty list. :source-paths: Normally taken from your Leiningen project.clj file. - Default: ["src"] if not specified there. - Can be specified in the Eastwood option map to override. :test-paths: Similar to :source-paths. - Default: ["test"] if not specified in your project.clj file. ``` -------------------------------- ### Eastwood Linter: Performance Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:performance` linter in Eastwood, which provides performance warnings. This linter is enabled by default. ```APIDOC Linter Name: :performance Description: Performance warnings Status: Enabled by default ``` -------------------------------- ### Eastwood Linter: Boxed Math Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:boxed-math` linter in Eastwood, which warns about boxed math compiler issues. This linter is enabled by default. ```APIDOC Linter Name: :boxed-math Description: Boxed math compiler warnings Status: Enabled by default ``` -------------------------------- ### Output Eastwood Warnings to a File Source: https://github.com/jonase/eastwood/blob/master/README.md These commands direct all Eastwood warning lines and 'Entering directory' lines to a specified file, 'warn.txt'. This is useful for reviewing warnings incrementally and works across different shells. ```bash $ lein eastwood "{:out \"warn.txt\"}" ``` ```bash $ lein eastwood '{:out "warn.txt"}' ``` -------------------------------- ### Clojure: Limiting Symbol References with `use` and `require` Source: https://github.com/jonase/eastwood/blob/master/README.md Explains the `unlimited-use` linter warning in Clojure. It advises against using `(:use ...)` without `:refer` or `:only` to avoid polluting the namespace and improve code clarity. It recommends using `require` with `:refer` or `:as` for explicit symbol imports. The linter ignores `clojure.test` due to its common usage. ```Clojure (ns my.namespace (:use clojure.string)) ``` ```Clojure (ns my.namespace (:require [clojure.string :as str :refer [replace join]])) ``` ```Clojure (ns my.namespace (:use [clojure.string :as str :only [replace]] [clojure.walk :refer [prewalk]] [clojure [xml :only [emit]]])) ``` -------------------------------- ### Add Eastwood as a Leiningen Plugin Source: https://github.com/jonase/eastwood/blob/master/README.md To integrate Eastwood into a Leiningen project, merge this plugin declaration into your `project.clj` or `~/.lein/profiles.clj` file. This makes the `eastwood` task available for execution. ```Clojure :plugins [[jonase/eastwood "1.4.3"]] ``` -------------------------------- ### Clojure: Valid `extend-protocol` usage with type tags Source: https://github.com/jonase/eastwood/blob/master/README.md Demonstrates correct usage of `extend-protocol` with `Long` and `Double` types, showing how type tags are propagated after macro expansion and how `get-type` works without reflection. ```clojure (defprotocol MyType (get-type [x])) ;; A more interesting example would avoid reflection only because of ;; the auto-propagated type tags on the argument m. Better example ;; welcome. (extend-protocol MyType Long (get-type [m] :long) Double (get-type [m] :double)) ;; The extend-protocol expression above becomes the following after ;; macro expansion, with valid type tags ^Long and ^Double. (do (clojure.core/extend Long MyType {:get-type (fn ([^{:tag Long} m] :long))}) (clojure.core/extend Double MyType {:get-type (fn ([^{:tag Double} m] :double))})) (get-type 5) ;; => :long (get-type 5.3) ;; => :double ``` -------------------------------- ### Eastwood Linter: Implicit Dependencies Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:implicit-dependencies` linter in Eastwood, which warns when a fully-qualified var refers to a namespace that has not been listed in `:require`. This linter is enabled by default. ```APIDOC Linter Name: :implicit-dependencies Description: A fully-qualified var refers to a namespace that hasn't been listed in :require. Status: Enabled by default ``` -------------------------------- ### Current Transitive Dependencies of Eastwood's `deps` Project (Oct 2017) Source: https://github.com/jonase/eastwood/blob/master/copy-deps-scripts/README.md Displays the full transitive dependency tree for the `deps` project as of October 9, 2017. This project is used to simulate Eastwood's dependencies and verify what versions would be pulled in if not for the copied-source strategy. ```Leiningen % lein deps :tree [clojure-complete "0.2.4" :exclusions [[org.clojure/clojure]]] [jafingerhut/dolly "0.1.0" :scope "test"] [rhizome "0.2.1" :scope "test"] [org.clojars.brenton/google-diff-match-patch "0.1"] [org.clojure/clojure "1.6.0"] [org.clojure/tools.analyzer.jvm "0.7.1"] [org.clojure/core.memoize "0.5.9"] [org.clojure/core.cache "0.6.5"] [org.clojure/data.priority-map "0.0.7"] [org.ow2.asm/asm-all "4.2"] [org.clojure/tools.analyzer "0.6.9"] [org.clojure/tools.macro "0.1.2" :scope "test"] [org.clojure/tools.namespace "0.3.0-alpha3"] [org.clojure/java.classpath "0.2.3"] [org.clojure/tools.nrepl "0.2.12" :exclusions [[org.clojure/clojure]]] [org.clojure/tools.reader "1.1.0"] ``` -------------------------------- ### Pushing Git Tags to Remote Repository Source: https://github.com/jonase/eastwood/blob/master/doc/README-creating-new-release.md This command is used to push all local Git tags to the remote origin. By default, 'git push' does not include tags, so this explicit command is necessary to make release tags available on the remote server. ```Shell % git push origin --tags ``` -------------------------------- ### Lint Specific Clojure Namespaces and Exclude Linters Source: https://github.com/jonase/eastwood/blob/master/README.md This command allows linting only specified namespaces and excluding certain linters. It demonstrates how to pass a Leiningen options map to customize the linting process. ```bash $ lein eastwood "{:namespaces [compojure.handler compojure.core-test] :exclude-linters [:unlimited-use]}" ``` -------------------------------- ### Run Dolly to Copy Dependencies in Eastwood Source: https://github.com/jonase/eastwood/blob/master/copy-deps-scripts/README.md Executes the Dolly tool to copy and rename dependencies into the Eastwood project's source code. This command first clones necessary scripts and then runs Dolly via Leiningen with specific profiles. ```bash ./copy-deps-scripts/clone.sh && lein with-profile -user,-dev,+dolly run -m dolly ``` -------------------------------- ### Configure Eastwood Linter in Clojure deps.edn Source: https://github.com/jonase/eastwood/blob/master/README.md This snippet shows how to add Eastwood as an alias in your `deps.edn` file. It includes the main options for running the linter and specifies the Eastwood dependency version. This configuration allows Eastwood to infer source and test paths automatically. ```Clojure {:aliases {:eastwood {:main-opts ["-m" "eastwood.lint" ;; Any Eastwood options can be passed here as edn: {}] :extra-deps {jonase/eastwood {:mvn/version "1.4.3"}}}}} ``` -------------------------------- ### Checking Eastwood Dependencies with Leiningen Commands Source: https://github.com/jonase/eastwood/blob/master/copy-deps-scripts/README.md Provides Leiningen commands to inspect the transitive dependencies and check for newer versions of libraries that Eastwood would normally depend on. These commands are run within a dedicated `deps` project. ```Leiningen lein deps :tree lein ancient ``` -------------------------------- ### Correct `clojure.test/is` Macro Forms Source: https://github.com/jonase/eastwood/blob/master/README.md Defines the standard and correct forms for using the `clojure.test/is` macro, including basic assertions, assertions with messages, and assertions for thrown exceptions with or without message matching. ```clojure (is expr) (is expr message-string) (is (thrown? ExceptionClass expr1 ...)) (is (thrown? ExceptionClass expr1 ...) message-string) (is (thrown-with-msg? ExceptionClass regex expr1 ...)) (is (thrown-with-msg? ExceptionClass regex expr1 ...) message-string) ``` -------------------------------- ### Eastwood Linter: Bad Arglists Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:bad-arglists` linter in Eastwood, which identifies function/macro `:arglists` metadata that does not match the number of arguments it is defined with. This linter is enabled by default. ```APIDOC Linter Name: :bad-arglists Description: Function/macro :arglists metadata that does not match the number of args it is defined with. Status: Enabled by default ``` -------------------------------- ### Eastwood Linter: No NS Form Found Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:no-ns-form-found` linter in Eastwood, which warns about Clojure files where no `ns` form could be found. This linter is enabled by default. ```APIDOC Linter Name: :no-ns-form-found Description: Warn about Clojure files where no `ns` form could be found. Status: Enabled by default ``` -------------------------------- ### Configure Eastwood to Enable Unused Locals Linter Source: https://github.com/jonase/eastwood/blob/master/README.md This configuration snippet demonstrates how to enable the `:unused-locals` linter in Eastwood. By adding this line to your `project.clj` or `$HOME/.lein/profiles.clj` file, Eastwood will warn about symbols bound with `let` or `loop` that are never used within their scope. ```Clojure :eastwood {:add-linters [:unused-locals]} ``` -------------------------------- ### Clojure: Shadowing with `comp` causing a linter warning Source: https://github.com/jonase/eastwood/blob/master/README.md Shows a case where a local `replace` binding is created using `comp`, which Eastwood's analysis cannot determine to be a function, thus triggering a `:local-shadows-var` warning. ```clojure (let [replace (comp str biginteger)] (println (replace 5))) ``` -------------------------------- ### Eastwood Linter Enable/Disable Options Source: https://github.com/jonase/eastwood/blob/master/README.md This section outlines the options for enabling, disabling, and adding specific linters. It provides flexibility to customize which linting checks are performed. ```APIDOC :linters: Linters to use. - Default: [:default] (all linters except those documented as 'disabled by default'). :exclude-linters: Linters (or linter sub :kinds) to exclude. :add-linters: Linters to add. - Can enable linters that are disabled by default. - Final list: (:linters - :excluded-linters + :add-linters). Keywords: - :all: Replaced with the collection of all linters. - :default: Replaced with the collection of default linters. Examples: - :linters [:all]: Enables all linters, even those disabled by default. - :linters [:all] :exclude-linters [:default]: Enables only those that are disabled by default. ``` -------------------------------- ### Resulting Merged Eastwood Options Map Source: https://github.com/jonase/eastwood/blob/master/README.md Shows the final `:eastwood` options map after Leiningen applies its merging rules to the user and project profile configurations. This demonstrates how vectors are concatenated and maps are merged recursively. ```clojure {:exclude-linters (:unlimited-use :wrong-arity :bad-arglists) :debug (:time :progress) :warning-format :map-v2} ``` -------------------------------- ### Eastwood Linter Enhancements for Clojure Constructs Source: https://github.com/jonase/eastwood/blob/master/changes.md Overview of various Eastwood linter improvements and bug fixes related to specific Clojure forms, macros, and patterns, reducing false positives and improving analysis accuracy. ```Clojure clojure.core.async/go Description: Eastwood now omits exceptions from top-level forms using this macro, improving analysis of core.async-based projects. ``` ```Clojure (class (byte-array 0)) Description: Supported as an extend-protocol target without triggering the :wrong-tag linter. ``` ```Clojure some->, some->> Description: False positives for these macros have been fixed. ``` ```Clojure if-some, when-some Description: The :constant-test linter is now available for these conditional macros. ``` ```Clojure multimethods Description: The :unused-fn-args linter now plays better with multimethods. ``` ```Clojure require (dynamic forms) Description: The :implicit-requires linter now works correctly in the presence of dynamic require forms. ``` ```Clojure (is false) Description: This clojure.test pattern is now supported. ``` ```Clojure (while true) Description: This common loop pattern is now supported. ``` ```Clojure let (destructuring) Description: A false positive for let destructuring has been fixed. ``` ```Clojure Manifold's let-flow Description: Eastwood now supports Manifold's let-flow macro. ``` ```Clojure clojure.test/are Description: A certain pattern of usage of this macro no longer triggers a linter fault. ``` ```Clojure clojure.test/is Description: False positives for :suspicious-expression related to clojure.test/is have been fixed. ``` ```Clojure clojure.test/assert-expr Description: Better support for clojure.test/assert-expr. ``` ```Clojure defn (with :test metadata) Description: Vanilla defns having :test metadata no longer result in false positives for the :bad-arglists linter. ``` ```Clojure unused-ret-vals-in-try (linter) Description: False positives for this linter with clojure.test have been fixed. ``` -------------------------------- ### Correct Primitive Type Hints on Clojure Vars Source: https://github.com/jonase/eastwood/blob/master/README.md Demonstrates the correct syntax for applying primitive and primitive-array type hints to Clojure Vars using the `^{:tag 'type}` metadata. These hints assist Clojure in avoiding reflection during Java interop calls when the Var name is used as an argument, without enforcing the value's type. ```Clojure ;; Correct primitive/primitive-array type hints on Vars (def ^{:tag 'int} my-int -2) (def ^{:tag 'bytes} bytearr1 (byte-array [2 3 4])) (defn ^{:tag 'boolean} positive? [x] (> x 0)) ``` -------------------------------- ### Eastwood Linter: Local Shadows Var Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:local-shadows-var` linter in Eastwood, which warns when a local name (e.g., a function argument or `let` binding) has the same name as a global Var and is called as a function. This linter is enabled by default. ```APIDOC Linter Name: :local-shadows-var Description: A local name, e.g. a function arg or let binding, has the same name as a global Var, and is called as a function. Status: Enabled by default ``` -------------------------------- ### Incorrect `thrown?` Usage with Regex Source: https://github.com/jonase/eastwood/blob/master/README.md Addresses the common misunderstanding that `clojure.test/thrown?` can validate an exception message using a regex. It clarifies that `thrown?` ignores regex arguments and advises using `clojure.test/thrown-with-msg?` when message content verification is required. ```clojure (is (thrown? Throwable #"There were 2 vertices returned." (expr-i-expect-to-throw-exception))) ``` ```clojure (is (thrown-with-msg? Throwable #"There were 2 vertices returned." (expr-i-expect-to-throw-exception))) ``` -------------------------------- ### Eastwood Linter: Deprecations Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:deprecations` linter in Eastwood, which identifies deprecated Clojure Vars and deprecated Java constructors, methods, and fields. This linter is enabled by default. ```APIDOC Linter Name: :deprecations Description: Deprecated Clojure Vars, and deprecated Java constructors, methods, and fields. Status: Enabled by default ``` -------------------------------- ### Eastwood Linter: No Name (File/Namespace Consistency) Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the 'no name*' linter in Eastwood, which checks for inconsistencies between file names and the namespaces declared within them. This linter is a core check and cannot be disabled. It also provides information on its debug and suppression capabilities. ```APIDOC Linter Name: no name* Description: Inconsistencies between file names and the namespaces declared within them. Status: Cannot be disabled Debug Option: No Suppressible: No ``` -------------------------------- ### Add Eastwood Dependency to Leiningen Project Source: https://github.com/jonase/eastwood/blob/master/README.md This Leiningen profile configuration snippet adds the Eastwood library as a development dependency to a Clojure project. It specifies version 1.4.3 and excludes `org.clojure/clojure` to avoid potential dependency conflicts. ```Clojure :profiles {:dev {:dependencies [[jonase/eastwood "1.4.3" :exclusions [org.clojure/clojure]]]}} ``` -------------------------------- ### Eastwood Linter: Non-Dynamic Earmuffs Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:non-dynamic-earmuffs` linter in Eastwood, which checks if Vars marked `^:dynamic` follow the "earmuff" naming convention, and vice versa. This linter is enabled by default. ```APIDOC Linter Name: :non-dynamic-earmuffs Description: Vars marked ^:dynamic should follow the "earmuff" naming convention, and vice versa. Status: Enabled by default ``` -------------------------------- ### Eastwood Linter: Constant Test Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:constant-test` linter in Eastwood, which flags test expressions that always evaluate as true or always false. This linter is enabled by default. ```APIDOC Linter Name: :constant-test Description: A test expression always evaluates as true, or always false. Status: Enabled by default ``` -------------------------------- ### Eastwood Analysis Error: Explicit `&env` Usage Source: https://github.com/jonase/eastwood/blob/master/README.md Eastwood's `tools.analyzer` engine is stricter than the Clojure compiler and throws a `ClassCastException` when analyzing code that explicitly uses the values of `&env` (e.g., `Compiler$LocalBinding` instances), as it cannot provide a compatible `&env`. ```Clojure Exception thrown during phase :analyze+eval of linting namespace immutable-bitset ClassCastException clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Compiler$LocalBinding ``` -------------------------------- ### Configure Eastwood to Ignore Specific Linter Faults Source: https://github.com/jonase/eastwood/blob/master/README.md This configuration snippet demonstrates how to use the `:ignored-faults` option in Eastwood to suppress specific linter warnings. It allows ignoring faults based on linter name, namespace, and precise location (line and column), or an entire namespace. The `target` can be a specific line/column, a line only, or `true` to ignore all occurrences within a namespace. ```clj ;;linter-name ns-name target ;;--- --- --- {:implicit-dependencies {'example.namespace [{:line 3 :column 2}] 'another.namespace [{:line 79}] 'random.namespace [{:line 89}, {:line 110}, {:line 543 :column 10}]} :unused-ret-vals {'yet.another.namespace true}} ``` -------------------------------- ### Detecting Incorrect Clojure `ns` Form Syntax with Eastwood Source: https://github.com/jonase/eastwood/blob/master/README.md This section explains how the Eastwood linter warns about malformed `ns` macro usage in Clojure. It covers issues like using vectors instead of parentheses for references, multiple `ns` forms in a single file, invalid keywords or flags in references, and improperly structured libspecs, which can hinder dependency analysis by tools like `tools.namespace`. ```Clojure (ns clojure.tools.test-trace [:use [clojure.test] [clojure.tools.trace]] [:require [clojure.string :as s]]) ``` -------------------------------- ### Clojure: Shadowed variable not called as function, no warning Source: https://github.com/jonase/eastwood/blob/master/README.md Demonstrates a scenario where a local `pmap` binding shadows a global Var but is not used in a function call position, thus avoiding a `:local-shadows-var` warning. ```clojure (let [pmap {:a 1 :b 2}] (println (map pmap [1 2 3]))) ``` -------------------------------- ### Linter Exception for `clojure.test/is` with String Message Source: https://github.com/jonase/eastwood/blob/master/README.md Explains a specific scenario where the `:suspicious-test` linter will not issue a warning: when the second argument to `is` is a form that commonly returns a string (e.g., `str`, `format`). This is an assumed correct usage for providing a test message. ```clojure (is (= ["josh"] names) (str "error when testing with josh and " names)) ``` -------------------------------- ### Eastwood Linter: Keyword Typos Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:keyword-typos` linter in Eastwood, which identifies keyword names that may be typos because they occur only once in the source code and are slight variations on other keywords. This linter is disabled by default. ```APIDOC Linter Name: :keyword-typos Description: Keyword names that may be typos because they occur only once in the source code and are slight variations on other keywords. Status: Disabled by default ``` -------------------------------- ### Clojure: Calling a shadowed `count` variable as a function Source: https://github.com/jonase/eastwood/blob/master/README.md Demonstrates a common bug where a local `let` binding named `count` shadows `clojure.core/count`, leading to an attempt to call a non-function value. ```clojure (let [{count :count data :data} (fetch-data) real-count (count data)] ... ) ``` -------------------------------- ### Eastwood Warning for Incorrect Clojure Pre/Postconditions (`:wrong-pre-post`) Source: https://github.com/jonase/eastwood/blob/master/README.md This section details the `:wrong-pre-post` linter warning in Eastwood, which identifies errors in Clojure function preconditions and postconditions. It illustrates the common mistake of not enclosing conditions in a vector, causing them to be evaluated incorrectly, and also warns about conditions that are always logically true or false, such as referencing a function Var instead of calling it. ```Clojure (defn square-root [x] {:pre [(>= x 0)]} (Math/sqrt x)) ;; AssertionError exception thrown when called with negative number user=> (square-root -5) AssertionError Assert failed: (>= x 0) user/square-root (file.clj:38) ``` ```Clojure (defn square-root [x] {:pre (>= x 0)} ; should be [(>= x 0)] like above (Math/sqrt x)) ;; No exception when called with negative number! user=> (square-root -5) NaN ``` ```Clojure (defn non-neg? [x] (>= x 0)) (defn square-root [x] {:pre [non-neg?]} ; [(non-neg? x)] would be correct (Math/sqrt x)) ;; No exception when called with negative number! user=> (square-root -5) NaN ``` -------------------------------- ### Correct Primitive Type Hints on Clojure Function Arguments and Return Values Source: https://github.com/jonase/eastwood/blob/master/README.md Shows how to correctly apply primitive type hints to function arguments and return values in Clojure, specifically for `long` and `double` types. It emphasizes that the return type tag must be placed immediately before the argument vector, not before the function name, to avoid compilation errors. ```Clojure ;; correct primitive type hints on function arguments and return value (defn add ^long [^long x ^long y] (+ x y)) (defn reciprocal ^double [^long x] (/ 1.0 x)) ``` -------------------------------- ### Eastwood Linter: Unused Metadata on Macro Invocations (`:unused-meta-on-macro`) Source: https://github.com/jonase/eastwood/blob/master/README.md The `:unused-meta-on-macro` linter identifies instances where metadata applied to a macro invocation is ignored by the Clojure compiler, typically during macro expansion. This is particularly problematic for type hints intended to prevent reflection in Java interop calls. A common workaround involves binding the macro's return value to a symbol with `let` and applying the type hint to that symbol. ```Clojure (require 'clojure.java.io) (import '(java.io Writer StringWriter)) (defn my-fn [x] (clojure.java.io/writer x)) ;; Example behavior below is for Clojure 1.5.0 through 1.7.0 alphas, ;; at least. (defmacro my-macro [x] (if (>= (compare ((juxt :major :minor) *clojure-version*) [1 5]) 0) `(my-fn ~x) 'something-else)) ;; No metadata here, so nothing to lose, and no Eastwood warning. ;; .close call will give reflection warning, though. (.close (my-macro (StringWriter.))) ;; All metadata is discarded, including type tags like ^Writer, which ;; is just a shorthand for ^{:tag Writer}. Clojure will give a ;; reflection warning, which is mightily confusing if you are not ;; aware of this issue. Eastwood will warn about it. (.close ^Writer (my-macro (StringWriter.))) ``` ```Clojure ;; No reflection warning from Clojure, and no warning from Eastwood, ;; for this. (let [^Writer w (my-macro (StringWriter.))] (.close w)) ``` -------------------------------- ### Eastwood Linter: Detecting Implicit Clojure Dependencies Source: https://github.com/jonase/eastwood/blob/master/README.md This linter warns when a qualified var resolves due to `some-namespace` being loaded, even if it's not explicitly required in the current namespace. This can lead to accidental dependencies based on load order. The linter encourages explicit `require` statements for clarity and reliability. ```Clojure (ns a) (some-namespace/foo) ``` ```Clojure (ns a (:require some-namespace)) (some-namespace/foo) ``` -------------------------------- ### Eastwood Linter: Def In Def Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:def-in-def` linter in Eastwood, which warns about `def` forms nested inside other `def` forms. This linter is enabled by default. ```APIDOC Linter Name: :def-in-def Description: def's nested inside other def's. Status: Enabled by default ``` -------------------------------- ### Eastwood Linter: Misplaced Docstrings Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:misplaced-docstrings` linter in Eastwood, which flags function or macro doc strings placed after the argument vector instead of before it. This linter is enabled by default. ```APIDOC Linter Name: :misplaced-docstrings Description: Function or macro doc strings placed after the argument vector, instead of before the argument vector where they belong. Status: Enabled by default ``` -------------------------------- ### Suspicious `clojure.test/is` with Constant First Argument Source: https://github.com/jonase/eastwood/blob/master/README.md Illustrates a common mistake where a constant collection is used as the first argument to `is`, causing the test to always pass because non-nil/non-false values are logically true. Shows the incorrect form and the corrected version using `=` for comparison. ```clojure (is ["josh"] names) ``` ```clojure (is (= ["josh"] names)) ``` -------------------------------- ### Clojure: Unused Local Symbol Warning Source: https://github.com/jonase/eastwood/blob/master/README.md Demonstrates a scenario where a locally bound symbol's value (`a`) is unused, as the function implicitly returns the value of `b`. Eastwood identifies such cases as potential code issues. ```Clojure (defn unused-val [a b] a b) ``` -------------------------------- ### Disabling Eastwood's Wrong Arity Warning for Clojure.java.jdbc/query Source: https://github.com/jonase/eastwood/blob/master/README.md This Clojure configuration snippet demonstrates how to disable the `:wrong-arity` warning for the `clojure.java.jdbc/query` function in Eastwood. It specifies the correct argument lists for linting, overriding the default behavior which might be misled by `:arglists` metadata used purely for documentation in `java.jdbc`. This ensures Eastwood correctly validates the function's arity without false positives. ```clojure (disable-warning {:linter :wrong-arity :function-symbol 'clojure.java.jdbc/query :arglists-for-linting '([db sql-params & {:keys [result-set-fn row-fn identifiers as-arrays?] :or {row-fn identity identifiers str/lower-case}}]) :reason "clojure.java.jdbc/query uses metadata to override the default value of :arglists for documentation purposes. This configuration tells Eastwood what the actual :arglists is, i.e. would have been without that."}) ``` -------------------------------- ### Detecting Redefined Vars in Clojure with Eastwood Source: https://github.com/jonase/eastwood/blob/master/README.md This snippet demonstrates how Eastwood's `:redefd-vars` linter identifies multiple definitions of the same var within a Clojure namespace. While Clojure silently allows this, replacing earlier definitions with later ones, it can lead to lost functionality, especially with `deftest` in `clojure.test`. The linter helps prevent accidental overwrites and ensures all intended code paths are active. ```clojure (defn my-favorite-function-name [x] ;; code here ) ;; lots of other functions here (defn my-favorite-function-name [a b c] ;; different code here ) ``` ```clojure (deftest test-feature-a ;; This test should cause test runs to fail, but IT DOES NOT. (is (= 0 1))) ;; lots of other tests here (deftest test-feature-a ; perhaps written months after the earlier tests (is (= 5 (+ 2 3)))) ``` -------------------------------- ### Incorrect Primitive Type Hints on Clojure Vars Source: https://github.com/jonase/eastwood/blob/master/README.md Illustrates incorrect primitive type hinting on Clojure Vars using the shorthand `^type` syntax (e.g., `^int`). This approach causes Clojure to use the function values of `clojure.core/int`, `clojure.core/bytes`, or `clojure.core/boolean` as type tags, which are ineffective for avoiding reflection. While the Clojure compiler does not warn, the Eastwood linter will identify these issues. ```Clojure ;; Incorrect primitive/primitive-array type hints on Vars, for which ;; Eastwood will warn (def ^int my-int -2) (def ^bytes bytearr1 (byte-array [2 3 4])) (defn ^boolean positive? [x] (> x 0)) ``` -------------------------------- ### Eastwood Linter: Correcting Misplaced Docstrings in Clojure Functions Source: https://github.com/jonase/eastwood/blob/master/README.md This linter identifies docstrings placed after the argument vector in Clojure functions or macros, which is incorrect. It demonstrates the proper placement before the argument vector, explaining that misplaced docstrings prevent `(doc)` from working and hinder documentation extraction tools. ```Clojure (defn my-function "Do the thing, with the stuff. Fast." [thing stuff] (conj stuff thing)) ``` ```Clojure (defn my-function [thing stuff] "Do the thing, with the stuff. Fast." (conj stuff thing)) ``` -------------------------------- ### Eastwood Linter: Constant Test Expression (`:constant-test`) Source: https://github.com/jonase/eastwood/blob/master/README.md The `:constant-test` linter warns when `if`, `cond`, `if-let`, or `when-let` expressions use a test condition that is a compile-time constant or a literal collection, which always evaluates to logical true. This can indicate dead code or logical errors. The warning can be disabled globally via Leiningen configuration or surgically using Eastwood config files. ```Clojure ;; These all cause :constant-test warnings, because the test condition ;; is a compile-time constant. (if false 1 2) (if-not [nil] 1 2) (when-first [x [1 2]] (println "Goodbye")) ;; Even though Eastwood knows that the test condition is not a compile ;; time constant here, it is a map, which always evaluate to logical ;; true in a test condition. (defn foo [x] (if {:a (inc x)} 1 2)) ``` ```Clojure :eastwood {:exclude-linters [:constant-test]} ``` -------------------------------- ### Eastwood Linter: Non-Clojure File Source: https://github.com/jonase/eastwood/blob/master/README.md Documents the `:non-clojure-file` linter in Eastwood, which warns about files that will not be linted because they are not Clojure source files (i.e., their name does not end with '.clj'). This linter is disabled by default. ```APIDOC Linter Name: :non-clojure-file Description: Warn about files that will not be linted because they are not Clojure source files, i.e. their name does not end with '.clj'. Status: Disabled by default ``` -------------------------------- ### Clojure: Intentional local function definition not causing warning Source: https://github.com/jonase/eastwood/blob/master/README.md Illustrates a scenario where a local `replace` binding is intentionally defined as a function, preventing a `:local-shadows-var` warning from Eastwood. ```clojure (let [replace #(str (biginteger %))] (println (replace 5))) ``` -------------------------------- ### Exclude Specific Linter Kinds in Eastwood Source: https://github.com/jonase/eastwood/blob/master/README.md This configuration snippet shows how to use the `:exclude-linters` option to prevent specific kinds of warnings from being emitted by Eastwood linters. It supports excluding individual linter-kind pairs, a vector of kinds for a single linter, or mixing these with keywords to exclude entire linters. This allows fine-grained control over which warnings are reported. ```clj ;; simple pairs of [, ]: :exclude-linters [[:suspicious-test :first-arg-is-constant-true], [:suspicious-test :thrown-regex]] ;; or ;; pairs of [, ]: :exclude-linters [[:suspicious-test [:first-arg-is-constant-true :thrown-regex]]] ;; You can mix and match both syntaxes. ;; You can also mix them with single keywords which denote a whole linter to be omitted: :exclude-linters [:constant-test, [:suspicious-test :first-arg-is-constant-true]] ``` -------------------------------- ### Disabling Specific Eastwood Linter Warnings Source: https://github.com/jonase/eastwood/blob/master/changes.md Details how to disable specific Eastwood linters using the `disable-warning` mechanism to prevent false positives or unwanted warnings for certain code patterns. ```APIDOC Mechanism: disable-warning Linters configurable via this mechanism: - :wrong-arity - :unused-fn-args (disabled by default) - :wrong-tag - :suspicious-test - :unused-meta-on-macro ``` -------------------------------- ### Clojure Macro Usage Causing Unused Private Var Linter Warning Source: https://github.com/jonase/eastwood/blob/master/README.md This Clojure code illustrates a specific case where the `:unused-private-vars` linter in Eastwood may produce an undesirable warning. A private function `private-fn` is invoked indirectly through a public macro `public-macro` using `#'my.ns/private-fn`, which can be difficult for static analysis to detect as a valid usage, leading to a false positive. ```Clojure (defn- private-fn [x] (inc x)) (defmacro public-macro [y] `(#'my.ns/private-fn ~y)) ``` -------------------------------- ### Configure Eastwood to Lint Only Modified Files Source: https://github.com/jonase/eastwood/blob/master/README.md This option instructs Eastwood to lint only files that have been modified since the timestamp stored in the `.eastwood` file. This can significantly speed up linting on large projects by focusing on recent changes. ```clojure :only-modified true ``` -------------------------------- ### Disable Suspicious Expression Warning in Eastwood Config Source: https://github.com/jonase/eastwood/blob/master/README.md This Clojure snippet demonstrates how to use `disable-warning` in an Eastwood config file to suppress `:suspicious-expression` warnings. It specifically targets `clojure.core/let` forms that appear within the macroexpansion of `clojure.core/when-first`, preventing redundant warnings for empty bodies. ```Clojure (disable-warning {:linter :suspicious-expression ;; specifically, those detected in function suspicious-macro-invocations :for-macro 'clojure.core/let :if-inside-macroexpansion-of #{'clojure.core/when-first} :within-depth 6 :reason "when-first with an empty body is warned about, so warning about let with an empty body in its macroexpansion is redundant."}) ```