diff --git a/docs/diagnostics/AttachIdleHandler.md b/docs/diagnostics/AttachIdleHandler.md
new file mode 100644
index 00000000000..5952a060746
--- /dev/null
+++ b/docs/diagnostics/AttachIdleHandler.md
@@ -0,0 +1,59 @@
+# Использование метода ПодключитьОбработчикОжидания (AttachIdleHandler)
+
+| Тип | Поддерживаются
языки | Важность | Включена
по умолчанию | Время на
исправление (мин) | Тэги |
+| :-: | :-: | :-: | :-: | :-: | :-: |
+| `Ошибка` | `BSL`
`OS` | `Информационный` | `Да` | `1` | `error`
`unpredictable` |
+
+
+## Описание диагностики
+Подключение или отключение обработчика ожидания с указанием несуществующего метода
+
+## Примеры
+Неправильно
+
+```Bsl
+
+&НаКлиенте
+Процедура НайтиСтрокуСОшибкой(Команда)
+
+ ПодключитьОбработчикОжидания("НеизвестныйМетод", 0.1, Истина);
+
+КонецПроцедуры
+
+```
+
+Правильно
+
+```Bsl
+&НаКлиенте
+Процедура НайтиСтроку(Команда)
+
+ ПодключитьОбработчикОжидания("ВыполнитьПоиск", 0.1, Истина);
+
+КонецПроцедуры
+
+&НаКлиенте
+Процедура ВыполнитьПоиск()
+
+КонецПроцедуры
+
+```
+## Источники
+
+* Полезная информация: [Отложенная обработка события элемента управления в форме](https://its.1c.ru/db/metod8dev/content/1820/hdoc)
+
+## Сниппеты
+
+
+### Экранирование кода
+
+```bsl
+// BSLLS:AttachIdleHandler-off
+// BSLLS:AttachIdleHandler-on
+```
+
+### Параметр конфигурационного файла
+
+```json
+"AttachIdleHandler": false
+```
diff --git a/docs/diagnostics/index.md b/docs/diagnostics/index.md
index c260de678e7..1a957f7adb0 100644
--- a/docs/diagnostics/index.md
+++ b/docs/diagnostics/index.md
@@ -8,15 +8,16 @@
## Список реализованных диагностик
-Общее количество: **113**
+Общее количество: **114**
* Дефект кода: **71**
* Уязвимость: **3**
-* Ошибка: **35**
+* Ошибка: **36**
* Потенциальная уязвимость: **4**
| Ключ | Название | Включена по умолчанию | Важность | Тип | Тэги |
| --- | --- | :-: | --- | --- | --- |
+| [AttachIdleHandler](AttachIdleHandler.md) | Использование метода ПодключитьОбработчикОжидания | Да | Информационный | Ошибка | `error`
`unpredictable` |
| [BeginTransactionBeforeTryCatch](BeginTransactionBeforeTryCatch.md) | Нарушение правил работы с транзакциями для метода 'НачатьТранзакцию' | Да | Важный | Ошибка | `standard` |
| [CachedPublic](CachedPublic.md) | Кеширование программного интерфейса | Да | Важный | Дефект кода | `standard`
`design` |
| [CanonicalSpellingKeywords](CanonicalSpellingKeywords.md) | Каноническое написание ключевых слов | Да | Информационный | Дефект кода | `standard` |
diff --git a/docs/en/diagnostics/AttachIdleHandler.md b/docs/en/diagnostics/AttachIdleHandler.md
new file mode 100644
index 00000000000..1279e739120
--- /dev/null
+++ b/docs/en/diagnostics/AttachIdleHandler.md
@@ -0,0 +1,60 @@
+# Usage AttachIdleHandler (AttachIdleHandler)
+
+| Type | Scope | Severity | Activated
by default | Minutes
to fix | Tags |
+| :-: | :-: | :-: | :-: | :-: | :-: |
+| `Error` | `BSL`
`OS` | `Info` | `Yes` | `1` | `error`
`unpredictable` |
+
+
+## Description
+Attach or detach idle handler with not existed method
+
+## Examples
+
+BAD
+
+```Bsl
+
+&НаКлиенте
+Процедура НайтиСтрокуСОшибкой(Команда)
+
+ ПодключитьОбработчикОжидания("НеизвестныйМетод", 0.1, Истина);
+
+КонецПроцедуры
+
+```
+
+GOOD
+
+```Bsl
+&НаКлиенте
+Процедура НайтиСтроку(Команда)
+
+ ПодключитьОбработчикОжидания("ВыполнитьПоиск", 0.1, Истина);
+
+КонецПроцедуры
+
+&НаКлиенте
+Процедура ВыполнитьПоиск()
+
+КонецПроцедуры
+
+```
+## Sources
+
+* Usage info: [Отложенная обработка события элемента управления в форме](https://its.1c.ru/db/metod8dev/content/1820/hdoc)
+
+## Snippets
+
+
+### Diagnostic ignorance in code
+
+```bsl
+// BSLLS:AttachIdleHandler-off
+// BSLLS:AttachIdleHandler-on
+```
+
+### Parameter for config
+
+```json
+"AttachIdleHandler": false
+```
diff --git a/docs/en/diagnostics/index.md b/docs/en/diagnostics/index.md
index 6de16916d85..ec693e97fa5 100644
--- a/docs/en/diagnostics/index.md
+++ b/docs/en/diagnostics/index.md
@@ -8,15 +8,16 @@ To escape individual sections of code or files from triggering diagnostics, you
## Implemented diagnostics
-Total: **113**
+Total: **114**
-* Error: **35**
+* Error: **36**
* Code smell: **71**
* Vulnerability: **3**
* Security Hotspot: **4**
| Key | Name| Enabled by default | Severity | Type | Tags |
| --- | --- | :-: | --- | --- | --- |
+| [AttachIdleHandler](AttachIdleHandler.md) | Usage AttachIdleHandler | Yes | Info | Error | `error`
`unpredictable` |
| [BeginTransactionBeforeTryCatch](BeginTransactionBeforeTryCatch.md) | Violating transaction rules for the 'BeginTransaction' method | Yes | Major | Error | `standard` |
| [CachedPublic](CachedPublic.md) | Cached public methods | Yes | Major | Code smell | `standard`
`design` |
| [CanonicalSpellingKeywords](CanonicalSpellingKeywords.md) | Canonical keyword writing | Yes | Info | Code smell | `standard` |
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic.java
new file mode 100644
index 00000000000..20ba550def3
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic.java
@@ -0,0 +1,120 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.diagnostics;
+
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticInfo;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
+import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8TypeHelper;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import com.github._1c_syntax.mdclasses.metadata.additional.ModuleType;
+import com.github._1c_syntax.utils.CaseInsensitivePattern;
+import org.antlr.v4.runtime.tree.ParseTree;
+
+import java.util.regex.Pattern;
+
+@DiagnosticMetadata(
+ type = DiagnosticType.ERROR,
+ severity = DiagnosticSeverity.INFO,
+ minutesToFix = 1,
+ modules = {
+ ModuleType.FormModule
+ },
+ tags = {
+ DiagnosticTag.ERROR,
+ DiagnosticTag.UNPREDICTABLE
+ }
+
+)
+public class AttachIdleHandlerDiagnostic extends AbstractVisitorDiagnostic {
+
+ private static final Pattern MESSAGE_PATTERN_ATTACH = CaseInsensitivePattern.compile(
+ "ПодключитьОбработчикОжидания|AttachIdleHandler"
+ );
+ private static final Pattern MESSAGE_PATTERN_DETACH = CaseInsensitivePattern.compile(
+ "ОтключитьОбработчикОжидания|DetachIdleHandler"
+ );
+
+ public AttachIdleHandlerDiagnostic(DiagnosticInfo info) {
+ super(info);
+ }
+
+ @Override
+ public ParseTree visitGlobalMethodCall(BSLParser.GlobalMethodCallContext ctx) {
+
+ if (checkGlobalMethodCall(ctx)) {
+ diagnosticStorage.addDiagnostic(ctx.methodName(), getMessage(ctx));
+ }
+
+ return super.visitGlobalMethodCall(ctx);
+ }
+
+ /**
+ * Получает сообщение диагностики для пользователя
+ *
+ * @param ctx контекст узла
+ * @return В случае если передан контекст метода, параметризованное сообщение,
+ * первым параметром которого всегда будет имя метода.
+ * В противном случае возвращается обычное сообщение без параметров.
+ */
+ protected String getMessage(BSLParser.GlobalMethodCallContext ctx) {
+ return ctx.methodName().getText();
+ }
+
+ protected boolean checkGlobalMethodCall(BSLParser.GlobalMethodCallContext ctx) {
+
+ boolean isAttachHandler = MESSAGE_PATTERN_ATTACH.matcher(ctx.methodName().getText()).matches();
+ if (!(isAttachHandler
+ || MESSAGE_PATTERN_DETACH.matcher(ctx.methodName().getText()).matches())) {
+ return false;
+ }
+
+ var callContext = ctx.doCall();
+ // Проверка на существование метода в текущем контексте без параметров
+ boolean hasError = V8TypeHelper.getStringConstantFromFirstParam(callContext)
+ .get().map(methodName -> documentContext.getSymbolTree().getMethods()
+ .stream()
+ .noneMatch(method -> method.getName().equalsIgnoreCase(methodName) && method.getParameters().size() == 0)
+ ).orElse(false);
+
+ if (!isAttachHandler) {
+ return hasError;
+ }
+
+ // Проверка что при таймауте меньше 1 секунды, третий параметр не равен Ложь
+ hasError = hasError || V8TypeHelper.getFloatNumberConstantFromParam(callContext, 1)
+ .get()
+ .filter(timeout -> timeout < 1.0f)
+ // TODO change while got context
+ .map(e -> V8TypeHelper.getBooleanConstantFromParam(callContext, 2, Boolean.FALSE)
+ // .map(e -> V8TypeHelper.get(Boolean.FALSE, (constValue) -> constValue.TRUE() != null).apply(callContext,2)
+ .get()
+ .map(be -> be.equals(Boolean.FALSE))
+ .orElse(false)
+ )
+ .orElse(false);
+ return hasError;
+ }
+}
+
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 8de4d96733e..5136445f139 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
@@ -26,24 +26,23 @@
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.scope.CodeFlowType;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.scope.ProgramScope;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.scope.VariableDefinition;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8Type;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8TypeFromPresentationSupplier;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8TypeHelper;
import com.github._1c_syntax.bsl.parser.BSLParser;
import com.github._1c_syntax.bsl.parser.BSLParser.AssignmentContext;
import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
import com.github._1c_syntax.utils.CaseInsensitivePattern;
-import lombok.ToString;
-import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
-import java.util.ArrayDeque;
-import java.util.Collection;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
+import java.util.Collections;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
@DiagnosticMetadata(
type = DiagnosticType.ERROR,
@@ -61,178 +60,130 @@ public class CreateQueryInCycleDiagnostic extends AbstractVisitorDiagnostic {
CaseInsensitivePattern.compile("ПостроительОтчета|ReportBuilder");
private static final Pattern QUERY_PATTERN = CaseInsensitivePattern.compile("Запрос|Query");
- private static final String BOOLEAN_TYPE = "Boolean";
- private static final String DATE_TYPE = "Datetime";
- private static final String NULL_TYPE = "Null";
- private static final String NUMBER_TYPE = "Number";
- private static final String REPORT_BUILDER_TYPE = "ReportBuilder";
- private static final String STRING_TYPE = "String";
- private static final String QUERY_BUILDER_TYPE = "QueryBuilder";
- private static final String QUERY_TYPE = "Query";
- private static final String UNDEFINED_TYPE = "Undefined";
private static final String GLOBAL_SCOPE = "GLOBAL_SCOPE";
private static final String MODULE_SCOPE = "MODULE_SCOPE";
- private VariableScope currentScope;
+ private ProgramScope programScope = new ProgramScope();
public CreateQueryInCycleDiagnostic(DiagnosticInfo info) {
super(info);
+ programScope.getTypeSuppliers().add(getTypeSupplier());
}
- private static String getTypeFromConstValue(BSLParser.ConstValueContext constValue) {
- String result;
- if (constValue.string() != null) {
- result = STRING_TYPE;
- } else if (constValue.DATETIME() != null) {
- result = DATE_TYPE;
- } else if (constValue.numeric() != null) {
- result = NUMBER_TYPE;
- } else if (constValue.TRUE() != null) {
- result = BOOLEAN_TYPE;
- } else if (constValue.FALSE() != null) {
- result = BOOLEAN_TYPE;
- } else if (constValue.NULL() != null) {
- result = NULL_TYPE;
- } else {
- result = UNDEFINED_TYPE;
- }
-
- return result;
- }
-
- private static String getTypeFromNewExpressionContext(BSLParser.NewExpressionContext newExpression) {
-
- String typeName = Optional.ofNullable(newExpression.typeName())
- .map(RuleContext::getText)
- .or(() -> Optional.ofNullable(newExpression.doCall())
- .map(BSLParser.DoCallContext::callParamList)
- .flatMap(callParamListContext -> callParamListContext.callParam().stream().findFirst())
- .map(BSLParser.CallParamContext::expression)
- .map(BSLParser.ExpressionContext::member)
- .flatMap(memberListContext -> memberListContext.stream().findFirst())
- .map(BSLParser.MemberContext::constValue)
- .filter(constValue -> getTypeFromConstValue(constValue).equals(STRING_TYPE))
- .map(RuleContext::getText)
- .map(constValueText -> constValueText.substring(1, constValueText.length() - 1))
- )
- .orElse(UNDEFINED_TYPE);
-
- if (QUERY_BUILDER_PATTERN.matcher(typeName).matches()) {
- return QUERY_BUILDER_TYPE;
- } else if (REPORT_BUILDER_PATTERN.matcher(typeName).matches()) {
- return REPORT_BUILDER_TYPE;
- } else if (QUERY_PATTERN.matcher(typeName).matches()) {
- return QUERY_TYPE;
- } else {
- return typeName;
- }
- }
-
- private static String getVariableNameFromCallStatementContext(BSLParser.CallStatementContext callStatement) {
- return callStatement.IDENTIFIER().getText();
+ public static V8TypeFromPresentationSupplier getTypeSupplier() {
+ return (typeName) -> {
+ if (QUERY_PATTERN.matcher(typeName).matches()) {
+ return Optional.of(NecessaryTypes.QUERY_TYPE);
+ } else if (REPORT_BUILDER_PATTERN.matcher(typeName).matches()) {
+ return Optional.of(NecessaryTypes.REPORT_BUILDER_TYPE);
+ } else if (QUERY_BUILDER_PATTERN.matcher(typeName).matches()) {
+ return Optional.of(NecessaryTypes.QUERY_BUILDER_TYPE);
+ }
+ return Optional.empty();
+ };
}
- private static String getVariableNameFromModifierContext(BSLParser.ModifierContext modifier) {
- ParserRuleContext parent = modifier.getParent();
- if (parent instanceof BSLParser.ComplexIdentifierContext) {
- return getComplexPathName(((BSLParser.ComplexIdentifierContext) parent), modifier);
- } else if (parent instanceof BSLParser.CallStatementContext) {
- BSLParser.CallStatementContext parentCall = (BSLParser.CallStatementContext) parent;
-
- return parentCall.modifier().stream()
- .takeWhile(e -> !e.equals(modifier))
- .map(RuleContext::getText)
- .collect(Collectors.joining("", parentCall.IDENTIFIER().getText(), ""));
+ private static BSLParserRuleContext getProperErrorContext(BSLParser.AccessCallContext ctx) {
+ BSLParserRuleContext errorContext = null;
+ BSLParserRuleContext parent = (BSLParserRuleContext) ctx.getParent();
+ if (parent instanceof BSLParser.CallStatementContext) {
+ errorContext = parent;
+ } else if (parent instanceof BSLParser.ModifierContext) {
+ BSLParser.ModifierContext callModifier = (BSLParser.ModifierContext) parent;
+ errorContext = (BSLParserRuleContext) callModifier.getParent();
}
- return null;
- }
-
- private static String getComplexPathName(BSLParser.ComplexIdentifierContext ci, BSLParser.ModifierContext to) {
-
- return ci.modifier().stream()
- .takeWhile(e -> !e.equals(to))
- .map(RuleContext::getText)
- .collect(Collectors.joining("", ci.getChild(0).getText(), ""));
-
+ return errorContext;
}
@Override
public ParseTree visitFile(BSLParser.FileContext ctx) {
- currentScope = new VariableScope();
- currentScope.enterScope(GLOBAL_SCOPE);
+ programScope.enterScope(GLOBAL_SCOPE);
ParseTree result = super.visitFile(ctx);
- currentScope = null;
+ programScope = null;
return result;
}
@Override
public ParseTree visitFileCodeBlock(BSLParser.FileCodeBlockContext ctx) {
- currentScope.enterScope(MODULE_SCOPE);
+ programScope.enterScope(MODULE_SCOPE);
ParseTree result = super.visitFileCodeBlock(ctx);
- currentScope.leaveScope();
+ programScope.leaveScope();
return result;
}
@Override
public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) {
- currentScope.enterScope(ctx.procDeclaration().subName().getText());
+ programScope.enterScope(ctx.procDeclaration().subName().getText());
ParseTree result = super.visitProcedure(ctx);
- currentScope.leaveScope();
+ programScope.leaveScope();
return result;
}
@Override
public ParseTree visitFunction(BSLParser.FunctionContext ctx) {
- currentScope.enterScope(ctx.funcDeclaration().subName().getText());
+ programScope.enterScope(ctx.funcDeclaration().subName().getText());
ParseTree result = super.visitFunction(ctx);
- currentScope.leaveScope();
+ programScope.leaveScope();
return result;
}
+ @Override
+ public ParseTree visitIfStatement(BSLParser.IfStatementContext ctx) {
+ if (ctx.ifBranch() != null) {
+ visitExpression(ctx.ifBranch().expression());
+ programScope.enterFlowScope(CodeFlowType.CONDITIONAL);
+ visitCodeBlock(ctx.ifBranch().codeBlock());
+ programScope.leaveFlowScope();
+ }
+ for (var branch : ctx.elsifBranch()) {
+ visitExpression(branch.expression());
+ programScope.enterFlowScope(CodeFlowType.CONDITIONAL);
+ visitCodeBlock(branch.codeBlock());
+ programScope.leaveFlowScope();
+ }
+ if (ctx.elseBranch() != null) {
+ programScope.enterFlowScope(CodeFlowType.CONDITIONAL);
+ visitCodeBlock(ctx.elseBranch().codeBlock());
+ programScope.leaveFlowScope();
+ }
+
+ return null;
+ }
+
@Override
public ParseTree visitAssignment(AssignmentContext ctx) {
if (ctx.expression() == null) {
return super.visitAssignment(ctx);
}
- BSLParser.MemberContext firstMember = ctx.expression().member(0);
- if (firstMember == null) {
+ Set types = V8TypeHelper.getTypesFromExpressionContext(ctx.expression(), programScope);
+ if (types == null) {
return super.visitAssignment(ctx);
}
+
String variableName = ctx.lValue().getText();
- VariableDefinition currentVariable = new VariableDefinition(variableName);
- currentVariable.addDeclaration(ctx.lValue());
- if (firstMember.complexIdentifier() != null) {
- currentVariable.types.addAll(getTypesFromComplexIdentifier(firstMember.complexIdentifier()));
- } else if (firstMember.constValue() != null) {
- currentVariable.types.add(getTypeFromConstValue(firstMember.constValue()));
+ VariableDefinition currentVariable = programScope.getVariableByName(variableName)
+ .orElseGet(() -> programScope.addVariable(VariableDefinition.fromLValue(ctx.lValue())));
+
+ if (programScope.codeFlowInConditionalBlock()) {
+ currentVariable.addAll(types);
} else {
- currentVariable.addType(UNDEFINED_TYPE);
+ currentVariable.replaceAll(types);
}
-
- currentScope.addVariable(currentVariable);
return super.visitAssignment(ctx);
}
- private Set getTypesFromComplexIdentifier(BSLParser.ComplexIdentifierContext complexId) {
- if (complexId.newExpression() != null) {
- return Set.of(getTypeFromNewExpressionContext(complexId.newExpression()));
- } else if (complexId.IDENTIFIER() != null) {
- return currentScope.getVariableByName(getComplexPathName(complexId, null))
- .map(variableDefinition -> variableDefinition.types)
- .orElse(Set.of(UNDEFINED_TYPE));
- } else {
- return Set.of();
- }
+ @Override
+ public ParseTree visitCodeBlock(BSLParser.CodeBlockContext ctx) {
+ return Optional.ofNullable(ctx)
+ .map(super::visitCodeBlock).orElse(null);
}
- private void visitDescendantCodeBlock(BSLParser.CodeBlockContext ctx){
- Optional.ofNullable(ctx)
- .map(e -> e.children)
- .stream()
- .flatMap(Collection::stream)
- .forEach( t -> t.accept(this));
+ @Override
+ public ParseTree visitExpression(BSLParser.ExpressionContext ctx) {
+ return Optional.ofNullable(ctx)
+ .map(super::visitExpression).orElse(null);
}
@Override
@@ -240,166 +191,61 @@ public ParseTree visitAccessCall(BSLParser.AccessCallContext ctx) {
if (!EXECUTE_CALL_PATTERN.matcher(ctx.methodCall().methodName().getText()).matches()) {
return super.visitAccessCall(ctx);
}
- if (!currentScope.codeFlowInCycle()) {
+ if (!programScope.codeFlowInCycle()) {
return super.visitAccessCall(ctx);
}
- String variableName = null;
- BSLParserRuleContext errorContext = null;
- BSLParserRuleContext parent = (BSLParserRuleContext) ctx.getParent();
- if (parent instanceof BSLParser.CallStatementContext) {
- errorContext = parent;
- variableName = getVariableNameFromCallStatementContext((BSLParser.CallStatementContext) parent);
- } else if (parent instanceof BSLParser.ModifierContext) {
- BSLParser.ModifierContext callModifier = (BSLParser.ModifierContext) parent;
- errorContext = (BSLParserRuleContext) callModifier.getParent();
- variableName = getVariableNameFromModifierContext(callModifier);
+ BSLParserRuleContext errorContext = getProperErrorContext(ctx);
+ if (errorContext != null) {
+ String variableName = V8TypeHelper.getVariableNameFromAccessCallContext(ctx);
+ programScope.getVariableByName(variableName)
+ .filter(Predicate.not((VariableDefinition definition) -> Collections.disjoint(definition.getTypes(), NecessaryTypes.FULL_COLLECTION)))
+ .ifPresent(e -> diagnosticStorage.addDiagnostic(errorContext));
}
- Optional variableDefinition = currentScope.getVariableByName(variableName);
- BSLParserRuleContext finalErrorContext = errorContext;
- if (finalErrorContext != null) {
- variableDefinition.ifPresent((VariableDefinition definition) -> {
-
- if (definition.types.contains(QUERY_BUILDER_TYPE)
- || definition.types.contains(REPORT_BUILDER_TYPE)
- || definition.types.contains(QUERY_TYPE)) {
- diagnosticStorage.addDiagnostic(finalErrorContext);
- }
-
- });
- }
-
return super.visitAccessCall(ctx);
}
@Override
public ParseTree visitForEachStatement(BSLParser.ForEachStatementContext ctx) {
- boolean alreadyInCycle = currentScope.codeFlowInCycle();
- currentScope.flowMode.push(CodeFlowType.CYCLE);
- if(alreadyInCycle) {
- Optional.ofNullable(ctx.expression())
- .ifPresent( e -> e.accept(this));
- }
- visitDescendantCodeBlock(ctx.codeBlock());
- currentScope.flowMode.pop();
+ visitExpression(ctx.expression());
+ programScope.enterFlowScope(CodeFlowType.CYCLE);
+ visitCodeBlock(ctx.codeBlock());
+ programScope.leaveFlowScope();
return ctx;
}
@Override
public ParseTree visitWhileStatement(BSLParser.WhileStatementContext ctx) {
- currentScope.flowMode.push(CodeFlowType.CYCLE);
+ programScope.enterFlowScope(CodeFlowType.CYCLE);
ParseTree result = super.visitWhileStatement(ctx);
- currentScope.flowMode.pop();
+ programScope.leaveFlowScope();
return result;
}
@Override
public ParseTree visitForStatement(BSLParser.ForStatementContext ctx) {
- boolean alreadyInCycle = currentScope.codeFlowInCycle();
- currentScope.flowMode.push(CodeFlowType.CYCLE);
- if(alreadyInCycle) {
- ctx.expression()
- .forEach( e-> e.accept(this));
- }
- visitDescendantCodeBlock(ctx.codeBlock());
- currentScope.flowMode.pop();
- return ctx;
- }
-
- public enum CodeFlowType {
- LINEAR, CYCLE
- }
-
- @ToString
- public static class VariableDefinition {
- private final String variableName;
- private final Set types = new HashSet<>();
- private ParseTree firstDeclaration;
-
- VariableDefinition(String variableName) {
- this.variableName = variableName;
- }
- public void addType(String type) {
- this.types.add(type);
- }
-
- public void addDeclaration(ParseTree firstDeclaration) {
- if (this.firstDeclaration == null) {
- this.firstDeclaration = firstDeclaration;
- }
- }
+ ctx.expression()
+ .forEach(this::visitExpression);
+ programScope.enterFlowScope(CodeFlowType.CYCLE);
+ visitCodeBlock(ctx.codeBlock());
+ programScope.leaveFlowScope();
+ return ctx;
}
- private static class Scope {
- private final String name;
+ enum NecessaryTypes implements V8Type {
+ REPORT_BUILDER_TYPE("ReportBuilder"), QUERY_BUILDER_TYPE("QueryBuilder"), QUERY_TYPE("Query");
+ public static Set FULL_COLLECTION = Set.of(QUERY_TYPE, REPORT_BUILDER_TYPE, QUERY_BUILDER_TYPE);
+ String name;
- private final HashMap variables = new HashMap<>();
-
- public Scope(String name) {
+ NecessaryTypes(String name) {
this.name = name;
}
- public void addVariable(VariableDefinition variableDefinition, boolean typesMerge) {
- this.variables.merge(
- variableDefinition.variableName,
- variableDefinition,
- (VariableDefinition key, VariableDefinition value) -> {
- if (!typesMerge) {
- key.types.clear();
- }
- key.types.addAll(value.types);
-
- return key;
- });
- }
-
+ @Override
public String getName() {
- return name;
+ return this.name;
}
}
- private static class VariableScope extends ArrayDeque {
- private final Deque flowMode = new ArrayDeque<>();
-
- public boolean codeFlowInCycle() {
- final CodeFlowType flowType = flowMode.peek();
- if (flowType == null) {
- return false;
- }
- return flowType == CodeFlowType.CYCLE;
- }
-
- public Optional getVariableByName(String variableName) {
- return Optional.ofNullable(current().variables.get(variableName));
- }
-
- public void addVariable(VariableDefinition variableDefinition) {
- final CodeFlowType flowType = flowMode.peek();
- if (flowType == null) {
- return;
- }
- this.current().addVariable(variableDefinition, flowType == CodeFlowType.CYCLE);
- }
-
- public void enterScope(String name) {
- Scope newScope = new Scope(name);
- if (!this.isEmpty()) {
- Scope prevScope = this.peek();
- newScope.variables.putAll(prevScope.variables);
- }
- this.push(newScope);
- flowMode.push(CodeFlowType.LINEAR);
- }
-
- public void leaveScope() {
- this.pop();
- flowMode.pop();
- }
-
- public Scope current() {
- return this.peek();
- }
-
- }
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/CodeFlowType.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/CodeFlowType.java
new file mode 100644
index 00000000000..2effcecfee5
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/CodeFlowType.java
@@ -0,0 +1,26 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.scope;
+
+public enum CodeFlowType {
+ LINEAR, CYCLE, CONDITIONAL
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/HierarchicalNamedScope.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/HierarchicalNamedScope.java
new file mode 100644
index 00000000000..a2a73d6714d
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/HierarchicalNamedScope.java
@@ -0,0 +1,82 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.scope;
+
+import com.github._1c_syntax.bsl.languageserver.utils.variable.values.V8NamedObject;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Deque;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class HierarchicalNamedScope extends NamedScope {
+ private final Deque scope = new ArrayDeque<>();
+
+ public HierarchicalNamedScope(String name) {
+ super(name);
+ scope.push(this);
+ }
+
+ public HierarchicalNamedScope() {
+ super();
+ scope.push(this);
+ }
+
+ public NamedScope current() {
+ return scope.peek();
+ }
+
+ public void enterSubScope(V8NamedObject object) {
+ NamedScope newScope = new NamedScope();
+ newScope.fillFromScope(current());
+ newScope.addToScope(object);
+ scope.push(newScope);
+ }
+
+ public void enterNamedSubScope(String nameOfScope) {
+ NamedScope newScope = new NamedScope(nameOfScope);
+ newScope.fillFromScope(current());
+ scope.push(newScope);
+ }
+
+ public void leaveSubScope() {
+ scope.pop();
+ }
+
+ @Override
+ public boolean contains(T object) {
+ if (current().equals(this)) {
+ return super.contains(object);
+ } else {
+ return current().contains(object);
+ }
+ }
+
+ @Override
+ public boolean containsAnyOf(T... objects) {
+ if (current().equals(this)) {
+ return super.containsAnyOf(Arrays.asList(objects));
+ } else {
+ return current().containsAnyOf(objects);
+ }
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/HierarchicalScope.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/HierarchicalScope.java
new file mode 100644
index 00000000000..40024084ae8
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/HierarchicalScope.java
@@ -0,0 +1,80 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.scope;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+public class HierarchicalScope extends Scope {
+ private final Deque> scope = new ArrayDeque<>();
+
+ public HierarchicalScope(String name) {
+ super(name);
+ scope.push(this);
+ }
+
+ public HierarchicalScope() {
+ super();
+ scope.push(this);
+ }
+
+ public Scope current() {
+ return scope.peek();
+ }
+
+ public void enterSubScope(T object) {
+ Scope newScope = new Scope<>();
+ newScope.fillFromScope(current());
+ newScope.addToScope(object);
+ scope.push(newScope);
+ }
+
+ public void enterNamedScope(String nameOfScope) {
+ Scope newScope = new Scope<>(nameOfScope);
+ newScope.fillFromScope(current());
+ scope.push(newScope);
+ }
+
+ public void leaveSubScope() {
+ scope.pop();
+ }
+
+ @Override
+ public boolean contains(T object) {
+ if (current().equals(this)) {
+ return super.contains(object);
+ } else {
+ return current().contains(object);
+ }
+
+ }
+
+ @SafeVarargs
+ @Override
+ public final boolean containsAnyOf(T... objects) {
+ if (current().equals(this)) {
+ return super.containsAnyOf(objects);
+ } else {
+ return current().containsAnyOf(objects);
+ }
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/NamedScope.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/NamedScope.java
new file mode 100644
index 00000000000..2a3f212e0fe
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/NamedScope.java
@@ -0,0 +1,63 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.scope;
+
+import com.github._1c_syntax.bsl.languageserver.utils.variable.values.V8NamedObject;
+
+import java.util.HashMap;
+
+@SuppressWarnings("uncheked")
+public class NamedScope extends Scope {
+
+ private final HashMap namedObject = new HashMap<>();
+
+ public NamedScope(String name) {
+ super(name);
+ }
+
+ public NamedScope() {
+ super();
+ }
+
+ @Override
+ public void addToScope(T variableDefinition) {
+ super.addToScope(variableDefinition);
+ this.namedObject.put(variableDefinition.getName(), variableDefinition);
+ }
+
+ @Override
+ @SuppressWarnings("uncheked")
+ public void fillFromScope(Scope extends T> anotherScope) {
+ super.fillFromScope(anotherScope);
+ if (anotherScope instanceof NamedScope) {
+ this.namedObject.putAll(((NamedScope) anotherScope).namedObject);
+ } else {
+ anotherScope.objects.forEach(e ->
+ this.namedObject.putIfAbsent(e.getName(), e));
+ }
+ }
+
+ public T findByName(String variableName) {
+ return namedObject.get(variableName);
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/ProgramScope.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/ProgramScope.java
new file mode 100644
index 00000000000..c2d367d4b7c
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/ProgramScope.java
@@ -0,0 +1,94 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.scope;
+
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8Type;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8TypeFromPresentationSupplier;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8TypeFromVariableSupplier;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+public class ProgramScope implements V8TypeFromPresentationSupplier, V8TypeFromVariableSupplier {
+ private final HierarchicalScope flowMode = new HierarchicalScope<>();
+ private final HierarchicalNamedScope variableScope = new HierarchicalNamedScope<>();
+ private List typeSuppliers = new ArrayList<>();
+
+ public boolean codeFlowInConditionalBlock() {
+ return flowMode.containsAnyOf(CodeFlowType.CYCLE, CodeFlowType.CONDITIONAL);
+ }
+
+ public boolean codeFlowInCycle() {
+ return flowMode.contains(CodeFlowType.CYCLE);
+ }
+
+ public Optional getVariableByName(String variableName) {
+ return Optional.ofNullable(this.variableScope.findByName(variableName));
+ }
+
+ public VariableDefinition addVariable(VariableDefinition variableDefinition) {
+ this.variableScope.addToScope(variableDefinition);
+ return variableDefinition;
+ }
+
+ public void enterScope(String name) {
+ variableScope.enterNamedSubScope(name);
+ flowMode.enterSubScope(CodeFlowType.LINEAR);
+ }
+
+ public void leaveScope() {
+ variableScope.leaveSubScope();
+ flowMode.leaveSubScope();
+ }
+
+ public void enterFlowScope(CodeFlowType additionalMode) {
+ flowMode.enterSubScope(additionalMode);
+ }
+
+ public void leaveFlowScope() {
+ flowMode.leaveSubScope();
+ }
+
+ @Override
+ public Optional getTypeFromPresentation(String presentation) {
+ Optional started = Optional.empty();
+ for (var typeSupplier : typeSuppliers) {
+ started = typeSupplier.getTypeFromPresentation(presentation);
+ if (started.isPresent()) {
+ break;
+ }
+ }
+ return started;
+ }
+
+ @Override
+ public Optional> getTypesFromVariable(String variableName) {
+ return this.getVariableByName(variableName)
+ .map(VariableDefinition::getTypes);
+ }
+
+ public List getTypeSuppliers() {
+ return typeSuppliers;
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/Scope.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/Scope.java
new file mode 100644
index 00000000000..67b315bb265
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/Scope.java
@@ -0,0 +1,65 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.scope;
+
+import lombok.ToString;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+@ToString
+public class Scope {
+ private final String name;
+ protected Set objects = new HashSet<>();
+
+ public Scope(String name) {
+ this.name = name;
+ }
+ public Scope() {
+ this.name = "UnnamedScope";
+ }
+ public void addToScope(T scopedObject) {
+ objects.add(scopedObject);
+ }
+
+ public void fillFromScope(Scope extends T> anotherScope) {
+ this.objects.addAll(anotherScope.objects);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean contains(T object){
+ return objects.contains(object);
+ }
+
+ public boolean containsAnyOf(T ...objects){
+ return !Collections.disjoint(this.objects, Arrays.asList(objects));
+ }
+ public boolean containsAnyOf(Collection objects){
+ return !Collections.disjoint(this.objects, objects);
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/VariableDefinition.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/VariableDefinition.java
new file mode 100644
index 00000000000..aaac7c00103
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/scope/VariableDefinition.java
@@ -0,0 +1,77 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.scope;
+
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8Type;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.values.V8NamedObject;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import lombok.ToString;
+import org.antlr.v4.runtime.tree.ParseTree;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+@ToString(exclude = {"firstDeclaration"})
+public class VariableDefinition implements V8NamedObject {
+
+ private final String variablePath;
+ private final Set types = new HashSet<>();
+ private ParseTree firstDeclaration;
+
+ public VariableDefinition(String variableName) {
+ this.variablePath = variableName;
+ }
+
+ public static VariableDefinition fromLValue(BSLParser.LValueContext lValue) {
+ var variable = new VariableDefinition(lValue.getText());
+ variable.addDeclaration(lValue);
+ return variable;
+ }
+
+ public Set getTypes() {
+ return types;
+ }
+
+ public void addDeclaration(ParseTree firstDeclaration) {
+ if (this.firstDeclaration == null) {
+ this.firstDeclaration = firstDeclaration;
+ }
+ }
+
+ public void clearTypes() {
+ this.types.clear();
+ }
+
+ public void addAll(Collection newTypes) {
+ this.types.addAll(newTypes);
+ }
+ public void replaceAll(Collection newTypes) {
+ this.types.clear();
+ this.types.addAll(newTypes);
+ }
+ public String getName() {
+ return variablePath;
+ }
+
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8BasicType.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8BasicType.java
new file mode 100644
index 00000000000..5633fd790c5
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8BasicType.java
@@ -0,0 +1,48 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.types;
+
+public enum V8BasicType implements V8Type, V8TypedObject {
+ STRING_TYPE("Строка"), DATE_TYPE("Дата"), NUMBER_TYPE("Число"),
+ BOOLEAN_TYPE("Булево"), NULL_TYPE("Null"), UNDEFINED_TYPE("Неопределено"),
+ TYPE_TYPE("Тип");
+
+ private String name;
+
+ V8BasicType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ @Override
+ public V8Type getType() {
+ return TYPE_TYPE;
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8Type.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8Type.java
new file mode 100644
index 00000000000..25c56d03026
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8Type.java
@@ -0,0 +1,27 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.types;
+
+import com.github._1c_syntax.bsl.languageserver.utils.variable.values.V8NamedObject;
+
+public interface V8Type extends V8NamedObject {
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeFromPresentationSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeFromPresentationSupplier.java
new file mode 100644
index 00000000000..e4808da93ef
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeFromPresentationSupplier.java
@@ -0,0 +1,28 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.types;
+
+import java.util.Optional;
+
+public interface V8TypeFromPresentationSupplier extends V8TypeSupplier {
+ Optional getTypeFromPresentation(String presentation);
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeFromVariableSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeFromVariableSupplier.java
new file mode 100644
index 00000000000..5369a43c614
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeFromVariableSupplier.java
@@ -0,0 +1,29 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.types;
+
+import java.util.Optional;
+import java.util.Set;
+
+public interface V8TypeFromVariableSupplier extends V8TypeSupplier {
+ Optional> getTypesFromVariable(String variableName);
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeHelper.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeHelper.java
new file mode 100644
index 00000000000..42a00437d0d
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeHelper.java
@@ -0,0 +1,266 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.types;
+
+import com.github._1c_syntax.bsl.languageserver.utils.variable.scope.ProgramScope;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.values.V8BasicValue;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.values.V8Value;
+import com.github._1c_syntax.bsl.parser.BSLParser;
+import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
+import lombok.ToString;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.RuleContext;
+import org.antlr.v4.runtime.tree.ParseTree;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+
+public class V8TypeHelper {
+ private static V8TypeFromPresentationSupplier anyTypeSupplier = (typeNameValue) -> Optional.of(new AnyType(typeNameValue));
+
+ private static Function> GET_CONST_VALUE_FROM_EXPRESSION = (paramListContext) -> {
+ if (paramListContext.member().size() == 1) {
+ return getConstValue(paramListContext.member(0).constValue());
+ } else {
+ return Optional.empty();
+ }
+ };
+
+
+ private static Predicate CONST_VALUE_TYPE_IS_STRING = constValue -> V8BasicType.STRING_TYPE.equals(constValue.getType());
+ private static Predicate CONST_VALUE_TYPE_IS_NUMBER = constValue -> V8BasicType.NUMBER_TYPE.equals(constValue.getType());
+ private static Predicate CONST_VALUE_TYPE_IS_BOOLEAN = constValue -> V8BasicType.BOOLEAN_TYPE.equals(constValue.getType());
+
+ /**
+ * @param constValue Константное значение, тип которого необходимо получить
+ * @return тип переданного выражения или null
+ */
+ public static V8Type getConstValueType(BSLParser.ConstValueContext constValue) {
+
+ return getConstValue(constValue)
+ .map(V8Value::getType)
+ .orElse(null);
+
+ }
+
+ /**
+ * @param constValue Константное значение, значение которого необходимо получить
+ * @return значение переданного выражения или null
+ */
+ public static Optional extends V8Value> getConstValue(BSLParser.ConstValueContext constValue) {
+ if (constValue == null) {
+ return Optional.empty();
+ }
+
+ if (constValue.string() != null) {
+ return V8BasicValue.fromStringLiteral(constValue.string().getText());
+ } else if (constValue.DATETIME() != null) {
+ // TODO need reimplement V8BasicType.DATE_TYPE;
+ } else if (constValue.numeric() != null) {
+ return V8BasicValue.fromNumberLiteral(constValue.numeric().getText());
+ } else if (constValue.TRUE() != null) {
+ return Optional.of(V8BasicValue.TRUE);
+ } else if (constValue.FALSE() != null) {
+ return Optional.of(V8BasicValue.FALSE);
+ } else if (constValue.NULL() != null) {
+ return Optional.of(V8BasicValue.NULL);
+ } else if (constValue.UNDEFINED() != null) {
+ return Optional.of(V8BasicValue.UNDEFINED);
+ }
+ return Optional.empty();
+ }
+
+
+ public static Optional getParamByIndexInDoCallContext(BSLParser.DoCallContext doCallContext, int index) {
+ return Optional.ofNullable(doCallContext)
+ .map(BSLParser.DoCallContext::callParamList)
+ .stream()
+ .flatMap(e -> e.callParam().stream())
+ .skip(index)
+ .findFirst()
+ .map(BSLParser.CallParamContext::expression);
+ }
+
+ public static Supplier extends Optional> getStringConstantFromFirstParam(BSLParser.DoCallContext doCallContext) {
+ return () -> getParamByIndexInDoCallContext(doCallContext, 0)
+ .flatMap(GET_CONST_VALUE_FROM_EXPRESSION)
+ .filter(CONST_VALUE_TYPE_IS_STRING)
+ .map(V8Value::getValue)
+ .filter(String.class::isInstance)
+ .map(String.class::cast);
+ }
+
+ public static Supplier extends Optional> getFloatNumberConstantFromParam(BSLParser.DoCallContext doCallContext, int index) {
+ return () -> getParamByIndexInDoCallContext(doCallContext, index)
+ .flatMap(GET_CONST_VALUE_FROM_EXPRESSION)
+ .filter(CONST_VALUE_TYPE_IS_NUMBER)
+ .map(V8Value::getValue)
+ .filter(Float.class::isInstance)
+ .map(Float.class::cast);
+
+ }
+
+ public static Supplier extends Optional> getBooleanConstantFromParam(BSLParser.DoCallContext doCallContext, int index, Boolean defaultValue) {
+ return () -> {
+ var param = getParamByIndexInDoCallContext(doCallContext, index);
+ if (param.isPresent()) {
+ return param
+ .flatMap(GET_CONST_VALUE_FROM_EXPRESSION)
+ .filter(CONST_VALUE_TYPE_IS_BOOLEAN)
+ .map(V8Value::getValue)
+ .filter(Boolean.class::isInstance)
+ .map(Boolean.class::cast);
+ } else {
+ return Optional.ofNullable(defaultValue);
+ }
+ };
+ }
+
+ public static V8Type getTypeFromNewExpressionContext(BSLParser.NewExpressionContext newExpression, V8TypeSupplier supplier) {
+
+ Optional typeName = Optional.ofNullable(newExpression.typeName())
+ .map(RuleContext::getText)
+ .or(getStringConstantFromFirstParam(newExpression.doCall()));
+
+ if (typeName.isPresent()) {
+ String typeNameValue = typeName.get();
+ Optional calculatedType = Optional.empty();
+ if (supplier instanceof V8TypeFromPresentationSupplier) {
+ calculatedType = ((V8TypeFromPresentationSupplier) supplier).getTypeFromPresentation(typeNameValue);
+ }
+ return calculatedType.orElseGet(anyTypeSupplier.getTypeFromPresentation(typeNameValue)::get);
+ } else {
+ return V8BasicType.UNDEFINED_TYPE;
+ }
+ }
+
+ public static String getVariableNameFromComplexIdentifierContext(BSLParser.ComplexIdentifierContext complexIdentifier) {
+ return getLimitedText(complexIdentifier, null);
+ }
+
+ public static String getLimitedText(ParserRuleContext context, BSLParserRuleContext limitedChild) {
+ if (limitedChild == null) {
+ return context.getText();
+ }
+
+ return context.children.stream()
+ .takeWhile(Predicate.not(Predicate.isEqual(limitedChild)))
+ .map(ParseTree::getText)
+ .collect(Collectors.joining(""));
+ }
+
+ public static String getVariableNameFromCallStatementContext(BSLParser.CallStatementContext callStatement, BSLParserRuleContext limitedChild) {
+ return getLimitedText(callStatement, limitedChild);
+ }
+
+ public static String getVariableNameFromModifierContext(BSLParser.ModifierContext modifier) {
+ ParserRuleContext parent = modifier.getParent();
+ if (parent instanceof BSLParser.ComplexIdentifierContext) {
+ return V8TypeHelper.getLimitedText(parent, modifier);
+ } else if (parent instanceof BSLParser.CallStatementContext) {
+ return V8TypeHelper.getLimitedText(parent, modifier);
+ }
+ return null;
+ }
+
+ public static String getVariableNameFromAccessCallContext(BSLParser.AccessCallContext accessCall) {
+ String variableName = null;
+ BSLParserRuleContext parent = (BSLParserRuleContext) accessCall.getParent();
+ if (parent instanceof BSLParser.CallStatementContext) {
+ variableName = V8TypeHelper.getVariableNameFromCallStatementContext((BSLParser.CallStatementContext) parent, accessCall);
+ } else if (parent instanceof BSLParser.ModifierContext) {
+ variableName = V8TypeHelper.getVariableNameFromModifierContext((BSLParser.ModifierContext) parent);
+ }
+ return variableName;
+ }
+
+ public static Set getTypesFromComplexIdentifier(BSLParser.ComplexIdentifierContext complexId, V8TypeSupplier supplier) {
+ if (complexId.newExpression() != null) {
+ return Set.of(getTypeFromNewExpressionContext(complexId.newExpression(), supplier));
+ } else if (complexId.IDENTIFIER() != null) {
+ Optional> calculatedTypes = Optional.empty();
+ if (supplier instanceof V8TypeFromVariableSupplier) {
+ calculatedTypes = ((V8TypeFromVariableSupplier) supplier).getTypesFromVariable(getVariableNameFromComplexIdentifierContext(complexId));
+ }
+ return calculatedTypes.orElse(Set.of(V8BasicType.UNDEFINED_TYPE));
+ }
+ return Set.of();
+ }
+
+ public static Set getTypesFromExpressionContext(BSLParser.ExpressionContext ctx, ProgramScope programScope) {
+ List extends BSLParser.MemberContext> members = ctx.member();
+ if (members.size() != 1) {
+ if (ctx.operation().size() == 0) {
+ return null;
+ }
+ BSLParser.OperationContext firstOperation = ctx.operation(0);
+ if (firstOperation.boolOperation() != null
+ || firstOperation.compareOperation() != null) {
+ return Collections.singleton(V8BasicType.BOOLEAN_TYPE);
+ } else if(firstOperation.MODULO() != null
+ || firstOperation.QUOTIENT() != null
+ || firstOperation.MUL() != null) {
+ return Collections.singleton(V8BasicType.NUMBER_TYPE);
+ }
+ }
+
+ BSLParser.MemberContext firstMember = members.get(0);
+ if (firstMember == null) {
+ return null;
+ }
+ Set types;
+
+ if (firstMember.complexIdentifier() != null) {
+ types = V8TypeHelper.getTypesFromComplexIdentifier(firstMember.complexIdentifier(), programScope);
+ } else if (firstMember.constValue() != null) {
+ types = Collections.singleton(V8TypeHelper.getConstValueType(firstMember.constValue()));
+ } else if (firstMember.expression() != null) {
+ types = getTypesFromExpressionContext(firstMember.expression(), programScope);
+ } else {
+ types = Collections.singleton(V8BasicType.UNDEFINED_TYPE);
+ }
+ return types;
+ }
+
+ @ToString
+ static class AnyType implements V8Type {
+
+ String name;
+
+ AnyType(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+ }
+}
+
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeSupplier.java
new file mode 100644
index 00000000000..53e4d53bff0
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypeSupplier.java
@@ -0,0 +1,26 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.types;
+
+public interface V8TypeSupplier {
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypedObject.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypedObject.java
new file mode 100644
index 00000000000..e0da003cba8
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/types/V8TypedObject.java
@@ -0,0 +1,26 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.types;
+
+public interface V8TypedObject {
+ V8Type getType();
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8BasicValue.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8BasicValue.java
new file mode 100644
index 00000000000..f34872f12bb
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8BasicValue.java
@@ -0,0 +1,134 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.values;
+
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8BasicType;
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8Type;
+
+import java.util.Optional;
+
+public enum V8BasicValue implements V8Value {
+ TRUE(V8BasicType.BOOLEAN_TYPE), FALSE(V8BasicType.BOOLEAN_TYPE), NULL(V8BasicType.NULL_TYPE), UNDEFINED(V8BasicType.UNDEFINED_TYPE);
+
+ private V8Type type;
+
+ V8BasicValue(V8Type type) {
+ this.type = type;
+ }
+
+ public static Optional fromStringLiteral(String literal) {
+ return Optional.of(new StringValue(literal.substring(1, literal.length() - 1).replace("\"\"","\"")));
+ }
+
+ public static Optional fromNumberLiteral(String literal) {
+ return Optional.of(new FloatValue(Float.parseFloat(literal)));
+ }
+
+ @Override
+ public V8Type getType() {
+ return type;
+ }
+
+ @Override
+ public Object getValue() {
+ if(this.equals(TRUE)){
+ return Boolean.TRUE;
+ }else if(this.equals(FALSE)){
+ return Boolean.FALSE;
+ }
+ return null;
+ }
+
+ @Override
+ public void setValue(Object o) {
+
+ }
+
+ static class FloatValue implements V8Value {
+ private Float value;
+
+ public FloatValue(Float value) {
+ this.value = value;
+ }
+
+ @Override
+ public V8Type getType() {
+ return V8BasicType.NUMBER_TYPE;
+ }
+
+ @Override
+ public void setValue(Float s) {
+ this.value = s;
+ }
+
+ @Override
+ public Float getValue() {
+ return value;
+ }
+ }
+
+ static class V8TypeValue implements V8Value {
+ private V8Type value;
+
+ public V8TypeValue(V8Type value) {
+ this.value = value;
+ }
+
+ @Override
+ public V8Type getType() {
+ return V8BasicType.TYPE_TYPE;
+ }
+
+ @Override
+ public void setValue(V8Type s) {
+ this.value = s;
+ }
+
+ @Override
+ public V8Type getValue() {
+ return value;
+ }
+ }
+
+ public static class StringValue implements V8Value {
+ String value;
+
+ StringValue(String literal) {
+ value = literal;
+ }
+
+ @Override
+ public V8Type getType() {
+ return V8BasicType.STRING_TYPE;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public void setValue(String s) {
+ this.value = s;
+ }
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8NamedObject.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8NamedObject.java
new file mode 100644
index 00000000000..4d486096fcf
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8NamedObject.java
@@ -0,0 +1,26 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.values;
+
+public interface V8NamedObject {
+ String getName();
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8Value.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8Value.java
new file mode 100644
index 00000000000..da7c7f901ef
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/variable/values/V8Value.java
@@ -0,0 +1,29 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.utils.variable.values;
+
+import com.github._1c_syntax.bsl.languageserver.utils.variable.types.V8TypedObject;
+
+public interface V8Value extends V8TypedObject {
+ void setValue(T t);
+ T getValue();
+}
diff --git a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json
index e38e48aed8d..eea56a53445 100644
--- a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json
+++ b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json
@@ -4,6 +4,16 @@
"type": "object",
"title": "BSL Language Server Configuration File. Parameters definition part",
"definitions": {
+ "AttachIdleHandler": {
+ "description": "Usage AttachIdleHandler",
+ "default": true,
+ "type": [
+ "boolean",
+ "object"
+ ],
+ "title": "Usage AttachIdleHandler",
+ "$id": "#/definitions/AttachIdleHandler"
+ },
"BeginTransactionBeforeTryCatch": {
"description": "Violating transaction rules for the 'BeginTransaction' method",
"default": true,
diff --git a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/schema.json b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/schema.json
index fab08d69adf..7b32925fbba 100644
--- a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/schema.json
+++ b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/schema.json
@@ -23,6 +23,9 @@
"$ref": "#/definitions/parameter"
},
"properties": {
+ "AttachIdleHandler": {
+ "$ref": "parameters-schema.json#/definitions/AttachIdleHandler"
+ },
"BeginTransactionBeforeTryCatch": {
"$ref": "parameters-schema.json#/definitions/BeginTransactionBeforeTryCatch"
},
diff --git a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic_en.properties b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic_en.properties
new file mode 100644
index 00000000000..772cd422a5d
--- /dev/null
+++ b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic_en.properties
@@ -0,0 +1,2 @@
+diagnosticMessage=Select existed method in params
+diagnosticName=Usage AttachIdleHandler
diff --git a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic_ru.properties b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic_ru.properties
new file mode 100644
index 00000000000..33b3d483c19
--- /dev/null
+++ b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnostic_ru.properties
@@ -0,0 +1,2 @@
+diagnosticMessage=Выбирите существующий метод в параметрах
+diagnosticName=Использование метода ПодключитьОбработчикОжидания
diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnosticTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnosticTest.java
new file mode 100644
index 00000000000..4f5a10bec0b
--- /dev/null
+++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/AttachIdleHandlerDiagnosticTest.java
@@ -0,0 +1,53 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright © 2018-2020
+ * Alexey Sosnoviy , Nikita Gryzlov 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.diagnostics;
+
+import org.eclipse.lsp4j.Diagnostic;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat;
+
+class AttachIdleHandlerDiagnosticTest extends AbstractDiagnosticTest {
+ AttachIdleHandlerDiagnosticTest() {
+ super(AttachIdleHandlerDiagnostic.class);
+ }
+
+
+ @Test
+ void test() {
+
+ List diagnostics = getDiagnostics();
+
+ assertThat(diagnostics).hasSize(5);
+ assertThat(diagnostics, true)
+ .hasRange(9, 4, 9, 32)
+ .hasRange(38, 0, 38, 27)
+ .hasRange(42, 0, 42, 28)
+ .hasRange(44, 0, 44, 28)
+ .hasRange(52, 0, 52, 28);
+
+
+ }
+
+}
diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CreateQueryInCycleDiagnosticTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CreateQueryInCycleDiagnosticTest.java
index 81e82a4be88..7955c15f8c0 100644
--- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CreateQueryInCycleDiagnosticTest.java
+++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/CreateQueryInCycleDiagnosticTest.java
@@ -39,7 +39,7 @@ class CreateQueryInCycleDiagnosticTest extends AbstractDiagnosticTest diagnostics = getDiagnostics();
- assertThat(diagnostics).hasSize(10);
+ assertThat(diagnostics).hasSize(11);
assertThat(diagnostics, true)
.hasRange(4, 8, 4, 36)
.hasRange(27, 23, 27, 47)
@@ -50,6 +50,7 @@ void test() {
.hasRange(66, 4, 66, 22)
.hasRange(73, 2, 73, 30)
.hasRange(79, 4, 79, 34)
- .hasRange(90, 41, 90, 71);
+ .hasRange(90, 41, 90, 71)
+ .hasRange(103, 4, 103, 25);
}
}
diff --git a/src/test/resources/diagnostics/AttachIdleHandlerDiagnostic.bsl b/src/test/resources/diagnostics/AttachIdleHandlerDiagnostic.bsl
new file mode 100644
index 00000000000..7d637174d5a
--- /dev/null
+++ b/src/test/resources/diagnostics/AttachIdleHandlerDiagnostic.bsl
@@ -0,0 +1,53 @@
+
+&НаКлиенте
+Процедура НайтиСтрокуСОшибкой(Команда)
+
+ Если ПустаяСтрока(СтрокаПоиска) Тогда
+ ТекущийЭлемент = Элементы.СтрокаПоиска;
+ Возврат;
+ КонецЕсли;
+
+ ПодключитьОбработчикОжидания("НеизвестныйПоиск", 0.1, Истина); //bad
+
+КонецПроцедуры
+
+&НаКлиенте
+Процедура НайтиСтроку(Команда)
+
+ Если ПустаяСтрока(СтрокаПоиска) Тогда
+ ТекущийЭлемент = Элементы.СтрокаПоиска;
+ Возврат;
+ КонецЕсли;
+
+ ПодключитьОбработчикОжидания("ВыполнитьПоиск", 0.1, Истина); //good
+
+КонецПроцедуры
+
+&НаКлиенте
+Процедура ВыполнитьПоиск()
+
+ НичегоНеНашли = Ложь;
+ ИскатьСтрокуНаСервере(НичегоНеНашли);
+
+ Если НичегоНеНашли Тогда
+ Предупреждение(НСтр("ru = 'Строка не найдена'"));
+ КонецЕсли;
+
+КонецПроцедуры
+
+
+ОтключитьОбработчикОжидания("НеизвестныйПоиск"); //bad
+
+ОтключитьОбработчикОжидания("ВыполнитьПоиск"); //good
+
+ПодключитьОбработчикОжидания("НайтиСтроку", 0.1, Истина); //bad
+
+ПодключитьОбработчикОжидания("ВыполнитьПоиск", 0.1, Ложь); //bad
+
+ПодключитьОбработчикОжидания("ВыполнитьПоиск", 0.1, Истина); //good
+
+ПодключитьОбработчикОжидания("ВыполнитьПоиск", 1, Ложь); //good
+
+ПодключитьОбработчикОжидания("ВыполнитьПоиск", 0.1, Переменная); //good
+
+ПодключитьОбработчикОжидания("ВыполнитьПоиск", 0.1); //bad
diff --git a/src/test/resources/diagnostics/CreateQueryInCycleDiagnostic.bsl b/src/test/resources/diagnostics/CreateQueryInCycleDiagnostic.bsl
index fd524b44328..c5f36c3ab9c 100644
--- a/src/test/resources/diagnostics/CreateQueryInCycleDiagnostic.bsl
+++ b/src/test/resources/diagnostics/CreateQueryInCycleDiagnostic.bsl
@@ -93,4 +93,13 @@
КонецЦикла;
+КонецЦикла;
+
+Запрос222 = Новый("Запрос");
+Если Ложь Тогда
+ Запрос222 = 1;
+КонецЦикла
+
+Для ит = 1 По 10 Цикл
+ Запрос222.Выполнить();// Тут
КонецЦикла;
\ No newline at end of file