Repository: crytic/slither

Issue:
AttributeError: 'StateVariableSolc' object has no attribute 'view'
This small contract will crash the echidna printer:

```solidity 
contract A {
  bool public b;
}

contract C {
  A a;

  function f() public returns (bool) {
   return a.b();
  }
}
```

To reproduce, just run:

```
$ slither --print echidna test.sol
Compilation warnings/errors on test.sol:
test.sol:1:1: Warning: Source file does not specify required compiler version! Consider adding "pragma solidity ^0.5.7;"
contract A {
^ (Relevant source part starts here and spans across multiple lines).
test.sol:8:3: Warning: Function state mutability can be restricted to view
  function f() public returns (bool) {
  ^ (Relevant source part starts here and spans across multiple lines).

ERROR:root:Error in test.sol
ERROR:root:Traceback (most recent call last):
  File "/home/g/.local/lib/python3.6/site-packages/slither/__main__.py", line 578, in main_impl
    (slither_instances, results_detectors, results_printers, number_contracts) = process_all(filename, args, detector_classes, printer_classes)
  File "/home/g/.local/lib/python3.6/site-packages/slither/__main__.py", line 66, in process_all
    (slither, current_results_detectors, current_results_printers, current_analyzed_count) = process_single(compilation, args, detector_classes, printer_classes)
  File "/home/g/.local/lib/python3.6/site-packages/slither/__main__.py", line 56, in process_single
    return _process(slither, detector_classes, printer_classes)
  File "/home/g/.local/lib/python3.6/site-packages/slither/__main__.py", line 93, in _process
    printer_results = slither.run_printers()
  File "/home/g/.local/lib/python3.6/site-packages/slither/slither.py", line 170, in run_printers
    return [p.output(self.filename).data for p in self._printers]
  File "/home/g/.local/lib/python3.6/site-packages/slither/slither.py", line 170, in <listcomp>
    return [p.output(self.filename).data for p in self._printers]
  File "/home/g/.local/lib/python3.6/site-packages/slither/printers/guidance/echidna.py", line 304, in output
    cst_functions = _extract_constant_functions(self.slither)
  File "/home/g/.local/lib/python3.6/site-packages/slither/printers/guidance/echidna.py", line 98, in _extract_constant_functions
    cst_functions = [_get_name(f) for f in contract.functions_entry_points if _is_constant(f)]
  File "/home/g/.local/lib/python3.6/site-packages/slither/printers/guidance/echidna.py", line 98, in <listcomp>
    cst_functions = [_get_name(f) for f in contract.functions_entry_points if _is_constant(f)]
  File "/home/g/.local/lib/python3.6/site-packages/slither/printers/guidance/echidna.py", line 82, in _is_constant
    if ir.function.view or ir.function.pure:
AttributeError: 'StateVariableSolc' object has no attribute 'view'
```


Discussion:

Resolving patch:
diff --git a/slither/printers/guidance/echidna.py b/slither/printers/guidance/echidna.py
--- a/slither/printers/guidance/echidna.py
+++ b/slither/printers/guidance/echidna.py
@@ -12,6 +12,7 @@
 from slither.core.expressions import NewContract
 from slither.core.slither_core import Slither
 from slither.core.variables.state_variable import StateVariable
+from slither.core.variables.variable import Variable
 from slither.printers.abstract_printer import AbstractPrinter
 from slither.slithir.operations import Member, Operation, SolidityCall, LowLevelCall, HighLevelCall, EventCall, Send, \
     Transfer, InternalDynamicCall, InternalCall, TypeConversion, Balance
@@ -79,7 +80,7 @@ def _is_constant(f: Function) -> bool:
                                                             SolidityFunction('suicide(address)')]:
             return False
         if isinstance(ir, HighLevelCall):
-            if ir.function.view or ir.function.pure:
+            if isinstance(ir.function, Variable) or ir.function.view or ir.function.pure:
                 # External call to constant functions are ensured to be constant only for solidity >= 0.5
                 if f.contract.slither.crytic_compile.compiler_version.version.startswith('0.4'):
                     return False
diff --git a/slither/slithir/operations/high_level_call.py b/slither/slithir/operations/high_level_call.py
--- a/slither/slithir/operations/high_level_call.py
+++ b/slither/slithir/operations/high_level_call.py
@@ -1,3 +1,5 @@
+from typing import Union
+
 from slither.slithir.operations.call import Call
 from slither.slithir.operations.lvalue import OperationWithLValue
 from slither.core.variables.variable import Variable
@@ -73,7 +75,7 @@ def function_name(self):
         return self._function_name
 
     @property
-    def function(self):
+    def function(self) -> Union[Function, Variable]:
         return self._function_instance
 
     @function.setter


Test patch: