mirror of
https://github.com/1C-Company/v8-code-style.git
synced 2025-02-03 09:57:35 +02:00
Проверка на запросы в цикле (#32)
#17 Добавлена проверка на запросы в цикле
This commit is contained in:
parent
464de06c3b
commit
4b9bf9530b
@ -16,12 +16,15 @@ 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.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.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.util;version="[7.0.0,8.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)",
|
||||
com._1c.g5.v8.dt.metadata.mdclass;version="[8.0.0,9.0.0)",
|
||||
com._1c.g5.v8.dt.platform;version="[5.0.0,6.0.0)",
|
||||
com._1c.g5.v8.dt.platform.version;version="[2.13.0,3.0.0)",
|
||||
com._1c.g5.wiring;version="[2.0.0,3.0.0)",
|
||||
com._1c.g5.wiring.binder;version="[1.0.0,2.0.0)",
|
||||
com.e1c.g5.v8.dt.bsl.check;version="[1.0.0,2.0.0)",
|
||||
|
@ -0,0 +1,8 @@
|
||||
# query-in-loop
|
||||
|
||||
## Noncompliant Code Example
|
||||
|
||||
## Compliant Solution
|
||||
|
||||
## See
|
||||
|
@ -0,0 +1,9 @@
|
||||
# query-in-loop
|
||||
|
||||
## Неправильно
|
||||
|
||||
## Правильно
|
||||
|
||||
## См.
|
||||
|
||||
https://its.1c.ru/db/pubqlang#content:150:hdoc
|
@ -11,21 +11,30 @@
|
||||
|
||||
Contributors:
|
||||
1C-Soft LLC - initial API and implementation
|
||||
Aleksandr Kapralov - issue #17
|
||||
-->
|
||||
|
||||
<plugin>
|
||||
<extension
|
||||
point="com.e1c.g5.v8.dt.check.checks">
|
||||
|
||||
<category
|
||||
category="com.e1c.v8codestyle"
|
||||
description="%category.bls.description"
|
||||
id="com.e1c.v8codestyle.bsl"
|
||||
title="%category.bsl.title">
|
||||
</category>
|
||||
|
||||
<check
|
||||
category="com.e1c.v8codestyle.bsl"
|
||||
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.StructureCtorTooManyKeysCheck">
|
||||
</check>
|
||||
|
||||
<check
|
||||
category="com.e1c.v8codestyle.bsl"
|
||||
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.QueryInLoopCheck">
|
||||
</check>
|
||||
|
||||
</extension>
|
||||
|
||||
</plugin>
|
||||
|
@ -9,6 +9,7 @@
|
||||
*
|
||||
* Contributors:
|
||||
* 1C-Soft LLC - initial API and implementation
|
||||
* Aleksandr Kapralov - issue #17
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
@ -25,10 +26,18 @@ final class Messages
|
||||
extends NLS
|
||||
{
|
||||
private static final String BUNDLE_NAME = "com.e1c.v8codestyle.bsl.check.messages"; //$NON-NLS-1$
|
||||
|
||||
public static String QueryInLoop_check_query_in_infinite_loop;
|
||||
public static String QueryInLoop_description;
|
||||
public static String QueryInLoop_Loop_has_query;
|
||||
public static String QueryInLoop_Loop_has_method_with_query__0;
|
||||
public static String QueryInLoop_title;
|
||||
|
||||
public static String StructureCtorTooManyKeysCheck_description;
|
||||
public static String StructureCtorTooManyKeysCheck_Maximum_structure_constructor_keys;
|
||||
public static String StructureCtorTooManyKeysCheck_Structure_constructor_has_more_than__0__keys;
|
||||
public static String StructureCtorTooManyKeysCheck_title;
|
||||
|
||||
static
|
||||
{
|
||||
// initialize resource bundle
|
||||
|
@ -0,0 +1,390 @@
|
||||
/*******************************************************************************
|
||||
* 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:
|
||||
* Aleksandr Kapralov - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.e1c.v8codestyle.bsl.check;
|
||||
|
||||
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.FEATURE_ACCESS__NAME;
|
||||
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.MODULE;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.emf.common.util.EList;
|
||||
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.nodemodel.ICompositeNode;
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
|
||||
import com._1c.g5.v8.dt.bsl.model.BooleanLiteral;
|
||||
import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
|
||||
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.Invocation;
|
||||
import com._1c.g5.v8.dt.bsl.model.LoopStatement;
|
||||
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.StaticFeatureAccess;
|
||||
import com._1c.g5.v8.dt.bsl.model.WhileStatement;
|
||||
import com._1c.g5.v8.dt.bsl.model.util.BslUtil;
|
||||
import com._1c.g5.v8.dt.bsl.resource.TypesComputer;
|
||||
import com._1c.g5.v8.dt.mcore.ContextDef;
|
||||
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.util.McoreUtil;
|
||||
import com._1c.g5.v8.dt.platform.IEObjectProvider;
|
||||
import com._1c.g5.v8.dt.platform.IEObjectTypeNames;
|
||||
import com._1c.g5.v8.dt.platform.version.IRuntimeVersionSupport;
|
||||
import com._1c.g5.v8.dt.platform.version.Version;
|
||||
import com.e1c.g5.v8.dt.check.CheckComplexity;
|
||||
import com.e1c.g5.v8.dt.check.ICheckParameters;
|
||||
import com.e1c.g5.v8.dt.check.components.BasicCheck;
|
||||
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
|
||||
import com.e1c.g5.v8.dt.check.settings.IssueType;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Checks queries in loops.
|
||||
* Skip checks for queries in infinite while loops by default.
|
||||
*
|
||||
* @author Aleksandr Kapralov
|
||||
*
|
||||
*/
|
||||
public class QueryInLoopCheck
|
||||
extends BasicCheck
|
||||
{
|
||||
|
||||
private static final String CHECK_ID = "query-in-loop"; //$NON-NLS-1$
|
||||
|
||||
private static final String PARAM_CHECK_QUERIY_IN_INFINITE_LOOP = "checkQueryInInfiniteLoop"; //$NON-NLS-1$
|
||||
|
||||
private static final String DEFAULT_CHECK_QUERY_IN_INFINITE_LOOP = Boolean.toString(false);
|
||||
|
||||
private final TypesComputer typesComputer;
|
||||
|
||||
private final IRuntimeVersionSupport versionSupport;
|
||||
|
||||
@Inject
|
||||
public QueryInLoopCheck(IRuntimeVersionSupport versionSupport)
|
||||
{
|
||||
super();
|
||||
|
||||
IResourceServiceProvider rsp =
|
||||
IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(URI.createURI("*.bsl")); //$NON-NLS-1$
|
||||
typesComputer = rsp.get(TypesComputer.class);
|
||||
|
||||
this.versionSupport = versionSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCheckId()
|
||||
{
|
||||
return CHECK_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureCheck(CheckConfigurer builder)
|
||||
{
|
||||
//@formatter:off
|
||||
builder.title(Messages.QueryInLoop_title)
|
||||
.description(Messages.QueryInLoop_description)
|
||||
.disable()
|
||||
.complexity(CheckComplexity.NORMAL)
|
||||
.severity(IssueSeverity.CRITICAL)
|
||||
.issueType(IssueType.PERFORMANCE)
|
||||
.module()
|
||||
.checkedObjectType(MODULE)
|
||||
.parameter(PARAM_CHECK_QUERIY_IN_INFINITE_LOOP, Boolean.class, DEFAULT_CHECK_QUERY_IN_INFINITE_LOOP,
|
||||
Messages.QueryInLoop_check_query_in_infinite_loop);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
|
||||
IProgressMonitor monitor)
|
||||
{
|
||||
if (monitor.isCanceled() || !(object instanceof Module))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Module module = (Module)object;
|
||||
|
||||
Set<String> queryExecutionMethods = getQueryExecutionMethods(module);
|
||||
if (queryExecutionMethods.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, String> methodsWithQuery = getMethodsWithQuery(module, queryExecutionMethods, monitor);
|
||||
if (methodsWithQuery.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
boolean checkQueryInInfiniteLoop = parameters.getBoolean(PARAM_CHECK_QUERIY_IN_INFINITE_LOOP);
|
||||
Collection<FeatureAccess> queryInLoopCallers =
|
||||
getQueryInLoopCallers(module, methodsWithQuery, queryExecutionMethods, checkQueryInInfiniteLoop, monitor);
|
||||
|
||||
for (FeatureAccess featureAccess : queryInLoopCallers)
|
||||
{
|
||||
if (monitor.isCanceled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (featureAccess instanceof DynamicFeatureAccess)
|
||||
{
|
||||
resultAceptor.addIssue(Messages.QueryInLoop_Loop_has_query, featureAccess, FEATURE_ACCESS__NAME);
|
||||
}
|
||||
|
||||
if (featureAccess instanceof StaticFeatureAccess)
|
||||
{
|
||||
String errorPath = methodsWithQuery.get(featureAccess.getName());
|
||||
String errorMessage =
|
||||
MessageFormat.format(Messages.QueryInLoop_Loop_has_method_with_query__0, errorPath);
|
||||
resultAceptor.addIssue(errorMessage, featureAccess, FEATURE_ACCESS__NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> getQueryExecutionMethods(EObject object)
|
||||
{
|
||||
Set<String> queryExecuteMethods = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
IEObjectProvider provider = IEObjectProvider.Registry.INSTANCE.get(McorePackage.Literals.TYPE_ITEM,
|
||||
versionSupport.getRuntimeVersionOrDefault(object, Version.LATEST));
|
||||
EObject proxyType = provider.getProxy(IEObjectTypeNames.QUERY);
|
||||
if (!(proxyType instanceof Type))
|
||||
{
|
||||
return queryExecuteMethods;
|
||||
}
|
||||
|
||||
Type queryType = (Type)EcoreUtil.resolve(proxyType, object);
|
||||
|
||||
ContextDef contextDef = queryType.getContextDef();
|
||||
if (contextDef == null)
|
||||
{
|
||||
return queryExecuteMethods;
|
||||
}
|
||||
|
||||
EList<com._1c.g5.v8.dt.mcore.Method> queryMethods = contextDef.allMethods();
|
||||
for (com._1c.g5.v8.dt.mcore.Method queryMethod : queryMethods)
|
||||
{
|
||||
if (!queryMethod.getName().startsWith("Execute")) //$NON-NLS-1$
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
queryExecuteMethods.add(queryMethod.getName());
|
||||
queryExecuteMethods.add(queryMethod.getNameRu());
|
||||
}
|
||||
|
||||
return queryExecuteMethods;
|
||||
}
|
||||
|
||||
private boolean isQueryTypeSource(Expression source)
|
||||
{
|
||||
Environmental envs = EcoreUtil2.getContainerOfType(source, Environmental.class);
|
||||
List<TypeItem> sourceTypes = typesComputer.computeTypes(source, envs.environments());
|
||||
if (sourceTypes.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (TypeItem sourceType : sourceTypes)
|
||||
{
|
||||
if (IEObjectTypeNames.QUERY.equals(McoreUtil.getTypeName(sourceType)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isQueryExecution(DynamicFeatureAccess dfa, Set<String> queryExecutionMethods)
|
||||
{
|
||||
return queryExecutionMethods.contains(dfa.getName()) && BslUtil.getInvocation(dfa) != null
|
||||
&& isQueryTypeSource(dfa.getSource());
|
||||
}
|
||||
|
||||
private String getSourceName(Expression source)
|
||||
{
|
||||
String result = ""; //$NON-NLS-1$
|
||||
|
||||
if (source instanceof FeatureAccess)
|
||||
{
|
||||
result = ((FeatureAccess)source).getName() + "."; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
else if (source instanceof Invocation)
|
||||
{
|
||||
result = getSourceName(((Invocation)source).getMethodAccess());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getPositionForFeatureObject(EObject object)
|
||||
{
|
||||
ICompositeNode node = NodeModelUtils.findActualNodeFor(object);
|
||||
return MessageFormat.format("'{'{0}'}' ", String.valueOf(node.getStartLine())); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private String getMethodPath(Method method, Map<String, String> result)
|
||||
{
|
||||
if (result.containsKey(method.getName()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
StaticFeatureAccess calledMethod = getMethodWithQuery(method, result);
|
||||
if (calledMethod == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
String calledMethodPath = result.get(calledMethod.getName());
|
||||
if (calledMethodPath == null)
|
||||
{
|
||||
calledMethodPath = calledMethod.getName() + "()"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
return String.join("", method.getName(), "() -> ", //$NON-NLS-1$ //$NON-NLS-2$
|
||||
getPositionForFeatureObject(calledMethod), calledMethodPath);
|
||||
}
|
||||
|
||||
private Map<String, String> getMethodsWithQuery(Module module, Set<String> queryExecutionMethods,
|
||||
IProgressMonitor monitor)
|
||||
{
|
||||
Map<String, String> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
for (DynamicFeatureAccess dfa : EcoreUtil2.eAllOfType(module, DynamicFeatureAccess.class))
|
||||
{
|
||||
if (monitor.isCanceled())
|
||||
{
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
if (isQueryExecution(dfa, queryExecutionMethods))
|
||||
{
|
||||
Method method = EcoreUtil2.getContainerOfType(dfa, Method.class);
|
||||
String sourceName = getSourceName(dfa.getSource());
|
||||
|
||||
String methodPath = String.join("", method.getName(), "() -> ", //$NON-NLS-1$ //$NON-NLS-2$
|
||||
getPositionForFeatureObject(dfa), sourceName, dfa.getName(), "()"); //$NON-NLS-1$
|
||||
result.put(method.getName(), methodPath);
|
||||
}
|
||||
}
|
||||
|
||||
EList<Method> methods = module.allMethods();
|
||||
|
||||
int methodsCount = 0;
|
||||
while (result.size() != methodsCount)
|
||||
{
|
||||
for (Method method : methods)
|
||||
{
|
||||
if (monitor.isCanceled())
|
||||
{
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
String methodPath = getMethodPath(method, result);
|
||||
if (methodPath == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.put(method.getName(), methodPath);
|
||||
}
|
||||
|
||||
methodsCount = result.size();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isMethodWithQueryCalled(StaticFeatureAccess sfa, Map<String, String> methodsWithQuery)
|
||||
{
|
||||
return methodsWithQuery.containsKey(sfa.getName()) && BslUtil.getInvocation(sfa) != null;
|
||||
}
|
||||
|
||||
private StaticFeatureAccess getMethodWithQuery(Method method, Map<String, String> methodsWithQuery)
|
||||
{
|
||||
for (StaticFeatureAccess sfa : EcoreUtil2.eAllOfType(method, StaticFeatureAccess.class))
|
||||
{
|
||||
if (isMethodWithQueryCalled(sfa, methodsWithQuery))
|
||||
{
|
||||
return sfa;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isInfiniteWhileLoop(LoopStatement loopStatement)
|
||||
{
|
||||
if (!(loopStatement instanceof WhileStatement))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Expression predicate = ((WhileStatement)loopStatement).getPredicate();
|
||||
return predicate instanceof BooleanLiteral;
|
||||
}
|
||||
|
||||
private Collection<FeatureAccess> getQueryInLoopCallers(Module module, Map<String, String> methodsWithQuery,
|
||||
Set<String> queryExecutionMethods, boolean checkQueryInInfiniteLoop, IProgressMonitor monitor)
|
||||
{
|
||||
Collection<FeatureAccess> result = new ArrayList<>();
|
||||
|
||||
for (LoopStatement loopStatement : EcoreUtil2.eAllOfType(module, LoopStatement.class))
|
||||
{
|
||||
if (monitor.isCanceled())
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (!checkQueryInInfiniteLoop && isInfiniteWhileLoop(loopStatement))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (FeatureAccess featureAccess : EcoreUtil2.eAllOfType(loopStatement, FeatureAccess.class))
|
||||
{
|
||||
if (featureAccess instanceof StaticFeatureAccess
|
||||
&& isMethodWithQueryCalled((StaticFeatureAccess)featureAccess, methodsWithQuery)
|
||||
|| featureAccess instanceof DynamicFeatureAccess
|
||||
&& isQueryExecution((DynamicFeatureAccess)featureAccess, queryExecutionMethods))
|
||||
{
|
||||
result.add(featureAccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
###############################################################################
|
||||
# Copyright (C) 2021, 1C-Soft LLC and others.
|
||||
#
|
||||
@ -9,8 +10,23 @@
|
||||
#
|
||||
# Contributors:
|
||||
# 1C-Soft LLC - initial API and implementation
|
||||
# Aleksandr Kapralov - issue #17
|
||||
###############################################################################
|
||||
StructureCtorTooManyKeysCheck_description=Check structure constructor has too many keys
|
||||
StructureCtorTooManyKeysCheck_Maximum_structure_constructor_keys=Maximum structure constructor keys
|
||||
StructureCtorTooManyKeysCheck_Structure_constructor_has_more_than__0__keys=Structure constructor has more than {0} keys
|
||||
StructureCtorTooManyKeysCheck_title=Structure constructor has too many keys
|
||||
|
||||
QueryInLoop_Loop_has_method_with_query__0 = Loop has method with query "{0}"
|
||||
|
||||
QueryInLoop_Loop_has_query = Loop has query
|
||||
|
||||
QueryInLoop_check_query_in_infinite_loop = Check query in infinite loop
|
||||
|
||||
QueryInLoop_description = Check query in loop
|
||||
|
||||
QueryInLoop_title = Query in loop
|
||||
|
||||
StructureCtorTooManyKeysCheck_Maximum_structure_constructor_keys = Maximum structure constructor keys
|
||||
|
||||
StructureCtorTooManyKeysCheck_Structure_constructor_has_more_than__0__keys = Structure constructor has more than {0} keys
|
||||
|
||||
StructureCtorTooManyKeysCheck_description = Check structure constructor has too many keys
|
||||
|
||||
StructureCtorTooManyKeysCheck_title = Structure constructor has too many keys
|
||||
|
@ -1,3 +1,4 @@
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
###############################################################################
|
||||
# Copyright (C) 2021, 1C-Soft LLC and others.
|
||||
#
|
||||
@ -9,10 +10,20 @@
|
||||
#
|
||||
# Contributors:
|
||||
# 1C-Soft LLC - initial API and implementation
|
||||
# Aleksandr Kapralov - issue #17
|
||||
###############################################################################
|
||||
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||
|
||||
StructureCtorTooManyKeysCheck_Maximum_structure_constructor_keys = Мксимальное количество ключей структуры в контструкторе
|
||||
QueryInLoop_Loop_has_method_with_query__0 = Цикл содержит вызов метода с запросом "{0}"
|
||||
|
||||
QueryInLoop_Loop_has_query = Цикл содержит выполнение запроса
|
||||
|
||||
QueryInLoop_check_query_in_infinite_loop = Проверять запрос в бесконечном цикле
|
||||
|
||||
QueryInLoop_description = Проверка запрос в цикле
|
||||
|
||||
QueryInLoop_title = Запрос в цикле
|
||||
|
||||
StructureCtorTooManyKeysCheck_Maximum_structure_constructor_keys = Максимальное количество ключей структуры в контструкторе
|
||||
|
||||
StructureCtorTooManyKeysCheck_Structure_constructor_has_more_than__0__keys = Конструктор структуры содержит более чем {0} ключей
|
||||
|
||||
|
@ -9,11 +9,13 @@
|
||||
*
|
||||
* Contributors:
|
||||
* 1C-Soft LLC - initial API and implementation
|
||||
* Aleksandr Kapralov - issue #17
|
||||
*******************************************************************************/
|
||||
package com.e1c.v8codestyle.internal.bsl;
|
||||
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
|
||||
import com._1c.g5.v8.dt.platform.version.IRuntimeVersionSupport;
|
||||
import com._1c.g5.wiring.AbstractServiceAwareModule;
|
||||
|
||||
/**
|
||||
@ -32,8 +34,7 @@ class ExternalDependenciesModule
|
||||
@Override
|
||||
protected void doConfigure()
|
||||
{
|
||||
// bind V8 services
|
||||
|
||||
bind(IRuntimeVersionSupport.class).toService();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,195 @@
|
||||
/*******************************************************************************
|
||||
* 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:
|
||||
* Aleksandr Kapralov - initial API and implementation
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.e1c.v8codestyle.bsl.check.itests;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.xtext.EcoreUtil2;
|
||||
import org.junit.Test;
|
||||
|
||||
import com._1c.g5.v8.bm.core.IBmObject;
|
||||
import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
|
||||
import com._1c.g5.v8.dt.bsl.model.Method;
|
||||
import com._1c.g5.v8.dt.bsl.model.Module;
|
||||
import com._1c.g5.v8.dt.core.platform.IDtProject;
|
||||
import com._1c.g5.v8.dt.metadata.mdclass.CommonModule;
|
||||
import com._1c.g5.v8.dt.validation.marker.IExtraInfoKeys;
|
||||
import com._1c.g5.v8.dt.validation.marker.Marker;
|
||||
import com.e1c.g5.v8.dt.check.settings.CheckUid;
|
||||
import com.e1c.g5.v8.dt.check.settings.ICheckSettings;
|
||||
import com.e1c.g5.v8.dt.testing.check.CheckTestBase;
|
||||
import com.e1c.v8codestyle.bsl.check.QueryInLoopCheck;
|
||||
import com.e1c.v8codestyle.internal.bsl.BslPlugin;
|
||||
|
||||
/**
|
||||
* Tests for {@link QueryInLoopCheck} check.
|
||||
*
|
||||
* @author Aleksandr Kapralov
|
||||
*/
|
||||
public class QueryInLoopCheckTest
|
||||
extends CheckTestBase
|
||||
{
|
||||
|
||||
private static final String PROJECT_NAME = "QueryInLoop";
|
||||
|
||||
private static final String CHECK_ID = "query-in-loop"; //$NON-NLS-1$
|
||||
|
||||
private static final String PARAM_CHECK_QUERIY_IN_INFINITE_LOOP = "checkQueryInInfiniteLoop"; //$NON-NLS-1$
|
||||
|
||||
@Test
|
||||
public void testQueryInLoop() throws Exception
|
||||
{
|
||||
IDtProject dtProject = openProjectAndWaitForValidationFinish(PROJECT_NAME);
|
||||
assertNotNull(dtProject);
|
||||
|
||||
IBmObject mdObject = getTopObjectByFqn("CommonModule.CommonModule", dtProject);
|
||||
assertTrue(mdObject instanceof CommonModule);
|
||||
Module module = ((CommonModule)mdObject).getModule();
|
||||
assertNotNull(module);
|
||||
|
||||
String id = module.eResource().getURI().toPlatformString(true);
|
||||
Marker[] markers = markerManager.getMarkers(dtProject.getWorkspaceProject(), id);
|
||||
assertNotNull(markers);
|
||||
|
||||
Set<String> uriErrors = new HashSet<>();
|
||||
|
||||
for (Method method : module.allMethods())
|
||||
{
|
||||
List<FeatureAccess> featureAccessList = EcoreUtil2.eAllOfType(method, FeatureAccess.class);
|
||||
|
||||
switch (method.getName())
|
||||
{
|
||||
case "QueryCorrect":
|
||||
case "QueryExecutionCorrect":
|
||||
case "MethodCallsQueryCorrect":
|
||||
case "MethodCallsIncorrectMethodCorrect":
|
||||
case "GetNewQuery":
|
||||
{
|
||||
// Those methods doesn't have errors
|
||||
break;
|
||||
}
|
||||
|
||||
case "ForEachStatementIncorrect":
|
||||
{
|
||||
assertEquals(14, featureAccessList.size());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(8)).toString());
|
||||
break;
|
||||
}
|
||||
case "ForToStatementIncorrect":
|
||||
{
|
||||
assertEquals(12, featureAccessList.size());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(7)).toString());
|
||||
break;
|
||||
}
|
||||
case "WhileStatementIncorrect":
|
||||
{
|
||||
assertEquals(9, featureAccessList.size());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(3)).toString());
|
||||
break;
|
||||
}
|
||||
case "LoopCallsMethodIncorrect":
|
||||
{
|
||||
assertEquals(9, featureAccessList.size());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(4)).toString());
|
||||
break;
|
||||
}
|
||||
case "LoopCallsMethodWithOtherMethodIncorrect":
|
||||
{
|
||||
assertEquals(6, featureAccessList.size());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(3)).toString());
|
||||
break;
|
||||
}
|
||||
case "LoopWithConditionsIncorrect":
|
||||
{
|
||||
assertEquals(12, featureAccessList.size());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(2)).toString());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(6)).toString());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(8)).toString());
|
||||
break;
|
||||
}
|
||||
case "QueryTypeFromFunctionIncorrect":
|
||||
{
|
||||
assertEquals(9, featureAccessList.size());
|
||||
uriErrors.add(EcoreUtil.getURI(featureAccessList.get(2)).toString());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException(MessageFormat.format("Unknown method name {0}", method.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Marker marker : markers)
|
||||
{
|
||||
String checkUid = getCheckIdFromMarker(marker, dtProject);
|
||||
assertNotNull(checkUid);
|
||||
assertTrue(CHECK_ID.equals(checkUid));
|
||||
|
||||
String uriToProblem = marker.getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_URI_TO_PROBLEM_KEY);
|
||||
assertTrue(uriErrors.contains(uriToProblem));
|
||||
uriErrors.remove(uriToProblem);
|
||||
}
|
||||
|
||||
assertEquals(0, uriErrors.size());
|
||||
}
|
||||
|
||||
private CheckUid cuid(String checkId)
|
||||
{
|
||||
return new CheckUid(checkId, BslPlugin.PLUGIN_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInfiniteLoop() throws Exception
|
||||
{
|
||||
IDtProject dtProject = openProjectAndWaitForValidationFinish(PROJECT_NAME);
|
||||
assertNotNull(dtProject);
|
||||
|
||||
IBmObject mdObject = getTopObjectByFqn("CommonModule.InfiniteLoop", dtProject);
|
||||
assertTrue(mdObject instanceof CommonModule);
|
||||
Module module = ((CommonModule)mdObject).getModule();
|
||||
assertNotNull(module);
|
||||
|
||||
String id = module.eResource().getURI().toPlatformString(true);
|
||||
Marker[] markers = markerManager.getMarkers(dtProject.getWorkspaceProject(), id);
|
||||
assertNotNull(markers);
|
||||
|
||||
assertEquals(0, markers.length);
|
||||
|
||||
IProject project = dtProject.getWorkspaceProject();
|
||||
ICheckSettings settings = checkRepository.getSettings(cuid(CHECK_ID), project);
|
||||
settings.getParameters().get(PARAM_CHECK_QUERIY_IN_INFINITE_LOOP).setValue(Boolean.toString(true));
|
||||
checkRepository.applyChanges(Collections.singleton(settings), project);
|
||||
waitForDD(dtProject);
|
||||
|
||||
markers = markerManager.getMarkers(dtProject.getWorkspaceProject(), id);
|
||||
assertNotNull(markers);
|
||||
|
||||
assertEquals(1, markers.length);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>QueryInLoop</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>
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"version": 1,
|
||||
"settings": {
|
||||
"query-in-loop": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
topObjects=true
|
@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
Runtime-Version: 8.3.19
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mdclass:CommonModule xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="1f97dda8-37e7-4746-915e-00498e2ecd48">
|
||||
<name>CommonModule</name>
|
||||
<synonym>
|
||||
<key>en</key>
|
||||
<value>Common module</value>
|
||||
</synonym>
|
||||
<server>true</server>
|
||||
<externalConnection>true</externalConnection>
|
||||
<clientOrdinaryApplication>true</clientOrdinaryApplication>
|
||||
</mdclass:CommonModule>
|
@ -0,0 +1,148 @@
|
||||
Procedure QueryCorrect(SomeParameter) Export
|
||||
|
||||
SimpleQuery = New Query;
|
||||
|
||||
SimpleQuery.SetParameter("SomeParameter", SomeParameter);
|
||||
|
||||
SimpleQuery.Text =
|
||||
"SELECT
|
||||
| 1";
|
||||
|
||||
SimpleQuery.Execute();
|
||||
|
||||
EndProcedure
|
||||
|
||||
Function QueryExecutionCorrect(Query) Export
|
||||
|
||||
Result = Query.Execute();
|
||||
|
||||
Return Result;
|
||||
|
||||
EndFunction
|
||||
|
||||
Procedure MethodCallsQueryCorrect(SomeParameter) Export
|
||||
|
||||
QueryCorrect(SomeParameter);
|
||||
|
||||
EndProcedure
|
||||
|
||||
Procedure ForEachStatementIncorrect(SomeArray) Export
|
||||
|
||||
ForEachQuery = New Query;
|
||||
|
||||
ForEachQuery.Text =
|
||||
"SELECT
|
||||
| 1";
|
||||
|
||||
For Each ArrayElement In SomeArray Do
|
||||
ForEachQuery.SetParameter("SomeParameter", ArrayElement);
|
||||
Selection = ForEachQuery.Execute().Select();
|
||||
Selection.Next();
|
||||
EndDo;
|
||||
|
||||
EndProcedure
|
||||
|
||||
Procedure ForToStatementIncorrect(SomeArray) Export
|
||||
|
||||
ForToQuery = New Query;
|
||||
|
||||
ForToQuery.Text =
|
||||
"SELECT
|
||||
| 1";
|
||||
|
||||
For ArrayElement = 1 To 10 Do
|
||||
ForToQuery.SetParameter("SomeParameter", ArrayElement);
|
||||
Result = ForToQuery.ExecuteBatch();
|
||||
Result[0].Select();
|
||||
EndDo;
|
||||
|
||||
EndProcedure
|
||||
|
||||
Procedure WhileStatementIncorrect(SomeArray) Export
|
||||
|
||||
WhileQuery = New Query;
|
||||
|
||||
WhileQuery.Text =
|
||||
"SELECT
|
||||
| 1";
|
||||
|
||||
While SomeArray.Count() > 0 And SomeArray.Count() < 5 Do
|
||||
WhileQuery.ExecuteBatchWithIntermediateData();
|
||||
EndDo;
|
||||
|
||||
EndProcedure
|
||||
|
||||
Procedure MethodCallsIncorrectMethodCorrect(SomeArray) Export
|
||||
|
||||
ForEachStatementIncorrect(SomeArray);
|
||||
|
||||
EndProcedure
|
||||
|
||||
Procedure LoopCallsMethodIncorrect(SomeParameter) Export
|
||||
|
||||
LoopCallQuery = New Query;
|
||||
|
||||
LoopCallQuery.Text =
|
||||
"SELECT
|
||||
| 1";
|
||||
|
||||
While SomeParameter = 0 Do
|
||||
Result = QueryExecutionCorrect(LoopCallQuery);
|
||||
Result.Select();
|
||||
EndDo;
|
||||
|
||||
EndProcedure
|
||||
|
||||
Procedure LoopCallsMethodWithOtherMethodIncorrect(SomeParameter) Export
|
||||
|
||||
MethodCallQuery = New Query;
|
||||
|
||||
MethodCallQuery.Text =
|
||||
"SELECT
|
||||
| 1";
|
||||
|
||||
While SomeParameter = 0 Do
|
||||
MethodCallsQueryCorrect(MethodCallQuery);
|
||||
EndDo;
|
||||
|
||||
EndProcedure
|
||||
|
||||
Procedure LoopWithConditionsIncorrect(SomeArray) Export
|
||||
|
||||
While SomeArray.Count() = 0 Do
|
||||
If SomeArray.Size() = 1 Then
|
||||
ForEachStatementIncorrect(SomeArray);
|
||||
|
||||
ElsIf SomeArray.Size() = 2 Then
|
||||
ForToStatementIncorrect(SomeArray);
|
||||
|
||||
Else
|
||||
WhileStatementIncorrect(SomeArray);
|
||||
|
||||
EndIf;
|
||||
EndDo;
|
||||
|
||||
EndProcedure
|
||||
|
||||
Function GetNewQuery(ArrayElement)
|
||||
|
||||
FunctionQuery = New Query;
|
||||
|
||||
FunctionQuery.Text =
|
||||
"SELECT
|
||||
| 1";
|
||||
|
||||
FunctionQuery.SetParameter("SomeParameter", ArrayElement);
|
||||
|
||||
Return FunctionQuery;
|
||||
|
||||
EndFunction
|
||||
|
||||
Procedure QueryTypeFromFunctionIncorrect(SomeArray) Export
|
||||
|
||||
For Each ArrayElement In SomeArray Do
|
||||
Selection = GetNewQuery(ArrayElement).Execute().Select();
|
||||
Selection.Next();
|
||||
EndDo;
|
||||
|
||||
EndProcedure
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mdclass:CommonModule xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="d83a4f24-b0a1-49f1-96be-01e8955a2adf">
|
||||
<name>InfiniteLoop</name>
|
||||
<synonym>
|
||||
<key>en</key>
|
||||
<value>Infinite loop</value>
|
||||
</synonym>
|
||||
<server>true</server>
|
||||
<externalConnection>true</externalConnection>
|
||||
<clientOrdinaryApplication>true</clientOrdinaryApplication>
|
||||
</mdclass:CommonModule>
|
@ -0,0 +1,13 @@
|
||||
Procedure WhileStatementInfiniteLoop(SomeArray) Export
|
||||
|
||||
Query = New Query;
|
||||
|
||||
Query.Text =
|
||||
"SELECT
|
||||
| 1";
|
||||
|
||||
While True Do
|
||||
Query.ExecuteBatchWithIntermediateData();
|
||||
EndDo;
|
||||
|
||||
EndProcedure
|
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<cmi:CommandInterface xmlns:cmi="http://g5.1c.ru/v8/dt/cmi"/>
|
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mdclass:Configuration xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="f8166085-112b-4451-8d9e-88dbfe86d90f">
|
||||
<name>QueryInLoop</name>
|
||||
<synonym>
|
||||
<key>en</key>
|
||||
<value>Query in loop</value>
|
||||
</synonym>
|
||||
<containedObjects classId="9cd510cd-abfc-11d4-9434-004095e12fc7" objectId="133ede92-0c7f-4f71-9e9c-9f44c3da9722"/>
|
||||
<containedObjects classId="9fcd25a0-4822-11d4-9414-008048da11f9" objectId="8d533318-a072-4c80-aa16-8893a3602ec4"/>
|
||||
<containedObjects classId="e3687481-0a87-462c-a166-9f34594f9bba" objectId="5ec2f4d8-7bd9-4088-b89c-83e979381dae"/>
|
||||
<containedObjects classId="9de14907-ec23-4a07-96f0-85521cb6b53b" objectId="aa80ec52-e027-4261-8209-52d0c99d52d9"/>
|
||||
<containedObjects classId="51f2d5d8-ea4d-4064-8892-82951750031e" objectId="f44271e2-de0e-4466-8fe5-296bb6de7def"/>
|
||||
<containedObjects classId="e68182ea-4237-4383-967f-90c1e3370bc7" objectId="ea7014f6-7658-4fd7-aa94-3abb90a8ac1c"/>
|
||||
<configurationExtensionCompatibilityMode>8.3.16</configurationExtensionCompatibilityMode>
|
||||
<defaultRunMode>ManagedApplication</defaultRunMode>
|
||||
<usePurposes>PersonalComputer</usePurposes>
|
||||
<requiredMobileApplicationPermissions>
|
||||
<permission>AllowOSBackup</permission>
|
||||
<use>true</use>
|
||||
</requiredMobileApplicationPermissions>
|
||||
<defaultLanguage>Language.English</defaultLanguage>
|
||||
<dataLockControlMode>Managed</dataLockControlMode>
|
||||
<objectAutonumerationMode>NotAutoFree</objectAutonumerationMode>
|
||||
<modalityUseMode>DontUse</modalityUseMode>
|
||||
<synchronousPlatformExtensionAndAddInCallUseMode>DontUse</synchronousPlatformExtensionAndAddInCallUseMode>
|
||||
<compatibilityMode>8.3.19</compatibilityMode>
|
||||
<languages uuid="0ced1c9f-d92b-4c54-80c9-6c421fac2136">
|
||||
<name>English</name>
|
||||
<synonym>
|
||||
<key>en</key>
|
||||
<value>English</value>
|
||||
</synonym>
|
||||
<languageCode>en</languageCode>
|
||||
</languages>
|
||||
<commonModules>CommonModule.CommonModule</commonModules>
|
||||
<commonModules>CommonModule.InfiniteLoop</commonModules>
|
||||
</mdclass:Configuration>
|
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<cmi:CommandInterface xmlns:cmi="http://g5.1c.ru/v8/dt/cmi"/>
|
Loading…
x
Reference in New Issue
Block a user