Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Frontend-go] Add unit test 4 with fixes on index/slicing expression type detection #1973

Merged
merged 4 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions src/fuzz_introspector/frontends/frontend_go.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ def dump_module_logic(self,
for func_def in functions_methods:
func_def.extract_local_variable_type(
self.functions_methods_map)
# Need a second pass because the processing may out of order
# That could affect some local variable types that are
# relying on other variables
func_def.extract_local_variable_type(
self.functions_methods_map)

func_def.extract_callsites(self.functions_methods_map)
func_dict: dict[str, Any] = {}
func_dict['functionName'] = func_def.function_name
Expand Down Expand Up @@ -663,10 +669,15 @@ def _detect_variable_type(
if target_name:
return target_name

# TODO Handles the following type
# index_expression slice_expression
# type_assertion_expression type_conversion_expression
# type_instantiation_expression
# Index expression / Slice expression
elif child.type in ['index_expression', 'slice_expression']:
op = child.child_by_field_name('operand')
parent_type = self.var_map.get(op.text.decode())
if parent_type:
if '[' in parent_type and ']' in parent_type:
return parent_type.rsplit(']', 1)[-1]
elif parent_type == 'string':
return 'uint8'

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

query = self.tree_sitter_lang.query('( var_declaration ) @vd')
for _, exprs in query.captures(self.root).items():
Expand Down
109 changes: 109 additions & 0 deletions src/test/data/source-code/go/test-project-4/fuzzer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package structs

import (
"testing"
"fmt"
"strconv"
)

type Person struct {
Name string
Age int
}

func (p Person) Greet() string {
return fmt.Sprintf("Hello, my name is %s and I am %d years old.", p.Name, p.Age)
}

func (p Person) Introduce() string {
return fmt.Sprintf("I am %s, a person of age %d.", p.Name, p.Age)
}

func (p Person) Describe() string {
return fmt.Sprintf("Person: %s, Age: %d", p.Name, p.Age)
}

type Dog struct {
Name string
}

func (d Dog) Greet() string {
return fmt.Sprintf("Hello, my dog's name is %s.", d.Name)
}

func (d Dog) Introduce() string {
return fmt.Sprintf("This is my dog, %s.", d.Name)
}

func (d Dog) Describe() string {
return fmt.Sprintf("Dog: %s", d.Name)
}

func NewDog(name string) Dog {
return Dog{Name: name}
}

type Robot struct {
Model string
}

func (r Robot) Greet() string {
return fmt.Sprintf("Hello, I am a robot of model %s.", r.Model)
}

func (r Robot) Introduce() string {
return fmt.Sprintf("I am %s, a highly advanced robot.", r.Model)
}

func (r Robot) Describe() string {
return fmt.Sprintf("Robot Model: %s", r.Model)
}

func FuzzStructs(f *testing.F) {
f.Fuzz(func(t *testing.T, name string, ageString string, model string) {
age, err := strconv.Atoi(ageString)
if err != nil {
return
}

personMap := map[int]Person{
0: {Name: "Default", Age: 0},
1: {Name: name, Age: age},
}
p := personMap[1]

var dogInterface interface{} = Dog{Name: name}
d, ok := dogInterface.(Dog)
if !ok {
return
}

d := NewDog(name)

robots := [3]Robot{
{Model: "X-1000"},
{Model: "R2-D2"},
{Model: model},
}
r := robots[0]

_ = p.Greet()
_ = d.Introduce()
_ = r.Describe()
})
}
16 changes: 15 additions & 1 deletion src/test/test_frontends_go.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,21 @@ def test_tree_sitter_go_sample4():

# Project check
harness = project.get_source_codes_with_harnesses()
assert len(harness) == 0
assert len(harness) == 1

functions_reached = project.get_reachable_functions(harness[0].source_file, harness[0])

# Callsite check
assert 'strconv.Atoi' in functions_reached
assert 'Person.Greet' in functions_reached
assert 'Dog.Introduce' in functions_reached
assert 'Robot.Describe' in functions_reached
assert 'Person.Introduce' not in functions_reached
assert 'Person.Describe' not in functions_reached
assert 'Dog.Greet' not in functions_reached
assert 'Dog.Describe' not in functions_reached
assert 'Robot.Greet' not in functions_reached
assert 'Robot.Introduce' not in functions_reached


def test_tree_sitter_go_sample5():
Expand Down
Loading