diff --git a/build.gradle.kts b/build.gradle.kts index db8340e4230..7c266ebc528 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -82,11 +82,7 @@ dependencies { 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", "bsl-parser", "0.31.0-rc.1") 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") diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/aop/sentry/PermissionFilterBeforeSendCallback.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/aop/sentry/PermissionFilterBeforeSendCallback.java index 7da56b48224..2107b6369d8 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/aop/sentry/PermissionFilterBeforeSendCallback.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/aop/sentry/PermissionFilterBeforeSendCallback.java @@ -131,7 +131,7 @@ private CompletableFuture askUserForPermission(LanguageClient return languageClient.showMessageRequest(requestParams); } - @Nullable private MessageActionItem waitForPermission(CompletableFuture sendQuestion) { + private @Nullable MessageActionItem waitForPermission(CompletableFuture sendQuestion) { try { return sendQuestion.get(); } catch (InterruptedException e) { diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/aop/sentry/SentryScopeConfigurer.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/aop/sentry/SentryScopeConfigurer.java index 53d28f11653..3350b1e8444 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/aop/sentry/SentryScopeConfigurer.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/aop/sentry/SentryScopeConfigurer.java @@ -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; diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java index 7533af65b4b..09453609d7d 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java @@ -76,7 +76,7 @@ public ControlFlowGraph buildGraph(BSLParser.CodeBlockContext block) { // Если это тело модуля, то самую первую инструкцию препроцессора сожрет грамматика file // надо ее тоже посетить принудительно. var parent = block.getParent(); - if (parent instanceof BSLParser.FileCodeBlockContext fileBlock) { + if (parent instanceof BSLParser.FileCodeBlockContext fileBlock && fileBlock.getParent() != null) { var probablyPreprocessor = Trees.getPreviousNode(fileBlock.getParent(), fileBlock, BSLParser.RULE_preprocessor); @@ -210,15 +210,15 @@ public ParseTree visitElsifBranch(BSLParser.ElsifBranchContext ctx) { if (currentIfBlock == null) { throw new IllegalStateException( "Cannot process elsif branch: there is no active condition block. " + - "This may occur when preprocessor directives modify the block stack."); + "This may occur when preprocessor directives modify the block stack."); } var buildParts = currentIfBlock.getBuildParts(); if (buildParts.isEmpty()) { throw new IllegalStateException( "Cannot process elsif branch: build parts stack is empty. " + - "Expected previous condition on stack. " + - "This may occur when preprocessor conditions modify the stack inside if statement body."); + "Expected previous condition on stack. " + + "This may occur when preprocessor conditions modify the stack inside if statement body."); } var previousCondition = buildParts.pop(); @@ -256,7 +256,7 @@ public ParseTree visitElseBranch(BSLParser.ElseBranchContext ctx) { if (currentIfBlock == null) { throw new IllegalStateException( "Cannot process else branch: there is no active condition block. " + - "This may occur when preprocessor directives modify the block stack."); + "This may occur when preprocessor directives modify the block stack."); } var condition = currentIfBlock.getBuildParts().pop(); graph.addEdge(condition, block.begin(), CfgEdgeType.FALSE_BRANCH); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/ExtractStructureConstructorSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/ExtractStructureConstructorSupplier.java index 1e96c9409bc..57e5a38b794 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/ExtractStructureConstructorSupplier.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codeactions/ExtractStructureConstructorSupplier.java @@ -46,6 +46,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; /** @@ -85,7 +86,7 @@ public List 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)) @@ -163,9 +164,14 @@ public List getCodeActions(CodeActionParams params, DocumentContext } private static boolean isParentAssignment(BSLParser.DoCallContext doCall, BSLParser.AssignmentContext assignment) { - return assignment.expression().member().stream() + var expression = assignment.expression(); + if (expression == null) { + return false; + } + return expression.member().stream() .map(BSLParser.MemberContext::complexIdentifier) - .map(BSLParser.ComplexIdentifierContext::newExpression) + .map(ctx -> ctx != null ? ctx.newExpression() : null) + .filter(Objects::nonNull) .filter(newExpressionContext -> newExpressionContext == doCall.getParent()) .findAny().isEmpty(); } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/semantictokens/SemanticTokensOptions.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/semantictokens/SemanticTokensOptions.java index 1c5e0862a87..2e33e3be165 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/semantictokens/SemanticTokensOptions.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/semantictokens/SemanticTokensOptions.java @@ -33,7 +33,6 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Set; /** diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AllFunctionPathMustHaveReturnDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AllFunctionPathMustHaveReturnDiagnostic.java index 41cb5d2255d..ded94921c72 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AllFunctionPathMustHaveReturnDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AllFunctionPathMustHaveReturnDiagnostic.java @@ -151,7 +151,7 @@ private Optional checkElseIfClauseExitingNode(ConditionalVert var expression = v.getExpression(); if (expression.getParent() instanceof BSLParser.ElsifBranchContext elsifBranch && !ignoreMissingElseOnExit) { - return Optional.of(elsifBranch.getParent()); + return Optional.ofNullable(elsifBranch.getParent()); } return Optional.empty(); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AssignAliasFieldsInQueryDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AssignAliasFieldsInQueryDiagnostic.java index 3fe8b3e7b7e..500750b3f33 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AssignAliasFieldsInQueryDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AssignAliasFieldsInQueryDiagnostic.java @@ -28,6 +28,7 @@ import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType; import com.github._1c_syntax.bsl.parser.SDBLParser; import org.antlr.v4.runtime.tree.ParseTree; +import org.jspecify.annotations.Nullable; @DiagnosticMetadata( type = DiagnosticType.CODE_SMELL, @@ -44,9 +45,9 @@ public class AssignAliasFieldsInQueryDiagnostic extends AbstractSDBLVisitorDiagnostic { @Override - public ParseTree visitQuery(SDBLParser.QueryContext ctx) { + public @Nullable ParseTree visitQuery(SDBLParser.QueryContext ctx) { - if (ctx.getParent().getRuleIndex() != SDBLParser.RULE_subquery) { + if (ctx.getParent() != null && ctx.getParent().getRuleIndex() != SDBLParser.RULE_subquery) { return super.visitQuery(ctx); } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CreateQueryInCycleDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CreateQueryInCycleDiagnostic.java index 1b0fc73eb02..cc1e9a51def 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CreateQueryInCycleDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CreateQueryInCycleDiagnostic.java @@ -145,7 +145,7 @@ private static String getComplexPathName( } @Override - public ParseTree visitFile(BSLParser.FileContext ctx) { + public @Nullable ParseTree visitFile(BSLParser.FileContext ctx) { currentScope = new VariableScope(); currentScope.enterScope(GLOBAL_SCOPE); ParseTree result = super.visitFile(ctx); @@ -154,7 +154,7 @@ public ParseTree visitFile(BSLParser.FileContext ctx) { } @Override - public ParseTree visitFileCodeBlock(BSLParser.FileCodeBlockContext ctx) { + public @Nullable ParseTree visitFileCodeBlock(BSLParser.FileCodeBlockContext ctx) { currentScope.enterScope(MODULE_SCOPE); ParseTree result = super.visitFileCodeBlock(ctx); currentScope.leaveScope(); @@ -162,7 +162,7 @@ public ParseTree visitFileCodeBlock(BSLParser.FileCodeBlockContext ctx) { } @Override - public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) { + public @Nullable ParseTree visitProcedure(BSLParser.ProcedureContext ctx) { currentScope.enterScope(ctx.procDeclaration().subName().getText()); ParseTree result = super.visitProcedure(ctx); currentScope.leaveScope(); @@ -170,7 +170,7 @@ public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) { } @Override - public ParseTree visitFunction(BSLParser.FunctionContext ctx) { + public @Nullable ParseTree visitFunction(BSLParser.FunctionContext ctx) { currentScope.enterScope(ctx.funcDeclaration().subName().getText()); ParseTree result = super.visitFunction(ctx); currentScope.leaveScope(); @@ -178,7 +178,7 @@ public ParseTree visitFunction(BSLParser.FunctionContext ctx) { } @Override - public ParseTree visitAssignment(AssignmentContext ctx) { + public @Nullable ParseTree visitAssignment(AssignmentContext ctx) { if (ctx.expression() == null) { return super.visitAssignment(ctx); } @@ -217,14 +217,14 @@ private Set getTypesFromComplexIdentifier(BSLParser.ComplexIdentifierCon private void visitDescendantCodeBlock(BSLParser.@Nullable CodeBlockContext ctx) { Optional.ofNullable(ctx) - .map(e -> e.children) + .map(ParserRuleContext::getChildren) .stream() .flatMap(Collection::stream) .forEach(t -> t.accept(this)); } @Override - public ParseTree visitAccessCall(BSLParser.AccessCallContext ctx) { + public @Nullable ParseTree visitAccessCall(BSLParser.AccessCallContext ctx) { if (!EXECUTE_CALL_PATTERN.matcher(ctx.methodCall().methodName().getText()).matches()) { return super.visitAccessCall(ctx); } @@ -273,7 +273,7 @@ public ParseTree visitForEachStatement(BSLParser.ForEachStatementContext ctx) { } @Override - public ParseTree visitWhileStatement(BSLParser.WhileStatementContext ctx) { + public @Nullable ParseTree visitWhileStatement(BSLParser.WhileStatementContext ctx) { currentScope.flowMode.push(CodeFlowType.CYCLE); ParseTree result = super.visitWhileStatement(ctx); currentScope.flowMode.pop(); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DoubleNegativesDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DoubleNegativesDiagnostic.java index 392f4760705..73a25d3062d 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DoubleNegativesDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/DoubleNegativesDiagnostic.java @@ -86,7 +86,12 @@ private static boolean isNegationOperator(BslExpression parent) { } private void addDiagnostic(BinaryOperationNode node) { - var startToken = Trees.getTokens(node.getParent().getRepresentingAst()) + var parent = node.getParent(); + if (parent == null) { + return; + } + + var startToken = Trees.getTokens(parent.getRepresentingAst()) .stream() .findFirst() .orElseThrow(); @@ -100,7 +105,11 @@ private void addDiagnostic(BinaryOperationNode node) { } private void addDiagnostic(UnaryOperationNode node) { - var startToken = Trees.getTokens(node.getParent().getRepresentingAst()) + var parent = node.getParent(); + if (parent == null) { + return; + } + var startToken = Trees.getTokens(parent.getRepresentingAst()) .stream() .findFirst() .orElseThrow(); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FieldsFromJoinsWithoutIsNullDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FieldsFromJoinsWithoutIsNullDiagnostic.java index ac6251ce6cc..d480fa768f5 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FieldsFromJoinsWithoutIsNullDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FieldsFromJoinsWithoutIsNullDiagnostic.java @@ -108,11 +108,11 @@ private static Stream joinedTables(SDBLParser.JoinPartContext joinPartCt private static List joinedDataSourceContext(SDBLParser.JoinPartContext joinPartCtx) { final List result; - if (joinPartCtx.LEFT() != null) { + if (joinPartCtx.leftJoin() != null) { result = Collections.singletonList(joinPartCtx.dataSource()); - } else if (joinPartCtx.RIGHT() != null) { + } else if (joinPartCtx.rightJoin() != null) { result = Collections.singletonList(((SDBLParser.DataSourceContext) joinPartCtx.getParent())); - } else if (joinPartCtx.FULL() != null) { + } else if (joinPartCtx.fullJoin() != null) { result = Arrays.asList(((SDBLParser.DataSourceContext) joinPartCtx.getParent()), joinPartCtx.dataSource()); } else { diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FullOuterJoinQueryDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FullOuterJoinQueryDiagnostic.java index a4eba273b87..521d0e63a48 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FullOuterJoinQueryDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FullOuterJoinQueryDiagnostic.java @@ -45,8 +45,8 @@ public class FullOuterJoinQueryDiagnostic extends AbstractSDBLVisitorDiagnostic @Override public ParseTree visitJoinPart(SDBLParser.JoinPartContext ctx) { - if (ctx.FULL() != null && ctx.JOIN() != null) { - diagnosticStorage.addDiagnostic(ctx.FULL(), ctx.JOIN()); + if (ctx.fullJoin() != null) { + diagnosticStorage.addDiagnostic(ctx.fullJoin()); } return super.visitJoinPart(ctx); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IfElseDuplicatedCodeBlockDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IfElseDuplicatedCodeBlockDiagnostic.java index 7dfe34fe478..eed8245d243 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IfElseDuplicatedCodeBlockDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IfElseDuplicatedCodeBlockDiagnostic.java @@ -32,6 +32,7 @@ import jakarta.annotation.PostConstruct; import org.antlr.v4.runtime.tree.ParseTree; import org.eclipse.lsp4j.DiagnosticRelatedInformation; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.HashSet; @@ -61,7 +62,7 @@ public void init() { } @Override - public ParseTree visitIfStatement(BSLParser.IfStatementContext ctx) { + public @Nullable ParseTree visitIfStatement(BSLParser.IfStatementContext ctx) { checkedBlocks.clear(); List codeBlocks = new ArrayList<>(); @@ -96,7 +97,7 @@ private void checkCodeBlock(List codeBlockContexts, .skip(i) .filter(codeBlockContext -> !codeBlockContext.equals(currentCodeBlock) - && !(currentCodeBlock.children == null && codeBlockContext.children == null) + && !(currentCodeBlock.getChildren().isEmpty() && codeBlockContext.getChildren().isEmpty()) && DiagnosticHelper.equalNodes(currentCodeBlock, codeBlockContext)) .toList(); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IncorrectUseOfStrTemplateDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IncorrectUseOfStrTemplateDiagnostic.java index 4ef6ff8b141..753028693e8 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IncorrectUseOfStrTemplateDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/IncorrectUseOfStrTemplateDiagnostic.java @@ -145,7 +145,7 @@ private static Optional getConstValue(Optional calcStringForMemberContext(memberContext, isFullSearch)); } - private static Optional calcStringForMemberContext(BSLParser.MemberContext memberContext, + private static Optional calcStringForMemberContext(BSLParser.MemberContext memberContext, boolean isFullSearch) { final var constValue = memberContext.constValue(); if (constValue != null) { @@ -161,8 +161,8 @@ private static Optional calcStringForMemberContext( } private static Optional calcAssignedValueForIdentifier( - BSLParser.ComplexIdentifierContext complexIdentifier) { - + BSLParser.ComplexIdentifierContext complexIdentifier) { + final var identifier = complexIdentifier.IDENTIFIER(); if (identifier == null) { return Optional.empty(); @@ -172,9 +172,9 @@ private static Optional calcAssignedValueForIdentif var prevStatement = (BSLParser.StatementContext) Objects.requireNonNull(Trees.getRootParent(complexIdentifier, BSLParser.RULE_statement)); while (true) { - prevStatement = (BSLParser.StatementContext) getPreviousNode(Objects.requireNonNull(prevStatement), + prevStatement = (BSLParser.StatementContext) getPreviousNode(Objects.requireNonNull(prevStatement), BSLParser.RULE_statement); - + if (prevStatement == null) { break; } @@ -191,8 +191,12 @@ private static Optional calcAssignedValueForIdentif @Nullable private static ParserRuleContext getPreviousNode(ParserRuleContext node, int ruleStatement) { + var parent = node.getParent(); + if (parent == null) { + return null; + } - final var children = node.getParent().children; + final var children = parent.getChildren(); final var pos = children.indexOf(node); if (pos > 0) { for (int i = pos - 1; i >= 0; i--) { diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MultilineStringInQueryDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MultilineStringInQueryDiagnostic.java index 58e03b14bff..9cbf07b5491 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MultilineStringInQueryDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MultilineStringInQueryDiagnostic.java @@ -41,7 +41,7 @@ scope = DiagnosticScope.BSL ) public class MultilineStringInQueryDiagnostic extends AbstractSDBLVisitorDiagnostic { - private static final int MULTI_STRING_MIN_SIZE = 2; // see SDBLParser grammar + private static final int MULTI_STRING_MIN_SIZE = 1; // see SDBLParser grammar @Override public ParseTree visitMultiString(SDBLParser.MultiStringContext ctx) { diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/ParseErrorDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/ParseErrorDiagnostic.java index 16f6691cc45..1f559082308 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/ParseErrorDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/ParseErrorDiagnostic.java @@ -88,11 +88,15 @@ public void enterFile(BSLParser.FileContext ctx) { } private static String getTokenName(int tokenType) { - String value = BSLLexer.VOCABULARY.getLiteralName(tokenType); + var value = BSLLexer.VOCABULARY.getLiteralName(tokenType); if (value == null) { value = BSLLexer.VOCABULARY.getSymbolicName(tokenType); } + if (value == null) { // вероятность равна нолю + value = ""; + } + return value; } } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RefOveruseDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RefOveruseDiagnostic.java index 04dc9880c08..5255fd58355 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RefOveruseDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/RefOveruseDiagnostic.java @@ -107,7 +107,7 @@ public ParseTree visitQueryPackage(SDBLParser.QueryPackageContext ctx) { } @Override - public ParseTree visitQuery(SDBLParser.QueryContext ctx) { + public @Nullable ParseTree visitQuery(SDBLParser.QueryContext ctx) { checkQuery(ctx).forEach(diagnosticStorage::addDiagnostic); return super.visitQuery(ctx); } @@ -312,7 +312,7 @@ private static int findLastRef(List children) { private static List extractFirstMetadataTypeName(SDBLParser.ColumnContext ctx) { final var mdoName = ctx.mdoName; - final var children = ctx.children; + final var children = ctx.getChildren(); if (mdoName == null || children.size() < COUNT_OF_TABLE_DOT_REF_DOT_REF || !METADATA_TYPES.contains(mdoName.getStart().getType())) { return children; diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnionAllDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnionAllDiagnostic.java index 3fb54d0fd0b..d7de0876073 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnionAllDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnionAllDiagnostic.java @@ -28,6 +28,7 @@ import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType; import com.github._1c_syntax.bsl.parser.SDBLParser; import org.antlr.v4.runtime.tree.ParseTree; +import org.jspecify.annotations.Nullable; @DiagnosticMetadata( type = DiagnosticType.CODE_SMELL, @@ -43,8 +44,8 @@ public class UnionAllDiagnostic extends AbstractSDBLVisitorDiagnostic { @Override - public ParseTree visitUnion(SDBLParser.UnionContext ctx) { - if (ctx.UNION() != null && ctx.ALL() != null) { + public @Nullable ParseTree visitUnion(SDBLParser.UnionContext ctx) { + if (ctx.UNION_ALL() != null) { return super.visitUnion(ctx); } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnsafeSafeModeMethodCallDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnsafeSafeModeMethodCallDiagnostic.java index 606f13c4ca1..a690a4f3de1 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnsafeSafeModeMethodCallDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnsafeSafeModeMethodCallDiagnostic.java @@ -87,12 +87,16 @@ private static boolean nonValidExpression(BSLParser.MemberContext currentRootMem return true; } - ParserRuleContext rootExpressionNode = currentRootMember.getParent(); + var rootExpressionNode = currentRootMember.getParent(); + if (rootExpressionNode == null) { + return false; + } - ParserRuleContext rootIfNode = Trees.getRootParent(rootExpressionNode, ROOT_LIST); + var rootIfNode = Trees.getRootParent(rootExpressionNode, ROOT_LIST); if (rootIfNode == null || rootIfNode.getRuleIndex() == BSLParser.RULE_codeBlock) { return false; } + if (rootExpressionNode.getChildCount() == 1 && IF_BRANCHES.contains(rootIfNode.getRuleIndex())) { return true; } @@ -103,9 +107,9 @@ private static boolean nonValidExpression(BSLParser.MemberContext currentRootMem private static boolean haveNeighboorBooleanOperator(ParserRuleContext currentRootMember, ParserRuleContext rootExpressionNode) { var haveNeighbourBoolOperation = false; - int indexOfCurrentMemberNode = rootExpressionNode.children.indexOf(currentRootMember); + int indexOfCurrentMemberNode = rootExpressionNode.getChildren().indexOf(currentRootMember); if (indexOfCurrentMemberNode > 0) { - var prev = (ParserRuleContext) rootExpressionNode.children.get(indexOfCurrentMemberNode - 1); + var prev = (ParserRuleContext) rootExpressionNode.getChildren().get(indexOfCurrentMemberNode - 1); if (Trees.nodeContains(prev, BSLParser.RULE_compareOperation)) { return false; } @@ -113,7 +117,7 @@ private static boolean haveNeighboorBooleanOperator(ParserRuleContext currentRoo } if (indexOfCurrentMemberNode < rootExpressionNode.getChildCount() - 1) { - var next = (ParserRuleContext) rootExpressionNode.children.get(indexOfCurrentMemberNode + 1); + var next = (ParserRuleContext) rootExpressionNode.getChildren().get(indexOfCurrentMemberNode + 1); if (Trees.nodeContains(next, BSLParser.RULE_compareOperation)) { return false; } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingFindElementByStringDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingFindElementByStringDiagnostic.java index 6fffacd2782..eebb0ce8dea 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingFindElementByStringDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingFindElementByStringDiagnostic.java @@ -29,7 +29,9 @@ import com.github._1c_syntax.bsl.parser.BSLParser; import com.github._1c_syntax.utils.CaseInsensitivePattern; import org.antlr.v4.runtime.tree.ParseTree; +import org.jspecify.annotations.Nullable; +import java.util.Optional; import java.util.regex.Pattern; @DiagnosticMetadata( @@ -51,14 +53,21 @@ public class UsingFindElementByStringDiagnostic extends AbstractVisitorDiagnosti ); @Override - public ParseTree visitMethodCall(BSLParser.MethodCallContext ctx) { - var matcher = pattern.matcher(ctx.methodName().getText()); - if (matcher.matches()) { - BSLParser.CallParamContext param = ctx.doCall().callParamList().callParam().get(0); - if (param.children == null || - param.getStart().getType() == BSLParser.STRING || - param.getStart().getType() == BSLParser.DECIMAL) { - diagnosticStorage.addDiagnostic(ctx, info.getMessage(matcher.group(0))); + public @Nullable ParseTree visitMethodCall(BSLParser.MethodCallContext ctx) { + var methodName = ctx.methodName(); + if (methodName != null) { + var matcher = pattern.matcher(methodName.getText()); + if (matcher.matches()) { + Optional.ofNullable(ctx.doCall()) + .map(BSLParser.DoCallContext::callParamList) + .ifPresent(callParamList -> { + var param = callParamList.callParam(0); + if (param == null || param.getChildren().isEmpty() || + param.getStart().getType() == BSLParser.STRING || + param.getStart().getType() == BSLParser.DECIMAL) { + diagnosticStorage.addDiagnostic(ctx, info.getMessage(matcher.group(0))); + } + }); } } return super.visitMethodCall(ctx); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AbstractASTDocumentHighlightSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AbstractASTDocumentHighlightSupplier.java index b0ef1381ca6..1c5745a65e5 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AbstractASTDocumentHighlightSupplier.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AbstractASTDocumentHighlightSupplier.java @@ -24,7 +24,6 @@ import com.github._1c_syntax.bsl.languageserver.utils.Ranges; import org.antlr.v4.runtime.tree.TerminalNode; import org.eclipse.lsp4j.DocumentHighlight; -import java.util.Optional; import org.jspecify.annotations.Nullable; import java.util.List; @@ -41,7 +40,7 @@ public abstract class AbstractASTDocumentHighlightSupplier implements DocumentHi *

* Используется для прямого доступа к токенам через геттеры ANTLR-контекста. * - * @param highlights Список подсветок, в который будет добавлена подсветка токена + * @param highlights Список подсветок, в который будет добавлена подсветка токена * @param terminalNode Терминальный узел с токеном (может быть null) */ protected void addTokenHighlight(List highlights, @Nullable TerminalNode terminalNode) { diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AbstractSDBLDocumentHighlightSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AbstractSDBLDocumentHighlightSupplier.java index 03d5ac69c6e..af5ce3a25ba 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AbstractSDBLDocumentHighlightSupplier.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AbstractSDBLDocumentHighlightSupplier.java @@ -28,12 +28,10 @@ import org.antlr.v4.runtime.tree.TerminalNode; import org.eclipse.lsp4j.DocumentHighlight; import org.eclipse.lsp4j.Position; -import java.util.Optional; import org.jspecify.annotations.Nullable; import java.util.List; import java.util.Optional; -import org.jspecify.annotations.Nullable; /** * Базовый класс для поставщиков подсветки в SDBL-запросах. diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/BracketDocumentHighlightSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/BracketDocumentHighlightSupplier.java index db66d702c9a..0e48f5d9763 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/BracketDocumentHighlightSupplier.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/BracketDocumentHighlightSupplier.java @@ -28,6 +28,8 @@ import org.eclipse.lsp4j.DocumentHighlight; import org.eclipse.lsp4j.DocumentHighlightParams; import java.util.Optional; + +import org.jspecify.annotations.Nullable; import org.springframework.stereotype.Component; import java.util.ArrayList; @@ -111,6 +113,7 @@ private List highlightMatchingBracket(Token token, DocumentCo return highlights; } + @Nullable private Token findMatchingBracket(Token token, List allTokens, int openType, int closeType, boolean isOpening) { int tokenIndex = token.getTokenIndex(); int depth = 1; diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/LoopStatementDocumentHighlightSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/LoopStatementDocumentHighlightSupplier.java index 04992731d22..314f38bd120 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/LoopStatementDocumentHighlightSupplier.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/LoopStatementDocumentHighlightSupplier.java @@ -26,13 +26,13 @@ import org.antlr.v4.runtime.ParserRuleContext; import org.eclipse.lsp4j.DocumentHighlight; import org.eclipse.lsp4j.DocumentHighlightParams; -import java.util.Optional; import org.jspecify.annotations.Nullable; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; /** * Поставщик подсветки для циклов (For/While/Do/EndDo). @@ -96,12 +96,11 @@ private ParserRuleContext findNearestLoopStatement(ParserRuleContext context) { while (current != null) { var ruleIndex = current.getRuleIndex(); if (ruleIndex == BSLParser.RULE_whileStatement - || ruleIndex == BSLParser.RULE_forStatement - || ruleIndex == BSLParser.RULE_forEachStatement) { + || ruleIndex == BSLParser.RULE_forStatement + || ruleIndex == BSLParser.RULE_forEachStatement) { return current; } - var parent = current.getParent(); - current = parent instanceof ParserRuleContext ? (ParserRuleContext) parent : null; + current = current.getParent(); } return null; } @@ -170,7 +169,7 @@ private List highlightForEachStatement(ParserRuleContext forE * Добавляет подсветку для break и continue внутри блока кода цикла. * Ищет только на первом уровне вложенности - не заходит во вложенные циклы. */ - private void addBreakAndContinueHighlights(List highlights, BSLParser.CodeBlockContext codeBlock) { + private void addBreakAndContinueHighlights(List highlights, BSLParser.@Nullable CodeBlockContext codeBlock) { if (codeBlock == null) { return; } @@ -210,7 +209,7 @@ private void addBreakAndContinueHighlights(List highlights, B * Ищет break/continue в if-блоках. */ private void addBreakAndContinueFromIfStatement(List highlights, - BSLParser.IfStatementContext ifStatement) { + BSLParser.IfStatementContext ifStatement) { var ifBranch = ifStatement.ifBranch(); if (ifBranch != null) { addBreakAndContinueHighlights(highlights, ifBranch.codeBlock()); @@ -230,8 +229,10 @@ private void addBreakAndContinueFromIfStatement(List highligh * Ищет break/continue в try-блоках. */ private void addBreakAndContinueFromTryStatement(List highlights, - BSLParser.TryStatementContext tryStatement) { - addBreakAndContinueHighlights(highlights, tryStatement.tryCodeBlock().codeBlock()); - addBreakAndContinueHighlights(highlights, tryStatement.exceptCodeBlock().codeBlock()); + BSLParser.TryStatementContext tryStatement) { + Optional.ofNullable(tryStatement.tryCodeBlock()) + .ifPresent(block -> addBreakAndContinueHighlights(highlights, block.codeBlock())); + Optional.ofNullable(tryStatement.exceptCodeBlock()) + .ifPresent(block -> addBreakAndContinueHighlights(highlights, block.codeBlock())); } } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/SDBLJoinDocumentHighlightSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/SDBLJoinDocumentHighlightSupplier.java index 1d26497fe22..ba1b154e6d3 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/SDBLJoinDocumentHighlightSupplier.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/SDBLJoinDocumentHighlightSupplier.java @@ -29,13 +29,13 @@ import org.eclipse.lsp4j.DocumentHighlight; import org.eclipse.lsp4j.DocumentHighlightParams; import org.eclipse.lsp4j.Position; -import java.util.Optional; import org.jspecify.annotations.Nullable; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; /** * Поставщик подсветки для конструкций JOIN в SDBL-запросах. @@ -79,13 +79,14 @@ public List getDocumentHighlight( private boolean isJoinKeyword(int tokenType) { return tokenType == SDBLLexer.JOIN - || tokenType == SDBLLexer.LEFT - || tokenType == SDBLLexer.RIGHT - || tokenType == SDBLLexer.FULL - || tokenType == SDBLLexer.INNER - || tokenType == SDBLLexer.OUTER - || tokenType == SDBLLexer.ON_EN - || tokenType == SDBLLexer.PO_RU; + || tokenType == SDBLLexer.LEFT_JOIN + || tokenType == SDBLLexer.LEFT_OUTER_JOIN + || tokenType == SDBLLexer.RIGHT_JOIN + || tokenType == SDBLLexer.RIGHT_OUTER_JOIN + || tokenType == SDBLLexer.FULL_JOIN + || tokenType == SDBLLexer.FULL_OUTER_JOIN + || tokenType == SDBLLexer.INNER_JOIN + || tokenType == SDBLLexer.BY; } private SDBLParser.@Nullable JoinPartContext findJoinPartAtPosition( @@ -107,20 +108,19 @@ private List highlightJoinPart(SDBLParser.JoinPartContext joi List highlights = new ArrayList<>(); // LEFT/RIGHT/FULL/INNER - addTerminalHighlight(highlights, joinCtx.LEFT()); - addTerminalHighlight(highlights, joinCtx.RIGHT()); - addTerminalHighlight(highlights, joinCtx.FULL()); - addTerminalHighlight(highlights, joinCtx.INNER()); + Optional.ofNullable(joinCtx.leftJoin()) + .ifPresent(join -> addTokenHighlight(highlights, join.keyword)); + + Optional.ofNullable(joinCtx.rightJoin()) + .ifPresent(join -> addTokenHighlight(highlights, join.keyword)); - // OUTER (опционально после LEFT/RIGHT/FULL) - addTerminalHighlight(highlights, joinCtx.OUTER()); + Optional.ofNullable(joinCtx.fullJoin()) + .ifPresent(join -> addTokenHighlight(highlights, join.keyword)); - // JOIN - addTerminalHighlight(highlights, joinCtx.JOIN()); + Optional.ofNullable(joinCtx.innerJoin()) + .ifPresent(join -> addTokenHighlight(highlights, join.keyword)); - // ON/ПО - addTerminalHighlight(highlights, joinCtx.ON_EN()); - addTerminalHighlight(highlights, joinCtx.PO_RU()); + addTerminalHighlight(highlights, joinCtx.BY()); return highlights; } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/SelectionRangeProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/SelectionRangeProvider.java index 5e56eeadb8f..6db1014e0a9 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/SelectionRangeProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/SelectionRangeProvider.java @@ -180,8 +180,7 @@ private static ParserRuleContext getStatementParent(BSLParser.StatementContext s if (!nearbyStatements.isEmpty() && (nearbyStatements.size() + 1 != children.size())) { - var statementsBlock = new ParserRuleContext(); - statementsBlock.setParent(parent); + var statementsBlock = new ParserRuleContext(parent, -1); // todo стоит переделать nearbyStatements.add(statement); nearbyStatements.sort(Comparator.comparing(ruleContext -> ruleContext.getStart().getLine())); @@ -207,6 +206,6 @@ private static boolean ifBranchMatchesIfStatement(ParserRuleContext ctx) { } var ifStatement = (BSLParser.IfStatementContext) ifBranch.getParent(); - return ifStatement.elseBranch() == null && ifStatement.elsifBranch().isEmpty(); + return ifStatement != null && ifStatement.elseBranch() == null && ifStatement.elsifBranch().isEmpty(); } } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/strings/SdblTokenTypes.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/strings/SdblTokenTypes.java index 9be931a7bd7..5a6103b1d9e 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/strings/SdblTokenTypes.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/strings/SdblTokenTypes.java @@ -96,14 +96,14 @@ public static SdblTokenTypeAndModifiers getTokenTypeAndModifiers(int tokenType) private static Set createSdblKeywords() { return Set.of( - SDBLLexer.ALL, SDBLLexer.ALLOWED, + SDBLLexer.ADD, SDBLLexer.AND, SDBLLexer.AS, SDBLLexer.ASC, SDBLLexer.AUTOORDER, SDBLLexer.BETWEEN, - SDBLLexer.BY_EN, + SDBLLexer.BY, SDBLLexer.CASE, SDBLLexer.CAST, SDBLLexer.DESC, @@ -112,53 +112,59 @@ private static Set createSdblKeywords() { SDBLLexer.ELSE, SDBLLexer.END, SDBLLexer.ESCAPE, - SDBLLexer.FOR, SDBLLexer.FROM, - SDBLLexer.FULL, - SDBLLexer.GROUP, SDBLLexer.HAVING, - SDBLLexer.HIERARCHY, - SDBLLexer.HIERARCHY_FOR_IN, - SDBLLexer.IN, - SDBLLexer.INDEX, - SDBLLexer.INNER, SDBLLexer.INTO, SDBLLexer.IS, - SDBLLexer.JOIN, - SDBLLexer.LEFT, SDBLLexer.LIKE, SDBLLexer.NOT, SDBLLexer.OF, - SDBLLexer.ONLY, - SDBLLexer.ON_EN, SDBLLexer.OR, - SDBLLexer.ORDER, SDBLLexer.OVERALL, - SDBLLexer.OUTER, - SDBLLexer.PERIODS, - SDBLLexer.PO_RU, - SDBLLexer.REFS, - SDBLLexer.RIGHT, SDBLLexer.SELECT, - SDBLLexer.SET, SDBLLexer.THEN, SDBLLexer.TOP, SDBLLexer.TOTALS, - SDBLLexer.UNION, - SDBLLexer.UPDATE, SDBLLexer.WHEN, SDBLLexer.WHERE, SDBLLexer.EMPTYREF, - SDBLLexer.GROUPEDBY, - SDBLLexer.GROUPING + SDBLLexer.UNIQUE, + SDBLLexer.PERIODS, + SDBLLexer.REFS, + SDBLLexer.INDEX_BY_SETS, + SDBLLexer.INDEX_BY, + SDBLLexer.GROUP_BY_GROUPING_SETS, + SDBLLexer.GROUP_BY, + SDBLLexer.ORDER_BY, + SDBLLexer.FOR_UPDATE, + SDBLLexer.RIGHT_OUTER_JOIN, + SDBLLexer.RIGHT_JOIN, + SDBLLexer.LEFT_OUTER_JOIN, + SDBLLexer.LEFT_JOIN, + SDBLLexer.FULL_OUTER_JOIN, + SDBLLexer.FULL_JOIN, + SDBLLexer.INNER_JOIN, + SDBLLexer.JOIN, + SDBLLexer.UNION_ALL, + SDBLLexer.UNION, + SDBLLexer.ONLY_HIERARCHY, + SDBLLexer.HIERARCHY, + SDBLLexer.IN_HIERARCHY, + SDBLLexer.IN, + SDBLLexer.GROUPEDBY ); } private static Set createSdblFunctions() { return Set.of( + SDBLLexer.ISNULL, + SDBLLexer.ACOS, + SDBLLexer.ASIN, + SDBLLexer.ATAN, SDBLLexer.AVG, SDBLLexer.BEGINOFPERIOD, SDBLLexer.BOOLEAN, + SDBLLexer.COS, SDBLLexer.COUNT, SDBLLexer.DATE, SDBLLexer.DATEADD, @@ -168,9 +174,14 @@ private static Set createSdblFunctions() { SDBLLexer.DAYOFYEAR, SDBLLexer.EMPTYTABLE, SDBLLexer.ENDOFPERIOD, + SDBLLexer.EXP, SDBLLexer.HALFYEAR, SDBLLexer.HOUR, - SDBLLexer.ISNULL, + SDBLLexer.INT, + SDBLLexer.LEFT, + SDBLLexer.LOG, + SDBLLexer.LOG10, + SDBLLexer.LOWER, SDBLLexer.MAX, SDBLLexer.MIN, SDBLLexer.MINUTE, @@ -180,40 +191,32 @@ private static Set createSdblFunctions() { SDBLLexer.PRESENTATION, SDBLLexer.RECORDAUTONUMBER, SDBLLexer.REFPRESENTATION, + SDBLLexer.POW, + SDBLLexer.RIGHT, + SDBLLexer.ROUND, SDBLLexer.SECOND, + SDBLLexer.SIN, + SDBLLexer.SQRT, + SDBLLexer.STOREDDATASIZE, SDBLLexer.STRING, + SDBLLexer.STRINGLENGTH, + SDBLLexer.STRFIND, + SDBLLexer.STRREPLACE, SDBLLexer.SUBSTRING, SDBLLexer.SUM, + SDBLLexer.TAN, SDBLLexer.TENDAYS, + SDBLLexer.TRIMALL, + SDBLLexer.TRIML, + SDBLLexer.TRIMR, SDBLLexer.TYPE, + SDBLLexer.UPPER, SDBLLexer.VALUE, SDBLLexer.VALUETYPE, SDBLLexer.WEEK, SDBLLexer.WEEKDAY, SDBLLexer.YEAR, - SDBLLexer.INT, - SDBLLexer.ACOS, - SDBLLexer.ASIN, - SDBLLexer.ATAN, - SDBLLexer.COS, - SDBLLexer.SIN, - SDBLLexer.TAN, - SDBLLexer.LOG, - SDBLLexer.LOG10, - SDBLLexer.EXP, - SDBLLexer.POW, - SDBLLexer.SQRT, - SDBLLexer.LOWER, - SDBLLexer.STRINGLENGTH, - SDBLLexer.TRIMALL, - SDBLLexer.TRIML, - SDBLLexer.TRIMR, - SDBLLexer.UPPER, - SDBLLexer.ROUND, - SDBLLexer.STOREDDATASIZE, - SDBLLexer.UUID, - SDBLLexer.STRFIND, - SDBLLexer.STRREPLACE + SDBLLexer.UUID ); } @@ -251,22 +254,22 @@ private static Set createSdblLiterals() { private static Set createSdblOperators() { return Set.of( - SDBLLexer.SEMICOLON, SDBLLexer.DOT, + SDBLLexer.SEMICOLON, + SDBLLexer.COMMA, + SDBLLexer.ASSIGN, SDBLLexer.PLUS, SDBLLexer.MINUS, - SDBLLexer.MUL, - SDBLLexer.QUOTIENT, - SDBLLexer.ASSIGN, SDBLLexer.LESS_OR_EQUAL, - SDBLLexer.LESS, SDBLLexer.NOT_EQUAL, + SDBLLexer.LESS, SDBLLexer.GREATER_OR_EQUAL, SDBLLexer.GREATER, - SDBLLexer.COMMA, + SDBLLexer.MUL, + SDBLLexer.QUOTIENT, + SDBLLexer.NUMBER_SIGH, SDBLLexer.BRACE, - SDBLLexer.BRACE_START, - SDBLLexer.NUMBER_SIGH + SDBLLexer.BRACE_START ); } } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/strings/SpecialContextVisitor.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/strings/SpecialContextVisitor.java index e641b3755f6..a0c583b8dd2 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/strings/SpecialContextVisitor.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/strings/SpecialContextVisitor.java @@ -273,11 +273,7 @@ private String extractVariableName(BSLParser.CallParamContext callParam) { return null; } - var children = parent.children; - if (children == null) { - return null; - } - + var children = parent.getChildren(); int pos = children.indexOf(statement); for (int i = pos - 1; i >= 0; i--) { var child = children.get(i); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/DiagnosticHelper.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/DiagnosticHelper.java index 19cda7b17e9..839bc9faad8 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/DiagnosticHelper.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/DiagnosticHelper.java @@ -56,8 +56,10 @@ public final class DiagnosticHelper { * @param rightNode Второй узел для сравнения * @return true, если узлы эквивалентны */ - public static boolean equalNodes(Tree leftNode, Tree rightNode) { - + public static boolean equalNodes(@Nullable Tree leftNode, @Nullable Tree rightNode) { + if (leftNode == null || rightNode == null) { + return false; + } if (leftNode.getChildCount() != rightNode.getChildCount() || !leftNode.getClass().equals(rightNode.getClass())) { return false; diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/Ranges.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/Ranges.java index 4688df0140c..0645b5ae23f 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/Ranges.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/Ranges.java @@ -21,8 +21,6 @@ */ package com.github._1c_syntax.bsl.languageserver.utils; -import com.github._1c_syntax.bsl.languageserver.context.symbol.ModuleSymbol; -import com.github._1c_syntax.bsl.parser.BSLLexer; import lombok.experimental.UtilityClass; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; @@ -32,16 +30,16 @@ import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.jsonrpc.util.Preconditions; import org.eclipse.lsp4j.util.Positions; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -import java.util.Collection; import java.util.List; -import java.util.Optional; /** * Набор методов для удобства работы с областями текста (ренджами) */ @UtilityClass +@NullMarked public final class Ranges { /** @@ -68,8 +66,8 @@ public Range create() { * * @param startLine Начальная строка * @param startChar Начальный символ - * @param endLine Конечная строка - * @param endChar Конечный символ + * @param endLine Конечная строка + * @param endChar Конечный символ * @return Созданный диапазон */ public Range create(int startLine, int startChar, int endLine, int endChar) { @@ -94,7 +92,10 @@ public Range create(int lineNo, int startChar, int endChar) { * @param ruleContext Контекст правила * @return Диапазон, покрывающий весь контекст */ - public Range create(ParserRuleContext ruleContext) { + public Range create(@Nullable ParserRuleContext ruleContext) { + if (ruleContext == null) { + return create(); + } return create(ruleContext.getStart(), ruleContext.getStop()); } @@ -102,7 +103,7 @@ public Range create(ParserRuleContext ruleContext) { * Создать диапазон от начала одного контекста до конца другого. * * @param startCtx Начальный контекст - * @param endCtx Конечный контекст + * @param endCtx Конечный контекст * @return Диапазон между контекстами */ public Range create(ParserRuleContext startCtx, ParserRuleContext endCtx) { @@ -113,7 +114,7 @@ public Range create(ParserRuleContext startCtx, ParserRuleContext endCtx) { * Создать диапазон из токенов. * * @param startToken Начальный токен - * @param endToken Конечный токен + * @param endToken Конечный токен * @return Диапазон между токенами */ public Range create(Token startToken, @Nullable Token endToken) { @@ -153,7 +154,10 @@ public Range create(List tokens) { * @param terminalNode Терминальный узел * @return Диапазон узла */ - public Range create(TerminalNode terminalNode) { + public Range create(@Nullable TerminalNode terminalNode) { + if (terminalNode == null) { + return create(); + } return create(terminalNode.getSymbol()); } @@ -161,7 +165,7 @@ public Range create(TerminalNode terminalNode) { * Создать диапазон между двумя терминальными узлами. * * @param startTerminalNode Начальный узел - * @param stopTerminalNode Конечный узел + * @param stopTerminalNode Конечный узел * @return Диапазон между узлами */ public Range create(TerminalNode startTerminalNode, TerminalNode stopTerminalNode) { @@ -210,7 +214,7 @@ public boolean containsPosition(Range range, Position position) { Preconditions.checkNotNull(position, "position"); return range.getStart().equals(position) || (Positions.isBefore(range.getStart(), position) - && Positions.isBefore(position, range.getEnd())); + && Positions.isBefore(position, range.getEnd())); } /** @@ -275,7 +279,6 @@ private boolean isBefore(int line1, int character1, int line2, int character2) { } - /** * Натуральный порядок сравнения Range * @@ -284,11 +287,11 @@ private boolean isBefore(int line1, int character1, int line2, int character2) { * @return 0 - равно, 1 - больше, -1 - меньше */ public int compare(Range o1, Range o2) { - if (o1.equals(o2)){ + if (o1.equals(o2)) { return 0; } final var startCompare = compare(o1.getStart(), o2.getStart()); - if (startCompare != 0){ + if (startCompare != 0) { return startCompare; } return compare(o1.getEnd(), o2.getEnd()); @@ -302,7 +305,7 @@ public int compare(Range o1, Range o2) { * @return 0 - равно, 1 - больше, -1 - меньше */ public int compare(Position pos1, Position pos2) { - if (pos1.equals(pos2)){ + if (pos1.equals(pos2)) { return 0; } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/ExpressionTreeBuildingVisitor.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/ExpressionTreeBuildingVisitor.java index bfab6875415..2b2aa3cc404 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/ExpressionTreeBuildingVisitor.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/ExpressionTreeBuildingVisitor.java @@ -92,7 +92,7 @@ public ParseTree visitExpression(BSLParser.ExpressionContext ctx) { var nestingCount = operatorsInFly.size(); recursionLevel++; - if (Trees.nodeContainsErrors(ctx) || (ctx.getChildCount() == 0 || ctx.children.stream().anyMatch(ErrorNode.class::isInstance))) { + if (Trees.nodeContainsErrors(ctx) || (ctx.getChildCount() == 0 || ctx.getChildren().stream().anyMatch(ErrorNode.class::isInstance))) { var errorExpressionNode = new ErrorExpressionNode(ctx); if (recursionLevel > 0) { operands.push(errorExpressionNode); @@ -147,10 +147,10 @@ public ParseTree visitExpression(BSLParser.ExpressionContext ctx) { } @Override - public ParseTree visitMember(BSLParser.MemberContext ctx) { + public @Nullable ParseTree visitMember(BSLParser.MemberContext ctx) { // В случае ошибки парсинга member может быть пустой. - if (Trees.nodeContainsErrors(ctx) || ctx.getChildCount() == 0 || ctx.children.stream().anyMatch(ErrorNode.class::isInstance)) { + if (Trees.nodeContainsErrors(ctx) || ctx.getChildCount() == 0 || ctx.getChildren().stream().anyMatch(ErrorNode.class::isInstance)) { operands.push(new ErrorExpressionNode(ctx)); return ctx; } @@ -168,7 +168,7 @@ public ParseTree visitMember(BSLParser.MemberContext ctx) { if (unaryModifier != null) { visitUnaryModifier(unaryModifier); - childIndex = ctx.children.indexOf(unaryModifier) + 1; + childIndex = ctx.getChildren().indexOf(unaryModifier) + 1; } if (ctx.waitExpression() != null) { @@ -299,7 +299,7 @@ public ParseTree visitConstValue(BSLParser.ConstValueContext ctx) { @Override public ParseTree visitUnaryModifier(BSLParser.UnaryModifierContext ctx) { var child = (TerminalNode) ctx.getChild(0); - var token = (child).getSymbol().getType(); + var token = child.getSymbol().getType(); var operator = switch (token) { case BSLLexer.PLUS -> BslOperator.UNARY_PLUS; @@ -318,7 +318,7 @@ public ParseTree visitComplexIdentifier(BSLParser.ComplexIdentifierContext ctx) if (ctx.IDENTIFIER() != null) { operands.push(TerminalSymbolNode.identifier(ctx.IDENTIFIER())); } else { - var childVariant = ctx.children.get(0); + var childVariant = ctx.getChildren().get(0); childVariant.accept(this); } @@ -413,10 +413,12 @@ public ParseTree visitAccessIndex(BSLParser.AccessIndexContext ctx) { public ParseTree visitAccessCall(BSLParser.AccessCallContext ctx) { var target = operands.pop(); var methodCall = ctx.methodCall(); - var callNode = MethodCallNode.create(methodCall.methodName().IDENTIFIER()); - addCallArguments(callNode, methodCall.doCall().callParamList().callParam()); - var operation = BinaryOperationNode.create(BslOperator.DEREFERENCE, target, callNode, ctx); - operands.push(operation); + if (methodCall != null) { + var callNode = MethodCallNode.create(methodCall.methodName().IDENTIFIER()); + addCallArguments(callNode, methodCall.doCall().callParamList().callParam()); + var operation = BinaryOperationNode.create(BslOperator.DEREFERENCE, target, callNode, ctx); + operands.push(operation); + } return ctx; } @@ -442,7 +444,7 @@ public ParseTree visitTernaryOperator(BSLParser.TernaryOperatorContext ctx) { return ctx; } - private static @Nullable BslExpression makeSubexpression(BSLParser.ExpressionContext ctx) { + private static @Nullable BslExpression makeSubexpression(BSLParser.@Nullable ExpressionContext ctx) { return buildExpressionTree(ctx); } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/TerminalSymbolNode.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/TerminalSymbolNode.java index 296cddac19d..6beaf196879 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/TerminalSymbolNode.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/TerminalSymbolNode.java @@ -24,6 +24,7 @@ import com.github._1c_syntax.bsl.parser.BSLParser; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; +import org.jspecify.annotations.Nullable; /** * Терминальный узел дерева выражений. @@ -32,7 +33,7 @@ * числа, строки, булевы значения, Неопределено, имена переменных. */ public class TerminalSymbolNode extends BslExpression { - private TerminalSymbolNode(ExpressionNodeType type, ParseTree representingAst) { + private TerminalSymbolNode(ExpressionNodeType type, @Nullable ParseTree representingAst) { super(type, representingAst, null); } @@ -48,7 +49,7 @@ public static TerminalSymbolNode literal(BSLParser.ConstValueContext constant) { * @param constant константа * @return терминал константы */ - public static TerminalSymbolNode literal(TerminalNode constant) { + public static TerminalSymbolNode literal(@Nullable TerminalNode constant) { return new TerminalSymbolNode(ExpressionNodeType.LITERAL, constant); } @@ -56,7 +57,7 @@ public static TerminalSymbolNode literal(TerminalNode constant) { * @param identifier идентификатор * @return терминал идентификатора */ - public static TerminalSymbolNode identifier(TerminalNode identifier) { + public static TerminalSymbolNode identifier(@Nullable TerminalNode identifier) { return new TerminalSymbolNode(ExpressionNodeType.IDENTIFIER, identifier); } } diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingFindElementByStringDiagnosticTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingFindElementByStringDiagnosticTest.java index 17057f4e1cc..55d60194cb2 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingFindElementByStringDiagnosticTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UsingFindElementByStringDiagnosticTest.java @@ -28,7 +28,6 @@ import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat; - class UsingFindElementByStringDiagnosticTest extends AbstractDiagnosticTest { UsingFindElementByStringDiagnosticTest() { diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AllKnownTokenTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AllKnownTokenTest.java new file mode 100644 index 00000000000..18efeed93be --- /dev/null +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/AllKnownTokenTest.java @@ -0,0 +1,91 @@ +/* + * This file is a part of BSL Language Server. + * + * Copyright (c) 2018-2026 + * Alexey Sosnoviy , Nikita Fedkin and contributors + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * BSL Language Server is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * BSL Language Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with BSL Language Server. + */ +package com.github._1c_syntax.bsl.languageserver.documenthighlight; + +import com.github._1c_syntax.bsl.languageserver.semantictokens.strings.SdblTokenTypes; +import com.github._1c_syntax.bsl.parser.BSLLexer; +import com.github._1c_syntax.bsl.parser.SDBLLexer; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Тесты для проверки того, что обо всех токенах лексера было известно + */ +public class AllKnownTokenTest { + + private static final Set skippedSdblToken = Set.of( + SDBLLexer.WHITE_SPACE, + SDBLLexer.LPAREN, + SDBLLexer.RPAREN, + SDBLLexer.AMPERSAND, + SDBLLexer.ROUTEPOINT_FIELD, + SDBLLexer.INCORRECT_IDENTIFIER, + SDBLLexer.IDENTIFIER, + SDBLLexer.UNKNOWN, + SDBLLexer.PARAMETER_IDENTIFIER, + SDBLLexer.ACTUAL_ACTION_PERIOD_VT, + SDBLLexer.BALANCE_VT, + SDBLLexer.BALANCE_AND_TURNOVERS_VT, + SDBLLexer.BOUNDARIES_VT, + SDBLLexer.DR_CR_TURNOVERS_VT, + SDBLLexer.EXT_DIMENSIONS_VT, + SDBLLexer.RECORDS_WITH_EXT_DIMENSIONS_VT, + SDBLLexer.SCHEDULE_DATA_VT, + SDBLLexer.SLICEFIRST_VT, + SDBLLexer.SLICELAST_VT, + SDBLLexer.TASK_BY_PERFORMER_VT, + SDBLLexer.TURNOVERS_VT + ); + + @Test + void sdblTokens() { + List unknown = new ArrayList<>(); + // токены имею индекс от одного максимального + var endToken = SDBLLexer.VOCABULARY.getMaxTokenType(); + for (int i = 1; i <= endToken; i++) { + var type = SdblTokenTypes.getTokenTypeAndModifiers(i); + if (type == null) { + // проверим на исключения + if (!skippedSdblToken.contains(i)) { + unknown.add("Type=%s, name %s".formatted(i, SDBLLexer.VOCABULARY.getSymbolicName(i))); + } + } + } + + assertThat(unknown).isEmpty(); + } + + @Test + @Disabled("Заготовка. Надо реализовать аналог для bsl lexer") + void bslTokens() { + List unknown = new ArrayList<>(); + // токены имею индекс от одного максимального + var endToken = BSLLexer.VOCABULARY.getMaxTokenType(); + assertThat(unknown).isEmpty(); + } +} diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/SDBLJoinDocumentHighlightSupplierTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/SDBLJoinDocumentHighlightSupplierTest.java index 69b5a3def2c..5b6c837720f 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/SDBLJoinDocumentHighlightSupplierTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/documenthighlight/SDBLJoinDocumentHighlightSupplierTest.java @@ -60,11 +60,10 @@ void testLeftKeyword() { // then assertThat(highlights).isNotEmpty(); // Должны подсветиться: ЛЕВОЕ, СОЕДИНЕНИЕ, ПО (первого JOIN) - assertThat(highlights).hasSize(3); + assertThat(highlights).hasSize(2); // Проверяем точные позиции - assertHighlightRange(highlights, 10, 5, 10, 10); // ЛЕВОЕ - assertHighlightRange(highlights, 10, 11, 10, 21); // СОЕДИНЕНИЕ + assertHighlightRange(highlights, 10, 5, 10, 21); // ЛЕВОЕ СОЕДИНЕНИЕ assertHighlightRange(highlights, 11, 8, 11, 10); // ПО } @@ -83,11 +82,10 @@ void testJoinKeyword() { // then assertThat(highlights).isNotEmpty(); - assertThat(highlights).hasSize(3); + assertThat(highlights).hasSize(2); // Проверяем точные позиции - assertHighlightRange(highlights, 10, 5, 10, 10); // ЛЕВОЕ - assertHighlightRange(highlights, 10, 11, 10, 21); // СОЕДИНЕНИЕ + assertHighlightRange(highlights, 10, 5, 10, 21); // ЛЕВОЕ соединение assertHighlightRange(highlights, 11, 8, 11, 10); // ПО } @@ -106,11 +104,10 @@ void testOnKeyword() { // then assertThat(highlights).isNotEmpty(); - assertThat(highlights).hasSize(3); + assertThat(highlights).hasSize(2); // Проверяем точные позиции - assertHighlightRange(highlights, 10, 5, 10, 10); // ЛЕВОЕ - assertHighlightRange(highlights, 10, 11, 10, 21); // СОЕДИНЕНИЕ + assertHighlightRange(highlights, 10, 5, 10, 21); // ЛЕВОЕ СОЕДИНЕНИЕ assertHighlightRange(highlights, 11, 8, 11, 10); // ПО } diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SemanticTokensProviderTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SemanticTokensProviderTest.java index 329acf5e7ed..8ea92022395 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SemanticTokensProviderTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SemanticTokensProviderTest.java @@ -928,8 +928,7 @@ void sdblQuery_complexQueryWithJoin() { new ExpectedToken(7, 56, 3, SemanticTokenTypes.Keyword, "КАК"), new ExpectedToken(7, 60, 5, SemanticTokenTypes.Variable, SemanticTokenModifiers.Declaration, "Курсы"), // Line 8: ИНДЕКСИРОВАТЬ ПО Валюта, Период - new ExpectedToken(8, 3, 13, SemanticTokenTypes.Keyword, "ИНДЕКСИРОВАТЬ"), - new ExpectedToken(8, 17, 2, SemanticTokenTypes.Keyword, "ПО"), + new ExpectedToken(8, 3, 16, SemanticTokenTypes.Keyword, "ИНДЕКСИРОВАТЬ ПО"), // Second query - line 10: ВЫБРАТЬ new ExpectedToken(10, 3, 7, SemanticTokenTypes.Keyword, "ВЫБРАТЬ"), // Line 14: ИЗ ВТ_Курсы КАК ВТ @@ -938,8 +937,7 @@ void sdblQuery_complexQueryWithJoin() { new ExpectedToken(14, 15, 3, SemanticTokenTypes.Keyword, "КАК"), new ExpectedToken(14, 19, 2, SemanticTokenTypes.Variable, SemanticTokenModifiers.Declaration, "ВТ"), // Line 15: ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Валюты КАК СпрВалюта - new ExpectedToken(15, 3, 5, SemanticTokenTypes.Keyword, "ЛЕВОЕ"), - new ExpectedToken(15, 9, 10, SemanticTokenTypes.Keyword, "СОЕДИНЕНИЕ"), + new ExpectedToken(15, 3, 16, SemanticTokenTypes.Keyword, "ЛЕВОЕ СОЕДИНЕНИЕ"), new ExpectedToken(15, 20, 10, SemanticTokenTypes.Namespace, "Справочник"), new ExpectedToken(15, 31, 6, SemanticTokenTypes.Class, "Валюты"), new ExpectedToken(15, 38, 3, SemanticTokenTypes.Keyword, "КАК"),