Repository: crytic/slither

Issue:
Immutables are not completely understood/supported
Slither reports the following:
```
MyContract.myImmutable (contracts/MyContract.sol#10) should be constant
```

However it is a constant:
```
    uint256 public immutable myImmutable;
```

Immutables are set-once (in the constructor) variables, so in practice act as constants.


Discussion:

Resolving patch:
diff --git a/slither/core/variables/variable.py b/slither/core/variables/variable.py
--- a/slither/core/variables/variable.py
+++ b/slither/core/variables/variable.py
@@ -20,6 +20,7 @@ def __init__(self):
         self._initialized: Optional[bool] = None
         self._visibility: Optional[str] = None
         self._is_constant = False
+        self._is_immutable: bool = False
 
     @property
     def is_scalar(self) -> bool:
@@ -106,6 +107,19 @@ def set_type(self, t):
         assert isinstance(t, (Type, list)) or t is None
         self._type = t
 
+    @property
+    def is_immutable(self) -> bool:
+        """
+        Return true of the variable is immutable
+
+        :return:
+        """
+        return self._is_immutable
+
+    @is_immutable.setter
+    def is_immutable(self, immutablility: bool):
+        self._is_immutable = immutablility
+
     @property
     def function_name(self):
         """
diff --git a/slither/detectors/variables/possible_const_state_variables.py b/slither/detectors/variables/possible_const_state_variables.py
--- a/slither/detectors/variables/possible_const_state_variables.py
+++ b/slither/detectors/variables/possible_const_state_variables.py
@@ -31,7 +31,7 @@ class ConstCandidateStateVars(AbstractDetector):
 
     @staticmethod
     def _valid_candidate(v):
-        return isinstance(v.type, ElementaryType) and not v.is_constant
+        return isinstance(v.type, ElementaryType) and not (v.is_constant or v.is_immutable)
 
     # https://solidity.readthedocs.io/en/v0.5.2/contracts.html#constant-state-variables
     valid_solidity_function = [
diff --git a/slither/solc_parsing/variables/variable_declaration.py b/slither/solc_parsing/variables/variable_declaration.py
--- a/slither/solc_parsing/variables/variable_declaration.py
+++ b/slither/solc_parsing/variables/variable_declaration.py
@@ -136,6 +136,14 @@ def _init_from_declaration(self, var: Dict, init: bool):  # pylint: disable=too-
         if "constant" in attributes:
             self._variable.is_constant = attributes["constant"]
 
+        if "mutability" in attributes:
+            # Note: this checked is not needed if "constant" was already in attribute, but we keep it
+            # for completion
+            if attributes["mutability"] == "constant":
+                self._variable.is_constant = True
+            if attributes["mutability"] == "immutable":
+                self._variable.is_immutable = True
+
         self._analyze_variable_attributes(attributes)
 
         if self._is_compact_ast:


Test patch:
diff --git a/tests/detectors/constable-states/0.8.0/immutable.sol b/tests/detectors/constable-states/0.8.0/immutable.sol
new file mode 100644
--- /dev/null
+++ b/tests/detectors/constable-states/0.8.0/immutable.sol
@@ -0,0 +1,7 @@
+contract C{
+    uint immutable v;
+
+    constructor() public{
+        v = 0;
+    }
+}
diff --git a/tests/detectors/constable-states/0.8.0/immutable.sol.0.8.0.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.8.0/immutable.sol.0.8.0.ConstCandidateStateVars.json
new file mode 100644
--- /dev/null
+++ b/tests/detectors/constable-states/0.8.0/immutable.sol.0.8.0.ConstCandidateStateVars.json
@@ -0,0 +1,3 @@
+[
+    []
+]
\ No newline at end of file
diff --git a/tests/test_detectors.py b/tests/test_detectors.py
--- a/tests/test_detectors.py
+++ b/tests/test_detectors.py
@@ -472,6 +472,11 @@ def id_test(test_item: Test):
         "const_state_variables.sol",
         "0.7.6",
     ),
+    Test(
+        all_detectors.ConstCandidateStateVars,
+        "immutable.sol",
+        "0.8.0",
+    ),
     Test(
         all_detectors.ExternalFunction,
         "external_function.sol",