Repository: wemake-services/wemake-python-styleguide

Issue:
Forbid to use multiple negations for numbers
# Rule request

<!-- Thanks for coming up with a proposal! -->

## Thesis

We can write things like `dt = ---6`. But, we need to force `-6` for numbers.
Related #434 

## Reasoning

Consistency.



Discussion:
What about others duplicated operators? `~~~42` or  `not not bar`? Those are rare, but feels like on the same page.
Hmm, I have missed that. 
Feels like a plan.

What do you think?
Looks good, except it's hard to find any cases for them. Original issue `+5` has own reality roots (for instance, readability by rewriting some constants from a reference guide where those numbers are explicitly signed), but multiple same operators feels quite synthetic. 
You may not believe me, but not not in real life: https://github.com/pypa/setuptools/blob/master/pkg_resources/_vendor/pyparsing.py#L458 - I guess it's int to bool casting. But why so hard?
That's why we should forbid it. This it not a javascript with `!!` operators.

Resolving patch:
diff --git a/wemake_python_styleguide/violations/consistency.py b/wemake_python_styleguide/violations/consistency.py
--- a/wemake_python_styleguide/violations/consistency.py
+++ b/wemake_python_styleguide/violations/consistency.py
@@ -1150,7 +1150,8 @@ class UselessOperatorsViolation(ASTViolation):
     Forbids the use of unnecessary operators in your code.
 
     You can write: ``5.4`` and ``+5.4``. There's no need to use the second
-    version.
+    version. Similarly ``--5.4``, ``---5.4``, ``not not foo``, and ``~~42``
+    contain unnecessary operators.
 
     Reasoning:
          This is done for consistency reasons.
@@ -1162,9 +1163,16 @@ class UselessOperatorsViolation(ASTViolation):
 
         # Correct:
         profit = 3.33
+        profit = -3.33
+        inverse = ~5
+        complement = not foo
 
         # Wrong:
         profit = +3.33
+        profit = --3.33
+        profit = ---3.33
+        number = ~~42
+        bar = not not foo
 
     .. versionadded:: 0.8.0
 
diff --git a/wemake_python_styleguide/visitors/ast/builtins.py b/wemake_python_styleguide/visitors/ast/builtins.py
--- a/wemake_python_styleguide/visitors/ast/builtins.py
+++ b/wemake_python_styleguide/visitors/ast/builtins.py
@@ -95,6 +95,21 @@ def _check_plus_sign(self, node: ast.Num) -> None:
             return
         self.add_violation(UselessOperatorsViolation(node, text=str(node.n)))
 
+    def _check_minus_sign(self, node: ast.Num) -> None:
+        if not count_unary_operator(node, ast.USub) > 1:
+            return
+        self.add_violation(UselessOperatorsViolation(node, text=str(node.n)))
+
+    def _check_tilde_sign(self, node: ast.Num) -> None:
+        if not count_unary_operator(node, ast.Invert) > 1:
+            return
+        self.add_violation(UselessOperatorsViolation(node, text=str(node.n)))
+
+    def _check_not(self, node: ast.Num) -> None:
+        if not count_unary_operator(node, ast.Not) > 1:
+            return
+        self.add_violation(UselessOperatorsViolation(node, text=str(node.n)))
+
     def visit_Num(self, node: ast.Num) -> None:
         """
         Checks numbers unnecessary operators inside the code.
@@ -104,8 +119,9 @@ def visit_Num(self, node: ast.Num) -> None:
 
         """
         self._check_plus_sign(node)
-        # TODO: Add forbid to use multiple negations for numbers,
-        # see issue 435 self.generic_visit(node)
+        self._check_minus_sign(node)
+        self._check_tilde_sign(node)
+        self._check_not(node)
         self.generic_visit(node)
 
 


Test patch:
diff --git a/tests/test_visitors/test_ast/test_builtins/test_useless_operators_before_numbers.py b/tests/test_visitors/test_ast/test_builtins/test_useless_operators_before_numbers.py
--- a/tests/test_visitors/test_ast/test_builtins/test_useless_operators_before_numbers.py
+++ b/tests/test_visitors/test_ast/test_builtins/test_useless_operators_before_numbers.py
@@ -45,6 +45,11 @@ def function_name(param1, param2={0}):
    '+-5',
    '~+5',
    '+~5',
+   '--5',
+   '---5',
+   '~~5',
+   '~~~5',
+   '(not not 5)',
 ])
 def test_plus_sign_before_numbers(
     assert_errors,
@@ -68,6 +73,7 @@ def test_plus_sign_before_numbers(
    '5',
    '-5',
    '~5',
+   '(not 5)',
 ])
 def test_plus_sign_before_numbers_valid(
     assert_errors,