Skip to content
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
16 changes: 16 additions & 0 deletions sourcecode-parser/graph/construct.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Node struct {
YieldStmt *model.YieldStmt
AssertStmt *model.AssertStmt
ReturnStmt *model.ReturnStmt
BlockStmt *model.BlockStmt
}

type Edge struct {
Expand Down Expand Up @@ -183,6 +184,21 @@ func parseJavadocTags(commentContent string) *model.Javadoc {
func buildGraphFromAST(node *sitter.Node, sourceCode []byte, graph *CodeGraph, currentContext *Node, file string) {
isJavaSourceFile := isJavaSourceFile(file)
switch node.Type() {
case "block":
blockNode := javalang.ParseBlockStatement(node, sourceCode)
uniqueBlockID := fmt.Sprintf("block_%d_%d_%s", node.StartPoint().Row+1, node.StartPoint().Column+1, file)
blockStmtNode := &Node{
ID: GenerateSha256(uniqueBlockID),
Type: "BlockStmt",
LineNumber: node.StartPoint().Row + 1,
Name: "BlockStmt",
IsExternal: true,
CodeSnippet: node.Content(sourceCode),
File: file,
isJavaSourceFile: isJavaSourceFile,
BlockStmt: blockNode,
}
graph.AddNode(blockStmtNode)
case "return_statement":
returnNode := javalang.ParseReturnStatement(node, sourceCode)
uniqueReturnID := fmt.Sprintf("return_%d_%d_%s", node.StartPoint().Row+1, node.StartPoint().Column+1, file)
Expand Down
18 changes: 9 additions & 9 deletions sourcecode-parser/graph/construct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,9 +701,9 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 3,
expectedNodes: 4,
expectedEdges: 0,
expectedTypes: []string{"class_declaration", "method_declaration", "variable_declaration"},
expectedTypes: []string{"class_declaration", "method_declaration", "variable_declaration", "BlockStmt"},
unexpectedTypes: []string{"method_invocation"},
},
{
Expand All @@ -718,9 +718,9 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 5,
expectedNodes: 7,
expectedEdges: 2,
expectedTypes: []string{"class_declaration", "method_declaration", "method_invocation"},
expectedTypes: []string{"class_declaration", "method_declaration", "method_invocation", "BlockStmt"},
unexpectedTypes: []string{"variable_declaration"},
},
{
Expand All @@ -732,7 +732,7 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 5,
expectedNodes: 6,
expectedEdges: 0,
expectedTypes: []string{"class_declaration", "method_declaration", "binary_expression", "ReturnStmt"},
unexpectedTypes: []string{"variable_declaration"},
Expand Down Expand Up @@ -791,9 +791,9 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 74,
expectedNodes: 83,
expectedEdges: 5,
expectedTypes: []string{"class_declaration", "method_declaration", "binary_expression", "comp_expression", "and_expression", "or_expression", "IfStmt", "ForStmt", "WhileStmt", "DoStmt", "BreakStmt", "ContinueStmt", "YieldStmt", "ReturnStmt"},
expectedTypes: []string{"class_declaration", "method_declaration", "binary_expression", "comp_expression", "and_expression", "or_expression", "IfStmt", "ForStmt", "WhileStmt", "DoStmt", "BreakStmt", "ContinueStmt", "YieldStmt", "ReturnStmt", "BlockStmt"},
unexpectedTypes: []string{""},
},
{
Expand All @@ -811,7 +811,7 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 4,
expectedNodes: 5,
expectedEdges: 0,
expectedTypes: []string{"class_declaration", "method_declaration", "block_comment", "ReturnStmt"},
unexpectedTypes: []string{"variable_declaration", "binary_expression"},
Expand All @@ -827,7 +827,7 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 6,
expectedNodes: 7,
expectedEdges: 0,
expectedTypes: []string{"class_declaration", "method_declaration", "ClassInstanceExpr"},
unexpectedTypes: []string{"binary_expression"},
Expand Down
10 changes: 10 additions & 0 deletions sourcecode-parser/graph/java/parse_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,13 @@ func ParseReturnStatement(node *sitter.Node, sourcecode []byte) *model.ReturnStm
}
return returnStmt
}

func ParseBlockStatement(node *sitter.Node, sourcecode []byte) *model.BlockStmt {
blockStmt := &model.BlockStmt{}
for i := 0; i < int(node.ChildCount()); i++ {
singleBlockStmt := &model.Stmt{}
singleBlockStmt.NodeString = node.Child(i).Content(sourcecode)
blockStmt.Stmts = append(blockStmt.Stmts, *singleBlockStmt)
}
return blockStmt
}
80 changes: 80 additions & 0 deletions sourcecode-parser/graph/java/parse_statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,83 @@ func TestParseAssertStatement(t *testing.T) {
})
}
}

