Skip to content
Open

jdk21 #3829

Show file tree
Hide file tree
Changes from 5 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
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This is a Java-based language server that provides code analysis, diagnostics, c

## Technology Stack

- **Language:** Java 17
- **Language:** Java 21
- **Build System:** Gradle with Kotlin DSL
- **Frameworks:** Spring Boot
- **Key Technologies:**
Expand All @@ -27,7 +27,7 @@ This is a Java-based language server that provides code analysis, diagnostics, c
## Environment Setup

### Prerequisites
- Java Development Kit 17
- Java Development Kit 21
- Gradle (wrapper included in the repository)

### Building the Project
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
strategy:
fail-fast: false
matrix:
java_version: ['17', '21', '25']
java_version: ['21', '25']
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v6
Expand Down
78 changes: 37 additions & 41 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,70 +74,66 @@ dependencies {
api("info.picocli:picocli-spring-boot-starter:4.7.7")

// кэширование
api("com.github.ben-manes.caffeine", "caffeine", "3.2.3")
api("com.github.ben-manes.caffeine:caffeine:3.2.3")
api("org.ehcache:ehcache:3.11.1")

// lsp4j core
api("org.eclipse.lsp4j", "org.eclipse.lsp4j", "0.24.0")
api("org.eclipse.lsp4j", "org.eclipse.lsp4j.websocket.jakarta", "0.24.0")
api("org.eclipse.lsp4j:org.eclipse.lsp4j:0.24.0")
api("org.eclipse.lsp4j:org.eclipse.lsp4j.websocket.jakarta:0.24.0")

// 1c-syntax
api("io.github.1c-syntax", "bsl-parser", "0.30.0") {
exclude("com.ibm.icu", "*")
exclude("org.antlr", "ST4")
exclude("org.antlr", "antlr-runtime")
}
api("io.github.1c-syntax", "utils", "0.6.9")
api("io.github.1c-syntax", "mdclasses", "0.17.4")
api("io.github.1c-syntax", "bsl-common-library", "0.9.2")
api("io.github.1c-syntax", "supportconf", "0.15.0")
api("io.github.1c-syntax:bsl-parser:0.31.0")
api("io.github.1c-syntax:utils:0.7.0")
api("io.github.1c-syntax:mdclasses:0.18.0")
api("io.github.1c-syntax:bsl-common-library:0.10.0")
api("io.github.1c-syntax:supportconf:0.16.0")

// nullability annotations
api("org.jspecify", "jspecify", "1.0.0")
api("org.jspecify:jspecify:1.0.0")

// JLanguageTool
implementation("org.languagetool", "languagetool-core", languageToolVersion){
exclude("commons-logging", "commons-logging")
exclude("com.sun.xml.bind", "jaxb-core")
exclude("com.sun.xml.bind", "jaxb-impl")
implementation("org.languagetool:languagetool-core:$languageToolVersion"){
exclude("commons-logging:commons-logging")
exclude("com.sun.xml.bind:jaxb-core")
exclude("com.sun.xml.bind:jaxb-impl")
}
implementation("org.languagetool", "language-en", languageToolVersion){
exclude("commons-logging", "commons-logging")
exclude("com.sun.xml.bind", "jaxb-core")
exclude("com.sun.xml.bind", "jaxb-impl")
implementation("org.languagetool:language-en:$languageToolVersion"){
exclude("commons-logging:commons-logging")
exclude("com.sun.xml.bind:jaxb-core")
exclude("com.sun.xml.bind:jaxb-impl")
}
implementation("org.languagetool", "language-ru", languageToolVersion){
exclude("commons-logging", "commons-logging")
exclude("com.sun.xml.bind", "jaxb-core")
exclude("com.sun.xml.bind", "jaxb-impl")
implementation("org.languagetool:language-ru:$languageToolVersion"){
exclude("commons-logging:commons-logging")
exclude("com.sun.xml.bind:jaxb-core")
exclude("com.sun.xml.bind:jaxb-impl")
}

// AOP
implementation("org.aspectj", "aspectjrt", "1.9.25.1")
implementation("org.aspectj:aspectjrt:1.9.25.1")

// commons utils
implementation("commons-io", "commons-io", "2.21.0")
implementation("commons-beanutils", "commons-beanutils", "1.11.0"){
exclude("commons-logging", "commons-logging")
implementation("commons-io:commons-io:2.21.0")
implementation("commons-beanutils:commons-beanutils:1.11.0"){
exclude("commons-logging:commons-logging")
}
implementation("commons-codec", "commons-codec", "1.20.0")
implementation("org.apache.commons", "commons-lang3", "3.20.0")
implementation("org.apache.commons", "commons-collections4", "4.5.0")
implementation("org.apache.commons", "commons-exec", "1.6.0")
implementation("commons-codec:commons-codec:1.20.0")
implementation("org.apache.commons:commons-lang3:3.20.0")
implementation("org.apache.commons:commons-collections4:4.5.0")
implementation("org.apache.commons:commons-exec:1.6.0")

// progress bar
implementation("me.tongfei", "progressbar", "0.10.1")
implementation("me.tongfei:progressbar:0.10.1")

// (de)serialization
implementation("tools.jackson.core:jackson-databind")
implementation("tools.jackson.dataformat:jackson-dataformat-xml")
implementation("io.leangen.geantyref:geantyref:2.0.1")

// graphs
implementation("org.jgrapht", "jgrapht-core", "1.5.2")
implementation("org.jgrapht:jgrapht-core:1.5.2")

// SARIF serialization
implementation("com.contrastsecurity", "java-sarif", "2.0")
implementation("com.contrastsecurity:java-sarif:2.0")

// CONSTRAINTS
implementation("com.google.guava:guava") {
Expand All @@ -152,21 +148,21 @@ dependencies {

// spring
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude("com.vaadin.external.google", "android-json")
exclude("com.vaadin.external.google:android-json")
}

testImplementation("org.junit.jupiter:junit-jupiter")

// test utils
testImplementation("org.jmockit", "jmockit", "1.50")
testImplementation("org.awaitility", "awaitility", "4.3.0")
testImplementation("org.jmockit:jmockit:1.50")
testImplementation("org.awaitility:awaitility:4.3.0")
Comment on lines +157 to +158
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

jmockit 1.50 Java 21 compatibility issues JEP 403

💡 Result:

JMockit 1.50 tends to run into Java 17+ / Java 21 problems for the same underlying reason as many legacy instrumentation/mocking tools: JEP 403 (delivered in Java 17) tightened access to JDK internals so you can’t rely on the old “relaxed” illegal reflective access behavior anymore; you must explicitly open the needed JDK packages (or the tool must be updated to stop depending on them). [1]

What it looks like on Java 21

Typical failures show up as java.lang.reflect.InaccessibleObjectException / “module java.base does not opens …”, commonly involving packages like java.lang / java.lang.reflect. This is the class of failure people are explicitly fixing for JDK 21+ by propagating --add-opens into the test JVM. [3]

Why JMockit specifically is risky here

  • 1.50 is the latest published JMockit 1.x artifact (there isn’t a newer line that “officially” modernizes it for JPMS/JDK 21). [5]
  • The project’s own issue tracker contains unresolved Java 17-era incompatibilities/limitations in real builds (often interacting badly with other agents like JaCoCo), which is a strong signal that Java 21 will be painful/fragile. [4]

Practical workarounds (tests)

Because JEP 403 removed the “single switch” approach (--illegal-access), the remaining escape hatch is to open specific packages with --add-opens. [1][2]

Common starting point (adjust based on the exact package named in your exception):

--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED

(You may need additional --add-opens lines depending on what JMockit and/or your test stack reflectively touches; the exception message tells you the exact module/package to open.) [2][3]

Bottom line

If you must stay on JMockit 1.50 with Java 21, expect to maintain a growing list of --add-opens for your test JVM due to JEP 403’s strong encapsulation. [1][2][3] For longer-term stability on Java 21+, most teams end up migrating away from JMockit rather than fighting JPMS/agent edge-cases. [4][5]

Sources:
[1] OpenJDK JEP 403 (Strongly Encapsulate JDK Internals)
[2] StackOverflow explanation of InaccessibleObjectException + --add-opens + note that --illegal-access stops working from JDK 17 (JEP 403)
[3] Apache Maven PR discussion: JDK 21+ test failures fixed by propagating --add-opens (mentions java.lang / java.lang.reflect)
[4] JMockit issue: incompatibilities on Java 17 (example of ongoing breakage/fragility)
[5] javadoc.io listing showing latest org.jmockit:jmockit version is 1.50


🌐 Web query:

jmockit Java agent bytecode instrumentation Java 21 encapsulation

💡 Result:

JMockit’s mocking works by bytecode instrumentation via a -javaagent (it’s not a pure proxy-based mocking library). With Java 21’s strong encapsulation, this tends to break in two main ways:

  1. JMockit is effectively unmaintained for modern JDKs
    The last “current release” shown in JMockit’s own history is v1.49 (Dec 29, 2019), i.e., pre–Java 21 and even pre–Java 17 LTS, so incompatibilities with newer classfiles/JDK behaviors are common and often not fixed upstream. [1]

  2. Encapsulation / deep-reflection failures (InaccessibleObjectException)
    On Java 9+, you can get java.lang.reflect.InaccessibleObjectException when code tries to “break in” to non-opened JDK internals (access checks can’t be suppressed). [3]
    Typical mitigations are JVM flags such as --add-opens ...=ALL-UNNAMED (or targeted opens to specific modules), but this weakens encapsulation and is increasingly discouraged.

  3. Agent-loading rules tightened (especially dynamic attach)
    If your setup loads the agent dynamically (Attach API) rather than at JVM startup, JDK 21 emits warnings and is explicitly moving toward disallowing dynamic agent loading by default. The official guidance is to prefer startup-time -javaagent, and if you truly must attach dynamically you may need -XX:+EnableDynamicAgentLoading (and related attach settings). [2]

Practical takeaways for Java 21

  • Prefer startup agent: run tests with -javaagent:/path/to/jmockit.jar (not dynamic attach). [2]
  • If you hit InaccessibleObjectException, you’ll need targeted --add-opens for the specific JDK packages you’re trying to instrument/reflect into (but consider that this is fighting the platform direction). [3]
  • Given JMockit’s last release date, the most robust “Java 21 + encapsulation” fix is usually migrating away from JMockit (or limiting tests to mocking only your own code where module access isn’t restricted). [1]

Sources
[1] JMockit “Development history” (current release v1.49, Dec 29, 2019) https://jmockit.github.io/changes.html
[2] OpenJDK JEP 451 (JDK 21): Prepare to Disallow the Dynamic Loading of Agents https://openjdk.org/jeps/451
[3] Oracle JDK docs: InaccessibleObjectException (thrown when access checks can’t be suppressed) https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/InaccessibleObjectException.html


🏁 Script executed:

cd /tmp && git ls-files | grep -E "(build\.gradle|pom\.xml|\.java-version)" | head -20

Repository: 1c-syntax/bsl-language-server

Length of output: 141


🏁 Script executed:

cat -n build.gradle.kts | sed -n '1,50p'

Repository: 1c-syntax/bsl-language-server

Length of output: 2185


🏁 Script executed:

cat -n build.gradle.kts | sed -n '200,250p'

Repository: 1c-syntax/bsl-language-server

Length of output: 2158


🏁 Script executed:

rg -n "java\s*\{|sourceCompatibility|targetCompatibility|jvmArgs|add-opens" build.gradle.kts

Repository: 1c-syntax/bsl-language-server

Length of output: 249


🏁 Script executed:

rg -n "test|jvmArgs|javaagent" build.gradle.kts | head -30

Repository: 1c-syntax/bsl-language-server

Length of output: 1308


Add --add-opens flags to test task for Java 21 compatibility with jmockit 1.50.

The codebase targets Java 21 (lines 164–165) while using jmockit 1.50 with -javaagent (lines 157, 232). JMockit relies on bytecode instrumentation to access JDK internals, but Java 21's strong encapsulation (JEP 403) blocks this by default, causing InaccessibleObjectException failures. To run tests on Java 21, add the following to the test task configuration:

jvmArgs(
  "-javaagent:${jmockitPath}",
  "--add-opens", "java.base/java.lang=ALL-UNNAMED",
  "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED"
)

Adjust the --add-opens packages based on the specific InaccessibleObjectException errors encountered. For longer-term stability, consider migrating to a modern mocking library or the maintained jmockit fork at com.github.hazendaz.jmockit, as the original jmockit project (v1.50) is not actively maintained for modern JDKs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@build.gradle.kts` around lines 157 - 158, The test task needs JVM args to
allow JMockit bytecode instrumentation on Java 21: update the Gradle test task
configuration (the Test task where jmockit is added and jmockitPath / -javaagent
is configured) to include jvmArgs("-javaagent:${jmockitPath}", "--add-opens",
"java.base/java.lang=ALL-UNNAMED", "--add-opens",
"java.base/java.lang.reflect=ALL-UNNAMED") so tests run without
InaccessibleObjectException; add or adjust the jvmArgs invocation in the Test
task that currently sets the javaagent and consider making the opens
configurable if you encounter different packages.


testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
withSourcesJar()
withJavadocJar()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public void run(String... args) {

private static String[] addDefaultCommand(String[] args) {
List<String> tmpList = new ArrayList<>(Arrays.asList(args));
tmpList.add(0, DEFAULT_COMMAND);
tmpList.addFirst(DEFAULT_COMMAND);
args = tmpList.toArray(new String[0]);
return args;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ private void setConfigurationRoot(InitializeParams params) {
return;
}

var rootUri = workspaceFolders.get(0).getUri();
var rootUri = workspaceFolders.getFirst().getUri();
Path rootPath;
try {
rootPath = new File(new URI(rootUri).getPath()).getCanonicalFile().toPath();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import io.sentry.protocol.Geo;
import io.sentry.protocol.User;
import lombok.RequiredArgsConstructor;
import org.eclipse.lsp4j.ClientInfo;
import org.eclipse.lsp4j.ServerInfo;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.event.ApplicationReadyEvent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public Optional<ParserRuleContext> getAst() {
return super.getAst();
}

return Optional.of(statements.get(0));
return Optional.of(statements.getFirst());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -677,8 +677,8 @@ private void removeOrphanedNodes() {
return edges.isEmpty()
|| (adjacentDeadCodeEnabled
&& edges.size() == 1
&& edges.get(0).getType() == CfgEdgeType.ADJACENT_CODE
&& graph.getEdgeTarget(edges.get(0)) == vertex);
&& edges.getFirst().getType() == CfgEdgeType.ADJACENT_CODE
&& graph.getEdgeTarget(edges.getFirst()) == vertex);

})
.toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ private void formatFile(File file) {
return;
}

final TextEdit textEdit = formatting.get(0);
final TextEdit textEdit = formatting.getFirst();
final String newText = textEdit.getNewText();
FileUtils.writeStringToFile(file, newText, StandardCharsets.UTF_8);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public List<CodeAction> getCodeActions(CodeActionParams params, DocumentContext

var parameters = maybeDoCall
.map(BSLParser.DoCallContext::callParamList)
.map(callParamListContext -> callParamListContext.children)
.map(ParserRuleContext::getChildren)
.orElse(Collections.emptyList())
.stream()
.filter(Predicate.not(TerminalNode.class::isInstance))
Expand All @@ -96,12 +96,12 @@ public List<CodeAction> getCodeActions(CodeActionParams params, DocumentContext
return Collections.emptyList();
}

var firstParam = parameters.get(0);
var firstParam = parameters.getFirst();
if (firstParam.getTokens().isEmpty()) {
return Collections.emptyList();
}

var firstToken = firstParam.getTokens().get(0);
var firstToken = firstParam.getTokens().getFirst();
if (firstToken.getType() != BSLLexer.STRING) {
return Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public List<CodeLens> getCodeLenses(DocumentContext documentContext) {
return Collections.emptyList();
}

var firstMethod = methods.get(0);
var firstMethod = methods.getFirst();

return List.of(toCodeLens(firstMethod, documentContext));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private static Double getColorValue(BSLParser.CallParamListContext callParams, b
return Optional.ofNullable(callParams.callParam(colorPosition))
.map(BSLParser.CallParamContext::expression)
.filter(expression -> expression.getTokens().size() == 1)
.map(expression -> expression.getTokens().get(0))
.map(expression -> expression.getTokens().getFirst())
.map(Token::getText)
.map(ConstructorColorInformationSupplier::tryParseInteger)
.map(colorValue -> (double) colorValue / MAX_COLOR_COMPONENT_VALUE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ private void runWorker() {
}
}
} catch (Exception e) {
LOGGER.error("Unexpected error in document executor worker: " + e.getMessage(), e);
LOGGER.error("Unexpected error in document executor worker: {}", e.getMessage(), e);
} finally {
flushPendingChanges();
}
Expand Down Expand Up @@ -225,7 +225,7 @@ private void accumulate(ChangeTask task) {
pendingContent = changeApplier.apply(baseContent, task.contentChanges);
pendingVersion = task.version;
} catch (Exception e) {
LOGGER.error("Error while accumulating document change task: " + e.getMessage(), e);
LOGGER.error("Error while accumulating document change task: {}", e.getMessage(), e);
pendingContent = null;
pendingVersion = -1;
latestAppliedVersion.accumulateAndGet(task.version, Math::max);
Expand All @@ -249,7 +249,7 @@ private void flushPendingChanges() {
latestAppliedVersion.accumulateAndGet(pendingVersion, Math::max);
completeWaitersUpTo(latestAppliedVersion.get());
} catch (Exception e) {
LOGGER.error("Error while applying accumulated document changes: " + e.getMessage(), e);
LOGGER.error("Error while applying accumulated document changes: {}", e.getMessage(), e);
} finally {
lock.writeLock().unlock();
pendingContent = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ private MetricStorage computeMetrics() {
if (tokensUnboxed.isEmpty()) {
lines = 0;
} else {
lines = tokensUnboxed.get(tokensUnboxed.size() - 1).getLine();
lines = tokensUnboxed.getLast().getLine();
}
metricsTemp.setLines(lines);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ private void computeCommentsIgnorance(List<Token> codeTokens, List<Token> commen
int lastTokenLine;
if (codeTokens.isEmpty()) {
// File contains only comments
lastTokenLine = comments.isEmpty() ? 0 : comments.get(comments.size() - 1).getLine();
lastTokenLine = comments.isEmpty() ? 0 : comments.getLast().getLine();
} else {
int lastCodeTokenLine = codeTokens.get(codeTokens.size() - 1).getLine();
int lastCommentLine = comments.isEmpty() ? 0 : comments.get(comments.size() - 1).getLine();
int lastCodeTokenLine = codeTokens.getLast().getLine();
int lastCommentLine = comments.isEmpty() ? 0 : comments.getLast().getLine();
lastTokenLine = Math.max(lastCodeTokenLine, lastCommentLine);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public ParseTree visitFunction(BSLParser.FunctionContext ctx) {
}

if (!declaration.annotation().isEmpty()) {
startNode = declaration.annotation().get(0).AMPERSAND();
startNode = declaration.annotation().getFirst().AMPERSAND();
}

MethodSymbol methodSymbol = createMethodSymbol(
Expand Down Expand Up @@ -132,7 +132,7 @@ public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) {
}

if (!declaration.annotation().isEmpty()) {
startNode = declaration.annotation().get(0).AMPERSAND();
startNode = declaration.annotation().getFirst().AMPERSAND();
}

MethodSymbol methodSymbol = createMethodSymbol(
Expand Down Expand Up @@ -190,7 +190,7 @@ private static Optional<CompilerDirectiveKind> getCompilerDirective(
.map(compilerDirectiveContext -> compilerDirectiveContext.getStop().getType())
.filter(SPECIAL_COMPILER_DIRECTIVES_TOKEN_TYPES::contains)
.findAny()
.orElseGet(() -> compilerDirectiveContexts.get(0).getStop().getType());
.orElseGet(() -> compilerDirectiveContexts.getFirst().getStop().getType());

return CompilerDirectiveKind.of(tokenType);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public ParseTree visitString(BSLParser.StringContext ctx) {
var startLine = 0;
var startEmptyLines = "";
if (!ctx.getTokens().isEmpty()) {
startLine = ctx.getTokens().get(0).getLine();
startLine = ctx.getTokens().getFirst().getLine();
startEmptyLines = "\n".repeat(startLine - 1);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -567,12 +567,12 @@ private static boolean isValidStructureConstructorParameter(
return true;
}

var firstParam = callParams.get(0);
var firstParam = callParams.getFirst();
var tokens = firstParam.getTokens();
if (tokens.isEmpty()) {
return false;
}
return tokens.get(0).getType() == BSLParser.STRING;
return tokens.getFirst().getType() == BSLParser.STRING;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,13 @@ private void checkAllPathsHaveReturns(BSLParser.FunctionContext ctx) {
}

private Optional<ParserRuleContext> nonExplicitReturnNode(CfgVertex v, ControlFlowGraph graph) {
if (v instanceof BasicBlockVertex basicBlock) {
return checkBasicBlockExitingNode(basicBlock);
} else if (v instanceof LoopVertex loop) {
return checkLoopExitingNode(loop);
} else if (v instanceof ConditionalVertex conditional) {
return checkElseIfClauseExitingNode(conditional, graph);
}
return switch (v) {
case BasicBlockVertex basicBlock -> checkBasicBlockExitingNode(basicBlock);
case LoopVertex loop -> checkLoopExitingNode(loop);
case ConditionalVertex conditional -> checkElseIfClauseExitingNode(conditional, graph);
default -> v.getAst();
};

return v.getAst();
}

private Optional<ParserRuleContext> checkElseIfClauseExitingNode(ConditionalVertex v, ControlFlowGraph graph) {
Expand All @@ -159,7 +157,7 @@ private Optional<ParserRuleContext> checkElseIfClauseExitingNode(ConditionalVert

private static Optional<ParserRuleContext> checkBasicBlockExitingNode(BasicBlockVertex block) {
if (!block.statements().isEmpty()) {
var lastStatement = block.statements().get(block.statements().size() - 1);
var lastStatement = block.statements().getLast();

var nodes = Trees.findAllRuleNodes(lastStatement, BSLParser.RULE_returnStatement, BSLParser.RULE_raiseStatement);
if (nodes.isEmpty()) {
Expand Down
Loading
Loading