Repository: protofire/solhint
Pull request #536 (2024-01-08 13:46:03)

Release 4.1.0 - Develop to Master


Patch:
diff --git a/.github/workflows/DOCKER.yml b/.github/workflows/DOCKER.yml
new file mode 100644
index 0000000..394ebfe
--- /dev/null
+++ b/.github/workflows/DOCKER.yml
@@ -0,0 +1,29 @@
+name: Docker Image CI
+
+on:
+  workflow_dispatch:
+    inputs:
+      version:
+        description: 'Solhint version'
+        required: true
+      image_name:
+        description: 'Name of image to be used on docker hub'
+        required: true
+        default: 'protodb/protofire-solhint'
+jobs:
+
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v3
+
+    - name: Login to Docker Hub
+      run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_ACCESS_TOKEN }}
+
+    - name: Build Docker image
+      run: docker build . --file docker/Dockerfile --tag ${{ inputs.image_name }}:${{ inputs.version }} --build-arg VERSION=${{ inputs.version }}
+
+    - name: Push Docker image to Docker Hub
+      run: docker push ${{ inputs.image_name }}:${{ inputs.version }}
diff --git a/.gitignore b/.gitignore
index 8f52611..5086acd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,6 @@ antlr4.jar
 /docs/.sass-cache/
 _temp/
 *solhintReport*.*
