1
0
mirror of https://github.com/1C-Company/v8-code-style.git synced 2024-11-28 09:33:06 +02:00

#1 Перенос подсистемы проверок строгой типизации (#448)

This commit is contained in:
Dmitriy Marmyshev 2021-09-21 13:02:36 +03:00 committed by GitHub
parent 926daee909
commit dcf348df9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 3712 additions and 8 deletions

View File

@ -33,10 +33,22 @@
- Проверка конструктора структуры содержащего больше 3х ключей
- Выполнение запроса в цикле с учетом локальных вызовов в модуле
- Проверка ОбменДанными.Загрузка в обработчике события
- Система строгой типизации кода:
- Переменная имеет тип значения
- Параметр метода имеет тип
- Функция возвращает типизированное значение
- Утверждение меняет тип
- Типизация значений в конструкторе структуры
- Вызываеемый тип пересекается с типом параметра
- Секция возвращаемого значения функции-конструктора данных
- Свойство объекта имеет тип возвращаемого значения
- Метод в объекте не найден
- Поле документирующего комментария имеет описание типа
- Конструкция "Попытка...Исключение...КонецПопытки" не содержит кода в исключении
- Аннотация для метода написана канонически
- Используется аннотация &ИзменениеИКонтроль вместо &Вместо
#### Запросы
- Временная таблица должна содержать индексы

View File

@ -15,12 +15,16 @@ Bundle-RequiredExecutionEnvironment: JavaSE-11
Automatic-Module-Name: com.e1c.v8codestyle.bsl
Bundle-ActivationPolicy: lazy
Import-Package: com._1c.g5.v8.bm.core;version="[7.0.0,8.0.0)",
com._1c.g5.v8.dt.bsl.comment;version="[3.0.0,4.0.0)",
com._1c.g5.v8.dt.bsl.common;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.bsl.documentation.comment;version="[3.0.0,4.0.0)",
com._1c.g5.v8.dt.bsl.model;version="[4.0.0,5.0.0)",
com._1c.g5.v8.dt.bsl.model.util;version="[4.6.0,5.0.0)",
com._1c.g5.v8.dt.bsl.model.util;version="[4.0.0,5.0.0)",
com._1c.g5.v8.dt.bsl.resource;version="[13.0.0,14.0.0)",
com._1c.g5.v8.dt.bsl.typesystem;version="[9.0.0,10.0.0)",
com._1c.g5.v8.dt.bsl.typesystem.util;version="[9.0.0,10.0.0)",
com._1c.g5.v8.dt.bsl.util;version="[7.0.0,8.0.0)",
com._1c.g5.v8.dt.core.platform;version="[10.0.0,11.0.0)",
com._1c.g5.v8.dt.lcore.util;version="[2.0.0,3.0.0)",
com._1c.g5.v8.dt.mcore;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.mcore.util;version="[3.6.0,4.0.0)",
@ -33,3 +37,4 @@ Import-Package: com._1c.g5.v8.bm.core;version="[7.0.0,8.0.0)",
com.e1c.g5.v8.dt.check;version="[1.0.0,2.0.0)",
com.e1c.g5.v8.dt.check.components;version="[1.0.0,2.0.0)",
com.e1c.g5.v8.dt.check.settings;version="[1.0.0,2.0.0)"
Export-Package: com.e1c.v8codestyle.bsl.strict;version="0.1.0"

View File

@ -0,0 +1,10 @@
# Data constructor function return section
Check of module strict types system that return statements of function equals documentation comment return section types
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,10 @@
# Documentation comment Field has no type defenition
Check of module strict types system that documentation comment field has section with types
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,10 @@
# Method not found in accessed object
Check that dynamicly accessed method exist in the object
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,10 @@
# Function reuturns typed value
Check of module strict types system that every function has return value type
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,10 @@
# Invocation parameter types intersects
Check of module strict types system that invocation expression has intercection with invocation parameter type
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,10 @@
# Method parameter has value type
Check of module strict types system that every method parameter has value type
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,10 @@
# Object property has return value type
Check of module strict types system that dynamicly accessed object property has reutun type
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,10 @@
# Секция возвращаемого значения функции-конструктора данных
Система строгой типизации кода проверяет что поле документирующего комментария имеет описание типа
## Неправильно
## Правильно
## См.

View File

@ -0,0 +1,10 @@
# Поле документирующего комментария имеет описание типа
Система строгой типизации кода проверяет что поле документирующего комментария имеет описание типа
## Неправильно
## Правильно
## См.

View File

@ -0,0 +1,10 @@
# Метод в объекте не найден
Система строгой типизации кода проверяет что динамически вызываемый метод существует в объекте
## Неправильно
## Правильно
## См.

View File

@ -0,0 +1,10 @@
# Функция возвращает типизированное значение
Система строгой типизации кода проверяет что каждая функция возвращает типизированное значение
## Неправильно
## Правильно
## См.

View File

@ -0,0 +1,10 @@
# Вызываеемый тип пересекается с типом параметра
Система строгой типизации кода проверяет что тип вызываемого выражения пересекается с типом параметра вызываемого метода
## Неправильно
## Правильно
## См.

View File

@ -0,0 +1,10 @@
# Параметр метода имеет тип
Система строгой типизации кода проверяет что каждый параметр метода имеет тип значения
## Неправильно
## Правильно
## См.

View File

@ -0,0 +1,10 @@
# Свойство объекта имеет тип возвращаемого значения
Система строгой типизации кода проверяет что динамическое свойство объекта имеет тип возвращаемого значения
## Неправильно
## Правильно
## См.

View File

@ -0,0 +1,10 @@
# Утверждение меняет тип
Система строгой типизации кода проверяет что утверждение (строка присвоения значения) меняет тип
## Неправильно
## Правильно
## См.

View File

@ -0,0 +1,45 @@
# Типизация значений в конструкторе структуры
Проверяет строковый литерал в конструкторе структуры что каждый ключ имеет типзированное значение.
## Неправильно
Ключи структуры инициализируются без какого-либо значения по умолчанию что устанавливает пустой тип значения для ключа структуры на всё время жизни.
```bsl
// @strict-types
Процедура Тест() Экспорт
Параметры = новый Структура("Ключ1, Ключ2, Ключ3");
// некоторый код...
Параметры.Ключ1 = 1345;
Параметры.Ключ2 = "New vlaue";
Параметры.Ключ3 = Справочники.Товары.Service;
КонецПроцедуры
```
## Правильно
Инициализируйте ключи структуры с типизированным значением по умолчанию в конструкторе или вставляйте новый ключ с типизированным значением по умолчанию.
```bsl
// @strict-types
Процедура Тест() Экспорт
Параметры = новый Структура("Ключ1, Ключ2", 0, "");
Параметры.Вставить("Ключ3", Справочники.Товары.ПустаяСсылка());
// некоторый код...
Параметры.Ключ1 = 1345;
Параметры.Ключ2 = "New vlaue";
Параметры.Ключ3 = Справочники.Товары.Услуга;
КонецПроцедуры
```
## См.

View File

@ -0,0 +1,105 @@
# Переменная имеет тип значения
Система строгой типизации кода проверяет что каждая переменная имеет тип значения
## Неправильно
Обявляемая локальная переменная в методе:
```bsl
// @strict-types
Процедура Тест() Экспорт
Перем ТестПеременная;
// здесь код
КонецПроцедуры
```
Объявляемая переменная в модуле объекта и скрытая инициализация в каком-то методе:
```bsl
// @strict-types
Перем ПараметрыОбъекта;
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
ПараметрыОбъекта = НовыеПараметрыОбъекта();
Если ЗначениеЗаполнено(ПараметрыОбъекта.Парам1) Тогда
// здесь код
КонецЕсли;
КонецПроцедуры
// Возвращаемое значение:
// Структура:
// * Парам1 - Строка -
Функция НовыеПараметрыОбъекта()
Параметры = Новый Структура();
Параметры.Вставить("Парам1", "Строковое значение");
Возврат Параметры;
КонецФункции
```
## Правильно
Инициализируйте локальную переменную с пустым значением по умолчанию:
```bsl
// @strict-types
Процедура Тест() Экспорт
ТестПеременная = 0;
// code here
КонецПроцедуры
```
Инициализируйте переменную модуля значением по умоланию в коде модуля и типизируйте строчным типизирующим комментарим в месте определения переменной.
```bsl
// @strict-types
Перем ПараметрыОбъекта; // См. НовыеПараметрыОбъекта
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если ЗначениеЗаполнено(ПараметрыОбъекта.Парам1) Тогда
// code here
КонецЕсли;
КонецПроцедуры
// Возвращаемое значение:
// Структура:
// * Парам1 - Строка -
Функция НовыеПараметрыОбъекта()
Параметры = Новый Структура();
Параметры.Вставить("Парам1", "String value");
Возврат Параметры;
КонецФункции
// Обязательная инициализация значения в коде модуля
ПараметрыОбъекта = НовыеПараметрыОбъекта();
```
## См.

View File

@ -0,0 +1,10 @@
# Statement type change
Check of module strict types system that statement does not change type
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,45 @@
# Structure contstructor value types
Checks Structure constructor string literal that each key has typed value.
## Noncompliant Code Example
Structure keys initalizing without any default value that set empty types for the structure key for lifetime.
```bsl
// @strict-types
Procedure Test() Export
Params = new Structure("Key1, Key2, Key3");
// some code...
Params.Key1 = 1345;
Params.Key2 = "New vlaue";
Params.Key3 = Catalogs.Products.Service;
EndProcedure
```
## Compliant Solution
Initialize structure keys with default typed values in the constructor or insert new key with default typed value.
```bsl
// @strict-types
Procedure Test() Export
Params = new Structure("Key1, Key2", 0, "");
Params.Insert("Key3", Catalogs.Products.EmptyRef());
// some code...
Params.Key1 = 1345;
Params.Key2 = "New vlaue";
Params.Key3 = Catalogs.Products.Service;
EndProcedure
```
## See

View File

@ -0,0 +1,105 @@
# Variable has value type
Check of module strict types system that every variable has value type
## Noncompliant Code Example
Declared local variable in method:
```bsl
// @strict-types
Procedure Test() Export
Var TestVar;
// code here
EndProcedure
```
Declared variable in object module and hidden initialization in some method:
```bsl
// @strict-types
Var ObjectParameters;
Procedure BeforeWrite(Cancel)
If DataExchange.Load Then
Return;
EndIf;
ObjectParameters = NewObjectParameters();
If ValueIsFilled(ObjectParameters.Param1) Then
// code here
EndIf;
EndProcedure
// Returns:
// Structure:
// * Param1 - String -
Function NewObjectParameters()
Params = New Structure();
Params.Insert("Param1", "String value");
return Params;
EndFunction
```
## Compliant Solution
Initialize local variable with default empty value:
```bsl
// @strict-types
Procedure Test() Export
TestVar = 0;
// code here
EndProcedure
```
Initialize module variable with default value in module statements and add typed in-line documentation comments for variable declaration.
```bsl
// @strict-types
Var ObjectParameters; // see NewObjectParameters
Procedure BeforeWrite(Cancel)
If DataExchange.Load Then
Return;
EndIf;
If ValueIsFilled(ObjectParameters.Param1) Then
// code here
EndIf;
EndProcedure
// Returns:
// Structure:
// * Param1 - String -
Function NewObjectParameters()
Params = New Structure();
Params.Insert("Param1", "String value");
Return Params;
EndFunction
// Explicitly initialize value in module statements
ObjectParameters = NewObjectParameters();
```
## See

View File

@ -15,4 +15,6 @@ providerName = 1C-Soft LLC
pluginName = 1C:Code style V8 Bsl plugin
category.bsl.title = Built-in script language
category.bls.description = Checks of 1C:Enterprise build-in module language by 1C:Development standard (code style)
category.bsl.description = Checks of 1C:Enterprise build-in module language by 1C:Development standard (code style)
category.bsl.strict.title = Strict types system
category.bsl.strict.description = Checks of 1C:Enterprise build-in module language that each object strictly typed

View File

@ -20,11 +20,16 @@
<category
category="com.e1c.v8codestyle"
description="%category.bls.description"
description="%category.bsl.description"
id="com.e1c.v8codestyle.bsl"
title="%category.bsl.title">
</category>
<category
category="com.e1c.v8codestyle.bsl"
description="%category.bsl.strict.description"
id="com.e1c.v8codestyle.bsl.strict"
title="%category.bsl.strict.title">
</category>
<check
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.StructureCtorTooManyKeysCheck">
@ -49,6 +54,48 @@
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.ChangeAndValidateInsteadOfAroundCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.MethodParamTypeCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.VariableTypeCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.DynamicFeatureAccessTypeCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.DynamicFeatureAccessMethodNotFoundCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.SimpleStatementTypeCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.InvocationParamIntersectionCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.FunctionReturnTypeCheck">
</check>
<!-- Disabled untill release 2021.2.6+
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.FunctionCtorReturnSectionCheck">
</check>
-->
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.DocCommentFieldTypeCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl.strict"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.strict.check.StructureCtorValueTypeCheck">
</check>
</extension>

