1
0
mirror of https://github.com/1C-Company/v8-code-style.git synced 2024-11-21 13:15:53 +02:00

Проверки и квик-фиксы для BSL-модулей (#955)

This commit is contained in:
Vadim Geraskin 2022-02-10 22:18:53 +07:00 committed by GitHub
parent 9180efe9bf
commit 1bcce78983
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 2502 additions and 17 deletions

View File

@ -1,4 +1,5 @@
eclipse.preferences.version=1
encoding//src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties=UTF-8
encoding//src/com/e1c/v8codestyle/internal/bsl/ui/preferences/messages_ru.properties=UTF-8
encoding//src/com/e1c/v8codestyle/internal/bsl/ui/properties/messages_ru.properties=UTF-8
encoding//src/com/e1c/v8codestyle/internal/bsl/ui/views/messages_ru.properties=UTF-8

View File

@ -25,13 +25,20 @@ Import-Package: com._1c.g5.ides.ui.texteditor.xtext.embedded;version="[5.0.0,6.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="[5.0.0,6.0.0)",
com._1c.g5.v8.dt.bsl.services;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.bsl.ui;version="[8.2.0,9.0.0)",
com._1c.g5.v8.dt.bsl.ui.contentassist;version="[8.0.0,9.0.0)",
com._1c.g5.v8.dt.bsl.ui.editor;version="[8.0.0,9.0.0)",
com._1c.g5.v8.dt.bsl.ui.menu;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.bsl.ui.quickfix;version="[4.1.0,5.0.0)",
com._1c.g5.v8.dt.bsl.util;version="[7.0.0,8.0.0)",
com._1c.g5.v8.dt.common;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.core.filesystem;version="[5.0.0,6.0.0)",
com._1c.g5.v8.dt.core.model;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.core.platform;version="[10.0.0,11.0.0)",
com._1c.g5.v8.dt.lcore.ui.editor;version="[2.3.0,3.0.0)",
com._1c.g5.v8.dt.lcore.ui.texteditor;version="[1.1.0,2.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.metadata.mdclass;version="[8.0.0,9.0.0)",
com._1c.g5.v8.dt.theming.ui.util;version="[1.0.0,2.0.0)",
@ -39,5 +46,9 @@ Import-Package: com._1c.g5.ides.ui.texteditor.xtext.embedded;version="[5.0.0,6.0
com._1c.g5.v8.dt.ui.wizards;version="[8.0.0,9.0.0)",
com._1c.g5.wiring;version="[2.2.0,3.0.0)",
com._1c.g5.wiring.binder;version="[1.1.0,2.0.0)",
com.e1c.g5.v8.dt.bsl.check.qfix;version="[1.0.0,2.0.0)",
com.e1c.g5.v8.dt.check.qfix;version="[1.0.0,2.0.0)",
com.e1c.g5.v8.dt.check.qfix.components;version="[1.0.0,2.0.0)",
com.e1c.v8codestyle.bsl;version="[0.2.0,0.3.0)",
com.e1c.v8codestyle.bsl.qfix.external;version="[0.2.0,0.3.0)",
com.e1c.v8codestyle.bsl.strict;version="[0.2.0,0.3.0)"

View File

@ -344,5 +344,11 @@
</reference></activeWhen>
</handler>
</extension>
<extension point="com.e1c.g5.v8.dt.check.fixes">
<fix class="com.e1c.v8codestyle.internal.bsl.ui.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.ui.qfix.UndefinedMethodFix"/>
<fix class="com.e1c.v8codestyle.internal.bsl.ui.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.ui.qfix.UndefinedFunctionFix"/>
<fix class="com.e1c.v8codestyle.internal.bsl.ui.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.ui.qfix.UndefinedVariableFix"/>
</extension>
</plugin>

View File

@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (C) 2022, 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.ui.qfix;
import org.eclipse.osgi.util.NLS;
/**
* NLS messages
*
* @author Vadim Geraskin
*/
final class Messages
extends NLS
{
private static final String BUNDLE_NAME = "com.e1c.v8codestyle.bsl.ui.qfix.messages"; //$NON-NLS-1$
public static String UndefinedMethodFix_func_title;
public static String UndefinedMethodFix_func_desc;
public static String UndefinedMethodFix_proc_title;
public static String UndefinedMethodFix_proc_desc;
public static String UndefinedVariableFix_title;
public static String UndefinedVariableFix_desc;
static
{
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
private Messages()
{
// N/A
}
}

View File

@ -0,0 +1,232 @@
/*******************************************************************************
* Copyright (C) 2022, 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.ui.qfix;
import java.util.Optional;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.link.LinkedPosition;
import org.eclipse.jface.text.link.LinkedPositionGroup;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import com._1c.g5.v8.dt.bsl.model.Method;
import com._1c.g5.v8.dt.bsl.model.StaticFeatureAccess;
import com._1c.g5.v8.dt.bsl.ui.contentassist.BslProposalProvider;
import com._1c.g5.v8.dt.bsl.ui.quickfix.BslQuickFixUtil;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com.e1c.v8codestyle.bsl.qfix.external.IXtextBslModuleFixModel;
import com.e1c.v8codestyle.bsl.qfix.external.IXtextInteractiveBslModuleFixModel;
import com.google.common.base.Strings;
/**
* Helper methods for xtext-based quick fixes
*
* @author Vadim Geraskin
*/
public final class QuickFixMethodsHelper
{
/**
* Creates method and writes it to module
*
* @param model the xtext BSL quick fix model, cannot be {@code null}
* @param isFunc indicates whether the method is function or procedure
* @throws BadLocationException
*/
static void createMethod(IXtextInteractiveBslModuleFixModel model, boolean isFunc) throws BadLocationException
{
EObject element = model.getElement();
String methodName = getMethodName(((StaticFeatureAccess)element).getName());
String directiveName = ""; //$NON-NLS-1$
//up to Method class
Method method = EcoreUtil2.getContainerOfType(element, Method.class);
if (method != null)
{
String methodKeywordType = getTypeMethodName(model, isFunc);
String methodEndKeywordType = getTypeEndMethodName(model, isFunc);
//calculation offset
int totalEndOffset = NodeModelUtils.getNode(method).getTotalEndOffset();
Optional<String> indent = model.getFormatString(method);
if (indent.isPresent())
{
String func = createMethod(model, indent.get(), directiveName, methodName, methodKeywordType,
methodEndKeywordType);
// Write method to module
IXtextDocument document = (IXtextDocument)model.getDocument();
BslQuickFixUtil.writeToDoc(document, totalEndOffset, func);
flushMethod(model, indent.get(), methodKeywordType, totalEndOffset, directiveName);
}
}
}
/**
* Provides offset for the given {@Method}
*
* @param method the method, cannot be {@code null}
* @return offset
*/
static int getMethodOffset(Method method)
{
//method always has statement
return NodeModelUtils.findActualNodeFor(method.allStatements().get(0)).getOffset();
}
/**
* Gets 'Procedure' or 'Function'
*
* @param model {@link IXtextBslModuleFixModel}, cannot be {@code null}
* @param isFunc defines what will be return
* @return 'Procedure' if <code>isFunc == false, else return 'Function'</code>
*/
static String getTypeMethodName(IXtextBslModuleFixModel model, boolean isFunc)
{
boolean isRussion = model.getScriptVariant() == ScriptVariant.RUSSIAN;
return BslProposalProvider.getTypeMethodName(model.getBslGrammar(), isFunc, isRussion);
}
/**
* Gets 'EndProcedure' or 'EndFunction'
*
* @param model {@link IXtextBslModuleFixModel}, cannot be {@code null}
* @param isFunc defines what will be return
* @return 'EndProcedure' if <code>isFunc == false, else return 'EndFunction'</code>
*/
static String getTypeEndMethodName(IXtextBslModuleFixModel model, boolean isFunc)
{
boolean isRussion = model.getScriptVariant() == ScriptVariant.RUSSIAN;
return BslProposalProvider.getTypeEndMethodName(model.getBslGrammar(), isFunc, isRussion);
}
private static String getMethodName(String name)
{
StringBuilder builder = new StringBuilder();
builder.append(name);
builder.append('(');
builder.append(')');
return builder.toString();
}
private static String createMethod(IXtextInteractiveBslModuleFixModel model, String indent, String directive,
String methodName, String methodKeyword, String methodEndKeyword)
{
String lineSeparator = model.getLineSeparator();
String commentContent = Strings.repeat(lineSeparator, 2);
String todoComment = indent + model.getIndentProvider().getIndent()
+ model.getBslGeneratorMultiLangProposals().getImplementationPropStr();
StringBuilder builder = new StringBuilder();
//add comment above function
builder.append(commentContent);
//create function body
if (!Strings.isNullOrEmpty(directive))
{
builder.append(indent).append('&').append(directive).append(lineSeparator);
}
builder.append(indent).append(methodKeyword).append(' ');
builder.append(methodName);
builder.append(lineSeparator).append(todoComment).append(lineSeparator);
builder.append(indent).append(methodEndKeyword);
return builder.toString();
}
private static void flushMethod(IXtextInteractiveBslModuleFixModel model, String indent, String methodKeywordType,
int totalEndOffset, String directiveName)
{
IXtextDocument document = (IXtextDocument)model.getDocument();
String lineSeparator = model.getLineSeparator();
String commentContent = Strings.repeat(lineSeparator, 2);
//creating LinkedModeModel
LinkedPosition[] groupParams = calculateParamsGroupForMethod(commentContent, indent, lineSeparator,
methodKeywordType, document, model.getIssueData(), totalEndOffset);
int posDec = totalEndOffset + indent.length() + methodKeywordType.length() + 1 + commentContent.length();
if (!Strings.isNullOrEmpty(directiveName))
{
posDec += indent.length() + 1 + directiveName.length() + lineSeparator.length();
}
int posUse = model.getIssue().getOffset();
int nameLen = ((StaticFeatureAccess)model.getElement()).getName().length();
createLinkedModeModel(model, posDec, posUse, nameLen, groupParams);
}
private static LinkedPosition[] calculateParamsGroupForMethod(String commentContent, String indent,
String lineSeparator, String functionKeywordType, IXtextDocument doc, String[] data, int offset)
{
if (data != null && data.length >= 2)
{
int numParams = Integer.parseInt(data[2]);
LinkedPosition[] groupParams = new LinkedPosition[numParams];
int startLen = data[1].length() + 2 + offset + commentContent.length() + indent.length()
+ functionKeywordType.length();
if (!Strings.isNullOrEmpty(data[0]))
{
startLen += indent.length() + data[0].length() + lineSeparator.length() + 1;
}
for (int i = 3; i < data.length; ++i)
{
groupParams[i - 3] = new LinkedPosition(doc, startLen, data[i].length());
startLen += data[i].length() + 2;
}
return groupParams;
}
else
{
return new LinkedPosition[0];
}
}
private static void createLinkedModeModel(IXtextInteractiveBslModuleFixModel model, int posDec, int posUse,
int length, LinkedPosition[] params)
{
IXtextDocument document = (IXtextDocument)model.getDocument();
try
{
// create groups - this step is independent of the linked mode
LinkedPositionGroup group = new LinkedPositionGroup();
group.addPosition(new LinkedPosition(document, posDec, length));
group.addPosition(new LinkedPosition(document, posUse, length));
/* set up linked mode */
LinkedModeModel linkedModeModel = model.getLinkedModeModel();
linkedModeModel.addGroup(group);
for (int i = 0; i < params.length; ++i)
{
LinkedPositionGroup groupParam = new LinkedPositionGroup();
groupParam.addPosition(params[i]);
linkedModeModel.addGroup(groupParam);
}
LinkedModeModel.closeAllModels(document);
linkedModeModel.forceInstall();
model.enterUiMode();
model.selectAndRevealForLinkedModeModel(posDec, length);
}
catch (Exception e)
{
model.selectAndRevealForLinkedModeModel(posUse, length);
}
}
private QuickFixMethodsHelper()
{
// Not to be instantiated
}
}

View File

@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (C) 2022, 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.ui.qfix;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.xtext.resource.XtextResource;
import com.e1c.g5.v8.dt.check.qfix.components.QuickFix;
import com.e1c.v8codestyle.bsl.qfix.external.IXtextBslModuleFixModel;
import com.e1c.v8codestyle.bsl.qfix.external.IXtextInteractiveBslModuleFixModel;
import com.e1c.v8codestyle.bsl.qfix.external.SingleVariantXtextBslModuleFix;
/**
* Quick fix for check com.e1c.v8codestyle.bsl.check:undefined-function
*
* @author Vadim Geraskin
*/
@QuickFix(checkId = "module-undefined-function", supplierId = "com.e1c.v8codestyle.bsl")
public class UndefinedFunctionFix
extends SingleVariantXtextBslModuleFix
{
@Override
protected void configureFix(FixConfigurer configurer)
{
configurer.interactive(true).description(Messages.UndefinedMethodFix_func_title);
}
@Override
protected TextEdit fixIssue(XtextResource state, IXtextBslModuleFixModel model) throws BadLocationException
{
QuickFixMethodsHelper.createMethod((IXtextInteractiveBslModuleFixModel)model, true);
return null;
}
}

View File

@ -0,0 +1,72 @@
/*******************************************************************************
* Copyright (C) 2022, 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.ui.qfix;
import org.eclipse.jface.text.BadLocationException;
import com.e1c.g5.v8.dt.check.qfix.components.QuickFix;
import com.e1c.v8codestyle.bsl.qfix.external.IXtextInteractiveBslModuleFixModel;
import com.e1c.v8codestyle.bsl.qfix.external.MultiVariantXtextBslModuleFix;
import com.e1c.v8codestyle.internal.bsl.ui.UiPlugin;
/**
* Quick fix for check com.e1c.v8codestyle.bsl.check:undefined-method
*
* @author Vadim Geraskin
*/
@QuickFix(checkId = "module-undefined-method", supplierId = "com.e1c.v8codestyle.bsl")
public class UndefinedMethodFix
extends MultiVariantXtextBslModuleFix
{
@Override
protected void buildVariants()
{
// 1-st variant of issue qf: create function
VariantBuilder.create(this)
.description(Messages.UndefinedMethodFix_func_title, Messages.UndefinedMethodFix_func_desc)
.interactive(true)
.change((context, session, state, model) -> createFunction((IXtextInteractiveBslModuleFixModel)model))
.build();
// 2-nd variant of issue qf: create procedure
VariantBuilder.create(this)
.description(Messages.UndefinedMethodFix_proc_title, Messages.UndefinedMethodFix_proc_desc)
.interactive(true)
.change((context, session, state, model) -> createProcedure((IXtextInteractiveBslModuleFixModel)model))
.build();
}
private void createFunction(IXtextInteractiveBslModuleFixModel model)
{
try
{
QuickFixMethodsHelper.createMethod(model, true);
}
catch (BadLocationException e)
{
UiPlugin.log(UiPlugin.createErrorStatus("Error occured when creating function", e)); //$NON-NLS-1$
}
}
private void createProcedure(IXtextInteractiveBslModuleFixModel model)
{
try
{
QuickFixMethodsHelper.createMethod(model, false);
}
catch (BadLocationException e)
{
UiPlugin.log(UiPlugin.createErrorStatus("Error occured when creating procedure", e)); //$NON-NLS-1$
}
}
}

View File

@ -0,0 +1,129 @@
/*******************************************************************************
* Copyright (C) 2022, 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.ui.qfix;
import java.util.Optional;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.link.LinkedPosition;
import org.eclipse.jface.text.link.LinkedPositionGroup;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import com._1c.g5.v8.dt.bsl.model.Method;
import com._1c.g5.v8.dt.bsl.model.StaticFeatureAccess;
import com._1c.g5.v8.dt.bsl.ui.quickfix.BslQuickFixUtil;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com.e1c.g5.v8.dt.check.qfix.components.QuickFix;
import com.e1c.v8codestyle.bsl.qfix.external.IXtextBslModuleFixModel;
import com.e1c.v8codestyle.bsl.qfix.external.IXtextInteractiveBslModuleFixModel;
import com.e1c.v8codestyle.bsl.qfix.external.SingleVariantXtextBslModuleFix;
/**
* Quick fix for check com.e1c.v8codestyle.bsl.check:undefined-variable
*
* @author Vadim Geraskin
*/
@QuickFix(checkId = "module-undefined-variable", supplierId = "com.e1c.v8codestyle.bsl")
public class UndefinedVariableFix
extends SingleVariantXtextBslModuleFix
{
@Override
protected void configureFix(FixConfigurer configurer)
{
configurer.interactive(true)
.description(Messages.UndefinedVariableFix_title)
.details(Messages.UndefinedVariableFix_desc);
}
@Override
protected TextEdit fixIssue(XtextResource state, IXtextBslModuleFixModel model) throws BadLocationException
{
IXtextInteractiveBslModuleFixModel interactiveModel = (IXtextInteractiveBslModuleFixModel)model;
EObject element = model.getElement();
String declarationKeyWord = getDeclarationKeyword(model);
//up to Method class
Method method = EcoreUtil2.getContainerOfType(element, Method.class);
if (method != null)
{
Optional<String> indent = interactiveModel.getFormatString(method);
if (indent.isPresent())
{
int offset = QuickFixMethodsHelper.getMethodOffset(method);
String variableName = ((StaticFeatureAccess)model.getElement()).getName();
IXtextDocument document = (IXtextDocument)interactiveModel.getDocument();
String lineSeparator = model.getLineSeparator();
String variable = BslQuickFixUtil.createVariable(declarationKeyWord, variableName,
indent.get() + interactiveModel.getIndentProvider().getIndent(), lineSeparator);
//write var to module
BslQuickFixUtil.writeToDoc(document, offset, variable);
//linked mode model
int posDec = offset + declarationKeyWord.length() + 1;
int posUse = model.getIssue().getOffset() + variable.length();
int length = variableName.length();
createLinkedModeModel(interactiveModel, posDec, posUse, length);
}
}
return null;
}
//CHECKSTYLE.OFF: LineLength
private static String getDeclarationKeyword(IXtextBslModuleFixModel model)
{
boolean isRussion = model.getScriptVariant() == ScriptVariant.RUSSIAN;
return !isRussion ? model.getBslGrammar().getDeclareStatementAccess().getVarKeyword_0_0().getValue() : model
.getBslGrammar()
.getDeclareStatementAccess()
.getCyrillicCapitalLetterPeCyrillicSmallLetterIeCyrillicSmallLetterErCyrillicSmallLetterIeCyrillicSmallLetterEmKeyword_0_1()
.getValue();
}
//CHECKSTYLE.ON: LineLength
private static void createLinkedModeModel(IXtextInteractiveBslModuleFixModel model, int posDec, int posUse,
int length)
{
IXtextDocument document = (IXtextDocument)model.getDocument();
try
{
//create groups - this step is independent of the linked mode
LinkedPositionGroup group = new LinkedPositionGroup();
group.addPosition(new LinkedPosition(document, posDec, length));
group.addPosition(new LinkedPosition(document, posUse, length));
//set up linked mode
LinkedModeModel linkedModeModel = model.getLinkedModeModel();
linkedModeModel.addGroup(group);
LinkedModeModel.closeAllModels(document);
linkedModeModel.forceInstall();
model.enterUiMode();
model.selectAndRevealForLinkedModeModel(posUse, length);
}
catch (Exception e)
{
//mark using varible
model.selectAndRevealForLinkedModeModel(posUse, length);
}
}
}

View File

@ -0,0 +1,22 @@
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
###############################################################################
# Copyright (C) 2022, 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
# Vadim Geraskin - initial contibution
###############################################################################
UndefinedMethodFix_func_title=Create function
UndefinedMethodFix_func_desc=Create a new function in the module
UndefinedMethodFix_proc_title=Create procedure
UndefinedMethodFix_proc_desc=Create a new procedure in the module
UndefinedVariableFix_title=Create variable
UndefinedVariableFix_desc=Create a missing variable in the method or module.\nSave changes in the editor after quick fix is applied.

View File

@ -0,0 +1,21 @@
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
###############################################################################
# Copyright (C) 2022, 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
# Vadim Geraskin - initial contibution
###############################################################################
UndefinedMethodFix_func_title=Создать функцию
UndefinedMethodFix_func_desc=Создать новую функцию в модуле
UndefinedMethodFix_proc_title=Создать процедуру
UndefinedMethodFix_proc_desc=Создать новую процедуру в модуле
UndefinedVariableFix_title=Создать переменную
UndefinedVariableFix_desc=Создать пропущенную переменную на уровне метода или модуля.\nПосле применения исправления сохраните изменения в редакторе.

View File

@ -6,16 +6,22 @@ Bundle-Version: 0.2.0.qualifier
Bundle-Activator: com.e1c.v8codestyle.internal.bsl.BslPlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.0.0,4.0.0)",
Require-Bundle: org.eclipse.core.resources;bundle-version="[3.13.0,4.0.0)",
org.eclipse.core.runtime;bundle-version="[3.0.0,4.0.0)",
org.eclipse.emf.common;bundle-version="[2.15.0,3.0.0)",
org.eclipse.text;bundle-version="[3.8.100,4.0.0)",
org.eclipse.xtext;bundle-version="[2.17.0,3.0.0)",
org.eclipse.core.resources;bundle-version="[3.13.0,4.0.0)",
org.eclipse.xtext.builder;bundle-version="[2.18.0,3.0.0)",
org.eclipse.xtext.ui;bundle-version="[2.24.0,3.0.0)",
org.eclipse.handly;bundle-version="[1.5.0,2.0.0)",
org.eclipse.xtext.ui.shared;bundle-version="[2.19.0,3.0.0)",
org.eclipse.jface.text;bundle-version="[3.17.0,4.0.0)"
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)",
Import-Package: com._1c.g5.ides.ui.texteditor.xtext.embedded;version="[5.0.0,6.0.0)",
com._1c.g5.v8.bm.core;version="[7.0.0,8.0.0)",
com._1c.g5.v8.dt.bsl;version="[4.4.0,5.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.contextdef;version="[2.0.0,3.0.0)",
@ -24,25 +30,37 @@ Import-Package: com._1c.g5.v8.bm.core;version="[7.0.0,8.0.0)",
com._1c.g5.v8.dt.bsl.model.resource.owner;version="[2.0.0,3.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.services;version="[6.0.0,7.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.ui;version="[8.2.0,9.0.0)",
com._1c.g5.v8.dt.bsl.ui.contentassist;version="[8.0.0,9.0.0)",
com._1c.g5.v8.dt.bsl.ui.quickfix;version="[4.1.0,5.0.0)",
com._1c.g5.v8.dt.bsl.util;version="[7.0.0,8.0.0)",
com._1c.g5.v8.dt.bsl.validation;version="[16.0.0,17.0.0)",
com._1c.g5.v8.dt.common;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.core.platform;version="[10.0.0,11.0.0)",
com._1c.g5.v8.dt.form.model;version="[10.0.0,11.0.0)",
com._1c.g5.v8.dt.lcore.ui.editor;version="[2.3.0,3.0.0)",
com._1c.g5.v8.dt.lcore.ui.texteditor;version="[1.1.0,2.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)",
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.v8.dt.validation.marker;version="[5.0.0,6.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)",
com.e1c.g5.v8.dt.bsl.check.qfix;version="[1.0.0,3.0.0)",
com.e1c.g5.v8.dt.check;version="[2.0.0,3.0.0)",
com.e1c.g5.v8.dt.check.components;version="[2.0.0,3.0.0)",
com.e1c.g5.v8.dt.check.qfix;version="[1.0.0,2.0.0)",
com.e1c.g5.v8.dt.check.qfix.components;version="[1.0.0,2.0.0)",
com.e1c.g5.v8.dt.check.settings;version="[2.0.0,3.0.0)",
com.e1c.v8codestyle;version="[0.2.0,0.3.0)",
com.e1c.v8codestyle.check;version="[0.2.0,0.3.0)"
Export-Package: com.e1c.v8codestyle.bsl;version="0.2.0",
com.e1c.v8codestyle.bsl.qfix.external;version="0.2.0",
com.e1c.v8codestyle.bsl.strict;version="0.2.0"

View File

@ -214,6 +214,15 @@
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.bsl.check.IsInRoleCheck">
</check>
<check category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.UndefinedMethodCheck">
</check>
<check category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.UndefinedFunctionCheck">
</check>
<check category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.UndefinedVariableCheck">
</check>
<check
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.bsl.check.InvocationFormEventHandlerCheck">
@ -226,8 +235,8 @@
category="com.e1c.v8codestyle.bsl"
class="com.e1c.v8codestyle.bsl.check.ExportMethodInCommandFormModuleCheck">
</check>
</extension>
<extension
point="org.eclipse.core.runtime.preferences">
<initializer

View File

@ -16,8 +16,9 @@ package com.e1c.v8codestyle.bsl.check;
import org.eclipse.osgi.util.NLS;
/**
* @author Dmitriy Marmyshev
* NLS messages
*
* @author Dmitriy Marmyshev
*/
final class Messages
extends NLS
@ -194,6 +195,16 @@ final class Messages
public static String IsInRoleCheck_Using_IsInRole;
public static String ModuleUndefinedVariableCheck_Title;
public static String ModuleUndefinedVariableCheck_Description;
public static String ModuleUndefinedVariable_msg;
public static String ModuleUndefinedMethodCheck_Title;
public static String ModuleUndefinedMethodCheck_Description;
public static String ModuleUndefinedFunctionCheck_Title;
public static String ModuleUndefinedFunctionCheck_Description;
public static String ModuleUndefinedFunction_msg;
public static String ModuleUndefinedMethod_msg;
static
{
// initialize resource bundle
@ -202,5 +213,6 @@ final class Messages
private Messages()
{
// N/A
}
}

View File

@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (C) 2022, 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.check;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.osgi.util.NLS;
import com._1c.g5.v8.dt.bsl.model.BslPackage;
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.StaticFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.util.BslUtil;
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;
/**
* Check for undefined function or procedure in module
*
* @author Vadim Geraskin
*/
public class UndefinedFunctionCheck
extends BasicCheck
{
private static final String CHECK_ID = "module-undefined-function"; //$NON-NLS-1$
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void check(Object object, ResultAcceptor resultAcceptor, ICheckParameters parameters,
IProgressMonitor progressMonitor)
{
if (progressMonitor.isCanceled())
{
return;
}
Invocation invocation = (Invocation)object;
if (invocation != null)
{
FeatureAccess fa = invocation.getMethodAccess();
if (fa instanceof StaticFeatureAccess)
{
String name = fa.getName();
String msg;
if (((StaticFeatureAccess)fa).getImplicitVariable() == null
&& !BslUtil.isProcedureInvocation(invocation))
{
msg = NLS.bind(Messages.ModuleUndefinedFunction_msg, name);
resultAcceptor.addIssue(msg, fa);
}
}
}
}
@Override
protected void configureCheck(CheckConfigurer configurationBuilder)
{
configurationBuilder.title(Messages.ModuleUndefinedFunctionCheck_Title)
.description(Messages.ModuleUndefinedFunctionCheck_Description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.ERROR)
.module()
.checkedObjectType(BslPackage.Literals.INVOCATION);
}
}

View File

@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright (C) 2022, 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.check;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.osgi.util.NLS;
import com._1c.g5.v8.dt.bsl.model.BslPackage;
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.StaticFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.util.BslUtil;
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;
/**
* Check for undefined function or procedure in module
*
* @author Vadim Geraskin
*/
public class UndefinedMethodCheck
extends BasicCheck
{
private static final String CHECK_ID = "module-undefined-method"; //$NON-NLS-1$
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void check(Object object, ResultAcceptor resultAcceptor, ICheckParameters parameters,
IProgressMonitor progressMonitor)
{
if (progressMonitor.isCanceled())
{
return;
}
Invocation invocation = (Invocation)object;
FeatureAccess fa = invocation.getMethodAccess();
if (fa instanceof StaticFeatureAccess)
{
String name = fa.getName();
String msg;
if (((StaticFeatureAccess)fa).getImplicitVariable() == null && BslUtil.isProcedureInvocation(invocation))
{
msg = NLS.bind(Messages.ModuleUndefinedMethod_msg, name);
resultAcceptor.addIssue(msg, fa);
}
}
}
@Override
protected void configureCheck(CheckConfigurer configurationBuilder)
{
configurationBuilder.title(Messages.ModuleUndefinedMethodCheck_Title)
.description(Messages.ModuleUndefinedMethodCheck_Description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.ERROR)
.module()
.checkedObjectType(BslPackage.Literals.INVOCATION);
}
}

View File

@ -0,0 +1,133 @@
/*******************************************************************************
* Copyright (C) 2022, 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.check;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.xtext.EcoreUtil2;
import com._1c.g5.v8.dt.bsl.model.BslPackage;
import com._1c.g5.v8.dt.bsl.model.FeatureEntry;
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.StaticFeatureAccess;
import com._1c.g5.v8.dt.bsl.model.util.BslUtil;
import com._1c.g5.v8.dt.bsl.validation.BslPreferences;
import com._1c.g5.v8.dt.mcore.util.Environment;
import com._1c.g5.v8.dt.mcore.util.Environments;
import com._1c.g5.v8.dt.mcore.util.McoreUtil;
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;
/**
* Check for undefined variable in bsl module
*
* @author Vadim Geraskin
*/
public class UndefinedVariableCheck
extends BasicCheck
{
private static final String CHECK_ID = "module-undefined-variable"; //$NON-NLS-1$
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void check(Object object, ResultAcceptor resultAcceptor, ICheckParameters parameters,
IProgressMonitor progressMonitor)
{
if (progressMonitor.isCanceled())
{
return;
}
StaticFeatureAccess fa = (StaticFeatureAccess)object;
if (fa.eContainer() instanceof Invocation || fa.getImplicitVariable() == null)
{
return;
}
String varName = fa.getName();
String msg = NLS.bind(Messages.ModuleUndefinedVariable_msg, varName);
if (!fa.getFeatureEntries().isEmpty())
{
if (allStatementsAreDeclare(fa, varName))
{
return;
}
FeatureEntry entry = fa.getFeatureEntries().get(0);
Environments envs = getEnv(entry);
Invocation invocation = BslUtil.getInvocation(entry);
if (invocation == null && !BslUtil.isEventHandler(entry))
{
msg += " [" + Arrays.stream(envs.toArray()) //$NON-NLS-1$
.map(McoreUtil::getEnvironmentText)
.collect(Collectors.joining(", ")) //$NON-NLS-1$
+ ']';
}
else
{
return;
}
}
resultAcceptor.addIssue(msg, fa);
}
@Override
protected void configureCheck(CheckConfigurer configurationBuilder)
{
configurationBuilder.title(Messages.ModuleUndefinedVariableCheck_Title)
.description(Messages.ModuleUndefinedVariableCheck_Description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.ERROR)
.module()
.checkedObjectType(BslPackage.Literals.STATIC_FEATURE_ACCESS);
}
private static boolean allStatementsAreDeclare(StaticFeatureAccess fa, String varName)
{
Method method = EcoreUtil2.getContainerOfType(fa, Method.class);
return method.allDeclareStatements()
.stream()
.flatMap(ds -> ds.getVariables().stream())
.anyMatch(v -> v.getName().equals(varName));
}
private static Environments getEnv(FeatureEntry entry)
{
Environments envs = new Environments(entry.getEnvironments().toArray());
if (entry.eContainer() instanceof StaticFeatureAccess && envs.contains(Environment.MNG_CLIENT)
&& !envs.contains(Environment.SERVER) && !BslPreferences.detectIsClientServer(entry))
{
StaticFeatureAccess sfa = (StaticFeatureAccess)entry.eContainer();
if (sfa.getFeatureEntries()
.stream()
.anyMatch(item -> item != entry && item.getEnvironments().contains(Environment.SERVER)))
{
envs = envs.remove(Environment.MNG_CLIENT);
}
}
return envs;
}
}

View File

@ -1,7 +1,7 @@
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
# Copyright (C) 2021-2022, 1C-Soft LLC and others.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
@ -211,3 +211,15 @@ UseNonRecommendedMethods_message = Using non-recommended method
UseNonRecommendedMethods_parameter = List of non-recommended methods
UseNonRecommendedMethods_title = Using non-recommended methods
ModuleUndefinedVariableCheck_Title = Undefined variable
ModuleUndefinedVariableCheck_Description = Undefined variable
ModuleUndefinedVariable_msg = Variable "{0}" is not defined
ModuleUndefinedMethodCheck_Title = Undefined method
ModuleUndefinedMethodCheck_Description = Undefined function or procedure
ModuleUndefinedFunctionCheck_Title = Undefined function
ModuleUndefinedFunctionCheck_Description = Undefined function
ModuleUndefinedFunction_msg = Function "{0}" is not defined
ModuleUndefinedMethod_msg = Procedure or function "{0}" is not defined

View File

@ -1,6 +1,6 @@
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
# Copyright (C) 2021-2022, 1C-Soft LLC and others.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
@ -211,3 +211,14 @@ UseNonRecommendedMethods_message = Используется не рекомен
UseNonRecommendedMethods_parameter = Список дополнительных не рекомендуемых методов для проверки
UseNonRecommendedMethods_title = Использование не рекомендуемых методов
ModuleUndefinedVariableCheck_Title = Переменная не определена
ModuleUndefinedVariableCheck_Description = Переменная не определена
ModuleUndefinedVariable_msg = Переменная "{0}" не определена
ModuleUndefinedMethodCheck_Title = Метод не определен
ModuleUndefinedMethodCheck_Description = Функция или процедура не определена
ModuleUndefinedFunctionCheck_Title = Функция не определена
ModuleUndefinedFunctionCheck_Description = Функция не определена
ModuleUndefinedFunction_msg = Функция "{0}" не определена
ModuleUndefinedMethod_msg = Процедура или функция "{0}" не определена

View File

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import com._1c.g5.wiring.IManagedService;
import com.e1c.g5.v8.dt.check.qfix.IFixRepository;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* Java-based registrar of BSL quick fix components
*
* @author Alexander Tretyakevich
*/
@Singleton
public class BslCheckFixBoostrap
implements IManagedService
{
@Inject
private IFixRepository fixRepository;
@Inject
private SingleVariantXtextBslModuleFixContextFactory singleVariantXtextBslModuleFixContextFactory;
@Override
public void activate()
{
fixRepository.registerContextFactory(singleVariantXtextBslModuleFixContextFactory);
}
@Override
public void deactivate()
{
// Not necessary at the moment
}
}

View File

@ -0,0 +1,109 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.ui.IEditorPart;
import org.eclipse.xtext.ui.editor.IURIEditorOpener;
import org.eclipse.xtext.ui.editor.XtextEditor;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import org.eclipse.xtext.ui.editor.model.edit.IssueModificationContext;
import org.eclipse.xtext.validation.Issue;
import com._1c.g5.v8.dt.lcore.ui.editor.ViewerAwareIssueModificationContext;
import com.google.common.base.Preconditions;
/**
* Extension of {@link IssueModificationContext} to be used by quick fixes and suppressions
*
* @author Vadim Geraskin
*/
public class BslIssueModificationContext
extends ViewerAwareIssueModificationContext
{
private final AtomicReference<ITextViewer> viewerRef = new AtomicReference<>();
private final Issue issue;
private final IURIEditorOpener editorOpener;
private IXtextDocument document;
/**
* Instantiates modification context
*
* @param issue the issue, cannot be {@code null}
* @param editorOpener the editor opener, cannot be {@code null}
*/
public BslIssueModificationContext(Issue issue, IURIEditorOpener editorOpener)
{
this.issue = Preconditions.checkNotNull(issue);
this.editorOpener = Preconditions.checkNotNull(editorOpener);
}
@Override
public IXtextDocument getXtextDocument()
{
return getXtextDocument(issue.getUriToProblem());
}
@Override
public IXtextDocument getXtextDocument(URI uri)
{
if (document != null)
{
return document;
}
document = getXtextDocument(uri, editorOpener, editor -> viewerRef.set(extractLocalTextViewer(editor)));
setTextViewer(viewerRef.get());
return document;
}
/*
* Extract text viewer from editor. Can return {@code null}
*/
private static ITextViewer extractLocalTextViewer(IEditorPart editor)
{
ITextOperationTarget target = editor.getAdapter(ITextOperationTarget.class);
if (target instanceof ITextViewer)
{
return (ITextViewer)target;
}
return null;
}
private static IXtextDocument getXtextDocument(URI uri, IURIEditorOpener editorOpener,
Consumer<IEditorPart> editorConsumer)
{
for (int trial = 0; trial < 2; trial++)
{
IEditorPart editor = editorOpener.open(uri, false);
if (editor == null)
{
return null;
}
if (editorConsumer != null)
{
editorConsumer.accept(editor);
}
if (editor instanceof XtextEditor)
{
XtextEditor xtextEditor = (XtextEditor)editor;
return xtextEditor.getDocument();
}
}
return null;
}
}

View File

@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import org.eclipse.xtext.resource.XtextResource;
import com.e1c.g5.v8.dt.check.qfix.IFixSession;
/**
* Functional delegate that allows to specify the matching method as a change execution logic for multi-variant
* quick fixes
*
* @author Vadim Geraskin
*/
@FunctionalInterface
public interface IMultiVariantXtextModuleFixChangeDelegate
{
/**
* Performs the fix application
*
* @param context the quick fix context, cannot be {@code null}
* @param session the fix session, cannot be {@code null}
* @param state the xtext resource, cannot be {@code null}
* @param model the quick fix model, cannot be {@code null}
*/
void applyFix(SingleVariantXtextBslModuleFixContext context, IFixSession session, XtextResource state,
IXtextBslModuleFixModel model);
}

View File

@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import com.e1c.g5.v8.dt.check.qfix.IFixSession;
/**
* Functional delegate that allows to specify the matching method as a change execution logic for multi-variant
* quick fixes
*
* @author Vadim Geraskin
*/
@FunctionalInterface
public interface ISingleVariantXtextModuleFixChangeDelegate
{
/**
* Perfoms apply of the fix
*
* @param context the quick fix context, cannot be {@code null}
* @param session the session, cannot be {@code null}
*/
void applyFix(SingleVariantXtextBslModuleFixContext context, IFixSession session);
}

View File

@ -0,0 +1,83 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.IDocument;
import org.eclipse.xtext.validation.Issue;
import com._1c.g5.v8.dt.bsl.services.BslGrammarAccess;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
/**
* Contract for xtext BSL quick fix model
*
* @author Vadim Geraskin
*/
public interface IXtextBslModuleFixModel
{
/**
* Provides {@link IDocument}
*
* @return {@link IDocument}, never {@code null}
*/
IDocument getDocument();
/**
* Provides module {@link IResourceLookup}
*
* @return {link IResourceLookup}, never {@code null}
*/
IResourceLookup getResourceLookup();
/**
* Provides the element which is used to create a quick fix
*
* @return the element, can be {@code null}
*/
EObject getElement();
/**
* xtext validation issue reference
*
* @return {@link Issue}, never {@code null}
*/
Issue getIssue();
/**
* The associated user data. May be {@code null} or empty but may not contain {@code null} entries.
*
* @return user data, can be {@code null}
*/
String[] getIssueData();
/**
* Provides {@link BslGrammarAccess}
*
* @return {@link BslGrammarAccess}, never {@code null}
*/
BslGrammarAccess getBslGrammar();
/**
* Returns {@code ScriptVariant} for current project
*
* @return {@code ScriptVariant}, never {@code null}
*/
ScriptVariant getScriptVariant();
/**
* Gets line separator preference set for current project. If the preference is not set for the project then
* the canonical lookup order is used (instance, configuration, default).
*
* @return the line separator preference. Never {@code null}.
*/
String getLineSeparator();
}

View File

@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.validation.Issue;
import com._1c.g5.v8.dt.core.platform.IDtProject;
import com.e1c.g5.v8.dt.check.qfix.IFixSession;
/**
* Contract for {@link XtextBslModuleFixProvider}
*
* @author Vadim Geraskin
*/
public interface IXtextBslModuleFixProvider
{
/**
* Returns xtext quick fix model
*
* @param dtProject the {@IDtProject}, cannot be {@code null}
* @param issue instance of the {@link Issue}, cannot be {@code null}
* @param session the {@code IFixSession}, cannot be {@code null}
* @param targetModuleUri the target module Uri, cannot be {@code null}
* @param isInteractive {@code true} if quick fix supports interactive (UI) model, {@code false} otherwise
* @return the quick fix model, never {@code null}
*/
IXtextBslModuleFixModel getXtextFixModel(IDtProject dtProject, Issue issue, IFixSession session,
URI targetModuleUri, boolean isInteractive);
}

View File

@ -0,0 +1,92 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import java.util.Optional;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.xtext.ui.editor.model.edit.IModificationContext;
import com._1c.g5.v8.dt.bsl.ui.BslGeneratorMultiLangProposals;
import com._1c.g5.v8.dt.lcore.ui.texteditor.IndentTextEditorProvider;
/**
* Contract for xtext BSL interactive quick fix model
*
* @author Vadim Geraskin
*/
public interface IXtextInteractiveBslModuleFixModel
extends IXtextBslModuleFixModel
{
/**
* Provides {@link IndentTextEditorProvider}
*
* @return {@link IndentTextEditorProvider}, never {@code null}
*/
IndentTextEditorProvider getIndentProvider();
/**
* Multilanguage proposals for quick-fix and content-assist for Bsl
*
* @return reference to {@link BslGeneratorMultiLangProposals}, never {@code null}
*/
BslGeneratorMultiLangProposals getBslGeneratorMultiLangProposals();
/**
* Provides modification context
*
* @return {@link IModificationContext}, never {@code null}
*/
IModificationContext getModificationContext();
/**
* Provides the format string for the given {@code EObject} which is the semantic object whose node should
* be provided {@code NodeModelUtils.findActualNodeFor()}
*
* @param eObject the object, cannot be {@code null}
* @return format string, never {@code null}
* @throws BadLocationException
*/
Optional<String> getFormatString(EObject eObject) throws BadLocationException;
/**
* Provides {@code LinkedModeModel}
*
* @return {@code LinkedModeModel}, never {@code null}
*/
LinkedModeModel getLinkedModeModel();
/**
* Returns a description of the line at the given offset.The description contains the offset and the length of the
* line excluding the line's delimiter.
*
* @param offset the offset whose line should be described
* @return a region describing the line, never {@code null}
* @throws BadLocationException
*/
IRegion getLineInformationOfOffset(int offset) throws BadLocationException;
/**
* Connects the ui mode for linked mode and starts UI on the first position
* Should be called write after installation of linkedModeModel: {@code linkedModeModel.forceInstall()}
*/
void enterUiMode();
/**
* Sets the selected range and reveals it
*
* @param posStart the start position
* @param length the length of selection
*/
void selectAndRevealForLinkedModeModel(int posStart, int length);
}

View File

@ -0,0 +1,257 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
import com.e1c.g5.v8.dt.check.qfix.FixDescriptor;
import com.e1c.g5.v8.dt.check.qfix.FixVariantDescriptor;
import com.e1c.g5.v8.dt.check.qfix.IFix;
import com.e1c.g5.v8.dt.check.qfix.IFixChange;
import com.e1c.g5.v8.dt.check.qfix.IFixChangeProcessor;
import com.e1c.g5.v8.dt.check.qfix.IFixSession;
import com.e1c.g5.v8.dt.check.qfix.IFixVariant;
import com.e1c.g5.v8.dt.check.qfix.components.BasicFix;
/**
* Multi-variant xtext module fix definition
*
* @author Alexander Tretyakevich - Initial contribution
* @author Vadim Geraskin - Additional features
*/
public abstract class MultiVariantXtextBslModuleFix
extends BasicFix<SingleVariantXtextBslModuleFixContext>
implements IFix<SingleVariantXtextBslModuleFixContext>
{
private Collection<IFixVariant<SingleVariantXtextBslModuleFixContext>> fixVariants = new HashSet<>();
@Override
public Class<SingleVariantXtextBslModuleFixContext> getRequiredContextType()
{
return SingleVariantXtextBslModuleFixContext.class;
}
@Override
public Collection<IFixVariant<SingleVariantXtextBslModuleFixContext>> getVariants(
SingleVariantXtextBslModuleFixContext context, IFixSession session)
{
return fixVariants;
}
@Override
public void onRegistration(FixDescriptor registrationContext)
{
VariantXtextBslModuleFixChangeProcessor changeProcessor = new VariantXtextBslModuleFixChangeProcessor();
registrationContext.setChangeProcessor(changeProcessor);
buildVariants();
}
/**
* Creates and sets up fix variants
*/
protected abstract void buildVariants();
/**
* Provides a builder of the quick fix variant
*
* @author Vadim Geraskin
*/
protected static class VariantBuilder
{
private final MultiVariantXtextBslModuleFix fix;
private IMultiVariantXtextModuleFixChangeDelegate delegate;
private String description;
private String details;
private boolean isInteractive;
/**
* Creates variant builder instance
*
* @param fix the reference to the model fix, cannot be {@code null}
*/
public VariantBuilder(MultiVariantXtextBslModuleFix fix)
{
this.fix = fix;
}
/**
* Static variant builder creator
*
* @param fix the reference to the model fix, cannot be {@code null}
* @return the instance of the variant builder, never {@code null}
*/
public static VariantBuilder create(MultiVariantXtextBslModuleFix fix)
{
return new VariantBuilder(fix);
}
/**
* Creates code change delegate
*
* @param delegate change delegate, cannot be {@code null}
* @return the instance of the variant builder, never {@code null}
*/
public VariantBuilder change(IMultiVariantXtextModuleFixChangeDelegate delegate)
{
this.delegate = delegate;
return this;
}
/**
* Sets the modification model type - either interactive (UI) or not
*
* @param isInteractive {@code true} if quick fix supports inbteractive (UI) model, {@code false} otherwise
* @return the instance of the variant builder, never {@code null}
*/
public VariantBuilder interactive(boolean isInteractive)
{
this.isInteractive = isInteractive;
return this;
}
/**
* Creates variant description and details messages
*
* @param description the short description, cannot be {@code null}
* @param details the detailed message, can be {@code null}
* @return the instance of the variant builder, never {@code null}
*/
public VariantBuilder description(String description, String details)
{
this.description = description;
this.details = details;
return this;
}
/**
* Finalizes the variant builder, registers the variant
*/
public void build()
{
IFixVariant<SingleVariantXtextBslModuleFixContext> variant =
new MultiVariantXtextBslModuleVariant<>(delegate, description, details, isInteractive);
fix.fixVariants.add(variant);
}
}
private static class MultiVariantXtextBslModuleVariant<C extends SingleVariantXtextBslModuleFixContext>
implements IFixVariant<C>
{
private final IMultiVariantXtextModuleFixChangeDelegate delegate;
private final String description;
private final String details;
private final boolean isInteractive;
/**
* Creates {@link MultiVariantXtextBslModuleVariant} instance
*
* @param delegate the delegate to be executed, cannot be {@code null}
* @param description the fix variant short description, cannot be {@code null}
* @param details the fix variant detailed description, can be {@code null}
* @param isInteractive {@code true} if quick fix supports interactive (UI) model, {@code false} otherwise
*/
MultiVariantXtextBslModuleVariant(IMultiVariantXtextModuleFixChangeDelegate delegate, String description,
String details, boolean isInteractive)
{
this.delegate = delegate;
this.description = description;
this.details = details;
this.isInteractive = true;
}
@Override
public Collection<IFixChange> prepareChanges(C context, IFixSession session)
{
if (context.getTargetModuleUri() == null)
{
return Collections.emptyList();
}
return Collections.singleton(new VariantXtextBslModuleFixChange(delegate, isInteractive));
}
@Override
public FixVariantDescriptor describeChanges(C context, IFixSession session)
{
return new FixVariantDescriptor(description, details);
}
}
private static final class VariantXtextBslModuleFixChange
implements IFixChange
{
private final IMultiVariantXtextModuleFixChangeDelegate delegate;
private final boolean isInteractive;
/**
* Creates {@link VariantXtextBslModuleFixChange} instance
*
* @param delegate the delegate to be executed, cannot be {@code null}
* @param isInteractive {@code true} if quick fix supports interactive (UI) model, {@code false} otherwise
*/
VariantXtextBslModuleFixChange(IMultiVariantXtextModuleFixChangeDelegate delegate, boolean isInteractive)
{
this.delegate = delegate;
this.isInteractive = isInteractive;
}
/**
* Executes the quick fix resolution code
*
* @param context the quick fix context, cannot be {@code null}
* @param session the quick fix session, cannot be {@code null}
*/
public void applyFix(SingleVariantXtextBslModuleFixContext context, IFixSession session)
{
IXtextBslModuleFixModel fixModel = context.getModel(session, isInteractive);
if (fixModel instanceof IXtextInteractiveBslModuleFixModel)
{
((IXtextDocument)fixModel.getDocument()).readOnly(new IUnitOfWork.Void<XtextResource>()
{
@Override
public void process(XtextResource state) throws Exception
{
delegate.applyFix(context, session, state, fixModel);
}
});
}
else
{
// Nothing at the moment
}
}
}
/*
* Variant fix change processor
*/
private static final class VariantXtextBslModuleFixChangeProcessor
implements IFixChangeProcessor<VariantXtextBslModuleFixChange, SingleVariantXtextBslModuleFixContext>
{
@Override
public void applyFix(VariantXtextBslModuleFixChange fixChange, SingleVariantXtextBslModuleFixContext context,
IFixSession session)
{
fixChange.applyFix(context, session);
}
@Override
public Class<VariantXtextBslModuleFixChange> getProcessedFixType()
{
return VariantXtextBslModuleFixChange.class;
}
}
}

View File

@ -0,0 +1,285 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import org.eclipse.xtext.ui.editor.model.edit.IModificationContext;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
import org.eclipse.xtext.validation.Issue;
import org.eclipse.xtext.validation.Issue.IssueImpl;
import com._1c.g5.v8.dt.bsl.model.Module;
import com._1c.g5.v8.dt.common.Pair;
import com._1c.g5.v8.dt.common.StringUtils;
import com.e1c.g5.v8.dt.bsl.check.qfix.ExternalQuickfixModification;
import com.e1c.g5.v8.dt.check.qfix.FixDescriptor;
import com.e1c.g5.v8.dt.check.qfix.FixVariantDescriptor;
import com.e1c.g5.v8.dt.check.qfix.IFixChange;
import com.e1c.g5.v8.dt.check.qfix.IFixChangeProcessor;
import com.e1c.g5.v8.dt.check.qfix.IFixSession;
import com.e1c.g5.v8.dt.check.qfix.components.SingleVariantBasicFix;
import com.e1c.v8codestyle.internal.bsl.BslPlugin;
/**
* Single variant xtext bsl module fix common class for multi-variant quick fixes
*
* @author Vadim Geraskin
*/
public abstract class SingleVariantXtextBslModuleFix
extends SingleVariantBasicFix<SingleVariantXtextBslModuleFixContext>
{
private BiFunction<SingleVariantXtextBslModuleFixContext, IFixSession, Pair<String, String>> descriptionSupplier;
private boolean isInteractive;
@Override
public Collection<IFixChange> prepareChanges(SingleVariantXtextBslModuleFixContext context, IFixSession session)
{
Module module = session.getModule(context.getTargetModuleUri());
if (module == null)
{
return Collections.emptyList();
}
return prepareChanges(this::applyChanges);
}
@Override
public final FixVariantDescriptor describeChanges(SingleVariantXtextBslModuleFixContext context,
IFixSession session)
{
Pair<String, String> description = descriptionSupplier.apply(context, session);
return new FixVariantDescriptor(description.first, description.second);
}
@Override
public final void onRegistration(FixDescriptor registrationContext)
{
registrationContext.setChangeProcessor(new SingleVariantModuleFixChangeProcessor());
FixConfigurer configurer = new FixConfigurer();
configureFix(configurer);
applyConfiguration(configurer);
}
@Override
public Class<SingleVariantXtextBslModuleFixContext> getRequiredContextType()
{
return SingleVariantXtextBslModuleFixContext.class;
}
/**
* Configures the fix. The developer could provide descreptive/filtering information for the fix here
*
* @param configurer The configurer of the fix. May not be {@code null}
*/
protected void configureFix(FixConfigurer configurer)
{
// Nothing by default
}
/**
* Modification of code to be overriden by clients
*
* @param state the xtext resource, cannot be {@code null}
* @param model xtext bsl module fix model facade, cannot be {@code null}
* @return {@link TextEdit}, can be {@code null}
* @throws BadLocationException
*/
protected abstract TextEdit fixIssue(XtextResource state, IXtextBslModuleFixModel model)
throws BadLocationException;
protected void applyChanges(SingleVariantXtextBslModuleFixContext context, IFixSession session)
{
IssueImpl issue = context.getIssue();
IXtextBslModuleFixModel fixModel = context.getModel(session, isInteractive);
if (fixModel instanceof IXtextInteractiveBslModuleFixModel)
{
IModificationContext modificationContext =
((XtextInteractiveBslModuleFixModel)fixModel).getModificationContext();
ExternalQuickfixModification<EObject> quickFixModification = new ExternalQuickfixModification<>(issue,
EObject.class, element -> fixIssue((IXtextInteractiveBslModuleFixModel)fixModel));
try
{
quickFixModification.apply(modificationContext);
}
catch (Exception e)
{
BslPlugin.log(BslPlugin.createErrorStatus("Error occured when applying quick fix", e)); //$NON-NLS-1$
}
}
else
{
// Nothing at the moment
}
}
private TextEdit fixIssue(IXtextInteractiveBslModuleFixModel fixModel)
{
Issue issue = fixModel.getIssue();
if (issue.getOffset() == null)
{
return null;
}
List<TextEdit> textEdits = new ArrayList<>();
IXtextDocument document = (IXtextDocument)fixModel.getDocument();
document.readOnly(new IUnitOfWork.Void<XtextResource>()
{
@Override
public void process(XtextResource state) throws Exception
{
TextEdit te = fixIssue(state, fixModel);
if (te != null)
{
textEdits.add(te);
}
}
});
return !textEdits.isEmpty() ? textEdits.get(0) : null;
}
private Collection<IFixChange> prepareChanges(ISingleVariantXtextModuleFixChangeDelegate changeDelegate)
{
return Collections.singleton(new SingleVariantModuleFixChange(changeDelegate));
}
/*
* Applies configuration provided by the fix developer
*/
private void applyConfiguration(FixConfigurer configurer)
{
this.descriptionSupplier = configurer.descriptionSupplier;
if (this.descriptionSupplier == null)
{
// Description isn't specified - adding the safety loopback
this.descriptionSupplier = (context, session) -> Pair.newPair(StringUtils.EMPTY, StringUtils.EMPTY);
}
this.isInteractive = configurer.isInteractive;
}
/*
* Single variant fix change unique for the SingleVariantModelBasicFix
*/
private static final class SingleVariantModuleFixChange
implements IFixChange
{
private final ISingleVariantXtextModuleFixChangeDelegate delegate;
SingleVariantModuleFixChange(ISingleVariantXtextModuleFixChangeDelegate delegate)
{
this.delegate = delegate;
}
public void applyFix(SingleVariantXtextBslModuleFixContext context, IFixSession session)
{
delegate.applyFix(context, session);
}
}
/*
* Single variant fix change processor unique for the SingleVariantModelBasicFix
*/
private static final class SingleVariantModuleFixChangeProcessor
implements IFixChangeProcessor<SingleVariantModuleFixChange, SingleVariantXtextBslModuleFixContext>
{
@Override
public void applyFix(SingleVariantModuleFixChange fixChange, SingleVariantXtextBslModuleFixContext context,
IFixSession session)
{
fixChange.applyFix(context, session);
}
@Override
public Class<SingleVariantModuleFixChange> getProcessedFixType()
{
return SingleVariantModuleFixChange.class;
}
}
/**
* Configuration container for the {@link SingleVariantXtextBslModuleFixContext} descendants allowing them to
* specify fix parameters via the pure Java API
*
* @author Alexander Tretyakevich
*/
protected static final class FixConfigurer
{
private BiFunction<SingleVariantXtextBslModuleFixContext, IFixSession, Pair<String, String>>
descriptionSupplier;
private boolean isInteractive = true;
private String description = StringUtils.EMPTY;
private String details = StringUtils.EMPTY;
/**
* Sets the dynamic description supplier for the fix. The description may be formed using the data from
* the {@link SingleVariantXtextBslModuleFixContext}
*
* @param descriptionSupplier The supplier to set. May not be {@code null}
* @return the instance of the fix configurer, never {@code null}
*/
public FixConfigurer description(
BiFunction<SingleVariantXtextBslModuleFixContext, IFixSession, Pair<String, String>> descriptionSupplier)
{
this.descriptionSupplier = descriptionSupplier;
return this;
}
/**
* Sets the static description for the fix
*
* @param description The description to set. May not be {@code null}
* @return the instance of the fix configurer, never {@code null}
*/
public FixConfigurer description(String description)
{
this.description = description;
descriptionSupplier = (context, session) -> Pair.newPair(description, details);
return this;
}
/**
* Sets the static details for the fix
*
* @param description The description to set. May not be {@code null}
* @return the instance of the fix configurer, never {@code null}
*/
public FixConfigurer details(String details)
{
this.details = details;
descriptionSupplier = (context, session) -> Pair.newPair(description, details);
return this;
}
/**
* Sets the modification model type - either interactive (UI) or not
*
* @param isInteractive {@code true} if quick fix supports inbteractive (UI) model, {@code false} otherwise
* @return the instance of the fix configurer, never {@code null}
*/
public FixConfigurer interactive(boolean isInteractive)
{
this.isInteractive = isInteractive;
return this;
}
}
}

View File

@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.validation.Issue.IssueImpl;
import com._1c.g5.v8.dt.core.platform.IDtProject;
import com.e1c.g5.v8.dt.check.qfix.IFixSession;
import com.e1c.g5.v8.dt.check.qfix.components.BasicFixContext;
/**
* Single-variant xtext module quick fix context
*
* @author Vadim Geraskin
*/
public class SingleVariantXtextBslModuleFixContext
extends BasicFixContext
{
private final URI targetModuleUri;
private final IssueImpl issue;
private final IXtextBslModuleFixProvider provider;
/**
* Creates quick fix context
*
* @param targetModuleUri the module {@code URI}, cannot be {@code null}
* @param issue the {@code IssueImpl} instance, cannot be {@code null}
* @param provider the {@code IXtextBslModuleFixProvider} instance, cannot be {@code null}
* @param dtProject the DT project, cannot be {@code null}
*/
public SingleVariantXtextBslModuleFixContext(URI targetModuleUri, IssueImpl issue,
IXtextBslModuleFixProvider provider, IDtProject dtProject)
{
super(dtProject);
this.targetModuleUri = targetModuleUri;
this.issue = issue;
this.provider = provider;
}
/**
* Provides the target module URI
*
* @return the targetModuleUri, never {@code null}
*/
public URI getTargetModuleUri()
{
return targetModuleUri;
}
/**
* Provides the {@code IssueImpl} for quick fix
*
* @return xtext issue, never {@code null}
*/
public IssueImpl getIssue()
{
return issue;
}
/**
* Provides the model {@code IXtextBslModuleFixModel} for quick fix
*
* @param session {@link IFixSession}, cannot be {@code null}
* @param isInteractive {@code true} if quick fix supports inbteractive (UI) model, {@code false} otherwise
* @return model {@code IXtextBslModuleFixModel}, never {@code null}
*/
public IXtextBslModuleFixModel getModel(IFixSession session, boolean isInteractive)
{
return provider.getXtextFixModel(getDtProject(), issue, session, targetModuleUri, isInteractive);
}
}

View File

@ -0,0 +1,54 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.validation.CheckType;
import org.eclipse.xtext.validation.Issue.IssueImpl;
import com._1c.g5.v8.dt.bsl.validation.BslValidationUtil;
import com._1c.g5.v8.dt.validation.marker.IMarkerWrapper;
import com._1c.g5.v8.dt.validation.marker.PlainEObjectMarker;
import com.e1c.g5.v8.dt.check.qfix.IFixContextFactory;
import com.e1c.g5.v8.dt.check.qfix.IFixSession;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* Context factory for {@link SingleVariantXtextBslModuleFixContext}
*
* @author Vadim Geraskin
*/
@Singleton
public class SingleVariantXtextBslModuleFixContextFactory
implements IFixContextFactory<SingleVariantXtextBslModuleFixContext>
{
@Inject
private IXtextBslModuleFixProvider provider;
@Override
public final SingleVariantXtextBslModuleFixContext createContext(IMarkerWrapper marker, IFixSession session)
{
if (marker.getMarker() instanceof PlainEObjectMarker)
{
PlainEObjectMarker plainObjectMarker = (PlainEObjectMarker)marker.getMarker();
URI uri = plainObjectMarker.getURI();
IssueImpl issue = BslValidationUtil.createIssue(plainObjectMarker, CheckType.EXPENSIVE);
return new SingleVariantXtextBslModuleFixContext(uri, issue, provider, session.getDtProject());
}
return null;
}
@Override
public final Class<SingleVariantXtextBslModuleFixContext> getProvidedContextType()
{
return SingleVariantXtextBslModuleFixContext.class;
}
}

View File

@ -0,0 +1,158 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.xtext.validation.Issue;
import com._1c.g5.v8.dt.bsl.model.Module;
import com._1c.g5.v8.dt.bsl.services.BslGrammarAccess;
import com._1c.g5.v8.dt.common.PreferenceUtils;
import com._1c.g5.v8.dt.core.platform.IDtProject;
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.metadata.mdclass.ScriptVariant;
import com.e1c.v8codestyle.internal.bsl.BslPlugin;
import com.google.common.base.Preconditions;
/**
* The xtext module quick fix model
*
* @author Vadim Geraskin
*/
public class XtextBslModuleFixModel
implements IXtextBslModuleFixModel
{
protected final IV8Project v8project;
private final Supplier<Module> moduleSupp;
private final BslGrammarAccess bslGrammar;
private final IResourceLookup resourceLookup;
private final Issue issue;
private IDocument document;
/**
* Creates module quick fix model
*
* @param moduleSupp supplier for {@link Module}, cannot be {@code null}
* @param v8projectManager V8 project manager, cannot be {@code null}
* @param bslGrammar BSL grammar, cannot be {@code null}
* @param resourceLookup resource lookup service, cannot be {@code null}
* @param issue issue, cannot be {@code null}
* @param dtProject {@code IDtProject}, cannot be {@code null}
*/
public XtextBslModuleFixModel(Supplier<Module> moduleSupp, IV8ProjectManager v8projectManager,
BslGrammarAccess bslGrammar, IResourceLookup resourceLookup, Issue issue, IDtProject dtProject)
{
this.moduleSupp = Preconditions.checkNotNull(moduleSupp);
this.bslGrammar = Preconditions.checkNotNull(bslGrammar);
this.resourceLookup = Preconditions.checkNotNull(resourceLookup);
this.issue = Preconditions.checkNotNull(issue);
this.v8project = v8projectManager.getProject(dtProject);
}
@Override
public IDocument getDocument()
{
if (document == null)
{
Module module = moduleSupp.get();
if (module != null)
{
URI uri = EcoreUtil.getURI(module).trimFragment();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(URIConverter.INSTANCE.createInputStream(uri), StandardCharsets.UTF_8)))
{
Stream<String> lines = reader.lines();
String content = lines.collect(Collectors.joining(System.lineSeparator()));
document = new Document(content);
}
catch (IOException e)
{
BslPlugin.log(BslPlugin.createErrorStatus("Unable to read bsl module file", e)); //$NON-NLS-1$
}
}
}
return document;
}
@Override
public IResourceLookup getResourceLookup()
{
return resourceLookup;
}
@Override
public EObject getElement()
{
URI uriToProblem = issue.getUriToProblem();
String fragment = uriToProblem != null ? uriToProblem.fragment() : null;
if (fragment != null)
{
Module module = moduleSupp.get();
return module != null ? module.eResource().getEObject(fragment) : null;
}
return null;
}
@Override
public Issue getIssue()
{
return issue;
}
@Override
public String[] getIssueData()
{
return issue.getData();
}
@Override
public BslGrammarAccess getBslGrammar()
{
return bslGrammar;
}
@Override
public ScriptVariant getScriptVariant()
{
return getScriptVariant(v8project);
}
@Override
public String getLineSeparator()
{
return PreferenceUtils.getLineSeparator(v8project.getProject());
}
protected static ScriptVariant getScriptVariant(IV8Project v8project)
{
if (v8project != null)
{
return v8project.getScriptVariant();
}
return Locale.getDefault().getLanguage().equals(new Locale("ru").getLanguage()) ? ScriptVariant.RUSSIAN //$NON-NLS-1$
: ScriptVariant.ENGLISH;
}
}

