Repository: crytic/slither

Issue:
[Bug]: is_fully_implemented property of Contract objects always False
### Describe the issue:

All `Contract` objects' `is_fully_implemented` property seems to never get updated, and is always False (since initialisation).
In previous versions of Slither, the equivalent property was `fullyImplemented`, and was working well at least up till v0.6.8

### Code example to reproduce the issue:

Here is an example with 2 contracts, Loan (not fully implemented) and LoanDirectory (fully implemented).

https://etherscan.io/address/0xc477042db387DD59C038Ca4b829a07964b674347#code

### Version:

0.9.3

### Relevant log output:

_No response_


Discussion:

Resolving patch:
diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py
--- a/slither/solc_parsing/declarations/contract.py
+++ b/slither/solc_parsing/declarations/contract.py
@@ -170,10 +170,9 @@ def _parse_contract_info(self) -> None:
             elif attributes["contractKind"] == "library":
                 self._contract.is_library = True
             self._contract.contract_kind = attributes["contractKind"]
-            self._contract.is_fully_implemented = attributes["fullyImplemented"]
 
+        self._contract.is_fully_implemented = attributes["fullyImplemented"]
         self._linearized_base_contracts = attributes["linearizedBaseContracts"]
-        # self._contract.fullyImplemented = attributes["fullyImplemented"]
 
         # Parse base contract information
         self._parse_base_contract_info()


Test patch:
diff --git a/tests/unit/core/test_contract_declaration.py b/tests/unit/core/test_contract_declaration.py
--- a/tests/unit/core/test_contract_declaration.py
+++ b/tests/unit/core/test_contract_declaration.py
@@ -27,6 +27,20 @@ def test_abstract_contract(solc_binary_path) -> None:
     assert not slither.contracts[0].is_fully_implemented
 
 
+def test_concrete_contract(solc_binary_path) -> None:
+    solc_path = solc_binary_path("0.8.0")
+    slither = Slither(Path(CONTRACT_DECL_TEST_ROOT, "concrete.sol").as_posix(), solc=solc_path)
+    assert slither.contracts[0].is_fully_implemented
+
+    solc_path = solc_binary_path("0.5.0")
+    slither = Slither(
+        Path(CONTRACT_DECL_TEST_ROOT, "concrete_old.sol").as_posix(),
+        solc_force_legacy_json=True,
+        solc=solc_path,
+    )
+    assert slither.contracts[0].is_fully_implemented
+
+
 def test_private_variable(solc_binary_path) -> None:
     solc_path = solc_binary_path("0.8.15")
     slither = Slither(
diff --git a/tests/unit/core/test_data/contract_declaration/concrete.sol b/tests/unit/core/test_data/contract_declaration/concrete.sol
new file mode 100644
--- /dev/null
+++ b/tests/unit/core/test_data/contract_declaration/concrete.sol
@@ -0,0 +1,9 @@
+pragma solidity ^0.8.0;
+
+contract Concrete {
+    uint256 public value;
+
+    function setValue(uint256 newValue) public {
+        value = newValue;
+    }
+}
diff --git a/tests/unit/core/test_data/contract_declaration/concrete_old.sol b/tests/unit/core/test_data/contract_declaration/concrete_old.sol
new file mode 100644
--- /dev/null
+++ b/tests/unit/core/test_data/contract_declaration/concrete_old.sol
@@ -0,0 +1,13 @@
+pragma solidity ^0.5.0;
+
+contract ConcreteOld {
+    uint256 public myNumber;
+
+    constructor(uint256 initialNumber) public {
+        myNumber = initialNumber;
+    }
+
+    function setNumber(uint256 newNumber) public {
+        myNumber = newNumber;
+    }
+}