func TestParseBlockStatement(t *testing.T) {
tests := []struct {
name string
input string
expected *model.BlockStmt
}{
{
name: "Empty block statement",
input: "{}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "}"},
},
},
},
{
name: "Single statement block",
input: "{return true;}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "return true;"},
{NodeString: "}"},
},
},
},
{
name: "Multiple statement block",
input: "{int x = 1; x++; return x;}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "int x = 1;"},
{NodeString: "x++;"},
{NodeString: "return x;"},
{NodeString: "}"},
},
},
},
{
name: "Nested block statements",
input: "{{int x = 1;}{int y = 2;}}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "{int x = 1;}"},
{NodeString: "{int y = 2;}"},
{NodeString: "}"},
},
},
},
{
name: "Block with complex statements",
input: "{System.out.println(\"Hello\"); if(x > 0) { return true; } throw new Exception();}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "System.out.println(\"Hello\");"},
{NodeString: "if(x > 0) { return true; }"},
{NodeString: "throw new Exception();"},
{NodeString: "}"},
},
},
},
}

parser := sitter.NewParser()
parser.SetLanguage(java.GetLanguage())

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tree := parser.Parse(nil, []byte(tt.input))
node := tree.RootNode().Child(0)
result := ParseBlockStatement(node, []byte(tt.input))
assert.Equal(t, tt.expected, result)
})
}
}
11 changes: 11 additions & 0 deletions sourcecode-parser/graph/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@
return env.Node.ReturnStmt
}

func (env *Env) GetBlockStmt() *model.BlockStmt {
return env.Node.BlockStmt

Check warning on line 159 in sourcecode-parser/graph/query.go

View check run for this annotation

Codecov / codecov/patch

sourcecode-parser/graph/query.go#L158-L159

Added lines #L158 - L159 were not covered by tests
}

func QueryEntities(graph *CodeGraph, query parser.Query) (nodes [][]*Node, output [][]interface{}) {
result := make([][]*Node, 0)

Expand Down Expand Up @@ -335,6 +339,7 @@
yieldStmt := "YieldStmt"
assertStmt := "AssertStmt"
returnStmt := "ReturnStmt"
blockStmt := "BlockStmt"

// print query select list
for _, entity := range query.SelectList {
Expand Down Expand Up @@ -401,6 +406,8 @@
assertStmt = entity.Alias
case "ReturnStmt":
returnStmt = entity.Alias
case "BlockStmt":
blockStmt = entity.Alias

Check warning on line 410 in sourcecode-parser/graph/query.go

View check run for this annotation

Codecov / codecov/patch

sourcecode-parser/graph/query.go#L409-L410

Added lines #L409 - L410 were not covered by tests
}
}
env := map[string]interface{}{
Expand Down Expand Up @@ -567,6 +574,10 @@
"toString": proxyenv.ToString,
"getReturnStmt": proxyenv.GetReturnStmt,
},
blockStmt: map[string]interface{}{
"toString": proxyenv.ToString,
"getBlockStmt": proxyenv.GetBlockStmt,
},
}
return env
}
Expand Down
49 changes: 49 additions & 0 deletions sourcecode-parser/model/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,52 @@
func (returnStmt *ReturnStmt) GetResult() *Expr {
return returnStmt.Result
}

type BlockStmt struct {
Stmt
Stmts []Stmt
}

