Repository: protofire/solhint
Pull request #400 (2023-02-09 20:10:09)

fix: false positive on for-loop Yul
This PR solves this issue:
https://github.com/protofire/solhint/issues/315




Patch:
diff --git a/docs/rules.md b/docs/rules.md
index e59f2a0..b656971 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -14,7 +14,6 @@ title:       "Rule Index of Solhint"
 | [max-states-count](./rules/best-practises/max-states-count.md)     | Contract has "some count" states declarations but allowed no more than maxstates.                                     | ✔️          |
 | [no-console](./rules/best-practises/no-console.md)                 | No console.log/logInt/logBytesX/logString/etc & No hardhat and forge-std console.sol import statements                | ✔️          |
 | [no-empty-blocks](./rules/best-practises/no-empty-blocks.md)       | Code contains empty block.                                                                                            | ✔️          |
-| [no-global-import](./rules/best-practises/no-global-import.md)     | Import statement includes an entire file instead of selected symbols                                                  | ✔️          |
 | [no-unused-vars](./rules/best-practises/no-unused-vars.md)         | Variable "name" is unused.                                                                                            | ✔️          |
 | [payable-fallback](./rules/best-practises/payable-fallback.md)     | When fallback is not payable you will not be able to receive ethers.                                                  | ✔️          |
 | [reason-string](./rules/best-practises/reason-string.md)           | Require or revert statement must have a reason string and check that each reason string is at most N characters long. | ✔️          |
