Repository: crytic/slither

Issue:
Improper work of naming-convention detector
`naming-convention` detector acts incorrectly in case the function parameters have no name: 
```
contract ERC677 {
    function transferAndCall(address, uint, bytes) external returns (bool);
}
```
```
Parameter '' of ERC677.transferAndCall (contracts/ERC677.sol#2) is not in mixedCase
```

Moreover, it finds function arguments, which names are starting with '_'. You may consider ignoring this case as it is a common practice.
Improper work of naming-convention detector
`naming-convention` detector acts incorrectly in case the function parameters have no name: 
```
contract ERC677 {
    function transferAndCall(address, uint, bytes) external returns (bool);
}
```
```
Parameter '' of ERC677.transferAndCall (contracts/ERC677.sol#2) is not in mixedCase
```

Moreover, it finds function arguments, which names are starting with '_'. You may consider ignoring this case as it is a common practice.


Discussion:
Hi @sobolev-igor.

Thank you for reporting the issue. We are going to fix it as soon as possible.
Hi @sobolev-igor.

Thank you for reporting the issue. We are going to fix it as soon as possible.

Resolving patch:
diff --git a/slither/detectors/naming_convention/naming_convention.py b/slither/detectors/naming_convention/naming_convention.py
--- a/slither/detectors/naming_convention/naming_convention.py
+++ b/slither/detectors/naming_convention/naming_convention.py
@@ -41,7 +41,7 @@ def is_mixed_case(name):
     def is_mixed_case_with_underscore(name):
         # Allow _ at the beginning to represent private variable
         # or unused parameters
-        return re.search('^[a-z_]([A-Za-z0-9]+)?_?$', name) is not None
+        return re.search('^[_]?[a-z]([A-Za-z0-9]+)?_?$', name) is not None
 
     @staticmethod
     def is_upper_case_with_underscores(name):
@@ -93,6 +93,8 @@ def _detect(self):
 
             for func in contract.functions_declared:
                 if not self.is_mixed_case(func.name):
+                    if func.visibility in ['internal', 'private'] and self.is_mixed_case_with_underscore(func.name):
+                        continue
                     info = "Function '{}' ({}) is not in mixedCase\n"
                     info = info.format(func.canonical_name, func.source_mapping_str)
 
diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py
--- a/slither/solc_parsing/declarations/function.py
+++ b/slither/solc_parsing/declarations/function.py
@@ -98,9 +98,10 @@ def _add_local_variable(self, local_var):
         # This is done to prevent collision during SSA translation
         # Use of while in case of collision
         # In the worst case, the name will be really long
-        while local_var.name in self._variables:
-            local_var.name += "_scope_{}".format(self._counter_scope_local_variables)
-            self._counter_scope_local_variables += 1
+        if local_var.name:
+            while local_var.name in self._variables:
+                local_var.name += "_scope_{}".format(self._counter_scope_local_variables)
+                self._counter_scope_local_variables += 1
         if not local_var.reference_id is None:
             self._variables_renamed[local_var.reference_id] = local_var
         self._variables[local_var.name] = local_var


Test patch: