Skip to content

Fix BSLHighlighter crash on multiline SDBL tokens (GROUP BY on separate lines)#424

Merged
nixel2007 merged 6 commits intodevelopfrom
copilot/fix-scanner-parsing-error
Apr 23, 2026
Merged

Fix BSLHighlighter crash on multiline SDBL tokens (GROUP BY on separate lines)#424
nixel2007 merged 6 commits intodevelopfrom
copilot/fix-scanner-parsing-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 2, 2026

BSLHighlighter.highlightToken() crashes the entire SonarScanner with IllegalArgumentException when SDBL multi-word keywords like СГРУППИРОВАТЬ ПО (GROUP BY) are placed on separate BSL string continuation lines. The SDBL lexer combines these into a single token whose text contains \n, but highlightToken() computed the end offset using the total codepoint count across all lines — producing an offset that exceeded the first line's actual length.

Root cause fix in highlightToken()

Multiline token text is truncated to the first line before computing the highlight range. This correctly highlights СГРУППИРОВАТЬ on its line, while ПО on the next line is highlighted as part of the BSL STRING token.

var newlineIndex = tokenText.indexOf('\n');
if (newlineIndex >= 0) {
    tokenText = tokenText.substring(0, newlineIndex).stripTrailing();
}

Safety net in saveHighlighting()

Added @Slf4j and try-catch around highlighting.highlight() — any remaining invalid tokens are logged and skipped instead of terminating the scan. Follows the same pattern established in IssuesLoader.getTextRange().

Tests

  • testHighlightingWithMultilineGroupByToken: Reproducing test using a real-world query from issue comments containing СГРУППИРОВАТЬ ПО on separate lines
  • testSaveHighlightingWithInvalidTokenPosition: Safety net test with a token at an invalid offset, asserting no exception is thrown
  • testHighlightingWithLongQuery: Tab-indented query highlighting test

Copilot AI changed the title [WIP] Fix error parsing file causing scanner failure Catch IllegalArgumentException in BSLHighlighter to prevent scanner crash Apr 2, 2026
Copilot AI requested a review from nixel2007 April 2, 2026 08:22
@nixel2007
Copy link
Copy Markdown
Member

@copilot а что по поводу куска кода из комментария к оригинальной задаче? Саму ошибку подсветки тоже надо поправить

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 8, 2026

@copilot а что по поводу куска кода из комментария к оригинальной задаче? Саму ошибку подсветки тоже надо поправи...

Нашёл и исправил корневую причину. Проблема в том, что SDBL лексер объединяет СГРУППИРОВАТЬ ПО (GROUP BY) в один токен, даже когда эти ключевые слова находятся на разных строках BSL (через | продолжение строки). Текст такого токена содержит \n, а highlightToken() вычислял конечное смещение по всему тексту, включая символы после переноса строки — это давало offset, превышающий длину строки.

Исправление в highlightToken(): обрезаем текст токена до первой строки перед вычислением диапазона подсветки (ad92e75).

Проверено на файле CRM_КлиентыСервер.bsl.txt из комментария к issue #318 — воспроизведено и исправлено.

Copilot AI changed the title Catch IllegalArgumentException in BSLHighlighter to prevent scanner crash Fix BSLHighlighter crash on multiline SDBL tokens (GROUP BY on separate lines) Apr 8, 2026
@para11ax
Copy link
Copy Markdown

para11ax commented Apr 8, 2026

В плагине сонаркуба 1.18.0 (в 1.17.2 не повторяется) поймал похоже #121, тут в чате уже обсуждалось. java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Unable to highlight file
На строке 599 ("ИНДЕКСИРОВАТЬ") в длинном запросе в типовом модуле ERP 2.5.14.59: config/CommonModules/СтруктураЗаказа/Ext/Module.bsl
Выше в запросе аналогичный текст встречается, но падает всегда на этой
|
|ИНДЕКСИРОВАТЬ
| ПО ГруппаИзделий, КлючПартияРодитель, ДлительностьДоВыпускаРодитель
|;

На плагине, собранном из этой ветки, ошибка та же, что и на 1.18.0:

11:48:00.838 ERROR Error during SonarScanner Engine execution
java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Unable to highlight file config/CommonModules/СтруктураЗаказа/Ext/Module.bsl
at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(Unknown Source)
at java.base/java.util.concurrent.ForkJoinTask.reportException(Unknown Source)
at java.base/java.util.concurrent.ForkJoinTask.invoke(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(Unknown Source)
at com.github._1c_syntax.bsl.sonar.BSLCoreSensor.lambda$execute$5(BSLCoreSensor.java:164)
at java.base/java.util.HashMap.forEach(Unknown Source)
at com.github._1c_syntax.bsl.sonar.BSLCoreSensor.execute(BSLCoreSensor.java:149)
at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:69)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:88)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:61)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:79)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:61)
at org.sonar.scanner.scan.SpringModuleScanContainer.doAfterStart(SpringModuleScanContainer.java:80)
at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:227)
at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:206)
at org.sonar.scanner.scan.SpringProjectScanContainer.scan(SpringProjectScanContainer.java:212)
at org.sonar.scanner.scan.SpringProjectScanContainer.scanRecursively(SpringProjectScanContainer.java:208)
at org.sonar.scanner.scan.SpringProjectScanContainer.doAfterStart(SpringProjectScanContainer.java:178)
at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:227)
at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:206)
at org.sonar.scanner.bootstrap.SpringScannerContainer.doAfterStart(SpringScannerContainer.java:344)
at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:227)
at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:206)
at org.sonar.scanner.bootstrap.SpringGlobalContainer.doAfterStart(SpringGlobalContainer.java:143)
at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:227)
at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:206)
at org.sonar.scanner.bootstrap.ScannerMain.runScannerEngine(ScannerMain.java:157)
at org.sonar.scanner.bootstrap.ScannerMain.run(ScannerMain.java:72)
at org.sonar.scanner.bootstrap.ScannerMain.main(ScannerMain.java:56)
Caused by: java.lang.IllegalArgumentException: Unable to highlight file config/CommonModules/СтруктураЗаказа/Ext/Module.bsl
at org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting.highlight(DefaultHighlighting.java:85)
at org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting.highlight(DefaultHighlighting.java:37)
at com.github._1c_syntax.bsl.sonar.BSLHighlighter.lambda$saveHighlighting$6(BSLHighlighter.java:162)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
at com.github._1c_syntax.bsl.sonar.BSLHighlighter.saveHighlighting(BSLHighlighter.java:161)
at com.github._1c_syntax.bsl.sonar.BSLCoreSensor.processFile(BSLCoreSensor.java:202)
at com.github._1c_syntax.bsl.sonar.BSLCoreSensor.lambda$execute$4(BSLCoreSensor.java:167)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(Unknown Source)
at java.base/java.util.concurrent.CountedCompleter.exec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool.scan(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(Unknown Source)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: 21 is not a valid line offset for pointer. File config/CommonModules/СтруктураЗаказа/Ext/Module.bsl has 15 character(s) at line 599
at org.sonar.api.utils.Preconditions.checkArgument(Preconditions.java:43)
at org.sonar.api.batch.fs.internal.DefaultInputFile.checkValid(DefaultInputFile.java:378)
at org.sonar.api.batch.fs.internal.DefaultInputFile.newPointer(DefaultInputFile.java:311)
at org.sonar.api.batch.fs.internal.DefaultInputFile.newRange(DefaultInputFile.java:327)
at org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting.highlight(DefaultHighlighting.java:83)
... 24 common frames omitted

11:48:02.800 DEBUG Java command exited with code 1
11:48:02.803 INFO EXECUTION FAILURE
11:48:02.813 INFO Total time: 22:31.847s

@nixel2007
Copy link
Copy Markdown
Member

@copilot посмотри комментарии тут и в оригинальном ишузе. Убедись, что все примеры файлов успешно анализируются твоей версией кода

Adds reproducers from the comments on issue #318 and PR #424:
- The full CRM_КлиентыСервер.bsl module attached by @Bazil1c to issue #318,
  which crashed the scanner on a multiline СГРУППИРОВАТЬ ПО SDBL token.
- The ИНДЕКСИРОВАТЬ ПО (INDEX BY) on separate BSL continuation lines
  scenario reported by @para11ax (ERP 2.5 СтруктураЗаказа module).

Both tests fail on the initial commit of this branch and pass with the
multiline-token truncation fix, confirming the fix covers every code
sample shared in the PR/issue discussion.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nixel2007 nixel2007 marked this pull request as ready for review April 22, 2026 20:32
Copilot AI review requested due to automatic review settings April 22, 2026 20:32
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a SonarScanner crash caused by SDBL multi-word keywords being tokenized as a single token containing a newline (e.g., СГРУППИРОВАТЬ ПО split across BSL string-continuation lines), which previously led to invalid highlight ranges.

Changes:

  • Truncate multiline token text to the first line before computing highlight ranges in BSLHighlighter.highlightToken().
  • Add a safety net in BSLHighlighter.saveHighlighting() to catch and log invalid highlight ranges instead of terminating the scan.
  • Add regression tests and real-world BSL example files covering multiline SDBL keywords and long/tab-indented queries.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/main/java/com/github/_1c_syntax/bsl/sonar/BSLHighlighter.java Prevents invalid ranges from multiline token text; adds exception shielding around highlight emission.
src/test/java/com/github/_1c_syntax/bsl/sonar/BSLHighlighterTest.java Adds regression tests ensuring highlighting does not throw for multiline SDBL tokens and invalid positions.
src/test/resources/examples/highlightCrmQuery.bsl Realistic reproducer with СГРУППИРОВАТЬ / ПО split across lines.
src/test/resources/examples/highlightErpIndexByQuery.bsl Reproducer for ИНДЕКСИРОВАТЬ / ПО split across lines.
src/test/resources/examples/highlightLongQuery.bsl Long/tab-indented query example to ensure highlighting remains stable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +172 to +174
} catch (IllegalArgumentException e) {
LOGGER.error("Unable to highlight file {}", inputFile, e);
}
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

The catch block logs only the file and emits an ERROR + stacktrace for every invalid token. If a file produces many invalid ranges, this can spam logs and still won’t identify which token/range caused it. Consider including the failing range/token details in the message and/or lowering to WARN/DEBUG or aggregating (e.g., count failures per file and log once).

Copilot uses AI. Check for mistakes.
Comment on lines +134 to +169
@Test
void testHighlightingWithLongQuery() {
// given
context = SensorContextTester.create(Path.of("."));
highlighter = new BSLHighlighter(context);
var fileName = "highlightLongQuery.bsl";
var baseDirName = "src/test/resources/examples";
var path = Path.of(baseDirName, fileName);
documentContext = BSLLSBinding.getServerContext().addDocument(path.toUri());
BSLLSBinding.getServerContext().rebuildDocument(documentContext);
inputFile = Tools.inputFileBSL(fileName, Path.of(baseDirName).toFile());

// when/then - should not throw even with tabs causing position differences
assertThatNoException().isThrownBy(() ->
highlighter.saveHighlighting(inputFile, documentContext)
);
}

@Test
void testHighlightingWithMultilineGroupByToken() {
// given - file with СГРУППИРОВАТЬ ПО (GROUP BY) on separate lines,
// which the SDBL lexer combines into a single multiline token
context = SensorContextTester.create(Path.of("."));
highlighter = new BSLHighlighter(context);
var fileName = "highlightCrmQuery.bsl";
var baseDirName = "src/test/resources/examples";
var path = Path.of(baseDirName, fileName);
documentContext = BSLLSBinding.getServerContext().addDocument(path.toUri());
BSLLSBinding.getServerContext().rebuildDocument(documentContext);
inputFile = Tools.inputFileBSL(fileName, Path.of(baseDirName).toFile());

// when/then - should not throw despite multiline SDBL tokens
assertThatNoException().isThrownBy(() ->
highlighter.saveHighlighting(inputFile, documentContext)
);
}
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

The new tests repeat the same setup boilerplate (creating context/highlighter, resolving baseDirName/path, adding & rebuilding the document, building the InputFile). Extracting a small helper (e.g., loadDocumentAndInputFile(fileName)) would reduce duplication and make future repro additions less error-prone.

Copilot uses AI. Check for mistakes.
- S138 (BSLHighlighter.saveHighlighting too long): extract
  applyHighlighting() helper to shrink the method below the 75-line limit.
- S2211 (lambda parameter without explicit type): replace the inline
  block lambda with a method reference to the new helper.
- S5976 (repeated test bodies): collapse the four file-based
  highlighting tests into a single @ParameterizedTest sourced from
  @valuesource. Added junit-jupiter-params test dependency.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sonarqubecloud
Copy link
Copy Markdown

@nixel2007 nixel2007 merged commit 5702b70 into develop Apr 23, 2026
17 checks passed
@theshadowco theshadowco deleted the copilot/fix-scanner-parsing-error branch May 8, 2026 04:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Ошибка разбора файла прерывает работу сканера

4 participants