Skip to content

Commit

Permalink
[Frontend-go] Add unit test 4 with fixes on index/slicing expression …
Browse files Browse the repository at this point in the history
…type detection (#1973)

* [Frontend-go] Add unit test for object type detect and fix logic

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

* [Frontend-go] Fix for index/slicing expression type detection

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

* Fix formatting

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

---------

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>
  • Loading branch information
arthurscchan authored Jan 15, 2025
1 parent 4577575 commit abe1ea1
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 7 deletions.
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

0 comments on commit abe1ea1

Please sign in to comment.