Skip to content

Commit abe1ea1

Browse files
authored
[Frontend-go] Add unit test 4 with fixes on index/slicing expression type detection (#1973)
* [Frontend-go] Add unit test for object type detect and fix logic Signed-off-by: Arthur Chan <[email protected]> * [Frontend-go] Fix for index/slicing expression type detection Signed-off-by: Arthur Chan <[email protected]> * Fix formatting Signed-off-by: Arthur Chan <[email protected]> --------- Signed-off-by: Arthur Chan <[email protected]>
1 parent 4577575 commit abe1ea1

File tree

3 files changed

+139
-7
lines changed

3 files changed

+139
-7
lines changed

src/fuzz_introspector/frontends/frontend_go.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ def dump_module_logic(self,
222222
for func_def in functions_methods:
223223
func_def.extract_local_variable_type(
224224
self.functions_methods_map)
225+
# Need a second pass because the processing may out of order
226+
# That could affect some local variable types that are
227+
# relying on other variables
228+
func_def.extract_local_variable_type(
229+
self.functions_methods_map)
230+
225231
func_def.extract_callsites(self.functions_methods_map)
226232
func_dict: dict[str, Any] = {}
227233
func_dict['functionName'] = func_def.function_name
@@ -663,10 +669,15 @@ def _detect_variable_type(
663669
if target_name:
664670
return target_name
665671

666-
# TODO Handles the following type
667-
# index_expression slice_expression
668-
# type_assertion_expression type_conversion_expression
669-
# type_instantiation_expression
672+
# Index expression / Slice expression
673+
elif child.type in ['index_expression', 'slice_expression']:
674+
op = child.child_by_field_name('operand')
675+
parent_type = self.var_map.get(op.text.decode())
676+
if parent_type:
677+
if '[' in parent_type and ']' in parent_type:
678+
return parent_type.rsplit(']', 1)[-1]
679+
elif parent_type == 'string':
680+
return 'uint8'
670681

671682
# Other expression that need to recursive deeper
672683
# unary_expression binary_expression
@@ -680,8 +691,6 @@ def extract_local_variable_type(self,
680691
all_funcs_meths: dict[str,
681692
'FunctionMethod']):
682693
"""Gets the local variable types of the function."""
683-
# TODO The handling of all kind of variable declaration approach is not done.
684-
# There are some requires extensive search to determine a type.
685694

686695
query = self.tree_sitter_lang.query('( var_declaration ) @vd')
687696
for _, exprs in query.captures(self.root).items():
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
package structs
17+
18+
import (
19+
"testing"
20+
"fmt"
21+
"strconv"
22+
)
23+
24+
type Person struct {
25+
Name string
26+
Age int
27+
}
28+
29+
func (p Person) Greet() string {
30+
return fmt.Sprintf("Hello, my name is %s and I am %d years old.", p.Name, p.Age)
31+
}
32+
33+
func (p Person) Introduce() string {
34+
return fmt.Sprintf("I am %s, a person of age %d.", p.Name, p.Age)
35+
}
36+
37+
func (p Person) Describe() string {
38+
return fmt.Sprintf("Person: %s, Age: %d", p.Name, p.Age)
39+
}
40+
41+
type Dog struct {
42+
Name string
43+
}
44+
45+
func (d Dog) Greet() string {
46+
return fmt.Sprintf("Hello, my dog's name is %s.", d.Name)
47+
}
48+
49+
func (d Dog) Introduce() string {
50+
return fmt.Sprintf("This is my dog, %s.", d.Name)
51+
}
52+
53+
func (d Dog) Describe() string {
54+
return fmt.Sprintf("Dog: %s", d.Name)
55+
}
56+
57+
func NewDog(name string) Dog {
58+
return Dog{Name: name}
59+
}
60+
61+
type Robot struct {
62+
Model string
63+
}
64+
65+
func (r Robot) Greet() string {
66+
return fmt.Sprintf("Hello, I am a robot of model %s.", r.Model)
67+
}
68+
69+
func (r Robot) Introduce() string {
70+
return fmt.Sprintf("I am %s, a highly advanced robot.", r.Model)
71+
}
72+
73+
func (r Robot) Describe() string {
74+
return fmt.Sprintf("Robot Model: %s", r.Model)
75+
}
76+
77+
func FuzzStructs(f *testing.F) {
78+
f.Fuzz(func(t *testing.T, name string, ageString string, model string) {
79+
age, err := strconv.Atoi(ageString)
80+
if err != nil {
81+
return
82+
}
83+
84+
personMap := map[int]Person{
85+
0: {Name: "Default", Age: 0},
86+
1: {Name: name, Age: age},
87+
}
88+
p := personMap[1]
89+
90+
var dogInterface interface{} = Dog{Name: name}
91+
d, ok := dogInterface.(Dog)
92+
if !ok {
93+
return
94+
}
95+
96+
d := NewDog(name)
97+
98+
robots := [3]Robot{
99+
{Model: "X-1000"},
100+
{Model: "R2-D2"},
101+
{Model: model},
102+
}
103+
r := robots[0]
104+
105+
_ = p.Greet()
106+
_ = d.Introduce()
107+
_ = r.Describe()
108+
})
109+
}

src/test/test_frontends_go.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,21 @@ def test_tree_sitter_go_sample4():
9191

9292
# Project check
9393
harness = project.get_source_codes_with_harnesses()
94-
assert len(harness) == 0
94+
assert len(harness) == 1
95+
96+
functions_reached = project.get_reachable_functions(harness[0].source_file, harness[0])
97+
98+
# Callsite check
99+
assert 'strconv.Atoi' in functions_reached
100+
assert 'Person.Greet' in functions_reached
101+
assert 'Dog.Introduce' in functions_reached
102+
assert 'Robot.Describe' in functions_reached
103+
assert 'Person.Introduce' not in functions_reached
104+
assert 'Person.Describe' not in functions_reached
105+
assert 'Dog.Greet' not in functions_reached
106+
assert 'Dog.Describe' not in functions_reached
107+
assert 'Robot.Greet' not in functions_reached
108+
assert 'Robot.Introduce' not in functions_reached
95109

96110

97111
def test_tree_sitter_go_sample5():

0 commit comments

Comments
 (0)