View File

@ -13,8 +13,10 @@
###############################################################################
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
category.bls.description = Проверки встроенного языка исполнения 1С:Предприятия по Старндартам разработки
category.bsl.title = Встроенный язык исполнения
category.bsl.description = Проверки встроенного языка исполнения 1С:Предприятия по Старндартам разработки
category.bsl.strict.description = Проверки встроенного языка исполнения 1С:Предприятия, что каждый объект строго типизирован
category.bsl.strict.title = Система строгой типизации
category.bsl.title = Встроенный язык исполнения
pluginName = 1С:Стандарты разработки V8 плагин Встроенного языка

View File

@ -0,0 +1,141 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import com._1c.g5.v8.dt.bsl.documentation.comment.BslCommentUtils;
import com._1c.g5.v8.dt.bsl.documentation.comment.IBslCommentToken;
import com._1c.g5.v8.dt.bsl.model.Module;
/**
* The utility class for strict-types system.
*
* @author Dmitriy Marmyshev
*/
public final class StrictTypeUtil
{
/** The strict-types annotation using in module header to activate checks */
public static final String STRICT_TYPE_ANNOTATION = "@strict-types"; //$NON-NLS-1$
public static final String BSL_FILE_EXTENSION = "bsl"; //$NON-NLS-1$
private static final int COMMENT_LENGTH = IBslCommentToken.LINE_STARTER.length();
/**
* Checks for {@code @strict-types} annotation in BSL module file.
*
* @param file the file of BSL module, cannot be {@code null}.
* @return true, if the module has {@code @strict-types} annotation in module header
* @throws CoreException the core exception
* @throws IOException Signals that an I/O exception has occurred.
*/
public static boolean hasStrictTypeAnnotation(IFile file) throws CoreException, IOException
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContents(), file.getCharset())))
{
String line = reader.readLine();
while (line != null)
{
line = line.trim();
if (!line.isEmpty() && !line.startsWith(IBslCommentToken.LINE_STARTER))
{
return false;
}
if (line.length() > 0 && line.substring(COMMENT_LENGTH).trim().startsWith(STRICT_TYPE_ANNOTATION))
{
return true;
}
line = reader.readLine();
}
}
return false;
}
/**
* Checks for {@code @strict-types} annotation in module description.
*
* @param object the object of BSL module, cannot be {@code null}.
* @return true, if module has annotation in header
*/
public static boolean hasStrictTypeAnnotation(EObject object)
{
Module module = EcoreUtil2.getContainerOfType(object, Module.class);
if (module == null)
{
return false;
}
return hasStrictTypeAnnotation(module);
}
/**
* Checks for {@code @strict-types} annotation in module description.
*
* @param module the module, cannot be {@code null}.
* @return true, if module has annotation in header
*/
public static boolean hasStrictTypeAnnotation(Module module)
{
ICompositeNode node = NodeModelUtils.getNode(module);
node = node.getRootNode();
return hasStrictTypeAnnotation(node);
}
/**
* Checks for {@code @strict-types} annotation in module description.
*
* @param root the root, cannot be {@code null}.
* @return true, if module has annotation in header
*/
public static boolean hasStrictTypeAnnotation(INode root)
{
for (ILeafNode node : root.getLeafNodes())
{
if (!node.isHidden())
{
return false;
}
if (BslCommentUtils.isCommentNode(node)
&& node.getText().substring(COMMENT_LENGTH).trim().startsWith(STRICT_TYPE_ANNOTATION))
{
return true;
}
}
return false;
}
private StrictTypeUtil()
{
throw new IllegalAccessError();
}
}

View File

@ -0,0 +1,328 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.IScopeProvider;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.documentation.comment.BslMultiLineCommentDocumentationProvider;
import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.ExplicitVariable;
import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
import com._1c.g5.v8.dt.bsl.resource.DynamicFeatureAccessComputer;
import com._1c.g5.v8.dt.bsl.resource.TypesComputer;
import com._1c.g5.v8.dt.bsl.typesystem.util.TypeSystemUtil;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.mcore.Environmental;
import com._1c.g5.v8.dt.mcore.McorePackage;
import com._1c.g5.v8.dt.mcore.Type;
import com._1c.g5.v8.dt.mcore.TypeItem;
import com._1c.g5.v8.dt.mcore.TypeSet;
import com._1c.g5.v8.dt.mcore.util.Environments;
import com._1c.g5.v8.dt.mcore.util.McoreUtil;
import com._1c.g5.v8.dt.platform.IEObjectDynamicTypeNames;
import com._1c.g5.v8.dt.platform.IEObjectTypeNames;
import com.e1c.g5.v8.dt.check.components.BasicCheck;
import com.google.common.collect.Sets;
/**
* Abstract check of types in module objects. Allows to compute types respecting system enums,
* compare intersections of type collections and etc.
*
* @author Dmitriy Marmyshev
*/
public abstract class AbstractTypeCheck
extends BasicCheck
{
private static final Collection<String> ALL_REF_TYPE_SET_PARENT_TYPE_NAMES =
Set.of(IEObjectDynamicTypeNames.CATALOG_REF_TYPE_NAME, IEObjectDynamicTypeNames.DOCUMENT_REF_TYPE_NAME,
IEObjectDynamicTypeNames.ENUM_REF_TYPE_NAME, IEObjectDynamicTypeNames.COC_REF_TYPE_NAME,
IEObjectDynamicTypeNames.COA_REF_TYPE_NAME, IEObjectDynamicTypeNames.CALCULATION_TYPE_REF_TYPE_NAME,
IEObjectDynamicTypeNames.BP_REF_TYPE_NAME, IEObjectDynamicTypeNames.BP_ROUTEPOINT_TYPE_NAME,
IEObjectDynamicTypeNames.TASK_REF_TYPE_NAME, IEObjectDynamicTypeNames.EXCHANGE_PLAN_REF_TYPE_NAME);
protected final IResourceLookup resourceLookup;
protected final IBslPreferences bslPreferences;
protected final TypesComputer typeComputer;
protected final DynamicFeatureAccessComputer dynamicFeatureAccessComputer;
private final IScopeProvider scopeProvider;
private final IQualifiedNameConverter qualifiedNameConverter;
private final BslMultiLineCommentDocumentationProvider commentProvider;
/**
* Instantiates a new abstract type check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
protected AbstractTypeCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IQualifiedNameConverter qualifiedNameConverter)
{
super();
this.resourceLookup = resourceLookup;
this.bslPreferences = bslPreferences;
IResourceServiceProvider rsp =
IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(URI.createURI("*.bsl")); //$NON-NLS-1$
this.typeComputer = rsp.get(TypesComputer.class);
this.dynamicFeatureAccessComputer = rsp.get(DynamicFeatureAccessComputer.class);
this.scopeProvider = rsp.get(IScopeProvider.class);
this.commentProvider = rsp.get(BslMultiLineCommentDocumentationProvider.class);
this.qualifiedNameConverter = qualifiedNameConverter;
}
/**
* Checks if the object has empty types.
*
* @param object the object, cannot be {@code null}.
* @return true, if the object has empty types
*/
protected boolean isEmptyTypes(EObject object)
{
Environmental envs = EcoreUtil2.getContainerOfType(object, Environmental.class);
if (envs == null)
{
return true;
}
Environments actualEnvs = bslPreferences.getLoadEnvs(object).intersect(envs.environments());
if (actualEnvs.isEmpty())
{
return true;
}
List<TypeItem> types = computeTypes(object, actualEnvs);
if (types.isEmpty() && object instanceof ExplicitVariable)
{
IScope typeScope = scopeProvider.getScope(object, McorePackage.Literals.TYPE_DESCRIPTION__TYPES);
IProject project = resourceLookup.getProject(object);
boolean oldFormatComment = bslPreferences.getDocumentCommentProperties(project).oldCommentFormat();
Collection<TypeItem> commentTypes = TypeSystemUtil.computeCommentTypes(object, typeScope, scopeProvider,
qualifiedNameConverter, commentProvider, oldFormatComment);
return commentTypes.isEmpty();
}
return types.isEmpty();
}
/**
* Compute types with respect to system enumeration.
*
* @param object the object, cannot be {@code null}.
* @param envs the environments, cannot be {@code null}.
* @return the list of types, cannot return {@code null}.
*/
protected List<TypeItem> computeTypes(EObject object, Environments envs)
{
List<TypeItem> types = typeComputer.computeTypes(object, envs);
if (types.isEmpty() && object instanceof DynamicFeatureAccess
&& ((DynamicFeatureAccess)object).getSource() instanceof FeatureAccess)
{
// Bypass system enum types with property without type
DynamicFeatureAccess dfa = (DynamicFeatureAccess)object;
FeatureAccess fa = (FeatureAccess)dfa.getSource();
List<TypeItem> sourceTypes = typeComputer.computeTypes(fa, envs);
if (sourceTypes.size() == 1)
{
String typeName = fa.getName();
String propertyName = dfa.getName();
TypeItem type = sourceTypes.get(0);
if ((typeName.equalsIgnoreCase(McoreUtil.getTypeNameRu(type))
|| typeName.equalsIgnoreCase(McoreUtil.getTypeName(type)))
&& dynamicFeatureAccessComputer.getAllProperties(sourceTypes, object.eResource())
.stream()
.flatMap(e -> e.getFirst().stream())
.anyMatch(p -> propertyName.equalsIgnoreCase(p.getNameRu())
|| propertyName.equalsIgnoreCase(p.getName())))
{
return sourceTypes;
}
}
}
return types;
}
/**
* Checks that collections of {@link TypeItem} have common item
* @param expectedTypes expected collection of {@link TypeItem}, cannot be <code>null</code>
* @param realTypes real collection of {@link TypeItem}, cannot be <code>null</code>
* @param context {@link EObject} for resolving proxy checking types, cannot be <code>null</code>
* @return <code>true</code> if intersection was detected
*/
protected static boolean intersectTypeItem(List<TypeItem> expectedTypes, List<TypeItem> realTypes, EObject context)
{
if (expectedTypes.isEmpty())
{
return true;
}
List<TypeItem> parentTypes = getParentTypes(expectedTypes);
parentTypes.addAll(expectedTypes);
Collection<String> expectedTypesNames = getTypeNames(parentTypes, context);
expectedTypesNames.addAll(getCastingType(expectedTypesNames));
expectedTypesNames = Sets.newLinkedHashSet(expectedTypesNames);
if (expectedTypesNames.contains(IEObjectTypeNames.ARBITRARY)
|| expectedTypesNames.contains(IEObjectTypeNames.UNDEFINED)
|| expectedTypesNames.contains(IEObjectTypeNames.REFERENCE_TO_OBJECT_OF_INFORMATION_BASE)
|| expectedTypesNames.contains(IEObjectTypeNames.XDTO_DATA_VALUE)
|| expectedTypesNames.contains(IEObjectTypeNames.XDTO_DATA_OBJECT))
{
return true;
}
if (realTypes.isEmpty())
{
return false;
}
parentTypes = getParentTypes(realTypes);
parentTypes.addAll(realTypes);
Collection<String> realTypesNames = getTypeNames(parentTypes, context);
if (!expectedTypesNames.isEmpty() && !realTypesNames.isEmpty())
{
expectedTypesNames.retainAll(realTypesNames);
return !expectedTypesNames.isEmpty();
}
else
{
return true;
}
}
private static Collection<? extends String> getCastingType(Collection<String> expectedTypesNames)
{
List<String> castTypeNames = new ArrayList<>();
for (String typeName : expectedTypesNames)
{
if (IEObjectTypeNames.STRUCTURE.equals(typeName))
{
castTypeNames.add(IEObjectTypeNames.FIXED_STRUCTURE);
}
}
return castTypeNames;
}
private static List<TypeItem> getParentTypes(List<TypeItem> theFirstCollectionTypes)
{
List<TypeItem> types = new ArrayList<>(theFirstCollectionTypes);
List<TypeItem> parentTypes = new ArrayList<>();
Iterator<TypeItem> iterator = types.iterator();
while (iterator.hasNext())
{
TypeItem type = iterator.next();
while (type instanceof Type && ((Type)type).getParentType() != null)
{
parentTypes.add(((Type)type).getParentType());
type = ((Type)type).getParentType();
}
}
return parentTypes;
}
private static Collection<String> getTypeNames(List<TypeItem> parentTypes, EObject context)
{
Set<String> typeNames = new HashSet<>();
for (TypeItem type : parentTypes)
{
String typeName = McoreUtil.getTypeName(type);
String[] parts = typeName.split("\\."); //$NON-NLS-1$
if (parts.length == 2)
{
typeNames.add(parts[0]);
if (type.eIsProxy() && (IEObjectTypeNames.DEFINED_TYPE.equals(parts[0])
|| IEObjectTypeNames.CHARACTERISTIC.equals(parts[0])))
{
type = (TypeItem)EcoreUtil.resolve(type, context);
}
}
typeNames.add(typeName);
if (type instanceof TypeSet)
{
if (parts.length == 2)
{
typeNames.addAll(((TypeSet)type).getTypes()
.stream()
.map(typeItem -> McoreUtil.getTypeName(typeItem))
.collect(Collectors.toList()));
}
else if (IEObjectTypeNames.ANY_REF.equals(typeName))
{
typeNames.addAll(ALL_REF_TYPE_SET_PARENT_TYPE_NAMES);
}
else
{
String parentTypeName = getTypeSetItemParentTypeName(typeName);
if (parentTypeName != null)
{
typeNames.add(parentTypeName);
}
}
}
}
return typeNames;
}
private static String getTypeSetItemParentTypeName(String typeName)
{
switch (typeName)
{
case IEObjectTypeNames.CATALOG_REF:
return IEObjectDynamicTypeNames.CATALOG_REF_TYPE_NAME;
case IEObjectTypeNames.DOCUMENT_REF:
return IEObjectDynamicTypeNames.DOCUMENT_REF_TYPE_NAME;
case IEObjectTypeNames.ENUM_REF:
return IEObjectDynamicTypeNames.ENUM_REF_TYPE_NAME;
case IEObjectTypeNames.CHART_OF_CHARACTERISTIC_TYPES_REF:
return IEObjectDynamicTypeNames.COC_REF_TYPE_NAME;
case IEObjectTypeNames.CHART_OF_ACCOUNTS_REF:
return IEObjectDynamicTypeNames.COA_REF_TYPE_NAME;
case IEObjectTypeNames.CHART_OF_CALCULATION_TYPES_REF:
return IEObjectDynamicTypeNames.CALCULATION_TYPE_REF_TYPE_NAME;
case IEObjectTypeNames.BUSINESS_PROCESS_REF:
return IEObjectDynamicTypeNames.BP_REF_TYPE_NAME;
case IEObjectTypeNames.BUSINESS_PROCESS_ROUTE_POINT_REF:
return IEObjectDynamicTypeNames.BP_ROUTEPOINT_TYPE_NAME;
case IEObjectTypeNames.TASK_REF:
return IEObjectDynamicTypeNames.TASK_REF_TYPE_NAME;
case IEObjectTypeNames.EXCHANGE_PLAN_REF:
return IEObjectDynamicTypeNames.EXCHANGE_PLAN_REF_TYPE_NAME;
default:
return null;
}
}
}

