diff --git a/ast/src/lang/queries/angular.rs b/ast/src/lang/queries/angular.rs index 1d4986931..4e4053a5c 100644 --- a/ast/src/lang/queries/angular.rs +++ b/ast/src/lang/queries/angular.rs @@ -99,6 +99,7 @@ impl Stack for Angular { } fn variables_query(&self) -> Option { let types = "(string)(template_string)(number)(object)(array)(true)(false)(new_expression)"; + let field_types = "(string)(template_string)(number)(object)(array)(true)(false)(new_expression)(call_expression)"; Some(format!( r#"(program (export_statement @@ -142,7 +143,16 @@ impl Stack for Angular { value: [{types}]+ @{VARIABLE_VALUE} ) ) @{VARIABLE_DECLARATION} - + + ) + (class_declaration + (class_body + (public_field_definition + name: (property_identifier) @{VARIABLE_NAME} + type: (_)? @{VARIABLE_TYPE} + value: [{field_types}]+ @{VARIABLE_VALUE} + )@{VARIABLE_DECLARATION} + ) )"#, )) } diff --git a/ast/src/lang/queries/go.rs b/ast/src/lang/queries/go.rs index e9e3a1b97..18bf02367 100644 --- a/ast/src/lang/queries/go.rs +++ b/ast/src/lang/queries/go.rs @@ -185,6 +185,9 @@ impl Stack for Go { ] field: (field_identifier) @{FUNCTION_NAME} ) + (type_instantiation_expression + type: (type_identifier) @{FUNCTION_NAME} + ) ] arguments: (argument_list) @{ARGUMENTS} ) @{FUNCTION_CALL}" diff --git a/ast/src/lang/queries/java.rs b/ast/src/lang/queries/java.rs index e86f93df4..c985b7f0d 100644 --- a/ast/src/lang/queries/java.rs +++ b/ast/src/lang/queries/java.rs @@ -111,7 +111,7 @@ impl Stack for Java { r#" (class_declaration (identifier)@{CLASS_NAME} - (superclass + (superclass (type_identifier)@{CLASS_PARENT} )? (super_interfaces @@ -119,6 +119,11 @@ impl Stack for Java { (type_identifier)@{INCLUDED_MODULES} ) )? + (permits + (type_list + (type_identifier)@{INCLUDED_MODULES} + ) + )? )@{CLASS_DEFINITION} "# ) diff --git a/ast/src/testing/angular/src/app/add-person/add-person.component.ts b/ast/src/testing/angular/src/app/add-person/add-person.component.ts index a219d8728..eedf722f1 100644 --- a/ast/src/testing/angular/src/app/add-person/add-person.component.ts +++ b/ast/src/testing/angular/src/app/add-person/add-person.component.ts @@ -10,6 +10,7 @@ import { FormsModule } from '@angular/forms'; // @ast edge: Calls -> Request "this.router.navigate" "add-person.component.ts" // @ast node: Import "import-imports-srctestingangularsrcappaddpersonaddpersoncomponentts-0" // @ast node: Page "AddPersonComponent" +// @ast node: Var "name" @Component({ diff --git a/ast/src/testing/angular/src/app/app.component.ts b/ast/src/testing/angular/src/app/app.component.ts index 8f6905634..8d79a6d1f 100644 --- a/ast/src/testing/angular/src/app/app.component.ts +++ b/ast/src/testing/angular/src/app/app.component.ts @@ -3,6 +3,7 @@ import { RouterOutlet } from '@angular/router'; // @ast node: Class "AppComponent" // @ast node: Import "import-imports-srctestingangularsrcappappcomponentts-0" // @ast node: Page "AppComponent" +// @ast node: Var "title" @Component({ selector: 'app-root', diff --git a/ast/src/testing/angular/src/app/counter/counter.component.ts b/ast/src/testing/angular/src/app/counter/counter.component.ts new file mode 100644 index 000000000..6ccedcdf3 --- /dev/null +++ b/ast/src/testing/angular/src/app/counter/counter.component.ts @@ -0,0 +1,19 @@ +import { Component, signal, computed } from '@angular/core'; +// @ast node: Class "CounterComponent" +// @ast node: Var "count" +// @ast node: Var "doubled" +// @ast node: Function "increment" +// @ast node: Import "import-imports-srctestingangularsrcappcountercountercomponentts-0" + +@Component({ + selector: 'app-counter', + template: '

{{ count() }}

' +}) +export class CounterComponent { + count = signal(0); + doubled = computed(() => this.count() * 2); + + increment() { + this.count.set(this.count() + 1); + } +} diff --git a/ast/src/testing/angular/src/app/people-list/people-list.component.ts b/ast/src/testing/angular/src/app/people-list/people-list.component.ts index baa91c7ca..6fd3bacfc 100644 --- a/ast/src/testing/angular/src/app/people-list/people-list.component.ts +++ b/ast/src/testing/angular/src/app/people-list/people-list.component.ts @@ -11,6 +11,9 @@ import { CommonModule } from '@angular/common'; // @ast edge: Calls -> Request "this.personDeleted.emit" "people-list.component.ts" // @ast node: Import "import-imports-srctestingangularsrcapppeoplelistpeoplelistcomponentts-0" // @ast node: Page "PeopleListComponent" +// @ast node: Var "people" +// @ast node: Var "maxItems" +// @ast node: Var "personDeleted" diff --git a/ast/src/testing/angular/src/app/people.service.ts b/ast/src/testing/angular/src/app/people.service.ts index 893d06e26..d2a8bd498 100644 --- a/ast/src/testing/angular/src/app/people.service.ts +++ b/ast/src/testing/angular/src/app/people.service.ts @@ -16,6 +16,9 @@ import { Person } from './models/person.model'; // @ast edge: Calls -> Request "this.peopleSubject.next" "people.service.ts" // @ast node: Function "getPeople" // @ast node: Import "import-imports-srctestingangularsrcapppeopleservicets-2" +// @ast node: Var "peopleSubject" +// @ast node: Var "people$" +// @ast node: Var "people" function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; diff --git a/ast/src/testing/coverage/go.rs b/ast/src/testing/coverage/go.rs index 43a3bfb07..f9325c815 100644 --- a/ast/src/testing/coverage/go.rs +++ b/ast/src/testing/coverage/go.rs @@ -71,7 +71,7 @@ async fn test_btreemap_graph_structure() -> Result<()> { assert_eq!(endpoints.len(), 5); let functions = graph.find_nodes_by_type(NodeType::Function); - assert_eq!(functions.len(), 37); + assert_eq!(functions.len(), 38); let unit_tests = graph.find_nodes_by_type(NodeType::UnitTest); assert_eq!(unit_tests.len(), 2); @@ -108,10 +108,10 @@ async fn test_btreemap_test_to_function_edges() -> Result<()> { let graph = repo.build_graph_inner::().await?; let calls_edges = graph.count_edges_of_type(EdgeType::Calls); - assert_eq!(calls_edges, 19); + assert_eq!(calls_edges, 20); let contains_edges = graph.count_edges_of_type(EdgeType::Contains); - assert_eq!(contains_edges, 128); + assert_eq!(contains_edges, 129); let handler_edges = graph.count_edges_of_type(EdgeType::Handler); assert_eq!(handler_edges, 5); diff --git a/ast/src/testing/coverage/java.rs b/ast/src/testing/coverage/java.rs index 3f4edc801..7c6ee159c 100644 --- a/ast/src/testing/coverage/java.rs +++ b/ast/src/testing/coverage/java.rs @@ -83,7 +83,7 @@ async fn test_btreemap_graph_structure() -> Result<()> { assert_eq!(e2e_tests.len(), 0); let classes = graph.find_nodes_by_type(NodeType::Class); - assert_eq!(classes.len(), 18); + assert_eq!(classes.len(), 20); let data_models = graph.find_nodes_by_type(NodeType::DataModel); assert_eq!(data_models.len(), 2); @@ -111,7 +111,7 @@ async fn test_btreemap_test_to_function_edges() -> Result<()> { assert_eq!(calls_edges, 35); let contains_edges = graph.count_edges_of_type(EdgeType::Contains); - assert_eq!(contains_edges, 247); + assert_eq!(contains_edges, 252); let handler_edges = graph.count_edges_of_type(EdgeType::Handler); assert_eq!(handler_edges, 11); diff --git a/ast/src/testing/go/generics.go b/ast/src/testing/go/generics.go index f7122263a..3aa5b78bb 100644 --- a/ast/src/testing/go/generics.go +++ b/ast/src/testing/go/generics.go @@ -7,6 +7,8 @@ package main // @ast node: Function "Push" // @ast node: Function "Pop" // @ast node: Function "Map" +// @ast node: Function "UseMap" +// @ast edge: Calls -> Function "Map" "generics.go" // Stack is a generic stack implementation type Stack[T any] struct { @@ -37,3 +39,9 @@ func Map[T any, U any](input []T, f func(T) U) []U { } return result } + +// UseMap calls Map with an explicit type instantiation. +func UseMap() []string { + nums := []int{1, 2, 3} + return Map[int, string](nums, func(n int) string { return "" }) +} diff --git a/ast/src/testing/java/src/main/java/graph/stakgraph/java/nonweb/Shape.java b/ast/src/testing/java/src/main/java/graph/stakgraph/java/nonweb/Shape.java new file mode 100644 index 000000000..b011db84c --- /dev/null +++ b/ast/src/testing/java/src/main/java/graph/stakgraph/java/nonweb/Shape.java @@ -0,0 +1,12 @@ +// @ast node: Class "Shape" +// @ast edge: Imports -> Class "Circle" "Shape.java" +// @ast node: Class "Circle" +// @ast node: Var "radius" +package graph.stakgraph.java.nonweb; + +public sealed class Shape permits Circle { +} + +final class Circle extends Shape { + double radius; +} diff --git a/cli/tests/cli/angular.rs b/cli/tests/cli/angular.rs index 9b2f624ca..4db1505de 100644 --- a/cli/tests/cli/angular.rs +++ b/cli/tests/cli/angular.rs @@ -34,8 +34,8 @@ fn parse_stats_angular_dir() { assert_eq!(out.exit_code, 0, "stderr: {}", out.stderr); assert!(out.stdout.contains("Endpoint 1"), "stdout: {}", out.stdout); - assert!(out.stdout.contains("Function 13"), "stdout: {}", out.stdout); - assert!(out.stdout.contains("Class 5"), "stdout: {}", out.stdout); + assert!(out.stdout.contains("Function 14"), "stdout: {}", out.stdout); + assert!(out.stdout.contains("Class 6"), "stdout: {}", out.stdout); assert!(out.stdout.contains("UnitTest 4"), "stdout: {}", out.stdout); } diff --git a/cli/tests/cli/java.rs b/cli/tests/cli/java.rs index 88abdcb32..23b5086a1 100644 --- a/cli/tests/cli/java.rs +++ b/cli/tests/cli/java.rs @@ -40,8 +40,8 @@ fn parse_stats_java_dir() { let out = run_stakgraph(&["--stats", &dir]); assert_eq!(out.exit_code, 0, "stderr: {}", out.stderr); - assert!(out.stdout.contains("Class 13"), "stdout: {}", out.stdout); - assert!(out.stdout.contains("Import 17"), "stdout: {}", out.stdout); + assert!(out.stdout.contains("Class 15"), "stdout: {}", out.stdout); + assert!(out.stdout.contains("Import 18"), "stdout: {}", out.stdout); } // ── search ────────────────────────────────────────────────────────────────────