Skip to content

[master][LS] Fix IndexOutOfBoundException in STModify API #44047

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

Merged
merged 3 commits into from
Apr 24, 2025
Merged
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 @@ -55,12 +55,11 @@
public final class BallerinaTreeModifyUtil {

private static final String DELETE = "delete";
private static final String IMPORT = "import";

private BallerinaTreeModifyUtil() {
}

private static final Map<String, String> typeMapping = new HashMap<String, String>() {{
private static final Map<String, String> typeMapping = new HashMap<>() {{
put("DELETE", "");
put("INSERT", "$STATEMENT");
}};
Expand Down Expand Up @@ -138,7 +137,6 @@
theEndOffset - theStartOffset), mainStartMapping);
}


public static JsonElement modifyTree(ASTModification[] astModifications, Path compilationPath,
WorkspaceManager workspaceManager)
throws Exception {
Expand Down Expand Up @@ -205,7 +203,7 @@
newSyntaxTree = Formatter.format(newSyntaxTree);

SemanticModel newSemanticModel = updateWorkspaceDocument(compilationPath, newSyntaxTree.toSourceCode(),
workspaceManager);
workspaceManager);

Optional<Document> formattedSrcFile = workspaceManager.document(compilationPath);
if (formattedSrcFile.isEmpty()) {
Expand Down Expand Up @@ -233,8 +231,7 @@
// Update project instance

PackageCompilation packageCompilation = updatedDoc.module().packageInstance().getCompilation();
SemanticModel semanticModel = packageCompilation.getSemanticModel(updatedDoc.module().moduleId());
return semanticModel;
return packageCompilation.getSemanticModel(updatedDoc.module().moduleId());
}

private static boolean importExist(UnusedSymbolsVisitor unusedSymbolsVisitor, ASTModification astModification) {
Expand All @@ -243,32 +240,64 @@
|| unusedSymbolsVisitor.getUnusedImports().containsKey(importValue));
}

private static TextEdit constructEdit(
UnusedSymbolsVisitor unusedSymbolsVisitor, TextDocument oldTextDocument,
ASTModification astModification) {
String mapping = BallerinaTreeModifyUtil.resolveMapping(astModification.getType(),
private static TextEdit constructEdit(UnusedSymbolsVisitor unusedSymbolsVisitor, TextDocument oldTextDocument,
ASTModification astModification) {

String editText = BallerinaTreeModifyUtil.resolveMapping(astModification.getType(),
astModification.getConfig() == null ? new JsonObject() : astModification.getConfig());
if (mapping != null) {
boolean doEdit = false;
if (DELETE.equals(astModification.getType())) {
if (unusedSymbolsVisitor.toBeDeletedRanges().contains(astModification)) {
doEdit = true;
}
} else {
if (editText == null) {
return null;

Check warning on line 249 in language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java

View check run for this annotation

Codecov / codecov/patch

language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java#L249

Added line #L249 was not covered by tests
}

boolean doEdit = false;
if (DELETE.equals(astModification.getType())) {
if (unusedSymbolsVisitor.toBeDeletedRanges().contains(astModification)) {
doEdit = true;
}
if (doEdit) {
LinePosition startLinePos = LinePosition.from(astModification.getStartLine(),
astModification.getStartColumn());
LinePosition endLinePos = LinePosition.from(astModification.getEndLine(),
astModification.getEndColumn());
int startOffset = oldTextDocument.textPositionFrom(startLinePos);
int endOffset = oldTextDocument.textPositionFrom(endLinePos);
return TextEdit.from(
TextRange.from(startOffset,
endOffset - startOffset), mapping);
} else {
doEdit = true;
}
if (doEdit) {
TextRange range = getRange(astModification, oldTextDocument);
if (range == null) {
return null;

Check warning on line 263 in language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java

View check run for this annotation

Codecov / codecov/patch

language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java#L263

Added line #L263 was not covered by tests
}
return TextEdit.from(range, editText);
}
return null;
}

public static TextRange getRange(ASTModification modification, TextDocument oldTextDocument) {
// Get line positions from modification
LinePosition startLinePos = LinePosition.from(modification.getStartLine(), modification.getStartColumn());
LinePosition endLinePos = LinePosition.from(modification.getEndLine(), modification.getEndColumn());

// Calculate offsets
int startOffset = calculateOffset(oldTextDocument, startLinePos);
int endOffset = calculateOffset(oldTextDocument, endLinePos);

if (startOffset < 0 || endOffset < 0) {
return null;

Check warning on line 280 in language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java

View check run for this annotation

Codecov / codecov/patch

language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java#L280

Added line #L280 was not covered by tests
}

return TextRange.from(startOffset, endOffset - startOffset);
}

/**
* Helper method to calculate text offset from a line position.
*/
private static int calculateOffset(TextDocument document, LinePosition linePos) {
try {
return document.textPositionFrom(linePos);
} catch (IndexOutOfBoundsException e) {

Check warning on line 292 in language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java

View check run for this annotation

Codecov / codecov/patch

language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java#L292

Added line #L292 was not covered by tests
// If the line position is at the end of the document, return the document length
if (linePos.line() == document.textLines().size()) {
return document.toCharArray().length;

Check warning on line 295 in language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java

View check run for this annotation

Codecov / codecov/patch

language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java#L295

Added line #L295 was not covered by tests
}
return -1;
} catch (Exception e) {

Check warning on line 298 in language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java

View check run for this annotation

Codecov / codecov/patch

language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java#L297-L298

Added lines #L297 - L298 were not covered by tests
// TODO: Handle other exceptions as needed
return -1;

Check warning on line 300 in language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java

View check run for this annotation

Codecov / codecov/patch

language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/extensions/ballerina/document/BallerinaTreeModifyUtil.java#L300

Added line #L300 was not covered by tests
}
}
}
Loading