From d707b1054d831e40b27f6cf844e9a2614a5e298a Mon Sep 17 00:00:00 2001 From: Mark Hudnall Date: Mon, 1 Mar 2021 23:44:17 -0800 Subject: [PATCH 1/3] Simplify checkers and add solhint - Add a checker for solhint - Simplify checkers. This commit removes some of the load-time logic that determined whether to define the flycheck checkers. Flycheck has its own logic to enable or disable checkers based on the presence of the :command binary, making these checks redundant. Some of the other checks done at load time have been moved into (eval ...) forms, so that the binaries can be customized after load-time with flycheck's pre-defined vars e.g. `flycheck-solium-checker-executable'. This is useful when linting binaries are installed locally in a project. --- solidity-common.el | 6 ++ solidity-flycheck.el | 207 +++++++++++++++++++++++-------------------- 2 files changed, 116 insertions(+), 97 deletions(-) diff --git a/solidity-common.el b/solidity-common.el index 3527912..a830742 100644 --- a/solidity-common.el +++ b/solidity-common.el @@ -37,5 +37,11 @@ :type 'string :package-version '(solidity . "0.1.4")) +(defcustom solidity-solhint-path "solhint" + "Path to the solium binary." + :group 'solidity + :type 'string + :package-version '(solidity . "0.1.12")) + (provide 'solidity-common) ;;; solidity-common.el ends here diff --git a/solidity-flycheck.el b/solidity-flycheck.el index 4147a40..796f921 100644 --- a/solidity-flycheck.el +++ b/solidity-flycheck.el @@ -30,16 +30,7 @@ (require 'flycheck) (require 'solidity-common) (require 'dash) - -(defvar flycheck-solidity-checker-executable) -(defvar flycheck-solium-checker-executable) - -(defcustom solidity-flycheck-solc-checker-active nil - "A boolean flag denoting if solc flycheck checker should be active." - :group 'solidity - :type 'boolean - :safe #'booleanp - :package-version '(solidity . "0.1.5")) +(require 'project) (defcustom solidity-flycheck-chaining-error-level 'warning "The maximum error level at which chaining of checkers will happen. @@ -69,13 +60,6 @@ Possible values are: :package-version '(solidity . "0.1.5") :safe #'symbolp) -(defcustom solidity-flycheck-solium-checker-active nil - "A boolean flag denoting if solium flycheck checker should be active." - :group 'solidity - :type 'boolean - :safe #'booleanp - :package-version '(solidity . "0.1.5")) - (flycheck-def-option-var flycheck-solidity-solium-soliumrcfile nil solium-check "The path to use for soliumrc.json @@ -111,13 +95,15 @@ during compilation and linting. solidity-flycheck will look for a .soliumrc.json in a parent directory. If found, this directory is considered the project root. If no .soliumrc.json is found, `project-roots' is used. -When `solidity-flycheck-solium-checker-active' is t, the .soliumrc.json found in -the project root will be used as the solium config, rather than a .soliumrc.json -in the same directory as the file being linted. +When using solium-checker, the .soliumrc.json found in the project root will be +used as the solium config, rather than a .soliumrc.json in the same directory as +the file being linted. -When `solidity-flycheck-solc-checker-active' is t, the project root will be passed -to solc using the --allow-paths flag. This means imports to other files inside the -project will lint without erorr." +When using solhint-checker, solhint will be run at the project root. + +When using solidity-checker , the project root will be passed to solc using the +--allow-paths flag. This means imports to other files inside the project will +lint without erorr." :group 'solidity :type 'boolean :safe #'booleanp @@ -136,45 +122,52 @@ no .soliumrc.json is found, `project-roots' is used." (car roots))))) (expand-file-name root)))) -(when solidity-flycheck-solium-checker-active ;; define solium flycheck syntax checker ;; expanded the flycheck-define-checker macro in order to eval certain args, as per advice given in gitter ;; https://gitter.im/flycheck/flycheck?at=5a43b3a8232e79134d98872b ;; first try to add solium to the checker's list since if we got solc ;; it must come after it in the list due to it being chained after solc - (flycheck-def-executable-var solium-checker "solium") - (let ((solium-full-path (funcall flycheck-executable-find solidity-solium-path))) - (if solium-full-path - (let ((solium-has-reporter (string-match-p "--reporter" (shell-command-to-string (concat solium-full-path " --help"))))) - (flycheck-define-command-checker 'solium-checker - "A Solidity linter using solium" - :command `("solium" - ,(if solium-has-reporter "--reporter=gcc" "") - (option "--config=" flycheck-solidity-solium-soliumrcfile concat) - "-f" - source-inplace) - :error-patterns `((error line-start (zero-or-more not-newline) "[Fatal error]" (message)) - ,(if solium-has-reporter - '(error line-start (file-name) ":" line ":" column ": error: " (message)) - '(error line-start (zero-or-more " ") line ":" column (zero-or-more " ") "error" (message))) - ,(if solium-has-reporter - '(warning line-start (file-name) ":" line ":" column ": warning: " (message)) - '(warning line-start (zero-or-more " ") line ":" column (zero-or-more " ") "warning" (message)))) - :error-filter - ;; Add fake line numbers if they are missing in the lint output - #'(lambda (errors) - (dolist (err errors) - (unless (flycheck-error-line err) - (setf (flycheck-error-line err) 1))) - errors) - :modes 'solidity-mode - :predicate #'(lambda nil (eq major-mode 'solidity-mode)) - :next-checkers 'nil - :standard-input 'nil - :working-directory 'solidity-flycheck--find-working-directory) - (add-to-list 'flycheck-checkers 'solium-checker) - (setq flycheck-solium-checker-executable solidity-solium-path)) - (error (format "Solidity Mode Configuration error. Requested solium flycheck integration but can't find solium at: %s" solidity-solium-path))))) +(flycheck-def-executable-var solium-checker "solium") + +(defun solium-has-reporter () + (let ((solium-full-path (funcall + flycheck-executable-find + (or flycheck-solium-checker-executable solidity-solium-path)))) + (and solium-full-path + (string-match-p "--reporter" (shell-command-to-string (concat solium-full-path " --help")))))) + +(flycheck-define-command-checker 'solium-checker + "A Solidity linter using solium" + :command `(,solidity-solium-path + (eval (when (solium-has-reporter) "--reporter=gcc")) + (option "--config=" flycheck-solidity-solium-soliumrcfile concat) + "-f" + source-inplace) +:error-patterns `((error line-start (zero-or-more not-newline) "[Fatal error]" (message)) + (error line-start (zero-or-more " ") line ":" column (zero-or-more " ") "error" (message)) + (warning line-start (zero-or-more " ") line ":" column (zero-or-more " ") "warning" (message)) + ;; reporter=gcc formats + (error line-start (file-name) ":" line ":" column ": error: " (message)) + (warning line-start (file-name) ":" line ":" column ": warning: " (message))) + + :error-filter + ;; Add fake line numbers if they are missing in the lint output + #'(lambda (errors) + (dolist (err errors) + (unless (flycheck-error-line err) + (setf (flycheck-error-line err) 1))) + errors) + :modes 'solidity-mode + :predicate #'(lambda nil (eq major-mode 'solidity-mode)) + :next-checkers `((,solidity-flycheck-chaining-error-level . solhint-checker)) + :standard-input 'nil + :working-directory 'solidity-flycheck--find-working-directory) + +;; add a solidity mode callback to set the executable of solc for flycheck +;; define solidity's flycheck syntax checker +;; expanded the flycheck-define-checker macro in order to eval certain args, as per advice given in gitter +;; https://gitter.im/flycheck/flycheck?at=5a43b3a8232e79134d98872b +(flycheck-def-executable-var solidity-checker "solc") (defun get-solc-version () "Query solc executable and return its version. @@ -182,12 +175,15 @@ no .soliumrc.json is found, `project-roots' is used." The result is returned in a list with 3 elements.MAJOR MINOR PATCH. If the solc output can't be parsed an error is returned." - (let ((output (shell-command-to-string (format "%s --version" solidity-solc-path)))) + (let* ((solc-full-path (funcall + flycheck-executable-find + (or flycheck-solidity-checker-executable solidity-solc-path))) + (output (shell-command-to-string (format "%s --version" solc-full-path)))) (if (string-match "Version: \\([[:digit:]]+\\)\.\\([[:digit:]]+\\)\.\\([[:digit:]]+\\)" output) (list (match-string 1 output) (match-string 2 output) (match-string 3 output)) - (error "Could not parse the output of %s --version:\n %s" solidity-solc-path output)))) + (error "Could not parse the output of %s --version:\n %s" solc-full-path output)))) (defun solc-gt-0.6.0 () "Return `t` if solc >= 0.6.0 and `nil` otherwise." @@ -230,44 +226,61 @@ no .soliumrc.json is found, `project-roots' is used." `("--allow-paths" ,allow-paths)))) (defun solidity-flycheck--solc-cmd () - (if (solc-gt-0.6.0) - `("solc" - "--no-color" - ,@(solidity-flycheck--solc-allow-paths-opt) - ,@(solidity-flycheck--solc-remappings-opt) - source-inplace) - '("solc" source-inplace))) - -(when solidity-flycheck-solc-checker-active - ;; add a solidity mode callback to set the executable of solc for flycheck - ;; define solidity's flycheck syntax checker - ;; expanded the flycheck-define-checker macro in order to eval certain args, as per advice given in gitter - ;; https://gitter.im/flycheck/flycheck?at=5a43b3a8232e79134d98872b - (flycheck-def-executable-var solidity-checker "solc") - (let* ((cmd (solidity-flycheck--solc-cmd))) - (if (funcall flycheck-executable-find solidity-solc-path) - (progn - (flycheck-define-command-checker 'solidity-checker - "A Solidity syntax checker using the solc compiler" - :command cmd - :error-patterns '( - ;; Solidity >= 0.6.0 error formats - (error line-start "Error: " (message) "\n" (zero-or-more whitespace) "--> " (file-name) ":" line ":" column) - (warning line-start "Warning: " (message) "\n" (zero-or-more whitespace) "--> " (file-name) ":" line ":" column) - - ;; Solidity < 0.6.0 error formats - (error line-start (file-name) ":" line ":" column ":" " Error: " (message)) - (error line-start (file-name) ":" line ":" column ":" " Compiler error: " (message)) - (error line-start "Error: " (message)) - (warning line-start (file-name) ":" line ":" column ":" " Warning: " (message))) - :modes 'solidity-mode - :predicate #'(lambda nil (eq major-mode 'solidity-mode)) - :next-checkers `((,solidity-flycheck-chaining-error-level . solium-checker)) - :standard-input 'nil - :working-directory 'solidity-flycheck--find-working-directory) - (add-to-list 'flycheck-checkers 'solidity-checker) - (setq flycheck-solidity-checker-executable solidity-solc-path)) - (error (format "Solidity Mode Configuration error. Requested solc flycheck integration but can't find solc at: %s" solidity-solc-path))))) + `(,solidity-solc-path + (eval + (when (solc-gt-0.6.0) + `("--no-color" + ,@(solidity-flycheck--solc-allow-paths-opt) + ,@(solidity-flycheck--solc-remappings-opt)))) + source-inplace)) + +(flycheck-define-command-checker 'solidity-checker + "A Solidity syntax checker using the solc compiler" + :command (solidity-flycheck--solc-cmd) + :error-patterns '( + ;; Solidity >= 0.6.0 error formats + (error line-start "Error: " (message) "\n" (zero-or-more whitespace) "--> " (file-name) ":" line ":" column) + (warning line-start "Warning: " (message) "\n" (zero-or-more whitespace) "--> " (file-name) ":" line ":" column) + + ;; Solidity < 0.6.0 error formats + (error line-start (file-name) ":" line ":" column ":" " Error: " (message)) + (error line-start (file-name) ":" line ":" column ":" " Compiler error: " (message)) + (error line-start "Error: " (message)) + (warning line-start (file-name) ":" line ":" column ":" " Warning: " (message))) + :modes 'solidity-mode + :predicate #'(lambda nil (eq major-mode 'solidity-mode)) + :next-checkers + `((,solidity-flycheck-chaining-error-level . solium-checker) + (,solidity-flycheck-chaining-error-level . solhint-checker)) + :standard-input 'nil + :working-directory 'solidity-flycheck--find-working-directory) + +(flycheck-def-executable-var solhint-checker "solhint") +(flycheck-define-command-checker 'solhint-checker + "A Solidity linter using solhint" + :command `(,solidity-solhint-path "-f" "visualstudio" source-inplace) + :error-patterns `((error + line-start (file-name) "(" line "," column "):" (zero-or-more " ") + "error" (zero-or-more " ") (message)) + (warning + line-start (file-name) "(" line "," column "):" (zero-or-more " ") + "warning" (zero-or-more " ") (message))) + :error-filter + ;; Add fake line numbers if they are missing in the lint output + #'(lambda (errors) + (dolist (err errors) + (unless (flycheck-error-line err) + (setf (flycheck-error-line err) 1))) + errors) + :modes 'solidity-mode + :predicate #'(lambda nil (eq major-mode 'solidity-mode)) + :next-checkers 'nil + :standard-input 'nil + :working-directory 'solidity-flycheck--find-working-directory) + +(add-to-list 'flycheck-checkers 'solhint-checker) +(add-to-list 'flycheck-checkers 'solium-checker) +(add-to-list 'flycheck-checkers 'solidity-checker) (provide 'solidity-flycheck) ;;; solidity-flycheck.el ends here From d3901a3291e85822c0630b09d107c520b02bdfea Mon Sep 17 00:00:00 2001 From: Mark Hudnall Date: Tue, 18 Oct 2022 21:39:40 -0700 Subject: [PATCH 2/3] Use unix formatter The unix formatter is documented, while the visualstudio formatter is not. Prefer the unix formatter. --- solidity-flycheck.el | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/solidity-flycheck.el b/solidity-flycheck.el index 796f921..5e48d8f 100644 --- a/solidity-flycheck.el +++ b/solidity-flycheck.el @@ -258,13 +258,13 @@ no .soliumrc.json is found, `project-roots' is used." (flycheck-def-executable-var solhint-checker "solhint") (flycheck-define-command-checker 'solhint-checker "A Solidity linter using solhint" - :command `(,solidity-solhint-path "-f" "visualstudio" source-inplace) + :command `(,solidity-solhint-path "-f" "unix" source-inplace) :error-patterns `((error - line-start (file-name) "(" line "," column "):" (zero-or-more " ") - "error" (zero-or-more " ") (message)) + line-start (file-name) ":" line ":" column ":" (zero-or-more " ") + (zero-or-more " ") (message (one-or-more not-newline) "[Error/" (one-or-more not-newline) "]" )) (warning - line-start (file-name) "(" line "," column "):" (zero-or-more " ") - "warning" (zero-or-more " ") (message))) + line-start (file-name) ":" line ":" column ":" (zero-or-more " ") + (zero-or-more " ") (message (one-or-more not-newline) "[Warning/" (one-or-more not-newline) "]" ))) :error-filter ;; Add fake line numbers if they are missing in the lint output #'(lambda (errors) From 699d9645910706aa32fdfe58fccd8d42f83e072e Mon Sep 17 00:00:00 2001 From: Mark Hudnall Date: Tue, 18 Oct 2022 21:41:52 -0700 Subject: [PATCH 3/3] Fix typo --- solidity-common.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solidity-common.el b/solidity-common.el index a830742..bbc3fcd 100644 --- a/solidity-common.el +++ b/solidity-common.el @@ -38,7 +38,7 @@ :package-version '(solidity . "0.1.4")) (defcustom solidity-solhint-path "solhint" - "Path to the solium binary." + "Path to the solhint binary." :group 'solidity :type 'string :package-version '(solidity . "0.1.12"))