+.env
+**/.DS_Store
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 96c84c9..ed6ef12 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,25 @@
-## [4.0] - 2023-10-01
+## [4.1.0] - 2024-01- ????????????????????
+
+### Updated
+- Included `Sarif` formatter [#530](https://github.com/protofire/solhint/pull/530) (Thanks to [@eshaan7](https://github.com/eshaan7))
+- Cache `npm` on workflows [#534](https://github.com/protofire/solhint/pull/534)
+
+
+### Added
+- Official Docker Image [#524](https://github.com/protofire/solhint/pull/524) (Thanks to [@keypee](https://github.com/keypee90))
+- Autofix for `payable-fallback` rule [#528](https://github.com/protofire/solhint/pull/528)
+- Autofix for `quotes` rule [#529](https://github.com/protofire/solhint/pull/529)
+- Autofix for `avoid-suicide` rule [#531](https://github.com/protofire/solhint/pull/531)
+- Autofix for `contract-name-camelcase` rule [#532](https://github.com/protofire/solhint/pull/532)
+- Autofix for `event-name-camelcase` rule [#533](https://github.com/protofire/solhint/pull/533)
+
+### Fixed
+- Fix private vars leading underscore on libraries [#525](https://github.com/protofire/solhint/pull/525)
+
+ 
+
+
+## [4.0.0] - 2023-10-01
 
 ### Updated
 - Enhance explicit types sensitivity [#493](https://github.com/protofire/solhint/pull/493) (Thanks to [@vladyan18](https://github.com/vladyan18))
diff --git a/README.md b/README.md
index 27ffa79..1d31513 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,12 @@
 <p align="center">
-  <img src="solhint.png">
+  <a href="https://protofire.io/projects/solhint"><img src="solhint.png"></a>
 </p>
 <p align="center">
   By <a href="https://protofire.io/">Protofire</a>
 </p>
 
-[![Join Discord](https://img.shields.io/badge/join-Discord-red)](https://discord.gg/4TYGq3zpjs)
+[![](https://img.shields.io/badge/Solhint%20Website-cyan)](https://protofire.io/projects/solhint)
+[![](https://img.shields.io/badge/Join%20Our%20Discord-magenta)](https://discord.gg/4TYGq3zpjs)
 [![Donate with Ethereum](https://img.shields.io/badge/Donate-ETH-blue)](https://etherscan.io/address/0xA81705c8C247C413a19A244938ae7f4A0393944e)
 [![NPM version](https://badge.fury.io/js/solhint.svg)](https://npmjs.org/package/solhint)
 [![Coverage Status](https://coveralls.io/repos/github/protofire/solhint/badge.svg?branch=master)](
@@ -14,8 +15,10 @@ https://coveralls.io/github/protofire/solhint?branch=master)
 
 This is an open source project for linting [Solidity](http://solidity.readthedocs.io/en/develop/) code. This project
 provides both **Security** and **Style Guide** validations.
-
+<br>
+[VISIT OUR WEBSITE](https://protofire.io/projects/solhint)<br>
 [JOIN OUR DISCORD SERVER](https://discord.gg/4TYGq3zpjs)
+<br>
 ## Installation
 
 You can install Solhint using **npm**:
@@ -57,7 +60,7 @@ Linter for Solidity programming language
 Options:
 
   -V, --version                           output the version number
-  -f, --formatter [name]                  report formatter name (stylish, table, tap, unix, json, compact)
+  -f, --formatter [name]                  report formatter name (stylish, table, tap, unix, json, compact, sarif)
   -w, --max-warnings [maxWarningsNumber]  number of allowed warnings
   -c, --config [file_name]                file to use as your .solhint.json
   -q, --quiet                             report errors only - default: false
@@ -198,8 +201,11 @@ Or disable all validations for a group of lines:
 ### Best Practices Rules
 [Full list with all supported Best Practices Rules](docs/rules.md#best-practise-rules)
 
-## Documentation
+## Docker
+### Solhint has an official Docker Image
+Go to docker folder and follow [this](docker/docker.md) instructions.
 
+## Documentation
 Related documentation you may find [here](https://protofire.github.io/solhint/).
 
 ## IDE Integrations
diff --git a/ROADMAP.md b/ROADMAP.md
deleted file mode 100644
index 4b90f8d..0000000
--- a/ROADMAP.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Roadmap
-
-An overview of what the core Solhint team is looking to work on over the next few months.
-
-As a caveat - this is a living doc, and will evolve as priorities grow and shift. The Solhint project will always be adapting to new use-cases and evolutions in the blockchain world - this roadmap is more of a "North Star" of what we're looking to work on than a strict timeline.
-
-Please feel free to fill issues on this repository if you have questions, concerns, or suggestions.
-
-
-## What's next?
-
-So, what will that new chapter hold? We see a few major themes...
-
-This is our next releases plan:
-
-- 1.4.0 [released on Oct 10, 2018]
-  - Support prettier-solidity [#72]
-- 2.0.0.beta.1 [released beta version on Jan 31, 2019]
-  - Switch from Blocklisting to Rulesets + Allowlisting [#73]
-  - Plugins support [#70]
-  - Support prettier-solidity as a plugin [#72]
-- 2.1.0
-  - Separate core library from CLI app [#69]
\ No newline at end of file
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..5ace919
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,5 @@
+FROM node:20-alpine
+LABEL maintainer="diego.bale@protofire.io" 
+ENV VERSION=4.1.0
+
+RUN npm install -g solhint@"$VERSION"
\ No newline at end of file
diff --git a/docker/docker.md b/docker/docker.md
new file mode 100644
index 0000000..de4c36f
--- /dev/null
+++ b/docker/docker.md
@@ -0,0 +1,25 @@
+# Docker Instructions
+Thanks to [@kaypee90](https://github.com/kaypee90) for the contribution<br><br>
+
+1. Get the image. Run:<br>
+`docker pull protodb/protofire-solhint:latest`
+
+2. Check if image is present (protodb/protofire-solhint:latest)<br>
+`docker images`
+
+3. Solhint use:<br>
+
+- Execute solhint with default config file<br>
+`docker run -v ./:/app -w /app -it protodb/protofire-solhint solhint './contracts/*.sol'`
+
+This command:<br>
+- Maps current folder to app/ inside container<br>
+- Executes solhint in './contracts/*.sol'<br>
+
+- Navigate inside container sharing current folder into app/ container folder<br>
+`docker run -v ./:/app -w /app -it protodb/protofire-solhint /bin/sh`<br>
+
+This command:<br>
+- Maps current folder to app/ container folder<br>
+- Can run solhint inside the container by typing `solhint ./contracts/*.sol`<br>
+(use your correct path, type exit to finish)<br>
diff --git a/docs/rules.md b/docs/rules.md
index 64185cd..4bded6c 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -38,7 +38,7 @@ title:       "Rule Index of Solhint"
 | Rule Id                                                                              | Error                                                                                                         | Recommended  | Deprecated  |
 | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | ------------ | ----------- |
 | [const-name-snakecase](./rules/naming/const-name-snakecase.md)                       | Constant name must be in capitalized SNAKE_CASE. (Does not check IMMUTABLES, use immutable-vars-naming)       | $~~~~~~~~$✔️ |             |
-| [contract-name-camelcase](./rules/naming/contract-name-camelcase.md)                 | Contract name must be in CamelCase.                                                                           | $~~~~~~~~$✔️ |             |
+| [contract-name-camelcase](./rules/naming/contract-name-camelcase.md)                 | Contract, Structs and Enums should be in CamelCase.                                                           | $~~~~~~~~$✔️ |             |
 | [event-name-camelcase](./rules/naming/event-name-camelcase.md)                       | Event name must be in CamelCase.                                                                              | $~~~~~~~~$✔️ |             |
 | [foundry-test-functions](./rules/naming/foundry-test-functions.md)                   | Enforce naming convention on functions for Foundry test cases                                                 |              |             |
 | [func-name-mixedcase](./rules/naming/func-name-mixedcase.md)                         | Function name must be in mixedCase.                                                                           | $~~~~~~~~$✔️ |             |
diff --git a/docs/rules/best-practises/no-console.md b/docs/rules/best-practises/no-console.md
index da6676e..84f6549 100644
--- a/docs/rules/best-practises/no-console.md
+++ b/docs/rules/best-practises/no-console.md
@@ -28,6 +28,8 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 }
 ```
 
+### Notes
+- Solhint allows this rule to automatically fix the code with `--fix` option
 
 ## Examples
 ### 👎 Examples of **incorrect** code for this rule
diff --git a/docs/rules/best-practises/payable-fallback.md b/docs/rules/best-practises/payable-fallback.md
index 4350d04..be0f61f 100644
--- a/docs/rules/best-practises/payable-fallback.md
+++ b/docs/rules/best-practises/payable-fallback.md
@@ -26,6 +26,8 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 }
 ```
 
+### Notes
+- Solhint allows this rule to automatically fix the code with `--fix` option
 
 ## Examples
 ### 👍 Examples of **correct** code for this rule
diff --git a/docs/rules/naming/contract-name-camelcase.md b/docs/rules/naming/contract-name-camelcase.md
index 5165c2e..03fca32 100644
--- a/docs/rules/naming/contract-name-camelcase.md
+++ b/docs/rules/naming/contract-name-camelcase.md
@@ -12,7 +12,7 @@ title:       "contract-name-camelcase | Solhint"
 
 
 ## Description
-Contract name must be in CamelCase.
+Contract, Structs and Enums should be in CamelCase.
 
 ## Options
 This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Default to warn.
@@ -26,6 +26,9 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 }
 ```
 
+### Notes
+- Solhint allows this rule to automatically fix the code with `--fix` option
+- The FIX will only change first letter and remove underscores
 
 ## Examples
 This rule does not have examples.
diff --git a/docs/rules/naming/event-name-camelcase.md b/docs/rules/naming/event-name-camelcase.md
index 7020782..a6c00b6 100644
--- a/docs/rules/naming/event-name-camelcase.md
+++ b/docs/rules/naming/event-name-camelcase.md
@@ -26,6 +26,9 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 }
 ```
 
+### Notes
+- Solhint allows this rule to automatically fix the code with `--fix` option
+- The FIX will only change first letter and remove underscores
 
 ## Examples
 This rule does not have examples.
diff --git a/docs/rules/naming/private-vars-leading-underscore.md b/docs/rules/naming/private-vars-leading-underscore.md
index bba9e89..a638d31 100644
--- a/docs/rules/naming/private-vars-leading-underscore.md
+++ b/docs/rules/naming/private-vars-leading-underscore.md
@@ -30,10 +30,11 @@ This rule accepts an array of options:
 ```
 
 ### Notes
-- This rule considers functions and variables in Libraries as well
+- This rule DO NOT considers functions and variables in Libraries
 - This rule skips external and public functions
 - This rule skips external and public state variables
 - See [here](https://docs.soliditylang.org/en/latest/style-guide.html#underscore-prefix-for-non-external-functions-and-variables) for further information
+- Solhint allows this rule to automatically fix the code with `--fix` option
 
 ## Examples
 ### 👍 Examples of **correct** code for this rule
diff --git a/lib/common/ast-types.js b/lib/common/ast-types.js
index 0bdae5a..d2fbe4d 100644
--- a/lib/common/ast-types.js
+++ b/lib/common/ast-types.js
@@ -1,5 +1,5 @@
 function isFallbackFunction(node) {
-  return isFunctionDefinition(node) && node.isFallback
+  return isFunctionDefinition(node) && (node.isFallback || node.isReceiveEther)
 }
 
 function isReceiveFunction(node) {
diff --git a/lib/formatters/README.md b/lib/formatters/README.md
index 9d6ee6c..ae5c147 100644
--- a/lib/formatters/README.md
+++ b/lib/formatters/README.md
@@ -8,4 +8,5 @@ files in this directory are pulled from eslint repository:
 - stylish.js: eslint - Sindre Sorhus
 - json.js: eslint - Artur Lukianov
 - compact.js: eslint - Nicholas C. Zakas
+- sarif.js: [@microsoft/eslint-formatter-sarif](https://www.npmjs.com/package/@microsoft/eslint-formatter-sarif)
   
\ No newline at end of file
diff --git a/lib/formatters/sarif.js b/lib/formatters/sarif.js
new file mode 100644
index 0000000..52f51cb
--- /dev/null
+++ b/lib/formatters/sarif.js
@@ -0,0 +1,264 @@
+/**
+ * @fileoverview SARIF v2.1 formatter
+ * @author Adapted for solhint by @eshaan7 (Original: Microsoft <https://www.npmjs.com/package/@microsoft/eslint-formatter-sarif>)
+ */
+
+const url = require('url')
+const lodash = require('lodash')
+
+//------------------------------------------------------------------------------
+// Helper Functions
+//------------------------------------------------------------------------------
+
+/**
+ * Returns the version of used solhint package
+ * @returns {string} solhint version or undefined
+ * @private
+ */
+function getSolhintVersion() {
+  try {
+    // Resolve solhint relative to main entry script, not the formatter
+    const solhintPackageJson = require('../../package.json')
+    return solhintPackageJson.version
+  } catch {
+    // Formatter was not called from solhint, return undefined
+  }
+}
+
+/**
+ * Returns the severity of warning or error
+ * @param {Object} message message object to examine
+ * @returns {string} severity level
+ * @private
+ */
+function getResultLevel(message) {
+  if (message.fatal || message.severity === 2) {
+    return 'error'
+  }
+  return 'warning'
+}
+
+//------------------------------------------------------------------------------
+// Public Interface
+//------------------------------------------------------------------------------
+
+module.exports = function (results, data) {
+  const rulesMeta = lodash.get(data, 'rulesMeta', null)
+
+  const sarifLog = {
+    version: '2.1.0',
+    $schema: 'http://json.schemastore.org/sarif-2.1.0-rtm.5',
+    runs: [
+      {
+        tool: {
+          driver: {
+            name: 'solhint',
+            informationUri: 'https://github.com/protofire/solhint',
+            rules: [],
+          },
+        },
+      },
+    ],
+  }
+
+  const solhintVersion = getSolhintVersion()
+  if (typeof solhintVersion !== 'undefined') {
+    sarifLog.runs[0].tool.driver.version = solhintVersion
+  }
+
+  const sarifFiles = {}
+  const sarifArtifactIndices = {}
+  let nextArtifactIndex = 0
+  const sarifRules = {}
+  const sarifRuleIndices = {}
+  let nextRuleIndex = 0
+  const sarifResults = []
+
+  // Emit a tool configuration notification with this id if ESLint emits a message with
+  // no ruleId (which indicates an internal error in ESLint).
+  //
+  // It is not clear whether we should treat these messages tool configuration notifications,
+  // tool execution notifications, or a mixture of the two, based on the properties of the
+  // message. https://github.com/microsoft/sarif-sdk/issues/1798, "ESLint formatter can't
+  // distinguish between an internal error and a misconfiguration", tracks this issue.
+  const internalErrorId = 'ESL0999'
+
+  const toolConfigurationNotifications = []
+  let executionSuccessful = true
+
+  for (const result of results) {
+    // Only add it if not already there.
+    if (typeof sarifFiles[result.filePath] === 'undefined') {
+      sarifArtifactIndices[result.filePath] = nextArtifactIndex++
+
+      // Create a new entry in the files dictionary.
+      sarifFiles[result.filePath] = {
+        location: {
+          uri: url.pathToFileURL(result.filePath),
+        },
+      }
+
+      const containsSuppressedMessages =
+        result.suppressedMessages && result.suppressedMessages.length > 0
+      const messages = containsSuppressedMessages
+        ? [...result.messages, ...result.suppressedMessages]
+        : result.messages
+
+      if (messages.length > 0) {
+        for (const message of messages) {
+          const sarifRepresentation = {
+            level: getResultLevel(message),
+            message: {
+              text: message.message,
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: url.pathToFileURL(result.filePath),
+                    index: sarifArtifactIndices[result.filePath],
+                  },
+                },
+              },
+            ],
+          }
+
+          if (message.ruleId) {
+            sarifRepresentation.ruleId = message.ruleId
+
+            if (rulesMeta && typeof sarifRules[message.ruleId] === 'undefined') {
+              const meta = rulesMeta[message.ruleId]
+
+              // An unknown ruleId will return null. This check prevents unit test failure.
+              if (meta) {
+                sarifRuleIndices[message.ruleId] = nextRuleIndex++
+
+                if (meta.docs) {
+                  // Create a new entry in the rules dictionary.
+                  sarifRules[message.ruleId] = {
+                    id: message.ruleId,
+                    helpUri: meta.docs.url,
+                    properties: {
+                      category: meta.docs.category,
+                    },
+                  }
+                  if (meta.docs.description) {
+                    sarifRules[message.ruleId].shortDescription = {
+                      text: meta.docs.description,
+                    }
+                  }
+                  // Some rulesMetas do not have docs property
+                } else {
+                  sarifRules[message.ruleId] = {
+                    id: message.ruleId,
+                    helpUri: 'Please see details in message',
+                    properties: {
+                      category: 'No category provided',
+                    },
+                  }
+                }
+              }
+            }
+
+            if (sarifRuleIndices[message.ruleId] !== 'undefined') {
+              sarifRepresentation.ruleIndex = sarifRuleIndices[message.ruleId]
+            }
+
+            if (containsSuppressedMessages) {
+              sarifRepresentation.suppressions = message.suppressions
+                ? message.suppressions.map((suppression) => {
+                    return {
+                      kind: suppression.kind === 'directive' ? 'inSource' : 'external',
+                      justification: suppression.justification,
+                    }
+                  })
+                : []
+            }
+          } else {
+            // ESLint produces a message with no ruleId when it encounters an internal
+            // error. SARIF represents this as a tool execution notification rather
+            // than as a result, and a notification has a descriptor.id property rather
+            // than a ruleId property.
+            sarifRepresentation.descriptor = {
+              id: internalErrorId,
+            }
+
+            // As far as we know, whenever ESLint produces a message with no rule id,
+            // it has severity: 2 which corresponds to a SARIF error. But check here
+            // anyway.
+            if (sarifRepresentation.level === 'error') {
+              // An error-level notification means that the tool failed to complete
+              // its task.
+              executionSuccessful = false
+            }
+          }
+
+          if (message.line > 0 || message.column > 0) {
+            sarifRepresentation.locations[0].physicalLocation.region = {}
+            if (message.line > 0) {
+              sarifRepresentation.locations[0].physicalLocation.region.startLine = message.line
+            }
+            if (message.column > 0) {
+              sarifRepresentation.locations[0].physicalLocation.region.startColumn = message.column
+            }
+            if (message.endLine > 0) {
+              sarifRepresentation.locations[0].physicalLocation.region.endLine = message.endLine
+            }
+            if (message.endColumn > 0) {
+              sarifRepresentation.locations[0].physicalLocation.region.endColumn = message.endColumn
+            }
+          }
+
+          if (message.source) {
+            // Create an empty region if we don't already have one from the line / column block above.
+            sarifRepresentation.locations[0].physicalLocation.region =
+              sarifRepresentation.locations[0].physicalLocation.region || {}
+            sarifRepresentation.locations[0].physicalLocation.region.snippet = {
+              text: message.source,
+            }
+          }
+
+          if (message.ruleId) {
+            sarifResults.push(sarifRepresentation)
+          } else {
+            toolConfigurationNotifications.push(sarifRepresentation)
+          }
+        }
+      }
+    }
+  }
+
+  if (Object.keys(sarifFiles).length > 0) {
+    sarifLog.runs[0].artifacts = []
+
+    for (const path of Object.keys(sarifFiles)) {
+      sarifLog.runs[0].artifacts.push(sarifFiles[path])
+    }
+  }
+
+  // Per the SARIF spec §3.14.23, run.results must be present even if there are no results.
+  // This provides a positive indication that the run completed and no results were found.
+  sarifLog.runs[0].results = sarifResults
+
+  if (toolConfigurationNotifications.length > 0) {
+    sarifLog.runs[0].invocations = [
+      {
+        toolConfigurationNotifications,
+        executionSuccessful,
+      },
+    ]
+  }
+
+  if (Object.keys(sarifRules).length > 0) {
+    for (const ruleId of Object.keys(sarifRules)) {
+      const rule = sarifRules[ruleId]
+      sarifLog.runs[0].tool.driver.rules.push(rule)
+    }
+  }
+
+  return JSON.stringify(
+    sarifLog,
+    null, // replacer function
+    2 // # of spaces for indents
+  )
+}
diff --git a/lib/index.js b/lib/index.js
index 1c10e66..f7a2fd3 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -41,7 +41,7 @@ function processStr(inputStr, config = {}, fileName = '') {
     }
   }
 
-  const tokens = parser.tokenize(inputStr, { loc: true })
+  const tokens = parser.tokenize(inputStr, { loc: true, range: true })
   const reporter = new Reporter(tokens, config)
   const listener = new TreeListener(checkers(reporter, config, inputStr, tokens, fileName))
 
diff --git a/lib/rules/best-practises/no-console.js b/lib/rules/best-practises/no-console.js
index c6156fb..1a8a0fa 100644
--- a/lib/rules/best-practises/no-console.js
+++ b/lib/rules/best-practises/no-console.js
@@ -23,6 +23,11 @@ const meta = {
         },
       ],
     },
+    notes: [
+      {
+        note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
+      },
+    ],
   },
 
   isDefault: true,
diff --git a/lib/rules/best-practises/payable-fallback.js b/lib/rules/best-practises/payable-fallback.js
index 79921a9..473c7c6 100644
--- a/lib/rules/best-practises/payable-fallback.js
+++ b/lib/rules/best-practises/payable-fallback.js
@@ -22,12 +22,17 @@ const meta = {
         },
       ],
     },
+    notes: [
+      {
+        note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
+      },
+    ],
   },
 
   isDefault: false,
   recommended: true,
   defaultSetup: 'warn',
-
+  fixable: true,
   schema: null,
 }
 
@@ -39,10 +44,27 @@ class PayableFallbackChecker extends BaseChecker {
   FunctionDefinition(node) {
     if (isFallbackFunction(node)) {
       if (node.stateMutability !== 'payable') {
-        this.warn(node, 'When fallback is not payable you will not be able to receive ether')
+        this.warn(
+          node,
+          'Fallback should be external and payable to accept native currency',
+          this.fixStatement(node)
+        )
       }
     }
   }
+
+  fixStatement(node) {
+    const range = node.range
+    const stringToPut = ' payable '
+
+    if (node.isReceiveEther) {
+      range[0] += 9
+    } else {
+      range[0] += 10
+    }
+
+    return (fixer) => fixer.insertTextBeforeRange(range, stringToPut)
+  }
 }
 
 module.exports = PayableFallbackChecker
diff --git a/lib/rules/miscellaneous/quotes.js b/lib/rules/miscellaneous/quotes.js
index 5eff88d..2c0aca7 100644
--- a/lib/rules/miscellaneous/quotes.js
+++ b/lib/rules/miscellaneous/quotes.js
@@ -61,7 +61,7 @@ const meta = {
   isDefault: false,
   recommended: true,
   defaultSetup: [DEFAULT_SEVERITY, DEFAULT_QUOTES_TYPE],
-
+  fixable: true,
   schema: {
     type: 'string',
     enum: QUOTE_TYPES,
@@ -113,8 +113,30 @@ class QuotesChecker extends BaseChecker {
     this.visitedNodes.add(`${line}${column}`)
   }
 
-  _error(ctx) {
-    this.error(ctx, `Use ${this.quoteType} quotes for string literals`)
+  _error(node) {
+    this.error(node, `Use ${this.quoteType} quotes for string literals`, this.fixStatement(node))
+  }
+
+  swapQuotes(inputString, quoteType) {
+    // Define the opposite quote type
+    const oppositeQuote = quoteType === "'" ? '"' : "'"
+
+    // Regular expression to match either single or double quotes within the string
+    const quoteRegex = new RegExp(`[${quoteType}${oppositeQuote}]`, 'g')
+
+    // Replace each occurrence of the specified quote type with the opposite quote
+    const resultString = inputString.replace(quoteRegex, (match) =>
+      match === quoteType ? oppositeQuote : quoteType
+    )
+
+    return resultString
+  }
+
+  fixStatement(node) {
+    const stringToPut = this.swapQuotes(node.value, this.incorrectQuote)
+    const range = node.range
+    range[1] -= 1
+    return (fixer) => fixer.replaceTextRange(range, stringToPut)
   }
 }
 
diff --git a/lib/rules/naming/contract-name-camelcase.js b/lib/rules/naming/contract-name-camelcase.js
index 2d39a88..d7fd9de 100644
--- a/lib/rules/naming/contract-name-camelcase.js
+++ b/lib/rules/naming/contract-name-camelcase.js
@@ -6,14 +6,22 @@ const meta = {
   type: 'naming',
 
   docs: {
-    description: 'Contract name must be in CamelCase.',
+    description: 'Contract, Structs and Enums should be in CamelCase.',
     category: 'Style Guide Rules',
+    notes: [
+      {
+        note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
+      },
+      {
+        note: 'The FIX will only change first letter and remove underscores',
+      },
+    ],
   },
 
   isDefault: false,
   recommended: true,
   defaultSetup: 'warn',
-
+  fixable: true,
   schema: null,
 }
 
@@ -23,25 +31,51 @@ class ContractNameCamelcaseChecker extends BaseChecker {
   }
 
   ContractDefinition(node) {
-    this.validateName(node)
+    this.validateName(node, 'contract')
   }
 
   EnumDefinition(node) {
-    this.validateName(node)
+    this.validateName(node, 'enum')
   }
 
   StructDefinition(node) {
-    this.validateName(node)
+    this.validateName(node, 'struct')
   }
 
-  validateName(node) {
+  validateName(node, type) {
     if (naming.isNotCamelCase(node.name)) {
-      this._error(node)
+      this._error(node, type)
     }
   }
 
-  _error(node) {
-    this.error(node, 'Contract name must be in CamelCase')
+  fixStatement(node, type) {
+    // Remove leading and trailing underscores
+    let nameToPut = node.name.replace(/^[_]+|[_]+$/g, '')
+
+    // Replace '-' with space and split the string into an array
+    let words = nameToPut.replace(/-/g, ' ').split('_')
+
+    // Capitalize the first letter of each word
+    words = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
+
+    // Join the words back into a single string
+    nameToPut = words.join('')
+
+    const originalNameLength = node.name.length
+    const typeLength = type.length
+
+    const rangeStart = node.range[0] + typeLength + 1
+    const rangeEnd = node.range[0] + typeLength + originalNameLength
+
+    return (fixer) => fixer.replaceTextRange([rangeStart, rangeEnd], nameToPut)
+  }
+
+  _error(node, type) {
+    this.error(
+      node,
+      'Contract, Structs and Enums should be in CamelCase',
+      this.fixStatement(node, type)
+    )
   }
 }
 
diff --git a/lib/rules/naming/event-name-camelcase.js b/lib/rules/naming/event-name-camelcase.js
index 5bcbbb1..aecfca9 100644
--- a/lib/rules/naming/event-name-camelcase.js
+++ b/lib/rules/naming/event-name-camelcase.js
@@ -8,12 +8,20 @@ const meta = {
   docs: {
     description: 'Event name must be in CamelCase.',
     category: 'Style Guide Rules',
+    notes: [
+      {
+        note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
+      },
+      {
+        note: 'The FIX will only change first letter and remove underscores',
+      },
+    ],
   },
 
   isDefault: false,
   recommended: true,
   defaultSetup: 'warn',
-
+  fixable: true,
   schema: null,
 }
 
@@ -22,9 +30,31 @@ class EventNameCamelcaseChecker extends BaseChecker {
     super(reporter, ruleId, meta)
   }
 
+  fixStatement(node) {
+    // Remove leading and trailing underscores
+    let nameToPut = node.name.replace(/^[_]+|[_]+$/g, '')
+
+    // Replace '-' with space and split the string into an array
+    let words = nameToPut.replace(/-/g, ' ').split('_')
+
+    // Capitalize the first letter of each word
+    words = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
+
+    // Join the words back into a single string
+    nameToPut = words.join('')
+
+    const originalNameLength = node.name.length
+    const typeLength = 'event'.length
+
+    const rangeStart = node.range[0] + typeLength + 1
+    const rangeEnd = node.range[0] + typeLength + originalNameLength
+
+    return (fixer) => fixer.replaceTextRange([rangeStart, rangeEnd], nameToPut)
+  }
+
   EventDefinition(node) {
     if (naming.isNotCamelCase(node.name)) {
-      this.error(node, 'Event name must be in CamelCase')
+      this.error(node, 'Event name must be in CamelCase', this.fixStatement(node))
     }
   }
 }
diff --git a/lib/rules/naming/private-vars-leading-underscore.js b/lib/rules/naming/private-vars-leading-underscore.js
index bcbfdff..e630e20 100644
--- a/lib/rules/naming/private-vars-leading-underscore.js
+++ b/lib/rules/naming/private-vars-leading-underscore.js
@@ -67,7 +67,7 @@ const meta = {
     },
     notes: [
       {
-        note: 'This rule considers functions and variables in Libraries as well',
+        note: 'This rule DO NOT considers functions and variables in Libraries',
       },
       {
         note: 'This rule skips external and public functions',
@@ -78,6 +78,9 @@ const meta = {
       {
         note: 'See [here](https://docs.soliditylang.org/en/latest/style-guide.html#underscore-prefix-for-non-external-functions-and-variables) for further information',
       },
+      {
+        note: 'Solhint allows this rule to automatically fix the code with `--fix` option',
+      },
     ],
   },
 
@@ -103,26 +106,27 @@ class PrivateVarsLeadingUnderscoreChecker extends BaseChecker {
     this.isStrict = config && config.getObjectPropertyBoolean(ruleId, 'strict', DEFAULT_STRICTNESS)
   }
 
-  // ContractDefinition(node) {
-  //   if (node.kind === 'library') {
-  //     this.inLibrary = true
-  //   }
-  // }
+  ContractDefinition(node) {
+    if (node.kind === 'library') {
+      this.inLibrary = true
+    }
+  }
 
-  // 'ContractDefinition:exit'() {
-  //   this.inLibrary = false
-  // }
+  'ContractDefinition:exit'() {
+    this.inLibrary = false
+  }
 
   FunctionDefinition(node) {
-    if (!node.name) {
-      return
-    }
+    if (!this.inLibrary) {
+      if (!node.name) {
+        return
+      }
 
-    const isPrivate = node.visibility === 'private'
-    const isInternal = node.visibility === 'internal' || node.visibility === 'default'
-    // const shouldHaveLeadingUnderscore = isPrivate || (!this.inLibrary && isInternal)
-    const shouldHaveLeadingUnderscore = isPrivate || isInternal
-    this.validateName(node, shouldHaveLeadingUnderscore, 'function')
+      const isPrivate = node.visibility === 'private'
+      const isInternal = node.visibility === 'internal' || node.visibility === 'default'
+      const shouldHaveLeadingUnderscore = isPrivate || isInternal
+      this.validateName(node, shouldHaveLeadingUnderscore, 'function')
+    }
   }
 
   StateVariableDeclaration() {
@@ -134,18 +138,20 @@ class PrivateVarsLeadingUnderscoreChecker extends BaseChecker {
   }
 
   VariableDeclaration(node) {
-    if (!this.inStateVariableDeclaration) {
-      // if strict is enabled, non-state vars should not start with leading underscore
-      if (this.isStrict) {
-        this.validateName(node, false, 'variable')
+    if (!this.inLibrary) {
+      if (!this.inStateVariableDeclaration) {
+        // if strict is enabled, non-state vars should not start with leading underscore
+        if (this.isStrict) {
+          this.validateName(node, false, 'variable')
+        }
+        return
       }
-      return
-    }
 
-    const isPrivate = node.visibility === 'private'
-    const isInternal = node.visibility === 'internal' || node.visibility === 'default'
-    const shouldHaveLeadingUnderscore = isPrivate || isInternal
-    this.validateName(node, shouldHaveLeadingUnderscore, 'variable')
+      const isPrivate = node.visibility === 'private'
+      const isInternal = node.visibility === 'internal' || node.visibility === 'default'
+      const shouldHaveLeadingUnderscore = isPrivate || isInternal
+      this.validateName(node, shouldHaveLeadingUnderscore, 'variable')
+    }
   }
 
   validateName(node, shouldHaveLeadingUnderscore, type) {
diff --git a/lib/rules/security/avoid-suicide.js b/lib/rules/security/avoid-suicide.js
index 4efabb9..2fdb5ed 100644
--- a/lib/rules/security/avoid-suicide.js
+++ b/lib/rules/security/avoid-suicide.js
@@ -12,7 +12,7 @@ const meta = {
   isDefault: false,
   recommended: true,
   defaultSetup: 'warn',
-
+  fixable: true,
   schema: null,
 }
 
@@ -21,10 +21,24 @@ class AvoidSuicideChecker extends BaseChecker {
     super(reporter, ruleId, meta)
   }
 
-  Identifier(node) {
-    if (node.name === 'suicide') {
-      this.error(node, 'Use "selfdestruct" instead of deprecated "suicide"')
+  FunctionCall(node) {
+    if (node.expression.type === 'Identifier' && node.expression.name === 'suicide') {
+      this.error(
+        node,
+        'Use "selfdestruct" instead of deprecated "suicide"',
+        this.fixStatement(node)
+      )
+    }
+  }
+
+  fixStatement(node) {
+    let stringToPut = 'selfdestruct()'
+
+    if (node.arguments.length > 0) {
+      stringToPut = 'selfdestruct(' + node.arguments[0].name + ')'
     }
+
+    return (fixer) => fixer.replaceTextRange(node.range, stringToPut)
   }
 }
 
diff --git a/package.json b/package.json
index 79a21f8..4120b8e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "solhint",
-  "version": "4.0.0",
+  "version": "4.1.0",
   "description": "Solidity Code Linter",
   "main": "lib/index.js",
   "keywords": [
@@ -18,7 +18,7 @@
   "scripts": {
     "exec-tests": "nyc mocha --recursive && nyc report --reporter=text-lcov | coveralls",
     "test:coverage": "npm run exec-tests",
-    "test": "mocha --recursive",
+    "test": "mocha --recursive --timeout 10000",
     "lint": "eslint .",
     "generate-rulesets": "node scripts/generate-rulesets.js && prettier --write conf/rulesets",
     "docs": "node scripts/generate-rule-docs.js",
diff --git a/solhint.js b/solhint.js
old mode 100644
new mode 100755
index 520a6e5..484c643
--- a/solhint.js
+++ b/solhint.js
@@ -21,7 +21,7 @@ function init() {
     .usage('[options] <file> [...other_files]')
     .option(
       '-f, --formatter [name]',
-      'report formatter name (stylish, table, tap, unix, json, compact)'
+      'report formatter name (stylish, table, tap, unix, json, compact, sarif)'
     )
     .option('-w, --max-warnings [maxWarningsNumber]', 'number of allowed warnings')
     .option('-c, --config [file_name]', 'file to use as your .solhint.json')
@@ -127,7 +127,6 @@ function executeMainActionLogic() {
   const reportLists = program.args.filter(_.isString).map(processPath)
   const reports = _.flatten(reportLists)
 
-  // if (program.opts().fix || program.opts().fixShow) {
   if (program.opts().fix) {
     for (const report of reports) {
       const inputSrc = fs.readFileSync(report.filePath).toString()
@@ -140,23 +139,13 @@ function executeMainActionLogic() {
 
       const { fixed, output } = applyFixes(fixes, inputSrc)
       if (fixed) {
-        // // skip or not the report when fixed
-        // // This was filtering fixed rules so status code was not 1
-        // if (program.opts().fix) {
-        //   report.reports = report.reports.filter((x) => !x.fix)
-        // } else {
-        // console.log('report.reports :>> ', report.reports)
         report.reports.forEach((report) => {
           if (report.fix !== null) {
             report.message = `[FIXED] - ${report.message}`
           }
         })
-        // }
-
-        // fs.writeFileSync(report.filePath, output)
         try {
           fs.writeFileSync(report.filePath, output)
-          // fs.writeFileSync('no-console/Foo1Modified.sol', output)
         } catch (error) {
           console.error('An error occurred while writing the file:', error)
         }


Test patch:
diff --git a/.github/workflows/E2E.yml b/.github/workflows/E2E.yml
index 60d1e06..c3fc7f2 100644
--- a/.github/workflows/E2E.yml
+++ b/.github/workflows/E2E.yml
@@ -21,6 +21,7 @@ jobs:
       - uses: actions/setup-node@v3
         with:
           node-version: ${{ matrix.node }}
+          cache: 'npm'
       
       - name: Install dependencies
         run: npm install --include=dev
@@ -55,6 +56,7 @@ jobs:
       - uses: actions/setup-node@v3
         with:
           node-version: 18
+          cache: 'npm'
 
       - name: Install dependencies
         run: npm install --include=dev
@@ -92,6 +94,7 @@ jobs:
     - uses: actions/setup-node@v3
       with:
         node-version: 18
+        cache: 'npm'
 
     - name: Install dependencies
       run: npm install --include=dev
diff --git a/.github/workflows/TESTS.yml b/.github/workflows/TESTS.yml
index c04448e..e469e4e 100644
--- a/.github/workflows/TESTS.yml
+++ b/.github/workflows/TESTS.yml
@@ -23,6 +23,7 @@ jobs:
     - uses: actions/setup-node@v3
       with:
         node-version: ${{ matrix.node-version }}
+        cache: 'npm'
 
     - name: Install dependencies
       run: npm ci
@@ -41,6 +42,7 @@ jobs:
     - uses: actions/setup-node@v3
       with:
         node-version: 18
+        cache: 'npm'
 
     - name: Install dependencies
       run: npm ci
@@ -59,6 +61,7 @@ jobs:
     - uses: actions/setup-node@v3
       with:
         node-version: 18
+        cache: 'npm'
 
     - name: Install dependencies
       run: npm ci
diff --git a/e2e/08-autofix/commands/.solhint.json b/e2e/08-autofix/_commands/.solhint.json
similarity index 100%
rename from e2e/08-autofix/commands/.solhint.json
rename to e2e/08-autofix/_commands/.solhint.json
diff --git a/e2e/08-autofix/commands/Foo1.sol b/e2e/08-autofix/_commands/Foo1.sol
similarity index 100%
rename from e2e/08-autofix/commands/Foo1.sol
rename to e2e/08-autofix/_commands/Foo1.sol
diff --git a/e2e/08-autofix/commands/Foo1AfterFix.sol b/e2e/08-autofix/_commands/Foo1AfterFix.sol
similarity index 100%
rename from e2e/08-autofix/commands/Foo1AfterFix.sol
rename to e2e/08-autofix/_commands/Foo1AfterFix.sol
diff --git a/e2e/08-autofix/commands/Foo1BeforeFix.sol b/e2e/08-autofix/_commands/Foo1BeforeFix.sol
similarity index 100%
rename from e2e/08-autofix/commands/Foo1BeforeFix.sol
rename to e2e/08-autofix/_commands/Foo1BeforeFix.sol
diff --git a/e2e/08-autofix/avoid-suicide/.solhint.json b/e2e/08-autofix/avoid-suicide/.solhint.json
new file mode 100644
index 0000000..7f54d63
--- /dev/null
+++ b/e2e/08-autofix/avoid-suicide/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "avoid-suicide": "error"
+  }
+}
diff --git a/e2e/08-autofix/avoid-suicide/Foo1.sol b/e2e/08-autofix/avoid-suicide/Foo1.sol
new file mode 100644
index 0000000..cf6b1ad
--- /dev/null
+++ b/e2e/08-autofix/avoid-suicide/Foo1.sol
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import '@openzeppelin/contracts/ownership/Suicide.sol';
+import { feature as suicide} from '@openzeppelin/contracts/ownership/Suicide.sol';
+
+uint256 constant suicide = 1;
+
+enum MyEnum {
+    suicide,
+    B
+}
+
+struct OneNiceStruct {
+    uint256 suicide;
+    uint256 b;
+}
+
+error Unauthorized();
+
+function freeFunction() pure returns (uint256) {
+    suicide();
+    return 1;
+}
+
+contract Generic {
+    struct AnotherNiceStruct {
+        uint256 suicide;
+        uint256 c;
+    }
+
+    address constant owner = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
+
+    function seekAndestroy1() external {
+        suicide();
+    }    
+
+    function seekAndestroy2() external {
+        suicide(owner);
+    }
+
+    function seekAndestroy3() external {
+        selfdestruct();
+    }
+
+    function seekAndestroy4() external {
+        selfdestruct(owner);
+    }
+}
diff --git a/e2e/08-autofix/avoid-suicide/Foo1AfterFix.sol b/e2e/08-autofix/avoid-suicide/Foo1AfterFix.sol
new file mode 100644
index 0000000..9ccba15
--- /dev/null
+++ b/e2e/08-autofix/avoid-suicide/Foo1AfterFix.sol
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import '@openzeppelin/contracts/ownership/Suicide.sol';
+import { feature as suicide} from '@openzeppelin/contracts/ownership/Suicide.sol';
+
+uint256 constant suicide = 1;
+
+enum MyEnum {
+    suicide,
+    B
+}
+
+struct OneNiceStruct {
+    uint256 suicide;
+    uint256 b;
+}
+
+error Unauthorized();
+
+function freeFunction() pure returns (uint256) {
+    selfdestruct();
+    return 1;
+}
+
+contract Generic {
+    struct AnotherNiceStruct {
+        uint256 suicide;
+        uint256 c;
+    }
+
+    address constant owner = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
+
+    function seekAndestroy1() external {
+        selfdestruct();
+    }    
+
+    function seekAndestroy2() external {
+        selfdestruct(owner);
+    }
+
+    function seekAndestroy3() external {
+        selfdestruct();
+    }
+
+    function seekAndestroy4() external {
+        selfdestruct(owner);
+    }
+}
diff --git a/e2e/08-autofix/avoid-suicide/Foo1BeforeFix.sol b/e2e/08-autofix/avoid-suicide/Foo1BeforeFix.sol
new file mode 100644
index 0000000..cf6b1ad
--- /dev/null
+++ b/e2e/08-autofix/avoid-suicide/Foo1BeforeFix.sol
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import '@openzeppelin/contracts/ownership/Suicide.sol';
+import { feature as suicide} from '@openzeppelin/contracts/ownership/Suicide.sol';
+
+uint256 constant suicide = 1;
+
+enum MyEnum {
+    suicide,
+    B
+}
+
+struct OneNiceStruct {
+    uint256 suicide;
+    uint256 b;
+}
+
+error Unauthorized();
+
+function freeFunction() pure returns (uint256) {
+    suicide();
+    return 1;
+}
+
+contract Generic {
+    struct AnotherNiceStruct {
+        uint256 suicide;
+        uint256 c;
+    }
+
+    address constant owner = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
+
+    function seekAndestroy1() external {
+        suicide();
+    }    
+
+    function seekAndestroy2() external {
+        suicide(owner);
+    }
+
+    function seekAndestroy3() external {
+        selfdestruct();
+    }
+
+    function seekAndestroy4() external {
+        selfdestruct(owner);
+    }
+}
diff --git a/e2e/08-autofix/contract-name-camelcase/.solhint.json b/e2e/08-autofix/contract-name-camelcase/.solhint.json
new file mode 100644
index 0000000..6da8ad1
--- /dev/null
+++ b/e2e/08-autofix/contract-name-camelcase/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "contract-name-camelcase": "error"
+  }
+}
diff --git a/e2e/08-autofix/contract-name-camelcase/Foo1.sol b/e2e/08-autofix/contract-name-camelcase/Foo1.sol
new file mode 100644
index 0000000..2cf3e9b
--- /dev/null
+++ b/e2e/08-autofix/contract-name-camelcase/Foo1.sol
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+struct not_Used_Struct1 {
+        uint256 three;
+        uint256 four;
+}
+
+enum __status1_ {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+struct NotUsedStruct2 {
+        uint256 three;
+        uint256 four;
+}
+
+enum Status2 {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+contract __generic {
+
+    struct not_UsedStruct3__ {
+        uint256 three;
+        uint256 four;
+    }
+
+    enum status3     {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+    struct NotUsedStruct4 {
+        uint256 three;
+        uint256 four;
+    }
+
+    enum Status4 {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+    constructor() {}
+
+    function function1() pure external {
+        uint af1 = 0;
+        af1;
+    }
+
+    function function2() external pure {
+        uint b;
+        b;
+    }
+}
diff --git a/e2e/08-autofix/contract-name-camelcase/Foo1AfterFix.sol b/e2e/08-autofix/contract-name-camelcase/Foo1AfterFix.sol
new file mode 100644
index 0000000..eb5ab8f
--- /dev/null
+++ b/e2e/08-autofix/contract-name-camelcase/Foo1AfterFix.sol
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+struct NotUsedStruct1 {
+        uint256 three;
+        uint256 four;
+}
+
+enum Status1 {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+struct NotUsedStruct2 {
+        uint256 three;
+        uint256 four;
+}
+
+enum Status2 {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+contract Generic {
+
+    struct NotUsedStruct3 {
+        uint256 three;
+        uint256 four;
+    }
+
+    enum Status3     {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+    struct NotUsedStruct4 {
+        uint256 three;
+        uint256 four;
+    }
+
+    enum Status4 {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+    constructor() {}
+
+    function function1() pure external {
+        uint af1 = 0;
+        af1;
+    }
+
+    function function2() external pure {
+        uint b;
+        b;
+    }
+}
diff --git a/e2e/08-autofix/contract-name-camelcase/Foo1BeforeFix.sol b/e2e/08-autofix/contract-name-camelcase/Foo1BeforeFix.sol
new file mode 100644
index 0000000..2cf3e9b
--- /dev/null
+++ b/e2e/08-autofix/contract-name-camelcase/Foo1BeforeFix.sol
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+struct not_Used_Struct1 {
+        uint256 three;
+        uint256 four;
+}
+
+enum __status1_ {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+struct NotUsedStruct2 {
+        uint256 three;
+        uint256 four;
+}
+
+enum Status2 {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+contract __generic {
+
+    struct not_UsedStruct3__ {
+        uint256 three;
+        uint256 four;
+    }
+
+    enum status3     {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+    struct NotUsedStruct4 {
+        uint256 three;
+        uint256 four;
+    }
+
+    enum Status4 {
+        Pending,
+        Approved,
+        Rejected
+    }
+
+    constructor() {}
+
+    function function1() pure external {
+        uint af1 = 0;
+        af1;
+    }
+
+    function function2() external pure {
+        uint b;
+        b;
+    }
+}
diff --git a/e2e/08-autofix/event-name-camelcase/.solhint.json b/e2e/08-autofix/event-name-camelcase/.solhint.json
new file mode 100644
index 0000000..7f809bb
--- /dev/null
+++ b/e2e/08-autofix/event-name-camelcase/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "event-name-camelcase": "error"
+  }
+}
diff --git a/e2e/08-autofix/event-name-camelcase/Foo1.sol b/e2e/08-autofix/event-name-camelcase/Foo1.sol
new file mode 100644
index 0000000..8a1b5cc
--- /dev/null
+++ b/e2e/08-autofix/event-name-camelcase/Foo1.sol
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+contract Generic {
+    
+    event not_UsedEvent1(uint256 indexed amount, address account);
+    
+    event __not_UsedEvent___2(uint256 indexed amount, address indexed account);
+
+    event not___UsedEvent3(uint256 amount, address account);
+
+    event notUsedEvent4(uint256 indexed amount, address indexed account);
+    
+    event notUsedEvent5____(uint256 indexed amount, address account);
+    
+    event __not_UsedEvent6__(uint256 indexed amount, address account);
+
+    event OkEvent1(uint256 indexed amount, address account);
+    
+    event OkEventOk2(uint256 indexed amount, address indexed account);
+
+    constructor() {}
+
+    function function1() external pure {
+        uint af1 = 0;
+        af1;
+    }
+
+    function function2() external pure {
+        uint b;
+        b;
+    }
+}
diff --git a/e2e/08-autofix/event-name-camelcase/Foo1AfterFix.sol b/e2e/08-autofix/event-name-camelcase/Foo1AfterFix.sol
new file mode 100644
index 0000000..8d6820c
--- /dev/null
+++ b/e2e/08-autofix/event-name-camelcase/Foo1AfterFix.sol
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+contract Generic {
+    
+    event NotUsedEvent1(uint256 indexed amount, address account);
+    
+    event NotUsedEvent2(uint256 indexed amount, address indexed account);
+
+    event NotUsedEvent3(uint256 amount, address account);
+
+    event NotUsedEvent4(uint256 indexed amount, address indexed account);
+    
+    event NotUsedEvent5(uint256 indexed amount, address account);
+    
+    event NotUsedEvent6(uint256 indexed amount, address account);
+
+    event OkEvent1(uint256 indexed amount, address account);
+    
+    event OkEventOk2(uint256 indexed amount, address indexed account);
+
+    constructor() {}
+
+    function function1() external pure {
+        uint af1 = 0;
+        af1;
+    }
+
+    function function2() external pure {
+        uint b;
+        b;
+    }
+}
diff --git a/e2e/08-autofix/event-name-camelcase/Foo1BeforeFix.sol b/e2e/08-autofix/event-name-camelcase/Foo1BeforeFix.sol
new file mode 100644
index 0000000..8a1b5cc
--- /dev/null
+++ b/e2e/08-autofix/event-name-camelcase/Foo1BeforeFix.sol
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+contract Generic {
+    
+    event not_UsedEvent1(uint256 indexed amount, address account);
+    
+    event __not_UsedEvent___2(uint256 indexed amount, address indexed account);
+
+    event not___UsedEvent3(uint256 amount, address account);
+
+    event notUsedEvent4(uint256 indexed amount, address indexed account);
+    
+    event notUsedEvent5____(uint256 indexed amount, address account);
+    
+    event __not_UsedEvent6__(uint256 indexed amount, address account);
+
+    event OkEvent1(uint256 indexed amount, address account);
+    
+    event OkEventOk2(uint256 indexed amount, address indexed account);
+
+    constructor() {}
+
+    function function1() external pure {
+        uint af1 = 0;
+        af1;
+    }
+
+    function function2() external pure {
+        uint b;
+        b;
+    }
+}
diff --git a/e2e/08-autofix/payable-fallback/.solhint.json b/e2e/08-autofix/payable-fallback/.solhint.json
new file mode 100644
index 0000000..aa02d3b
--- /dev/null
+++ b/e2e/08-autofix/payable-fallback/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "payable-fallback": "error"
+  }
+}
diff --git a/e2e/08-autofix/payable-fallback/Foo1.sol b/e2e/08-autofix/payable-fallback/Foo1.sol
new file mode 100644
index 0000000..eb1cfda
--- /dev/null
+++ b/e2e/08-autofix/payable-fallback/Foo1.sol
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+contract Generic {
+    
+    constructor()  {}
+
+    function anyFunction() {}
+
+    //// fallback with receive
+    receive() public {}
+    
+    receive() external onlyOwner {}
+
+    receive() external virtual {
+        uint256 anUintToFillSpace;
+    }
+
+    //// fallback with no name
+    function() public {}
+
+    function() {
+        uint256 anUintToFillSpace;
+    }
+
+    function() external onlyOwner {}
+
+    function() virtual {
+        uint256 anUintToFillSpace;
+    }
+
+
+    //// fallback explicit
+    fallback() {}
+
+    fallback() {
+        uint256 anUintToFillSpace;
+    }
+
+    fallback() external onlyOwner{
+        uint256 anUintToFillSpace;
+    }
+
+    fallback() virtual {}
+
+
+    fallback() external payable {}
+    function() external payable {}    
+    receive() public virtual payable {}
+}
diff --git a/e2e/08-autofix/payable-fallback/Foo1AfterFix.sol b/e2e/08-autofix/payable-fallback/Foo1AfterFix.sol
new file mode 100644
index 0000000..f32e5c5
--- /dev/null
+++ b/e2e/08-autofix/payable-fallback/Foo1AfterFix.sol
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+contract Generic {
+    
+    constructor()  {}
+
+    function anyFunction() {}
+
+    //// fallback with receive
+    receive() payable public {}
+    
+    receive() payable external onlyOwner {}
+
+    receive() payable external virtual {
+        uint256 anUintToFillSpace;
+    }
+
+    //// fallback with no name
+    function() payable public {}
+
+    function() payable {
+        uint256 anUintToFillSpace;
+    }
+
+    function() payable external onlyOwner {}
+
+    function() payable virtual {
+        uint256 anUintToFillSpace;
+    }
+
+
+    //// fallback explicit
+    fallback() payable {}
+
+    fallback() payable {
+        uint256 anUintToFillSpace;
+    }
+
+    fallback() payable external onlyOwner{
+        uint256 anUintToFillSpace;
+    }
+
+    fallback() payable virtual {}
+
+
+    fallback() external payable {}
+    function() external payable {}    
+    receive() public virtual payable {}
+}
diff --git a/e2e/08-autofix/payable-fallback/Foo1BeforeFix.sol b/e2e/08-autofix/payable-fallback/Foo1BeforeFix.sol
new file mode 100644
index 0000000..eb1cfda
--- /dev/null
+++ b/e2e/08-autofix/payable-fallback/Foo1BeforeFix.sol
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+contract Generic {
+    
+    constructor()  {}
+
+    function anyFunction() {}
+
+    //// fallback with receive
+    receive() public {}
+    
+    receive() external onlyOwner {}
+
+    receive() external virtual {
+        uint256 anUintToFillSpace;
+    }
+
+    //// fallback with no name
+    function() public {}
+
+    function() {
+        uint256 anUintToFillSpace;
+    }
+
+    function() external onlyOwner {}
+
+    function() virtual {
+        uint256 anUintToFillSpace;
+    }
+
+
+    //// fallback explicit
+    fallback() {}
+
+    fallback() {
+        uint256 anUintToFillSpace;
+    }
+
+    fallback() external onlyOwner{
+        uint256 anUintToFillSpace;
+    }
+
+    fallback() virtual {}
+
+
+    fallback() external payable {}
+    function() external payable {}    
+    receive() public virtual payable {}
+}
diff --git a/e2e/08-autofix/private-vars-underscore/Foo1AfterFix.sol b/e2e/08-autofix/private-vars-underscore/Foo1AfterFix.sol
index 87b80ad..42c05d9 100644
--- a/e2e/08-autofix/private-vars-underscore/Foo1AfterFix.sol
+++ b/e2e/08-autofix/private-vars-underscore/Foo1AfterFix.sol
@@ -1,21 +1,21 @@
 pragma solidity 0.8.0;
 
 library libraryName {
-    uint256 internal _lzarasa1;
-    uint256 internal _lzarasa2 = 2;
+    uint256 internal lzarasa1;
+    uint256 internal lzarasa2 = 2;
     uint256 internal _lzarasa3;
-    uint256 private _lzarasa4;
-    uint256 private _lzarasa5 = 5;
+    uint256 private lzarasa4;
+    uint256 private lzarasa5 = 5;
     uint256 private _lzarasa6;
 
-    uint256 public lzarasa7;
-    uint256 public lzarasa8 = 8;
+    uint256 public _lzarasa7;
+    uint256 public _lzarasa8 = 8;
     uint256 public lzarasa9;
 
     function fofo1() public {}
-    function fofo2() public {}
+    function _fofo2() public {}
     function _fofo3() internal {}
-    function _fofo4() internal {}
+    function fofo4() internal {}
 }
 
 contract Foo1 {
diff --git a/e2e/08-autofix/quotes/.doubleQuotes.json b/e2e/08-autofix/quotes/.doubleQuotes.json
new file mode 100644
index 0000000..bd5e47b
--- /dev/null
+++ b/e2e/08-autofix/quotes/.doubleQuotes.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "quotes": ["error", "double"]
+  }
+}
diff --git a/e2e/08-autofix/quotes/.singleQuotes.json b/e2e/08-autofix/quotes/.singleQuotes.json
new file mode 100644
index 0000000..1cd619b
--- /dev/null
+++ b/e2e/08-autofix/quotes/.singleQuotes.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "quotes": ["error", "single"]
+  }
+}
diff --git a/e2e/08-autofix/quotes/Foo1.sol b/e2e/08-autofix/quotes/Foo1.sol
new file mode 100644
index 0000000..c1ecfcb
--- /dev/null
+++ b/e2e/08-autofix/quotes/Foo1.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import "lib1.sol";
+import 'lib2.sol';
+import { something1 } from "lib3.sol";
+import { something2 } from 'lib4.sol';
+import { something1 as smg1 } from "lib3.sol";
+import { something2 as smg2 } from 'lib4.sol';
+
+contract Generic {
+
+    string private constant STR1 = "You shall not 'pass' !";
+    string private constant STR2 = 'You shall not "pass" !';
+
+    function asmSingle() external view {
+        assembly { 'abc' }
+        assembly { dataSize('uint') }
+        assembly { linkerSymbol('uint') }
+        assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }
+    }
+
+    function asmDouble() external view {
+        assembly { "abc" }
+        assembly { dataSize("uint") }
+        assembly { linkerSymbol("uint") }
+        assembly { let hexString := "48656c6c6f2c2027576f726c64212722" }
+    }
+}
diff --git a/e2e/08-autofix/quotes/Foo1AfterFixDouble.sol b/e2e/08-autofix/quotes/Foo1AfterFixDouble.sol
new file mode 100644
index 0000000..0695e5a
--- /dev/null
+++ b/e2e/08-autofix/quotes/Foo1AfterFixDouble.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import "lib1.sol";
+import "lib2.sol";
+import { something1 } from "lib3.sol";
+import { something2 } from "lib4.sol";
+import { something1 as smg1 } from "lib3.sol";
+import { something2 as smg2 } from "lib4.sol";
+
+contract Generic {
+
+    string private constant STR1 = "You shall not 'pass' !";
+    string private constant STR2 = "You shall not 'pass' !";
+
+    function asmSingle() external view {
+        assembly { "abc" }
+        assembly { dataSize("uint") }
+        assembly { linkerSymbol("uint") }
+        assembly { let hexString := "48656c6c6f2c2027576f726c64212722" }
+    }
+
+    function asmDouble() external view {
+        assembly { "abc" }
+        assembly { dataSize("uint") }
+        assembly { linkerSymbol("uint") }
+        assembly { let hexString := "48656c6c6f2c2027576f726c64212722" }
+    }
+}
diff --git a/e2e/08-autofix/quotes/Foo1AfterFixSingle.sol b/e2e/08-autofix/quotes/Foo1AfterFixSingle.sol
new file mode 100644
index 0000000..588512b
--- /dev/null
+++ b/e2e/08-autofix/quotes/Foo1AfterFixSingle.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import 'lib1.sol';
+import 'lib2.sol';
+import { something1 } from 'lib3.sol';
+import { something2 } from 'lib4.sol';
+import { something1 as smg1 } from 'lib3.sol';
+import { something2 as smg2 } from 'lib4.sol';
+
+contract Generic {
+
+    string private constant STR1 = 'You shall not "pass" !';
+    string private constant STR2 = 'You shall not "pass" !';
+
+    function asmSingle() external view {
+        assembly { 'abc' }
+        assembly { dataSize('uint') }
+        assembly { linkerSymbol('uint') }
+        assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }
+    }
+
+    function asmDouble() external view {
+        assembly { 'abc' }
+        assembly { dataSize('uint') }
+        assembly { linkerSymbol('uint') }
+        assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }
+    }
+}
diff --git a/e2e/08-autofix/quotes/Foo1BeforeFix.sol b/e2e/08-autofix/quotes/Foo1BeforeFix.sol
new file mode 100644
index 0000000..c1ecfcb
--- /dev/null
+++ b/e2e/08-autofix/quotes/Foo1BeforeFix.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.0;
+
+import "lib1.sol";
+import 'lib2.sol';
+import { something1 } from "lib3.sol";
+import { something2 } from 'lib4.sol';
+import { something1 as smg1 } from "lib3.sol";
+import { something2 as smg2 } from 'lib4.sol';
+
+contract Generic {
+
+    string private constant STR1 = "You shall not 'pass' !";
+    string private constant STR2 = 'You shall not "pass" !';
+
+    function asmSingle() external view {
+        assembly { 'abc' }
+        assembly { dataSize('uint') }
+        assembly { linkerSymbol('uint') }
+        assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }
+    }
+
+    function asmDouble() external view {
+        assembly { "abc" }
+        assembly { dataSize("uint") }
+        assembly { linkerSymbol("uint") }
+        assembly { let hexString := "48656c6c6f2c2027576f726c64212722" }
+    }
+}
diff --git a/e2e/autofix-test.js b/e2e/autofix-test.js
index 1f11d18..ae2c82d 100644
--- a/e2e/autofix-test.js
+++ b/e2e/autofix-test.js
@@ -25,7 +25,6 @@ function retrieveParams(subpath) {
 function compareTextFiles(file1Path, file2Path) {
   const file1Content = fs.readFileSync(file1Path, 'utf-8')
   const file2Content = fs.readFileSync(file2Path, 'utf-8')
-
   return file1Content === file2Content
 }
 
@@ -51,6 +50,8 @@ function useFixture(dir) {
 
 describe('e2e', function () {
   let result = false
+  let code
+  let stdout
 
   describe('autofix tests', () => {
     if (E2E) {
@@ -59,7 +60,7 @@ describe('e2e', function () {
 
     describe('autofix command line options', () => {
       before(function () {
-        params = retrieveParams('commands/')
+        params = retrieveParams('_commands/')
         currentConfig = `${params.path}${params.subpath}.solhint.json`
         currentFile = `${params.path}${params.subpath}Foo1.sol`
         beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
@@ -160,28 +161,32 @@ describe('e2e', function () {
           }
         })
 
-        it('should compare Foo1 file with template BEFORE FIX file and they should match 2', () => {
+        it('should compare Foo1 file with template BEFORE FIX file and they should match (2)', () => {
           result = compareTextFiles(currentFile, beforeFixFile)
           expect(result).to.be.true
         })
 
-        it('should compare Foo1 file with template AFTER FIX file and they should match 2', () => {
-          const { code, stdout } = shell.exec(
+        it('should execute and compare Foo1 with template AFTER FIX and they should match (2)', () => {
+          ;({ code, stdout } = shell.exec(
             `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
-          )
+          ))
 
+          result = compareTextFiles(currentFile, afterFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should execute and exit with code 1 (2)', () => {
           expect(code).to.equal(1)
+        })
 
+        it('should get the right report (2)', () => {
           const reportLines = stdout.split('\n')
           const finalLine = '5 problems (5 errors, 0 warnings)'
           expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
-
-          result = compareTextFiles(currentFile, afterFixFile)
-          expect(result).to.be.true
         })
       })
 
-      it('should check FOO1 does not change after test 2', () => {
+      it('should check FOO1 does not change after test (2)', () => {
         result = compareTextFiles(currentFile, beforeFixFile)
         expect(result).to.be.true
       })
@@ -202,36 +207,86 @@ describe('e2e', function () {
           }
         })
 
-        it('should compare Foo1 file with template BEFORE FIX file and they should match 3', () => {
+        it('should compare Foo1 file with template BEFORE FIX file and they should match (3)', () => {
           result = compareTextFiles(currentFile, beforeFixFile)
           expect(result).to.be.true
         })
 
-        it('should compare Foo1 file with template AFTER FIX file and they should match 3', () => {
-          const { code, stdout } = shell.exec(
+        it('should execute and compare Foo1 with template AFTER FIX and they should match (3)', () => {
+          ;({ code, stdout } = shell.exec(
             `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
-          )
+          ))
+
+          result = compareTextFiles(currentFile, afterFixFile)
+          expect(result).to.be.true
+        })
 
+        it('should execute and exit with code 1 (3)', () => {
           expect(code).to.equal(1)
+        })
 
+        it('should get the right report (3)', () => {
           const reportLines = stdout.split('\n')
           const finalLine = '9 problems (9 errors, 0 warnings)'
           expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+        })
+      })
+
+      it('should check FOO1 does not change after test (3)', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+    })
+
+    describe('autofix rule: private-vars-leading-underscore', () => {
+      before(function () {
+        params = retrieveParams('private-vars-underscore/')
+        currentConfig = `${params.path}${params.subpath}.solhint.json`
+        currentFile = `${params.path}${params.subpath}Foo1.sol`
+        beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+        afterFixFile = `${params.path}${params.subpath}Foo1AfterFix.sol`
+      })
+      describe('--fix with noPrompt', () => {
+        after(function () {
+          if (!E2E) {
+            copyFile(beforeFixFile, currentFile)
+          }
+        })
+
+        it('should compare Foo1 file with template BEFORE FIX file and they should match (4)', () => {
+          result = compareTextFiles(currentFile, beforeFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should execute and compare Foo1 with template AFTER FIX and they should match (4)', () => {
+          ;({ code, stdout } = shell.exec(
+            `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+          ))
 
           result = compareTextFiles(currentFile, afterFixFile)
           expect(result).to.be.true
         })
+
+        it('should execute and exit with code 1 (4)', () => {
+          expect(code).to.equal(1)
+        })
+
+        it('should get the right report (4)', () => {
+          const reportLines = stdout.split('\n')
+          const finalLine = '19 problems (19 errors, 0 warnings)'
+          expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+        })
       })
 
-      it('should check FOO1 does not change after test 3', () => {
+      it('should check FOO1 does not change after test (4)', () => {
         result = compareTextFiles(currentFile, beforeFixFile)
         expect(result).to.be.true
       })
     })
 
-    describe('autofix rule: private-vars-leading-underscore', () => {
+    describe('autofix rule: payable-fallback', () => {
       before(function () {
-        params = retrieveParams('private-vars-underscore/')
+        params = retrieveParams('payable-fallback/')
         currentConfig = `${params.path}${params.subpath}.solhint.json`
         currentFile = `${params.path}${params.subpath}Foo1.sol`
         beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
@@ -244,33 +299,262 @@ describe('e2e', function () {
           }
         })
 
-        it('should compare Foo1 file with template BEFORE FIX file and they should match 4', () => {
+        it('should compare Foo1 file with template BEFORE FIX file and they should match (5)', () => {
           result = compareTextFiles(currentFile, beforeFixFile)
           expect(result).to.be.true
         })
 
-        it('should compare Foo1 file with template AFTER FIX file and they should match 4', () => {
-          const { code, stdout } = shell.exec(
+        it('should execute and compare Foo1 with template AFTER FIX and they should match (5)', () => {
+          ;({ code, stdout } = shell.exec(
             `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
-          )
+          ))
 
+          result = compareTextFiles(currentFile, afterFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should execute and exit with code 1 (5)', () => {
           expect(code).to.equal(1)
+        })
 
+        it('should get the right report (5)', () => {
           const reportLines = stdout.split('\n')
-          const finalLine = '27 problems (27 errors, 0 warnings)'
+          const finalLine = '11 problems (11 errors, 0 warnings)'
           expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+        })
+      })
+
+      it('should check FOO1 does not change after test (5)', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+    })
+
+    describe('autofix rule: quotes', () => {
+      describe('--fix with noPrompt SINGLE QUOTES', () => {
+        before(function () {
+          params = retrieveParams('quotes/')
+          currentConfig = `${params.path}${params.subpath}.singleQuotes.json`
+          currentFile = `${params.path}${params.subpath}Foo1.sol`
+          beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+          afterFixFile = `${params.path}${params.subpath}Foo1AfterFixSingle.sol`
+        })
+
+        after(function () {
+          if (!E2E) {
+            copyFile(beforeFixFile, currentFile)
+          }
+        })
+
+        it('should compare Foo1 file with template BEFORE FIX file and they should match (6)', () => {
+          result = compareTextFiles(currentFile, beforeFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should execute and compare Foo1 with template AFTER FIX and they should match (6)', () => {
+          ;({ code, stdout } = shell.exec(
+            `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+          ))
 
           result = compareTextFiles(currentFile, afterFixFile)
           expect(result).to.be.true
         })
+
+        it('should execute and exit with code 1 (6)', () => {
+          expect(code).to.equal(1)
+        })
+
+        it('should get the right report (6)', () => {
+          const reportLines = stdout.split('\n')
+          const finalLine = '8 problems (8 errors, 0 warnings)'
+          expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+        })
       })
-      it('should check FOO1 does not change after test 4', () => {
+
+      describe('--fix with noPrompt DOUBLE QUOTES', () => {
+        before(function () {
+          params = retrieveParams('quotes/')
+          currentConfig = `${params.path}${params.subpath}.doubleQuotes.json`
+          currentFile = `${params.path}${params.subpath}Foo1.sol`
+          beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+          afterFixFile = `${params.path}${params.subpath}Foo1AfterFixDouble.sol`
+        })
+
+        after(function () {
+          if (!E2E) {
+            copyFile(beforeFixFile, currentFile)
+          }
+        })
+
+        it('should compare Foo1 file with template BEFORE FIX file and they should match (6)', () => {
+          result = compareTextFiles(currentFile, beforeFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should execute and compare Foo1 with template AFTER FIX and they should match (6)', () => {
+          ;({ code, stdout } = shell.exec(
+            `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+          ))
+
+          result = compareTextFiles(currentFile, afterFixFile)
+          expect(result).to.be.true
+        })
+
+        it('should execute and exit with code 1 (6)', () => {
+          expect(code).to.equal(1)
+        })
+
+        it('should get the right report (6)', () => {
+          const reportLines = stdout.split('\n')
+          const finalLine = '8 problems (8 errors, 0 warnings)'
+          expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+        })
+      })
+
+      it('should check FOO1 does not change after test (6)', () => {
         result = compareTextFiles(currentFile, beforeFixFile)
         expect(result).to.be.true
       })
     })
   })
+
+  describe('autofix rule: avoid-suicide', () => {
+    before(function () {
+      params = retrieveParams('avoid-suicide/')
+      currentConfig = `${params.path}${params.subpath}.solhint.json`
+      currentFile = `${params.path}${params.subpath}Foo1.sol`
+      beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+      afterFixFile = `${params.path}${params.subpath}Foo1AfterFix.sol`
+    })
+    after(function () {
+      if (!E2E) {
+        copyFile(beforeFixFile, currentFile)
+      }
+    })
+
+    describe('--fix with noPrompt', () => {
+      it('should compare Foo1 file with template BEFORE FIX file and they should match (7)', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+
+      it('should execute and compare Foo1 with template AFTER FIX and they should match (7)', () => {
+        ;({ code, stdout } = shell.exec(
+          `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+        ))
+
+        result = compareTextFiles(currentFile, afterFixFile)
+        expect(result).to.be.true
+      })
+
+      it('should execute and exit with code 1 (7)', () => {
+        expect(code).to.equal(1)
+      })
+
+      it('should get the right report (7)', () => {
+        const reportLines = stdout.split('\n')
+        const finalLine = '3 problems (3 errors, 0 warnings)'
+        expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+      })
+    })
+    
+    it('should check FOO1 does not change after test (7)', () => {
+      result = compareTextFiles(currentFile, beforeFixFile)
+      expect(result).to.be.true
+    })
+  })
+
+  describe('autofix rule: contract-name-camelcase', () => {
+    before(function () {
+      params = retrieveParams('contract-name-camelcase/')
+      currentConfig = `${params.path}${params.subpath}.solhint.json`
+      currentFile = `${params.path}${params.subpath}Foo1.sol`
+      beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+      afterFixFile = `${params.path}${params.subpath}Foo1AfterFix.sol`
+    })
+    after(function () {
+      if (!E2E) {
+        copyFile(beforeFixFile, currentFile)
+      }
+    })
+
+    describe('--fix with noPrompt', () => {
+      it('should compare Foo1 file with template BEFORE FIX file and they should match (8)', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+
+      it('should execute and compare Foo1 with template AFTER FIX and they should match (8)', () => {
+        ;({ code, stdout } = shell.exec(
+          `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+        ))
+
+        result = compareTextFiles(currentFile, afterFixFile)
+        expect(result).to.be.true
+      })
+
+      it('should execute and exit with code 1 (8)', () => {
+        expect(code).to.equal(1)
+      })
+
+      it('should get the right report (8)', () => {
+        const reportLines = stdout.split('\n')
+        const finalLine = '5 problems (5 errors, 0 warnings)'
+        expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+      })
+    })
+    
+    it('should check FOO1 does not change after test (8)', () => {
+      result = compareTextFiles(currentFile, beforeFixFile)
+      expect(result).to.be.true
+    })
+  })
+
+  describe('autofix rule: event-name-camelcase', () => {
+    before(function () {
+      params = retrieveParams('event-name-camelcase/')
+      currentConfig = `${params.path}${params.subpath}.solhint.json`
+      currentFile = `${params.path}${params.subpath}Foo1.sol`
+      beforeFixFile = `${params.path}${params.subpath}Foo1BeforeFix.sol`
+      afterFixFile = `${params.path}${params.subpath}Foo1AfterFix.sol`
+    })
+    after(function () {
+      if (!E2E) {
+        copyFile(beforeFixFile, currentFile)
+      }
+    })
+
+    describe('--fix with noPrompt', () => {
+      it('should compare Foo1 file with template BEFORE FIX file and they should match (8)', () => {
+        result = compareTextFiles(currentFile, beforeFixFile)
+        expect(result).to.be.true
+      })
+
+      it('should execute and compare Foo1 with template AFTER FIX and they should match (8)', () => {
+        ;({ code, stdout } = shell.exec(
+          `${params.command} ${params.param1} -c ${currentConfig} ${currentFile} --fix --disc --noPrompt`
+        ))
+
+        result = compareTextFiles(currentFile, afterFixFile)
+        expect(result).to.be.true
+      })
+
+      it('should execute and exit with code 1 (8)', () => {
+        expect(code).to.equal(1)
+      })
+
+      it('should get the right report (8)', () => {
+        const reportLines = stdout.split('\n')
+        const finalLine = '6 problems (6 errors, 0 warnings)'
+        expect(reportLines[reportLines.length - 3]).to.contain(finalLine)
+      })
+    })
+    
+    it('should check FOO1 does not change after test (8)', () => {
+      result = compareTextFiles(currentFile, beforeFixFile)
+      expect(result).to.be.true
+    })
+  })
 })
 
-// FALTA LA COMPARACION DEL FIX CON EL TEMPLATE FIX
 // FALTA LA PRUEBA DEL STORE TO FILE
diff --git a/e2e/formatters-test.js b/e2e/formatters-test.js
index 668c19d..09df3bc 100644
--- a/e2e/formatters-test.js
+++ b/e2e/formatters-test.js
@@ -4,6 +4,7 @@ const fs = require('fs-extra')
 const os = require('os')
 const path = require('path')
 const shell = require('shelljs')
+const url = require('url')
 
 function useFixture(dir) {
   beforeEach(`switch to ${dir}`, function () {
@@ -344,5 +345,338 @@ describe('e2e', function () {
         expect(code).to.equal(1)
       })
     })
+
+    describe('sarif formatter tests', () => {
+      const formatterType = 'sarif'
+
+      it('should always output with correct SARIF version and tool metadata', () => {
+        const { code, stdout } = shell.exec(`solhint -f ${formatterType}`)
+        const sarifOutput = JSON.parse(stdout)
+
+        expect(code).to.equal(0)
+        expect(sarifOutput['$schema']).to.eq('http://json.schemastore.org/sarif-2.1.0-rtm.5')
+        expect(sarifOutput.version).to.eq('2.1.0')
+        expect(sarifOutput.runs[0].tool.driver.name).to.eq('solhint')
+        expect(sarifOutput.runs[0].tool.driver.informationUri).to.eq('https://github.com/protofire/solhint')
+        expect(sarifOutput.runs[0].tool.driver.version).to.eq(require('../package.json').version)
+      })
+
+      it('should output with empty results and no artifacts when file does not exist and sarif is the formatter', () => {
+        const { code, stdout } = shell.exec(`solhint ${PATH}contracts/Foo1.sol -f ${formatterType}`)
+        const sarifOutput = JSON.parse(stdout)
+
+        expect(code).to.equal(0)
+        expect(sarifOutput.runs[0].artifacts).to.be.undefined
+        expect(sarifOutput.runs[0].results).to.be.empty
+      })
+
+      it('should output with sarif formatter for Foo2', () => {
+        const { code, stdout } = shell.exec(`solhint ${PATH}contracts/Foo2.sol -f ${formatterType}`)
+        const sarifOutput = JSON.parse(stdout)
+
+        const expectedUriPath = url.pathToFileURL(`${PATH}contracts/Foo2.sol`).toString()
+        const expectedResults = [
+          {
+            level: "warning",
+            message: {
+              text: "Constant name must be in capitalized SNAKE_CASE"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPath,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 5,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "const-name-snakecase"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Explicitly mark visibility in function (Set ignoreConstructors to true if using solidity >=0.7.0)"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPath,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 7,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "func-visibility"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Code contains empty blocks"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPath,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 7,
+                    startColumn: 19
+                  }
+                }
+              }
+            ],
+            ruleId: "no-empty-blocks"
+          }
+        ]
+
+        expect(code).to.equal(0)
+        expect(sarifOutput.runs[0].artifacts[0].location.uri).to.eq(expectedUriPath)
+        expect(sarifOutput.runs[0].results).to.deep.equal(expectedResults)
+      })
+
+
+      it('should output with sarif formatter for Foo and Foo2 and Foo3', () => {
+        const { code, stdout } = shell.exec(
+          `solhint ${PATH}contracts/Foo.sol ${PATH}contracts/Foo2.sol ${PATH}contracts/Foo3.sol -f ${formatterType}`
+        )
+        const sarifOutput = JSON.parse(stdout)
+
+        const expectedUriPathFoo = url.pathToFileURL(`${PATH}contracts/Foo.sol`).toString()
+        const expectedUriPathFoo2 = url.pathToFileURL(`${PATH}contracts/Foo2.sol`).toString()
+        const expectedUriPathFoo3 = url.pathToFileURL(`${PATH}contracts/Foo3.sol`).toString()
+        const expectedResults = [
+          {
+            level: "error",
+            message: {
+              text: "Compiler version >=0.6.0 does not satisfy the ^0.8.0 semver requirement"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 2,
+                    startColumn: 1
+                  }
+                }
+              }
+            ],
+            ruleId: "compiler-version"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Constant name must be in capitalized SNAKE_CASE"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 5,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "const-name-snakecase"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Explicitly mark visibility of state"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 6,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "state-visibility"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "'TEST2' should start with _"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 6,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "private-vars-leading-underscore"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Variable name must be in mixedCase"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 6,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "var-name-mixedcase"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Explicitly mark visibility in function (Set ignoreConstructors to true if using solidity >=0.7.0)"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 8,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "func-visibility"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Code contains empty blocks"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo,
+                    index: 0
+                  },
+                  region: {
+                    startLine: 8,
+                    startColumn: 19
+                  }
+                }
+              }
+            ],
+            ruleId: "no-empty-blocks"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Constant name must be in capitalized SNAKE_CASE"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo2,
+                    index: 1
+                  },
+                  region: {
+                    startLine: 5,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "const-name-snakecase"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Explicitly mark visibility in function (Set ignoreConstructors to true if using solidity >=0.7.0)"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo2,
+                    index: 1
+                  },
+                  region: {
+                    startLine: 7,
+                    startColumn: 5
+                  }
+                }
+              }
+            ],
+            ruleId: "func-visibility"
+          },
+          {
+            level: "warning",
+            message: {
+              text: "Code contains empty blocks"
+            },
+            locations: [
+              {
+                physicalLocation: {
+                  artifactLocation: {
+                    uri: expectedUriPathFoo2,
+                    index: 1
+                  },
+                  region: {
+                    startLine: 7,
+                    startColumn: 19
+                  }
+                }
+              }
+            ],
+            ruleId: "no-empty-blocks"
+          }
+        ]
+
+        // There's an error, that is why exit code is 1
+        expect(code).to.equal(1)
+        expect(sarifOutput.runs[0].artifacts[0].location.uri).to.eq(expectedUriPathFoo)
+        expect(sarifOutput.runs[0].artifacts[1].location.uri).to.eq(expectedUriPathFoo2)
+        expect(sarifOutput.runs[0].artifacts[2].location.uri).to.eq(expectedUriPathFoo3)
+        expect(sarifOutput.runs[0].results).to.deep.equal(expectedResults)
+      })
+
+    })
   })
 })
diff --git a/test/rules/best-practises/payable-fallback.js b/test/rules/best-practises/payable-fallback.js
index 734c551..281b776 100644
--- a/test/rules/best-practises/payable-fallback.js
+++ b/test/rules/best-practises/payable-fallback.js
@@ -33,4 +33,15 @@ describe('Linter - payable-fallback', () => {
 
     assertNoWarnings(report)
   })
+
+  it('should raise for other fallback types when are not payable', () => {
+    const code = contractWith('fallback() external {} receive() onlyOwner {}')
+
+    const report = linter.processStr(code, {
+      rules: { 'payable-fallback': 'warn' },
+    })
+
+    assertWarnsCount(report, 2)
+    assertErrorMessage(report, 'payable')
+  })
 })
diff --git a/test/rules/miscellaneous/quotes.js b/test/rules/miscellaneous/quotes.js
index bb1da18..2358582 100644
--- a/test/rules/miscellaneous/quotes.js
+++ b/test/rules/miscellaneous/quotes.js
@@ -54,6 +54,7 @@ describe('Linter - quotes', () => {
     "assembly { 'abc' }",
     "assembly { dataSize('uint') }",
     "assembly { linkerSymbol('uint') }",
+    "assembly { let hexString := '48656c6c6f2c2027576f726c64212722' }",
   ]
 
   ERROR_ASSEMBLY_CLAUSES.forEach((curText) =>
diff --git a/test/rules/naming/private-vars-leading-underscore.js b/test/rules/naming/private-vars-leading-underscore.js
index dbf02a2..f9a71ba 100644
--- a/test/rules/naming/private-vars-leading-underscore.js
+++ b/test/rules/naming/private-vars-leading-underscore.js
@@ -11,25 +11,18 @@ describe('Linter - private-vars-leading-underscore', () => {
     contractWith('function foo() {}'),
     contractWith('function foo() private {}'),
     contractWith('function foo() internal {}'),
-    libraryWith('function foo() {}'),
-    libraryWith('function foo() private {}'),
-    libraryWith('function foo() internal {}'),
 
     // warn when public/external names start with _
     contractWith('uint public _foo;'),
     contractWith('uint external _foo;'),
     contractWith('function _foo() public {}'),
     contractWith('function _foo() external {}'),
-    libraryWith('function _foo() public {}'),
-    libraryWith('function _foo() external {}'),
   ]
 
   const SHOULD_WARN_STRICT_CASES = [
     contractWith('function _foo() internal { uint _bar; }'),
     contractWith('function foo(uint _bar) external {}'),
     contractWith('function foo() public returns (uint256 _bar) {}'),
-    libraryWith('function _foo() returns (uint256 _bar) {}'),
-    libraryWith('function _foo(uint _bar) private {}'),
   ]
 
   const SHOULD_NOT_WARN_CASES = [
diff --git a/test/rules/security/avoid-suicide.js b/test/rules/security/avoid-suicide.js
index 3b84e3e..895af02 100644
--- a/test/rules/security/avoid-suicide.js
+++ b/test/rules/security/avoid-suicide.js
@@ -1,6 +1,7 @@
 const assert = require('assert')
 const linter = require('../../../lib/index')
 const funcWith = require('../../common/contract-builder').funcWith
+const contractWith = require('../../common/contract-builder').contractWith
 
 describe('Linter - avoid-suicide', () => {
   const DEPRECATION_ERRORS = ['suicide();']
@@ -18,7 +19,7 @@ describe('Linter - avoid-suicide', () => {
     })
   )
 
-  const ALMOST_DEPRECATION_ERRORS = ['suicides();']
+  const ALMOST_DEPRECATION_ERRORS = ['suicides();', 'selfdestruct();']
 
   ALMOST_DEPRECATION_ERRORS.forEach((curText) =>
     it(`should not return error when doing ${curText}`, () => {
@@ -31,4 +32,14 @@ describe('Linter - avoid-suicide', () => {
       assert.equal(report.errorCount, 0)
     })
   )
+
+  it(`should not return error when doing for struct name suicide`, () => {
+    const code = contractWith('struct AnotherNiceStruct { uint256 suicide; uint256 c; }')
+
+    const report = linter.processStr(code, {
+      rules: { 'avoid-suicide': 'error' },
+    })
+
+    assert.equal(report.errorCount, 0)
+  })
 })