You've already forked v8-code-style
							
							
				mirror of
				https://github.com/1C-Company/v8-code-style.git
				synced 2025-10-31 16:37:46 +02:00 
			
		
		
		
	Проверки и квик-фиксы для BSL-модулей (#955)
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
| @@ -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)" | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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 | ||||
|     } | ||||
| } | ||||
| @@ -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 | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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$ | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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. | ||||
| @@ -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После применения исправления сохраните изменения в редакторе. | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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}" не определена | ||||
|   | ||||
| @@ -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 | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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(); | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @@ -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) | ||||
|         { | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 --> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user