1
0
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:
Александр Капралов 2021-08-11 14:31:32 +03:00 committed by GitHub
parent 464de06c3b
commit 4b9bf9530b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 915 additions and 8 deletions

View File

@ -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)",

View File

@ -0,0 +1,8 @@
# query-in-loop
## Noncompliant Code Example
## Compliant Solution
## See

View File

@ -0,0 +1,9 @@
# query-in-loop
## Неправильно
## Правильно
## См.
https://its.1c.ru/db/pubqlang#content:150:hdoc

View File

@ -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>

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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} ключей

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -0,0 +1,8 @@
{
"version": 1,
"settings": {
"query-in-loop": {
"enabled": true
}
}
}

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
topObjects=true

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="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>

View File

@ -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

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="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>

View File

@ -0,0 +1,13 @@
Procedure WhileStatementInfiniteLoop(SomeArray) Export
Query = New Query;
Query.Text =
"SELECT
| 1";
While True Do
Query.ExecuteBatchWithIntermediateData();
EndDo;
EndProcedure

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,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>

View File

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