View File

@ -0,0 +1,123 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import static com.e1c.v8codestyle.bsl.strict.check.StrictTypeAnnotationCheckExtension.PARAM_CHECK_ANNOTATION_IN_MODULE_DESCRIPTION;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import com._1c.g5.v8.dt.bsl.documentation.comment.BslDocumentationComment;
import com._1c.g5.v8.dt.bsl.documentation.comment.IDescriptionPart;
import com._1c.g5.v8.dt.bsl.documentation.comment.LinkPart;
import com._1c.g5.v8.dt.bsl.documentation.comment.TextPart;
import com._1c.g5.v8.dt.bsl.documentation.comment.TypeSection.FieldDefinition;
import com.e1c.g5.v8.dt.bsl.check.DocumentationCommentBasicDelegateCheck;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.e1c.v8codestyle.bsl.strict.StrictTypeUtil;
import com.google.common.collect.Lists;
/**
* Checks the documentation comment {@link FieldDefinition field} that has section with types definition.
* By default it not respect {@code //@strict-types} annotation in module header.
*
* @author Dmitriy Marmyshev
*/
public class DocCommentFieldTypeCheck
extends DocumentationCommentBasicDelegateCheck
{
private static final String CHECK_ID = "doc-comment-field-type"; //$NON-NLS-1$
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.DocCommentFieldTypeCheck_title)
.description(Messages.DocCommentFieldTypeCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MINOR)
.issueType(IssueType.CODE_STYLE)
.delegate(FieldDefinition.class);
builder.parameter(PARAM_CHECK_ANNOTATION_IN_MODULE_DESCRIPTION, Boolean.class, Boolean.FALSE.toString(),
Messages.StrictTypeAnnotationCheckExtension_Check__strict_types_annotation_in_module_desctioption);
}
@Override
protected void checkDocumentationCommentObject(IDescriptionPart object, BslDocumentationComment root,
DocumentationCommentResultAcceptor resultAceptor, ICheckParameters parameters, IProgressMonitor monitor)
{
if (monitor.isCanceled() || parameters.getBoolean(PARAM_CHECK_ANNOTATION_IN_MODULE_DESCRIPTION)
&& !StrictTypeUtil.hasStrictTypeAnnotation(root.getModule()))
{
return;
}
FieldDefinition fieldDef = (FieldDefinition)object;
if (isFieldTypeEmpty(fieldDef))
{
String message = MessageFormat.format(Messages.DocCommentFieldTypeCheck_Field__N__has_no_type_definition,
fieldDef.getName());
resultAceptor.addIssue(message, fieldDef.getName().length());
}
}
private boolean isFieldTypeEmpty(FieldDefinition fieldDef)
{
if (!fieldDef.getTypeSections().isEmpty())
{
return false;
}
List<IDescriptionPart> parts = fieldDef.getDescription().getParts();
Collection<LinkPart> linkParts = Lists.newArrayListWithCapacity(parts.size());
int lastLine = -1;
for (IDescriptionPart part : parts)
{
if (part instanceof LinkPart && lastLine != part.getLineNumber())
{
linkParts.add((LinkPart)part);
lastLine = part.getLineNumber();
}
else
{
if (part instanceof TextPart)
{
String text = ((TextPart)part).getText();
if (text != null
&& (".".equals(text.trim()) || "-".equals(text.trim()) && lastLine != part.getLineNumber())) //$NON-NLS-1$ //$NON-NLS-2$
{
continue;
}
}
return true;
}
}
return linkParts.isEmpty();
}
}

View File