type IBlockStmt interface {
GetAPrimaryQlClass() string
GetHalsteadID() int
GetPP() string
ToString() string
GetStmt(index int) Stmt
GetAStmt() Stmt
GetNumStmt() int
GetLastStmt() Stmt
}

func (blockStmt *BlockStmt) GetAPrimaryQlClass() string {
return "BlockStmt"
}

func (blockStmt *BlockStmt) GetHalsteadID() int {
// TODO: Implement Halstead ID calculation for BlockStmt
return 0
}

func (blockStmt *BlockStmt) GetPP() string {
return fmt.Sprintf("block %s", blockStmt.Stmts)

Check warning on line 405 in sourcecode-parser/model/stmt.go

View check run for this annotation

Codecov / codecov/patch

sourcecode-parser/model/stmt.go#L404-L405

Added lines #L404 - L405 were not covered by tests
}

func (blockStmt *BlockStmt) ToString() string {
return fmt.Sprintf("block %s", blockStmt.Stmts)

Check warning on line 409 in sourcecode-parser/model/stmt.go

View check run for this annotation

Codecov / codecov/patch

sourcecode-parser/model/stmt.go#L408-L409

Added lines #L408 - L409 were not covered by tests
}

func (blockStmt *BlockStmt) GetStmt(index int) Stmt {
return blockStmt.Stmts[index]
}

func (blockStmt *BlockStmt) GetAStmt() Stmt {
return blockStmt.Stmts[0]
}

func (blockStmt *BlockStmt) GetNumStmt() int {
return len(blockStmt.Stmts)
}

func (blockStmt *BlockStmt) GetLastStmt() Stmt {
return blockStmt.Stmts[len(blockStmt.Stmts)-1]
}
58 changes: 58 additions & 0 deletions sourcecode-parser/model/stmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,61 @@ func TestReturnStmt_GetPP(t *testing.T) {
assert.Equal(t, "return x > 0 && y < 10", returnStmt.GetPP())
})
}

func TestBlockStmt(t *testing.T) {
t.Run("GetAPrimaryQlClass", func(t *testing.T) {
blockStmt := &BlockStmt{}
assert.Equal(t, "BlockStmt", blockStmt.GetAPrimaryQlClass())
})

t.Run("GetHalsteadID", func(t *testing.T) {
blockStmt := &BlockStmt{}
assert.Equal(t, 0, blockStmt.GetHalsteadID())
})

t.Run("GetStmt with valid index", func(t *testing.T) {
stmt1 := Stmt{NodeString: "x = 1"}
stmt2 := Stmt{NodeString: "y = 2"}
blockStmt := &BlockStmt{
Stmts: []Stmt{stmt1, stmt2},
}
assert.Equal(t, stmt2, blockStmt.GetStmt(1))
})

t.Run("GetAStmt with non-empty block", func(t *testing.T) {
stmt1 := Stmt{NodeString: "x = 1"}
stmt2 := Stmt{NodeString: "y = 2"}
blockStmt := &BlockStmt{
Stmts: []Stmt{stmt1, stmt2},
}
assert.Equal(t, stmt1, blockStmt.GetAStmt())
})

t.Run("GetNumStmt with multiple statements", func(t *testing.T) {
blockStmt := &BlockStmt{
Stmts: []Stmt{
{NodeString: "x = 1"},
{NodeString: "y = 2"},
{NodeString: "z = 3"},
},
}
assert.Equal(t, 3, blockStmt.GetNumStmt())
})

t.Run("GetNumStmt with empty block", func(t *testing.T) {
blockStmt := &BlockStmt{
Stmts: []Stmt{},
}
assert.Equal(t, 0, blockStmt.GetNumStmt())
})

t.Run("GetLastStmt with multiple statements", func(t *testing.T) {
stmt1 := Stmt{NodeString: "x = 1"}
stmt2 := Stmt{NodeString: "y = 2"}
stmt3 := Stmt{NodeString: "z = 3"}
blockStmt := &BlockStmt{
Stmts: []Stmt{stmt1, stmt2, stmt3},
}
assert.Equal(t, stmt3, blockStmt.GetLastStmt())
})
}
Loading