diff --git a/docs/diagnostics/MagicDate.md b/docs/diagnostics/MagicDate.md index 9f76aaa598b..986489a1b5c 100644 --- a/docs/diagnostics/MagicDate.md +++ b/docs/diagnostics/MagicDate.md @@ -22,3 +22,16 @@ ХоверБордБудетИзобретен = Неопределено; КонецЕсли; ``` + +Также хорошим решением является использование специального метода с говорящим названием, который возвращает +дату-константу + +```bsl +Функция ДатаИзобретенияХовера() + Возврат '20151021'; +КонецФункции + +Если текДата < ДатаИзобретенияХовера() Тогда + ХоверБордБудетИзобретен = Неопределено; +КонецЕсли; +``` diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MagicDateDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MagicDateDiagnostic.java index fc611406a09..eb8df9b7e00 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MagicDateDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/MagicDateDiagnostic.java @@ -72,42 +72,33 @@ public class MagicDateDiagnostic extends AbstractVisitorDiagnostic { ) private final Set authorizedDates = new HashSet<>(Arrays.asList(DEFAULT_AUTHORIZED_DATES.split(","))); - private static Optional getExpression(Optional contextOptional) { - return contextOptional - .map(BSLParserRuleContext::getParent) - .filter(context -> context.getChildCount() == 1) - .map(BSLParserRuleContext::getParent) - .filter(context -> context.getChildCount() == 1) - .filter(BSLParser.ExpressionContext.class::isInstance); + @Override + public void configure(Map configuration) { + var authorizedDatesString = (String) configuration.getOrDefault("authorizedDates", DEFAULT_AUTHORIZED_DATES); + Set authD = Arrays.stream(authorizedDatesString.split(",")) + .map(String::trim) + .collect(Collectors.toSet()); + authorizedDates.clear(); + authorizedDates.addAll(authD); } - private static boolean insideSimpleDateAssignment(Optional expressionContext) { - return expressionContext - .map(BSLParserRuleContext::getParent) - .filter(BSLParser.AssignmentContext.class::isInstance) - .isPresent(); - } + @Override + public ParseTree visitConstValue(BSLParser.ConstValueContext ctx) { + var tNode = ctx.DATETIME(); + var sNode = ctx.string(); + if ((tNode != null || sNode != null) && isAccepted(ctx)) { + if (sNode != null && !isValidDate(sNode)) { + return defaultResult(); + } - private static boolean insideAssignmentWithDateMethodForSimpleDate(Optional expressionContext) { - return expressionContext - .map(BSLParserRuleContext::getParent) // callParam - .filter(context -> context.getChildCount() == 1) - .map(BSLParserRuleContext::getParent) // callParamList - .filter(context -> context.getChildCount() == 1) - .map(BSLParserRuleContext::getParent) // doCall - .map(BSLParserRuleContext::getParent) // globalCall - метод Дата(ХХХ) - .filter(BSLParser.GlobalMethodCallContext.class::isInstance) - .map(BSLParser.GlobalMethodCallContext.class::cast) - .filter(context -> methodPattern.matcher(context.methodName().getText()).matches()) - .map(BSLParserRuleContext::getParent) // complexId - .filter(context -> context.getChildCount() == 1) - .map(BSLParserRuleContext::getParent) // member - .filter(context -> context.getChildCount() == 1) - .map(BSLParserRuleContext::getParent) // expression - .filter(context -> context.getChildCount() == 1) - .map(BSLParserRuleContext::getParent) - .filter(BSLParser.AssignmentContext.class::isInstance) - .isPresent(); + final var expressionContext = getExpression(Optional.of(ctx)); + if (!insideSimpleDateAssignment(expressionContext) && !insideReturnSimpleDate(expressionContext) + && !insideAssignmentWithDateMethodForSimpleDate(expressionContext)) { + diagnosticStorage.addDiagnostic(ctx, info.getMessage(ctx.getText())); + } + } + + return defaultResult(); } private static boolean isValidDate(BSLParser.StringContext ctx) { @@ -147,35 +138,6 @@ private static int parseInt(String text) { } } - @Override - public void configure(Map configuration) { - var authorizedDatesString = (String) configuration.getOrDefault("authorizedDates", DEFAULT_AUTHORIZED_DATES); - Set authD = Arrays.stream(authorizedDatesString.split(",")) - .map(String::trim) - .collect(Collectors.toSet()); - authorizedDates.clear(); - authorizedDates.addAll(authD); - } - - @Override - public ParseTree visitConstValue(BSLParser.ConstValueContext ctx) { - var tNode = ctx.DATETIME(); - var sNode = ctx.string(); - if ((tNode != null || sNode != null) && isAccepted(ctx)) { - if (sNode != null && !isValidDate(sNode)) { - return defaultResult(); - } - - final var expressionContext = getExpression(Optional.of(ctx)); - if (!insideSimpleDateAssignment(expressionContext) - && !insideAssignmentWithDateMethodForSimpleDate(expressionContext)) { - diagnosticStorage.addDiagnostic(ctx, info.getMessage(ctx.getText())); - } - } - - return defaultResult(); - } - private boolean isAccepted(BSLParser.ConstValueContext ctx) { String text = ctx.getText(); return text != null && !text.isEmpty() && !isExcluded(text); @@ -185,4 +147,52 @@ private boolean isExcluded(String text) { String s = nonNumberPattern.matcher(text).replaceAll(""); return authorizedDates.contains(s); } + + private static Optional getExpression(Optional constValue) { + return constValue + .map(BSLParserRuleContext::getParent) + .filter(context -> context.getChildCount() == 1) + .map(BSLParserRuleContext::getParent) + .filter(context -> context.getChildCount() == 1) + .filter(BSLParser.ExpressionContext.class::isInstance) + .map(BSLParser.ExpressionContext.class::cast); + } + + private static boolean insideSimpleDateAssignment(Optional expression) { + return insideContext(expression, BSLParser.AssignmentContext.class); + } + + private static boolean insideContext(Optional expression, + Class assignmentContextClass) { + return expression + .map(BSLParserRuleContext::getParent) + .filter(assignmentContextClass::isInstance) + .isPresent(); + } + + private static boolean insideReturnSimpleDate(Optional expression) { + return insideContext(expression, BSLParser.ReturnStatementContext.class); + } + + private static boolean insideAssignmentWithDateMethodForSimpleDate(Optional expression) { + return expression + .map(BSLParserRuleContext::getParent) // callParam + .filter(context -> context.getChildCount() == 1) + .map(BSLParserRuleContext::getParent) // callParamList + .filter(context -> context.getChildCount() == 1) + .map(BSLParserRuleContext::getParent) // doCall + .map(BSLParserRuleContext::getParent) // globalCall - метод Дата(ХХХ) + .filter(BSLParser.GlobalMethodCallContext.class::isInstance) + .map(BSLParser.GlobalMethodCallContext.class::cast) + .filter(context -> methodPattern.matcher(context.methodName().getText()).matches()) + .map(BSLParserRuleContext::getParent) // complexId + .filter(context -> context.getChildCount() == 1) + .map(BSLParserRuleContext::getParent) // member + .filter(context -> context.getChildCount() == 1) + .map(BSLParserRuleContext::getParent) // expression + .filter(context -> context.getChildCount() == 1) + .map(BSLParserRuleContext::getParent) + .filter(BSLParser.AssignmentContext.class::isInstance) + .isPresent(); + } } diff --git a/src/test/resources/diagnostics/MagicDateDiagnostic.bsl b/src/test/resources/diagnostics/MagicDateDiagnostic.bsl index a89df894f87..f83a88c487c 100644 --- a/src/test/resources/diagnostics/MagicDateDiagnostic.bsl +++ b/src/test/resources/diagnostics/MagicDateDiagnostic.bsl @@ -1,9 +1,9 @@ Функция МаксимальнаяДата() Экспорт - //Возврат '39991231235959'; // TODO + Возврат '39991231235959'; КонецФункции Функция МаксимальнаяДатаПриПродолжении() - //Возврат '39990101000000'; // TODO + Возврат '39990101000000'; КонецФункции Процедура Тест3()