Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement logging warnings for deprecated param usages in funcion call and fix inconsistent behaviour in warnings in deprecated record fields #40545

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a6538fc
Fix no warning in deprecated field-name
dulajdilshan May 31, 2023
5ca75c7
Add tests
dulajdilshan May 31, 2023
9d1530c
Fix naming grammar
dulajdilshan Jun 6, 2023
c1aae3e
Add more tests
dulajdilshan Jun 6, 2023
42b1c2c
Merge branch 'master' into fix/deprecate-record-field-40363
dulajdilshan Jun 28, 2023
9585a24
Improve tests
dulajdilshan Jul 4, 2023
93deae3
Merge branch 'master' into fix/deprecate-record-field-40363
dulajdilshan Jul 14, 2023
621b44b
Extract deprecate warning to a method
dulajdilshan Jul 14, 2023
a20ca5d
Implement deprecated usage warnings for func params
dulajdilshan Jul 14, 2023
f8469b7
Add more tests
dulajdilshan Jul 14, 2023
a05e734
Improve deprecate warning logic
dulajdilshan Jul 14, 2023
71b250f
Merge branch 'master' into fix/deprecate-record-field-40363
dulajdilshan Jul 25, 2023
4eda95c
Use referred type and refactor
dulajdilshan Jul 26, 2023
b3cfba1
Fix NPE if matching field not-found
dulajdilshan Jul 26, 2023
ed1f81c
Add deprecate warning for positional args for rest args
dulajdilshan Jul 28, 2023
0b9d0b0
Add more tests for deprecated param usages
dulajdilshan Jul 28, 2023
bb22c81
Merge branch 'master' into fix/deprecate-record-field-40363
dulajdilshan Aug 2, 2023
47e9001
Report deprecated usage warning for rest args
dulajdilshan Aug 2, 2023
964f8a3
Remove unreachable logic
dulajdilshan Aug 2, 2023
11543b7
Add support for complex deprecated scenes
dulajdilshan Aug 7, 2023
9225056
Replace with tag comparison
dulajdilshan Aug 7, 2023
9461771
Improved referredType usages
dulajdilshan Aug 7, 2023
eee15e9
Fixed unnecessary change in comment
dulajdilshan Aug 7, 2023
cae7e91
Fix checkstyle errors
dulajdilshan Aug 7, 2023
ca1a07a
Address review comments
dulajdilshan Aug 9, 2023
59a338d
Address review comments
dulajdilshan Aug 10, 2023
49f8e54
Remove null check for type
dulajdilshan Aug 10, 2023
a892bd5
Merge branch 'master' into fix/deprecate-record-field-40363
dulajdilshan Aug 10, 2023
5dc6764
Reduce indentation by adding continue;
dulajdilshan Aug 11, 2023
3f153e0
Merge branch 'master' into fix/deprecate-record-field-40363
dulajdilshan Aug 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2232,32 +2232,59 @@ public void visit(BLangTableConstructorExpr tableConstructorExpr, AnalyzerData d

@Override
public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) {
List<RecordLiteralNode.RecordField> fields = recordLiteral.fields;
BType referredType = Types.getReferredType(recordLiteral.getBType());
boolean isRecord = referredType.tag == TypeTags.RECORD;
List<RecordLiteralNode.RecordField> recordLiteralFields = recordLiteral.fields;

for (RecordLiteralNode.RecordField field : fields) {
LinkedHashMap<String, BField> recordFields = null;
if (isRecord) {
recordFields = ((BRecordType) referredType).getFields();
}

for (RecordLiteralNode.RecordField field : recordLiteralFields) {
if (field.isKeyValueField()) {
analyzeExpr(((BLangRecordKeyValueField) field).valueExpr, data);
reportIfDeprecatedUsage(((BLangRecordKeyValueField) field).key.fieldSymbol, recordLiteral,
((BLangRecordKeyValueField) field).pos);
} else if (field.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
analyzeExpr((BLangRecordLiteral.BLangRecordVarNameField) field, data);
BLangRecordLiteral.BLangRecordVarNameField recField
= (BLangRecordLiteral.BLangRecordVarNameField) field;
analyzeExpr(recField, data);

if (isRecord) {
BField matchingField = recordFields.get(recField.symbol.getName().getValue());
if (matchingField != null) {
reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, recField.pos);
}
}
} else {
analyzeExpr(((BLangRecordLiteral.BLangRecordSpreadOperatorField) field).expr, data);
BLangRecordLiteral.BLangRecordSpreadOperatorField spreadField
= (BLangRecordLiteral.BLangRecordSpreadOperatorField) field;
analyzeExpr(spreadField.expr, data);

BType spreadFieldType = Types.getReferredType(spreadField.expr.getBType());
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) {
reportIfDeprecatedUsage(matchingField.symbol, recordLiteral, spreadField.expr.pos);
}
}
}
}
}