diff --git a/docs/rules/best-practises/no-global-import.md b/docs/rules/best-practises/no-global-import.md
deleted file mode 100644
index e07bfc8..0000000
--- a/docs/rules/best-practises/no-global-import.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-warning:     "This is a dynamically generated file. Do not edit manually."
-layout:      "default"
-title:       "no-global-import | Solhint"
----
-
-# no-global-import
-![Recommended Badge](https://img.shields.io/badge/-Recommended-brightgreen)
-![Category Badge](https://img.shields.io/badge/-Best%20Practise%20Rules-informational)
-![Default Severity Badge warn](https://img.shields.io/badge/Default%20Severity-warn-yellow)
-> The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
-
-
-## Description
-Import statement includes an entire file instead of selected symbols
-
-## Options
-This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Default to warn.
-
-### Example Config
-```json
-{
-  "rules": {
-    "no-global-import": "warn"
-  }
-}
-```
-
-
-## Examples
-### 👍 Examples of **correct** code for this rule
-
-#### import names explicitly
-
-```solidity
-import {A} from "./A.sol"
-```
-
-### 👎 Examples of **incorrect** code for this rule
-
-#### import all members from a file
-
-```solidity
-import * from "foo.sol"
-```
-
-#### import an entire file
-
-```solidity
-import "foo.sol"
-```
-
-## Version
-This rule is introduced in the latest version.
-
-## Resources
-- [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/best-practises/no-global-import.js)
-- [Document source](https://github.com/protofire/solhint/tree/master/docs/rules/best-practises/no-global-import.md)
-- [Test cases](https://github.com/protofire/solhint/tree/master/test/rules/best-practises/no-global-import.js)
diff --git a/docs/rules/security/avoid-low-level-calls.md b/docs/rules/security/avoid-low-level-calls.md
index eea9d15..b543327 100644
--- a/docs/rules/security/avoid-low-level-calls.md
+++ b/docs/rules/security/avoid-low-level-calls.md
@@ -28,23 +28,14 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 
 
 ## Examples
-### 👍 Examples of **correct** code for this rule
-
-#### Using low level calls to transfer funds
-
-```solidity
-anyAddress.call{value: 1 ether}("");
-```
-
 ### 👎 Examples of **incorrect** code for this rule
 
 #### Using low level calls
 
 ```solidity
-anyAddress.call(code);
+msg.sender.call(code);
 a.callcode(test1);
 a.delegatecall(test1);
-anyAddress.call.value(code)();
 ```
 
 ## Version
diff --git a/lib/common/tree-traversing.js b/lib/common/tree-traversing.js
index fc0155b..77b74c0 100644
--- a/lib/common/tree-traversing.js
+++ b/lib/common/tree-traversing.js
@@ -77,6 +77,7 @@ TreeTraversing.typeOf = function typeOf(ctx) {
 
 TreeTraversing.hasMethodCalls = function hasMethodCalls(node, methodNames) {
   const text = node.memberName
+
   return methodNames.includes(text)
 }
 
diff --git a/lib/rules/best-practises/index.js b/lib/rules/best-practises/index.js
index 47012e7..98ff7e2 100644
--- a/lib/rules/best-practises/index.js
+++ b/lib/rules/best-practises/index.js
@@ -7,7 +7,6 @@ const NoUnusedVarsChecker = require('./no-unused-vars')
 const PayableFallbackChecker = require('./payable-fallback')
 const ReasonStringChecker = require('./reason-string')
 const NoConsoleLogChecker = require('./no-console')
-const NoGlobalImportsChecker = require('./no-global-import')
 
 module.exports = function checkers(reporter, config, inputSrc) {
   return [
@@ -20,6 +19,5 @@ module.exports = function checkers(reporter, config, inputSrc) {
     new PayableFallbackChecker(reporter),
     new ReasonStringChecker(reporter, config),
     new NoConsoleLogChecker(reporter),
-    new NoGlobalImportsChecker(reporter),
   ]
 }
diff --git a/lib/rules/best-practises/no-empty-blocks.js b/lib/rules/best-practises/no-empty-blocks.js
index 1fcb3e1..38ef76d 100644
--- a/lib/rules/best-practises/no-empty-blocks.js
+++ b/lib/rules/best-practises/no-empty-blocks.js
@@ -22,6 +22,11 @@ class NoEmptyBlocksChecker extends BaseChecker {
     super(reporter, ruleId, meta)
   }
 
+  ContractDefinition(node) {
+    this.isAssemblyFor = false
+    this._validateContractPartsCount(node)
+  }
+
   Block(node) {
     const isFallbackFunctionBlock = isFallbackFunction(node.parent)
     if (isFallbackFunctionBlock) {
@@ -40,11 +45,19 @@ class NoEmptyBlocksChecker extends BaseChecker {
   }
 
   AssemblyBlock(node) {
-    this._validateChildrenCount(node, 'operations')
+    if (!this.isAssemblyFor) {
+      this._validateChildrenCount(node, 'operations')
+    }
   }
 
-  ContractDefinition(node) {
-    this._validateContractPartsCount(node)
+  AssemblyFor(node) {
+    this.isAssemblyFor = true
+    const operationsCount = node.body.operations.length
+    if (operationsCount === 0) this._error(node)
+  }
+
+  'AssemblyFor:exit'() {
+    this.isAssemblyFor = false
   }
 
   _validateChildrenCount(node, children) {
diff --git a/lib/rules/best-practises/no-global-import.js b/lib/rules/best-practises/no-global-import.js
deleted file mode 100644
index d9ae75f..0000000
--- a/lib/rules/best-practises/no-global-import.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const BaseChecker = require('../base-checker')
-
-const ruleId = 'no-global-import'
-const meta = {
-  type: 'best-practises',
-
-  docs: {
-    description: 'Import statement includes an entire file instead of selected symbols',
-    category: 'Best Practise Rules',
-    examples: {
-      bad: [
-        { description: 'import all members from a file', code: 'import * from "foo.sol"' },
-        { description: 'import an entire file', code: 'import "foo.sol"' },
-      ],
-      good: [{ description: 'import names explicitly', code: 'import {A} from "./A.sol"' }],
-    },
-  },
-
-  isDefault: false,
-  recommended: true,
-  defaultSetup: 'warn',
-
-  schema: null,
-}
-
-class NoGlobalImportsChecker extends BaseChecker {
-  constructor(reporter) {
-    super(reporter, ruleId, meta)
-  }
-
-  ImportDirective(node) {
-    if (!node.symbolAliases) {
-      this.error(
-        node,
-        `global import of path ${node.path} is not allowed. Specify names to import individually`
-      )
-    }
-  }
-}
-
-module.exports = NoGlobalImportsChecker
diff --git a/lib/rules/best-practises/no-unused-vars.js b/lib/rules/best-practises/no-unused-vars.js
index 76cee5c..1ce5c57 100644
--- a/lib/rules/best-practises/no-unused-vars.js
+++ b/lib/rules/best-practises/no-unused-vars.js
@@ -31,19 +31,8 @@ class NoUnusedVarsChecker extends BaseChecker {
 
     if (!ignoreWhen(funcWithoutBlock, emptyBlock)) {
       VarUsageScope.activate(node)
-      // filters 'payable' keyword as name when defining function like this:
-      // function foo(address payable) public view {}
       node.parameters
-        .filter((parameter) => {
-          if (
-            parameter.typeName.name === 'address' &&
-            parameter.typeName.stateMutability === null &&
-            parameter.name === 'payable'
-          )
-            return null
-          else return parameter.name
-        })
-
+        .filter((parameter) => parameter.name)
         .forEach((parameter) => {
           this._addVariable(parameter)
         })
diff --git a/lib/rules/security/avoid-low-level-calls.js b/lib/rules/security/avoid-low-level-calls.js
index 8056de2..21bc1b0 100644
--- a/lib/rules/security/avoid-low-level-calls.js
+++ b/lib/rules/security/avoid-low-level-calls.js
@@ -1,11 +1,5 @@
-/* eslint-disable no-fallthrough */
-/* eslint-disable default-case */
 const BaseChecker = require('../base-checker')
 const { hasMethodCalls } = require('../../common/tree-traversing')
-const LOW_LEVEL_CALLS = require('../../../test/fixtures/security/low-level-calls')
-
-const WARN_LOW_LEVEL_CALLS = LOW_LEVEL_CALLS[0]
-const ALLOWED_LOW_LEVEL_CALLS = LOW_LEVEL_CALLS[1]
 
 const ruleId = 'avoid-low-level-calls'
 const meta = {
@@ -15,16 +9,10 @@ const meta = {
     description: `Avoid to use low level calls.`,
     category: 'Security Rules',
     examples: {
-      good: [
-        {
-          description: 'Using low level calls to transfer funds',
-          code: ALLOWED_LOW_LEVEL_CALLS.join('\n'),
-        },
-      ],
       bad: [
         {
           description: 'Using low level calls',
-          code: WARN_LOW_LEVEL_CALLS.join('\n'),
+          code: require('../../../test/fixtures/security/low-level-calls').join('\n'),
         },
       ],
     },
@@ -42,35 +30,9 @@ class AvoidLowLevelCallsChecker extends BaseChecker {
     super(reporter, ruleId, meta)
   }
 
-  FunctionCall(node) {
-    switch (node.expression.type) {
-      case 'MemberAccess':
-        if (
-          // can add 'value' in the array of hasMethodCalls() and remove the || condition but seems out of place
-          hasMethodCalls(node.expression, ['call', 'callcode', 'delegatecall']) ||
-          (node.expression.expression.memberName === 'call' && // this is for anyAddress.call.value(code)()
-            node.expression.memberName === 'value')
-        ) {
-          return this._warn(node)
-        }
-      case 'NameValueExpression':
-        // Allow low level method calls for transferring funds
-        //
-        // See:
-        //
-        // - https://solidity-by-example.org/sending-ether/
-        // - https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/
-        if (
-          node.expression.expression.memberName === 'call' &&
-          node.expression.arguments.type === 'NameValueList' &&
-          node.expression.arguments.names.includes('value')
-        ) {
-          return
-        }
-
-        if (hasMethodCalls(node.expression.expression, ['call', 'callcode', 'delegatecall'])) {
-          return this._warn(node)
-        }
+  MemberAccess(node) {
+    if (hasMethodCalls(node, ['call', 'callcode', 'delegatecall'])) {
+      this._warn(node)
     }
   }
 
diff --git a/lib/rules/security/func-visibility.js b/lib/rules/security/func-visibility.js
index 4f125df..aa69195 100644
--- a/lib/rules/security/func-visibility.js
+++ b/lib/rules/security/func-visibility.js
@@ -61,28 +61,18 @@ class FuncVisibilityChecker extends BaseChecker {
       config && config.getObjectPropertyBoolean(ruleId, 'ignoreConstructors', false)
   }
 
-  ContractDefinition() {
-    this.isContract = true
-  }
-
-  'ContractDefinition:exit'() {
-    this.isContract = false
-  }
-
   FunctionDefinition(node) {
     if (node.isConstructor && this.ignoreConstructors) {
       return
     }
 
-    if (this.isContract) {
-      if (node.visibility === 'default') {
-        this.warn(
-          node,
-          node.isConstructor
-            ? 'Explicitly mark visibility in function (Set ignoreConstructors to true if using solidity >=0.7.0)'
-            : 'Explicitly mark visibility in function'
-        )
-      }
+    if (node.visibility === 'default') {
+      this.warn(
+        node,
+        node.isConstructor
+          ? 'Explicitly mark visibility in function (Set ignoreConstructors to true if using solidity >=0.7.0)'
+          : 'Explicitly mark visibility in function'
+      )
     }
   }
 }


Test patch:
diff --git a/test/fixtures/security/contracts-with-free-functions.js b/test/fixtures/security/contracts-with-free-functions.js
deleted file mode 100644
index 77b2198..0000000
--- a/test/fixtures/security/contracts-with-free-functions.js
+++ /dev/null
@@ -1,69 +0,0 @@
-const CONTRACTS_FREE_FUNCTIONS_ERRORS_2 = `
-function freeAa() returns(bool) {
-    return true;
-}
-contract A {
-    // error here
-    function functionPublicViewA() returns (uint256) {
-        return 1;
-    }
-}
-
-function freeBb() returns(bool) {
-    return true;
-}
-contract B {
-    // error here
-    function functionPublicViewA() returns (uint256) {
-        return 1;
-    }
-
-    function functionPublicPureB() internal pure returns (bool) {
-        return true;
-    }
-}
-`
-
-const CONTRACT_FREE_FUNCTIONS_ERRORS_1 = `
-contract A {
-    constructor() {}
-
-    // error here
-    function functionPublicViewA() returns (uint256) {
-        return 1;
-    }
-}
-
-function freeBb() returns(bool) {
-    return true;
-}
-`
-
-const NOCONTRACT_FREE_FUNCTION_ERRORS_0 = `
-    // NO error here
-    function functionPublicViewA() returns (uint256) {
-        return 1;
-    }
-`
-
-const CONTRACT_FREE_FUNCTIONS_ERRORS_0 = `
-function freeBb() returns(bool) {
-    return true;
-}
-
-contract A {
-    constructor() {}
-
-    // NO error here
-    function functionPublicViewA() external returns (uint256) {
-        return 1;
-    }
-}
-`
-
-module.exports = {
-  CONTRACTS_FREE_FUNCTIONS_ERRORS_2,
-  CONTRACT_FREE_FUNCTIONS_ERRORS_1,
-  NOCONTRACT_FREE_FUNCTION_ERRORS_0,
-  CONTRACT_FREE_FUNCTIONS_ERRORS_0,
-}
diff --git a/test/fixtures/security/low-level-calls.js b/test/fixtures/security/low-level-calls.js
index 0c9ddaa..194d468 100644
--- a/test/fixtures/security/low-level-calls.js
+++ b/test/fixtures/security/low-level-calls.js
@@ -1,9 +1,1 @@
-const WARN_LOW_LEVEL_CODES = [
-  'anyAddress.call(code);',
-  'a.callcode(test1);',
-  'a.delegatecall(test1);',
-  'anyAddress.call.value(code)();',
-]
-const ALLOWED_LOW_LEVEL_CODES = ['anyAddress.call{value: 1 ether}("");']
-
-module.exports = [WARN_LOW_LEVEL_CODES, ALLOWED_LOW_LEVEL_CODES]
+module.exports = ['msg.sender.call(code);', 'a.callcode(test1);', 'a.delegatecall(test1);']
diff --git a/test/rules/best-practises/no-empty-blocks.js b/test/rules/best-practises/no-empty-blocks.js
index 86c121c..e95c30f 100644
--- a/test/rules/best-practises/no-empty-blocks.js
+++ b/test/rules/best-practises/no-empty-blocks.js
@@ -50,6 +50,69 @@ describe('Linter - no-empty-blocks', () => {
     assertNoWarnings(report)
   })
 
+  it('should not raise error for inline assembly [for] statement with some content', () => {
+    const code = funcWith(`
+      assembly {  
+        for { } lt(i, 0x100) { } {     
+          i := add(i, 0x20)
+        } 
+      }`)
+
+    const report = linter.processStr(code, {
+      rules: { 'no-empty-blocks': 'warn' },
+    })
+
+    assertNoWarnings(report)
+  })
+
+  it('should raise error for inline assembly [for] statement with empty content', () => {
+    const code = funcWith(`
+      assembly {  
+        for { } lt(i, 0x100) { } {     
+        } 
+      }`)
+
+    const report = linter.processStr(code, {
+      rules: { 'no-empty-blocks': 'warn' },
+    })
+    assertWarnsCount(report, 1)
+    assertErrorMessage(report, 'empty block')
+  })
+
+  it('should raise error for inline assembly [for nested] statement with empty content', () => {
+    const code = funcWith(`
+      assembly {  
+        for { } lt(i, 0x100) { } {     
+          for { } lt(j, 0x100) { } {     
+          } 
+        } 
+      }`)
+
+    const report = linter.processStr(code, {
+      rules: { 'no-empty-blocks': 'warn' },
+    })
+    assertWarnsCount(report, 1)
+    assertErrorMessage(report, 'empty block')
+  })
+
+  it('should not raise error for inline assembly [for nested] statement with some content', () => {
+    const code = funcWith(`
+      assembly {  
+        for { } lt(i, 0x100) { } {
+          i := add(i, 0x20)     
+          for { } lt(i, 0x100) { } {     
+            j := add(j, 0x20)
+          } 
+        } 
+      }`)
+
+    const report = linter.processStr(code, {
+      rules: { 'no-empty-blocks': 'warn' },
+    })
+
+    assertNoWarnings(report)
+  })
+
   function label(data) {
     const items = data.split('\n')
     const lastItemIndex = items.length - 1
diff --git a/test/rules/best-practises/no-global-import.js b/test/rules/best-practises/no-global-import.js
deleted file mode 100644
index 199f8c0..0000000
--- a/test/rules/best-practises/no-global-import.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const linter = require('../../../lib/index')
-const {
-  assertNoWarnings,
-  assertLineNumber,
-  assertErrorMessage,
-  assertWarnsCount,
-} = require('../../common/asserts')
-
-describe('Linter - no-global-import', () => {
-  it('should raise on import * from "path"', () => {
-    const code = `import * from './A.sol';`
-
-    const report = linter.processStr(code, {
-      rules: { 'no-global-import': 'warn' },
-    })
-    assertWarnsCount(report, 1)
-    assertErrorMessage(report, 'global import')
-    assertErrorMessage(report, 'Specify names to import individually')
-  })
-  it('should raise on import "path"', () => {
-    const code = `import './A.sol';`
-
-    const report = linter.processStr(code, {
-      rules: { 'no-global-import': 'warn' },
-    })
-    assertWarnsCount(report, 1)
-    assertErrorMessage(report, 'global import')
-    assertErrorMessage(report, 'Specify names to import individually')
-  })
-  it('should raise warning when using solhint:recommended', () => {
-    const code = `pragma solidity ^0.5.8; import "./A.sol";`
-
-    const report = linter.processStr(code, {
-      extends: 'solhint:recommended',
-    })
-    assertWarnsCount(report, 1)
-    assertErrorMessage(report, 'global import')
-    assertErrorMessage(report, 'Specify names to import individually')
-  })
-  it('should report correct line', () => {
-    const code = `import {A} from './A.sol';
-    import './A.sol';`
-
-    const report = linter.processStr(code, {
-      rules: { 'no-global-import': 'warn' },
-    })
-    assertLineNumber(report.reports[0], 2)
-    assertWarnsCount(report, 1)
-  })
-  it('should not raise on import {identifier} from "path"', () => {
-    const code = `import {A} from './A.sol';`
-
-    const report = linter.processStr(code, {
-      rules: { 'no-global-import': 'warn' },
-    })
-    assertNoWarnings(report)
-  })
-})
diff --git a/test/rules/best-practises/no-unused-vars.js b/test/rules/best-practises/no-unused-vars.js
index 0d0292b..a1d6b77 100644
--- a/test/rules/best-practises/no-unused-vars.js
+++ b/test/rules/best-practises/no-unused-vars.js
@@ -10,9 +10,6 @@ describe('Linter - no-unused-vars', () => {
     contractWith('function a(uint a, uint b) public { uint c = a + b; }'),
     contractWith('function foo(uint a) { assembly { let t := a } }'),
     contractWith('function foo(uint a) { uint b = a; } '),
-    contractWith('function foo(address payable unUsed1, address payable) { this; } '),
-    contractWith('function foo(string memory, uint unUsed2) { this; } '),
-    contractWith('function foo(string calldata, uint unUsed3) { this; } '),
   ]
 
   UNUSED_VARS.forEach((curData) =>
diff --git a/test/rules/security/avoid-low-level-calls.js b/test/rules/security/avoid-low-level-calls.js
index 7e4be38..386ab09 100644
--- a/test/rules/security/avoid-low-level-calls.js
+++ b/test/rules/security/avoid-low-level-calls.js
@@ -3,12 +3,10 @@ const funcWith = require('../../common/contract-builder').funcWith
 const { assertWarnsCount, assertErrorMessage } = require('../../common/asserts')
 
 describe('Linter - avoid-low-level-calls', () => {
-  const LOW_LEVEL_CALLS = require('../../fixtures/security/low-level-calls')
-  const WARN_LOW_LEVEL_CALLS = LOW_LEVEL_CALLS[0].map(funcWith)
-  const ALLOWED_LOW_LEVEL_CALLS = LOW_LEVEL_CALLS[1].map(funcWith)
+  const LOW_LEVEL_CALLS = require('../../fixtures/security/low-level-calls').map(funcWith)
 
-  WARN_LOW_LEVEL_CALLS.forEach((curCode) =>
-    it('should return warn when code contains low level calls', () => {
+  LOW_LEVEL_CALLS.forEach((curCode) =>
+    it('should return warn when code contains possible reentrancy', () => {
       const report = linter.processStr(curCode, {
         rules: { 'avoid-low-level-calls': 'warn' },
       })
@@ -17,14 +15,4 @@ describe('Linter - avoid-low-level-calls', () => {
       assertErrorMessage(report, 'low level')
     })
   )
-
-  ALLOWED_LOW_LEVEL_CALLS.forEach((curCode) =>
-    it('should not return warn when code contains allowed low level calls', () => {
-      const report = linter.processStr(curCode, {
-        rules: { 'avoid-low-level-calls': 'warn' },
-      })
-
-      assertWarnsCount(report, 0)
-    })
-  )
 })
diff --git a/test/rules/security/func-visibility.js b/test/rules/security/func-visibility.js
index 3dc3f10..e9779bc 100644
--- a/test/rules/security/func-visibility.js
+++ b/test/rules/security/func-visibility.js
@@ -1,48 +1,6 @@
 const assert = require('assert')
 const linter = require('../../../lib/index')
 const contractWith = require('../../common/contract-builder').contractWith
-const CONTRACTS = require('../../fixtures/security/contracts-with-free-functions')
-
-describe('Linter - func-visibility with free functions', () => {
-  it('should return two warnings and skip free functions', () => {
-    const code = CONTRACTS.CONTRACTS_FREE_FUNCTIONS_ERRORS_2
-    const report = linter.processStr(code, {
-      rules: { 'func-visibility': ['warn', { ignoreConstructors: true }] },
-    })
-
-    assert.equal(report.warningCount, 2)
-    assert.ok(report.reports[0].message.includes('visibility'))
-    assert.ok(report.reports[1].message.includes('visibility'))
-  })
-
-  it('should return one warning and skip free functions', () => {
-    const code = CONTRACTS.CONTRACT_FREE_FUNCTIONS_ERRORS_1
-    const report = linter.processStr(code, {
-      rules: { 'func-visibility': ['warn', { ignoreConstructors: true }] },
-    })
-
-    assert.equal(report.warningCount, 1)
-    assert.ok(report.reports[0].message.includes('visibility'))
-  })
-
-  it('should not return any warning for a free function only', () => {
-    const code = CONTRACTS.NOCONTRACT_FREE_FUNCTION_ERRORS_0
-    const report = linter.processStr(code, {
-      rules: { 'func-visibility': ['warn', { ignoreConstructors: true }] },
-    })
-
-    assert.equal(report.warningCount, 0)
-  })
-
-  it('should not return any warning for a correct contract with a free function', () => {
-    const code = CONTRACTS.CONTRACT_FREE_FUNCTIONS_ERRORS_0
-    const report = linter.processStr(code, {
-      rules: { 'func-visibility': ['warn', { ignoreConstructors: true }] },
-    })
-
-    assert.equal(report.warningCount, 0)
-  })
-})
 
 describe('Linter - func-visibility', () => {
   it('should return required visibility error', () => {