From a6538fc821a7a3e2f94e46577453e4c3af42e7d4 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Wed, 31 May 2023 06:29:09 +0530 Subject: [PATCH 01/24] Fix no warning in deprecated field-name --- .../semantics/analyzer/CodeAnalyzer.java | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 4b2d41e23a0a..e8722bd61668 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -31,6 +31,7 @@ import org.ballerinalang.model.tree.expressions.XMLNavigationAccess; import org.ballerinalang.model.tree.statements.StatementNode; import org.ballerinalang.model.tree.statements.VariableDefinitionNode; +import org.ballerinalang.model.types.TypeKind; import org.ballerinalang.util.diagnostic.DiagnosticErrorCode; import org.ballerinalang.util.diagnostic.DiagnosticHintCode; import org.ballerinalang.util.diagnostic.DiagnosticWarningCode; @@ -2228,11 +2229,57 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { for (RecordLiteralNode.RecordField field : fields) { if (field.isKeyValueField()) { + BVarSymbol fieldSymbol = ((BLangRecordKeyValueField) field).key.fieldSymbol; + analyzeExpr(((BLangRecordKeyValueField) field).valueExpr, data); + + if (fieldSymbol != null && Symbols.isFlagOn(fieldSymbol.flags, Flags.DEPRECATED)) { + String deprecatedConstruct = generateDeprecatedConstructString(recordLiteral, + fieldSymbol.toString(), fieldSymbol); + dlog.warning(((BLangRecordKeyValueField) field).pos, + DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, deprecatedConstruct); + } } else if (field.getKind() == NodeKind.SIMPLE_VARIABLE_REF) { - analyzeExpr((BLangRecordLiteral.BLangRecordVarNameField) field, data); + BLangRecordLiteral.BLangRecordVarNameField recField + = (BLangRecordLiteral.BLangRecordVarNameField) field; + analyzeExpr(recField, data); + + if (recordLiteral.getBType().tsymbol != null + && recordLiteral.getBType().tsymbol.type.getKind() == TypeKind.RECORD) { + + BRecordType recordType = (BRecordType) recordLiteral.getBType().tsymbol.type; + BField matchingField = recordType.getFields().get(recField.symbol.getName().getValue()); + + if (matchingField != null && Symbols.isFlagOn(matchingField.symbol.flags, Flags.DEPRECATED)) { + String deprecatedConstruct = generateDeprecatedConstructString(recordLiteral, + matchingField.name.getValue(), matchingField.symbol); + dlog.warning(((BLangRecordLiteral.BLangRecordVarNameField) field).pos, + DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, deprecatedConstruct); + } + } } else { - analyzeExpr(((BLangRecordLiteral.BLangRecordSpreadOperatorField) field).expr, data); + BLangRecordLiteral.BLangRecordSpreadOperatorField spreadField + = (BLangRecordLiteral.BLangRecordSpreadOperatorField) field; + analyzeExpr(spreadField.expr, data); + + BType spreadFieldType = Types.getReferredType(spreadField.expr.getBType()); + BType contextType = Types.getReferredType(recordLiteral.getBType()); + + if (spreadFieldType != null && spreadFieldType.getKind() == TypeKind.RECORD + && contextType.getKind() == TypeKind.RECORD) { + for (BField fieldEntry: ((BRecordType) spreadFieldType).getFields().values()) { + BRecordType recordType = (BRecordType) contextType; + BField matchingField = recordType.getFields().get(fieldEntry.getName().getValue()); + + if (matchingField != null && Symbols.isFlagOn(matchingField.symbol.flags, Flags.DEPRECATED)) { + String deprecatedConstruct = generateDeprecatedConstructString(recordLiteral, + matchingField.name.getValue(), matchingField.symbol); + dlog.warning(spreadField.expr.pos, + DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, deprecatedConstruct); + } + } + } + } } From 5ca75c720a38269f26e6b356036d9d76dd375e12 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Wed, 31 May 2023 06:29:31 +0530 Subject: [PATCH 02/24] Add tests --- .../test/annotations/DeprecationAnnotationTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java index 9118b6c9c291..48702359603b 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java @@ -86,15 +86,25 @@ public void testDeprecationAnnotation() { BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Person.name' is deprecated", 287, 16); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Person.getName' is deprecated", 288, 16); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'myFunction' is deprecated", 298, 5); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.name' is deprecated", 316, 26); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.job' is deprecated", 316, 49); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experiance' is deprecated", 316, 68); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.name' is deprecated", 317, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.job' is deprecated", 319, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.job' is deprecated", 320, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.job' is deprecated", 321, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experiance' is deprecated", 321, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee2.name' is deprecated", 343, 28); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee2.job' is deprecated", 343, 51); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experiance' is deprecated", 343, 70); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee2.name' is deprecated", 344, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee2.job' is deprecated", 346, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 354, 17); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 357, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 370, 17); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 373, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee5.address' is deprecated", + 393, 28); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee5.address' is deprecated", 394, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee5.address' is deprecated", From 9d1530cc39e99e71202bbf38b7d488ca8689ef5c Mon Sep 17 00:00:00 2001 From: Dulaj Date: Tue, 6 Jun 2023 10:20:54 +0530 Subject: [PATCH 03/24] Fix naming grammar --- .../test/annotations/DeprecationAnnotationTest.java | 6 +++--- .../test-src/annotations/deprecation_annotation.bal | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java index 48702359603b..034e974debf8 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java @@ -88,15 +88,15 @@ public void testDeprecationAnnotation() { BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'myFunction' is deprecated", 298, 5); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.name' is deprecated", 316, 26); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.job' is deprecated", 316, 49); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experiance' is deprecated", 316, 68); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 316, 68); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.name' is deprecated", 317, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.job' is deprecated", 319, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.job' is deprecated", 320, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee.job' is deprecated", 321, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experiance' is deprecated", 321, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 321, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee2.name' is deprecated", 343, 28); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee2.job' is deprecated", 343, 51); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experiance' is deprecated", 343, 70); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 343, 70); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee2.name' is deprecated", 344, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee2.job' is deprecated", 346, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 354, 17); diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal index da78250773c1..fdf6aed0999a 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal @@ -309,16 +309,16 @@ type Employee record {| type Job record {| string title; @deprecated - int experiance; + int experience; |}; public function testDeprecatedRecordFields() { - Employee employee = {name: "John", id: 112, job: {title: "SE", experiance: 2}}; + Employee employee = {name: "John", id: 112, job: {title: "SE", experience: 2}}; _ = employee.name; // warning _ = employee.id; _ = employee.job; // warning _ = employee.job.title; // warning - _ = employee.job.experiance; // warning + _ = employee.job.experience; // warning } # Employee2 record @@ -340,7 +340,7 @@ type Employee2 record {| |}; public function testDeprecatedRecordFieldsWithDocumentation() { - Employee2 employee2 = {name: "John", id: 112, job: {title: "SE", experiance: 2}}; + Employee2 employee2 = {name: "John", id: 112, job: {title: "SE", experience: 2}}; _ = employee2.name; // warning _ = employee2.id; _ = employee2.job; // warning From c1aae3e6fbcf54345425daf670e535577b7adaf7 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Tue, 6 Jun 2023 10:42:27 +0530 Subject: [PATCH 04/24] Add more tests --- .../test/annotations/DeprecationAnnotationTest.java | 4 ++++ .../test-src/annotations/deprecation_annotation.bal | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java index 034e974debf8..8506c91500dd 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java @@ -110,6 +110,10 @@ public void testDeprecationAnnotation() { BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee5.address' is deprecated", 395, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'line02' is deprecated", 395, 9); + BAssertUtil.validateWarning(compileResult, i++, "unused variable 'job1'", 400, 5); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 400, 30); + BAssertUtil.validateWarning(compileResult, i++, "unused variable 'job2'", 403, 5); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 403, 33); Assert.assertEquals(compileResult.getWarnCount(), i); } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal index fdf6aed0999a..a7becc596c7b 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal @@ -394,3 +394,11 @@ public function testDeprecatedAnonStructAsStructField() { _ = employee5.address; // warning _ = employee5.address.line02; // warning } + +public function testDeprecatedAnonRecordFieldWithVarRef() { + int experience = 2; + Job job1 = {title: "SE", experience}; // warning + + var details = {experience: 1}; + Job job2 = {title: "SE", ...details}; // warning +} From 9585a240bc67b9f34f7f5caff2a586e68c947e00 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Tue, 4 Jul 2023 07:37:36 +0530 Subject: [PATCH 05/24] Improve tests --- .../DeprecationAnnotationTest.java | 11 +++-- .../annotations/deprecation_annotation.bal | 41 +++++++++++++++++-- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java index 8506c91500dd..04833ef6b10f 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java @@ -110,10 +110,13 @@ public void testDeprecationAnnotation() { BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Employee5.address' is deprecated", 395, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'line02' is deprecated", 395, 9); - BAssertUtil.validateWarning(compileResult, i++, "unused variable 'job1'", 400, 5); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 400, 30); - BAssertUtil.validateWarning(compileResult, i++, "unused variable 'job2'", 403, 5); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 403, 33); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 414, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 420, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 426, 12); + + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.name' is deprecated", 433, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.city' is deprecated", 434, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.country' is deprecated", 435, 12); Assert.assertEquals(compileResult.getWarnCount(), i); } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal index a7becc596c7b..68e00c7316c8 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal @@ -395,10 +395,43 @@ public function testDeprecatedAnonStructAsStructField() { _ = employee5.address.line02; // warning } -public function testDeprecatedAnonRecordFieldWithVarRef() { +type Company record { + int companyId; + + @deprecated + string name; + + @deprecated + string city; + + @deprecated + string country; +}; + +public function testDeprecatedAnonRecordFieldInInitialization() { + Job _ = { + title: "SE", + experience: 1 // warning + }; + int experience = 2; - Job job1 = {title: "SE", experience}; // warning + Job _ = { + title: "SE", + experience // warning + }; - var details = {experience: 1}; - Job job2 = {title: "SE", ...details}; // warning + var details = {experience: 2}; + Job _ = { + title: "SE", + ...details // warning + }; + + string city = "Berlin"; + var companyDetails = {country: "Germany"}; + Company _ = { + companyId: 1, + name: "Foo", // warning + city: city, // warning + ...companyDetails // warning + }; } From 621b44be08bbf649b95054284980dda3e7ee933e Mon Sep 17 00:00:00 2001 From: Dulaj Date: Fri, 14 Jul 2023 11:18:12 +0530 Subject: [PATCH 06/24] Extract deprecate warning to a method --- .../semantics/analyzer/CodeAnalyzer.java | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 86945d41b183..1613cb8414fb 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2234,35 +2234,31 @@ public void visit(BLangTableConstructorExpr tableConstructorExpr, AnalyzerData d @Override public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { List fields = recordLiteral.fields; + BType recLiteralType = recordLiteral.getBType(); for (RecordLiteralNode.RecordField field : fields) { if (field.isKeyValueField()) { - BVarSymbol fieldSymbol = ((BLangRecordKeyValueField) field).key.fieldSymbol; - analyzeExpr(((BLangRecordKeyValueField) field).valueExpr, data); - if (fieldSymbol != null && Symbols.isFlagOn(fieldSymbol.flags, Flags.DEPRECATED)) { - String deprecatedConstruct = generateDeprecatedConstructString(recordLiteral, - fieldSymbol.toString(), fieldSymbol); - dlog.warning(((BLangRecordKeyValueField) field).pos, - DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, deprecatedConstruct); + BVarSymbol fieldSymbol = ((BLangRecordKeyValueField) field).key.fieldSymbol; + if (fieldSymbol != null) { + reportIfDeprecatedUsage(fieldSymbol, fieldSymbol.toString(), + recordLiteral, ((BLangRecordKeyValueField) field).pos); } } else if (field.getKind() == NodeKind.SIMPLE_VARIABLE_REF) { BLangRecordLiteral.BLangRecordVarNameField recField = (BLangRecordLiteral.BLangRecordVarNameField) field; analyzeExpr(recField, data); - if (recordLiteral.getBType().tsymbol != null - && recordLiteral.getBType().tsymbol.type.getKind() == TypeKind.RECORD) { + if (recLiteralType.tsymbol != null && recLiteralType.tsymbol.type != null + && recLiteralType.tsymbol.type.getKind() == TypeKind.RECORD) { - BRecordType recordType = (BRecordType) recordLiteral.getBType().tsymbol.type; + BRecordType recordType = (BRecordType) recLiteralType.tsymbol.type; BField matchingField = recordType.getFields().get(recField.symbol.getName().getValue()); - if (matchingField != null && Symbols.isFlagOn(matchingField.symbol.flags, Flags.DEPRECATED)) { - String deprecatedConstruct = generateDeprecatedConstructString(recordLiteral, - matchingField.name.getValue(), matchingField.symbol); - dlog.warning(((BLangRecordLiteral.BLangRecordVarNameField) field).pos, - DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, deprecatedConstruct); + if (matchingField != null && matchingField.symbol != null) { + reportIfDeprecatedUsage(matchingField.symbol, matchingField.name.getValue(), + recordLiteral, ((BLangRecordLiteral.BLangRecordVarNameField) field).pos); } } } else { @@ -2271,7 +2267,7 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { analyzeExpr(spreadField.expr, data); BType spreadFieldType = Types.getReferredType(spreadField.expr.getBType()); - BType contextType = Types.getReferredType(recordLiteral.getBType()); + BType contextType = Types.getReferredType(recLiteralType); if (spreadFieldType != null && spreadFieldType.getKind() == TypeKind.RECORD && contextType.getKind() == TypeKind.RECORD) { @@ -2279,22 +2275,18 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { BRecordType recordType = (BRecordType) contextType; BField matchingField = recordType.getFields().get(fieldEntry.getName().getValue()); - if (matchingField != null && Symbols.isFlagOn(matchingField.symbol.flags, Flags.DEPRECATED)) { - String deprecatedConstruct = generateDeprecatedConstructString(recordLiteral, - matchingField.name.getValue(), matchingField.symbol); - dlog.warning(spreadField.expr.pos, - DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, deprecatedConstruct); + if (matchingField != null && matchingField.symbol != null) { + reportIfDeprecatedUsage(matchingField.symbol, matchingField.name.getValue(), + recordLiteral, spreadField.expr.pos); } } } - } } Set names = new HashSet<>(); Set neverTypedKeys = new HashSet<>(); - BType literalBType = recordLiteral.getBType(); - BType type = Types.getReferredType(literalBType); + BType type = Types.getReferredType(recLiteralType); boolean isRecord = type.tag == TypeTags.RECORD; boolean isOpenRecord = isRecord && !((BRecordType) type).sealed; @@ -3972,6 +3964,16 @@ private BType getErrorTypes(BType bType) { return errorType; } + private void reportIfDeprecatedUsage(BSymbol constructSymbol, + String constructName, + BLangExpression expr, + Location usagePos) { + if (Symbols.isFlagOn(constructSymbol.flags, Flags.DEPRECATED)) { + dlog.warning(usagePos, DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, + generateDeprecatedConstructString(expr, constructName, constructSymbol)); + } + } + /** * This class contains the state machines for a set of workers. */ From a20ca5d6695aaba25a467f72189fca02922e35f7 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Fri, 14 Jul 2023 13:40:39 +0530 Subject: [PATCH 07/24] Implement deprecated usage warnings for func params --- .../semantics/analyzer/CodeAnalyzer.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 1613cb8414fb..d6c4c822b03e 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2535,6 +2535,7 @@ public void visit(BLangInvocation invocationExpr, AnalyzerData data) { logDeprecatedWarningForInvocation(invocationExpr); } } + analyzeInvocationParams(invocationExpr, data); } @Override @@ -3914,6 +3915,107 @@ private boolean checkReturnValidityInTransaction(AnalyzerData data) { && data.withinTransactionScope; } + private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { + if (iExpr.symbol == null) { + return; + } + + BType invocableType = Types.getReferredType(iExpr.symbol.type); + if (invocableType.tag != TypeTags.INVOKABLE) { + return; + } + + BInvokableSymbol invokableSymbol = ((BInvokableSymbol) iExpr.symbol); + + List nonRestParams = new ArrayList<>(invokableSymbol.params); + List incRecordParams = new ArrayList<>(); + + getIncRecordFields(iExpr, nonRestParams, incRecordParams); + + List paramTypes = ((BInvokableType) invocableType).getParameterTypes(); + int parameterCountForPositionalArgs = paramTypes.size(); + int parameterCountForNamedArgs = parameterCountForPositionalArgs + incRecordParams.size(); + for (BVarSymbol symbol : nonRestParams) { + if (!Symbols.isFlagOn(Flags.asMask(symbol.getFlags()), Flags.INCLUDED) || + Types.getReferredType(symbol.type).tag != TypeTags.RECORD) { + continue; + } + LinkedHashMap fields = + ((BRecordType) Types.getReferredType(symbol.type)).fields; + if (fields.isEmpty()) { + continue; + } + for (String field : fields.keySet()) { + if (Types.getReferredType(fields.get(field).type).tag != TypeTags.NEVER) { + parameterCountForNamedArgs = parameterCountForNamedArgs - 1; + break; + } + } + } + + int i = 0; + boolean foundNamedArg = false; + for (BLangExpression expr : iExpr.argExprs) { + switch (expr.getKind()) { + case NAMED_ARGS_EXPR: + foundNamedArg = true; + BLangNamedArgsExpression namedArgsExpression = (BLangNamedArgsExpression) expr; + if (namedArgsExpression.varSymbol != null + && Symbols.isFlagOn(namedArgsExpression.varSymbol.flags, Flags.DEPRECATED)) { + String deprecatedConstruct = generateDeprecatedConstructString(expr, + namedArgsExpression.varSymbol.toString(), namedArgsExpression.varSymbol); + dlog.warning(expr.pos, DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, + deprecatedConstruct); + } + i++; + break; + case REST_ARGS_EXPR: + if (foundNamedArg) { + continue; + } + analyzeExpr(expr, data); + break; + default: // positional args + if (foundNamedArg) { + continue; + } + if (i < parameterCountForPositionalArgs) { + BVarSymbol paramSymbol = invokableSymbol.params.get(i); + if (Symbols.isFlagOn(invokableSymbol.params.get(i).flags, Flags.INCLUDED)) { + analyzeExpr(expr, data); + } + else if (Symbols.isFlagOn(paramSymbol.flags, Flags.DEPRECATED)) { + String deprecatedConstruct = generateDeprecatedConstructString(expr, + paramSymbol.toString(), paramSymbol); + dlog.warning(expr.pos, DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, + deprecatedConstruct); + } + } + i++; + + } + } + } + + private void getIncRecordFields(BLangInvocation iExpr, List nonRestParams, List incRecordParams) { + if (iExpr.argExprs.size() > 0) { + return; + } + + for (BVarSymbol param : nonRestParams) { + BType paramType = Types.getReferredType(param.type); + if (!Symbols.isFlagOn(Flags.asMask(param.getFlags()), Flags.INCLUDED) || + paramType.getKind() != TypeKind.RECORD) { + continue; + } + for (BField field: ((BRecordType) paramType).fields.values()) { + if (field.symbol.type.tag != TypeTags.NEVER) { + incRecordParams.add(field.symbol); + } + } + } + } + private void validateModuleInitFunction(BLangFunction funcNode) { if (funcNode.attachedFunction || !Names.USER_DEFINED_INIT_SUFFIX.value.equals(funcNode.name.value)) { return; From f8469b7c945e7a22d8ad54274c596cfebd8852b0 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Fri, 14 Jul 2023 13:40:49 +0530 Subject: [PATCH 08/24] Add more tests --- .../DeprecationAnnotationTest.java | 16 ++++++++++- .../annotations/deprecation_annotation.bal | 27 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java index 04833ef6b10f..9c20f8ac5890 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java @@ -67,7 +67,13 @@ public void testDeprecationAnnotation() { BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Object3.fieldOne' is deprecated", 194, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Object3.t' is deprecated", 195, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'add1' is deprecated", 200, 13); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x' is deprecated", 200, 18); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y' is deprecated", 200, 21); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'z' is deprecated", 200, 24); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'add2' is deprecated", 201, 13); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x' is deprecated", 201, 18); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y' is deprecated", 201, 21); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'z' is deprecated", 201, 24); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Object1' is deprecated", 202, 5); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'z' is deprecated", 213, 13); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Foo' is deprecated", 216, 38); @@ -113,10 +119,18 @@ public void testDeprecationAnnotation() { BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 414, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 420, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Job.experience' is deprecated", 426, 12); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.name' is deprecated", 433, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.city' is deprecated", 434, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.country' is deprecated", 435, 12); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 446, 15); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 447, 15); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 448, 20); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.city' is deprecated", 451, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.country' is deprecated", 452, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.name' is deprecated", 453, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'city' is deprecated", 458, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'country' is deprecated", 459, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 460, 9); Assert.assertEquals(compileResult.getWarnCount(), i); } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal index 68e00c7316c8..360c6314f9b9 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal @@ -390,7 +390,7 @@ type Employee5 record { }; public function testDeprecatedAnonStructAsStructField() { - Employee5 employee5 = {address: {}}; + Employee5 employee5 = {address: {}}; // warning _ = employee5.address; // warning _ = employee5.address.line02; // warning } @@ -435,3 +435,28 @@ public function testDeprecatedAnonRecordFieldInInitialization() { ...companyDetails // warning }; } + +function fooFn(int x1, @deprecated int x2){ +} + +function barFn(string s, *Company company) { +} + +public function testDeprecatedParamUsages() { + fooFn(10, 11); + fooFn(12, x2 = 13); + fooFn(x1 = 14, x2 = 15); + barFn("bar", { + companyId: 1, + city: "Berlin", // Warning + country: "Germany", // Warning + name: "Bar" // Warning + }); + barFn( + "bar", + companyId = 1, + city = "Berlin", // Warning + country = "Germany", // Warning + name = "Bar" // Warning + ); +} From a05e734aa51643793cd46452fea92b406f11de9c Mon Sep 17 00:00:00 2001 From: Dulaj Date: Fri, 14 Jul 2023 17:31:12 +0530 Subject: [PATCH 09/24] Improve deprecate warning logic --- .../semantics/analyzer/CodeAnalyzer.java | 70 +++---------------- 1 file changed, 9 insertions(+), 61 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index d6c4c822b03e..a8b385ee81c0 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2504,10 +2504,8 @@ private void analyzeFieldBasedAccessExpr(BLangFieldBasedAccess fieldAccessExpr, BLangExpression expr = fieldAccessExpr.expr; analyzeExpr(expr, data); BSymbol symbol = fieldAccessExpr.symbol; - if (symbol != null && Symbols.isFlagOn(fieldAccessExpr.symbol.flags, Flags.DEPRECATED)) { - String deprecatedConstruct = generateDeprecatedConstructString(expr, fieldAccessExpr.field.toString(), - symbol); - dlog.warning(fieldAccessExpr.pos, DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, deprecatedConstruct); + if (symbol != null) { + reportIfDeprecatedUsage(symbol, fieldAccessExpr.field.toString(), expr, fieldAccessExpr.pos); } } @@ -3926,32 +3924,7 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { } BInvokableSymbol invokableSymbol = ((BInvokableSymbol) iExpr.symbol); - - List nonRestParams = new ArrayList<>(invokableSymbol.params); - List incRecordParams = new ArrayList<>(); - - getIncRecordFields(iExpr, nonRestParams, incRecordParams); - - List paramTypes = ((BInvokableType) invocableType).getParameterTypes(); - int parameterCountForPositionalArgs = paramTypes.size(); - int parameterCountForNamedArgs = parameterCountForPositionalArgs + incRecordParams.size(); - for (BVarSymbol symbol : nonRestParams) { - if (!Symbols.isFlagOn(Flags.asMask(symbol.getFlags()), Flags.INCLUDED) || - Types.getReferredType(symbol.type).tag != TypeTags.RECORD) { - continue; - } - LinkedHashMap fields = - ((BRecordType) Types.getReferredType(symbol.type)).fields; - if (fields.isEmpty()) { - continue; - } - for (String field : fields.keySet()) { - if (Types.getReferredType(fields.get(field).type).tag != TypeTags.NEVER) { - parameterCountForNamedArgs = parameterCountForNamedArgs - 1; - break; - } - } - } + int parameterCountForPositionalArgs = ((BInvokableType) invocableType).getParameterTypes().size(); int i = 0; boolean foundNamedArg = false; @@ -3960,12 +3933,9 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { case NAMED_ARGS_EXPR: foundNamedArg = true; BLangNamedArgsExpression namedArgsExpression = (BLangNamedArgsExpression) expr; - if (namedArgsExpression.varSymbol != null - && Symbols.isFlagOn(namedArgsExpression.varSymbol.flags, Flags.DEPRECATED)) { - String deprecatedConstruct = generateDeprecatedConstructString(expr, - namedArgsExpression.varSymbol.toString(), namedArgsExpression.varSymbol); - dlog.warning(expr.pos, DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, - deprecatedConstruct); + if (namedArgsExpression.varSymbol != null) { + reportIfDeprecatedUsage(namedArgsExpression.varSymbol, namedArgsExpression.varSymbol.toString(), + expr, expr.pos); } i++; break; @@ -3981,15 +3951,12 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { } if (i < parameterCountForPositionalArgs) { BVarSymbol paramSymbol = invokableSymbol.params.get(i); + if (paramSymbol != null && Symbols.isFlagOn(paramSymbol.flags, Flags.DEPRECATED)) { + logDeprecatedWaring(paramSymbol.toString(), paramSymbol, expr.pos); + } if (Symbols.isFlagOn(invokableSymbol.params.get(i).flags, Flags.INCLUDED)) { analyzeExpr(expr, data); } - else if (Symbols.isFlagOn(paramSymbol.flags, Flags.DEPRECATED)) { - String deprecatedConstruct = generateDeprecatedConstructString(expr, - paramSymbol.toString(), paramSymbol); - dlog.warning(expr.pos, DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, - deprecatedConstruct); - } } i++; @@ -3997,25 +3964,6 @@ else if (Symbols.isFlagOn(paramSymbol.flags, Flags.DEPRECATED)) { } } - private void getIncRecordFields(BLangInvocation iExpr, List nonRestParams, List incRecordParams) { - if (iExpr.argExprs.size() > 0) { - return; - } - - for (BVarSymbol param : nonRestParams) { - BType paramType = Types.getReferredType(param.type); - if (!Symbols.isFlagOn(Flags.asMask(param.getFlags()), Flags.INCLUDED) || - paramType.getKind() != TypeKind.RECORD) { - continue; - } - for (BField field: ((BRecordType) paramType).fields.values()) { - if (field.symbol.type.tag != TypeTags.NEVER) { - incRecordParams.add(field.symbol); - } - } - } - } - private void validateModuleInitFunction(BLangFunction funcNode) { if (funcNode.attachedFunction || !Names.USER_DEFINED_INIT_SUFFIX.value.equals(funcNode.name.value)) { return; From 4eda95cea8541115d3b1929b51a05723f135768f Mon Sep 17 00:00:00 2001 From: Dulaj Date: Wed, 26 Jul 2023 12:16:30 +0530 Subject: [PATCH 10/24] Use referred type and refactor Extract symbol's null check within the report-deprecated method --- .../semantics/analyzer/CodeAnalyzer.java | 73 ++++++------------- 1 file changed, 22 insertions(+), 51 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index a8b385ee81c0..d9c8d2c66f39 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2233,33 +2233,24 @@ public void visit(BLangTableConstructorExpr tableConstructorExpr, AnalyzerData d @Override public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { + BType referredType = Types.getReferredType(recordLiteral.getBType()); List fields = recordLiteral.fields; - BType recLiteralType = recordLiteral.getBType(); for (RecordLiteralNode.RecordField field : fields) { if (field.isKeyValueField()) { analyzeExpr(((BLangRecordKeyValueField) field).valueExpr, data); - - BVarSymbol fieldSymbol = ((BLangRecordKeyValueField) field).key.fieldSymbol; - if (fieldSymbol != null) { - reportIfDeprecatedUsage(fieldSymbol, fieldSymbol.toString(), - recordLiteral, ((BLangRecordKeyValueField) field).pos); - } + reportIfDeprecatedUsage(((BLangRecordKeyValueField) field).key.fieldSymbol, recordLiteral, + ((BLangRecordKeyValueField) field).pos); } else if (field.getKind() == NodeKind.SIMPLE_VARIABLE_REF) { BLangRecordLiteral.BLangRecordVarNameField recField = (BLangRecordLiteral.BLangRecordVarNameField) field; analyzeExpr(recField, data); - if (recLiteralType.tsymbol != null && recLiteralType.tsymbol.type != null - && recLiteralType.tsymbol.type.getKind() == TypeKind.RECORD) { - - BRecordType recordType = (BRecordType) recLiteralType.tsymbol.type; - BField matchingField = recordType.getFields().get(recField.symbol.getName().getValue()); - - if (matchingField != null && matchingField.symbol != null) { - reportIfDeprecatedUsage(matchingField.symbol, matchingField.name.getValue(), - recordLiteral, ((BLangRecordLiteral.BLangRecordVarNameField) field).pos); - } + if (referredType.getKind() == TypeKind.RECORD) { + BField matchingField = ((BRecordType) referredType).getFields().get(recField.symbol + .getName().getValue()); + reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, + ((BLangRecordLiteral.BLangRecordVarNameField) field).pos); } } else { BLangRecordLiteral.BLangRecordSpreadOperatorField spreadField @@ -2267,18 +2258,12 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { analyzeExpr(spreadField.expr, data); BType spreadFieldType = Types.getReferredType(spreadField.expr.getBType()); - BType contextType = Types.getReferredType(recLiteralType); - if (spreadFieldType != null && spreadFieldType.getKind() == TypeKind.RECORD - && contextType.getKind() == TypeKind.RECORD) { + && referredType.getKind() == TypeKind.RECORD) { for (BField fieldEntry: ((BRecordType) spreadFieldType).getFields().values()) { - BRecordType recordType = (BRecordType) contextType; + BRecordType recordType = (BRecordType) referredType; BField matchingField = recordType.getFields().get(fieldEntry.getName().getValue()); - - if (matchingField != null && matchingField.symbol != null) { - reportIfDeprecatedUsage(matchingField.symbol, matchingField.name.getValue(), - recordLiteral, spreadField.expr.pos); - } + reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, spreadField.expr.pos); } } } @@ -2286,9 +2271,8 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { Set names = new HashSet<>(); Set neverTypedKeys = new HashSet<>(); - BType type = Types.getReferredType(recLiteralType); - boolean isRecord = type.tag == TypeTags.RECORD; - boolean isOpenRecord = isRecord && !((BRecordType) type).sealed; + boolean isRecord = referredType.tag == TypeTags.RECORD; + boolean isOpenRecord = isRecord && !((BRecordType) referredType).sealed; // A record type is inferred for a record literal even if the contextually expected type is a map, if the // mapping constructor expression has `readonly` fields. @@ -2359,7 +2343,7 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { if (bField.type.tag != TypeTags.NEVER) { this.dlog.error(spreadOpExpr.pos, DiagnosticErrorCode.DUPLICATE_KEY_IN_RECORD_LITERAL_SPREAD_OP, - type.getKind().typeName(), fieldName, spreadOpField); + referredType.getKind().typeName(), fieldName, spreadOpField); } continue; } @@ -2404,7 +2388,8 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { unescapedName, inclusiveTypeSpreadField); } - if (!isInferredRecordForMapCET && isOpenRecord && !((BRecordType) type).fields.containsKey(name)) { + if (!isInferredRecordForMapCET && isOpenRecord + && !((BRecordType) referredType).fields.containsKey(name)) { dlog.error(keyExpr.pos, DiagnosticErrorCode.INVALID_RECORD_LITERAL_IDENTIFIER_KEY, unescapedName); } @@ -2427,7 +2412,7 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { } if (isInferredRecordForMapCET) { - recordLiteral.expectedType = type; + recordLiteral.expectedType = referredType; } } @@ -2503,10 +2488,7 @@ public void visit(BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess nsPrefix private void analyzeFieldBasedAccessExpr(BLangFieldBasedAccess fieldAccessExpr, AnalyzerData data) { BLangExpression expr = fieldAccessExpr.expr; analyzeExpr(expr, data); - BSymbol symbol = fieldAccessExpr.symbol; - if (symbol != null) { - reportIfDeprecatedUsage(symbol, fieldAccessExpr.field.toString(), expr, fieldAccessExpr.pos); - } + reportIfDeprecatedUsage(fieldAccessExpr.symbol, expr, fieldAccessExpr.pos); } @Override @@ -3919,10 +3901,6 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { } BType invocableType = Types.getReferredType(iExpr.symbol.type); - if (invocableType.tag != TypeTags.INVOKABLE) { - return; - } - BInvokableSymbol invokableSymbol = ((BInvokableSymbol) iExpr.symbol); int parameterCountForPositionalArgs = ((BInvokableType) invocableType).getParameterTypes().size(); @@ -3932,11 +3910,7 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { switch (expr.getKind()) { case NAMED_ARGS_EXPR: foundNamedArg = true; - BLangNamedArgsExpression namedArgsExpression = (BLangNamedArgsExpression) expr; - if (namedArgsExpression.varSymbol != null) { - reportIfDeprecatedUsage(namedArgsExpression.varSymbol, namedArgsExpression.varSymbol.toString(), - expr, expr.pos); - } + reportIfDeprecatedUsage(((BLangNamedArgsExpression) expr).varSymbol, expr, expr.pos); i++; break; case REST_ARGS_EXPR: @@ -4014,13 +3988,10 @@ private BType getErrorTypes(BType bType) { return errorType; } - private void reportIfDeprecatedUsage(BSymbol constructSymbol, - String constructName, - BLangExpression expr, - Location usagePos) { - if (Symbols.isFlagOn(constructSymbol.flags, Flags.DEPRECATED)) { + private void reportIfDeprecatedUsage(BSymbol constructSymbol, BLangExpression expr, Location usagePos) { + if (constructSymbol != null && Symbols.isFlagOn(constructSymbol.flags, Flags.DEPRECATED)) { dlog.warning(usagePos, DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, - generateDeprecatedConstructString(expr, constructName, constructSymbol)); + generateDeprecatedConstructString(expr, constructSymbol.name.getValue(), constructSymbol)); } } From b3cfba1a3e0b8f27eefceac81fc0a65c735b578e Mon Sep 17 00:00:00 2001 From: Dulaj Date: Wed, 26 Jul 2023 15:30:14 +0530 Subject: [PATCH 11/24] Fix NPE if matching field not-found --- .../compiler/semantics/analyzer/CodeAnalyzer.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index d9c8d2c66f39..89515279e730 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2249,8 +2249,9 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { if (referredType.getKind() == TypeKind.RECORD) { BField matchingField = ((BRecordType) referredType).getFields().get(recField.symbol .getName().getValue()); - reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, - ((BLangRecordLiteral.BLangRecordVarNameField) field).pos); + if (matchingField != null) { + reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, recField.pos); + } } } else { BLangRecordLiteral.BLangRecordSpreadOperatorField spreadField @@ -2263,7 +2264,9 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { for (BField fieldEntry: ((BRecordType) spreadFieldType).getFields().values()) { BRecordType recordType = (BRecordType) referredType; BField matchingField = recordType.getFields().get(fieldEntry.getName().getValue()); - reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, spreadField.expr.pos); + if (matchingField != null) { + reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, spreadField.expr.pos); + } } } } From ed1f81ce7a67914fa0d17e2b1ae650f940351972 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Fri, 28 Jul 2023 10:16:42 +0530 Subject: [PATCH 12/24] Add deprecate warning for positional args for rest args --- .../compiler/semantics/analyzer/CodeAnalyzer.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 89515279e730..93f0537d2d05 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -3928,15 +3928,14 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { } if (i < parameterCountForPositionalArgs) { BVarSymbol paramSymbol = invokableSymbol.params.get(i); - if (paramSymbol != null && Symbols.isFlagOn(paramSymbol.flags, Flags.DEPRECATED)) { - logDeprecatedWaring(paramSymbol.toString(), paramSymbol, expr.pos); - } + reportIfDeprecatedUsage(paramSymbol, expr, expr.pos); if (Symbols.isFlagOn(invokableSymbol.params.get(i).flags, Flags.INCLUDED)) { analyzeExpr(expr, data); } + } else { + reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos); } i++; - } } } From 0b9d0b06fdad1849da548dac067d8096f22214ef Mon Sep 17 00:00:00 2001 From: Dulaj Date: Fri, 28 Jul 2023 10:39:57 +0530 Subject: [PATCH 13/24] Add more tests for deprecated param usages --- .../DeprecationAnnotationTest.java | 26 ++++++++++----- .../annotations/deprecation_annotation.bal | 33 +++++++++++++++++++ 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java index 9c20f8ac5890..403cb6618b10 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java @@ -122,15 +122,23 @@ public void testDeprecationAnnotation() { BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.name' is deprecated", 433, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.city' is deprecated", 434, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.country' is deprecated", 435, 12); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 446, 15); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 447, 15); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 448, 20); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.city' is deprecated", 451, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.country' is deprecated", 452, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.name' is deprecated", 453, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'city' is deprecated", 458, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'country' is deprecated", 459, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 460, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 458, 15); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 459, 15); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 460, 20); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.city' is deprecated", 463, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.country' is deprecated", 464, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'Company.name' is deprecated", 465, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'city' is deprecated", 470, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'country' is deprecated", 471, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 472, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 476, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 477, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 478, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y1' is deprecated", 481, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y2' is deprecated", 482, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y1' is deprecated", 485, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y2' is deprecated", 486, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'age' is deprecated", 492, 13); Assert.assertEquals(compileResult.getWarnCount(), i); } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal index 360c6314f9b9..5e73cea1358a 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal @@ -442,6 +442,18 @@ function fooFn(int x1, @deprecated int x2){ function barFn(string s, *Company company) { } +function bazFn(string a, @deprecated int... c) { +} + +function quxFn(@deprecated string y1 = "Qux", @deprecated int y2 = 10) { +} + +function quuxFn(record {| + int id; + record {|string name; @deprecated int age;|} person; +|} z) { +} + public function testDeprecatedParamUsages() { fooFn(10, 11); fooFn(12, x2 = 13); @@ -459,4 +471,25 @@ public function testDeprecatedParamUsages() { country = "Germany", // Warning name = "Bar" // Warning ); + bazFn( + "A", + 1, // warning + 2, // warning + 3 // warning + ); + quxFn( + "Quux", // warning + 11 // warning + ); + quxFn( + y1 = "Quux", // warning + y2 = 11 // warning + ); + quuxFn({ + id: 1, + person: { + name: "John", + age: 12 // warning + } + }); } From 47e900126e6d4e06b1aebb2f8ba60506e595639c Mon Sep 17 00:00:00 2001 From: Dulaj Date: Wed, 2 Aug 2023 10:09:15 +0530 Subject: [PATCH 14/24] Report deprecated usage warning for rest args --- .../compiler/semantics/analyzer/CodeAnalyzer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 93f0537d2d05..49e41ed5991d 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -3920,7 +3920,9 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { if (foundNamedArg) { continue; } - analyzeExpr(expr, data); + if (i > parameterCountForPositionalArgs) { + reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos); + } break; default: // positional args if (foundNamedArg) { From 964f8a305600cb77ae2023231970b945aa2951ce Mon Sep 17 00:00:00 2001 From: Dulaj Date: Wed, 2 Aug 2023 10:30:21 +0530 Subject: [PATCH 15/24] Remove unreachable logic --- .../compiler/semantics/analyzer/CodeAnalyzer.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 49e41ed5991d..1ffd7e1843a6 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -3908,26 +3908,18 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { int parameterCountForPositionalArgs = ((BInvokableType) invocableType).getParameterTypes().size(); int i = 0; - boolean foundNamedArg = false; for (BLangExpression expr : iExpr.argExprs) { switch (expr.getKind()) { case NAMED_ARGS_EXPR: - foundNamedArg = true; reportIfDeprecatedUsage(((BLangNamedArgsExpression) expr).varSymbol, expr, expr.pos); i++; break; case REST_ARGS_EXPR: - if (foundNamedArg) { - continue; - } if (i > parameterCountForPositionalArgs) { reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos); } break; default: // positional args - if (foundNamedArg) { - continue; - } if (i < parameterCountForPositionalArgs) { BVarSymbol paramSymbol = invokableSymbol.params.get(i); reportIfDeprecatedUsage(paramSymbol, expr, expr.pos); From 11543b77864911233abeedb29f753d9d55255b48 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Mon, 7 Aug 2023 06:15:38 +0530 Subject: [PATCH 16/24] Add support for complex deprecated scenes --- .../semantics/analyzer/CodeAnalyzer.java | 66 ++++++++++++++++--- .../DeprecationAnnotationTest.java | 20 ++++-- .../annotations/deprecation_annotation.bal | 41 ++++++++++-- 3 files changed, 107 insertions(+), 20 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 1ffd7e1843a6..51b4c783284b 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2626,11 +2626,11 @@ private void logDeprecatedWarningForInvocation(BLangInvocation invocationExpr) { private String generateDeprecatedConstructString(BLangExpression expr, String fieldOrMethodName, BSymbol symbol) { BType bType = expr.getBType(); - if (bType.tag == TypeTags.TYPEREFDESC) { + if (bType != null && bType.tag == TypeTags.TYPEREFDESC) { return bType + "." + fieldOrMethodName; } - if (bType.tag == TypeTags.OBJECT) { + if (bType != null && bType.tag == TypeTags.OBJECT) { BObjectType objectType = (BObjectType) bType; // for anonymous objects, only the field name will be in the error msg if (objectType.classDef == null || objectType.classDef.internal == false) { @@ -3905,33 +3905,75 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { BType invocableType = Types.getReferredType(iExpr.symbol.type); BInvokableSymbol invokableSymbol = ((BInvokableSymbol) iExpr.symbol); + List reqParamSymbols = invokableSymbol.params; int parameterCountForPositionalArgs = ((BInvokableType) invocableType).getParameterTypes().size(); - int i = 0; + // data.visitedArgCount must be 0 for (BLangExpression expr : iExpr.argExprs) { switch (expr.getKind()) { case NAMED_ARGS_EXPR: reportIfDeprecatedUsage(((BLangNamedArgsExpression) expr).varSymbol, expr, expr.pos); - i++; + data.visitedArgCount++; break; case REST_ARGS_EXPR: - if (i > parameterCountForPositionalArgs) { + if (data.visitedArgCount >= parameterCountForPositionalArgs) { reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos); + } else { + BLangExpression restExpr = ((BLangRestArgsExpression) expr).expr; + if (restExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { + analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) restExpr, data, + reqParamSymbols, invokableSymbol.restParam); + } else { + for (int i = data.visitedArgCount; i < parameterCountForPositionalArgs; i++) { + if (reportIfDeprecatedUsage(reqParamSymbols.get(i), expr, expr.pos)) { + break; + } + } + } } break; default: // positional args - if (i < parameterCountForPositionalArgs) { - BVarSymbol paramSymbol = invokableSymbol.params.get(i); + if (data.visitedArgCount < parameterCountForPositionalArgs) { + BVarSymbol paramSymbol = reqParamSymbols.get(data.visitedArgCount); reportIfDeprecatedUsage(paramSymbol, expr, expr.pos); - if (Symbols.isFlagOn(invokableSymbol.params.get(i).flags, Flags.INCLUDED)) { + if (Symbols.isFlagOn(reqParamSymbols.get(data.visitedArgCount).flags, Flags.INCLUDED)) { analyzeExpr(expr, data); } } else { reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos); } - i++; + data.visitedArgCount++; + } + } + // Reset the visited arg count for the next invocation + data.visitedArgCount = 0; + } + + private void analyzeRestArgsAgainstReqParams(BLangListConstructorExpr listConstructorExpr, AnalyzerData data, + List reqParamSymbols, BVarSymbol restParamSymbol) { + for (BLangExpression expr : listConstructorExpr.exprs) { + if (data.visitedArgCount >= reqParamSymbols.size()) { + // Visiting args matching with the rest-param + reportIfDeprecatedUsage(restParamSymbol, expr, expr.pos); + continue; + } + if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP ) { + BLangExpression innerExpr = ((BLangListConstructorSpreadOpExpr) expr).expr; + if (innerExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { + analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) innerExpr, data, + reqParamSymbols, restParamSymbol); + } else { + for (int i = data.visitedArgCount; i < reqParamSymbols.size(); i++) { + if (reportIfDeprecatedUsage(reqParamSymbols.get(i), expr, expr.pos)) { + break; + } + } + } + } else { + reportIfDeprecatedUsage(reqParamSymbols.get(data.visitedArgCount++), expr, expr.pos); } } + } private void validateModuleInitFunction(BLangFunction funcNode) { @@ -3984,11 +4026,13 @@ private BType getErrorTypes(BType bType) { return errorType; } - private void reportIfDeprecatedUsage(BSymbol constructSymbol, BLangExpression expr, Location usagePos) { + private boolean reportIfDeprecatedUsage(BSymbol constructSymbol, BLangExpression expr, Location usagePos) { if (constructSymbol != null && Symbols.isFlagOn(constructSymbol.flags, Flags.DEPRECATED)) { dlog.warning(usagePos, DiagnosticWarningCode.USAGE_OF_DEPRECATED_CONSTRUCT, generateDeprecatedConstructString(expr, constructSymbol.name.getValue(), constructSymbol)); + return true; } + return false; } /** @@ -4273,5 +4317,7 @@ public static class AnalyzerData { Stack> returnTypes = new Stack<>(); Stack> errorTypes = new Stack<>(); DefaultValueState defaultValueState = DefaultValueState.NOT_IN_DEFAULT_VALUE; + // Field related to args and params + int visitedArgCount = 0; } } diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java index 403cb6618b10..0701deda6649 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/annotations/DeprecationAnnotationTest.java @@ -131,14 +131,22 @@ public void testDeprecationAnnotation() { BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'city' is deprecated", 470, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'country' is deprecated", 471, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'name' is deprecated", 472, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 476, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'b' is deprecated", 476, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 477, 9); BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 478, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y1' is deprecated", 481, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y2' is deprecated", 482, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y1' is deprecated", 485, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y2' is deprecated", 486, 9); - BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'age' is deprecated", 492, 13); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 479, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y1' is deprecated", 482, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y2' is deprecated", 483, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y1' is deprecated", 486, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'y2' is deprecated", 487, 9); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'age' is deprecated", 493, 13); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 499, 11); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 502, 13); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 509, 13); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'x2' is deprecated", 516, 16); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'b' is deprecated", 523, 13); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 524, 13); + BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'c' is deprecated", 525, 13); Assert.assertEquals(compileResult.getWarnCount(), i); } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal index 5e73cea1358a..b505bcf6fd24 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/annotations/deprecation_annotation.bal @@ -442,7 +442,7 @@ function fooFn(int x1, @deprecated int x2){ function barFn(string s, *Company company) { } -function bazFn(string a, @deprecated int... c) { +function bazFn(string a, @deprecated string b, @deprecated int... c) { } function quxFn(@deprecated string y1 = "Qux", @deprecated int y2 = 10) { @@ -473,9 +473,10 @@ public function testDeprecatedParamUsages() { ); bazFn( "A", - 1, // warning - 2, // warning - 3 // warning + "B", // warning + 1, // warning + 2, // warning + 3 // warning ); quxFn( "Quux", // warning @@ -492,4 +493,36 @@ public function testDeprecatedParamUsages() { age: 12 // warning } }); + + // As rest args + [int, int] argX = [1, 2]; + fooFn(...argX); + fooFn(...[ + 1, + 2 // warning + ] + ); + var fn1 = function () returns int => 1; + fooFn(...[ + 1, + ...[ + fn1() // warning + ] + ] + ); + var fn2 = function () returns [int, int] => [1, 2]; + fooFn(...[ + ...[ + ...fn2() // warning + ] + ] + ); + bazFn( + "A", + ...[ + "B", // warning + 1, // warning + 3 // warning + ] + ); } From 9225056010dd5789b4d8ce9b5f86c9967765f51b Mon Sep 17 00:00:00 2001 From: Dulaj Date: Mon, 7 Aug 2023 06:16:40 +0530 Subject: [PATCH 17/24] Replace with tag comparison --- .../compiler/semantics/analyzer/CodeAnalyzer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 51b4c783284b..bce76cd1dcef 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2246,7 +2246,7 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { = (BLangRecordLiteral.BLangRecordVarNameField) field; analyzeExpr(recField, data); - if (referredType.getKind() == TypeKind.RECORD) { + if (referredType.tag == TypeTags.RECORD) { BField matchingField = ((BRecordType) referredType).getFields().get(recField.symbol .getName().getValue()); if (matchingField != null) { @@ -2259,8 +2259,8 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { analyzeExpr(spreadField.expr, data); BType spreadFieldType = Types.getReferredType(spreadField.expr.getBType()); - if (spreadFieldType != null && spreadFieldType.getKind() == TypeKind.RECORD - && referredType.getKind() == TypeKind.RECORD) { + if (spreadFieldType != null && spreadFieldType.tag == TypeTags.RECORD + && referredType.tag == TypeTags.RECORD) { for (BField fieldEntry: ((BRecordType) spreadFieldType).getFields().values()) { BRecordType recordType = (BRecordType) referredType; BField matchingField = recordType.getFields().get(fieldEntry.getName().getValue()); From 94617717687298964b7c3b730750d94277d13f37 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Mon, 7 Aug 2023 06:25:24 +0530 Subject: [PATCH 18/24] Improved referredType usages --- .../semantics/analyzer/CodeAnalyzer.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index bce76cd1dcef..faf2318fa81e 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2234,9 +2234,15 @@ public void visit(BLangTableConstructorExpr tableConstructorExpr, AnalyzerData d @Override public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { BType referredType = Types.getReferredType(recordLiteral.getBType()); - List fields = recordLiteral.fields; + boolean isRecord = referredType.tag == TypeTags.RECORD; + List recordLiteralFields = recordLiteral.fields; + + LinkedHashMap recordFields = null; + if (isRecord) { + recordFields = ((BRecordType) referredType).getFields(); + } - for (RecordLiteralNode.RecordField field : fields) { + for (RecordLiteralNode.RecordField field : recordLiteralFields) { if (field.isKeyValueField()) { analyzeExpr(((BLangRecordKeyValueField) field).valueExpr, data); reportIfDeprecatedUsage(((BLangRecordKeyValueField) field).key.fieldSymbol, recordLiteral, @@ -2246,9 +2252,8 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { = (BLangRecordLiteral.BLangRecordVarNameField) field; analyzeExpr(recField, data); - if (referredType.tag == TypeTags.RECORD) { - BField matchingField = ((BRecordType) referredType).getFields().get(recField.symbol - .getName().getValue()); + if (isRecord) { + BField matchingField = recordFields.get(recField.symbol.getName().getValue()); if (matchingField != null) { reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, recField.pos); } @@ -2259,11 +2264,9 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { analyzeExpr(spreadField.expr, data); BType spreadFieldType = Types.getReferredType(spreadField.expr.getBType()); - if (spreadFieldType != null && spreadFieldType.tag == TypeTags.RECORD - && referredType.tag == TypeTags.RECORD) { + if (spreadFieldType != null && spreadFieldType.tag == TypeTags.RECORD && isRecord) { for (BField fieldEntry: ((BRecordType) spreadFieldType).getFields().values()) { - BRecordType recordType = (BRecordType) referredType; - BField matchingField = recordType.getFields().get(fieldEntry.getName().getValue()); + BField matchingField = recordFields.get(fieldEntry.getName().getValue()); if (matchingField != null) { reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, spreadField.expr.pos); } @@ -2274,16 +2277,15 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { Set names = new HashSet<>(); Set neverTypedKeys = new HashSet<>(); - boolean isRecord = referredType.tag == TypeTags.RECORD; boolean isOpenRecord = isRecord && !((BRecordType) referredType).sealed; // A record type is inferred for a record literal even if the contextually expected type is a map, if the - // mapping constructor expression has `readonly` fields. + // mapping constructor expression has `readonly` recordLiteralFields. boolean isInferredRecordForMapCET = isRecord && recordLiteral.expectedType != null && recordLiteral.expectedType.tag == TypeTags.MAP; BLangRecordLiteral.BLangRecordSpreadOperatorField inclusiveTypeSpreadField = null; - for (RecordLiteralNode.RecordField field : fields) { + for (RecordLiteralNode.RecordField field : recordLiteralFields) { BLangExpression keyExpr; @@ -2303,7 +2305,7 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { } inclusiveTypeSpreadField = spreadOpField; - if (fields.size() > 1) { + if (recordLiteralFields.size() > 1) { if (names.size() > 0) { this.dlog.error(spreadOpExpr.pos, DiagnosticErrorCode.SPREAD_FIELD_MAY_DULPICATE_ALREADY_SPECIFIED_KEYS, From eee15e9f0c694a6b119d5a27c4b114ef9d322e12 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Mon, 7 Aug 2023 06:28:46 +0530 Subject: [PATCH 19/24] Fixed unnecessary change in comment --- .../ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index faf2318fa81e..0e62fcfab345 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2280,7 +2280,7 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { boolean isOpenRecord = isRecord && !((BRecordType) referredType).sealed; // A record type is inferred for a record literal even if the contextually expected type is a map, if the - // mapping constructor expression has `readonly` recordLiteralFields. + // mapping constructor expression has `readonly` fields. boolean isInferredRecordForMapCET = isRecord && recordLiteral.expectedType != null && recordLiteral.expectedType.tag == TypeTags.MAP; From cae7e918b700f9b93e644509612fb3794f84c28c Mon Sep 17 00:00:00 2001 From: Dulaj Date: Mon, 7 Aug 2023 08:44:24 +0530 Subject: [PATCH 20/24] Fix checkstyle errors --- .../compiler/semantics/analyzer/CodeAnalyzer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 0e62fcfab345..fedd255a3cac 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -31,7 +31,6 @@ import org.ballerinalang.model.tree.expressions.XMLNavigationAccess; import org.ballerinalang.model.tree.statements.StatementNode; import org.ballerinalang.model.tree.statements.VariableDefinitionNode; -import org.ballerinalang.model.types.TypeKind; import org.ballerinalang.util.diagnostic.DiagnosticErrorCode; import org.ballerinalang.util.diagnostic.DiagnosticHintCode; import org.ballerinalang.util.diagnostic.DiagnosticWarningCode; @@ -3959,7 +3958,7 @@ private void analyzeRestArgsAgainstReqParams(BLangListConstructorExpr listConstr reportIfDeprecatedUsage(restParamSymbol, expr, expr.pos); continue; } - if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP ) { + if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) { BLangExpression innerExpr = ((BLangListConstructorSpreadOpExpr) expr).expr; if (innerExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) innerExpr, data, From ca1a07a270aa83bf3ddf3675ad69f5bf42e4eae7 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Wed, 9 Aug 2023 16:35:52 +0530 Subject: [PATCH 21/24] Address review comments --- .../semantics/analyzer/CodeAnalyzer.java | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index fedd255a3cac..62bb3b2db1d1 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2263,7 +2263,7 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) { analyzeExpr(spreadField.expr, data); BType spreadFieldType = Types.getReferredType(spreadField.expr.getBType()); - if (spreadFieldType != null && spreadFieldType.tag == TypeTags.RECORD && isRecord) { + if (isRecord && spreadFieldType != null && spreadFieldType.tag == TypeTags.RECORD) { for (BField fieldEntry: ((BRecordType) spreadFieldType).getFields().values()) { BField matchingField = recordFields.get(fieldEntry.getName().getValue()); if (matchingField != null) { @@ -3909,23 +3909,23 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { List reqParamSymbols = invokableSymbol.params; int parameterCountForPositionalArgs = ((BInvokableType) invocableType).getParameterTypes().size(); - // data.visitedArgCount must be 0 + int visitedArgCount = 0; for (BLangExpression expr : iExpr.argExprs) { switch (expr.getKind()) { case NAMED_ARGS_EXPR: reportIfDeprecatedUsage(((BLangNamedArgsExpression) expr).varSymbol, expr, expr.pos); - data.visitedArgCount++; + visitedArgCount++; break; case REST_ARGS_EXPR: - if (data.visitedArgCount >= parameterCountForPositionalArgs) { + if (visitedArgCount >= parameterCountForPositionalArgs) { reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos); } else { BLangExpression restExpr = ((BLangRestArgsExpression) expr).expr; if (restExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { - analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) restExpr, data, - reqParamSymbols, invokableSymbol.restParam); + visitedArgCount = analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) restExpr, + visitedArgCount, reqParamSymbols, invokableSymbol.restParam); } else { - for (int i = data.visitedArgCount; i < parameterCountForPositionalArgs; i++) { + for (int i = visitedArgCount; i < parameterCountForPositionalArgs; i++) { if (reportIfDeprecatedUsage(reqParamSymbols.get(i), expr, expr.pos)) { break; } @@ -3934,26 +3934,24 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { } break; default: // positional args - if (data.visitedArgCount < parameterCountForPositionalArgs) { - BVarSymbol paramSymbol = reqParamSymbols.get(data.visitedArgCount); + if (visitedArgCount < parameterCountForPositionalArgs) { + BVarSymbol paramSymbol = reqParamSymbols.get(visitedArgCount); reportIfDeprecatedUsage(paramSymbol, expr, expr.pos); - if (Symbols.isFlagOn(reqParamSymbols.get(data.visitedArgCount).flags, Flags.INCLUDED)) { + if (Symbols.isFlagOn(reqParamSymbols.get(visitedArgCount).flags, Flags.INCLUDED)) { analyzeExpr(expr, data); } } else { reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos); } - data.visitedArgCount++; + visitedArgCount++; } } - // Reset the visited arg count for the next invocation - data.visitedArgCount = 0; } - private void analyzeRestArgsAgainstReqParams(BLangListConstructorExpr listConstructorExpr, AnalyzerData data, + private int analyzeRestArgsAgainstReqParams(BLangListConstructorExpr listConstructorExpr, int visitedArgCount, List reqParamSymbols, BVarSymbol restParamSymbol) { for (BLangExpression expr : listConstructorExpr.exprs) { - if (data.visitedArgCount >= reqParamSymbols.size()) { + if (visitedArgCount >= reqParamSymbols.size()) { // Visiting args matching with the rest-param reportIfDeprecatedUsage(restParamSymbol, expr, expr.pos); continue; @@ -3961,20 +3959,20 @@ private void analyzeRestArgsAgainstReqParams(BLangListConstructorExpr listConstr if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) { BLangExpression innerExpr = ((BLangListConstructorSpreadOpExpr) expr).expr; if (innerExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { - analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) innerExpr, data, + analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) innerExpr, visitedArgCount, reqParamSymbols, restParamSymbol); } else { - for (int i = data.visitedArgCount; i < reqParamSymbols.size(); i++) { + for (int i = visitedArgCount; i < reqParamSymbols.size(); i++) { if (reportIfDeprecatedUsage(reqParamSymbols.get(i), expr, expr.pos)) { break; } } } } else { - reportIfDeprecatedUsage(reqParamSymbols.get(data.visitedArgCount++), expr, expr.pos); + reportIfDeprecatedUsage(reqParamSymbols.get(visitedArgCount++), expr, expr.pos); } } - + return visitedArgCount; } private void validateModuleInitFunction(BLangFunction funcNode) { @@ -4318,7 +4316,5 @@ public static class AnalyzerData { Stack> returnTypes = new Stack<>(); Stack> errorTypes = new Stack<>(); DefaultValueState defaultValueState = DefaultValueState.NOT_IN_DEFAULT_VALUE; - // Field related to args and params - int visitedArgCount = 0; } } From 59a338d22746039715b81c28715e0c37730351f3 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Thu, 10 Aug 2023 08:34:50 +0530 Subject: [PATCH 22/24] Address review comments --- .../compiler/semantics/analyzer/CodeAnalyzer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 62bb3b2db1d1..3f6aab44a5dd 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2627,7 +2627,7 @@ private void logDeprecatedWarningForInvocation(BLangInvocation invocationExpr) { private String generateDeprecatedConstructString(BLangExpression expr, String fieldOrMethodName, BSymbol symbol) { BType bType = expr.getBType(); - if (bType != null && bType.tag == TypeTags.TYPEREFDESC) { + if (bType.tag == TypeTags.TYPEREFDESC) { return bType + "." + fieldOrMethodName; } @@ -3956,14 +3956,15 @@ private int analyzeRestArgsAgainstReqParams(BLangListConstructorExpr listConstru reportIfDeprecatedUsage(restParamSymbol, expr, expr.pos); continue; } + if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) { BLangExpression innerExpr = ((BLangListConstructorSpreadOpExpr) expr).expr; if (innerExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { - analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) innerExpr, visitedArgCount, - reqParamSymbols, restParamSymbol); + visitedArgCount = analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) innerExpr, + visitedArgCount, reqParamSymbols, restParamSymbol); } else { for (int i = visitedArgCount; i < reqParamSymbols.size(); i++) { - if (reportIfDeprecatedUsage(reqParamSymbols.get(i), expr, expr.pos)) { + if (reportIfDeprecatedUsage(reqParamSymbols.get(i), innerExpr, innerExpr.pos)) { break; } } From 49f8e545cfd1dd37ba1c772e23721b31a4afdd42 Mon Sep 17 00:00:00 2001 From: Dulaj Date: Thu, 10 Aug 2023 14:16:25 +0530 Subject: [PATCH 23/24] Remove null check for type --- .../ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 3f6aab44a5dd..298d9705daba 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -2631,7 +2631,7 @@ private String generateDeprecatedConstructString(BLangExpression expr, String fi return bType + "." + fieldOrMethodName; } - if (bType != null && bType.tag == TypeTags.OBJECT) { + if (bType.tag == TypeTags.OBJECT) { BObjectType objectType = (BObjectType) bType; // for anonymous objects, only the field name will be in the error msg if (objectType.classDef == null || objectType.classDef.internal == false) { From 5dc67645e9b92f1cf65a61a93c06bc35fb94262a Mon Sep 17 00:00:00 2001 From: Dulaj Date: Fri, 11 Aug 2023 08:43:46 +0530 Subject: [PATCH 24/24] Reduce indentation by adding continue; --- .../semantics/analyzer/CodeAnalyzer.java | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 298d9705daba..45f0b0734db4 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -3919,18 +3919,18 @@ private void analyzeInvocationParams(BLangInvocation iExpr, AnalyzerData data) { case REST_ARGS_EXPR: if (visitedArgCount >= parameterCountForPositionalArgs) { reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos); - } else { - BLangExpression restExpr = ((BLangRestArgsExpression) expr).expr; - if (restExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { - visitedArgCount = analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) restExpr, - visitedArgCount, reqParamSymbols, invokableSymbol.restParam); - } else { - for (int i = visitedArgCount; i < parameterCountForPositionalArgs; i++) { - if (reportIfDeprecatedUsage(reqParamSymbols.get(i), expr, expr.pos)) { - break; - } - } - } + continue; + } + + BLangExpression restExpr = ((BLangRestArgsExpression) expr).expr; + if (restExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { + visitedArgCount = analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) restExpr, + visitedArgCount, reqParamSymbols, invokableSymbol.restParam); + continue; + } + + for (int i = visitedArgCount; i < parameterCountForPositionalArgs; i++) { + reportIfDeprecatedUsage(reqParamSymbols.get(i), expr, expr.pos); } break; default: // positional args @@ -3957,20 +3957,20 @@ private int analyzeRestArgsAgainstReqParams(BLangListConstructorExpr listConstru continue; } - if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) { - BLangExpression innerExpr = ((BLangListConstructorSpreadOpExpr) expr).expr; - if (innerExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { - visitedArgCount = analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) innerExpr, - visitedArgCount, reqParamSymbols, restParamSymbol); - } else { - for (int i = visitedArgCount; i < reqParamSymbols.size(); i++) { - if (reportIfDeprecatedUsage(reqParamSymbols.get(i), innerExpr, innerExpr.pos)) { - break; - } - } - } - } else { + if (expr.getKind() != NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) { reportIfDeprecatedUsage(reqParamSymbols.get(visitedArgCount++), expr, expr.pos); + continue; + } + + BLangExpression innerExpr = ((BLangListConstructorSpreadOpExpr) expr).expr; + if (innerExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR) { + visitedArgCount = analyzeRestArgsAgainstReqParams((BLangListConstructorExpr) innerExpr, + visitedArgCount, reqParamSymbols, restParamSymbol); + continue; + } + + for (int i = visitedArgCount; i < reqParamSymbols.size(); i++) { + reportIfDeprecatedUsage(reqParamSymbols.get(i), innerExpr, innerExpr.pos); } } return visitedArgCount;