Set<Object> names = new HashSet<>();
Set<Object> neverTypedKeys = new HashSet<>();
BType literalBType = recordLiteral.getBType();
BType type = Types.getReferredType(literalBType);
boolean isRecord = type.tag == TypeTags.RECORD;
boolean isOpenRecord = isRecord && !((BRecordType) type).sealed;
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.
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;

Expand All @@ -2277,7 +2304,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,
Expand Down Expand Up @@ -2320,7 +2347,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;
}
Expand Down Expand Up @@ -2365,7 +2392,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);
}
Expand All @@ -2388,7 +2416,7 @@ public void visit(BLangRecordLiteral recordLiteral, AnalyzerData data) {
}

if (isInferredRecordForMapCET) {
recordLiteral.expectedType = type;
recordLiteral.expectedType = referredType;
}
}

Expand Down Expand Up @@ -2464,12 +2492,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 && 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);
}
reportIfDeprecatedUsage(fieldAccessExpr.symbol, expr, fieldAccessExpr.pos);
}

@Override
Expand All @@ -2496,6 +2519,7 @@ public void visit(BLangInvocation invocationExpr, AnalyzerData data) {
logDeprecatedWarningForInvocation(invocationExpr);
}
}
analyzeInvocationParams(invocationExpr, data);
}

@Override
Expand Down Expand Up @@ -3875,6 +3899,83 @@ 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);
BInvokableSymbol invokableSymbol = ((BInvokableSymbol) iExpr.symbol);
List<BVarSymbol> reqParamSymbols = invokableSymbol.params;
int parameterCountForPositionalArgs = ((BInvokableType) invocableType).getParameterTypes().size();

int visitedArgCount = 0;
for (BLangExpression expr : iExpr.argExprs) {
switch (expr.getKind()) {
case NAMED_ARGS_EXPR:
reportIfDeprecatedUsage(((BLangNamedArgsExpression) expr).varSymbol, expr, expr.pos);
visitedArgCount++;
break;
case REST_ARGS_EXPR:
if (visitedArgCount >= parameterCountForPositionalArgs) {
reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos);
continue;
dulajdilshan marked this conversation as resolved.
Show resolved Hide resolved
}

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
if (visitedArgCount < parameterCountForPositionalArgs) {
BVarSymbol paramSymbol = reqParamSymbols.get(visitedArgCount);
reportIfDeprecatedUsage(paramSymbol, expr, expr.pos);
if (Symbols.isFlagOn(reqParamSymbols.get(visitedArgCount).flags, Flags.INCLUDED)) {
analyzeExpr(expr, data);
}
} else {
reportIfDeprecatedUsage(invokableSymbol.restParam, expr, expr.pos);
}
visitedArgCount++;
}
}
}

private int analyzeRestArgsAgainstReqParams(BLangListConstructorExpr listConstructorExpr, int visitedArgCount,
List<BVarSymbol> reqParamSymbols, BVarSymbol restParamSymbol) {
for (BLangExpression expr : listConstructorExpr.exprs) {
if (visitedArgCount >= reqParamSymbols.size()) {
// Visiting args matching with the rest-param
reportIfDeprecatedUsage(restParamSymbol, expr, expr.pos);
continue;
}

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;
}

private void validateModuleInitFunction(BLangFunction funcNode) {
if (funcNode.attachedFunction || !Names.USER_DEFINED_INIT_SUFFIX.value.equals(funcNode.name.value)) {
return;
Expand Down Expand Up @@ -3925,6 +4026,15 @@ private BType getErrorTypes(BType bType) {
return errorType;
}

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;
}

/**
* This class contains the state machines for a set of workers.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -86,20 +92,61 @@ 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.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.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);
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",
395, 9);
BAssertUtil.validateWarning(compileResult, i++, "usage of construct 'line02' is deprecated", 395, 9);
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", 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 '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 '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);
}

Expand Down
Loading
Loading