Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
* @param docs Documentation of the member
* @param annotations Annotations of the member.
* @param imports Imports of the member.
* @param includedIn The type inclusion this field comes from (null if from the record itself).
* @since 1.0.0
*/
public record Member(
Expand All @@ -47,7 +48,8 @@ public record Member(
boolean readonly,
String docs,
List<TypeData.Annotation> annotations,
Map<String, String> imports
Map<String, String> imports,
String includedIn
) {
public static class MemberBuilder {
private Member.MemberKind kind;
Expand All @@ -60,6 +62,7 @@ public static class MemberBuilder {
private String docs;
private List<TypeData.Annotation> annotations;
private Map<String, String> imports;
private String includedIn;

public MemberBuilder() {
}
Expand Down Expand Up @@ -114,12 +117,18 @@ public MemberBuilder imports(Map<String, String> imports) {
return this;
}

public MemberBuilder includedIn(String includedIn) {
this.includedIn = includedIn;
return this;
}

public Member build() {
Member member = new Member(
kind, refs != null ? List.copyOf(refs) : null,
type, name, defaultValue, optional, readonly, docs,
annotations != null ? List.copyOf(annotations) : null,
imports != null ? Map.copyOf(imports) : null
imports != null ? Map.copyOf(imports) : null,
includedIn
);
this.kind = null;
this.refs = null;
Expand All @@ -131,6 +140,7 @@ public Member build() {
this.docs = null;
this.annotations = null;
this.imports = null;
this.includedIn = null;
return member;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import io.ballerina.compiler.api.symbols.TypeDefinitionSymbol;
import io.ballerina.compiler.api.symbols.TypeDescKind;
import io.ballerina.compiler.api.symbols.TypeDescTypeSymbol;
import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol;
import io.ballerina.compiler.api.symbols.TypeSymbol;
import io.ballerina.compiler.api.symbols.UnionTypeSymbol;
import io.ballerina.compiler.api.values.ConstantValue;
Expand All @@ -64,6 +65,7 @@
import io.ballerina.projects.Module;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -300,8 +302,20 @@ public Object transform(RecordTypeSymbol recordTypeSymbol, TypeData.TypeDataBuil

// includes
List<String> includes = new ArrayList<>();
Map<String, String> fieldToInclusionMap = new HashMap<>();
recordTypeSymbol.typeInclusions().forEach(typeInclusion -> {
includes.add(CommonUtils.getTypeSignature(typeInclusion, this.moduleInfo));
String inclusionSignature = CommonUtils.getTypeSignature(typeInclusion, this.moduleInfo);
includes.add(inclusionSignature);

// Assume that type inclusion is always a type reference
TypeDefinitionSymbol typeDef =
(TypeDefinitionSymbol) ((TypeReferenceTypeSymbol) typeInclusion).definition();
Comment on lines +310 to +312
Copy link

Copilot AI Sep 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe cast operation without type checking. The code assumes typeInclusion is always a TypeReferenceTypeSymbol, but this should be verified before casting to prevent ClassCastException.

Copilot uses AI. Check for mistakes.
if (typeDef.typeDescriptor().typeKind() == TypeDescKind.RECORD) {
RecordTypeSymbol referencedRecord = (RecordTypeSymbol) typeDef.typeDescriptor();
referencedRecord.fieldDescriptors().forEach((fieldName, fieldSymbol) -> {
fieldToInclusionMap.put(fieldName, inclusionSignature);
});
}
});
typeDataBuilder.includes(includes);

Expand Down Expand Up @@ -329,6 +343,10 @@ public Object transform(RecordTypeSymbol recordTypeSymbol, TypeData.TypeDataBuil
recordTypeSymbol.fieldDescriptors().forEach((fieldName, fieldSymbol) -> {
TypeData.TypeDataBuilder memberTypeDataBuilder = new TypeData.TypeDataBuilder();
Object transformedFieldType = transform(fieldSymbol.typeDescriptor(), memberTypeDataBuilder);

// Check if this field comes from a type inclusion
String includedIn = fieldToInclusionMap.get(fieldName);

Member member = memberBuilder
.name(fieldSymbol.getName().orElse(fieldName))
.kind(Member.MemberKind.FIELD)
Expand All @@ -338,6 +356,7 @@ public Object transform(RecordTypeSymbol recordTypeSymbol, TypeData.TypeDataBuil
.refs(getTypeRefs(transformedFieldType, fieldSymbol.typeDescriptor()))
.docs(getDocumentString(fieldSymbol))
.defaultValue(getDefaultValueOfField(typeDataBuilder.name(), fieldName).orElse(null))
.includedIn(includedIn) // Add inclusion source information
.build();
fieldMembers.add(member);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@
"name": "id",
"optional": false,
"readonly": false,
"docs": ""
"docs": "",
"includedIn": "Person"
},
{
"kind": "FIELD",
Expand All @@ -115,7 +116,8 @@
"name": "name",
"optional": false,
"readonly": false,
"docs": ""
"docs": "",
"includedIn": "Person"
},
{
"kind": "FIELD",
Expand Down Expand Up @@ -168,7 +170,8 @@
"name": "addresses",
"optional": false,
"readonly": false,
"docs": ""
"docs": "",
"includedIn": "Person"
},
{
"kind": "FIELD",
Expand All @@ -179,7 +182,8 @@
"name": "dob",
"optional": false,
"readonly": false,
"docs": ""
"docs": "",
"includedIn": "Person"
}
],
"includes": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,8 @@
"name": "city",
"optional": false,
"readonly": false,
"docs": ""
"docs": "",
"includedIn": "City"
},
{
"kind": "FIELD",
Expand All @@ -457,7 +458,8 @@
"name": "country",
"optional": false,
"readonly": false,
"docs": ""
"docs": "",
"includedIn": "City"
}
],
"restMember": {
Expand Down
Loading
Loading