View File

@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import java.util.function.Supplier;
import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.ui.editor.IURIEditorOpener;
import org.eclipse.xtext.validation.Issue;
import com._1c.g5.v8.dt.bsl.model.Module;
import com._1c.g5.v8.dt.bsl.services.BslGrammarAccess;
import com._1c.g5.v8.dt.bsl.ui.BslGeneratorMultiLangProposals;
import com._1c.g5.v8.dt.core.platform.IDtProject;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
import com._1c.g5.v8.dt.lcore.ui.texteditor.IndentTextEditorProvider;
import com.e1c.g5.v8.dt.check.qfix.IFixSession;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* Xtext BSl module quick fix provider
*
* @author Vadim Geraskin
*/
@Singleton
public class XtextBslModuleFixProvider
implements IXtextBslModuleFixProvider
{
private final IV8ProjectManager v8projectManager;
private final BslGrammarAccess bslGrammar;
private final IResourceLookup resourceLookup;
private final IndentTextEditorProvider indentProvider;
private final BslGeneratorMultiLangProposals bslGenProp;
private final IURIEditorOpener editorOpener;
@Inject
/**
* @param v8projectManager V8 project manager, cannot be {@code null}
* @param bslGrammar BSl grammar, cannot be {@code null}
* @param resourceLookup resource lookup, cannot be {@code null}
* @param indentProvider indent provider, cannot be {@code null}
* @param bslGenProp BSL multi-language proposals generator, cannot be {@code null}
* @param editorOpener editor opener, cannot be {@code null}
*/
public XtextBslModuleFixProvider(IV8ProjectManager v8projectManager, BslGrammarAccess bslGrammar,
IResourceLookup resourceLookup, IndentTextEditorProvider indentProvider,
BslGeneratorMultiLangProposals bslGenProp, IURIEditorOpener editorOpener)
{
this.v8projectManager = Preconditions.checkNotNull(v8projectManager);
this.bslGrammar = Preconditions.checkNotNull(bslGrammar);
this.resourceLookup = Preconditions.checkNotNull(resourceLookup);
this.indentProvider = Preconditions.checkNotNull(indentProvider);
this.bslGenProp = Preconditions.checkNotNull(bslGenProp);
this.editorOpener = Preconditions.checkNotNull(editorOpener);
}
@Override
public IXtextBslModuleFixModel getXtextFixModel(IDtProject dtProject, Issue issue, IFixSession session,
URI targetModuleUri, boolean isInteractive)
{
Supplier<Module> moduleSupp = () -> session.getModule(targetModuleUri);
if (isInteractive)
{
return new XtextInteractiveBslModuleFixModel(moduleSupp, v8projectManager, bslGrammar, resourceLookup,
indentProvider, bslGenProp, issue, dtProject, editorOpener);
}
return new XtextBslModuleFixModel(moduleSupp, v8projectManager, bslGrammar, resourceLookup, issue, dtProject);
}
}

View File

@ -0,0 +1,186 @@
/*******************************************************************************
* Copyright (C) 2022, 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
*******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix.external;
import java.util.Optional;
import java.util.function.Supplier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.link.LinkedModeUI;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.ui.editor.IURIEditorOpener;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import org.eclipse.xtext.ui.editor.model.edit.IModificationContext;
import org.eclipse.xtext.validation.Issue;
import com._1c.g5.v8.dt.bsl.model.Module;
import com._1c.g5.v8.dt.bsl.services.BslGrammarAccess;
import com._1c.g5.v8.dt.bsl.ui.BslGeneratorMultiLangProposals;
import com._1c.g5.v8.dt.bsl.ui.quickfix.BslQuickFixUtil;
import com._1c.g5.v8.dt.common.PreferenceUtils;
import com._1c.g5.v8.dt.core.platform.IDtProject;
import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
import com._1c.g5.v8.dt.lcore.ui.texteditor.IndentTextEditorProvider;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com.google.common.base.Preconditions;
/**
* The xtext module quick fix model
*
* @author Vadim Geraskin
*/
public class XtextInteractiveBslModuleFixModel
extends XtextBslModuleFixModel
implements IXtextInteractiveBslModuleFixModel
{
private final IndentTextEditorProvider indentProvider;
private final BslGeneratorMultiLangProposals bslGenProp;
private final IModificationContext modificationContext;
private final IXtextDocument document;
private final LinkedModeModel linkedModeModel;
/**
/**
* Creates module quick fix model
*
* @param moduleSupp supplier for {@link Module}, cannot be {@code null}
* @param v8projectManager V8 project manager, cannot be {@code null}
* @param bslGrammar BSL grammar, cannot be {@code null}
* @param resourceLookup resource lookup service, cannot be {@code null}
* @param indentProvider indent provider, cannot be {@code null}
* @param bslGenProp Multi-lang BSL proposals generator, cannot be {@code null}
* @param issue issue, cannot be {@code null}
* @param dtProject {@code IDtProject}, cannot be {@code null}
* @param editorOpener {@code IURIEditorOpener}, cannot be {@code null}
*/
public XtextInteractiveBslModuleFixModel(Supplier<Module> moduleSupp, IV8ProjectManager v8projectManager,
BslGrammarAccess bslGrammar, IResourceLookup resourceLookup, IndentTextEditorProvider indentProvider,
BslGeneratorMultiLangProposals bslGenProp, Issue issue, IDtProject dtProject, IURIEditorOpener editorOpener)
{
super(moduleSupp, v8projectManager, bslGrammar, resourceLookup, issue, dtProject);
this.indentProvider = Preconditions.checkNotNull(indentProvider);
this.bslGenProp = Preconditions.checkNotNull(bslGenProp);
this.modificationContext = new BslIssueModificationContext(issue, Preconditions.checkNotNull(editorOpener));
this.document = modificationContext.getXtextDocument(issue.getUriToProblem());
linkedModeModel = new LinkedModeModel();
boolean isRussian = getScriptVariant(v8project) == ScriptVariant.RUSSIAN;
bslGenProp.setRussianLang(isRussian);
}
@Override
public IXtextDocument getDocument()
{
return document;
}
@Override
public IndentTextEditorProvider getIndentProvider()
{
return indentProvider;
}
@Override
public BslGeneratorMultiLangProposals getBslGeneratorMultiLangProposals()
{
return bslGenProp;
}
@Override
public IModificationContext getModificationContext()
{
return modificationContext;
}
@Override
public IRegion getLineInformationOfOffset(int offset) throws BadLocationException
{
return document.getLineInformationOfOffset(offset);
}
@Override
public String getLineSeparator()
{
return PreferenceUtils.getLineSeparator(getResourceLookup().getProject(document.getResourceURI()));
}
@Override
public Optional<String> getFormatString(EObject eObject) throws BadLocationException
{
INode node = NodeModelUtils.findActualNodeFor(eObject);
if (node == null)
{
return Optional.empty();
}
IRegion lineInformation = getLineInformationOfOffset(node.getOffset());
String indent = computeFormatLine(document, lineInformation).toString();
return Optional.ofNullable(indent);
}
@Override
public LinkedModeModel getLinkedModeModel()
{
return linkedModeModel;
}
@Override
public void enterUiMode()
{
LinkedModeUI ui = new LinkedModeUI(linkedModeModel, BslQuickFixUtil.getTextViewer(modificationContext));
ui.enter();
}
@Override
public void selectAndRevealForLinkedModeModel(int posStart, int length)
{
selectAndRevealForLinkedModeModel(BslQuickFixUtil.getTextViewer(modificationContext), posStart, length);
}
private static StringBuilder computeFormatLine(IDocument doc, IRegion lineInformation) throws BadLocationException
{
String lineContent = doc.get(lineInformation.getOffset(), lineInformation.getLength());
StringBuilder builder = new StringBuilder();
for (int i = 0; i < lineContent.length(); ++i)
{
if (Character.isWhitespace(lineContent.charAt(i)))
{
builder.append(lineContent.charAt(i));
}
else
{
break;
}
}
return builder;
}
private static void selectAndRevealForLinkedModeModel(ITextViewer viewer, int posStart, int length)
{
viewer.getSelectionProvider().addSelectionChangedListener(new ISelectionChangedListener()
{
@Override
public void selectionChanged(SelectionChangedEvent event)
{
viewer.getSelectionProvider().removeSelectionChangedListener(this);
viewer.revealRange(posStart, length);
viewer.setSelectedRange(posStart, length);
}
});
}
}

View File

@ -15,14 +15,19 @@ package com.e1c.v8codestyle.internal.bsl;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.eclipse.xtext.ui.shared.SharedStateModule;
import org.eclipse.xtext.util.Modules2;
import org.osgi.framework.BundleContext;
import com._1c.g5.v8.dt.bsl.BslRuntimeModule;
import com._1c.g5.v8.dt.bsl.model.BslPackage;
import com._1c.g5.wiring.InjectorAwareServiceRegistrator;
import com._1c.g5.wiring.ServiceInitialization;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
import com.e1c.v8codestyle.bsl.qfix.external.BslCheckFixBoostrap;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* The bundle activator to support plug-in life-cycle
@ -127,14 +132,12 @@ public class BslPlugin
plugin = this;
BslPackage.eINSTANCE.eClass();
registrator = new InjectorAwareServiceRegistrator(bundleContext, this::getInjector);
ServiceInitialization.schedule(() -> {
// register services from injector
registrator.service(IModuleStructureProvider.class).registerInjected();
registrator.managedService(BslCheckFixBoostrap.class).activateBeforeRegistration().registerInjected();
});
}
/*
@ -182,7 +185,15 @@ public class BslPlugin
{
try
{
return Guice.createInjector(new ServiceModule(), new ExternalDependenciesModule(this));
Module internalServiceModule = new ServiceModule();
Module bslExternalServicesModule = new com._1c.g5.v8.dt.bsl.ExternalServicesModule(this);
Module sharedStateModule = new SharedStateModule();
Module externalDepModule = new ExternalDependenciesModule(this);
Module bslRuntimeModule = new BslRuntimeModule();
Module mergedModule = Modules2.mixin(internalServiceModule, bslExternalServicesModule, sharedStateModule,
bslRuntimeModule, externalDepModule);
return Guice.createInjector(mergedModule);
}
catch (Exception e)
{

View File

@ -23,12 +23,15 @@ 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;
import com.e1c.g5.v8.dt.check.qfix.IFixRepository;
import com.e1c.g5.v8.dt.check.settings.ICheckRepository;
import com.e1c.v8codestyle.bsl.qfix.external.IXtextBslModuleFixProvider;
import com.e1c.v8codestyle.bsl.qfix.external.XtextBslModuleFixProvider;
/**
* The external dependencies for plugin
*
* @author Dmitriy Marmyshev
*
*/
class ExternalDependenciesModule
extends AbstractServiceAwareModule
@ -49,6 +52,9 @@ class ExternalDependenciesModule
bind(IQualifiedNameConverter.class).toService();
bind(IBslModuleContextDefService.class).toService();
bind(IQualifiedNameProvider.class).toService();
}
bind(ICheckRepository.class).toService();
bind(IFixRepository.class).toService();
bind(IXtextBslModuleFixProvider.class).to(XtextBslModuleFixProvider.class);
}
}

View File

@ -21,11 +21,13 @@
<property name="ignorePattern" value="^ *\* *[^ ]+$|(\s+\/\/\$NON-NLS-\d+\$)+$"/>
</module>
<module name="SuppressWithPlainTextCommentFilter">
<property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
<property name="checkFormat" value="$1"/>
</module>
<module name="TreeWalker">
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="checkstyle:off" />
<property name="onCommentFormat" value="checkstyle:on" />
</module>
<module name="SuppressWarningsHolder" />
<!-- imports -->