Repository: terryyin/lizard

Issue:
Go state machine misinterprets `func` keyword Inside Struct and Interface definitions
Golang state machine is incorrectly interpreting the func keyword inside struct and interface definitions as the start of new function declarations. But, because in golang you cannot define a function body inside type, this leads to incorrect function counts and potentially inaccurate complexity analysis. 

I suppose this issue arises because state machine does not properly handle the context where the func keyword appears inside structs and interfaces. 

Example for `struct`:
```go
type Geometry struct {
    isEqual func(float64, float64) error
 }

func (g *Geometry) sayGoodbye() { } // function name is None
```

Example for `interface`:
```go
type MyComparator struct{}

type Comparator interface {
    Handle(func(int) string)
}

func (m MyComparator) Handle(f func(int) string) {} // function name is None
```

Discussion:

Solution patch:
diff --git a/lizard_languages/golike.py b/lizard_languages/golike.py
index caa1583..a131460 100644
--- a/lizard_languages/golike.py
+++ b/lizard_languages/golike.py
@@ -13,11 +13,32 @@ class GoLikeStates(CodeStateMachine):  # pylint: disable=R0903
         if token == self.FUNC_KEYWORD:
             self._state = self._function_name
             self.context.push_new_function('')
+        elif token == 'type':
+            self._state = self._type_definition
         elif token in '{':
             self.sub_state(self.statemachine_clone())
         elif token in '}':
             self.statemachine_return()
 
+    def _type_definition(self, token):
+        self._state = self._after_type_name
+
+    def _after_type_name(self, token):
+        if token == 'struct':
+            self._state = self._struct_definition
+        elif token == 'interface':
+            self._state = self._interface_definition
+        else:
+            self._state = self._state_global
+
+    @CodeStateMachine.read_inside_brackets_then("{}", "_state_global")
+    def _struct_definition(self, tokens):
+        pass
+
+    @CodeStateMachine.read_inside_brackets_then("{}", "_state_global")
+    def _interface_definition(self, tokens):
+        pass
+
     def _function_name(self, token):
         if token != '`':
             if token == '(':


Test patch:
diff --git a/test/test_languages/testGo.py b/test/test_languages/testGo.py
index 22fce2a..5a6462d 100644
--- a/test/test_languages/testGo.py
+++ b/test/test_languages/testGo.py
@@ -127,3 +127,28 @@ class Test_parser_for_Go(unittest.TestCase):
                 ''')
         self.assertEqual(0, len(result))
 
+    def test_struct_with_func_followed_by_function_with_receiver(self):
+        result = get_go_function_list('''
+            type Geometry struct {
+                isEqual func(float64, float64) error
+            }
+
+            func (g *Geometry) sayGoodbye() { }
+                ''')
+
+        self.assertEqual(1, len(result))
+        self.assertEqual("sayGoodbye", result[0].name)
+
+    def test_interface_with_func_followed_by_function_with_receiver(self):
+        result = get_go_function_list('''
+            type MyComparator struct{}
+
+            type Comparator interface {
+                Handle(func(int) string)
+            }
+
+            func (m MyComparator) Handle(f func(int) string) {}
+                ''')
+
+        self.assertEqual(1, len(result))
+        self.assertEqual("Handle", result[0].name)