From 5f438cf64e92c52b7fa8b2c0a8f7cf67eff4e8c9 Mon Sep 17 00:00:00 2001 From: John Trujillo Date: Wed, 4 Mar 2026 11:31:02 -0500 Subject: [PATCH 1/2] fix: prevent StringIndexOutOfBoundsException in setter/getter generator Add safe coordinate bounds in EditHelper and try-catch fallback with UI error message. --- .../GenerateSettersAndGettersAction.kt | 24 ++++++++++++------- .../androidide/lsp/java/utils/EditHelper.java | 10 +++++++- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/generators/GenerateSettersAndGettersAction.kt b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/generators/GenerateSettersAndGettersAction.kt index 78fa088116..17f6c20f3d 100644 --- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/generators/GenerateSettersAndGettersAction.kt +++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/generators/GenerateSettersAndGettersAction.kt @@ -68,6 +68,13 @@ class GenerateSettersAndGettersAction : FieldBasedAction() { private val log = LoggerFactory.getLogger(GenerateSettersAndGettersAction::class.java) } + private fun showErrorMessage(error: Throwable, context: Context) { + log.error("Unable to generate setters and getters", error) + ThreadUtils.runOnUiThread { + flashError(context.getString(R.string.msg_cannot_generate_setters_getters)) + } + } + override fun onGetFields(fields: List, data: ActionData) { showFieldSelector(fields = fields, data = data, actionId = id, listener = { checkedNames -> @@ -76,12 +83,8 @@ class GenerateSettersAndGettersAction : FieldBasedAction() { _, error, -> if (error != null) { - log.error("Unable to generate setters and getters", error) - ThreadUtils.runOnUiThread { - flashError( - data[Context::class.java]!!.getString(R.string.msg_cannot_generate_setters_getters) - ) - } + val context = data[Context::class.java] + if (context != null) showErrorMessage(error, context) return@whenComplete } } @@ -132,8 +135,13 @@ class GenerateSettersAndGettersAction : FieldBasedAction() { } ThreadUtils.runOnUiThread { - editor.text.insert(insert.line, insert.column, sb) - editor.formatCodeAsync() + try { + editor.text.insert(insert.line, insert.column, sb) + editor.formatCodeAsync() + } catch (e: Exception) { + val context = data[Context::class.java] + if (context != null) showErrorMessage(e, context) + } } } diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/utils/EditHelper.java b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/utils/EditHelper.java index 1f8baac9a8..c8e1afa40d 100644 --- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/utils/EditHelper.java +++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/utils/EditHelper.java @@ -173,10 +173,18 @@ public static Position insertAtEndOfClass(JavacTask task, CompilationUnitTree ro ) { SourcePositions pos = Trees.instance(task).getSourcePositions(); LineMap lines = root.getLineMap(); + long end = pos.getEndPosition(root, leaf); + + if (end < 0) return new Position(0, 0); + int line = (int) lines.getLineNumber(end); int column = (int) lines.getColumnNumber(end); - return new Position(line - 1, column - 2); + + int safeLine = Math.max(0, line - 1); + int safeColumn = Math.max(0, column - 2); + + return new Position(safeLine, safeColumn); } private static String printParameters(final ExecutableType method, final MethodTree source) { From 81bf22ba9deb8c42bc0ca4e3bf6a6d5b4cadeedc Mon Sep 17 00:00:00 2001 From: John Trujillo Date: Wed, 4 Mar 2026 12:01:17 -0500 Subject: [PATCH 2/2] refactor: refine error handling for setter/getter generator --- .../generators/GenerateSettersAndGettersAction.kt | 11 +++++------ .../itsaky/androidide/lsp/java/utils/EditHelper.java | 9 +++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/generators/GenerateSettersAndGettersAction.kt b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/generators/GenerateSettersAndGettersAction.kt index 17f6c20f3d..dfefd23edb 100644 --- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/generators/GenerateSettersAndGettersAction.kt +++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/generators/GenerateSettersAndGettersAction.kt @@ -68,8 +68,9 @@ class GenerateSettersAndGettersAction : FieldBasedAction() { private val log = LoggerFactory.getLogger(GenerateSettersAndGettersAction::class.java) } - private fun showErrorMessage(error: Throwable, context: Context) { + private fun showErrorMessage(error: Throwable, context: Context?) { log.error("Unable to generate setters and getters", error) + context ?: return ThreadUtils.runOnUiThread { flashError(context.getString(R.string.msg_cannot_generate_setters_getters)) } @@ -83,8 +84,7 @@ class GenerateSettersAndGettersAction : FieldBasedAction() { _, error, -> if (error != null) { - val context = data[Context::class.java] - if (context != null) showErrorMessage(error, context) + showErrorMessage(error, data[Context::class.java]) return@whenComplete } } @@ -138,9 +138,8 @@ class GenerateSettersAndGettersAction : FieldBasedAction() { try { editor.text.insert(insert.line, insert.column, sb) editor.formatCodeAsync() - } catch (e: Exception) { - val context = data[Context::class.java] - if (context != null) showErrorMessage(e, context) + } catch (e: StringIndexOutOfBoundsException) { + showErrorMessage(e, data[Context::class.java]) } } } diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/utils/EditHelper.java b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/utils/EditHelper.java index c8e1afa40d..a49b46d6f9 100644 --- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/utils/EditHelper.java +++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/utils/EditHelper.java @@ -176,15 +176,16 @@ public static Position insertAtEndOfClass(JavacTask task, CompilationUnitTree ro long end = pos.getEndPosition(root, leaf); - if (end < 0) return new Position(0, 0); + if (end < 0) throw new IllegalStateException("Cannot determine class end position"); int line = (int) lines.getLineNumber(end); int column = (int) lines.getColumnNumber(end); - int safeLine = Math.max(0, line - 1); - int safeColumn = Math.max(0, column - 2); + if (line <= 0 || column <= 0) { + throw new IllegalStateException("Invalid class end position: line=" + line + ", column=" + column); + } - return new Position(safeLine, safeColumn); + return new Position(line - 1, Math.max(0, column - 2)); } private static String printParameters(final ExecutableType method, final MethodTree source) {