From aef7e33bb0755d974bc5fcc271e2293c35b6d619 Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Mon, 2 Feb 2026 12:57:48 +0530 Subject: [PATCH 1/4] Handle listeners without explicit type descriptors --- .../core/CodeAnalyzer.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/architecture-model-generator/modules/architecture-model-generator-core/src/main/java/io/ballerina/designmodelgenerator/core/CodeAnalyzer.java b/architecture-model-generator/modules/architecture-model-generator-core/src/main/java/io/ballerina/designmodelgenerator/core/CodeAnalyzer.java index 1857dd1148..2c254e7eed 100644 --- a/architecture-model-generator/modules/architecture-model-generator-core/src/main/java/io/ballerina/designmodelgenerator/core/CodeAnalyzer.java +++ b/architecture-model-generator/modules/architecture-model-generator-core/src/main/java/io/ballerina/designmodelgenerator/core/CodeAnalyzer.java @@ -347,25 +347,41 @@ public void visit(VariableDeclarationNode variableDeclarationNode) { @Override public void visit(ListenerDeclarationNode listenerDeclarationNode) { List arguments = new ArrayList<>(); - Optional symbol = semanticModel.symbol(listenerDeclarationNode.typeDescriptor().get()); + Optional typeSymbol; + String typeName; Node initializer = listenerDeclarationNode.initializer(); + + if (listenerDeclarationNode.typeDescriptor().isPresent()) { + Optional symbol = semanticModel.symbol(listenerDeclarationNode.typeDescriptor().get()); + typeSymbol = symbol.filter(s -> s instanceof TypeSymbol).map(s -> (TypeSymbol) s); + typeName = listenerDeclarationNode.typeDescriptor().get().toSourceCode().strip(); + } else if (initializer instanceof ExplicitNewExpressionNode explicitNewExpr) { + Optional symbol = semanticModel.symbol(explicitNewExpr.typeDescriptor()); + typeSymbol = symbol.filter(s -> s instanceof TypeSymbol).map(s -> (TypeSymbol) s); + typeName = explicitNewExpr.typeDescriptor().toSourceCode().strip(); + } else { + typeSymbol = semanticModel.typeOf(initializer); + typeName = typeSymbol.map(TypeSymbol::signature).orElse(""); + } + if (initializer instanceof NewExpressionNode newExpressionNode) { - if (symbol.isPresent() && symbol.get() instanceof TypeSymbol typeSymbol) { - TypeSymbol rawType = CommonUtils.getRawType(typeSymbol); + if (typeSymbol.isPresent()) { + TypeSymbol rawType = CommonUtils.getRawType(typeSymbol.get()); if (rawType instanceof ClassSymbol classSymbol) { arguments = getInitMethodParamNames(classSymbol, connectionFinder.getArgList(newExpressionNode)); } } } - String icon = symbol.flatMap(Symbol::getModule) + String icon = typeSymbol.flatMap(Symbol::getModule) .map(module -> CommonUtils.generateIcon(module.id())).orElse(""); LineRange lineRange = listenerDeclarationNode.lineRange(); String sortText = lineRange.fileName() + lineRange.startLine().line(); + this.intermediateModel.listeners.put(listenerDeclarationNode.variableName().text(), new Listener(listenerDeclarationNode.variableName().text(), sortText, getLocation(listenerDeclarationNode.lineRange()), - listenerDeclarationNode.typeDescriptor().get().toSourceCode().strip(), + typeName, icon, Listener.Kind.NAMED, arguments, true)); } From b56a0cd3e0dde0bb8e9449802d65e534e912bbf4 Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Mon, 2 Feb 2026 12:58:14 +0530 Subject: [PATCH 2/4] Add test coverage --- .../config/project_with_only_listener.json | 34 +++++++++++++++++++ .../source/project_8/Ballerina.toml | 4 +++ .../source/project_8/main.bal | 3 ++ 3 files changed, 41 insertions(+) create mode 100644 architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/config/project_with_only_listener.json create mode 100644 architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/Ballerina.toml create mode 100644 architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/main.bal diff --git a/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/config/project_with_only_listener.json b/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/config/project_with_only_listener.json new file mode 100644 index 0000000000..b27de74246 --- /dev/null +++ b/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/config/project_with_only_listener.json @@ -0,0 +1,34 @@ +{ + "description": "Project with only listener", + "projectPath": "project_8", + "output": { + "designModel": { + "connections": [], + "listeners": [ + { + "symbol": "list", + "location": { + "filePath": "/Users/pasindufernando/Desktop/BI/Ballerina-Language-Server/ballerina-language-server/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/main.bal", + "startLine": { + "line": 2, + "offset": 0 + }, + "endLine": { + "line": 2, + "offset": 40 + } + }, + "attachedServices": [], + "kind": "NAMED", + "type": "", + "args": [], + "icon": "", + "uuid": "4c5106b0-cf66-8fd0-6b50-9af851cd2896", + "enableFlowModel": true, + "sortText": "main.bal2" + } + ], + "services": [] + } + } +} diff --git a/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/Ballerina.toml b/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/Ballerina.toml new file mode 100644 index 0000000000..a3d0483ecb --- /dev/null +++ b/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/Ballerina.toml @@ -0,0 +1,4 @@ +[package] +org = "wso2" +name = "service" +version = "0.1.0" diff --git a/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/main.bal b/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/main.bal new file mode 100644 index 0000000000..79da7c56df --- /dev/null +++ b/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/source/project_8/main.bal @@ -0,0 +1,3 @@ +import ballerina/http; + +listener list = new http:Listener(8080); From 0825755cc40e84480ac9864800b244dc453f8850 Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Mon, 2 Feb 2026 13:33:20 +0530 Subject: [PATCH 3/4] Update test case --- .../config/project_with_only_listener.json | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/config/project_with_only_listener.json b/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/config/project_with_only_listener.json index b27de74246..12253f52dd 100644 --- a/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/config/project_with_only_listener.json +++ b/architecture-model-generator/modules/architecture-model-generator-ls-extension/src/test/resources/get_design_model/config/project_with_only_listener.json @@ -20,10 +20,15 @@ }, "attachedServices": [], "kind": "NAMED", - "type": "", - "args": [], - "icon": "", - "uuid": "4c5106b0-cf66-8fd0-6b50-9af851cd2896", + "type": "http:Listener", + "args": [ + { + "key": "port", + "value": "8080" + } + ], + "icon": "https://bcentral-packageicons.azureedge.net/images/ballerina_http_2.14.1.png", + "uuid": "PLACEHOLDER", "enableFlowModel": true, "sortText": "main.bal2" } From 54d8722f2e0ac5c5d215315c309f1e8cf653e9d9 Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Mon, 2 Feb 2026 13:37:42 +0530 Subject: [PATCH 4/4] Address PR suggestions --- .../designmodelgenerator/core/CodeAnalyzer.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/architecture-model-generator/modules/architecture-model-generator-core/src/main/java/io/ballerina/designmodelgenerator/core/CodeAnalyzer.java b/architecture-model-generator/modules/architecture-model-generator-core/src/main/java/io/ballerina/designmodelgenerator/core/CodeAnalyzer.java index 2c254e7eed..b31fb9b3fc 100644 --- a/architecture-model-generator/modules/architecture-model-generator-core/src/main/java/io/ballerina/designmodelgenerator/core/CodeAnalyzer.java +++ b/architecture-model-generator/modules/architecture-model-generator-core/src/main/java/io/ballerina/designmodelgenerator/core/CodeAnalyzer.java @@ -352,14 +352,17 @@ public void visit(ListenerDeclarationNode listenerDeclarationNode) { Node initializer = listenerDeclarationNode.initializer(); if (listenerDeclarationNode.typeDescriptor().isPresent()) { + // If explicit type descriptor is present, use it to get the type symbol and name Optional symbol = semanticModel.symbol(listenerDeclarationNode.typeDescriptor().get()); typeSymbol = symbol.filter(s -> s instanceof TypeSymbol).map(s -> (TypeSymbol) s); typeName = listenerDeclarationNode.typeDescriptor().get().toSourceCode().strip(); - } else if (initializer instanceof ExplicitNewExpressionNode explicitNewExpr) { - Optional symbol = semanticModel.symbol(explicitNewExpr.typeDescriptor()); + } else if (initializer instanceof ExplicitNewExpressionNode explicitNewExpressionNode) { + // If inferred type from explicit new expression + Optional symbol = semanticModel.symbol(explicitNewExpressionNode.typeDescriptor()); typeSymbol = symbol.filter(s -> s instanceof TypeSymbol).map(s -> (TypeSymbol) s); - typeName = explicitNewExpr.typeDescriptor().toSourceCode().strip(); + typeName = explicitNewExpressionNode.typeDescriptor().toSourceCode().strip(); } else { + // Fallback to getting the type from the initializer expression typeSymbol = semanticModel.typeOf(initializer); typeName = typeSymbol.map(TypeSymbol::signature).orElse(""); }