@ -0,0 +1,128 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.DYNAMIC_FEATURE_ACCESS;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.FEATURE_ACCESS__NAME;
import java.text.MessageFormat;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.FeatureEntry;
import com._1c.g5.v8.dt.bsl.model.util.BslUtil;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.mcore.Environmental;
import com._1c.g5.v8.dt.mcore.util.Environments;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.google.inject.Inject;
/**
* Checks that {@link DynamicFeatureAccess dynamic method} exists in accessed object.
*
* @author Dmitriy Marmyshev
*/
public class DynamicFeatureAccessMethodNotFoundCheck
extends AbstractTypeCheck
{
private static final String CHECK_ID = "dynamic-access-method-not-found"; //$NON-NLS-1$
/**
* Instantiates a new dynamic feature access method not found check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
@Inject
public DynamicFeatureAccessMethodNotFoundCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IQualifiedNameConverter qualifiedNameConverter)
{
super(resourceLookup, bslPreferences, qualifiedNameConverter);
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.DynamicFeatureAccessMethodNotFoundCheck_title)
.description(Messages.DynamicFeatureAccessMethodNotFoundCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.extension(new ModuleTopObjectNameFilterExtension())
.extension(new StrictTypeAnnotationCheckExtension())
.module()
.checkedObjectType(DYNAMIC_FEATURE_ACCESS);
}
@Override
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
IProgressMonitor monitor)
{
if (monitor.isCanceled() || !(object instanceof EObject))
{
return;
}
DynamicFeatureAccess fa = (DynamicFeatureAccess)object;
if (fa.getName() == null || fa.getName().isBlank())
{
return;
}
boolean isMethod = BslUtil.getInvocation(fa) != null;
if (isMethod && isEmptySource(fa))
{
String message = MessageFormat
.format(Messages.DynamicFeatureAccessTypeCheck_Method_M_not_found_in_accessed_object, fa.getName());
resultAceptor.addIssue(message, FEATURE_ACCESS__NAME);
}
}
private boolean isEmptySource(DynamicFeatureAccess object)
{
Environmental envs = EcoreUtil2.getContainerOfType(object, Environmental.class);
if (envs == null)
{
return true;
}
Environments actualEnvs = bslPreferences.getLoadEnvs(object).intersect(envs.environments());
if (actualEnvs.isEmpty())
{
return true;
}
List<FeatureEntry> objects = dynamicFeatureAccessComputer.getLastObject(object, actualEnvs);
return objects.isEmpty();
}
}

View File

@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.DYNAMIC_FEATURE_ACCESS;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.FEATURE_ACCESS__NAME;
import java.text.MessageFormat;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
import com._1c.g5.v8.dt.bsl.model.util.BslUtil;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.google.inject.Inject;
/**
* Checks {@link DynamicFeatureAccess dynamic property} has return types.
*
* @author Dmitriy Marmyshev
*/
public class DynamicFeatureAccessTypeCheck
extends AbstractTypeCheck
{
private static final String CHECK_ID = "property-return-type"; //$NON-NLS-1$
/**
* Instantiates a new dynamic feature access type check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
@Inject
public DynamicFeatureAccessTypeCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IQualifiedNameConverter qualifiedNameConverter)
{
super(resourceLookup, bslPreferences, qualifiedNameConverter);
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.DynamicFeatureAccessTypeCheck_title)
.description(Messages.DynamicFeatureAccessTypeCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.extension(new ModuleTopObjectNameFilterExtension())
.extension(new StrictTypeAnnotationCheckExtension())
.module()
.checkedObjectType(DYNAMIC_FEATURE_ACCESS);
}
@Override
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
IProgressMonitor monitor)
{
if (monitor.isCanceled() || !(object instanceof EObject))
{
return;
}
FeatureAccess fa = (FeatureAccess)object;
if (fa.getName() == null || fa.getName().isBlank())
{
return;
}
boolean isMethod = BslUtil.getInvocation(fa) != null;
if (!isMethod && isEmptyTypes((EObject)object))
{
String message = MessageFormat
.format(Messages.DynamicFeatureAccessTypeCheck_Feature_access_M_has_no_return_type, fa.getName());
resultAceptor.addIssue(message, FEATURE_ACCESS__NAME);
}
}
}

View File

@ -0,0 +1,385 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.IScopeProvider;
import org.eclipse.xtext.util.Pair;
import com._1c.g5.v8.dt.bsl.comment.DocumentationCommentProperties;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.documentation.comment.BslDocumentationComment;
import com._1c.g5.v8.dt.bsl.documentation.comment.BslDocumentationComment.ReturnSection;
import com._1c.g5.v8.dt.bsl.documentation.comment.BslMultiLineCommentDocumentationProvider;
import com._1c.g5.v8.dt.bsl.documentation.comment.IDescriptionPart;
import com._1c.g5.v8.dt.bsl.model.BslPackage.Literals;
import com._1c.g5.v8.dt.bsl.model.Function;
import com._1c.g5.v8.dt.bsl.model.ReturnStatement;
import com._1c.g5.v8.dt.bsl.resource.DynamicFeatureAccessComputer;
import com._1c.g5.v8.dt.bsl.resource.TypesComputer;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.core.platform.IV8Project;
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
import com._1c.g5.v8.dt.mcore.McorePackage;
import com._1c.g5.v8.dt.mcore.Property;
import com._1c.g5.v8.dt.mcore.TypeItem;
import com._1c.g5.v8.dt.mcore.util.McoreUtil;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com._1c.g5.v8.dt.platform.IEObjectTypeNames;
import com.e1c.g5.v8.dt.bsl.check.DocumentationCommentBasicDelegateCheck;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.e1c.v8codestyle.bsl.strict.StrictTypeUtil;
import com.google.common.base.Predicates;
import com.google.inject.Inject;
/**
* Documenting comment validator.
* Validate user's data types of function constructor in return types specified in documenting comments.
*
* @author Dmitriy Marmyshev
*
*/
public class FunctionCtorReturnSectionCheck
extends DocumentationCommentBasicDelegateCheck
{
private static final String CHECK_ID = "constructor-function-return-section"; //$NON-NLS-1$
private static final String PARAM_CHECK_TYPES = "checkTypes"; //$NON-NLS-1$
private static final Set<String> DEFAULT_CHECK_TYPES = Set.of(IEObjectTypeNames.STRUCTURE,
IEObjectTypeNames.FIXED_STRUCTURE, IEObjectTypeNames.VALUE_TABLE, IEObjectTypeNames.VALUE_TREE);
private final TypesComputer typesComputer;
private final DynamicFeatureAccessComputer dynamicComputer;
private final IScopeProvider scopeProvider;
private final IQualifiedNameConverter qualifiedNameConverter;
private final BslMultiLineCommentDocumentationProvider commentProvider;
private final IResourceLookup resourceLookup;
private final IV8ProjectManager v8ProjectManager;
private final IBslPreferences bslPreferences;
/**
* Instantiates a new function constructor documentation comment return section check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param v8ProjectManager the v8 project manager service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
*/
@Inject
public FunctionCtorReturnSectionCheck(IResourceLookup resourceLookup, IV8ProjectManager v8ProjectManager,
IQualifiedNameConverter qualifiedNameConverter, IBslPreferences bslPreferences)
{
super();
IResourceServiceProvider rsp =
IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(URI.createURI("*.bsl")); //$NON-NLS-1$
this.typesComputer = rsp.get(TypesComputer.class);
this.dynamicComputer = rsp.get(DynamicFeatureAccessComputer.class);
this.scopeProvider = rsp.get(IScopeProvider.class);
this.commentProvider = rsp.get(BslMultiLineCommentDocumentationProvider.class);
this.qualifiedNameConverter = qualifiedNameConverter;
this.resourceLookup = resourceLookup;
this.v8ProjectManager = v8ProjectManager;
this.bslPreferences = bslPreferences;
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.FunctionCtorReturnSectionCheck_title)
.description(Messages.FunctionCtorReturnSectionCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.delegate(ReturnSection.class);
builder.parameter(PARAM_CHECK_TYPES, String.class, String.join(",", DEFAULT_CHECK_TYPES), //$NON-NLS-1$
Messages.FunctionCtorReturnSectionCheck_User_extandable_Data_type_list_comma_separated);
}
@Override
protected void checkDocumentationCommentObject(IDescriptionPart object, BslDocumentationComment root,
DocumentationCommentResultAcceptor resultAceptor, ICheckParameters parameters, IProgressMonitor monitor)
{
if (monitor.isCanceled()
|| !(root.getMethod() instanceof Function) && !StrictTypeUtil.hasStrictTypeAnnotation(root.getModule()))
{
return;
}
ReturnSection returnSection = (ReturnSection)object;
Function method = (Function)root.getMethod();
IScope typeScope = scopeProvider.getScope(method, McorePackage.Literals.TYPE_DESCRIPTION__TYPES);
IProject project = resourceLookup.getProject(root.getModule());
boolean isRussianScript = isRussianScriptVariantProject(project);
DocumentationCommentProperties props = bslPreferences.getDocumentCommentProperties(project);
boolean oldFormat = props.oldCommentFormat();
Collection<TypeItem> computedReturnTypes = root.computeReturnTypes(typeScope, scopeProvider,
qualifiedNameConverter, commentProvider, oldFormat, method);
Set<String> checkTypes = getCheckTypes(parameters);
List<String> computedReturnTypeNames =
computedReturnTypes.stream().map(McoreUtil::getTypeName).collect(Collectors.toList());
if (isUserDataTypes(computedReturnTypeNames, checkTypes))
{
//@formatter:off
List<ReturnStatement> returns = method.allStatements()
.stream()
.filter(ReturnStatement.class::isInstance)
.map(ReturnStatement.class::cast)
.collect(Collectors.toList());
//@formatter:on
Resource res = method.eResource();
Collection<Pair<Collection<Property>, TypeItem>> coputedProperties =
dynamicComputer.getAllProperties(computedReturnTypes, res);
for (ReturnStatement statment : returns)
{
List<TypeItem> returnTypes =
typesComputer.computeTypes(statment.getExpression(), method.environments());
Collection<Pair<Collection<Property>, TypeItem>> properties =
dynamicComputer.getAllProperties(returnTypes, res);
for (TypeItem returnType : returnTypes)
{
String returnTypeName = McoreUtil.getTypeName(returnType);
if (computedReturnTypeNames.contains(returnTypeName))
{
if (isUserDataTypes(List.of(returnTypeName), checkTypes))
{
Optional<Pair<Collection<Property>, TypeItem>> declaredProperties =
coputedProperties.stream()
.filter(t -> McoreUtil.getTypeName(t.getSecond()).equals(returnTypeName))
.findAny();
Optional<Pair<Collection<Property>, TypeItem>> typeProperties = properties.stream()
.filter(t -> McoreUtil.getTypeName(t.getSecond()).equals(returnTypeName))
.findAny();
checkTypeProperties(method, statment, isRussianScript, returnType, declaredProperties.get(),
typeProperties.get(), resultAceptor);
}
}
else if (isWarningReturnNonDeclaredType(method, returnSection, returnType, computedReturnTypes))
{
addWarningReturnNonDeclaredType(statment, isRussianScript, returnType, returnTypeName,
resultAceptor);
}
}
}
}
}
private Set<String> getCheckTypes(ICheckParameters parameters)
{
String[] types = parameters.getString(PARAM_CHECK_TYPES).replace(" ", " ").split(","); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Set<String> checkTypes = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
checkTypes.addAll(Set.of(types));
return checkTypes;
}
private void checkTypeProperties(Function function, ReturnStatement statment, boolean useRussianScript,
TypeItem returnType, Pair<Collection<Property>, TypeItem> declaredProperties,
Pair<Collection<Property>, TypeItem> typeProperties, DocumentationCommentResultAcceptor resultAceptor)
{
if (declaredProperties == null || typeProperties == null)
{
return;
}
List<String> declaredProertyNames = new ArrayList<>();
// check declared properties and types
for (Property declaredProperty : declaredProperties.getFirst())
{
String propertyName = useRussianScript ? declaredProperty.getNameRu() : declaredProperty.getName();
declaredProertyNames.add(propertyName);
List<String> declaredType =
declaredProperty.getTypes().stream().map(McoreUtil::getTypeName).collect(Collectors.toList());
if (declaredType.isEmpty())
{
continue;
}
List<TypeItem> types = typeProperties.getFirst()
.stream()
.filter(p -> useRussianScript ? p.getNameRu().equals(declaredProperty.getNameRu())
: p.getName().equals(declaredProperty.getName()))
.flatMap(p -> p.getTypes().stream())
.collect(Collectors.toList());
List<TypeItem> types2 = types.stream()
.filter(t -> !declaredType.contains(McoreUtil.getTypeName(t)))
.collect(Collectors.toList());
if (types.isEmpty())
{
addWarningDeclaredNonReturningProperty(statment, useRussianScript, declaredProperty, resultAceptor);
}
else if (!types2.isEmpty())
{
addWarningDeclaredNonReturningPropertyType(statment, useRussianScript, declaredProperty, types2,
resultAceptor);
}
}
// check for non declared properties
if (isWarningReturnNonDeclaredProperty(function, statment, declaredProperties.getFirst()))
{
List<String> nonDeclaredProperties = typeProperties.getFirst()
.stream()
.map(useRussianScript ? Property::getNameRu : Property::getName)
.filter(Predicates.not(declaredProertyNames::contains))
.collect(Collectors.toList());
if (!nonDeclaredProperties.isEmpty())
{
addWarningNonDeclaredReturningProperty(statment, useRussianScript, nonDeclaredProperties,
resultAceptor);
}
}
}
private void addWarningReturnNonDeclaredType(ReturnStatement statment, boolean isRussianScript, TypeItem returnType,
String returnTypeName, DocumentationCommentResultAcceptor resultAceptor)
{
final String message = MessageFormat.format(Messages.FunctionCtorReturnSectionCheck_Return_non_declared_type__T,
isRussianScript ? McoreUtil.getTypeNameRu(returnType) : returnTypeName);
resultAceptor.addIssue(message, statment, Literals.RETURN_STATEMENT__EXPRESSION);
}
private boolean isWarningReturnNonDeclaredType(Function function, ReturnSection returnSection, TypeItem returnType,
Collection<TypeItem> computedReturnTypes)
{
return function.isExport();
}
private boolean isUserDataTypes(List<String> computedReturnTypeNames, Set<String> checkTypes)
{
if (computedReturnTypeNames.isEmpty())
{
return false;
}
for (String typeName : computedReturnTypeNames)
{
if (checkTypes.contains(typeName))
{
return true;
}
}
return false;
}
private void addWarningDeclaredNonReturningProperty(ReturnStatement statment, boolean useRussianScript,
Property property, DocumentationCommentResultAcceptor resultAceptor)
{
final String message = MessageFormat.format(
Messages.FunctionCtorReturnSectionCheck_Declared_property__N__with_type__T__not_returning,
useRussianScript ? property.getNameRu() : property.getName(), String.join(", ", //$NON-NLS-1$
property.getTypes()
.stream()
.map(useRussianScript ? McoreUtil::getTypeNameRu : McoreUtil::getTypeName)
.collect(Collectors.toList())));
resultAceptor.addIssue(message, statment, Literals.RETURN_STATEMENT__EXPRESSION);
}
private void addWarningDeclaredNonReturningPropertyType(ReturnStatement statment, boolean useRussianScript,
Property property, List<TypeItem> missingTypes, DocumentationCommentResultAcceptor resultAceptor)
{
final String message = MessageFormat.format(
Messages.FunctionCtorReturnSectionCheck_Declared_property__N__with_type__T__missing_returning_types__M,
useRussianScript ? property.getNameRu() : property.getName(), String.join(", ", //$NON-NLS-1$
property.getTypes()
.stream()
.map(useRussianScript ? McoreUtil::getTypeNameRu : McoreUtil::getTypeName)
.collect(Collectors.toList())),
String.join(", ", //$NON-NLS-1$
missingTypes.stream()
.map(useRussianScript ? McoreUtil::getTypeNameRu : McoreUtil::getTypeName)
.collect(Collectors.toList())));
resultAceptor.addIssue(message, statment, Literals.RETURN_STATEMENT__EXPRESSION);
}
private boolean isWarningReturnNonDeclaredProperty(Function function, ReturnStatement statment,
Collection<Property> computedReturnProperties)
{
return function.isExport();
}
private void addWarningNonDeclaredReturningProperty(ReturnStatement statment, boolean useRussianScript,
Collection<String> properties, DocumentationCommentResultAcceptor resultAceptor)
{
final String message = MessageFormat.format(
Messages.FunctionCtorReturnSectionCheck_Return_non_declared_propertes__N, String.join(", ", properties)); //$NON-NLS-1$
resultAceptor.addIssue(message, statment, Literals.RETURN_STATEMENT__EXPRESSION);
}
private boolean isRussianScriptVariantProject(IProject project)
{
IV8Project v8Project = v8ProjectManager.getProject(project);
return (v8Project != null) && (v8Project.getScriptVariant() == ScriptVariant.RUSSIAN);
}
}

View File

@ -0,0 +1,91 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.model.BslPackage;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.mcore.McorePackage;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.google.inject.Inject;
/**
* Checks function has return value types either computed from code or declared in documentation comment.
*
* @author Dmitriy Marmyshev
*/
public class FunctionReturnTypeCheck
extends AbstractTypeCheck
{
private static final String CHECK_ID = "function-return-value-type"; //$NON-NLS-1$
/**
* Instantiates a new function return type check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
@Inject
public FunctionReturnTypeCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IQualifiedNameConverter qualifiedNameConverter)
{
super(resourceLookup, bslPreferences, qualifiedNameConverter);
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.FunctionReturnTypeCheck_title)
.description(Messages.FunctionReturnTypeCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.extension(new ModuleTopObjectNameFilterExtension())
.extension(new StrictTypeAnnotationCheckExtension())
.module()
.checkedObjectType(BslPackage.Literals.FUNCTION);
}
@Override
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
IProgressMonitor monitor)
{
if (monitor.isCanceled() || !(object instanceof EObject))
{
return;
}
if (isEmptyTypes((EObject)object))
{
resultAceptor.addIssue(Messages.FunctionReturnTypeCheck_Function_has_no_return_value_type,
McorePackage.Literals.NAMED_ELEMENT__NAME);
}
}
}

View File

@ -0,0 +1,305 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.DYNAMIC_FEATURE_ACCESS;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.STATIC_FEATURE_ACCESS;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.model.BslPackage;
import com._1c.g5.v8.dt.bsl.model.Expression;
import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
import com._1c.g5.v8.dt.bsl.model.FeatureEntry;
import com._1c.g5.v8.dt.bsl.model.FormalParam;
import com._1c.g5.v8.dt.bsl.model.Invocation;
import com._1c.g5.v8.dt.bsl.model.Method;
import com._1c.g5.v8.dt.bsl.model.UndefinedLiteral;
import com._1c.g5.v8.dt.bsl.model.util.BslUtil;
import com._1c.g5.v8.dt.bsl.typesystem.ExportMethodTypeProvider;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.mcore.Environmental;
import com._1c.g5.v8.dt.mcore.ParamSet;
import com._1c.g5.v8.dt.mcore.Parameter;
import com._1c.g5.v8.dt.mcore.TypeItem;
import com._1c.g5.v8.dt.mcore.util.Environments;
import com._1c.g5.v8.dt.mcore.util.McoreUtil;
import com._1c.g5.v8.dt.platform.IEObjectTypeNames;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.google.inject.Inject;
/**
* Checks invokable method parameter types intersects with types of invocation expression.
*
* @author Dmitriy Marmyshev
*/
public class InvocationParamIntersectionCheck
extends AbstractTypeCheck
{
private static final String CHECK_ID = "invocation-parameter-type-intersect"; //$NON-NLS-1$
private final ExportMethodTypeProvider exportMethodTypeProvider;
/**
* Instantiates a new invocation param intersection check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
@Inject
public InvocationParamIntersectionCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IQualifiedNameConverter qualifiedNameConverter)
{
super(resourceLookup, bslPreferences, qualifiedNameConverter);
IResourceServiceProvider rsp =
IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(URI.createURI("*.bsl")); //$NON-NLS-1$
this.exportMethodTypeProvider = rsp.get(ExportMethodTypeProvider.class);
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.InvocationParamIntersectionCheck_title)
.description(Messages.InvocationParamIntersectionCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.extension(new ModuleTopObjectNameFilterExtension())
.extension(new StrictTypeAnnotationCheckExtension())
.module()
.checkedObjectType(STATIC_FEATURE_ACCESS, DYNAMIC_FEATURE_ACCESS);
}
@Override
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
IProgressMonitor monitor)
{
if (monitor.isCanceled() || !(object instanceof EObject))
{
return;
}
FeatureAccess fa = (FeatureAccess)object;
Invocation inv = BslUtil.getInvocation(fa);
if (inv == null || inv.getParams().isEmpty())
{
return;
}
EObject source = getSourceMethod(fa);
if (source instanceof Method)
{
checkParamTypesIntersect(inv, (Method)source, resultAceptor, monitor);
}
else if (source instanceof com._1c.g5.v8.dt.mcore.Method)
{
checkParamTypesIntersect(inv, (com._1c.g5.v8.dt.mcore.Method)source, resultAceptor, monitor);
}
}
private void checkParamTypesIntersect(Invocation inv, com._1c.g5.v8.dt.mcore.Method method,
ResultAcceptor resultAceptor, IProgressMonitor monitor)
{
if (method.getParamSet().isEmpty())
{
return;
}
List<ParamSet> paramSets = actualParamSet(method, inv.getParams().size());
if (paramSets.isEmpty())
{
return;
}
Environments actualEnvs = getActualEnvironments(inv);
for (int i = 0; i < inv.getParams().size(); i++)
{
if (monitor.isCanceled())
{
return;
}
Expression param = inv.getParams().get(i);
List<TypeItem> sorceTypes = computeTypes(param, actualEnvs);
boolean isUndefined = param == null || param instanceof UndefinedLiteral || isUndefinedType(sorceTypes);
List<TypeItem> targetTypes = Collections.emptyList();
boolean isIntersect = false;
for (Iterator<ParamSet> iterator = paramSets.iterator(); iterator.hasNext();)
{
ParamSet paramSet = iterator.next();
List<Parameter> targetParams = paramSet.getParams();
if (targetParams.size() <= i)
{
iterator.remove();
continue;
}
boolean isDefaultValue = targetParams.get(i).isDefaultValue();
if (isDefaultValue && isUndefined)
{
isIntersect = true;
break;
}
targetTypes = exportMethodTypeProvider.getMethodParamType(method, paramSet, i);
if (targetTypes.isEmpty())
{
continue;
}
isIntersect = intersectTypeItem(targetTypes, sorceTypes, inv);
if (isIntersect)
{
break;
}
}
if (!isIntersect && !targetTypes.isEmpty())
{
markInvalidSourceTypeNoIntercection(param, i, resultAceptor);
}
}
}
private boolean isUndefinedType(List<TypeItem> types)
{
if (types.size() == 1)
{
return IEObjectTypeNames.UNDEFINED.equals(McoreUtil.getTypeName(types.get(0)));
}
return false;
}
private void checkParamTypesIntersect(Invocation inv, Method method, ResultAcceptor resultAceptor,
IProgressMonitor monitor)
{
Environments actualEnvs = getActualEnvironments(inv);
List<FormalParam> targetParams = method.getFormalParams();
for (int i = 0; i < inv.getParams().size(); i++)
{
if (monitor.isCanceled() || targetParams.size() <= i)
{
return;
}
List<TypeItem> targetTypes = computeTypes(targetParams.get(i), actualEnvs);
if (targetTypes.isEmpty())
{
return;
}
Expression param = inv.getParams().get(i);
List<TypeItem> sorceTypes = computeTypes(param, actualEnvs);
if (!intersectTypeItem(targetTypes, sorceTypes, inv))
{
markInvalidSourceTypeNoIntercection(param, i, resultAceptor);
}
}
}
private void markInvalidSourceTypeNoIntercection(Expression param, int index, ResultAcceptor resultAceptor)
{
String message = MessageFormat.format(
Messages.StrictModuleInvocationCheck_Type_of_N_parameter_not_intersect_with_invocation_type, index + 1);
resultAceptor.addIssue(message, param, BslPackage.Literals.EXPRESSION__TYPES);
}
private EObject getSourceMethod(FeatureAccess object)
{
Environments actualEnvs = getActualEnvironments(object);
if (actualEnvs.isEmpty())
{
return null;
}
List<FeatureEntry> objects = dynamicFeatureAccessComputer.resolveObject(object, actualEnvs);
for (FeatureEntry entry : objects)
{
EObject source = entry.getFeature();
if (source instanceof Method || (source instanceof com._1c.g5.v8.dt.mcore.Method))
{
return source;
}
}
return null;
}
private Environments getActualEnvironments(EObject object)
{
Environmental envs = EcoreUtil2.getContainerOfType(object, Environmental.class);
if (envs == null)
{
return Environments.EMPTY;
}
return bslPreferences.getLoadEnvs(object).intersect(envs.environments());
}
private List<ParamSet> actualParamSet(com._1c.g5.v8.dt.mcore.Method method, int numParam)
{
List<ParamSet> result = new ArrayList<>();
List<ParamSet> paramSets = method.getParamSet();
for (ParamSet paramSet : paramSets)
{
if (numParam >= paramSet.getMinParams()
|| numParam <= paramSet.getMaxParams() && paramSet.getMaxParams() != -1)
{
result.add(paramSet);
}
}
if (result.isEmpty() && numParam > 0 && !paramSets.isEmpty())
{
result.addAll(paramSets);
}
return result;
}
}

View File

@ -0,0 +1,71 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import org.eclipse.osgi.util.NLS;
/**
* @author Dmitriy Marmyshev
*
*/
final class Messages
extends NLS
{
private static final String BUNDLE_NAME = "com.e1c.v8codestyle.bsl.strict.check.messages"; //$NON-NLS-1$
public static String DocCommentFieldTypeCheck_description;
public static String DocCommentFieldTypeCheck_Field__N__has_no_type_definition;
public static String DocCommentFieldTypeCheck_title;
public static String DynamicFeatureAccessMethodNotFoundCheck_description;
public static String DynamicFeatureAccessMethodNotFoundCheck_title;
public static String DynamicFeatureAccessTypeCheck_description;
public static String DynamicFeatureAccessTypeCheck_title;
public static String DynamicFeatureAccessTypeCheck_Feature_access_M_has_no_return_type;
public static String DynamicFeatureAccessTypeCheck_Method_M_not_found_in_accessed_object;
public static String FunctionCtorReturnSectionCheck_description;
public static String FunctionCtorReturnSectionCheck_title;
public static String FunctionCtorReturnSectionCheck_User_extandable_Data_type_list_comma_separated;
public static String FunctionCtorReturnSectionCheck_Declared_property__N__with_type__T__missing_returning_types__M;
public static String FunctionCtorReturnSectionCheck_Declared_property__N__with_type__T__not_returning;
public static String FunctionCtorReturnSectionCheck_Return_non_declared_propertes__N;
public static String FunctionCtorReturnSectionCheck_Return_non_declared_type__T;
public static String FunctionReturnTypeCheck_description;
public static String FunctionReturnTypeCheck_title;
public static String FunctionReturnTypeCheck_Function_has_no_return_value_type;
public static String InvocationParamIntersectionCheck_description;
public static String InvocationParamIntersectionCheck_title;
public static String MethodParamTypeCheck_description;
public static String MethodParamTypeCheck_title;
public static String MethodParamTypeCheck_Method_param_N_has_no_value_type;
public static String SimpleStatementTypeCheck_Allow_local_Variable_reset_to_Undefined_type;
public static String SimpleStatementTypeCheck_description;
public static String SimpleStatementTypeCheck_title;
public static String SimpleStatementTypeCheck_Value_type_N_changed_to_M;
public static String StrictModuleInvocationCheck_Type_of_N_parameter_not_intersect_with_invocation_type;
public static String StrictTypeAnnotationCheckExtension_Check__strict_types_annotation_in_module_desctioption;
public static String StructureCtorValueTypeCheck_description;
public static String StructureCtorValueTypeCheck_Structure_key__N__K__has_no_default_value_initializer;
public static String StructureCtorValueTypeCheck_Structure_key__N__K__value_initialized_with_empty_types;
public static String StructureCtorValueTypeCheck_title;
public static String VariableTypeCheck_description;
public static String VariableTypeCheck_title;
public static String VariableTypeCheck_Variable_M_has_no_value_type;
static
{
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
private Messages()
{
}
}

View File

@ -0,0 +1,99 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.FORMAL_PARAM;
import static com._1c.g5.v8.dt.mcore.McorePackage.Literals.NAMED_ELEMENT__NAME;
import java.text.MessageFormat;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.model.FormalParam;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.google.inject.Inject;
/**
* Checks method formal parameter has type either computed or declared in documentation comment.
*
* @author Dmitriy Marmyshev
*/
public class MethodParamTypeCheck
extends AbstractTypeCheck
{
private static final String CHECK_ID = "method-param-value-type"; //$NON-NLS-1$
/**
* Instantiates a new method formal parameter type check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
@Inject
public MethodParamTypeCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IQualifiedNameConverter qualifiedNameConverter)
{
super(resourceLookup, bslPreferences, qualifiedNameConverter);
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.MethodParamTypeCheck_title)
.description(Messages.MethodParamTypeCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.extension(new ModuleTopObjectNameFilterExtension())
.extension(new StrictTypeAnnotationCheckExtension())
.module()
.checkedObjectType(FORMAL_PARAM);
}
@Override
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
IProgressMonitor monitor)
{
if (monitor.isCanceled() || !(object instanceof EObject))
{
return;
}
FormalParam param = (FormalParam)object;
if (isEmptyTypes(param))
{
String message =
MessageFormat.format(Messages.MethodParamTypeCheck_Method_param_N_has_no_value_type, param.getName());
resultAceptor.addIssue(message, NAMED_ELEMENT__NAME);
}
}
}

View File

@ -0,0 +1,214 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.SIMPLE_STATEMENT;
import java.text.MessageFormat;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.model.BslPackage;
import com._1c.g5.v8.dt.bsl.model.Expression;
import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
import com._1c.g5.v8.dt.bsl.model.FeatureEntry;
import com._1c.g5.v8.dt.bsl.model.ImplicitVariable;
import com._1c.g5.v8.dt.bsl.model.SimpleStatement;
import com._1c.g5.v8.dt.bsl.model.StaticFeatureAccess;
import com._1c.g5.v8.dt.bsl.util.BslUtil;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
import com._1c.g5.v8.dt.mcore.Environmental;
import com._1c.g5.v8.dt.mcore.TypeItem;
import com._1c.g5.v8.dt.mcore.util.Environments;
import com._1c.g5.v8.dt.mcore.util.McoreUtil;
import com._1c.g5.v8.dt.platform.IEObjectTypeNames;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
/**
* Checks all simple statements that changes type from one to another, that should not do.
* Implicit variable allowed to reset to {@code Undefined} type by parameter.
*
* @author Dmitriy Marmyshev
*/
public class SimpleStatementTypeCheck
extends AbstractTypeCheck
{
private static final String CHECK_ID = "statement-type-change"; //$NON-NLS-1$
private static final String PARAM_ALLOW_IMPLICIT_VAR_RESET_TO_UNDEFINED = "allowImplicitVariableResetToUndefined"; //$NON-NLS-1$
private static final String DEFAULT_ALLOW_IMPLICIT_VAR_RESET_TO_UNDEFINED = Boolean.TRUE.toString();
private final IV8ProjectManager v8ProjectManager;
/**
* Instantiates a new simple statement change type check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param v8ProjectManager the v8 project manager service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
@Inject
public SimpleStatementTypeCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IV8ProjectManager v8ProjectManager, IQualifiedNameConverter qualifiedNameConverter)
{
super(resourceLookup, bslPreferences, qualifiedNameConverter);
this.v8ProjectManager = v8ProjectManager;
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.SimpleStatementTypeCheck_title)
.description(Messages.SimpleStatementTypeCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.extension(new ModuleTopObjectNameFilterExtension())
.extension(new StrictTypeAnnotationCheckExtension())
.module()
.checkedObjectType(SIMPLE_STATEMENT)
.parameter(PARAM_ALLOW_IMPLICIT_VAR_RESET_TO_UNDEFINED, Boolean.class,
DEFAULT_ALLOW_IMPLICIT_VAR_RESET_TO_UNDEFINED,
Messages.SimpleStatementTypeCheck_Allow_local_Variable_reset_to_Undefined_type);
}
@Override
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
IProgressMonitor monitor)
{
if (monitor.isCanceled() || !(object instanceof EObject))
{
return;
}
SimpleStatement statment = (SimpleStatement)object;
Expression left = statment.getLeft();
if (left instanceof StaticFeatureAccess && ((StaticFeatureAccess)left).getImplicitVariable() != null)
{
// check new variable type exist in VariableTypeCheck
return;
}
if (left == null || statment.getRight() == null)
{
return;
}
Environmental envs = EcoreUtil2.getContainerOfType(statment, Environmental.class);
Environments actualEnvs = bslPreferences.getLoadEnvs(statment).intersect(envs.environments());
if (actualEnvs.isEmpty())
{
return;
}
List<TypeItem> types = computeTypes(left, actualEnvs);
if (monitor.isCanceled() || types.isEmpty())
{
// empty previous types will be warned in upper code of module
return;
}
boolean allowImplicitVarResetToUndefined = parameters.getBoolean(PARAM_ALLOW_IMPLICIT_VAR_RESET_TO_UNDEFINED);
boolean canResetToUndefined = allowImplicitVarResetToUndefined && isImplicitVariableSource(left, actualEnvs);
List<TypeItem> newTypes = computeTypes(statment.getRight(), actualEnvs);
if (!monitor.isCanceled() && !hasTypeIntersection(types, newTypes, statment, canResetToUndefined))
{
boolean isRussian = com._1c.g5.v8.dt.bsl.util.BslUtil.isRussian(statment, this.v8ProjectManager);
String message = MessageFormat.format(Messages.SimpleStatementTypeCheck_Value_type_N_changed_to_M,
getTypesPresentation(types, isRussian), getTypesPresentation(newTypes, isRussian));
resultAceptor.addIssue(message, BslPackage.Literals.SIMPLE_STATEMENT__LEFT);
}
}
private boolean isImplicitVariableSource(Expression expression, Environments actualEnvs)
{
if (expression instanceof StaticFeatureAccess)
{
List<FeatureEntry> features =
dynamicFeatureAccessComputer.resolveObject((FeatureAccess)expression, actualEnvs);
for (FeatureEntry feature : features)
{
if (feature.getFeature() instanceof ImplicitVariable)
{
return true;
}
}
return false;
}
return true;
}
private boolean hasTypeIntersection(List<TypeItem> source, List<TypeItem> target, EObject context,
boolean canResetToUndefined)
{
if (target.isEmpty())
{
return false;
}
Set<String> targetNames = Sets.newLinkedHashSet(BslUtil.transform(target, BslUtil.TYPE_NAME));
if (canResetToUndefined && targetNames.contains(IEObjectTypeNames.UNDEFINED) && targetNames.size() == 1)
{
return true;
}
return intersectTypeItem(source, target, context);
}
private String getTypesPresentation(List<TypeItem> types, boolean isRussian)
{
StringBuilder sb = new StringBuilder();
for (TypeItem type : types)
{
if (sb.length() > 0)
{
sb.append(", "); //$NON-NLS-1$
}
sb.append(isRussian ? McoreUtil.getTypeNameRu(type) : McoreUtil.getTypeName(type));
}
return sb.toString();
}
}

View File

@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
/**
*
*/
package com.e1c.v8codestyle.bsl.strict.check;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import com._1c.g5.v8.dt.bsl.model.Module;
import com.e1c.g5.v8.dt.check.CheckParameterDefinition;
import com.e1c.g5.v8.dt.check.ICheckDefinition;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.IBasicCheckExtension;
import com.e1c.v8codestyle.bsl.strict.StrictTypeUtil;
/**
* The check extension adds parameter allows to skip search for annotation in module header.
* The extension also pre-check that that annotation exist.
*
* @author Dmitriy Marmyshev
*/
public class StrictTypeAnnotationCheckExtension
implements IBasicCheckExtension
{
protected static final String PARAM_CHECK_ANNOTATION_IN_MODULE_DESCRIPTION = "checkAnnotationInModuleDescription"; //$NON-NLS-1$
protected static final String DEFAULT_CHECK_ANNOTATION_IN_MODULE_DESCRIPTION = Boolean.TRUE.toString();
@Override
public void configureContextCollector(ICheckDefinition definition)
{
CheckParameterDefinition paramDef = new CheckParameterDefinition(PARAM_CHECK_ANNOTATION_IN_MODULE_DESCRIPTION,
Boolean.class, DEFAULT_CHECK_ANNOTATION_IN_MODULE_DESCRIPTION,
Messages.StrictTypeAnnotationCheckExtension_Check__strict_types_annotation_in_module_desctioption);
definition.addParameterDefinition(paramDef);
}
@Override
public boolean preCheck(Object object, ICheckParameters parameters, IProgressMonitor monitor)
{
if (monitor.isCanceled() || !(object instanceof EObject))
{
return false;
}
boolean checkAnnotation = parameters.getBoolean(PARAM_CHECK_ANNOTATION_IN_MODULE_DESCRIPTION);
if (!checkAnnotation)
{
return true;
}
Module module = EcoreUtil2.getContainerOfType((EObject)object, Module.class);
if (monitor.isCanceled() || module == null)
{
return false;
}
return StrictTypeUtil.hasStrictTypeAnnotation(module);
}
}

View File

@ -0,0 +1,131 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.OPERATOR_STYLE_CREATOR;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.STRING_LITERAL__LINES;
import java.text.MessageFormat;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.model.EmptyExpression;
import com._1c.g5.v8.dt.bsl.model.Expression;
import com._1c.g5.v8.dt.bsl.model.OperatorStyleCreator;
import com._1c.g5.v8.dt.bsl.model.StringLiteral;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.mcore.util.McoreUtil;
import com._1c.g5.v8.dt.platform.IEObjectTypeNames;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.google.inject.Inject;
/**
* Checks Structure constructor string literal that each key has typed value.
*
* @author Dmitriy Marmyshev
*/
public class StructureCtorValueTypeCheck
extends AbstractTypeCheck
{
private static final String CHECK_ID = "structure-consructor-value-type"; //$NON-NLS-1$
/**
* Instantiates a new structure constructor value type check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
@Inject
public StructureCtorValueTypeCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IQualifiedNameConverter qualifiedNameConverter)
{
super(resourceLookup, bslPreferences, qualifiedNameConverter);
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.StructureCtorValueTypeCheck_title)
.description(Messages.StructureCtorValueTypeCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.extension(new ModuleTopObjectNameFilterExtension())
.extension(new StrictTypeAnnotationCheckExtension())
.module()
.checkedObjectType(OPERATOR_STYLE_CREATOR);
}
@Override
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
IProgressMonitor monitor)
{
OperatorStyleCreator osc = (OperatorStyleCreator)object;
if (monitor.isCanceled() || osc.getParams().isEmpty()
|| !IEObjectTypeNames.STRUCTURE.equals(McoreUtil.getTypeName(osc.getType()))
|| !(osc.getParams().get(0) instanceof StringLiteral))
{
return;
}
StringLiteral literal = (StringLiteral)osc.getParams().get(0);
String content = String.join("", literal.lines(true)); //$NON-NLS-1$
String[] keys = content.replace(" ", "").split(","); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
int totalParams = osc.getParams().size() - 1;
for (int i = 0; i < keys.length; i++)
{
if (monitor.isCanceled())
{
return;
}
String key = keys[i];
if (totalParams > i && osc.getParams().get(i + 1) != null)
{
Expression param = osc.getParams().get(i + 1);
if (isEmptyTypes(param))
{
param = param instanceof EmptyExpression ? literal : param;
String message = MessageFormat.format(
Messages.StructureCtorValueTypeCheck_Structure_key__N__K__value_initialized_with_empty_types,
i + 1, key);
resultAceptor.addIssue(message, param);
}
}
else
{
String message = MessageFormat.format(
Messages.StructureCtorValueTypeCheck_Structure_key__N__K__has_no_default_value_initializer, i + 1,
key);
resultAceptor.addIssue(message, literal, STRING_LITERAL__LINES);
}
}
}
}

View File

@ -0,0 +1,131 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.DECLARE_STATEMENT;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.EXPLICIT_VARIABLE;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.IMPLICIT_VARIABLE;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.SIMPLE_STATEMENT;
import static com._1c.g5.v8.dt.mcore.McorePackage.Literals.NAMED_ELEMENT__NAME;
import java.text.MessageFormat;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.bsl.model.DeclareStatement;
import com._1c.g5.v8.dt.bsl.model.ExplicitVariable;
import com._1c.g5.v8.dt.bsl.model.ImplicitVariable;
import com._1c.g5.v8.dt.bsl.model.SimpleStatement;
import com._1c.g5.v8.dt.bsl.model.StaticFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.Variable;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.components.ModuleTopObjectNameFilterExtension;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.google.inject.Inject;
/**
* Checks variable of the module has value type.
*
* @author Dmitriy Marmyshev
*/
public class VariableTypeCheck
extends AbstractTypeCheck
{
private static final String CHECK_ID = "variable-value-type"; //$NON-NLS-1$
/**
* Instantiates a new variable type check.
*
* @param resourceLookup the resource lookup service, cannot be {@code null}.
* @param bslPreferences the BSL preferences service, cannot be {@code null}.
* @param qualifiedNameConverter the qualified name converter service, cannot be {@code null}.
*/
@Inject
public VariableTypeCheck(IResourceLookup resourceLookup, IBslPreferences bslPreferences,
IQualifiedNameConverter qualifiedNameConverter)
{
super(resourceLookup, bslPreferences, qualifiedNameConverter);
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.VariableTypeCheck_title)
.description(Messages.VariableTypeCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.CODE_STYLE)
.extension(new ModuleTopObjectNameFilterExtension())
.extension(new StrictTypeAnnotationCheckExtension())
.module()
.checkedObjectType(IMPLICIT_VARIABLE, EXPLICIT_VARIABLE, SIMPLE_STATEMENT, DECLARE_STATEMENT);
}
@Override
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
IProgressMonitor monitor)
{
if (monitor.isCanceled() || !(object instanceof EObject))
{
return;
}
if (object instanceof ImplicitVariable || object instanceof ExplicitVariable)
{
checkVariable((Variable)object, (EObject)object, resultAceptor, monitor);
}
else if (object instanceof SimpleStatement && ((SimpleStatement)object).getLeft() instanceof StaticFeatureAccess
&& ((StaticFeatureAccess)((SimpleStatement)object).getLeft()).getImplicitVariable() != null)
{
EObject checkType = ((SimpleStatement)object).getRight();
Variable variable = ((StaticFeatureAccess)((SimpleStatement)object).getLeft()).getImplicitVariable();
checkVariable(variable, checkType, resultAceptor, monitor);
}
else if (object instanceof DeclareStatement)
{
DeclareStatement declare = (DeclareStatement)object;
for (Variable variable : declare.getVariables())
{
checkVariable(variable, variable, resultAceptor, monitor);
}
}
}
private void checkVariable(Variable variable, EObject checkObject, ResultAcceptor resultAceptor,
IProgressMonitor monitor)
{
if (!monitor.isCanceled() && checkObject != null && variable != null && isEmptyTypes(checkObject))
{
String message =
MessageFormat.format(Messages.VariableTypeCheck_Variable_M_has_no_value_type, variable.getName());
resultAceptor.addIssue(message, variable, NAMED_ELEMENT__NAME);
}
}
}

View File

@ -0,0 +1,87 @@
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# 1C-Soft LLC - initial API and implementation
###############################################################################
DocCommentFieldTypeCheck_Field__N__has_no_type_definition = Field "{0}" has no type definition
DocCommentFieldTypeCheck_description = Check of module strict types system that documentation comment field has section with types
DocCommentFieldTypeCheck_title = Documentation comment Field has no type definition
DynamicFeatureAccessMethodNotFoundCheck_description = Check of module strict types system that dynamically accessed method exist in the object
DynamicFeatureAccessMethodNotFoundCheck_title = Method not found in accessed object
DynamicFeatureAccessTypeCheck_Feature_access_M_has_no_return_type = Feature access "{0}" has no return type
DynamicFeatureAccessTypeCheck_Method_M_not_found_in_accessed_object = Method "{0}" not found in accessed object
DynamicFeatureAccessTypeCheck_description = Check of module strict types system that dynamically accessed object property has return type
DynamicFeatureAccessTypeCheck_title = Object property has return value type
FunctionCtorReturnSectionCheck_Declared_property__N__with_type__T__missing_returning_types__M = Declared property "{0}" with type: "{1}" missing returning types "{2}"
FunctionCtorReturnSectionCheck_Declared_property__N__with_type__T__not_returning = Declared property "{0}" with type: "{1}" not returning
FunctionCtorReturnSectionCheck_Return_non_declared_propertes__N = Return non declared properties: "{0}"
FunctionCtorReturnSectionCheck_Return_non_declared_type__T = Return non-declared type: {0}
FunctionCtorReturnSectionCheck_User_extandable_Data_type_list_comma_separated = User-extendable Data type list, comma separated
FunctionCtorReturnSectionCheck_description = Check of module strict types system that return statements of function equals documentation comment return section types
FunctionCtorReturnSectionCheck_title = Data constructor function return section
FunctionReturnTypeCheck_Function_has_no_return_value_type = Function has no return value type
FunctionReturnTypeCheck_description = Check of module strict types system that every function has return value type
FunctionReturnTypeCheck_title = Function returns typed value
InvocationParamIntersectionCheck_description = Check of module strict types system that invocation expression has intersection with invocation parameter type
InvocationParamIntersectionCheck_title = Invocation parameter types intersects
MethodParamTypeCheck_Method_param_N_has_no_value_type = Method parameter "{0}" has no value type
MethodParamTypeCheck_description = Check of module strict types system that every method parameter has value type
MethodParamTypeCheck_title = Method parameter has value type
SimpleStatementTypeCheck_Allow_local_Variable_reset_to_Undefined_type = Allow local Variable reset to Undefined type
SimpleStatementTypeCheck_Value_type_N_changed_to_M = Value type "{0}" changed to "{1}"
SimpleStatementTypeCheck_description = Check of module strict types system that statement does not change type
SimpleStatementTypeCheck_title = Statement type change
StrictModuleInvocationCheck_Type_of_N_parameter_not_intersect_with_invocation_type = Type of "{0}" parameter not intersect with invocation type
StrictTypeAnnotationCheckExtension_Check__strict_types_annotation_in_module_desctioption = Check @strict-types annotation in module description
StructureCtorValueTypeCheck_Structure_key__N__K__has_no_default_value_initializer = Structure key {0} "{1}" has no default value initializer
StructureCtorValueTypeCheck_Structure_key__N__K__value_initialized_with_empty_types = Structure key {0} "{1}" value initialized with empty types
StructureCtorValueTypeCheck_description = Checks Structure constructor string literal that each key has typed value.
StructureCtorValueTypeCheck_title = Structure constructor value types
VariableTypeCheck_Variable_M_has_no_value_type = Variable "{0}" has no value type
VariableTypeCheck_description = Check of module strict types system that every variable has value type
VariableTypeCheck_title = Variable has value type

View File

@ -0,0 +1,87 @@
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# 1C-Soft LLC - initial API and implementation
###############################################################################
DocCommentFieldTypeCheck_Field__N__has_no_type_definition = Поле "{0}" не имеет описания типа
DocCommentFieldTypeCheck_description = Система строгой типизации кода проверяет что поле документирующего комментария имеет описание типа
DocCommentFieldTypeCheck_title = Поле документирующего комментария имеет описание типа
DynamicFeatureAccessMethodNotFoundCheck_description = Система строгой типизации кода проверяет что динамически вызываемый метод существует в объекте
DynamicFeatureAccessMethodNotFoundCheck_title = Метод в объекте не найден
DynamicFeatureAccessTypeCheck_Feature_access_M_has_no_return_type = Свойство "{0}" не имеет типа возвращаемого значения
DynamicFeatureAccessTypeCheck_Method_M_not_found_in_accessed_object = Метод "{0}" не найден в исходном объекте
DynamicFeatureAccessTypeCheck_description = Система строгой типизации кода проверяет что динамическое свойство объекта имеет тип возвращаемого значения
DynamicFeatureAccessTypeCheck_title = Свойство объекта имеет тип возвращаемого значения
FunctionCtorReturnSectionCheck_Declared_property__N__with_type__T__missing_returning_types__M = Декларируемое свойство "{0}" с типом: "{1}" не содержит возвращемые типы "{2}"
FunctionCtorReturnSectionCheck_Declared_property__N__with_type__T__not_returning = Декларируемое свойство "{0}" с типом: "{1}" не возвращается
FunctionCtorReturnSectionCheck_Return_non_declared_propertes__N = Возвращается не декларируемое свойство: "{0}"
FunctionCtorReturnSectionCheck_Return_non_declared_type__T = Возвращается не декларированный тип: {0}
FunctionCtorReturnSectionCheck_User_extandable_Data_type_list_comma_separated = Список типов данных расширяемых пользователем, через запятую
FunctionCtorReturnSectionCheck_description = Система строгой типизации кода проверяет что возвращаемые значения функции эквивалентны секции возвращаемого значения документирующего комментария
FunctionCtorReturnSectionCheck_title = Секция возвращаемого значения функции-конструктора данных
FunctionReturnTypeCheck_Function_has_no_return_value_type = Функция не имеет типа возвращаемого значения
FunctionReturnTypeCheck_description = Система строгой типизации кода проверяет что каждая функция возвращает типизированное значение
FunctionReturnTypeCheck_title = Функция возвращает типизированное значение
InvocationParamIntersectionCheck_description = Система строгой типизации кода проверяет что тип вызываемого выражения пересекается с типом параметра вызываемого метода
InvocationParamIntersectionCheck_title = Вызываеемый тип пересекается с типом параметра
MethodParamTypeCheck_Method_param_N_has_no_value_type = Параметр метода "{0}" не имеет типа значения
MethodParamTypeCheck_description = Система строгой типизации кода проверяет что каждый параметр метода имеет тип значения
MethodParamTypeCheck_title = Параметр метода имеет тип
SimpleStatementTypeCheck_Allow_local_Variable_reset_to_Undefined_type = Разрешить сбрасывать тип локальных переменных в Неопределено
SimpleStatementTypeCheck_Value_type_N_changed_to_M = Тип значения "{0}" заменен на "{1}"
SimpleStatementTypeCheck_description = Система строгой типизации кода проверяет что утверждение (строка присвоения значения) меняет тип
SimpleStatementTypeCheck_title = Утверждение меняет тип
StrictModuleInvocationCheck_Type_of_N_parameter_not_intersect_with_invocation_type = Тип "{0}" параметра не пересекается с вызываемым типом
StrictTypeAnnotationCheckExtension_Check__strict_types_annotation_in_module_desctioption = Проверять аннотацию @strict-types в заголовке модуля
StructureCtorValueTypeCheck_Structure_key__N__K__has_no_default_value_initializer = Ключ {0} "{1}" Структуры не имеет инициализатора значения по умолчанию
StructureCtorValueTypeCheck_Structure_key__N__K__value_initialized_with_empty_types = Ключ {0} "{1}" Структуры инициализируется с пустым типом
StructureCtorValueTypeCheck_description = Проверяет строковый литерал в конструкторе структуры что каждый ключ имеет типзированное значение
StructureCtorValueTypeCheck_title = Типизация значений в конструкторе структуры
VariableTypeCheck_Variable_M_has_no_value_type = Переменная "{0}" не имеет типа
VariableTypeCheck_description = Система строгой типизации кода проверяет что каждая переменная имеет тип значения
VariableTypeCheck_title = Переменная имеет тип значения

View File

@ -14,7 +14,11 @@
package com.e1c.v8codestyle.internal.bsl;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
import com._1c.g5.v8.dt.platform.version.IRuntimeVersionSupport;
import com._1c.g5.wiring.AbstractServiceAwareModule;
@ -34,7 +38,11 @@ class ExternalDependenciesModule
@Override
protected void doConfigure()
{
bind(IResourceLookup.class).toService();
bind(IRuntimeVersionSupport.class).toService();
bind(IV8ProjectManager.class).toService();
bind(IBslPreferences.class).toService();
bind(IQualifiedNameConverter.class).toService();
}
}

View File

@ -10,6 +10,6 @@ Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-Localization: fragment
Import-Package: com._1c.g5.v8.dt.core.platform;version="10.4.0",
com._1c.g5.v8.dt.testing;version="[3.1.0,4.0.0)",
com._1c.g5.v8.dt.validation.marker;version="4.0.0",
com._1c.g5.v8.dt.validation.marker;version="[4.0.0,5.0.0)",
com.e1c.g5.v8.dt.testing.check;version="[1.0.0,2.0.0)",
org.junit;version="[4.13.0,5.0.0)"

View File

@ -15,4 +15,5 @@ output.. = bin/
bin.includes = META-INF/,\
.,\
fragment.properties,\
workspace/
workspace/,\
resources/

View File

@ -0,0 +1,22 @@
// @strict-types
// Returns:
// Structure - Non complaint:
// * Key1 - Number -
// * Key3 - Number -
Function NonComplaint() Export
return new Structure("Key1, Key2", 10, "");
EndFunction
// Returns:
// Structure - Non complaint:
// * Key1 - Number -
// * Key2 - String -
Function Complaint() Export
return new Structure("Key1, Key2", 10, "");
EndFunction

View File

@ -0,0 +1,15 @@
// @strict-types
// Parameters:
// Parameters - Structure:
// * Key1 - has not type for key
Procedure NonComplaint(Parameters) Export
// empty
EndProcedure
// Parameters:
// Parameters - Structure:
// * Key1 - Number - has type for key
Procedure Complaint(Parameters) Export
// empty
EndProcedure

View File

@ -0,0 +1,19 @@
// @strict-types
Procedure NonComplaint(Module) Export
Module.CostomAction();
EndProcedure
Procedure Complaint() Export
ThisObject.CostomAction();
EndProcedure
Procedure CostomAction() Export
EndProcedure

View File

@ -0,0 +1,15 @@
// @strict-types
Function NonComplaint() Export
// empty
EndFunction
Function Complaint()
Return 0;
EndFunction
// Returns:
// String - returning value
Function Complaint() Export
// empty
EndFunction

View File

@ -0,0 +1,17 @@
// @strict-types
Procedure NonComplaint(Strings) Export
Result = StrConcat(Strings, "1");
EndProcedure
// Parameters:
// Strings - Array
Procedure Complaint(Strings) Export
Result = StrConcat(Strings, "1");
EndProcedure

View File

@ -0,0 +1,11 @@
// @strict-types
Procedure NonComplaint(Parameters) Export
// empty
EndProcedure
// Parameters:
// Parameters - String
Procedure Complaint(Parameters) Export
// empty
EndProcedure

View File

@ -0,0 +1,26 @@
// @strict-types
Procedure NonComplaint(Module) Export
Key1 = CustomAction().Key1;
EndProcedure
Procedure Complaint() Export
Key1 = CustomAction2().Key1;
EndProcedure
Function CustomAction() Export
return new Structure("Key1");
EndFunction
Function CustomAction2() Export
return new Structure("Key1", 10);
EndFunction

View File

@ -0,0 +1,13 @@
// @strict-types
// Parameters:
// Parameters - String
Procedure NonComplaint(Parameters) Export
Parameters = 1;
EndProcedure
// Parameters:
// Parameters - String
Procedure Complaint(Parameters) Export
Parameters = "1";
EndProcedure

View File

@ -0,0 +1,15 @@
// @strict-types
Procedure NonComplaint() Export
Params = new Structure("Key1,
|Key2, Key3", , 1);
EndProcedure
Procedure Complaint() Export
Params = new Structure("Key1, Key2", 0, "");
Params.Insert("Key3", "");
EndProcedure

View File

@ -0,0 +1,11 @@
// @strict-types
Procedure NonComplaint() Export
Var TestVar;
// empty
EndProcedure
Procedure Complaint() Export
Var TestVar; // Number
// empty
EndProcedure

View File

@ -0,0 +1,423 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl.strict.check.itests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.EcoreUtil2;
import org.junit.Ignore;
import org.junit.Test;
import com._1c.g5.v8.bm.core.IBmObject;
import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.Function;
import com._1c.g5.v8.dt.bsl.model.Method;
import com._1c.g5.v8.dt.bsl.model.Module;
import com._1c.g5.v8.dt.bsl.model.SimpleStatement;
import com._1c.g5.v8.dt.bsl.model.StaticFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.StringLiteral;
import com._1c.g5.v8.dt.bsl.model.Variable;
import com._1c.g5.v8.dt.metadata.mdclass.CommonModule;
import com._1c.g5.v8.dt.validation.marker.Marker;
import com.e1c.g5.v8.dt.testing.check.SingleProjectReadOnlyCheckTestBase;
import com.e1c.v8codestyle.bsl.strict.check.DocCommentFieldTypeCheck;
import com.e1c.v8codestyle.bsl.strict.check.DynamicFeatureAccessMethodNotFoundCheck;
import com.e1c.v8codestyle.bsl.strict.check.DynamicFeatureAccessTypeCheck;
import com.e1c.v8codestyle.bsl.strict.check.FunctionCtorReturnSectionCheck;
import com.e1c.v8codestyle.bsl.strict.check.FunctionReturnTypeCheck;
import com.e1c.v8codestyle.bsl.strict.check.InvocationParamIntersectionCheck;
import com.e1c.v8codestyle.bsl.strict.check.MethodParamTypeCheck;
import com.e1c.v8codestyle.bsl.strict.check.SimpleStatementTypeCheck;
import com.e1c.v8codestyle.bsl.strict.check.StructureCtorValueTypeCheck;
import com.e1c.v8codestyle.bsl.strict.check.VariableTypeCheck;
/**
* Tests of strict types system in BSL module.
*
* @author Dmitriy Marmyshev
*/
public class CommonModuleStrictTypesTest
extends SingleProjectReadOnlyCheckTestBase
{
private static final String PROJECT_NAME = "CommonModule";
private static final String FQN = "CommonModule.CommonModule";
private static final String FOLDER = "/resources/strict/";
private static final String COMMON_MODULE_FILE_NAME = "/src/CommonModules/CommonModule/Module.bsl";
@Override
protected String getTestConfigurationName()
{
return PROJECT_NAME;
}
/**
* Test of {@link StructureCtorValueTypeCheck} structure constructor value has returning type.
*
* @throws Exception the exception
*/
@Test
public void testStructureCtorValueTypeCheck() throws Exception
{
String checkId = "structure-consructor-value-type";
Module module = updateAndGetModule(checkId);
List<StringLiteral> literals = EcoreUtil2.eAllOfType(module, StringLiteral.class);
assertEquals(5, literals.size());
List<Marker> markers = getMarters(checkId, module);
assertEquals(2, markers.size());
String uriToProblem = EcoreUtil.getURI(literals.get(0)).toString();
Marker marker = markers.get(0);
assertEquals("5", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
marker = markers.get(1);
assertEquals("5", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link VariableTypeCheck} that each variable has value type.
*
* @throws Exception the exception
*/
@Test
public void testVariableTypeCheck() throws Exception
{
String checkId = "variable-value-type";
Module module = updateAndGetModule(checkId);
List<Variable> variables = EcoreUtil2.eAllOfType(module, Variable.class);
assertEquals(2, variables.size());
List<Marker> markers = getMarters(checkId, module);
assertEquals(1, markers.size());
String uriToProblem = EcoreUtil.getURI(variables.get(0)).toString();
Marker marker = markers.get(0);
assertEquals("4", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link DocCommentFieldTypeCheck} that each field in documentation comment has defined type.
*
* @throws Exception the exception
*/
@Test
@Ignore // FIXME check-system fails on issue add
public void testDocCommentFieldTypeCheck() throws Exception
{
String checkId = "doc-comment-field-type";
Module module = updateAndGetModule(checkId);
List<Method> methods = module.allMethods();
assertEquals(2, methods.size());
List<Marker> markers = getMarters(checkId, module);
assertEquals(1, markers.size());
String uriToProblem = EcoreUtil.getURI(methods.get(0)).toString();
Marker marker = markers.get(0);
assertEquals("5", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link FunctionReturnTypeCheck} that function has returning type.
*
* @throws Exception the exception
*/
@Test
public void testFunctionReturnTypeCheck() throws Exception
{
String checkId = "function-return-value-type";
Module module = updateAndGetModule(checkId);
List<Method> methods = module.allMethods();
assertEquals(3, methods.size());
List<Marker> markers = getMarters(checkId, module);
// FIXME check-system duplicates issues
assertEquals(2, markers.size());
String uriToProblem = EcoreUtil.getURI(methods.get(0)).toString();
Marker marker = markers.get(0);
assertEquals("3", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
marker = markers.get(1);
assertEquals("3", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link MethodParamTypeCheck} that each method's parameter has defined or computed type.
*
* @throws Exception the exception
*/
@Test
public void testMethodParamTypeCheckk() throws Exception
{
String checkId = "method-param-value-type";
Module module = updateAndGetModule(checkId);
List<Method> methods = module.allMethods();
assertEquals(2, methods.size());
List<Marker> markers = getMarters(checkId, module);
// FIXME check-system duplicates issues
assertEquals(2, markers.size());
String uriToProblem = EcoreUtil.getURI(methods.get(0).getFormalParams().get(0)).toString();
Marker marker = markers.get(0);
assertEquals("3", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
marker = markers.get(1);
assertEquals("3", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link DynamicFeatureAccessMethodNotFoundCheck} that dynamic method exist in the object.
*
* @throws Exception the exception
*/
@Test
public void testDynamicFeatureAccessMethodNotFoundCheck() throws Exception
{
String checkId = "dynamic-access-method-not-found";
Module module = updateAndGetModule(checkId);
List<DynamicFeatureAccess> dynamicMethods = EcoreUtil2.eAllOfType(module, DynamicFeatureAccess.class);
assertEquals(2, dynamicMethods.size());
List<Marker> markers = getMarters(checkId, module);
// FIXME check-system duplicates issues
assertEquals(2, markers.size());
String uriToProblem = EcoreUtil.getURI(dynamicMethods.get(0)).toString();
Marker marker = markers.get(0);
assertEquals("5", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
marker = markers.get(0);
assertEquals("5", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link DynamicFeatureAccessTypeCheck} that dynamic property exist and has return type.
*
* @throws Exception the exception
*/
@Test
public void testDynamicFeatureAccessTypeCheck() throws Exception
{
String checkId = "property-return-type";
Module module = updateAndGetModule(checkId);
List<DynamicFeatureAccess> dynamicProperties = EcoreUtil2.eAllOfType(module, DynamicFeatureAccess.class);
assertEquals(2, dynamicProperties.size());
List<Marker> markers = getMarters(checkId, module);
// FIXME check-system duplicates issues
assertEquals(2, markers.size());
String uriToProblem = EcoreUtil.getURI(dynamicProperties.get(0)).toString();
Marker marker = markers.get(0);
assertEquals("5", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
marker = markers.get(0);
assertEquals("5", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link SimpleStatementTypeCheck} that the statement change type of existing object type.
*
* @throws Exception the exception
*/
@Test
public void testSimpleStatementTypeCheck() throws Exception
{
String checkId = "statement-type-change";
Module module = updateAndGetModule(checkId);
List<SimpleStatement> statements = EcoreUtil2.eAllOfType(module, SimpleStatement.class);
assertEquals(2, statements.size());
List<Marker> markers = getMarters(checkId, module);
// FIXME check-system duplicates issues
assertEquals(2, markers.size());
String uriToProblem = EcoreUtil.getURI(statements.get(0)).toString();
Marker marker = markers.get(0);
assertEquals("6", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
marker = markers.get(0);
assertEquals("6", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link FunctionCtorReturnSectionCheck} that the statement change type of existing object type.
*
* @throws Exception the exception
*/
@Test
@Ignore // FIXME check-system fails on issue add
public void testFunctionCtorReturnSectionCheck() throws Exception
{
String checkId = "constructor-function-return-section";
Module module = updateAndGetModule(checkId);
List<Function> finctions = EcoreUtil2.eAllOfType(module, Function.class);
assertEquals(2, finctions.size());
List<Marker> markers = getMarters(checkId, module);
assertEquals(1, markers.size());
String uriToProblem = EcoreUtil.getURI(finctions.get(0)).toString();
Marker marker = markers.get(0);
assertEquals("6", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
/**
* Test of {@link InvocationParamIntersectionCheck} that invokable method parameter type intersects
* with caller type.
*
* @throws Exception the exception
*/
@Test
public void testInvocationParamIntersectionCheck() throws Exception
{
String checkId = "invocation-parameter-type-intersect";
Module module = updateAndGetModule(checkId);
List<StaticFeatureAccess> statements = EcoreUtil2.eAllOfType(module, StaticFeatureAccess.class);
assertEquals(6, statements.size());
List<Marker> markers = getMarters(checkId, module);
assertEquals(1, markers.size());
String uriToProblem = EcoreUtil.getURI(statements.get(2)).toString();
Marker marker = markers.get(0);
assertEquals("5", marker.getExtraInfo().get("line"));
assertEquals(uriToProblem, marker.getExtraInfo().get("uriToProblem"));
}
private List<Marker> getMarters(String checkId, Module module)
{
String id = module.eResource().getURI().toPlatformString(true);
List<Marker> markers =
new ArrayList<>(Arrays.asList(markerManager.getMarkers(getProject().getWorkspaceProject(), id)));
markers.removeIf(m -> !checkId.equals(getCheckIdFromMarker(m, getProject())));
return markers;
}
private Module updateAndGetModule(String checkId) throws CoreException, IOException
{
try (InputStream in = getClass().getResourceAsStream(FOLDER + checkId + ".bsl"))
{
IFile file = getProject().getWorkspaceProject().getFile(COMMON_MODULE_FILE_NAME);
file.setContents(in, true, true, new NullProgressMonitor());
}
testingWorkspace.waitForBuildCompletion();
waitForDD(getProject());
IBmObject mdObject = getTopObjectByFqn(FQN, getProject());
assertTrue(mdObject instanceof CommonModule);
Module module = ((CommonModule)mdObject).getModule();
assertNotNull(module);
return module;
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>CommonModule</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
<nature>com._1c.g5.v8.dt.core.V8ConfigurationNature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -0,0 +1,2 @@
Manifest-Version: 1.0
Runtime-Version: 8.3.19

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:CommonModule xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="cb364877-7f3a-44d9-8bc3-70387044034b">
<name>CommonModule</name>
<synonym>
<key>en</key>
<value>Common module</value>
</synonym>
<server>true</server>
<externalConnection>true</externalConnection>
<clientOrdinaryApplication>true</clientOrdinaryApplication>
</mdclass:CommonModule>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<cmi:CommandInterface xmlns:cmi="http://g5.1c.ru/v8/dt/cmi"/>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:Configuration xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="41e0d07d-ece6-42b2-bfbf-686d364ed4fd">
<name>CommonModule</name>
<synonym>
<key>en</key>
<value>Common module</value>
</synonym>
<containedObjects classId="9cd510cd-abfc-11d4-9434-004095e12fc7" objectId="6c1e7aa2-b0dc-40a6-9666-92dc3ee3eee8"/>
<containedObjects classId="9fcd25a0-4822-11d4-9414-008048da11f9" objectId="23a1191a-d0c7-4384-92b6-1c0af1530860"/>
<containedObjects classId="e3687481-0a87-462c-a166-9f34594f9bba" objectId="2e16e60c-a924-457f-806e-e24b71ccd04b"/>
<containedObjects classId="9de14907-ec23-4a07-96f0-85521cb6b53b" objectId="5c2b531d-3b51-4e77-99c5-1b3a36046623"/>
<containedObjects classId="51f2d5d8-ea4d-4064-8892-82951750031e" objectId="0b85a612-279e-4922-8f22-838ada8729f6"/>
<containedObjects classId="e68182ea-4237-4383-967f-90c1e3370bc7" objectId="1a856b15-b18e-43c7-8608-d37f533898a6"/>
<containedObjects classId="fb282519-d103-4dd3-bc12-cb271d631dfc" objectId="16633a11-1ecd-48ba-ab9b-fe39c9b63e9e"/>
<configurationExtensionCompatibilityMode>8.3.19</configurationExtensionCompatibilityMode>
<defaultRunMode>ManagedApplication</defaultRunMode>
<usePurposes>PersonalComputer</usePurposes>
<usedMobileApplicationFunctionalities>
<functionality>
<use>true</use>
</functionality>
<functionality>
<functionality>OSBackup</functionality>
<use>true</use>
</functionality>
</usedMobileApplicationFunctionalities>
<defaultLanguage>Language.English</defaultLanguage>
<dataLockControlMode>Managed</dataLockControlMode>
<objectAutonumerationMode>NotAutoFree</objectAutonumerationMode>
<modalityUseMode>DontUse</modalityUseMode>
<synchronousPlatformExtensionAndAddInCallUseMode>DontUse</synchronousPlatformExtensionAndAddInCallUseMode>
<compatibilityMode>8.3.19</compatibilityMode>
<languages uuid="6d6f56cc-2157-41a6-aa5c-a2ca5b24e90c">
<name>English</name>
<synonym>
<key>en</key>
<value>English</value>
</synonym>
<languageCode>en</languageCode>
</languages>
<commonModules>CommonModule.CommonModule</commonModules>
</mdclass:Configuration>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<cmi:CommandInterface xmlns:cmi="http://g5.1c.ru/v8/dt/cmi"/>