Repository: crytic/slither

Issue:
[Bug-Candidate]: solc_parsing for var[x][] dynamic arrays fails when inside top level struct
### Describe the issue:

Testing parser on various types and noticed this particular type fails to be parsed. 

Type is used in solidity docs as `bool[2][] pairsOfFlags;`
https://docs.soliditylang.org/en/latest/types.html?highlight=array#allocating-memory-arrays




### Code example to reproduce the issue:

```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

struct my_struct {
    uint[][] a; // works fine
    uint[][3] b; // works fine
    uint[3][] c; // fails
    uint[3][3] d; // fails
    uint[2**20] e; // works fine
}
contract BaseContract{
    struct my_struct_2 {
        uint[][] f; // works fine
        uint[][3] g; // works fine
        uint[3][] h; // works fine
        uint[3][3] i; // works fine
        uint[2**20] j; // works fine
    }
    
    uint[3][] k; // works fine
}
```

### Version:

0.8.3

### Relevant log output:

```shell
Error in a.sol Traceback (most recent call last): File "/home/plotchy/code/packages/slither/slither/main.py", line 755, in main_impl ) = process_all(filename, args, detector_classes, printer_classes) File "/home/plotchy/code/packages/slither/slither/main.py", line 87, in process_all ) = process_single(compilation, args, detector_classes, printer_classes) File "/home/plotchy/code/packages/slither/slither/main.py", line 70, in process_single slither = Slither(target, ast_format=ast, **vars(args)) File "/home/plotchy/code/packages/slither/slither/slither.py", line 118, in init parser.parse_contracts() File "/home/plotchy/code/packages/slither/slither/solc_parsing/slither_compilation_unit_solc.py", line 485, in parse_contracts self._analyze_second_part(contracts_to_be_analyzed, libraries) File "/home/plotchy/code/packages/slither/slither/solc_parsing/slither_compilation_unit_solc.py", line 553, in _analyze_second_part self._analyze_top_level_structures() File "/home/plotchy/code/packages/slither/slither/solc_parsing/slither_compilation_unit_solc.py", line 631, in _analyze_top_level_structures struct.analyze() File "/home/plotchy/code/packages/slither/slither/solc_parsing/declarations/structure_top_level.py", line 57, in analyze elem_parser.analyze(self) File "/home/plotchy/code/packages/slither/slither/solc_parsing/variables/variable_declaration.py", line 210, in analyze self._variable.type = parse_type(self._elem_to_parse, caller_context) File "/home/plotchy/code/packages/slither/slither/solc_parsing/solidity_types/type_parsing.py", line 401, in parse_type array_type = parse_type(t["baseType"], next_context) File "/home/plotchy/code/packages/slither/slither/solc_parsing/solidity_types/type_parsing.py", line 400, in parse_type length = parse_expression(t["length"], caller_context) File "/home/plotchy/code/packages/slither/slither/solc_parsing/expressions/expression_parsing.py", line 255, in parse_expression assert isinstance(caller_context, CallerContextExpression) AssertionError
```



Discussion:

Resolving patch:
diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py
--- a/slither/solc_parsing/slither_compilation_unit_solc.py
+++ b/slither/solc_parsing/slither_compilation_unit_solc.py
@@ -24,6 +24,7 @@
 from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc
 from slither.solc_parsing.exceptions import VariableNotFound
 from slither.solc_parsing.variables.top_level_variable import TopLevelVariableSolc
+from slither.solc_parsing.declarations.caller_context import CallerContextExpression
 
 logging.basicConfig()
 logger = logging.getLogger("SlitherSolcParsing")
@@ -57,7 +58,7 @@ def _handle_import_aliases(
             scope.renaming[local_name] = original_name
 
 
-class SlitherCompilationUnitSolc:
+class SlitherCompilationUnitSolc(CallerContextExpression):
     # pylint: disable=no-self-use,too-many-instance-attributes
     def __init__(self, compilation_unit: SlitherCompilationUnit):
         super().__init__()
@@ -95,6 +96,10 @@ def add_function_or_modifier_parser(self, f: FunctionSolc):
     def underlying_contract_to_parser(self) -> Dict[Contract, ContractSolc]:
         return self._underlying_contract_to_parser
 
+    @property
+    def slither_parser(self) -> "SlitherCompilationUnitSolc":
+        return self
+
     ###################################################################################
     ###################################################################################
     # region AST


Test patch:
diff --git a/tests/ast-parsing/compile/top-level-struct-0.8.0.sol-0.8.0-compact.zip b/tests/ast-parsing/compile/top-level-struct-0.8.0.sol-0.8.0-compact.zip
new file mode 100644
Binary files /dev/null and b/tests/ast-parsing/compile/top-level-struct-0.8.0.sol-0.8.0-compact.zip differ
diff --git a/tests/ast-parsing/expected/top-level-struct-0.8.0.sol-0.8.0-compact.json b/tests/ast-parsing/expected/top-level-struct-0.8.0.sol-0.8.0-compact.json
new file mode 100644
--- /dev/null
+++ b/tests/ast-parsing/expected/top-level-struct-0.8.0.sol-0.8.0-compact.json
@@ -0,0 +1,3 @@
+{
+  "BaseContract": {}
+}
\ No newline at end of file
diff --git a/tests/ast-parsing/top-level-struct-0.8.0.sol b/tests/ast-parsing/top-level-struct-0.8.0.sol
new file mode 100644
--- /dev/null
+++ b/tests/ast-parsing/top-level-struct-0.8.0.sol
@@ -0,0 +1,18 @@
+struct my_struct {
+    uint[][] a; // works fine
+    uint[][3] b; // works fine
+    uint[3][] c; // fails
+    uint[3][3] d; // fails
+    uint[2**20] e; // works fine
+}
+contract BaseContract{
+    struct my_struct_2 {
+        uint[][] f; // works fine
+        uint[][3] g; // works fine
+        uint[3][] h; // works fine
+        uint[3][3] i; // works fine
+        uint[2**20] j; // works fine
+    }
+    
+    uint[3][] k; // works fine
+}
diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py
--- a/tests/test_ast_parsing.py
+++ b/tests/test_ast_parsing.py
@@ -425,6 +425,7 @@ def make_version(minor: int, patch_min: int, patch_max: int) -> List[str]:
     Test("free_functions/library_constant_function_collision.sol", ["0.8.12"]),
     Test("ternary-with-max.sol", ["0.8.15"]),
     Test("library_event-0.8.16.sol", ["0.8.16"]),
+    Test("top-level-struct-0.8.0.sol", ["0.8.0"]),
 ]
 # create the output folder if needed
 try: