From 895b56dade9b346a060e7242d0c12628f5fd45d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Fri, 27 Feb 2026 21:12:52 +0100 Subject: [PATCH 01/23] feat: migrate check.core Xtend files to Java 21 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert all 8 Xtend source files in com.avaloq.tools.ddk.check.core to plain Java 21, eliminating the org.eclipse.xtend2.lib dependency: - CheckGeneratorConfig: @Accessors → manual getter/setter - CheckTypeComputer: override → @Override, typeof → .class - CheckGeneratorNaming: static utilities, explicit types - CheckScopeProvider: dispatch methods → if-instanceof dispatcher - CheckGeneratorExtensions: 4 dispatch families, switch expressions - CheckFormatter: dispatch _format methods, extension→explicit calls - CheckGenerator: template expressions → StringBuilder (no StringConcatenation) - CheckJvmModelInferrer: extension fields, JvmTypesBuilder lambdas Co-Authored-By: Claude Opus 4.6 --- .../check/compiler/CheckGeneratorConfig.java | 32 + .../check/compiler/CheckGeneratorConfig.xtend | 27 - .../ddk/check/formatting2/CheckFormatter.java | 623 +++++++++++++++ .../check/formatting2/CheckFormatter.xtend | 301 ------- .../ddk/check/generator/CheckGenerator.java | 276 +++++++ .../ddk/check/generator/CheckGenerator.xtend | 215 ----- .../generator/CheckGeneratorExtensions.java | 327 ++++++++ .../generator/CheckGeneratorExtensions.xtend | 267 ------- .../check/generator/CheckGeneratorNaming.java | 179 +++++ .../generator/CheckGeneratorNaming.xtend | 174 ---- .../check/jvmmodel/CheckJvmModelInferrer.java | 741 ++++++++++++++++++ .../jvmmodel/CheckJvmModelInferrer.xtend | 646 --------------- .../ddk/check/scoping/CheckScopeProvider.java | 224 ++++++ .../check/scoping/CheckScopeProvider.xtend | 178 ----- .../ddk/check/typing/CheckTypeComputer.java | 60 ++ .../ddk/check/typing/CheckTypeComputer.xtend | 60 -- 16 files changed, 2462 insertions(+), 1868 deletions(-) create mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.java delete mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.xtend create mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.java delete mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.xtend create mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java delete mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.xtend create mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java delete mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.xtend create mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java delete mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.xtend create mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java delete mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.xtend create mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.java delete mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.xtend create mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.java delete mode 100644 com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.xtend diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.java new file mode 100644 index 0000000000..a82f81c2a0 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.compiler; + +import org.eclipse.xtext.xbase.compiler.GeneratorConfig; + +public class CheckGeneratorConfig extends GeneratorConfig { + + private final String GENERATE_DOCUMENTATION_PROPERTY = "com.avaloq.tools.ddk.check.GenerateDocumentationForAllChecks"; + + private boolean generateLanguageInternalChecks = false; + + public boolean isGenerateLanguageInternalChecks() { + return generateLanguageInternalChecks; + } + + public void setGenerateLanguageInternalChecks(boolean generateLanguageInternalChecks) { + this.generateLanguageInternalChecks = generateLanguageInternalChecks; + } + + public boolean doGenerateDocumentationForAllChecks() { + return Boolean.parseBoolean(System.getProperty(GENERATE_DOCUMENTATION_PROPERTY)); + } +} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.xtend deleted file mode 100644 index 321ecdd7d9..0000000000 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.xtend +++ /dev/null @@ -1,27 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.check.compiler - -import org.eclipse.xtext.xbase.compiler.GeneratorConfig -import org.eclipse.xtend.lib.annotations.Accessors - -class CheckGeneratorConfig extends GeneratorConfig { - - val String GENERATE_DOCUMENTATION_PROPERTY = "com.avaloq.tools.ddk.check.GenerateDocumentationForAllChecks" - - @Accessors - boolean generateLanguageInternalChecks = false - - def doGenerateDocumentationForAllChecks() { - return Boolean.parseBoolean(System.getProperty(GENERATE_DOCUMENTATION_PROPERTY)); - } -} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.java new file mode 100644 index 0000000000..8edcaa6d70 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.java @@ -0,0 +1,623 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.formatting2; + +import java.util.Arrays; + +import com.avaloq.tools.ddk.check.check.Category; +import com.avaloq.tools.ddk.check.check.Check; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.Context; +import com.avaloq.tools.ddk.check.check.ContextVariable; +import com.avaloq.tools.ddk.check.check.FormalParameter; +import com.avaloq.tools.ddk.check.check.Implementation; +import com.avaloq.tools.ddk.check.check.Member; +import com.avaloq.tools.ddk.check.check.SeverityRange; +import com.avaloq.tools.ddk.check.check.XGuardExpression; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import com.avaloq.tools.ddk.check.services.CheckGrammarAccess; +import com.google.inject.Inject; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.common.types.JvmFormalParameter; +import org.eclipse.xtext.common.types.JvmGenericArrayTypeReference; +import org.eclipse.xtext.common.types.JvmParameterizedTypeReference; +import org.eclipse.xtext.common.types.JvmTypeConstraint; +import org.eclipse.xtext.common.types.JvmTypeParameter; +import org.eclipse.xtext.common.types.JvmWildcardTypeReference; +import org.eclipse.xtext.formatting2.IFormattableDocument; +import org.eclipse.xtext.formatting2.IHiddenRegionFormatter; +import org.eclipse.xtext.formatting2.regionaccess.IEObjectRegion; +import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.xbase.XAssignment; +import org.eclipse.xtext.xbase.XBasicForLoopExpression; +import org.eclipse.xtext.xbase.XBinaryOperation; +import org.eclipse.xtext.xbase.XBlockExpression; +import org.eclipse.xtext.xbase.XCastedExpression; +import org.eclipse.xtext.xbase.XClosure; +import org.eclipse.xtext.xbase.XCollectionLiteral; +import org.eclipse.xtext.xbase.XConstructorCall; +import org.eclipse.xtext.xbase.XDoWhileExpression; +import org.eclipse.xtext.xbase.XExpression; +import org.eclipse.xtext.xbase.XFeatureCall; +import org.eclipse.xtext.xbase.XForLoopExpression; +import org.eclipse.xtext.xbase.XIfExpression; +import org.eclipse.xtext.xbase.XInstanceOfExpression; +import org.eclipse.xtext.xbase.XListLiteral; +import org.eclipse.xtext.xbase.XMemberFeatureCall; +import org.eclipse.xtext.xbase.XPostfixOperation; +import org.eclipse.xtext.xbase.XReturnExpression; +import org.eclipse.xtext.xbase.XSwitchExpression; +import org.eclipse.xtext.xbase.XSynchronizedExpression; +import org.eclipse.xtext.xbase.XThrowExpression; +import org.eclipse.xtext.xbase.XTryCatchFinallyExpression; +import org.eclipse.xtext.xbase.XTypeLiteral; +import org.eclipse.xtext.xbase.XUnaryOperation; +import org.eclipse.xtext.xbase.XVariableDeclaration; +import org.eclipse.xtext.xbase.XWhileExpression; +import org.eclipse.xtext.xbase.annotations.formatting2.XbaseWithAnnotationsFormatter; +import org.eclipse.xtext.xbase.annotations.xAnnotations.XAnnotation; +import org.eclipse.xtext.xbase.lib.XbaseGenerated; +import org.eclipse.xtext.xtype.XFunctionTypeRef; +import org.eclipse.xtext.xtype.XImportDeclaration; +import org.eclipse.xtext.xtype.XImportSection; + +public class CheckFormatter extends XbaseWithAnnotationsFormatter { + + @Inject + private CheckGrammarAccess _checkGrammarAccess; + + /** + * Common formatting for curly brackets that are not handled by the parent formatter. + * + * @param semanticElement + * the element containing '{' and '}' keywords. + * @param document + * the formattable document. + */ + private void formatCurlyBracket(EObject semanticElement, IFormattableDocument document) { + // low priority so that it can be overridden by other custom formatting rules. + final ISemanticRegion open = regionFor(semanticElement).keyword("{"); + final ISemanticRegion close = regionFor(semanticElement).keyword("}"); + document.interior(open, close, (IHiddenRegionFormatter it) -> { + it.lowPriority(); + it.indent(); + }); + document.append(open, (IHiddenRegionFormatter it) -> { + it.lowPriority(); + it.newLine(); + }); + document.prepend(close, (IHiddenRegionFormatter it) -> { + it.lowPriority(); + it.newLine(); + }); + } + + /** + * Global formatting to be applied across the whole source. + * + * @param requestRoot + * the top level check catalog element. + * @param document + * the formattable document. + */ + private void globalFormatting(IEObjectRegion requestRoot, IFormattableDocument document) { + // autowrap everywhere. default to one-space between semantic regions. + // low priority so that it can be overridden by other custom formatting rules. + boolean firstRegion = true; + for (ISemanticRegion region : requestRoot.getAllSemanticRegions()) { + if (firstRegion) { + document.prepend(region, (IHiddenRegionFormatter it) -> { + it.lowPriority(); + it.autowrap(132); + }); + firstRegion = false; + } else { + document.prepend(region, (IHiddenRegionFormatter it) -> { + it.lowPriority(); + it.oneSpace(); + it.autowrap(132); + }); + } + } + } + + protected void _format(CheckCatalog checkcatalog, IFormattableDocument document) { + document.prepend(checkcatalog, (IHiddenRegionFormatter it) -> { + it.noSpace(); + it.setNewLines(0); + }); + document.append(checkcatalog, (IHiddenRegionFormatter it) -> { + it.noSpace(); + it.setNewLines(0, 0, 1); + }); + final ISemanticRegion finalKw = regionFor(checkcatalog).keyword("final"); + final ISemanticRegion catalog = regionFor(checkcatalog).keyword("catalog"); + if (finalKw != null) { + document.prepend(finalKw, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 2, 2); + }); + } else { + document.prepend(catalog, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 1, 2); + }); + } + final ISemanticRegion forKw = regionFor(checkcatalog).keyword("for"); + document.prepend(forKw, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 1, 2); + }); + formatCurlyBracket(checkcatalog, document); + + // Generated model traversal + this.format(checkcatalog.getImports(), document); + for (Category categories : checkcatalog.getCategories()) { + this.format(categories, document); + } + for (Implementation implementations : checkcatalog.getImplementations()) { + this.format(implementations, document); + } + for (Check checks : checkcatalog.getChecks()) { + this.format(checks, document); + } + for (Member members : checkcatalog.getMembers()) { + this.format(members, document); + } + + // ADDED: only fill in the gaps after any high priority formatting has been applied. + IEObjectRegion rootRegion = getTextRegionAccess().regionForRootEObject(); + if (rootRegion != null) { + globalFormatting(rootRegion, document); + } + } + + @Override + protected void _format(XImportSection ximportsection, IFormattableDocument document) { + // Generated model traversal + for (XImportDeclaration importDeclarations : ximportsection.getImportDeclarations()) { + // ADDED: formatting added before each import + document.prepend(importDeclarations, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 1, 2); + }); + + this.format(importDeclarations, document); + } + } + + protected void _format(Category category, IFormattableDocument document) { + document.prepend(category, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 2, 2); + }); + formatCurlyBracket(category, document); + + // Generated model traversal + for (Check checks : category.getChecks()) { + this.format(checks, document); + } + } + + protected void _format(Check check, IFormattableDocument document) { + document.prepend(check, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 2, 2); + }); + final ISemanticRegion open = regionFor(check).keyword("("); + final ISemanticRegion close = regionFor(check).keyword(")"); + document.interior(open, close, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); // High priority to override formatting from adjacent regions and parent formatter. + final ISemanticRegion message = regionFor(check).keyword("message"); + document.prepend(message, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 1, 2); + }); + formatCurlyBracket(check, document); + + // Generated model traversal + this.format(check.getSeverityRange(), document); + for (FormalParameter formalParameters : check.getFormalParameters()) { + // ADDED: formatting added around comma. + // High priority to override formatting from adjacent regions and parent formatter. + final ISemanticRegion comma = immediatelyFollowing(formalParameters).keyword(","); + document.prepend(comma, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + document.append(comma, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.setNewLines(0, 0, 1); + }); + + this.format(formalParameters, document); + } + for (Context contexts : check.getContexts()) { + this.format(contexts, document); + } + } + + protected void _format(SeverityRange severityrange, IFormattableDocument document) { + final ISemanticRegion range = regionFor(severityrange).keyword("SeverityRange"); + document.surround(range, (IHiddenRegionFormatter it) -> { + it.noSpace(); + }); + final ISemanticRegion open = regionFor(severityrange).keyword("("); + document.append(open, (IHiddenRegionFormatter it) -> { + it.noSpace(); + }); + final ISemanticRegion close = regionFor(severityrange).keyword(")"); + document.prepend(close, (IHiddenRegionFormatter it) -> { + it.noSpace(); + }); + document.append(close, (IHiddenRegionFormatter it) -> { + it.newLine(); + }); + } + + protected void _format(Member member, IFormattableDocument document) { + // Generated model traversal + for (XAnnotation annotations : member.getAnnotations()) { + this.format(annotations, document); + } + this.format(member.getType(), document); + this.format(member.getValue(), document); + } + + protected void _format(Implementation implementation, IFormattableDocument document) { + document.prepend(implementation, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 2, 2); + }); + + // Generated model traversal + this.format(implementation.getContext(), document); + } + + protected void _format(FormalParameter formalparameter, IFormattableDocument document) { + // Generated model traversal + this.format(formalparameter.getType(), document); + this.format(formalparameter.getRight(), document); + } + + protected void _format(XUnaryOperation xunaryoperation, IFormattableDocument document) { + // Generated model traversal + this.format(xunaryoperation.getOperand(), document); + } + + protected void _format(XListLiteral xlistliteral, IFormattableDocument document) { + // Generated model traversal + for (XExpression elements : xlistliteral.getElements()) { + this.format(elements, document); + } + } + + protected void _format(Context context, IFormattableDocument document) { + document.surround(context, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 2, 2); + }); + + // Generated model traversal + this.format(context.getContextVariable(), document); + this.format(context.getConstraint(), document); + } + + protected void _format(ContextVariable contextvariable, IFormattableDocument document) { + // Generated model traversal + this.format(contextvariable.getType(), document); + } + + protected void _format(XGuardExpression xguardexpression, IFormattableDocument document) { + document.prepend(xguardexpression, (IHiddenRegionFormatter it) -> { + it.setNewLines(1, 2, 2); + }); + + // Generated model traversal + this.format(xguardexpression.getGuard(), document); + } + + protected void _format(XIssueExpression xissueexpression, IFormattableDocument document) { + // High priority to override formatting from adjacent regions and parent formatter. + document.prepend(xissueexpression, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.setNewLines(1, 2, 2); + }); + _checkGrammarAccess.getXIssueExpressionAccess().findKeywords("#").forEach((Keyword kw) -> { + final ISemanticRegion hash = regionFor(xissueexpression).keyword(kw); + document.surround(hash, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + }); + final ISemanticRegion openSquare = regionFor(xissueexpression).keyword("["); + document.surround(openSquare, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + final ISemanticRegion closeSquare = regionFor(xissueexpression).keyword("]"); + document.prepend(closeSquare, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + _checkGrammarAccess.getXIssueExpressionAccess().findKeywords("(").forEach((Keyword kw) -> { + final ISemanticRegion open = regionFor(xissueexpression).keyword(kw); + document.append(open, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + }); + _checkGrammarAccess.getXIssueExpressionAccess().findKeywords(")").forEach((Keyword kw) -> { + final ISemanticRegion close = regionFor(xissueexpression).keyword(kw); + document.prepend(close, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + }); + + // Generated model traversal + this.format(xissueexpression.getMarkerObject(), document); + this.format(xissueexpression.getMarkerIndex(), document); + this.format(xissueexpression.getMessage(), document); + for (XExpression messageParameters : xissueexpression.getMessageParameters()) { + // ADDED: formatting added around comma + final ISemanticRegion comma = immediatelyFollowing(messageParameters).keyword(","); + document.prepend(comma, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + document.append(comma, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.oneSpace(); + }); + + this.format(messageParameters, document); + } + for (XExpression issueData : xissueexpression.getIssueData()) { + // ADDED: formatting added around comma + final ISemanticRegion comma = immediatelyFollowing(issueData).keyword(","); + document.prepend(comma, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + document.append(comma, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.oneSpace(); + }); + + this.format(issueData, document); + } + } + + @Override + protected void _format(XIfExpression xifexpression, IFormattableDocument document) { + // High priority to override formatting from adjacent regions and parent formatter. + document.prepend(xifexpression, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.setNewLines(1, 1, 2); + }); + final ISemanticRegion open = regionFor(xifexpression).keyword("("); + final ISemanticRegion close = regionFor(xifexpression).keyword(")"); + document.prepend(open, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.oneSpace(); + }); + document.append(open, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + document.prepend(close, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + document.append(close, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.setNewLines(0); + it.oneSpace(); + }); + final ISemanticRegion elseKw = regionFor(xifexpression).keyword("else"); + document.surround(elseKw, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.setNewLines(0); + it.oneSpace(); + }); + + // defer to super class for model traversal + super._format(xifexpression, document); + } + + @Override + protected void _format(XMemberFeatureCall xfeaturecall, IFormattableDocument document) { + // set no space after '::' in CheckUtil::hasQualifiedName(..., and also not after plain "." or "?." + // High priority to override formatting from adjacent regions and parent formatter. + _checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords(".").forEach((Keyword kw) -> { + final ISemanticRegion dot = regionFor(xfeaturecall).keyword(kw); + document.append(dot, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + }); + _checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords("?.").forEach((Keyword kw) -> { + final ISemanticRegion queryDot = regionFor(xfeaturecall).keyword(kw); + document.append(queryDot, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + }); + _checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords("::").forEach((Keyword kw) -> { + final ISemanticRegion colonColon = regionFor(xfeaturecall).keyword(kw); + document.append(colonColon, (IHiddenRegionFormatter it) -> { + it.highPriority(); + it.noSpace(); + }); + }); + + // defer to super class for model traversal + super._format(xfeaturecall, document); + } + + @Override + @XbaseGenerated + public void format(Object xlistliteral, IFormattableDocument document) { + if (xlistliteral instanceof JvmTypeParameter) { + _format((JvmTypeParameter) xlistliteral, document); + return; + } else if (xlistliteral instanceof JvmFormalParameter) { + _format((JvmFormalParameter) xlistliteral, document); + return; + } else if (xlistliteral instanceof XtextResource) { + _format((XtextResource) xlistliteral, document); + return; + } else if (xlistliteral instanceof XAssignment) { + _format((XAssignment) xlistliteral, document); + return; + } else if (xlistliteral instanceof XBinaryOperation) { + _format((XBinaryOperation) xlistliteral, document); + return; + } else if (xlistliteral instanceof XDoWhileExpression) { + _format((XDoWhileExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XFeatureCall) { + _format((XFeatureCall) xlistliteral, document); + return; + } else if (xlistliteral instanceof XListLiteral) { + _format((XListLiteral) xlistliteral, document); + return; + } else if (xlistliteral instanceof XMemberFeatureCall) { + _format((XMemberFeatureCall) xlistliteral, document); + return; + } else if (xlistliteral instanceof XPostfixOperation) { + _format((XPostfixOperation) xlistliteral, document); + return; + } else if (xlistliteral instanceof XUnaryOperation) { + _format((XUnaryOperation) xlistliteral, document); + return; + } else if (xlistliteral instanceof XWhileExpression) { + _format((XWhileExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XFunctionTypeRef) { + _format((XFunctionTypeRef) xlistliteral, document); + return; + } else if (xlistliteral instanceof Category) { + _format((Category) xlistliteral, document); + return; + } else if (xlistliteral instanceof Check) { + _format((Check) xlistliteral, document); + return; + } else if (xlistliteral instanceof CheckCatalog) { + _format((CheckCatalog) xlistliteral, document); + return; + } else if (xlistliteral instanceof Context) { + _format((Context) xlistliteral, document); + return; + } else if (xlistliteral instanceof Implementation) { + _format((Implementation) xlistliteral, document); + return; + } else if (xlistliteral instanceof Member) { + _format((Member) xlistliteral, document); + return; + } else if (xlistliteral instanceof XGuardExpression) { + _format((XGuardExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XIssueExpression) { + _format((XIssueExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof JvmGenericArrayTypeReference) { + _format((JvmGenericArrayTypeReference) xlistliteral, document); + return; + } else if (xlistliteral instanceof JvmParameterizedTypeReference) { + _format((JvmParameterizedTypeReference) xlistliteral, document); + return; + } else if (xlistliteral instanceof JvmWildcardTypeReference) { + _format((JvmWildcardTypeReference) xlistliteral, document); + return; + } else if (xlistliteral instanceof XBasicForLoopExpression) { + _format((XBasicForLoopExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XBlockExpression) { + _format((XBlockExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XCastedExpression) { + _format((XCastedExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XClosure) { + _format((XClosure) xlistliteral, document); + return; + } else if (xlistliteral instanceof XCollectionLiteral) { + _format((XCollectionLiteral) xlistliteral, document); + return; + } else if (xlistliteral instanceof XConstructorCall) { + _format((XConstructorCall) xlistliteral, document); + return; + } else if (xlistliteral instanceof XForLoopExpression) { + _format((XForLoopExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XIfExpression) { + _format((XIfExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XInstanceOfExpression) { + _format((XInstanceOfExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XReturnExpression) { + _format((XReturnExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XSwitchExpression) { + _format((XSwitchExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XSynchronizedExpression) { + _format((XSynchronizedExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XThrowExpression) { + _format((XThrowExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XTryCatchFinallyExpression) { + _format((XTryCatchFinallyExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XTypeLiteral) { + _format((XTypeLiteral) xlistliteral, document); + return; + } else if (xlistliteral instanceof XVariableDeclaration) { + _format((XVariableDeclaration) xlistliteral, document); + return; + } else if (xlistliteral instanceof XAnnotation) { + _format((XAnnotation) xlistliteral, document); + return; + } else if (xlistliteral instanceof ContextVariable) { + _format((ContextVariable) xlistliteral, document); + return; + } else if (xlistliteral instanceof FormalParameter) { + _format((FormalParameter) xlistliteral, document); + return; + } else if (xlistliteral instanceof SeverityRange) { + _format((SeverityRange) xlistliteral, document); + return; + } else if (xlistliteral instanceof JvmTypeConstraint) { + _format((JvmTypeConstraint) xlistliteral, document); + return; + } else if (xlistliteral instanceof XExpression) { + _format((XExpression) xlistliteral, document); + return; + } else if (xlistliteral instanceof XImportDeclaration) { + _format((XImportDeclaration) xlistliteral, document); + return; + } else if (xlistliteral instanceof XImportSection) { + _format((XImportSection) xlistliteral, document); + return; + } else if (xlistliteral instanceof EObject) { + _format((EObject) xlistliteral, document); + return; + } else if (xlistliteral == null) { + _format((Void) null, document); + return; + } else if (xlistliteral != null) { + _format(xlistliteral, document); + return; + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(xlistliteral, document).toString()); + } + } +} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.xtend deleted file mode 100644 index 4c6c39eeab..0000000000 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.xtend +++ /dev/null @@ -1,301 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.formatting2; - -import com.avaloq.tools.ddk.check.check.Category -import com.avaloq.tools.ddk.check.check.Check -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.check.Context -import com.avaloq.tools.ddk.check.check.ContextVariable -import com.avaloq.tools.ddk.check.check.FormalParameter -import com.avaloq.tools.ddk.check.check.Implementation -import com.avaloq.tools.ddk.check.check.Member -import com.avaloq.tools.ddk.check.check.SeverityRange -import com.avaloq.tools.ddk.check.check.XGuardExpression -import com.avaloq.tools.ddk.check.check.XIssueExpression -import com.avaloq.tools.ddk.check.services.CheckGrammarAccess -import com.google.inject.Inject -import org.eclipse.emf.ecore.EObject -import org.eclipse.xtext.formatting2.IFormattableDocument -import org.eclipse.xtext.formatting2.regionaccess.IEObjectRegion -import org.eclipse.xtext.xbase.XExpression -import org.eclipse.xtext.xbase.XIfExpression -import org.eclipse.xtext.xbase.XListLiteral -import org.eclipse.xtext.xbase.XMemberFeatureCall -import org.eclipse.xtext.xbase.XUnaryOperation -import org.eclipse.xtext.xbase.annotations.formatting2.XbaseWithAnnotationsFormatter -import org.eclipse.xtext.xbase.annotations.xAnnotations.XAnnotation -import org.eclipse.xtext.xtype.XImportDeclaration -import org.eclipse.xtext.xtype.XImportSection - -class CheckFormatter extends XbaseWithAnnotationsFormatter { - - @Inject extension CheckGrammarAccess - - /** - * Common formatting for curly brackets that are not handled by the parent formatter. - * - * @param semanticElement - * the element containing '{' and '}' keywords. - * @param document - * the formattable document. - */ - def private void formatCurlyBracket(EObject semanticElement, extension IFormattableDocument document) { - // low priority so that it can be overridden by other custom formatting rules. - val open = semanticElement.regionFor.keyword('{') - val close = semanticElement.regionFor.keyword('}') - interior(open, close)[lowPriority indent] - append(open)[lowPriority newLine] - prepend(close)[lowPriority newLine] - } - - /** - * Global formatting to be applied across the whole source. - * - * @param checkcatalog - * the top level check catalog element. - * @param document - * the formattable document. - */ - def private void globalFormatting(IEObjectRegion requestRoot, extension IFormattableDocument document) { - // autowrap everywhere. default to one-space between semantic regions. - // low priority so that it can be overridden by other custom formatting rules. - var firstRegion = true - for(region : requestRoot.allSemanticRegions) { - if (firstRegion) { - region.prepend[lowPriority autowrap(132)] - firstRegion = false - } else { - region.prepend[lowPriority oneSpace autowrap(132)] - } - } - } - - def dispatch void format(CheckCatalog checkcatalog, extension IFormattableDocument document) { - prepend(checkcatalog)[noSpace newLines=0] - append(checkcatalog)[noSpace setNewLines(0, 0, 1)] - val finalKw = checkcatalog.regionFor.keyword('final') - val catalog = checkcatalog.regionFor.keyword('catalog') - if (finalKw !== null) { - prepend(finalKw)[setNewLines(1, 2, 2)] - } else { - prepend(catalog)[setNewLines(1, 1, 2)] - } - val forKw = checkcatalog.regionFor.keyword('for') - prepend(forKw)[setNewLines(1, 1, 2)] - formatCurlyBracket(checkcatalog, document) - - // Generated model traversal - format(checkcatalog.getImports(), document); - for (Category categories : checkcatalog.getCategories()) { - format(categories, document); - } - for (Implementation implementations : checkcatalog.getImplementations()) { - format(implementations, document); - } - for (Check checks : checkcatalog.getChecks()) { - format(checks, document); - } - for (Member members : checkcatalog.getMembers()) { - format(members, document); - } - - // ADDED: only fill in the gaps after any high priority formatting has been applied. - textRegionAccess.regionForRootEObject?.globalFormatting(document) - } - - override dispatch void format(XImportSection ximportsection, extension IFormattableDocument document) { - // Generated model traversal - for (XImportDeclaration importDeclarations : ximportsection.getImportDeclarations()) { - // ADDED: formatting added before each import - prepend(importDeclarations)[setNewLines(1, 1, 2)] - - format(importDeclarations, document); - } - } - - def dispatch void format(Category category, extension IFormattableDocument document) { - prepend(category)[setNewLines(1, 2, 2)] - formatCurlyBracket(category, document) - - // Generated model traversal - for (Check checks : category.getChecks()) { - format(checks, document); - } - } - - def dispatch void format(Check check, extension IFormattableDocument document) { - prepend(check)[setNewLines(1, 2, 2)] - val open = check.regionFor.keyword('(') - val close = check.regionFor.keyword(')') - interior(open, close)[highPriority noSpace] // High priority to override formatting from adjacent regions and parent formatter. - val message = check.regionFor.keyword('message') - prepend(message)[setNewLines(1, 1, 2)] - formatCurlyBracket(check, document) - - // Generated model traversal - format(check.getSeverityRange(), document); - for (FormalParameter formalParameters : check.getFormalParameters()) { - // ADDED: formatting added around comma. - // High priority to override formatting from adjacent regions and parent formatter. - val comma = immediatelyFollowing(formalParameters).keyword(',') - prepend(comma)[highPriority noSpace] - append(comma)[highPriority setNewLines(0, 0, 1)] - - format(formalParameters, document); - } - for (Context contexts : check.getContexts()) { - format(contexts, document); - } - } - - def dispatch void format(SeverityRange severityrange, extension IFormattableDocument document) { - val range = severityrange.regionFor.keyword('SeverityRange') - surround(range)[noSpace] - val open = severityrange.regionFor.keyword('(') - append(open)[noSpace] - val close = severityrange.regionFor.keyword(')') - prepend(close)[noSpace] - append(close)[newLine] - } - - def dispatch void format(Member member, extension IFormattableDocument document) { - // Generated model traversal - for (XAnnotation annotations : member.getAnnotations()) { - format(annotations, document); - } - format(member.getType(), document); - format(member.getValue(), document); - } - - def dispatch void format(Implementation implementation, extension IFormattableDocument document) { - prepend(implementation)[setNewLines(1, 2, 2)] - - // Generated model traversal - format(implementation.getContext(), document); - } - - def dispatch void format(FormalParameter formalparameter, extension IFormattableDocument document) { - // Generated model traversal - format(formalparameter.getType(), document); - format(formalparameter.getRight(), document); - } - - def dispatch void format(XUnaryOperation xunaryoperation, extension IFormattableDocument document) { - // Generated model traversal - format(xunaryoperation.getOperand(), document); - } - - def dispatch void format(XListLiteral xlistliteral, extension IFormattableDocument document) { - // Generated model traversal - for (XExpression elements : xlistliteral.getElements()) { - format(elements, document); - } - } - - def dispatch void format(Context context, extension IFormattableDocument document) { - surround(context)[setNewLines(1, 2, 2)] - - // Generated model traversal - format(context.getContextVariable(), document); - format(context.getConstraint(), document); - } - - def dispatch void format(ContextVariable contextvariable, extension IFormattableDocument document) { - // Generated model traversal - format(contextvariable.getType(), document); - } - - def dispatch void format(XGuardExpression xguardexpression, extension IFormattableDocument document) { - prepend(xguardexpression)[setNewLines(1, 2, 2)] - - // Generated model traversal - format(xguardexpression.getGuard(), document); - } - - def dispatch void format(XIssueExpression xissueexpression, extension IFormattableDocument document) { - // High priority to override formatting from adjacent regions and parent formatter. - prepend(xissueexpression)[highPriority setNewLines(1, 2, 2)] - XIssueExpressionAccess.findKeywords('#').forEach[ - val hash = xissueexpression.regionFor.keyword(it) - surround(hash)[highPriority noSpace] - ] - val openSquare = xissueexpression.regionFor.keyword('[') - surround(openSquare)[highPriority noSpace] - val closeSquare = xissueexpression.regionFor.keyword(']') - prepend(closeSquare)[highPriority noSpace] - XIssueExpressionAccess.findKeywords('(').forEach[ - val open = xissueexpression.regionFor.keyword(it) - append(open)[highPriority noSpace] - ] - XIssueExpressionAccess.findKeywords(')').forEach[ - val close = xissueexpression.regionFor.keyword(it) - prepend(close)[highPriority noSpace] - ] - - // Generated model traversal - format(xissueexpression.getMarkerObject(), document); - format(xissueexpression.getMarkerIndex(), document); - format(xissueexpression.getMessage(), document); - for (XExpression messageParameters : xissueexpression.getMessageParameters()) { - // ADDED: formatting added around comma - val comma = immediatelyFollowing(messageParameters).keyword(',') - prepend(comma)[highPriority noSpace] - append(comma)[highPriority oneSpace] - - format(messageParameters, document); - } - for (XExpression issueData : xissueexpression.getIssueData()) { - // ADDED: formatting added around comma - val comma = immediatelyFollowing(issueData).keyword(',') - prepend(comma)[highPriority noSpace] - append(comma)[highPriority oneSpace] - - format(issueData, document); - } - } - - override dispatch void format(XIfExpression xifexpression, extension IFormattableDocument document) { - // High priority to override formatting from adjacent regions and parent formatter. - prepend(xifexpression)[highPriority setNewLines(1, 1, 2)] - val open = xifexpression.regionFor.keyword('(') - val close = xifexpression.regionFor.keyword(')') - prepend(open)[highPriority oneSpace] - append(open)[highPriority noSpace] - prepend(close)[highPriority noSpace] - append(close)[highPriority newLines=0 oneSpace] - val elseKw = xifexpression.regionFor.keyword('else') - surround(elseKw)[highPriority newLines=0 oneSpace] - - // defer to super class for model traversal - super._format(xifexpression, document) - } - - override dispatch void format(XMemberFeatureCall xfeaturecall, extension IFormattableDocument document) { - // set no space after '::' in CheckUtil::hasQualifiedName(..., and also not after plain "." or "?." - // High priority to override formatting from adjacent regions and parent formatter. - XMemberFeatureCallAccess.findKeywords('.').forEach[ - val dot = xfeaturecall.regionFor.keyword(it) - append(dot)[highPriority noSpace] - ] - XMemberFeatureCallAccess.findKeywords('?.').forEach[ - val queryDot = xfeaturecall.regionFor.keyword(it) - append(queryDot)[highPriority noSpace] - ] - XMemberFeatureCallAccess.findKeywords('::').forEach[ - val colonColon = xfeaturecall.regionFor.keyword(it) - append(colonColon)[highPriority noSpace] - ] - - // defer to super class for model traversal - super._format(xfeaturecall, document) - } -} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java new file mode 100644 index 0000000000..ff0ebe09eb --- /dev/null +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java @@ -0,0 +1,276 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.generator; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.avaloq.tools.ddk.check.check.Category; +import com.avaloq.tools.ddk.check.check.Check; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.FormalParameter; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import com.avaloq.tools.ddk.check.compiler.CheckGeneratorConfig; +import com.avaloq.tools.ddk.check.compiler.ICheckGeneratorConfigProvider; +import com.avaloq.tools.ddk.check.util.CheckUtil; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.common.types.JvmField; +import org.eclipse.xtext.generator.AbstractFileSystemAccess; +import org.eclipse.xtext.generator.IFileSystemAccess; +import org.eclipse.xtext.generator.OutputConfiguration; +import org.eclipse.xtext.xbase.compiler.GeneratorConfig; +import org.eclipse.xtext.xbase.compiler.JvmModelGenerator; +import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable; +import org.eclipse.xtext.xbase.lib.Functions.Function1; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.IteratorExtensions; +import org.eclipse.xtext.xbase.lib.StringExtensions; + +public class CheckGenerator extends JvmModelGenerator { + + @Inject + private CheckGeneratorExtensions generatorExtensions; + + @Inject + private CheckGeneratorNaming _checkGeneratorNaming; + + @Inject + private CheckCompiler compiler; + + @Inject + private ICheckGeneratorConfigProvider generatorConfigProvider; + + @Override + public void doGenerate(Resource resource, IFileSystemAccess fsa) { + super.doGenerate(resource, fsa); // Generate validator, catalog, and preference initializer from inferred Jvm models. + URI uri = null; + if (resource != null) { + uri = resource.getURI(); + } + final CheckGeneratorConfig config = generatorConfigProvider.get(uri); + Iterable catalogs = Iterables.filter(IteratorExtensions.toIterable(resource.getAllContents()), CheckCatalog.class); + for (CheckCatalog catalog : catalogs) { + fsa.generateFile(_checkGeneratorNaming.issueCodesFilePath(catalog), compileIssueCodes(catalog)); + fsa.generateFile(_checkGeneratorNaming.standaloneSetupPath(catalog), compileStandaloneSetup(catalog)); + + // change output path for service registry + fsa.generateFile( + CheckUtil.serviceRegistryClassName(), + CheckGeneratorConstants.CHECK_REGISTRY_OUTPUT, + generateServiceRegistry(catalog, CheckUtil.serviceRegistryClassName(), fsa)); + // generate documentation for SCA-checks only + if (config != null && (config.doGenerateDocumentationForAllChecks() || !config.isGenerateLanguageInternalChecks())) { + // change output path for html files to docs/ + fsa.generateFile(_checkGeneratorNaming.docFileName(catalog), CheckGeneratorConstants.CHECK_DOC_OUTPUT, compileDoc(catalog)); + } + } + } + + /* Documentation compiler, generates HTML output. */ + public CharSequence compileDoc(CheckCatalog catalog) { + final CharSequence body = bodyDoc(catalog); + final StringBuilder sb = new StringBuilder(); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append(" \n"); + sb.append(" \n"); + sb.append(" ").append(catalog.getName()).append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("

Check Catalog ").append(catalog.getName()).append("

\n"); + final String formattedDescription = generatorExtensions.formatDescription(catalog.getDescription()); + if (formattedDescription != null) { + sb.append("

").append(formattedDescription).append("

\n"); + } + sb.append(" ").append(body).append("\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("\n"); + return sb; + } + + public CharSequence bodyDoc(CheckCatalog catalog) { + final StringBuilder sb = new StringBuilder(); + for (Check check : catalog.getChecks()) { + sb.append("

").append(check.getLabel()) + .append(" (").append(check.getDefaultSeverity().name().toLowerCase()) + .append(")

\n"); + final String formattedCheckDescription = generatorExtensions.formatDescription(check.getDescription()); + if (formattedCheckDescription != null) { + sb.append(formattedCheckDescription).append("\n"); + } + sb.append("

Message: ").append(generatorExtensions.replacePlaceholder(check.getMessage())) + .append("


\n"); + } + for (Category category : catalog.getCategories()) { + sb.append("
\n"); + sb.append("

").append(category.getLabel()).append("

\n"); + final String formattedCategoryDescription = generatorExtensions.formatDescription(category.getDescription()); + if (formattedCategoryDescription != null) { + sb.append(" ").append(formattedCategoryDescription).append("\n"); + } + for (Check check : category.getChecks()) { + sb.append("
\n"); + sb.append("

").append(check.getLabel()) + .append(" (").append(check.getDefaultSeverity().name().toLowerCase()) + .append(")

\n"); + final String formattedCheckDescription = generatorExtensions.formatDescription(check.getDescription()); + if (formattedCheckDescription != null) { + sb.append(" ").append(formattedCheckDescription).append("\n"); + } + sb.append("

Message: ").append(generatorExtensions.replacePlaceholder(check.getMessage())) + .append("

\n"); + sb.append("
\n"); + } + sb.append("
\n"); + } + return sb; + } + + /* + * Creates an IssueCodes file for a Check Catalog. Every Check Catalog will have its own file + * of issue codes. + */ + public CharSequence compileIssueCodes(CheckCatalog catalog) { + final Iterable allIssues = generatorExtensions.checkAndImplementationIssues(catalog); + final Function1 keyFunction = (XIssueExpression issue) -> { + return CheckGeneratorExtensions.issueCode(issue); + }; + final Function1 valueFunction = (XIssueExpression issue) -> { + return CheckGeneratorExtensions.issueName(issue); + }; + final Map allIssueNames = IterableExtensions.toMap(allIssues, keyFunction, valueFunction); + final StringBuilder sb = new StringBuilder(); + if (!StringExtensions.isNullOrEmpty(catalog.getPackageName())) { + sb.append("package ").append(catalog.getPackageName()).append(";\n"); + } + sb.append("\n"); + sb.append("/**\n"); + sb.append(" * Issue codes which may be used to address validation issues (for instance in quickfixes).\n"); + sb.append(" */\n"); + sb.append("@SuppressWarnings(\"all\")\n"); + sb.append("public final class ").append(CheckGeneratorNaming.issueCodesClassName(catalog)).append(" {\n"); + sb.append("\n"); + final List sortedKeys = IterableExtensions.sort(allIssueNames.keySet()); + for (String issueCode : sortedKeys) { + sb.append(" public static final String ").append(issueCode) + .append(" = \"").append(CheckGeneratorExtensions.issueCodeValue(catalog, allIssueNames.get(issueCode))) + .append("\";\n"); + } + sb.append("\n"); + sb.append(" private ").append(CheckGeneratorNaming.issueCodesClassName(catalog)).append("() {\n"); + sb.append(" // Prevent instantiation.\n"); + sb.append(" }\n"); + sb.append("}\n"); + return sb; + } + + /* + * Generates the Java standalone setup class which will be called by the ServiceRegistry. + */ + public CharSequence compileStandaloneSetup(CheckCatalog catalog) { + final StringBuilder sb = new StringBuilder(); + if (!StringExtensions.isNullOrEmpty(catalog.getPackageName())) { + sb.append("package ").append(catalog.getPackageName()).append(";\n"); + } + sb.append("\n"); + sb.append("import org.apache.logging.log4j.Logger;\n"); + sb.append("import org.apache.logging.log4j.LogManager;\n"); + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.check.runtime.configuration.ModelLocation;\n"); + sb.append("import com.avaloq.tools.ddk.check.runtime.registry.ICheckCatalogRegistry;\n"); + sb.append("import com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorRegistry;\n"); + sb.append("import com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorStandaloneSetup;\n"); + sb.append("\n"); + sb.append("/**\n"); + sb.append(" * Standalone setup for ").append(catalog.getName()).append(" as required by the standalone builder.\n"); + sb.append(" */\n"); + sb.append("@SuppressWarnings(\"nls\")\n"); + sb.append("public class ").append(_checkGeneratorNaming.standaloneSetupClassName(catalog)) + .append(" implements ICheckValidatorStandaloneSetup {\n"); + sb.append("\n"); + sb.append(" private static final Logger LOG = LogManager.getLogger(") + .append(_checkGeneratorNaming.standaloneSetupClassName(catalog)).append(".class);\n"); + final Grammar grammar = catalog.getGrammar(); + if (grammar != null) { + sb.append(" private static final String GRAMMAR_NAME = \"") + .append(grammar.getName()).append("\";\n"); + } + sb.append(" private static final String CATALOG_FILE_PATH = \"") + .append(_checkGeneratorNaming.checkFilePath(catalog)).append("\";\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public void doSetup() {\n"); + sb.append(" ICheckValidatorRegistry.INSTANCE.registerValidator("); + if (grammar != null) { + sb.append("GRAMMAR_NAME, "); + } + sb.append("new ").append(_checkGeneratorNaming.validatorClassName(catalog)).append("());\n"); + sb.append(" ICheckCatalogRegistry.INSTANCE.registerCatalog("); + if (grammar != null) { + sb.append("GRAMMAR_NAME, "); + } + sb.append("new ModelLocation(\n"); + sb.append(" ").append(_checkGeneratorNaming.standaloneSetupClassName(catalog)) + .append(".class.getClassLoader().getResource(CATALOG_FILE_PATH), CATALOG_FILE_PATH));\n"); + sb.append(" LOG.info(\"Standalone setup done for ") + .append(_checkGeneratorNaming.checkFilePath(catalog)).append("\");\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public String toString() {\n"); + sb.append(" return \"CheckValidatorSetup(") + .append(catalog.eResource().getURI().path()).append(")\";\n"); + sb.append(" }\n"); + sb.append("}\n"); + return sb; + } + + /* + * Writes contents of the service registry file containing fully qualified class names of all validators. + * See also http://docs.oracle.com/javase/1.4.2/docs/api/javax/imageio/spi/ServiceRegistry.html + */ + public CharSequence generateServiceRegistry(CheckCatalog catalog, String serviceRegistryFileName, IFileSystemAccess fsa) { + final OutputConfiguration config = ((AbstractFileSystemAccess) fsa).getOutputConfigurations().get(CheckGeneratorConstants.CHECK_REGISTRY_OUTPUT); + final String outputDirectory = config.getOutputDirectory(); + final String path = outputDirectory + "/" + serviceRegistryFileName; + final Set contents = generatorExtensions.getContents(catalog, path); + contents.add(_checkGeneratorNaming.qualifiedStandaloneSetupClassName(catalog)); + final StringBuilder sb = new StringBuilder(); + for (String c : contents) { + sb.append(c).append("\n"); + } + return sb; + } + + @Override + public ITreeAppendable _generateMember(JvmField field, ITreeAppendable appendable, GeneratorConfig config) { + // Suppress generation of the "artificial" fields for FormalParameters in check impls, but not elsewhere. + if (field.isFinal() && !field.isStatic()) { // A bit hacky to use this as the distinction... + final FormalParameter parameter = compiler.getFormalParameter(field); + if (parameter != null) { + return appendable; + } + } + return super._generateMember(field, appendable, config); + } +} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.xtend deleted file mode 100644 index 1753758cc6..0000000000 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.xtend +++ /dev/null @@ -1,215 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.generator - -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.util.CheckUtil -import com.google.inject.Inject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.AbstractFileSystemAccess -import org.eclipse.xtext.generator.IFileSystemAccess -import org.eclipse.xtext.xbase.compiler.JvmModelGenerator - -import static org.eclipse.xtext.xbase.lib.IteratorExtensions.* -import com.avaloq.tools.ddk.check.check.FormalParameter -import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable -import org.eclipse.xtext.common.types.JvmField -import org.eclipse.xtext.xbase.compiler.GeneratorConfig - -import static extension com.avaloq.tools.ddk.check.generator.CheckGeneratorExtensions.* -import static extension com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming.* -import com.avaloq.tools.ddk.check.compiler.ICheckGeneratorConfigProvider - -class CheckGenerator extends JvmModelGenerator { - - @Inject extension CheckGeneratorExtensions generatorExtensions - @Inject extension CheckGeneratorNaming - @Inject CheckCompiler compiler - @Inject ICheckGeneratorConfigProvider generatorConfigProvider; - - override void doGenerate(Resource resource, IFileSystemAccess fsa) { - super.doGenerate(resource, fsa); // Generate validator, catalog, and preference initializer from inferred Jvm models. - val config = generatorConfigProvider.get(resource?.URI); - for (catalog : toIterable(resource.allContents).filter(typeof(CheckCatalog))) { - - fsa.generateFile(catalog.issueCodesFilePath, catalog.compileIssueCodes) - fsa.generateFile(catalog.standaloneSetupPath, catalog.compileStandaloneSetup) - - // change output path for service registry - fsa.generateFile( - CheckUtil::serviceRegistryClassName, - CheckGeneratorConstants::CHECK_REGISTRY_OUTPUT, - catalog.generateServiceRegistry(CheckUtil::serviceRegistryClassName, fsa) - ) - // generate documentation for SCA-checks only - if(config !== null && (config.doGenerateDocumentationForAllChecks || !config.generateLanguageInternalChecks)){ - // change output path for html files to docs/ - fsa.generateFile(catalog.docFileName, CheckGeneratorConstants::CHECK_DOC_OUTPUT, catalog.compileDoc) - } - } - } - - /* Documentation compiler, generates HTML output. */ - def compileDoc (CheckCatalog catalog)''' - «val body = bodyDoc(catalog)» - - - - - - «catalog.name» - - - -

Check Catalog «catalog.name»

- «val formattedDescription = catalog.description.formatDescription» - «IF formattedDescription !== null» -

«formattedDescription»

- «ENDIF» - «body» - - - - ''' - - def bodyDoc(CheckCatalog catalog)''' - «FOR check:catalog.checks» -

«check.label» («check.defaultSeverity.name().toLowerCase»)

- «val formattedCheckDescription = check.description.formatDescription» - «IF formattedCheckDescription !== null» - «formattedCheckDescription» - «ENDIF» -

Message: «check.message.replacePlaceholder»


- «ENDFOR» - «FOR category:catalog.categories» -
-

«category.label»

- «val formattedCateogryDescription = category.description.formatDescription» - «IF formattedCateogryDescription !== null» - «formattedCateogryDescription» - «ENDIF» - «FOR check:category.checks» -
-

«check.label» («check.defaultSeverity.name().toLowerCase»)

- «val formattedCheckDescription = check.description.formatDescription» - «IF formattedCheckDescription !== null» - «formattedCheckDescription» - «ENDIF» -

Message: «check.message.replacePlaceholder»

-
- «ENDFOR» -
- «ENDFOR» - ''' - - /* - * Creates an IssueCodes file for a Check Catalog. Every Check Catalog will have its own file - * of issue codes. - */ - def compileIssueCodes(CheckCatalog catalog) { - val allIssues = catalog.checkAndImplementationIssues // all Issue instances - val allIssueNames = allIssues.toMap([issue|issue.issueCode()], [issue|issue.issueName()]) // *all* issue names, unordered - - ''' - «IF !(catalog.packageName.isNullOrEmpty)» - package «catalog.packageName»; - «ENDIF» - - /** - * Issue codes which may be used to address validation issues (for instance in quickfixes). - */ - @SuppressWarnings("all") - public final class «catalog.issueCodesClassName» { - - «FOR issueCode:allIssueNames.keySet.sort» - public static final String «issueCode» = "«issueCodeValue(catalog, allIssueNames.get(issueCode))»"; - «ENDFOR» - - private «catalog.issueCodesClassName»() { - // Prevent instantiation. - } - } - ''' - } - - /* - * Generates the Java standalone setup class which will be called by the ServiceRegistry. - */ - def compileStandaloneSetup(CheckCatalog catalog) { - ''' - «IF !(catalog.packageName.isNullOrEmpty)» - package «catalog.packageName»; - «ENDIF» - - import org.apache.logging.log4j.Logger; - import org.apache.logging.log4j.LogManager; - - import com.avaloq.tools.ddk.check.runtime.configuration.ModelLocation; - import com.avaloq.tools.ddk.check.runtime.registry.ICheckCatalogRegistry; - import com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorRegistry; - import com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorStandaloneSetup; - - /** - * Standalone setup for «catalog.name» as required by the standalone builder. - */ - @SuppressWarnings("nls") - public class «catalog.standaloneSetupClassName» implements ICheckValidatorStandaloneSetup { - - private static final Logger LOG = LogManager.getLogger(«catalog.standaloneSetupClassName».class); - «IF catalog.grammar !== null» - private static final String GRAMMAR_NAME = "«catalog.grammar.name»"; - «ENDIF» - private static final String CATALOG_FILE_PATH = "«catalog.checkFilePath»"; - - @Override - public void doSetup() { - ICheckValidatorRegistry.INSTANCE.registerValidator(«IF catalog.grammar !== null»GRAMMAR_NAME,«ENDIF» new «catalog.validatorClassName»()); - ICheckCatalogRegistry.INSTANCE.registerCatalog(«IF catalog.grammar !== null»GRAMMAR_NAME,«ENDIF» new ModelLocation( - «catalog.standaloneSetupClassName».class.getClassLoader().getResource(CATALOG_FILE_PATH), CATALOG_FILE_PATH)); - LOG.info("Standalone setup done for «catalog.checkFilePath»"); - } - - @Override - public String toString() { - return "CheckValidatorSetup(«catalog.eResource.URI.path»)"; - } - } - ''' - } - - /* - * Writes contents of the service registry file containing fully qualified class names of all validators. - * See also http://docs.oracle.com/javase/1.4.2/docs/api/javax/imageio/spi/ServiceRegistry.html - */ - def generateServiceRegistry(CheckCatalog catalog, String serviceRegistryFileName, IFileSystemAccess fsa) { - val config = (fsa as AbstractFileSystemAccess).outputConfigurations.get(CheckGeneratorConstants::CHECK_REGISTRY_OUTPUT) - val path = config.outputDirectory + "/" + serviceRegistryFileName - val contents = catalog.getContents(path) - contents.add(catalog.qualifiedStandaloneSetupClassName) - ''' - «FOR c:contents» - «c» - «ENDFOR» - ''' - } - - override ITreeAppendable _generateMember(JvmField field, ITreeAppendable appendable, GeneratorConfig config) { - // Suppress generation of the "artificial" fields for FormalParameters in check impls, but not elsewhere. - if (field.final && !field.static) { // A bit hacky to use this as the distinction... - val FormalParameter parameter = compiler.getFormalParameter(field); - if (parameter !== null) { - return appendable; - } - } - return super._generateMember(field, appendable, config); - } -} - diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java new file mode 100644 index 0000000000..9e5256c091 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java @@ -0,0 +1,327 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.generator; + +import java.io.InputStreamReader; +import java.io.StringReader; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.avaloq.tools.ddk.check.check.Check; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.Context; +import com.avaloq.tools.ddk.check.check.Implementation; +import com.avaloq.tools.ddk.check.check.TriggerKind; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import com.avaloq.tools.ddk.check.util.CheckUtil; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; +import com.google.common.io.CharStreams; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.jdt.internal.ui.text.javadoc.JavaDoc2HTMLTextReader; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.validation.CheckType; +import org.eclipse.xtext.xbase.lib.ListExtensions; + +import static com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming.*; + +public class CheckGeneratorExtensions { + + protected String _qualifiedIssueCodeName(XIssueExpression issue) { + String result = issueCode(issue); + if (result == null) { + return null; + } else { + return issueCodesClassName(parent(issue, CheckCatalog.class)) + "." + result; + } + } + + /* Returns the qualified Java name for an issue code. */ + protected String _qualifiedIssueCodeName(Context context) { + return issueCodesClassName(parent(context, CheckCatalog.class)) + "." + issueCode(context); + } + + /* Gets the simple issue code name for a check. */ + protected static String _issueCode(Check check) { + if (null != check.getName()) { + return splitCamelCase(check.getName()).toUpperCase(); + } else { + return "ERROR_ISSUE_CODE_NAME_CHECK"; // should only happen if the ID is missing, which will fail a validation + } + } + + /* Gets the simple issue code name for an issue expression. */ + protected static String _issueCode(XIssueExpression issue) { + if (issue.getIssueCode() != null) { + return splitCamelCase(issue.getIssueCode()).toUpperCase(); + } else if (issue.getCheck() != null && !issue.getCheck().eIsProxy()) { + return issueCode(issue.getCheck()); + } else if (parent(issue, Check.class) != null) { + return issueCode(parent(issue, Check.class)); + } else { + return "ERROR_ISSUE_CODE_NAME_XISSUEEXPRESSION"; // should not happen + } + } + + /* Gets the simple issue code name for a check. */ + protected static String _issueName(Check check) { + if (null != check.getName()) { + return check.getName(); + } else { + return "ErrorIssueCodeNameCheck"; // should only happen if the ID is missing, which will fail a validation + } + } + + /* Gets the simple issue code name for an issue expression. */ + protected static String _issueName(XIssueExpression issue) { + if (issue.getIssueCode() != null) { + return issue.getIssueCode(); + } else if (issue.getCheck() != null && !issue.getCheck().eIsProxy()) { + return issueName(issue.getCheck()); + } else if (parent(issue, Check.class) != null) { + return issueName(parent(issue, Check.class)); + } else { + return "ErrorIssueCodeName_XIssueExpresion"; // should not happen + } + } + + public static String issueCodePrefix(CheckCatalog catalog) { + return catalog.getPackageName() + "." + issueCodesClassName(catalog) + "."; + } + + /* Returns the value of an issue code. */ + public static String issueCodeValue(EObject object, String issueName) { + CheckCatalog catalog = parent(object, CheckCatalog.class); + return issueCodePrefix(catalog) + CheckUtil.toIssueCodeName(splitCamelCase(issueName)); + } + + /* Gets the issue label for a Check. */ + protected String _issueLabel(Check check) { + return check.getLabel(); + } + + /* Gets the issue label for an issue expression. */ + protected String _issueLabel(XIssueExpression issue) { + if (issue.getCheck() != null && !issue.getCheck().eIsProxy()) { + return issueLabel(issue.getCheck()); + } else if (parent(issue, Check.class) != null) { + return issueLabel(parent(issue, Check.class)); + } else { + return "ERROR_ISSUE_LABEL_XISSUEEXPRESSION"; // should not happen + } + } + + /* Converts a string such as "AbcDef" to "ABC_DEF". */ + public static String splitCamelCase(String string) { + return string.replaceAll( + String.format( + "%s|%s|%s", + "(?<=[A-Z])(?=[A-Z][a-z])", + "(?<=[^A-Z_])(?=[A-Z])", + "(?<=[A-Za-z])(?=[^A-Za-z_])" + ), + "_" + ); + } + + public CheckType checkType(Check check) { + /* TODO handle the case of independent check implementations + * An Implementation is not a Check and has no kind, + * but it may execute checks of various types. + * As it is we treat them all as FAST regardless of declared kind. + */ + TriggerKind kind = check != null ? check.getKind() : null; + if (kind == null) { + kind = TriggerKind.FAST; + } + + return switch (kind) { + case EXPENSIVE -> CheckType.EXPENSIVE; + case NORMAL -> CheckType.NORMAL; + case FAST -> CheckType.FAST; + }; + } + + /* Returns a default CheckType for a non-Check context. */ + public CheckType checkType(Context context) { + EObject container = context.eContainer(); + Check check = (container instanceof Check) ? (Check) container : null; + return checkType(check); + } + + public String checkTypeQName(Context context) { + return "CheckType." + checkType(context); + } + + public Iterable issues(EObject object) { + return Iterables.filter(EcoreUtil2.eAllContents(object), XIssueExpression.class); + } + + public Iterable issues(CheckCatalog catalog) { + return Iterables.concat(ListExtensions.map(catalog.getAllChecks(), check -> issues(check))); + } + + public Iterable issues(Implementation implementation) { + return issues(implementation.getContext()); + } + + /* Returns all Check and Implementation Issues for a CheckCatalog. Issues are not necessarily unique. */ + public Iterable checkAndImplementationIssues(CheckCatalog catalog) { + Iterable checkIssues = issues(catalog); // Issues for all Checks + Iterable implIssues = Iterables.concat(ListExtensions.map(catalog.getImplementations(), impl -> issues(impl))); // Issues for all Implementations + return Iterables.concat(checkIssues, implIssues); // all Issue instances + } + + public Check issuedCheck(XIssueExpression expression) { + if (expression.getCheck() != null) { + return expression.getCheck(); + } else { + Check containerCheck = EcoreUtil2.getContainerOfType(expression, Check.class); + if (containerCheck != null) { + return containerCheck; + //TODO we obviously need a validation in the language so that there is always a value here! + } + return null; + } + } + + /** + * Gets the IFile which is associated with given object's eResource, or null if none + * could be determined. + */ + public IFile fileForObject(EObject object) { + Resource res = object.eResource(); + if (res.getURI().isPlatform()) { + return (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(res.getURI().toPlatformString(true)); + } + return null; + } + + /** + * Gets the IProject which is associated with a given EObject or null + * if none could be determined. + */ + public IProject projectForObject(EObject object) { + IFile file = object != null ? fileForObject(object) : null; + return file != null ? file.getProject() : null; + } + + /** + * Gets the name of the project in which given object is contained. + */ + public String bundleName(EObject object) { + IProject proj = projectForObject(object); + if (proj != null) { + return proj.getName(); + } + return null; + } + + /* + * Replace binding placeholders of a message with "...". + */ + public String replacePlaceholder(String message) { + Pattern p = Pattern.compile("\\{[0-9]+\\}"); + Matcher m = p.matcher(message); + return m.replaceAll("..."); + } + + /* + * Format the Check description for Eclipse Help + */ + public String formatDescription(String comment) { + if (comment == null) { + return null; + } + try { + JavaDoc2HTMLTextReader reader = new JavaDoc2HTMLTextReader(new StringReader(comment)); + return reader.getString(); + } catch (Exception e) { + return null; + } + } + + public Set getContents(CheckCatalog catalog, String path) { + IProject project = projectForObject(catalog); + if (project != null) { // In some compiler tests we may not have a project. + IFile file = project.getFile(new Path(path)); + if (file.exists()) { + InputStreamReader reader = new InputStreamReader(file.getContents()); + try { + List content = CharStreams.readLines(reader); + return Sets.newTreeSet(content); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + try { + reader.close(); + } catch (Exception e) { + // ignore + } + } + } + } + return new LinkedHashSet<>(); + } + + public String qualifiedIssueCodeName(EObject context) { + if (context instanceof Context) { + return _qualifiedIssueCodeName((Context) context); + } else if (context instanceof XIssueExpression) { + return _qualifiedIssueCodeName((XIssueExpression) context); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(context).toString()); + } + } + + public static String issueCode(EObject check) { + if (check instanceof Check) { + return _issueCode((Check) check); + } else if (check instanceof XIssueExpression) { + return _issueCode((XIssueExpression) check); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(check).toString()); + } + } + + public static String issueName(EObject check) { + if (check instanceof Check) { + return _issueName((Check) check); + } else if (check instanceof XIssueExpression) { + return _issueName((XIssueExpression) check); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(check).toString()); + } + } + + public String issueLabel(EObject check) { + if (check instanceof Check) { + return _issueLabel((Check) check); + } else if (check instanceof XIssueExpression) { + return _issueLabel((XIssueExpression) check); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(check).toString()); + } + } +} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.xtend deleted file mode 100644 index 432b588da1..0000000000 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.xtend +++ /dev/null @@ -1,267 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.generator - -import com.avaloq.tools.ddk.check.check.Check -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.check.Context -import com.avaloq.tools.ddk.check.check.Implementation -import com.avaloq.tools.ddk.check.check.TriggerKind -import com.avaloq.tools.ddk.check.check.XIssueExpression -import com.google.common.collect.Iterables -import com.google.common.collect.Sets -import com.google.common.io.CharStreams -import java.io.InputStreamReader -import java.io.StringReader -import java.util.Set -import java.util.regex.Pattern -import org.eclipse.core.resources.IFile -import org.eclipse.core.resources.IProject -import org.eclipse.core.resources.ResourcesPlugin -import org.eclipse.core.runtime.Path -import org.eclipse.emf.ecore.EObject -import org.eclipse.jdt.internal.ui.text.javadoc.JavaDoc2HTMLTextReader -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.validation.CheckType - -import static extension com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming.* -import static extension com.avaloq.tools.ddk.check.util.CheckUtil.* - -class CheckGeneratorExtensions { - - def dispatch String qualifiedIssueCodeName(XIssueExpression issue) { - val result = issue.issueCode() - if (result === null) { - null - } else { - issue.parent(typeof(CheckCatalog)).issueCodesClassName + '.' + result - } - } - - /* Returns the qualified Java name for an issue code. */ - def dispatch String qualifiedIssueCodeName(Context context) { - context.parent(typeof(CheckCatalog)).issueCodesClassName + '.' + context.issueCode - } - - /* Gets the simple issue code name for a check. */ - def static dispatch String issueCode(Check check) { - if (null !== check.name) { - check.name.splitCamelCase.toUpperCase - } else { - "ERROR_ISSUE_CODE_NAME_CHECK" // should only happen if the ID is missing, which will fail a validation - } - } - - /* Gets the simple issue code name for an issue expression. */ - def static dispatch String issueCode(XIssueExpression issue) { - if (issue.issueCode !== null) { - issue.issueCode.splitCamelCase.toUpperCase - } else if (issue.check !== null && !issue.check.eIsProxy) { - issueCode(issue.check) - } else if (issue.parent(Check) !== null) { - issueCode(issue.parent(Check)) - } else { - "ERROR_ISSUE_CODE_NAME_XISSUEEXPRESSION" // should not happen - } - } - - /* Gets the simple issue code name for a check. */ - def static dispatch String issueName(Check check) { - if (null !== check.name) { - check.name - } else { - "ErrorIssueCodeNameCheck" // should only happen if the ID is missing, which will fail a validation - } - } - - /* Gets the simple issue code name for an issue expression. */ - def static dispatch String issueName(XIssueExpression issue) { - if (issue.issueCode !== null) { - issue.issueCode - } else if (issue.check !== null && !issue.check.eIsProxy) { - issueName(issue.check) - } else if (issue.parent(Check) !== null) { - issueName(issue.parent(Check)) - } else { - "ErrorIssueCodeName_XIssueExpresion" // should not happen - } - } - - def static issueCodePrefix(CheckCatalog catalog) { - catalog.packageName + "." + catalog.issueCodesClassName + "." - } - - /* Returns the value of an issue code. */ - def static issueCodeValue(EObject object, String issueName) { - val catalog = object.parent(typeof(CheckCatalog)) - catalog.issueCodePrefix + issueName.splitCamelCase.toIssueCodeName - } - - /* Gets the issue label for a Check. */ - def dispatch String issueLabel(Check check) { - check.label - } - - /* Gets the issue label for an issue expression. */ - def dispatch String issueLabel(XIssueExpression issue) { - if (issue.check !== null && !issue.check.eIsProxy) { - issueLabel(issue.check) - } else if (issue.parent(Check) !== null) { - issueLabel(issue.parent(Check)) - } else { - "ERROR_ISSUE_LABEL_XISSUEEXPRESSION" // should not happen - } - } - - /* Converts a string such as "AbcDef" to "ABC_DEF". */ - def static String splitCamelCase(String string) { - string.replaceAll( - String::format( - "%s|%s|%s", - "(?<=[A-Z])(?=[A-Z][a-z])", - "(?<=[^A-Z_])(?=[A-Z])", - "(?<=[A-Za-z])(?=[^A-Za-z_])" - ), - "_" - ) - } - - def CheckType checkType(Check check) { - /* TODO handle the case of independent check implementations - * An Implementation is not a Check and has no kind, - * but it may execute checks of various types. - * As it is we treat them all as FAST regardless of declared kind. - */ - val TriggerKind kind = check?.kind ?: TriggerKind::FAST; - - return switch (kind) { - case TriggerKind::EXPENSIVE: CheckType::EXPENSIVE - case TriggerKind::NORMAL: CheckType::NORMAL - case TriggerKind::FAST: CheckType::FAST - }; - } - - /* Returns a default CheckType for a non-Check context. */ - def CheckType checkType(Context context) { - val container = context.eContainer(); - val Check check = if (container instanceof Check) container else null; - return checkType(check); - } - - def String checkTypeQName(Context context) { - return "CheckType." + checkType(context); - } - - def issues(EObject object) { - EcoreUtil2::eAllContents(object).filter(typeof(XIssueExpression)) - } - - def issues(CheckCatalog catalog) { - catalog.allChecks.map(check|check.issues).flatten - } - - def issues(Implementation implementation) { - implementation.context.issues - } - - /* Returns all Check and Implementation Issues for a CheckCatalog. Issues are not necessarily unique. */ - def checkAndImplementationIssues(CheckCatalog catalog) { - val checkIssues = catalog.issues // Issues for all Checks - val implIssues = catalog.implementations.map(impl|impl.issues).flatten // Issues for all Implementations - return Iterables::concat(checkIssues, implIssues) // all Issue instances - } - - def issuedCheck(XIssueExpression expression) { - if (expression.check !== null) { - expression.check - } else { - val containerCheck = EcoreUtil2::getContainerOfType(expression, typeof(Check)) - if (containerCheck !== null) { - containerCheck - //TODO we obviously need a validation in the language so that there is always a value here! - } - } - } - - /** - * Gets the IFile which is associated with given object's eResource, or null if none - * could be determined. - */ - def IFile fileForObject(EObject object) { - val res = object.eResource - if (res.URI.platform) { - return ResourcesPlugin::workspace.root.findMember(res.URI.toPlatformString(true)) as IFile - } - return null - } - - /** - * Gets the IProject which is associated with a given EObject or null - * if none could be determined. - */ - def IProject projectForObject(EObject object) { - return object?.fileForObject?.project - } - - /** - * Gets the name of the project in which given object is contained. - */ - def String bundleName(EObject object) { - val proj = object.projectForObject - if (proj !== null) { - return proj.name - } - return null - } - - /* - * Replace binding placeholders of a message with "...". - */ - def String replacePlaceholder(String message) { - val p = Pattern::compile("\\{[0-9]+\\}") - val m = p.matcher(message) - m.replaceAll("...") - } - - /* - * Format the Check description for Eclipse Help - */ - def String formatDescription(String comment) { - if (comment === null) { - return null - } - try { - val reader = new JavaDoc2HTMLTextReader(new StringReader(comment)) - return reader.string - } catch (Exception e) { - return null - } - } - - def Set getContents(CheckCatalog catalog, String path) { - val project = catalog.projectForObject - if (project !== null) { // In some compiler tests we may not have a project. - val file = project.getFile(new Path(path)) - if (file.exists) { - val reader = new InputStreamReader(file.getContents()) - try { - val content = CharStreams::readLines(reader) - return Sets.newTreeSet(content) - } finally { - reader.close - } - } - } - newLinkedHashSet() - } - -} - diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java new file mode 100644 index 0000000000..374f4735cc --- /dev/null +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.generator; + +import com.avaloq.tools.ddk.check.check.Category; +import com.avaloq.tools.ddk.check.check.Check; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.FormalParameter; +import com.google.inject.Inject; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.naming.IQualifiedNameProvider; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.xbase.lib.StringExtensions; + +import static com.avaloq.tools.ddk.check.runtime.CheckRuntimeConstants.ISSUE_CODES_CLASS_NAME_SUFFIX; + +public class CheckGeneratorNaming { + + @Inject + private IQualifiedNameProvider nameProvider; + + public static T parent(EObject object, Class c) { + return EcoreUtil2.getContainerOfType(object, c); + } + + // creates a pathName out of a qualified javaPackagename + public String asPath(String javaPackageName) { + if (javaPackageName != null) { + return javaPackageName.replace('.', '/') + "/"; + } else { + return ""; + } + } + + /* Gets the class name of the check validator. */ + public String validatorClassName(CheckCatalog c) { + return c.getName() + "CheckImpl"; + } + + /* Gets the fully qualified class name of the check validator. */ + public String qualifiedValidatorClassName(CheckCatalog c) { + return c.getPackageName() + "." + validatorClassName(c); + } + + /* Gets the file path of the check validator. */ + public String validatorFilePath(CheckCatalog c) { + return asPath(c.getPackageName()) + validatorClassName(c) + ".java"; + } + + /* Gets the check catalog class name. */ + public String catalogClassName(CheckCatalog c) { + return c.getName() + "CheckCatalog"; + } + + /* Gets the qualified check catalog class name. */ + public String qualifiedCatalogClassName(CheckCatalog c) { + return c.getPackageName() + "." + catalogClassName(c); + } + + /* Gets the preference initializer class name. */ + public String preferenceInitializerClassName(CheckCatalog c) { + return c.getName() + "PreferenceInitializer"; + } + + /* Gets the qualified standalone setup class name. */ + public String qualifiedStandaloneSetupClassName(CheckCatalog c) { + return c.getPackageName() + "." + standaloneSetupClassName(c); + } + + /* Gets the standalone setup class name. */ + public String standaloneSetupClassName(CheckCatalog c) { + return c.getName() + "StandaloneSetup"; + } + + /* Gets the qualified preference initializer class name. */ + public String qualifiedPreferenceInitializerClassName(CheckCatalog c) { + return c.getPackageName() + "." + preferenceInitializerClassName(c); + } + + /* Gets the standalone setup class file path. */ + public String standaloneSetupPath(CheckCatalog c) { + return asPath(c.getPackageName()) + standaloneSetupClassName(c) + ".java"; + } + + /* Gets the documentation file name. */ + public String docFileName(CheckCatalog c) { + return c.getName() + ".html"; + } + + /* Gets the issue codes class name. */ + public static String issueCodesClassName(CheckCatalog c) { + return c.getName() + ISSUE_CODES_CLASS_NAME_SUFFIX; + } + + /* Gets the issue codes file path. */ + public String issueCodesFilePath(CheckCatalog c) { + return asPath(c.getPackageName()) + issueCodesClassName(c) + ".java"; + } + + /* Gets the quickfix provider class name. */ + public String quickfixClassName(CheckCatalog c) { + return c.getName() + "QuickfixProvider"; + } + + /* Gets the qualified quickfix provider class name. */ + public String qualifiedQuickfixClassName(CheckCatalog c) { + return c.getPackageName() + "." + quickfixClassName(c); + } + + /* Gets the quickfix provider file path. */ + public String quickfixFilePath(CheckCatalog c) { + return asPath(c.getPackageName()) + quickfixClassName(c) + ".java"; + } + + /* Gets the full path to the check file, e.g. com/avaloq/MyChecks.check. */ + public String checkFilePath(CheckCatalog c) { + return asPath(c.getPackageName()) + c.getName() + ".check"; + } + + /* Gets the name of the getter method generated for a formal parameter. */ + public String formalParameterGetterName(FormalParameter p) { + Check check = (Check) p.eContainer(); + return "get" + + StringExtensions.toFirstUpper(check.getName()) + + "_" + + StringExtensions.toFirstUpper(p.getName()); + } + + /* Gets the name of the getter method generated for a field. */ + public String fieldGetterName(String fieldName) { + return "get" + StringExtensions.toFirstUpper(fieldName); + } + + /* Check catalog instance name in the validator */ + public String catalogInstanceName(EObject object) { + return StringExtensions.toFirstLower(EcoreUtil2.getContainerOfType(object, CheckCatalog.class).getName()) + "Catalog"; + } + + /* Check issue code to label map field name in the catalog */ + public String issueCodeToLabelMapFieldName() { + return "issueCodeToLabelMap"; + } + + /* Gets the name of the default validator class. */ + public String defaultValidatorClassName() { + return "DispatchingCheckImpl"; + } + + /* Gets the fully qualified name of the default validator class. */ + public String qualifiedDefaultValidatorClassName() { + return "com.avaloq.tools.ddk.check.runtime.issue." + defaultValidatorClassName(); + } + + /* Gets the prefix for the context id (used in contexts.xml) */ + public String getContextIdPrefix(QualifiedName catalog) { + return catalog.getLastSegment().toString().toLowerCase() + "_"; // TODO make context id use fully qualified catalog names + } + + /* Gets the full context id (used in contexts.xml) */ + public String getContextId(Check check) { + CheckCatalog catalog = parent(check, CheckCatalog.class); + return getContextIdPrefix(nameProvider.apply(catalog)) + check.getLabel().replaceAll(" ", "").replaceAll("\"", "").replaceAll("'", "").toLowerCase(); + } + + /* Gets the full context id (used in contexts.xml) */ + public String getContextId(Category category) { + CheckCatalog catalog = parent(category, CheckCatalog.class); + return getContextIdPrefix(nameProvider.apply(catalog)) + category.getLabel().replaceAll(" ", "").replaceAll("\"", "").replaceAll("'", "").toLowerCase(); + } +} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.xtend deleted file mode 100644 index 1a0c493c05..0000000000 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.xtend +++ /dev/null @@ -1,174 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.generator - -import com.avaloq.tools.ddk.check.check.Category -import com.avaloq.tools.ddk.check.check.Check -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.check.FormalParameter -import com.google.inject.Inject -import org.eclipse.emf.ecore.EObject -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.naming.IQualifiedNameProvider -import org.eclipse.xtext.naming.QualifiedName - -import static com.avaloq.tools.ddk.check.runtime.CheckRuntimeConstants.ISSUE_CODES_CLASS_NAME_SUFFIX - -class CheckGeneratorNaming { - - @Inject IQualifiedNameProvider nameProvider - - def static T parent(EObject object, Class c) { - EcoreUtil2::getContainerOfType(object, c) - } - - // creates a pathName out of a qualified javaPackagename - def String asPath(String javaPackageName) { - if (javaPackageName !== null) javaPackageName.replace('.', '/') + "/" else "" - } - - /* Gets the class name of the check validator. */ - def String validatorClassName(CheckCatalog c) { - c.name + "CheckImpl" - } - - /* Gets the fully qualified class name of the check validator. */ - def String qualifiedValidatorClassName(CheckCatalog c) { - c.packageName + '.' + c.validatorClassName - } - - /* Gets the file path of the check validator. */ - def String validatorFilePath(CheckCatalog c) { - c.packageName.asPath + c.validatorClassName + ".java" - } - - /* Gets the check catalog class name. */ - def String catalogClassName(CheckCatalog c) { - c.name + "CheckCatalog" - } - - /* Gets the qualified check catalog class name. */ - def String qualifiedCatalogClassName(CheckCatalog c) { - c.packageName + '.' + c.catalogClassName - } - - /* Gets the preference initializer class name. */ - def String preferenceInitializerClassName(CheckCatalog c) { - c.name + "PreferenceInitializer" - } - - /* Gets the qualified standalone setup class name. */ - def String qualifiedStandaloneSetupClassName(CheckCatalog c) { - c.packageName + '.' + c.standaloneSetupClassName - } - - /* Gets the standalone setup class name. */ - def String standaloneSetupClassName(CheckCatalog c) { - c.name + "StandaloneSetup" - } - - /* Gets the qualified preference initializer class name. */ - def String qualifiedPreferenceInitializerClassName(CheckCatalog c) { - c.packageName + '.' + c.preferenceInitializerClassName - } - - /* Gets the standalone setup class file path. */ - def String standaloneSetupPath(CheckCatalog c) { - c.packageName.asPath + c.standaloneSetupClassName + ".java" - } - - /* Gets the documentation file name. */ - def String docFileName(CheckCatalog c){ - c.name + ".html" - } - - /* Gets the issue codes class name. */ - def static String issueCodesClassName(CheckCatalog c) { - c.name + ISSUE_CODES_CLASS_NAME_SUFFIX - } - - /* Gets the issue codes file path. */ - def String issueCodesFilePath(CheckCatalog c) { - c.packageName.asPath + c.issueCodesClassName + ".java" - } - - /* Gets the quickfix provider class name. */ - def String quickfixClassName(CheckCatalog c) { - c.name + "QuickfixProvider" - } - - /* Gets the qualified quickfix provider class name. */ - def String qualifiedQuickfixClassName(CheckCatalog c) { - c.packageName + '.' + c.quickfixClassName - } - - /* Gets the quickfix provider file path. */ - def String quickfixFilePath(CheckCatalog c) { - c.packageName.asPath + c.quickfixClassName + ".java" - } - - /* Gets the full path to the check file, e.g. com/avaloq/MyChecks.check. */ - def String checkFilePath(CheckCatalog c) { - c.packageName.asPath + c.name + ".check" - } - - /* Gets the name of the getter method generated for a formal parameter. */ - def String formalParameterGetterName(FormalParameter p) { - val check = p.eContainer as Check - return "get" - + check.name.toFirstUpper - + "_" - + p.name.toFirstUpper - } - - /* Gets the name of the getter method generated for a field. */ - def String fieldGetterName(String fieldName) { - "get" + fieldName.toFirstUpper - } - - /* Check catalog instance name in the validator */ - def String catalogInstanceName(EObject object) { - EcoreUtil2::getContainerOfType(object, typeof(CheckCatalog)).name.toFirstLower + "Catalog" - } - - /* Check issue code to label map field name in the catalog */ - def String issueCodeToLabelMapFieldName() { - "issueCodeToLabelMap" - } - - /* Gets the name of the default validator class. */ - def String defaultValidatorClassName() { - "DispatchingCheckImpl" - } - - /* Gets the fully qualified name of the default validator class. */ - def String qualifiedDefaultValidatorClassName() { - "com.avaloq.tools.ddk.check.runtime.issue." + defaultValidatorClassName - } - - /* Gets the prefix for the context id (used in contexts.xml) */ - def getContextIdPrefix(QualifiedName catalog){ - catalog.lastSegment.toString.toLowerCase + "_" // TODO make context id use fully qualified catalog names - } - - /* Gets the full context id (used in contexts.xml) */ - def String getContextId(Check check) { - val catalog = check.parent(typeof (CheckCatalog)) - nameProvider.apply(catalog).contextIdPrefix + check.label.replaceAll(" ", "").replaceAll("\"", "").replaceAll("'", "").toLowerCase - } - - /* Gets the full context id (used in contexts.xml) */ - def String getContextId(Category category) { - val catalog = category.parent(typeof (CheckCatalog)) - nameProvider.apply(catalog).contextIdPrefix + category.label.replaceAll(" ", "").replaceAll("\"", "").replaceAll("'", "").toLowerCase - } - -} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java new file mode 100644 index 0000000000..16e81a8091 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java @@ -0,0 +1,741 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.jvmmodel; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; + +import org.apache.commons.lang.StringEscapeUtils; +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.common.types.JvmAnnotationReference; +import org.eclipse.xtext.common.types.JvmAnnotationType; +import org.eclipse.xtext.common.types.JvmDeclaredType; +import org.eclipse.xtext.common.types.JvmField; +import org.eclipse.xtext.common.types.JvmGenericType; +import org.eclipse.xtext.common.types.JvmMember; +import org.eclipse.xtext.common.types.JvmOperation; +import org.eclipse.xtext.common.types.JvmParameterizedTypeReference; +import org.eclipse.xtext.common.types.JvmTypeReference; +import org.eclipse.xtext.common.types.JvmVisibility; +import org.eclipse.xtext.common.types.TypesFactory; +import org.eclipse.xtext.diagnostics.Severity; +import org.eclipse.xtext.util.Strings; +import org.eclipse.xtext.validation.CheckMode; +import org.eclipse.xtext.validation.CheckType; +import org.eclipse.xtext.validation.EObjectDiagnosticImpl; +import org.eclipse.xtext.xbase.XFeatureCall; +import org.eclipse.xtext.xbase.XMemberFeatureCall; +import org.eclipse.xtext.xbase.XbaseFactory; +import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable; +import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer; +import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor; +import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.ListExtensions; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; +import org.eclipse.xtext.xbase.lib.StringExtensions; + +import com.avaloq.tools.ddk.check.CheckConstants; +import com.avaloq.tools.ddk.check.check.Category; +import com.avaloq.tools.ddk.check.check.Check; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.Context; +import com.avaloq.tools.ddk.check.check.FormalParameter; +import com.avaloq.tools.ddk.check.check.Implementation; +import com.avaloq.tools.ddk.check.check.Member; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import com.avaloq.tools.ddk.check.generator.CheckGeneratorExtensions; +import com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming; +import com.avaloq.tools.ddk.check.generator.CheckPropertiesGenerator; +import com.avaloq.tools.ddk.check.resource.CheckLocationInFileProvider; +import com.avaloq.tools.ddk.check.runtime.configuration.ICheckConfigurationStoreService; +import com.avaloq.tools.ddk.check.runtime.issue.AbstractIssue; +import com.avaloq.tools.ddk.check.runtime.issue.DispatchingCheckImpl; +import com.avaloq.tools.ddk.check.runtime.issue.DispatchingCheckImpl.DiagnosticCollector; +import com.avaloq.tools.ddk.check.runtime.issue.SeverityKind; +import com.avaloq.tools.ddk.check.validation.IssueCodes; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import com.google.inject.Singleton; + + +/** + *

Infers a JVM model from the source model.

+ * + *

The JVM model should contain all elements that would appear in the Java code + * which is generated from the source model. Other models link against the JVM model rather than the source model.

+ */ +public class CheckJvmModelInferrer extends AbstractModelInferrer { + + @Inject + private TypesFactory typesFactory; + + @Inject + private CheckLocationInFileProvider locationInFileProvider; + + @Inject + private CheckGeneratorExtensions _checkGeneratorExtensions; + + @Inject + private CheckGeneratorNaming _checkGeneratorNaming; + + @Inject + private JvmTypesBuilder _jvmTypesBuilder; + + protected void _infer(CheckCatalog catalog, IJvmDeclaredTypeAcceptor acceptor, boolean preIndexingPhase) { + // The xbase automatic scoping mechanism (typeRef()) cannot find secondary classes in the same resource. It can + // only find indexed resources (either in the JDT index or in the xtext index). However, we'll initialize the + // JVM validator class before the resource gets indexed, so the JVM catalog class cannot be found yet when we + // create the injection in the validator. Therefore, remember the class here directly, and set it directly + // in the validator, completely bypassing any scoping. + if (preIndexingPhase) { + return; + } + JvmGenericType catalogClass = _jvmTypesBuilder.toClass(catalog, _checkGeneratorNaming.qualifiedCatalogClassName(catalog)); + JvmTypeReference issueCodeToLabelMapTypeRef = _typeReferenceBuilder.typeRef(ImmutableMap.class, _typeReferenceBuilder.typeRef(String.class), _typeReferenceBuilder.typeRef(String.class)); + acceptor.accept(catalogClass, (JvmGenericType it) -> { + JvmTypeReference parentType = checkedTypeRef(catalog, AbstractIssue.class); + if (parentType != null) { + it.getSuperTypes().add(parentType); + } + Iterables.addAll(it.getAnnotations(), createAnnotation(checkedTypeRef(catalog, Singleton.class), (JvmAnnotationReference it1) -> { + })); + _jvmTypesBuilder.setDocumentation(it, "Issues for " + catalog.getName() + "."); + Iterables.addAll(it.getMembers(), createInjectedField(catalog, "checkConfigurationStoreService", checkedTypeRef(catalog, ICheckConfigurationStoreService.class))); + + // Create map of issue code to label and associated getter + it.getMembers().add(_jvmTypesBuilder.toField(catalog, _checkGeneratorNaming.issueCodeToLabelMapFieldName(), issueCodeToLabelMapTypeRef, (JvmField it1) -> { + it1.setStatic(true); + it1.setFinal(true); + // Get all issue codes and labels + Iterable issues = _checkGeneratorExtensions.checkAndImplementationIssues(catalog); + // Use a TreeMap to eliminate duplicates, + // and also to sort by qualified issue code name so autogenerated files are more readable and less prone to spurious ordering changes. + // Do this when compiling the Check, to avoid discovering duplicates at runtime. + TreeMap sortedUniqueQualifiedIssueCodeNamesAndLabels = new TreeMap(); + for (XIssueExpression issue : issues) { + String qualifiedIssueCodeName = _checkGeneratorExtensions.qualifiedIssueCodeName(issue); + String issueLabel = StringEscapeUtils.escapeJava(_checkGeneratorExtensions.issueLabel(issue)); + String existingIssueLabel = sortedUniqueQualifiedIssueCodeNamesAndLabels.putIfAbsent(qualifiedIssueCodeName, issueLabel); + if (null != existingIssueLabel && !Objects.equals(issueLabel, existingIssueLabel)) { + // This qualified issue code name is already in the map, with a different label. Fail the build. + throw new IllegalArgumentException("Multiple issues found with qualified issue code name: " + qualifiedIssueCodeName); + } + } + _jvmTypesBuilder.setInitializer(it1, (ITreeAppendable appendable) -> { + StringBuilder sb = new StringBuilder(); + sb.append(ImmutableMap.class.getSimpleName()).append(".<").append(String.class.getSimpleName()).append(", ").append(String.class.getSimpleName()).append(">builderWithExpectedSize(").append(sortedUniqueQualifiedIssueCodeNamesAndLabels.entrySet().size()).append(")\n"); + for (Map.Entry qualifiedIssueCodeNameAndLabel : sortedUniqueQualifiedIssueCodeNamesAndLabels.entrySet()) { + sb.append(" .put(").append(qualifiedIssueCodeNameAndLabel.getKey()).append(", \"").append(qualifiedIssueCodeNameAndLabel.getValue()).append("\")\n"); + } + sb.append(" .build()\n"); + appendable.append(sb.toString()); + }); + })); + it.getMembers().add(_jvmTypesBuilder.toMethod(catalog, _checkGeneratorNaming.fieldGetterName(_checkGeneratorNaming.issueCodeToLabelMapFieldName()), issueCodeToLabelMapTypeRef, (JvmOperation it1) -> { + _jvmTypesBuilder.setDocumentation(it1, "Get map of issue code to label for " + catalog.getName() + ".\n\n@returns Map of issue code to label for " + catalog.getName() + ".\n"); + it1.setStatic(true); + it1.setFinal(true); + _jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { + appendable.append("return " + _checkGeneratorNaming.issueCodeToLabelMapFieldName() + ";"); + }); + })); + + Iterables.addAll(it.getMembers(), IterableExtensions.filterNull(Iterables.concat(ListExtensions.>map(catalog.getAllChecks(), (Check c) -> createIssue(catalog, c))))); + }); + + acceptor.accept(_jvmTypesBuilder.toClass(catalog, _checkGeneratorNaming.qualifiedValidatorClassName(catalog)), (JvmGenericType it) -> { + JvmTypeReference parentType = checkedTypeRef(catalog, DispatchingCheckImpl.class); + if (parentType != null) { + it.getSuperTypes().add(parentType); + } + // Constructor will be added automatically. + _jvmTypesBuilder.setDocumentation(it, "Validator for " + catalog.getName() + "."); + // Create catalog injections + Iterables.addAll(it.getMembers(), createInjectedField(catalog, _checkGeneratorNaming.catalogInstanceName(catalog), _typeReferenceBuilder.typeRef(catalogClass))); + // Create fields + Iterables.addAll(it.getMembers(), ListExtensions.map(catalog.getMembers(), (Member m) -> _jvmTypesBuilder.toField(m, m.getName(), m.getType(), (JvmField it1) -> { + _jvmTypesBuilder.setInitializer(it1, m.getValue()); + _jvmTypesBuilder.addAnnotations(it1, m.getAnnotations()); + }))); + // Create catalog name function + it.getMembers().add(_jvmTypesBuilder.toMethod(catalog, "getQualifiedCatalogName", _typeReferenceBuilder.typeRef(String.class), (JvmOperation it1) -> { + _jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { + appendable.append("return \"" + catalog.getPackageName() + "." + catalog.getName() + "\";"); + }); + })); + + // Create getter for map of issue code to label + it.getMembers().add(_jvmTypesBuilder.toMethod(catalog, _checkGeneratorNaming.fieldGetterName(_checkGeneratorNaming.issueCodeToLabelMapFieldName()), issueCodeToLabelMapTypeRef, (JvmOperation it1) -> { + it1.setFinal(true); + _jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { + appendable.append("return " + _checkGeneratorNaming.catalogClassName(catalog) + "." + _checkGeneratorNaming.fieldGetterName(_checkGeneratorNaming.issueCodeToLabelMapFieldName()) + "();"); + }); + })); + + it.getMembers().add(createDispatcherMethod(catalog)); + + // Create methods for contexts in checks + EList checks = catalog.getChecks(); + Iterable flattenedCatChecks = Iterables.concat(ListExtensions.>map(catalog.getCategories(), (Category cat) -> cat.getChecks())); + Iterable allChecks = Iterables.concat(checks, flattenedCatChecks); + Iterables.addAll(it.getMembers(), Iterables.concat(IterableExtensions.>map(allChecks, (Check chk) -> createCheck(chk)))); + // Create methods for stand-alone context implementations + Iterables.addAll(it.getMembers(), IterableExtensions.filterNull(ListExtensions.map(catalog.getImplementations(), (Implementation impl) -> createCheckMethod(impl.getContext())))); + }); + acceptor.accept(_jvmTypesBuilder.toClass(catalog, _checkGeneratorNaming.qualifiedPreferenceInitializerClassName(catalog)), (JvmGenericType it) -> { + JvmTypeReference parentType = checkedTypeRef(catalog, AbstractPreferenceInitializer.class); + if (parentType != null) { + it.getSuperTypes().add(parentType); + } + it.getMembers().add(_jvmTypesBuilder.toField(catalog, "RUNTIME_NODE_NAME", _typeReferenceBuilder.typeRef(String.class), (JvmField it1) -> { + it1.setStatic(true); + it1.setFinal(true); + _jvmTypesBuilder.setInitializer(it1, (ITreeAppendable appendable) -> { + appendable.append("\"" + _checkGeneratorExtensions.bundleName(catalog) + "\""); + }); + })); + Iterables.addAll(it.getMembers(), createFormalParameterFields(catalog)); + Iterables.addAll(it.getMembers(), createPreferenceInitializerMethods(catalog)); + }); + } + + private JvmOperation createDispatcherMethod(CheckCatalog catalog) { + JvmTypeReference objectBaseJavaTypeRef = checkedTypeRef(catalog, EObject.class); + return _jvmTypesBuilder.toMethod(catalog, "validate", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + it.setVisibility(JvmVisibility.PUBLIC); + it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "checkMode", checkedTypeRef(catalog, CheckMode.class))); + it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "object", objectBaseJavaTypeRef)); + it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "diagnosticCollector", checkedTypeRef(catalog, DiagnosticCollector.class))); + Iterables.addAll(it.getAnnotations(), createAnnotation(checkedTypeRef(catalog, Override.class), (JvmAnnotationReference it1) -> { + })); + _jvmTypesBuilder.setBody(it, (ITreeAppendable out) -> { + emitDispatcherMethodBody(out, catalog, objectBaseJavaTypeRef); + }); + }); + } + + private void emitDispatcherMethodBody(ITreeAppendable out, CheckCatalog catalog, JvmTypeReference objectBaseJavaTypeRef) { + /* A catalog may contain both Check and Implementation objects, + * which in turn may contain Context objects. + * Categories may optionally be used for grouping checks, and + * we can include categorized checks by using getAllChecks(). + * We only consider Context objects with a typed contextVariable. + */ + Iterable checkContexts = Iterables.concat(ListExtensions.>map(catalog.getAllChecks(), (Check chk) -> chk.getContexts())); + Iterable implContexts = IterableExtensions.filterNull(ListExtensions.map(catalog.getImplementations(), (Implementation impl) -> impl.getContext())); + Iterable allContexts = IterableExtensions.filter(Iterables.concat(checkContexts, implContexts), (Context ctx) -> { + JvmTypeReference type = null; + if (ctx.getContextVariable() != null) { + type = ctx.getContextVariable().getType(); + } + return type != null; + }); + + /* Contexts grouped by CheckType. + * We use an OrderedMap for deterministic ordering of check type checks. + * For Context objects we retain their order of appearance, apart from groupings. + */ + TreeMap> contextsByCheckType = new TreeMap>(); + for (Context context : allContexts) { + contextsByCheckType.compute(_checkGeneratorExtensions.checkType(context), (CheckType k, List lst) -> lst != null ? lst : new ArrayList()).add(context); + } + + String baseTypeName = objectBaseJavaTypeRef.getQualifiedName(); + + for (Iterator>> iterator = contextsByCheckType.entrySet().iterator(); iterator.hasNext();) { + Map.Entry> entry = iterator.next(); + String checkType = "CheckType." + entry.getKey(); + + out.append("if (checkMode.shouldCheck(" + checkType + ")) {"); + out.increaseIndentation(); + out.newLine(); + out.append("diagnosticCollector.setCurrentCheckType(" + checkType + ");"); + emitInstanceOfConditionals(out, entry.getValue(), catalog, baseTypeName); // with preceding newline for each + out.decreaseIndentation(); + out.newLine(); + out.append("}"); + if (iterator.hasNext()) { // not at method body end + out.newLine(); // separator between mode checks + } + } + } + + private void emitInstanceOfConditionals(ITreeAppendable out, List contexts, CheckCatalog catalog, String baseTypeName) { + /* Contexts grouped by fully qualified variable type name, + * otherwise in order of appearance. + */ + TreeMap> contextsByVarType = new TreeMap>(); + for (Context context : contexts) { + contextsByVarType.compute(context.getContextVariable().getType().getQualifiedName(), + (String k, List lst) -> lst != null ? lst : new ArrayList() + ).add(context); + } + + /* Ordering for context variable type checks. */ + List contextVarTypes = ListExtensions.map(contexts, (Context x) -> x.getContextVariable().getType()); + InstanceOfCheckOrderer.Forest forest = InstanceOfCheckOrderer.orderTypes(contextVarTypes); + + emitInstanceOfTree(out, forest, null, contextsByVarType, catalog, baseTypeName, 0); + } + + private void emitInstanceOfTree(ITreeAppendable out, InstanceOfCheckOrderer.Forest forest, String node, Map> contextsByVarType, CheckCatalog catalog, String baseTypeName, int level) { + if (node != null) { + String typeName = node; + if (Objects.equals(typeName, baseTypeName)) { + typeName = null; + } + String varName; + if (typeName == null) { + varName = "object"; + } else { + varName = "castObject" + (level > 1 ? Integer.toString(level) : ""); + } + + out.newLine(); + StringBuilder sb = new StringBuilder(); + if (typeName != null) { + sb.append("if (object instanceof final ").append(typeName).append(" ").append(varName).append(") "); + } + sb.append("{"); + out.append(sb.toString()); + out.increaseIndentation(); + + List contexts = contextsByVarType.get(node); + for (Context context : contexts) { + emitCheckMethodCall(out, varName, context, catalog); // with preceding newline + } + } + + Collection subTypes = forest.getSubTypes(node); + for (String child : subTypes) { + emitInstanceOfTree(out, forest, child, contextsByVarType, catalog, baseTypeName, level + 1); + } + + if (node != null) { + out.decreaseIndentation(); + out.newLine(); + out.append("}"); + } + } + + private void emitCheckMethodCall(ITreeAppendable out, String varName, Context context, CheckCatalog catalog) { + String methodName = generateContextMethodName(context); + String jMethodName = toJavaLiteral(methodName); + String qMethodName = toJavaLiteral(catalog.getName(), methodName); + + out.newLine(); + out.append("validate(" + jMethodName + ", " + qMethodName + ", object,\n () -> " + methodName + "(" + varName + ", diagnosticCollector), diagnosticCollector);"); + } + + private String toJavaLiteral(String... strings) { + return "\"" + Strings.convertToJavaString(String.join(".", strings)) + "\""; + } + + private Iterable createInjectedField(CheckCatalog context, String fieldName, JvmTypeReference type) { + // Generate @Inject private typeName fieldName; + if (type == null) { + return Collections.emptyList(); + } + JvmField field = typesFactory.createJvmField(); + field.setSimpleName(fieldName); + field.setVisibility(JvmVisibility.PRIVATE); + field.setType(_jvmTypesBuilder.cloneWithProxies(type)); + Iterables.addAll(field.getAnnotations(), createAnnotation(checkedTypeRef(context, Inject.class), (JvmAnnotationReference it) -> { + })); + return Collections.singleton(field); + } + + private Iterable createCheck(Check chk) { + // If we don't have FormalParameters, there's no need to do all this song and dance with inner classes. + if (chk.getFormalParameters().isEmpty()) { + return ListExtensions.map(chk.getContexts(), (Context ctx) -> (JvmMember) createCheckMethod(ctx)); + } else { + return createCheckWithParameters(chk); + } + } + + private Iterable createCheckWithParameters(Check chk) { + // Generate an inner class, plus a field holding an instance of that class. + // Put the formal parameters into that class as fields. + // For each check context, generate a run method. + // For each check context, generate an annotated check method outside to call the appropriate run method. + // This is the only way I found to make those formal parameters visible in the check constraints... + // The generated Java looks a bit strange, because we suppress actually generating these fields, as we + // don't use them; we only need them for scoping based on this inferred model. + List newMembers = Lists.newArrayList(); + // First the class + JvmGenericType checkClass = _jvmTypesBuilder.toClass(chk, StringExtensions.toFirstUpper(chk.getName()) + "Class", (JvmGenericType it) -> { + it.getSuperTypes().add(_typeReferenceBuilder.typeRef(Object.class)); + it.setVisibility(JvmVisibility.PRIVATE); + // Add a fields for the parameters, so that they can be linked. We suppress generation of these fields in the generator, + // and replace all references by calls to the getter function in the catalog. + Iterables.addAll(it.getMembers(), IterableExtensions.map(IterableExtensions.filter(chk.getFormalParameters(), (FormalParameter f) -> f.getType() != null && f.getName() != null), (FormalParameter f) -> _jvmTypesBuilder.toField(f, f.getName(), f.getType(), (JvmField it1) -> { + it1.setFinal(true); + }))); + }); + newMembers.add(checkClass); + newMembers.add(_jvmTypesBuilder.toField(chk, StringExtensions.toFirstLower(chk.getName()) + "Impl", _typeReferenceBuilder.typeRef(checkClass), (JvmField it) -> { + _jvmTypesBuilder.setInitializer(it, (ITreeAppendable appendable) -> { + appendable.append("new " + checkClass.getSimpleName() + "()"); + }); + })); + Iterables.addAll(newMembers, IterableExtensions.filterNull(ListExtensions.map(chk.getContexts(), (Context ctx) -> createCheckCaller(ctx, chk)))); + // If we create these above in the class initializer, the types of the context variables somehow are not resolved yet. + Iterables.addAll(checkClass.getMembers(), IterableExtensions.filterNull(ListExtensions.map(chk.getContexts(), (Context ctx) -> createCheckExecution(ctx)))); + return newMembers; + } + + private JvmOperation createCheckExecution(Context ctx) { + if (ctx == null || ctx.getContextVariable() == null) { + return null; + } + JvmTypeReference ctxVarType = ctx.getContextVariable().getType(); + String simpleName = null; + if (ctxVarType != null) { + simpleName = ctxVarType.getSimpleName(); + } + String functionName = "run" + StringExtensions.toFirstUpper(simpleName); + return _jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + String paramName = ctx.getContextVariable().getName() == null ? CheckConstants.IT : ctx.getContextVariable().getName(); + it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, paramName, ctx.getContextVariable().getType())); + it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); + _jvmTypesBuilder.setBody(it, ctx.getConstraint()); + }); + } + + private Iterable createCheckAnnotation(Context ctx) { + JvmTypeReference checkTypeTypeRef = checkedTypeRef(ctx, CheckType.class); + if (checkTypeTypeRef == null) { + return Collections.emptyList(); + } + XFeatureCall featureCall = XbaseFactory.eINSTANCE.createXFeatureCall(); + featureCall.setFeature(checkTypeTypeRef.getType()); + featureCall.setTypeLiteral(true); + XMemberFeatureCall memberCall = XbaseFactory.eINSTANCE.createXMemberFeatureCall(); + memberCall.setMemberCallTarget(featureCall); + // The grammar doesn't use the CheckType constants directly... + String name = _checkGeneratorExtensions.checkTypeQName(ctx); + int i = name.lastIndexOf("."); + if (i >= 0) { + name = name.substring(i + 1); + } + memberCall.setFeature(IterableExtensions.head(((JvmDeclaredType) checkTypeTypeRef.getType()).findAllFeaturesByName(name))); + + // memberCall needs to belong to a resource. + // We add it as a separate model to the context's resource. + ctx.eResource().getContents().add(memberCall); + + return createAnnotation(checkedTypeRef(ctx, org.eclipse.xtext.validation.Check.class), (JvmAnnotationReference it) -> { + it.getExplicitValues().add(_jvmTypesBuilder.toJvmAnnotationValue(memberCall)); + }); + } + + private JvmOperation createCheckCaller(Context ctx, Check chk) { + if (ctx == null || ctx.getContextVariable() == null) { + return null; + } + JvmTypeReference ctxVarType = ctx.getContextVariable().getType(); + String simpleName = null; + if (ctxVarType != null) { + simpleName = ctxVarType.getSimpleName(); + } + String functionName = StringExtensions.toFirstLower(chk.getName()) + simpleName; + // To make the formal parameter visible, we have to generate quite a bit... I see no way to get the XVariableDeclaration for them + // into the XBlockExpression of ctx.constraint. Just copying them doesn't work; modifies the source model! + // Therefore, we generate something new: each check becomes a local class + + return _jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, "context", ctx.getContextVariable().getType())); + it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); + Iterables.addAll(it.getAnnotations(), createCheckAnnotation(ctx)); + _jvmTypesBuilder.setDocumentation(it, functionName + "."); // Well, that's not very helpful, but it is what the old compiler did... + _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + JvmTypeReference ctxVarType1 = ctx.getContextVariable().getType(); + String simpleName1 = null; + if (ctxVarType1 != null) { + simpleName1 = ctxVarType1.getSimpleName(); + } + appendable.append(StringExtensions.toFirstLower(chk.getName()) + "Impl" + ".run" + StringExtensions.toFirstUpper(simpleName1) + "(context, diagnosticCollector);"); + }); + }); + } + + private JvmOperation createCheckMethod(Context ctx) { + // Simple case for contexts of checks that do not have formal parameters. No need to generate nested classes for these. + if (ctx == null || ctx.getContextVariable() == null) { + return null; + } + String functionName = generateContextMethodName(ctx); + + return _jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + String paramName = ctx.getContextVariable().getName() == null ? CheckConstants.IT : ctx.getContextVariable().getName(); + it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, paramName, ctx.getContextVariable().getType())); + it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); + Iterables.addAll(it.getAnnotations(), createCheckAnnotation(ctx)); + _jvmTypesBuilder.setDocumentation(it, functionName + "."); // Well, that's not very helpful, but it is what the old compiler did... + _jvmTypesBuilder.setBody(it, ctx.getConstraint()); + }); + } + + private String generateContextMethodName(Context ctx) { + EObject container = ctx.eContainer(); + String baseName; + if (container instanceof Check check) { + baseName = check.getName(); + } else if (container instanceof Implementation impl) { + baseName = impl.getName(); + } else { + baseName = null; + } + JvmTypeReference ctxVarType = ctx.getContextVariable().getType(); + String simpleName = null; + if (ctxVarType != null) { + simpleName = ctxVarType.getSimpleName(); + } + return StringExtensions.toFirstLower(baseName) + simpleName; + } + + // CheckCatalog + + private Iterable createIssue(CheckCatalog catalog, Check check) { + List members = Lists.newArrayList(); + for (FormalParameter parameter : check.getFormalParameters()) { + JvmTypeReference returnType = parameter.getType(); + if (returnType != null && !returnType.eIsProxy()) { + String returnName = returnType.getQualifiedName(); + String operation; + if (returnName != null) { + operation = switch (returnName) { + case "java.lang.Boolean" -> "getBoolean"; + case "boolean" -> "getBoolean"; + case "java.lang.Integer" -> "getInt"; + case "int" -> "getInt"; + case "java.util.List" -> "getStrings"; + case "java.util.List" -> "getBooleans"; + case "java.util.List" -> "getIntegers"; + default -> "getString"; + }; + } else { + operation = "getString"; + } + String parameterKey = CheckPropertiesGenerator.parameterKey(parameter, check); + String defaultName = "null"; + if (parameter.getRight() != null) { + defaultName = CheckGeneratorExtensions.splitCamelCase(_checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; + // Is generated into the PreferenceInitializer. Actually, since we do have it in the initializer, passing it here again + // as default value is just a safety measure if something went wrong and the property shouldn't be set. + } + String javaDefaultValue = _checkGeneratorNaming.preferenceInitializerClassName(catalog) + "." + defaultName; + members.add(_jvmTypesBuilder.toMethod(parameter, _checkGeneratorNaming.formalParameterGetterName(parameter), returnType, (JvmOperation it) -> { + _jvmTypesBuilder.setDocumentation(it, "Gets the run-time value of formal parameter " + parameter.getName() + ". The value\nreturned is either the default as defined in the check definition, or the\nconfigured value, if existing.\n\n@param context\n the context object used to determine the current project in\n order to check if a configured value exists in a project scope\n@return the run-time value of " + parameter.getName() + ""); + JvmTypeReference eObjectTypeRef = checkedTypeRef(parameter, EObject.class); + if (eObjectTypeRef != null) { + it.getParameters().add(_jvmTypesBuilder.toParameter(parameter, "context", eObjectTypeRef)); + } + _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + appendable.append("return checkConfigurationStoreService.getCheckConfigurationStore(context)." + operation + "(\"" + parameterKey + "\", " + javaDefaultValue + ");"); + }); + })); + } // end if + } // end for + members.add(_jvmTypesBuilder.toMethod(check, "get" + StringExtensions.toFirstUpper(check.getName()) + "Message", _typeReferenceBuilder.typeRef(String.class), (JvmOperation it) -> { + _jvmTypesBuilder.setDocumentation(it, CheckJvmModelInferrerUtil.GET_MESSAGE_DOCUMENTATION); + // Generate one parameter "Object... bindings" + it.setVarArgs(true); + it.getParameters().add(_jvmTypesBuilder.toParameter(check, "bindings", _jvmTypesBuilder.addArrayTypeDimension(_typeReferenceBuilder.typeRef(Object.class)))); + _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + appendable.append("return org.eclipse.osgi.util.NLS.bind(\"" + Strings.convertToJavaString(check.getMessage()) + "\", bindings);"); + }); + // TODO (minor): how to get NLS into the imports? + })); + JvmTypeReference severityType = checkedTypeRef(check, SeverityKind.class); + if (severityType != null) { + members.add(_jvmTypesBuilder.toMethod(check, "get" + StringExtensions.toFirstUpper(check.getName()) + "SeverityKind", severityType, (JvmOperation it) -> { + _jvmTypesBuilder.setDocumentation(it, "Gets the {@link SeverityKind severity kind} of check\n" + check.getLabel() + ". The severity kind returned is either the\ndefault ({@code " + check.getDefaultSeverity().name() + "}), as is set in the check definition, or the\nconfigured value, if existing.\n\n@param context\n the context object used to determine the current project in\n order to check if a configured value exists in a project scope\n@return the severity kind of this check: returns the default (" + check.getDefaultSeverity().name() + ") if\n no configuration for this check was found, else the configured\n value looked up in the configuration store"); + JvmTypeReference eObjectTypeRef = checkedTypeRef(check, EObject.class); + if (eObjectTypeRef != null) { + it.getParameters().add(_jvmTypesBuilder.toParameter(check, "context", eObjectTypeRef)); + } + _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + appendable.append("final int result = checkConfigurationStoreService.getCheckConfigurationStore(context).getInt(\"" + CheckPropertiesGenerator.checkSeverityKey(check) + "\", " + check.getDefaultSeverity().getValue() + ");\nreturn SeverityKind.values()[result];"); + }); + })); + } + return members; + } + + // PreferenceInitializer. + + private Iterable createFormalParameterFields(CheckCatalog catalog) { + // For each formal parameter, create a public static final field with a unique name derived from the formal parameter and + // set it to its right-hand side expression. We let Java evaluate this! + EList checks = catalog.getChecks(); + Iterable flattenedCatChecks = Iterables.concat(ListExtensions.>map(catalog.getCategories(), (Category cat) -> cat.getChecks())); + Iterable allChecks = Iterables.concat(checks, flattenedCatChecks); + List result = Lists.newArrayList(); + for (Check c : allChecks) { + for (FormalParameter parameter : c.getFormalParameters()) { + if (parameter.getType() != null && parameter.getRight() != null) { + String defaultName = CheckGeneratorExtensions.splitCamelCase(_checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; + result.add(_jvmTypesBuilder.toField(parameter, defaultName, parameter.getType(), (JvmField it) -> { + it.setVisibility(JvmVisibility.PUBLIC); + it.setFinal(true); + it.setStatic(true); + _jvmTypesBuilder.setInitializer(it, parameter.getRight()); + })); + } + } + } + return result; + } + + private Iterable createPreferenceInitializerMethods(CheckCatalog catalog) { + JvmTypeReference prefStore = checkedTypeRef(catalog, IEclipsePreferences.class); + List result = Lists.newArrayList(); + + if (prefStore != null) { + result.add(_jvmTypesBuilder.toMethod(catalog, "initializeDefaultPreferences", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + Iterables.addAll(it.getAnnotations(), createAnnotation(checkedTypeRef(catalog, Override.class), (JvmAnnotationReference it1) -> { + })); + it.setVisibility(JvmVisibility.PUBLIC); + _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + appendable.append("IEclipsePreferences preferences = org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE.getNode(RUNTIME_NODE_NAME);\n\ninitializeSeverities(preferences);\ninitializeFormalParameters(preferences);"); + }); + })); + EList checks = catalog.getChecks(); + Iterable flattenedCatChecks = Iterables.concat(ListExtensions.>map(catalog.getCategories(), (Category cat) -> cat.getChecks())); + Iterable allChecks = Iterables.concat(checks, flattenedCatChecks); + result.add(_jvmTypesBuilder.toMethod(catalog, "initializeSeverities", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + it.setVisibility(JvmVisibility.PRIVATE); + it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "preferences", prefStore)); + _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + StringBuilder sb = new StringBuilder(); + for (Check c : allChecks) { + sb.append("preferences.putInt(\"").append(CheckPropertiesGenerator.checkSeverityKey(c)).append("\", ").append(c.getDefaultSeverity().getValue()).append(");\n"); + } + appendable.append(sb.toString()); + }); + })); + result.add(_jvmTypesBuilder.toMethod(catalog, "initializeFormalParameters", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + it.setVisibility(JvmVisibility.PRIVATE); + it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "preferences", _jvmTypesBuilder.cloneWithProxies(prefStore))); + _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + for (Check c : allChecks) { + for (FormalParameter parameter : c.getFormalParameters()) { + if (parameter.getRight() != null) { + String key = CheckPropertiesGenerator.parameterKey(parameter, c); + String defaultFieldName = CheckGeneratorExtensions.splitCamelCase(_checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; + JvmTypeReference jvmType = parameter.getType(); + String typeName = jvmType.getQualifiedName(); + if (typeName != null && typeName.startsWith("java.util.List<")) { + // Marshal lists. + EList args = ((JvmParameterizedTypeReference) jvmType).getArguments(); + if (args != null && args.size() == 1) { + String baseTypeName = IterableExtensions.head(args).getSimpleName(); + appendable.append("preferences.put(\"" + key + "\", com.avaloq.tools.ddk.check.runtime.configuration.CheckPreferencesHelper.marshal" + baseTypeName + "s(" + defaultFieldName + "));\n"); + } else { + appendable.append("// Found " + key + " with " + typeName + "\n"); + } + } else { + String operation; + if (typeName != null) { + operation = switch (typeName) { + case "java.lang.Boolean" -> "putBoolean"; + case "boolean" -> "putBoolean"; + case "java.lang.Integer" -> "putInt"; + case "int" -> "putInt"; + default -> "put"; + }; + } else { + operation = "put"; + } + appendable.append("preferences." + operation + "(\"" + key + "\", " + defaultFieldName + ");\n"); + } + } + } + } + }); + })); + } + return result; + } + + private Iterable createAnnotation(JvmTypeReference typeRef, Procedure1 initializer) { + if (typeRef == null) { + return Collections.emptyList(); + } + + JvmAnnotationReference annotation = typesFactory.createJvmAnnotationReference(); + annotation.setAnnotation((JvmAnnotationType) typeRef.getType()); + Objects.requireNonNull(initializer, "Initializer is null").apply(annotation); + + return Collections.singletonList(annotation); + } + + // Error handling etc. + + private void createError(String message, EObject context, EStructuralFeature feature) { + Resource rsc = context.eResource(); + if (rsc != null) { + EStructuralFeature f = feature; + if (f == null) { + f = locationInFileProvider.getIdentifierFeature(context); + } + rsc.getErrors().add(new EObjectDiagnosticImpl(Severity.ERROR, IssueCodes.INFERRER_ERROR, "Check compiler: " + message, context, f, -1, null)); + } + } + + private void createTypeNotFoundError(String name, EObject context) { + createError("Type " + name + " not found; check project setup (missing required bundle?)", context, null); + } + + private JvmTypeReference checkedTypeRef(EObject context, Class clazz) { + if (clazz == null) { + createTypeNotFoundError("", context); + return null; + } + JvmTypeReference result = _typeReferenceBuilder.typeRef(clazz); + if (result == null || result.getType() == null) { + createTypeNotFoundError(clazz.getName(), context); + return null; + } + return result; + } + + public void infer(EObject catalog, IJvmDeclaredTypeAcceptor acceptor, boolean preIndexingPhase) { + if (catalog instanceof CheckCatalog checkCatalog) { + _infer(checkCatalog, acceptor, preIndexingPhase); + return; + } else if (catalog != null) { + _infer(catalog, acceptor, preIndexingPhase); + return; + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(catalog, acceptor, preIndexingPhase).toString()); + } + } +} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.xtend deleted file mode 100644 index 56af88da6c..0000000000 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.xtend +++ /dev/null @@ -1,646 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.jvmmodel - -import com.avaloq.tools.ddk.check.CheckConstants -import com.avaloq.tools.ddk.check.check.Check -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.check.Context -import com.avaloq.tools.ddk.check.check.FormalParameter -import com.avaloq.tools.ddk.check.check.Implementation -import com.avaloq.tools.ddk.check.generator.CheckGeneratorExtensions -import com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming -import com.avaloq.tools.ddk.check.generator.CheckPropertiesGenerator -import com.avaloq.tools.ddk.check.resource.CheckLocationInFileProvider -import com.avaloq.tools.ddk.check.runtime.configuration.ICheckConfigurationStoreService -import com.avaloq.tools.ddk.check.runtime.issue.AbstractIssue -import com.avaloq.tools.ddk.check.runtime.issue.DispatchingCheckImpl -import com.avaloq.tools.ddk.check.runtime.issue.DispatchingCheckImpl.DiagnosticCollector -import com.avaloq.tools.ddk.check.runtime.issue.SeverityKind -import com.avaloq.tools.ddk.check.validation.IssueCodes -import com.google.common.collect.ImmutableMap -import com.google.common.collect.Lists -import com.google.inject.Inject -import com.google.inject.Singleton -import java.util.ArrayList -import java.util.Collections -import java.util.List -import java.util.Map -import java.util.Objects -import java.util.TreeMap -import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer -import org.eclipse.core.runtime.preferences.IEclipsePreferences -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.EStructuralFeature -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.common.types.JvmAnnotationReference -import org.eclipse.xtext.common.types.JvmAnnotationType -import org.eclipse.xtext.common.types.JvmDeclaredType -import org.eclipse.xtext.common.types.JvmField -import org.eclipse.xtext.common.types.JvmMember -import org.eclipse.xtext.common.types.JvmOperation -import org.eclipse.xtext.common.types.JvmParameterizedTypeReference -import org.eclipse.xtext.common.types.JvmTypeReference -import org.eclipse.xtext.common.types.JvmVisibility -import org.eclipse.xtext.common.types.TypesFactory -import org.eclipse.xtext.diagnostics.Severity -import org.eclipse.xtext.util.Strings -import org.eclipse.xtext.validation.CheckMode -import org.eclipse.xtext.validation.CheckType -import org.eclipse.xtext.validation.EObjectDiagnosticImpl -import org.eclipse.xtext.xbase.XFeatureCall -import org.eclipse.xtext.xbase.XMemberFeatureCall -import org.eclipse.xtext.xbase.XbaseFactory -import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable -import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer -import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor -import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder -import org.eclipse.xtext.xbase.lib.Procedures.Procedure1 - -import static extension com.avaloq.tools.ddk.check.generator.CheckGeneratorExtensions.* -import static extension org.apache.commons.lang.StringEscapeUtils.escapeJava - -/** - *

Infers a JVM model from the source model.

- * - *

The JVM model should contain all elements that would appear in the Java code - * which is generated from the source model. Other models link against the JVM model rather than the source model.

- */ -class CheckJvmModelInferrer extends AbstractModelInferrer { - - @Inject TypesFactory typesFactory - @Inject CheckLocationInFileProvider locationInFileProvider - - @Inject extension CheckGeneratorExtensions - @Inject extension CheckGeneratorNaming - @Inject extension JvmTypesBuilder - - def dispatch infer(CheckCatalog catalog, IJvmDeclaredTypeAcceptor acceptor, boolean preIndexingPhase) { - // The xbase automatic scoping mechanism (typeRef()) cannot find secondary classes in the same resource. It can - // only find indexed resources (either in the JDT index or in the xtext index). However, we'll initialize the - // JVM validator class before the resource gets indexed, so the JVM catalog class cannot be found yet when we - // create the injection in the validator. Therefore, remember the class here directly, and set it directly - // in the validator, completely bypassing any scoping. - if (preIndexingPhase) return; - val catalogClass = catalog.toClass(catalog.qualifiedCatalogClassName); - val issueCodeToLabelMapTypeRef = typeRef(ImmutableMap, typeRef(String), typeRef(String)) - acceptor.accept(catalogClass, [ - val parentType = checkedTypeRef(catalog, typeof(AbstractIssue)); - if (parentType !== null) { - superTypes += parentType; - } - annotations += createAnnotation(checkedTypeRef(catalog, typeof(Singleton)), []) - documentation = '''Issues for «catalog.name».'''; - members += createInjectedField(catalog, 'checkConfigurationStoreService', checkedTypeRef(catalog, typeof(ICheckConfigurationStoreService))); - - // Create map of issue code to label and associated getter - members += catalog.toField(issueCodeToLabelMapFieldName, issueCodeToLabelMapTypeRef, [ - static = true - final = true - // Get all issue codes and labels - val issues = catalog.checkAndImplementationIssues - // Use a TreeMap to eliminate duplicates, - // and also to sort by qualified issue code name so autogenerated files are more readable and less prone to spurious ordering changes. - // Do this when compiling the Check, to avoid discovering duplicates at runtime. - val sortedUniqueQualifiedIssueCodeNamesAndLabels = new TreeMap(); - for (issue : issues) { - val qualifiedIssueCodeName = issue.qualifiedIssueCodeName(); - val issueLabel = issue.issueLabel().escapeJava; - val existingIssueLabel = sortedUniqueQualifiedIssueCodeNamesAndLabels.putIfAbsent(qualifiedIssueCodeName, issueLabel); - if (null !== existingIssueLabel && issueLabel != existingIssueLabel) { - // This qualified issue code name is already in the map, with a different label. Fail the build. - throw new IllegalArgumentException('''Multiple issues found with qualified issue code name: «qualifiedIssueCodeName»''') - } - } - initializer = [append(''' - «ImmutableMap.simpleName».<«String.simpleName», «String.simpleName»>builderWithExpectedSize(«sortedUniqueQualifiedIssueCodeNamesAndLabels.entrySet.size») - «FOR qualifiedIssueCodeNameAndLabel : sortedUniqueQualifiedIssueCodeNamesAndLabels.entrySet» - .put(«qualifiedIssueCodeNameAndLabel.key», "«qualifiedIssueCodeNameAndLabel.value»") - «ENDFOR» - .build() - ''')] - ]) - members += catalog.toMethod(issueCodeToLabelMapFieldName.fieldGetterName, issueCodeToLabelMapTypeRef, [ - documentation = ''' - Get map of issue code to label for «catalog.name». - - @returns Map of issue code to label for «catalog.name». - '''; - static = true - final = true - body = '''return «issueCodeToLabelMapFieldName»;''' - ]) - - members += catalog.allChecks.map(c|createIssue(catalog, c)).flatten.filterNull; - ]); - - acceptor.accept(catalog.toClass(catalog.qualifiedValidatorClassName), [ - val parentType = checkedTypeRef(catalog, typeof(DispatchingCheckImpl)); - if (parentType !== null) { - superTypes += parentType; - } - // Constructor will be added automatically. - documentation = ''' - Validator for «catalog.name».'''; - // Create catalog injections - members += createInjectedField(catalog, catalog.catalogInstanceName, typeRef(catalogClass)); - // Create fields - members += catalog.members.map(m|m.toField(m.name, m.type) [initializer = m.value; it.addAnnotations(m.annotations);]); - // Create catalog name function - members += catalog.toMethod('getQualifiedCatalogName', typeRef(typeof(String))) [ - body = [append('''return "«catalog.packageName».«catalog.name»";''')]; - ]; - - // Create getter for map of issue code to label - members += catalog.toMethod(issueCodeToLabelMapFieldName.fieldGetterName, issueCodeToLabelMapTypeRef, [ - final = true - body = '''return «catalog.catalogClassName».«issueCodeToLabelMapFieldName.fieldGetterName»();''' - ]) - - members += createDispatcherMethod(catalog); - - // Create methods for contexts in checks - val allChecks = catalog.checks + catalog.categories.map(cat|cat.checks).flatten; - members += allChecks.map(chk|createCheck(chk)).flatten; - // Create methods for stand-alone context implementations - members += catalog.implementations.map(impl|createCheckMethod(impl.context)).filterNull; - ]); - acceptor.accept(catalog.toClass(catalog.qualifiedPreferenceInitializerClassName), [ - val parentType = checkedTypeRef(catalog, typeof(AbstractPreferenceInitializer)); - if (parentType !== null) { - superTypes += parentType; - } - members += catalog.toField('RUNTIME_NODE_NAME', typeRef(typeof(String))) [ - static = true; - final = true; - initializer = [append('"' + catalog.bundleName + '"')]; - ]; - members += createFormalParameterFields(catalog); - members += createPreferenceInitializerMethods(catalog); - ]); - } - - private def JvmOperation createDispatcherMethod(CheckCatalog catalog) { - val objectBaseJavaTypeRef = checkedTypeRef(catalog, EObject); - return catalog.toMethod("validate", typeRef("void"), [ - visibility = JvmVisibility::PUBLIC; - parameters += catalog.toParameter("checkMode", checkedTypeRef(catalog, CheckMode)); - parameters += catalog.toParameter("object", objectBaseJavaTypeRef); - parameters += catalog.toParameter("diagnosticCollector", checkedTypeRef(catalog, DiagnosticCollector)); - annotations += createAnnotation(checkedTypeRef(catalog, typeof(Override)), []); - body = [out | emitDispatcherMethodBody(out, catalog, objectBaseJavaTypeRef)]; - ]); - } - - private def void emitDispatcherMethodBody(ITreeAppendable out, CheckCatalog catalog, JvmTypeReference objectBaseJavaTypeRef) { - /* A catalog may contain both Check and Implementation objects, - * which in turn may contain Context objects. - * Categories may optionally be used for grouping checks, and - * we can include categorized checks by using getAllChecks(). - * We only consider Context objects with a typed contextVariable. - */ - val allContexts = (catalog.allChecks.map(chk | chk.contexts).flatten + - catalog.implementations.map(impl | impl.context).filterNull) - .filter(ctx | ctx.contextVariable?.type !== null); - - /* Contexts grouped by CheckType. - * We use an OrderedMap for deterministic ordering of check type checks. - * For Context objects we retain their order of appearance, apart from groupings. - */ - val contextsByCheckType = new TreeMap>(); - for (Context context : allContexts) { - contextsByCheckType.compute(checkType(context), [k, lst | lst ?: new ArrayList()]).add(context); - } - - val baseTypeName = objectBaseJavaTypeRef.qualifiedName; - - for (val iterator = contextsByCheckType.entrySet.iterator(); iterator.hasNext(); ) { - val entry = iterator.next(); - val checkType = '''CheckType.«entry.key»'''; - - out.append('''if (checkMode.shouldCheck(«checkType»)) {'''); - out.increaseIndentation; - out.newLine; - out.append('''diagnosticCollector.setCurrentCheckType(«checkType»);'''); - emitInstanceOfConditionals(out, entry.value, catalog, baseTypeName); // with preceding newline for each - out.decreaseIndentation; - out.newLine; - out.append("}"); - if (iterator.hasNext()) // not at method body end - out.newLine; // separator between mode checks - } - } - - private def void emitInstanceOfConditionals(ITreeAppendable out, List contexts, CheckCatalog catalog, String baseTypeName) { - /* Contexts grouped by fully qualified variable type name, - * otherwise in order of appearance. - */ - val contextsByVarType = new TreeMap>(); - for (Context context : contexts) { - contextsByVarType.compute(context.contextVariable.type.qualifiedName, - [k, lst | lst ?: new ArrayList()] - ).add(context); - } - - /* Ordering for context variable type checks. */ - val List contextVarTypes = contexts.map([x | x.contextVariable.type]); - val forest = InstanceOfCheckOrderer.orderTypes(contextVarTypes); - - emitInstanceOfTree(out, forest, null, contextsByVarType, catalog, baseTypeName, 0); - } - - private def void emitInstanceOfTree(ITreeAppendable out, InstanceOfCheckOrderer.Forest forest, String node, Map> contextsByVarType, CheckCatalog catalog, String baseTypeName, int level) { - if (node !== null) { - var String typeName = node; - if (typeName == baseTypeName) - typeName = null; - val varName = if (typeName === null) "object" else "castObject" + (if (level > 1) Integer.toString(level) else ""); - - out.newLine; - out.append('''«IF typeName !== null»if (object instanceof final «typeName» «varName») «ENDIF»{'''); - out.increaseIndentation; - - val contexts = contextsByVarType.get(node); - for (context : contexts) { - emitCheckMethodCall(out, varName, context, catalog); // with preceding newline - } - } - - for (child : forest.getSubTypes(node)) { - emitInstanceOfTree(out, forest, child, contextsByVarType, catalog, baseTypeName, level + 1); - } - - if (node !== null) { - out.decreaseIndentation; - out.newLine; - out.append('}'); - } - } - - private def void emitCheckMethodCall(ITreeAppendable out, String varName, Context context, CheckCatalog catalog) { - val methodName = generateContextMethodName(context); - val jMethodName = toJavaLiteral(methodName); - val qMethodName = toJavaLiteral(catalog.name, methodName); - - out.newLine; - out.append(''' - validate(«jMethodName», «qMethodName», object, - () -> «methodName»(«varName», diagnosticCollector), diagnosticCollector);'''); - } - - private def String toJavaLiteral(String... strings) { - return '''"«Strings::convertToJavaString(String.join(".", strings))»"'''; - } - - private def Iterable createInjectedField(CheckCatalog context, String fieldName, JvmTypeReference type) { - // Generate @Inject private typeName fieldName; - if (type === null) { - return Collections::emptyList; - } - val field = typesFactory.createJvmField(); - field.simpleName = fieldName; - field.visibility = JvmVisibility::PRIVATE; - field.type = cloneWithProxies(type); - field.annotations += createAnnotation(checkedTypeRef(context, typeof(Inject)), []); - return Collections::singleton(field); - } - - private def Iterable createCheck(Check chk) { - // If we don't have FormalParameters, there's no need to do all this song and dance with inner classes. - if (chk.formalParameters.empty) { - return chk.contexts.map(ctx|createCheckMethod(ctx) as JvmMember); - } else { - return createCheckWithParameters(chk); - } - } - - private def Iterable createCheckWithParameters(Check chk) { - // Generate an inner class, plus a field holding an instance of that class. - // Put the formal parameters into that class as fields. - // For each check context, generate a run method. - // For each check context, generate an annotated check method outside to call the appropriate run method. - // This is the only way I found to make those formal parameters visible in the check constraints... - // The generated Java looks a bit strange, because we suppress actually generating these fields, as we - // don't use them; we only need them for scoping based on this inferred model. - val List newMembers = Lists::newArrayList; - // First the class - val checkClass = chk.toClass(chk.name.toFirstUpper + 'Class') [ - superTypes += typeRef(typeof(Object)); - visibility = JvmVisibility::PRIVATE; - // Add a fields for the parameters, so that they can be linked. We suppress generation of these fields in the generator, - // and replace all references by calls to the getter function in the catalog. - members += chk.formalParameters.filter(f|f.type !== null && f.name !== null).map(f|f.toField(f.name, f.type) [final = true]); - ]; - newMembers += checkClass; - newMembers += chk.toField(chk.name.toFirstLower + 'Impl', typeRef(checkClass)) [initializer = [append('''new «checkClass.simpleName»()''')]]; - newMembers += chk.contexts.map(ctx|createCheckCaller(ctx, chk)).filterNull; - // If we create these above in the class initializer, the types of the context variables somehow are not resolved yet. - checkClass.members += chk.contexts.map(ctx|createCheckExecution(ctx)).filterNull; - return newMembers; - } - - private def JvmOperation createCheckExecution(Context ctx) { - if (ctx === null || ctx.contextVariable === null) { - return null; - } - val String functionName = 'run' + ctx.contextVariable.type?.simpleName.toFirstUpper; - ctx.toMethod(functionName, typeRef('void')) [ - parameters += ctx.toParameter(if (ctx.contextVariable.name === null) CheckConstants::IT else ctx.contextVariable.name, ctx.contextVariable.type); - parameters += ctx.toParameter("diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector)); - body = ctx.constraint; - ] - } - - private def Iterable createCheckAnnotation (Context ctx) { - val checkTypeTypeRef = checkedTypeRef(ctx, typeof(CheckType)); - if (checkTypeTypeRef === null) { - return Collections::emptyList; - } - val XFeatureCall featureCall = XbaseFactory::eINSTANCE.createXFeatureCall(); - featureCall.feature = checkTypeTypeRef.type; - featureCall.typeLiteral = true; - val XMemberFeatureCall memberCall = XbaseFactory::eINSTANCE.createXMemberFeatureCall(); - memberCall.memberCallTarget = featureCall; - // The grammar doesn't use the CheckType constants directly... - var String name = checkTypeQName(ctx); - val int i = name.lastIndexOf('.'); - if (i >= 0) { - name = name.substring(i+1); - } - memberCall.feature = (checkTypeTypeRef.type as JvmDeclaredType).findAllFeaturesByName(name).head; - - // memberCall needs to belong to a resource. - // We add it as a separate model to the context's resource. - ctx.eResource.contents.add(memberCall) - - return createAnnotation(checkedTypeRef(ctx, typeof(org.eclipse.xtext.validation.Check)), [ - explicitValues += memberCall.toJvmAnnotationValue(); - ]); - } - - private def JvmOperation createCheckCaller(Context ctx, Check chk) { - if (ctx === null || ctx.contextVariable === null) { - return null; - } - val String functionName = chk.name.toFirstLower + ctx.contextVariable.type?.simpleName; - // To make the formal parameter visible, we have to generate quite a bit... I see no way to get the XVariableDeclaration for them - // into the XBlockExpression of ctx.constraint. Just copying them doesn't work; modifies the source model! - // Therefore, we generate something new: each check becomes a local class - - ctx.toMethod(functionName, typeRef('void')) [ - parameters += ctx.toParameter("context", ctx.contextVariable.type); - parameters += ctx.toParameter("diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector)); - annotations += createCheckAnnotation(ctx); - documentation = functionName + '.'; // Well, that's not very helpful, but it is what the old compiler did... - body = [append(''' - «chk.name.toFirstLower + 'Impl'».run«ctx.contextVariable.type?.simpleName.toFirstUpper»(context, diagnosticCollector);''' - )] - ] - } - - private def JvmOperation createCheckMethod(Context ctx) { - // Simple case for contexts of checks that do not have formal parameters. No need to generate nested classes for these. - if (ctx === null || ctx.contextVariable === null) { - return null; - } - val String functionName = generateContextMethodName(ctx); - - ctx.toMethod(functionName, typeRef('void')) [ - parameters += ctx.toParameter(if (ctx.contextVariable.name === null) CheckConstants::IT else ctx.contextVariable.name, ctx.contextVariable.type); - parameters += ctx.toParameter("diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector)); - annotations += createCheckAnnotation(ctx); - documentation = functionName + '.'; // Well, that's not very helpful, but it is what the old compiler did... - body = ctx.constraint; - ] - } - - private def String generateContextMethodName(Context ctx) { - return switch container : ctx.eContainer { - Check : container.name - Implementation: container.name - }.toFirstLower + ctx.contextVariable.type?.simpleName; - } - - // CheckCatalog - - private def Iterable createIssue(CheckCatalog catalog, Check check) { - val List members = Lists::newArrayList(); - for (FormalParameter parameter : check.formalParameters) { - val JvmTypeReference returnType = parameter.type; - if (returnType !== null && !returnType.eIsProxy) { - val String returnName = returnType.qualifiedName; - val String operation = switch returnName { - case 'java.lang.Boolean' : 'getBoolean' - case 'boolean' : 'getBoolean' - case 'java.lang.Integer' : 'getInt' - case 'int' : 'getInt' - case 'java.util.List' : 'getStrings' - case 'java.util.List' : 'getBooleans' - case 'java.util.List' : 'getIntegers' - default : 'getString' - } - val String parameterKey = CheckPropertiesGenerator::parameterKey(parameter, check); - var String defaultName = 'null'; - if (parameter.right !== null) { - defaultName = parameter.formalParameterGetterName.splitCamelCase.toUpperCase + '_DEFAULT'; - // Is generated into the PreferenceInitializer. Actually, since we do have it in the initializer, passing it here again - // as default value is just a safety measure if something went wrong and the property shouldn't be set. - } - val javaDefaultValue = catalog.preferenceInitializerClassName + '.' + defaultName; - members += parameter.toMethod(parameter.formalParameterGetterName, returnType) [ - documentation = ''' - Gets the run-time value of formal parameter «parameter.name». The value - returned is either the default as defined in the check definition, or the - configured value, if existing. - - @param context - the context object used to determine the current project in - order to check if a configured value exists in a project scope - @return the run-time value of «parameter.name»'''; - val eObjectTypeRef = checkedTypeRef(parameter, typeof(EObject)); - if (eObjectTypeRef !== null) { - parameters += parameter.toParameter('context', eObjectTypeRef); - } - body = [append(''' - return checkConfigurationStoreService.getCheckConfigurationStore(context).«operation»("«parameterKey»", «javaDefaultValue»);''' - )]; - ]; - } // end if - } // end for - members += check.toMethod('get' + check.name.toFirstUpper + 'Message', typeRef(typeof(String))) [ - documentation = CheckJvmModelInferrerUtil.GET_MESSAGE_DOCUMENTATION; - // Generate one parameter "Object... bindings" - varArgs = true; - parameters += check.toParameter('bindings', addArrayTypeDimension(typeRef(typeof(Object)))); - body = [append(''' - return org.eclipse.osgi.util.NLS.bind("«Strings::convertToJavaString(check.message)»", bindings);''' - )]; - // TODO (minor): how to get NLS into the imports? - ]; - val severityType = checkedTypeRef(check, typeof(SeverityKind)); - if (severityType !== null) { - members += check.toMethod('get' + check.name.toFirstUpper + 'SeverityKind', severityType) [ - documentation = ''' - Gets the {@link SeverityKind severity kind} of check - «check.label». The severity kind returned is either the - default ({@code «check.defaultSeverity.name()»}), as is set in the check definition, or the - configured value, if existing. - - @param context - the context object used to determine the current project in - order to check if a configured value exists in a project scope - @return the severity kind of this check: returns the default («check.defaultSeverity.name()») if - no configuration for this check was found, else the configured - value looked up in the configuration store'''; - val eObjectTypeRef = checkedTypeRef(check, typeof(EObject)); - if (eObjectTypeRef !== null) { - parameters += check.toParameter('context', eObjectTypeRef); - } - body = [append(''' - final int result = checkConfigurationStoreService.getCheckConfigurationStore(context).getInt("«CheckPropertiesGenerator::checkSeverityKey(check)»", «check.defaultSeverity.value»); - return SeverityKind.values()[result];''' - )]; - ]; - } - return members; - } - - // PreferenceInitializer. - - private def Iterable createFormalParameterFields (CheckCatalog catalog) { - // For each formal parameter, create a public static final field with a unique name derived from the formal parameter and - // set it to its right-hand side expression. We let Java evaluate this! - val allChecks = catalog.checks + catalog.categories.map(cat|cat.checks).flatten; - val List result = Lists::newArrayList(); - for (Check c : allChecks) { - for (FormalParameter parameter : c.formalParameters) { - if (parameter.type !== null && parameter.right !== null) { - val String defaultName = parameter.formalParameterGetterName.splitCamelCase.toUpperCase + '_DEFAULT'; - result += parameter.toField(defaultName, parameter.type) [ - visibility = JvmVisibility::PUBLIC; - final = true; - static = true; - initializer = parameter.right; - ]; - } - - } - } - return result; - } - - private def Iterable createPreferenceInitializerMethods(CheckCatalog catalog) { - val JvmTypeReference prefStore = checkedTypeRef(catalog, typeof (IEclipsePreferences)); - val List result = Lists::newArrayList(); - - if (prefStore !== null) { - result += catalog.toMethod('initializeDefaultPreferences', typeRef('void')) [ - annotations += createAnnotation(checkedTypeRef(catalog, typeof(Override)), []); - visibility = JvmVisibility::PUBLIC; - body = [append(''' - IEclipsePreferences preferences = org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE.getNode(RUNTIME_NODE_NAME); - - initializeSeverities(preferences); - initializeFormalParameters(preferences);''')]; - ]; - val allChecks = catalog.checks + catalog.categories.map(cat|cat.checks).flatten; - result += catalog.toMethod('initializeSeverities', typeRef('void')) [ - visibility = JvmVisibility::PRIVATE; - parameters += catalog.toParameter('preferences', prefStore); - body = [append('''«FOR c:allChecks» - preferences.putInt("«CheckPropertiesGenerator::checkSeverityKey(c)»", «c.defaultSeverity.value»); - «ENDFOR»''')]; - ]; - result += catalog.toMethod('initializeFormalParameters', typeRef('void')) [ - visibility = JvmVisibility::PRIVATE; - parameters += catalog.toParameter('preferences', prefStore.cloneWithProxies); - body = [ - for (Check c : allChecks) { - for (FormalParameter parameter : c.formalParameters) { - if (parameter.right !== null) { - val String key = CheckPropertiesGenerator::parameterKey(parameter, c); - val String defaultFieldName = parameter.formalParameterGetterName.splitCamelCase.toUpperCase + '_DEFAULT'; - val JvmTypeReference jvmType = parameter.type; - val String typeName = jvmType.qualifiedName; - if (typeName !== null && typeName.startsWith("java.util.List<")) { - // Marshal lists. - val args = (jvmType as JvmParameterizedTypeReference).arguments; - if (args !== null && args.size == 1) { - val baseTypeName = args.head.simpleName; - append('''preferences.put("«key»", com.avaloq.tools.ddk.check.runtime.configuration.CheckPreferencesHelper.marshal«baseTypeName»s(«defaultFieldName»)); - '''); - } else { - append('''// Found «key» with «typeName» - '''); - } - } else { - val String operation = switch typeName { - case 'java.lang.Boolean' : 'putBoolean' - case 'boolean' : 'putBoolean' - case 'java.lang.Integer' : 'putInt' - case 'int' : 'putInt' - default : 'put' - }; - append('''preferences.«operation»("«key»", «defaultFieldName»); - '''); - } - } - } - } - ]; - ]; - } - return result; - - } - - private def Iterable createAnnotation (JvmTypeReference typeRef, Procedure1 initializer) { - if (typeRef === null) { - return Collections::emptyList; - } - - val annotation = typesFactory.createJvmAnnotationReference() - annotation.annotation = typeRef.type as JvmAnnotationType - Objects.requireNonNull(initializer, "Initializer is null").apply(annotation) - - return Collections::singletonList(annotation) - } - - // Error handling etc. - - private def createError (String message, EObject context, EStructuralFeature feature) { - val Resource rsc = context.eResource; - if (rsc !== null) { - var f = feature; - if (f === null) { - f = locationInFileProvider.getIdentifierFeature(context); - } - rsc.errors += new EObjectDiagnosticImpl(Severity::ERROR, IssueCodes::INFERRER_ERROR, "Check compiler: " + message, context, f, -1, null) - } - } - - private def createTypeNotFoundError(String name, EObject context) { - createError("Type " + name + " not found; check project setup (missing required bundle?)", context, null); - } - - private def JvmTypeReference checkedTypeRef(EObject context, Class clazz) { - if (clazz === null) { - createTypeNotFoundError ("", context); - return null; - } - val result = typeRef(clazz); - if (result === null || result.type === null) { - createTypeNotFoundError(clazz.name, context); - return null; - } - return result; - } -} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.java new file mode 100644 index 0000000000..36a7a159cd --- /dev/null +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.java @@ -0,0 +1,224 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.scoping; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +import com.avaloq.tools.ddk.check.check.Check; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.CheckPackage; +import com.avaloq.tools.ddk.check.check.Context; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import com.avaloq.tools.ddk.check.naming.CheckDeclarativeQualifiedNameProvider; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; +import com.google.inject.Inject; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.IGrammarAccess; +import org.eclipse.xtext.common.types.JvmType; +import org.eclipse.xtext.common.types.JvmTypeReference; +import org.eclipse.xtext.naming.IQualifiedNameConverter; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.EObjectDescription; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.resource.IResourceServiceProvider; +import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider; +import org.eclipse.xtext.scoping.IGlobalScopeProvider; +import org.eclipse.xtext.scoping.IScope; +import org.eclipse.xtext.scoping.impl.MapBasedScope; +import org.eclipse.xtext.scoping.impl.SimpleScope; +import org.eclipse.xtext.xbase.annotations.typesystem.XbaseWithAnnotationsBatchScopeProvider; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.ListExtensions; +import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver; + +public class CheckScopeProvider extends XbaseWithAnnotationsBatchScopeProvider { + + @Inject + private CheckDeclarativeQualifiedNameProvider checkQualifiedNameProvider; + + @Inject + private IQualifiedNameConverter qualifiedNameConverter; + + @Inject + private IBatchTypeResolver typeResolver; + + @Inject + private IGlobalScopeProvider globalScopeProvider; + + @Inject + private ResourceDescriptionsProvider descriptionsProvider; + + // Use dispatch definitions instead of a switch statement since + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=368263 + // will otherwise cause the builder to fail during linking. + @Override + public IScope getScope(EObject context, EReference reference) { + IScope res = scope(context, reference); + if (res != null) { + return res; + } else { + return super.getScope(context, reference); + } + } + + protected IScope _scope(XIssueExpression context, EReference reference) { + if (reference == CheckPackage.Literals.XISSUE_EXPRESSION__MARKER_FEATURE) { + JvmTypeReference jvmTypeRef; + if (context.getMarkerObject() != null) { + jvmTypeRef = typeResolver.resolveTypes(context.getMarkerObject()).getActualType(context.getMarkerObject()).toTypeReference(); + } else { + jvmTypeRef = EcoreUtil2.getContainerOfType(context, Context.class).getContextVariable().getType(); + } + + if (jvmTypeRef != null) { + EClass eClass = classForJvmType(context, jvmTypeRef.getType()); + if (eClass != null) { + EList features = eClass.getEAllStructuralFeatures(); + Collection descriptions = Collections2.transform(features, + (EStructuralFeature f) -> EObjectDescription.create(QualifiedName.create(f.getName()), f)); + return MapBasedScope.createScope(IScope.NULLSCOPE, descriptions); + } else { + return IScope.NULLSCOPE; + } + } else { + return IScope.NULLSCOPE; + } + } else if (reference == CheckPackage.Literals.XISSUE_EXPRESSION__CHECK) { + // Make sure that only Checks of the current model can be referenced, and if the CheckCatalog includes + // another CheckCatalog, then use that parent as parent scope + + CheckCatalog catalog = EcoreUtil2.getContainerOfType(context, CheckCatalog.class); + List checks = IterableExtensions.toList(IterableExtensions.filter(catalog.getAllChecks(), c -> c.getName() != null)); + + Collection descriptions = Collections2.transform(checks, + (Check c) -> EObjectDescription.create(QualifiedName.create(c.getName()), c)); + // Determine the parent scope; use NULLSCOPE if no included CheckCatalog is defined (or if it cannot be resolved) + IScope parentScope = IScope.NULLSCOPE; + + return MapBasedScope.createScope(parentScope, Iterables.filter(descriptions, Predicates.notNull())); + } + return null; + } + + protected IScope _scope(CheckCatalog context, EReference reference) { + if (reference == CheckPackage.Literals.CHECK_CATALOG__GRAMMAR) { + IResourceServiceProvider.Registry reg = IResourceServiceProvider.Registry.INSTANCE; + Collection descriptions = Collections2.transform(reg.getExtensionToFactoryMap().keySet(), + (String e) -> { + URI dummyUri = URI.createURI("foo:/foo." + e); + try { + Grammar g = reg.getResourceServiceProvider(dummyUri).get(IGrammarAccess.class).getGrammar(); + return EObjectDescription.create(qualifiedNameConverter.toQualifiedName(g.getName()), g); + } catch (Exception ex) { + return null; + } + }); + // We look first in the workspace for a grammar and then in the registry for a registered grammar + IScope parentScope = MapBasedScope.createScope(IScope.NULLSCOPE, Iterables.filter(descriptions, Predicates.notNull())); + return parentScope; + } else if (reference == CheckPackage.Literals.XISSUE_EXPRESSION__CHECK) { + List descriptions = ListExtensions.map(context.getAllChecks(), + (Check c) -> EObjectDescription.create(checkQualifiedNameProvider.getFullyQualifiedName(c), c)); + return new SimpleScope(super.getScope(context, reference), descriptions); + } + return null; + } + + // default implementation will throw an illegal argument exception + protected IScope _scope(EObject context, EReference reference) { + return null; + } + + public IScope scope(EObject context, EReference reference) { + if (context instanceof CheckCatalog) { + return _scope((CheckCatalog) context, reference); + } else if (context instanceof XIssueExpression) { + return _scope((XIssueExpression) context, reference); + } else if (context != null) { + return _scope(context, reference); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(context, reference).toString()); + } + } + + public EClass classForJvmType(EObject context, JvmType jvmType) { + if (jvmType != null && !jvmType.eIsProxy()) { + String qualifiedName = jvmType.getQualifiedName(); + String qualifiedPackageName = qualifiedName.substring(0, qualifiedName.lastIndexOf(".")); + String packageName = qualifiedPackageName.substring(qualifiedPackageName.lastIndexOf(".") + 1); + EPackage ePackage = getEPackage(context.eResource(), packageName); + if (ePackage != null) { + EClassifier eClassifier = ((EPackage) EcoreUtil.resolve(ePackage, context)).getEClassifier(jvmType.getSimpleName()); + if (eClassifier instanceof EClass) { + return (EClass) eClassifier; + } + } + } + return null; + } + + public EPackage getEPackage(Resource context, String name) { + // not using for-each loop, as it could result in a ConcurrentModificationException when a resource is demand-loaded + EList resources = context.getResourceSet().getResources(); + for (int i = 0; i < resources.size(); i++) { + Resource resource = resources.get(i); + for (EObject obj : resource.getContents()) { + if (obj instanceof EPackage && Objects.equals(((EPackage) obj).getName(), name)) { + return (EPackage) obj; + } + } + } + IEObjectDescription desc = globalScopeProvider.getScope(context, EcorePackage.Literals.EPACKAGE__ESUPER_PACKAGE, null).getSingleElement(QualifiedName.create(name)); + if (desc != null) { + return (EPackage) desc.getEObjectOrProxy(); + } + Iterator descs = descriptionsProvider.getResourceDescriptions(context).getExportedObjects(EcorePackage.Literals.EPACKAGE, QualifiedName.create(name), false).iterator(); + if (descs.hasNext()) { + EObject pkg = EcoreUtil.resolve(descs.next().getEObjectOrProxy(), context); + // this filtering only appears to be necessary when executing the unit test BugAig830 in Jenkins (see https://jira.sys.net/browse/ACF-8758) + if (!pkg.eIsProxy()) { + return (EPackage) pkg; + } + } + for (String nsUri : Sets.newHashSet(EPackage.Registry.INSTANCE.keySet())) { + EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(nsUri); + if (Objects.equals(ePackage.getName(), name)) { + return ePackage; + } + } + return null; + } + + //todo: scoping for the check implementation (e.g. the parameters are not visible) + + //todo: scope the allowed imports! +} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.xtend deleted file mode 100644 index 01e43d9725..0000000000 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.xtend +++ /dev/null @@ -1,178 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.scoping - -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.check.CheckPackage -import com.avaloq.tools.ddk.check.check.Context -import com.avaloq.tools.ddk.check.check.XIssueExpression -import com.avaloq.tools.ddk.check.naming.CheckDeclarativeQualifiedNameProvider -import com.google.common.base.Predicates -import com.google.common.collect.Collections2 -import com.google.common.collect.Iterables -import com.google.common.collect.Sets -import com.google.inject.Inject -import org.eclipse.emf.common.util.URI -import org.eclipse.emf.ecore.EClass -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.EPackage -import org.eclipse.emf.ecore.EReference -import org.eclipse.emf.ecore.EcorePackage -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.emf.ecore.util.EcoreUtil -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.IGrammarAccess -import org.eclipse.xtext.common.types.JvmType -import org.eclipse.xtext.naming.IQualifiedNameConverter -import org.eclipse.xtext.naming.QualifiedName -import org.eclipse.xtext.resource.EObjectDescription -import org.eclipse.xtext.resource.IResourceServiceProvider -import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider -import org.eclipse.xtext.scoping.IGlobalScopeProvider -import org.eclipse.xtext.scoping.IScope -import org.eclipse.xtext.scoping.impl.MapBasedScope -import org.eclipse.xtext.scoping.impl.SimpleScope -import org.eclipse.xtext.xbase.annotations.typesystem.XbaseWithAnnotationsBatchScopeProvider -import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver - -class CheckScopeProvider extends XbaseWithAnnotationsBatchScopeProvider { - - @Inject CheckDeclarativeQualifiedNameProvider checkQualifiedNameProvider - @Inject IQualifiedNameConverter qualifiedNameConverter - @Inject IBatchTypeResolver typeResolver; - @Inject IGlobalScopeProvider globalScopeProvider - @Inject ResourceDescriptionsProvider descriptionsProvider - - // Use dispatch definitions instead of a switch statement since - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=368263 - // will otherwise cause the builder to fail during linking. - override IScope getScope(EObject context, EReference reference) { - val res = scope(context, reference) - if (res !== null) res else super.getScope(context, reference) - } - - def dispatch IScope scope(XIssueExpression context, EReference reference) { - if (reference == CheckPackage.Literals::XISSUE_EXPRESSION__MARKER_FEATURE) { - var jvmTypeRef = - if (context.markerObject !== null) - typeResolver.resolveTypes(context.markerObject).getActualType(context.markerObject).toTypeReference - else - EcoreUtil2::getContainerOfType(context, typeof(Context)).contextVariable.type; - - if (jvmTypeRef !== null) { - val eClass = context.classForJvmType(jvmTypeRef.type); - if (eClass !== null) { - var features = eClass.EAllStructuralFeatures - val descriptions = Collections2::transform(features, [f | EObjectDescription::create(QualifiedName::create(f.name), f)]) - return MapBasedScope::createScope(IScope::NULLSCOPE, descriptions); - } else { - return IScope::NULLSCOPE; - } - } else { - return IScope::NULLSCOPE; - } - } else if (reference == CheckPackage.Literals::XISSUE_EXPRESSION__CHECK) { - // Make sure that only Checks of the current model can be referenced, and if the CheckCatalog includes - // another CheckCatalog, then use that parent as parent scope - - val catalog = EcoreUtil2::getContainerOfType(context, typeof(CheckCatalog)) - val checks = catalog.allChecks.filter(c|c.name !== null).toList - - val descriptions = Collections2::transform(checks, [c|EObjectDescription::create(QualifiedName::create(c.name), c)]) - // Determine the parent scope; use NULLSCOPE if no included CheckCatalog is defined (or if it cannot be resolved) - val parentScope = IScope::NULLSCOPE - - return MapBasedScope::createScope(parentScope, Iterables::filter(descriptions, Predicates::notNull)); - } - } - - def dispatch IScope scope(CheckCatalog context, EReference reference) { - if (reference == CheckPackage.Literals::CHECK_CATALOG__GRAMMAR) { - val reg = IResourceServiceProvider.Registry::INSTANCE - val descriptions = Collections2::transform(reg.extensionToFactoryMap.keySet, - [e | { - val dummyUri = URI::createURI("foo:/foo." + e) - try { - val g = reg.getResourceServiceProvider(dummyUri).get(typeof(IGrammarAccess)).grammar - return EObjectDescription::create(qualifiedNameConverter.toQualifiedName(g.name), g) - } catch (Exception ex) {} - }] - ) - // We look first in the workspace for a grammar and then in the registry for a registered grammar - val parentScope = MapBasedScope::createScope(IScope::NULLSCOPE, Iterables::filter(descriptions, Predicates::notNull)); - return parentScope; - //val grammarScope = new DelegatingScope(parentScope); - //grammarScope.setDelegate(super.getScope(context, reference)); - //return grammarScope; - } else if (reference == CheckPackage.Literals::XISSUE_EXPRESSION__CHECK) { - val descriptions = context.allChecks.map(c|EObjectDescription::create(checkQualifiedNameProvider.getFullyQualifiedName(c), c)) - return new SimpleScope(super.getScope(context, reference), descriptions) - } - } - - // default implementation will throw an illegal argument exception - def dispatch IScope scope(EObject context, EReference reference) { - return null - } - - def EClass classForJvmType(EObject context, JvmType jvmType) { - if (jvmType !== null && !jvmType.eIsProxy) { - val qualifiedName = jvmType.getQualifiedName(); - val qualifiedPackageName = qualifiedName.substring(0, qualifiedName.lastIndexOf(".")); - val packageName = qualifiedPackageName.substring(qualifiedPackageName.lastIndexOf(".") + 1); - val ePackage = getEPackage(context.eResource, packageName); - if (ePackage !== null) { - val eClassifier = (EcoreUtil::resolve(ePackage, context) as EPackage).getEClassifier(jvmType.simpleName) - if (eClassifier instanceof EClass) { - return eClassifier - } - } - } - return null - } - - def EPackage getEPackage(Resource context, String name) { - // not using for-each loop, as it could result in a ConcurrentModificationException when a resource is demand-loaded - val resources = context.resourceSet.resources - for (var i = 0; i < resources.size; i++) { - val resource = resources.get(i) - for (obj : resource.contents) { - if (obj instanceof EPackage && (obj as EPackage).name == name) - return obj as EPackage - } - } - val desc = globalScopeProvider.getScope(context, EcorePackage.Literals.EPACKAGE__ESUPER_PACKAGE, null).getSingleElement(QualifiedName.create(name)) - if (desc !== null) { - return desc.EObjectOrProxy as EPackage - } - val descs = descriptionsProvider.getResourceDescriptions(context).getExportedObjects(EcorePackage.Literals.EPACKAGE, QualifiedName.create(name), false).iterator - if (descs.hasNext) { - val pkg = EcoreUtil.resolve(descs.next.EObjectOrProxy, context) - // this filtering only appears to be necessary when executing the unit test BugAig830 in Jenkins (see https://jira.sys.net/browse/ACF-8758) - if (!pkg.eIsProxy) - return pkg as EPackage - } - for (nsUri : Sets.newHashSet(EPackage.Registry.INSTANCE.keySet)) { - val ePackage = EPackage.Registry.INSTANCE.getEPackage(nsUri) - if (ePackage.name == name) { - return ePackage - } - } - return null - } - - //todo: scoping for the check implementation (e.g. the parameters are not visible) - - //todo: scope the allowed imports! - - -} - diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.java new file mode 100644 index 0000000000..4efa5a7b53 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.typing; + +import com.avaloq.tools.ddk.check.check.FormalParameter; +import com.avaloq.tools.ddk.check.check.XGuardExpression; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.xbase.XExpression; +import org.eclipse.xtext.xbase.XListLiteral; +import org.eclipse.xtext.xbase.annotations.typesystem.XbaseWithAnnotationsTypeComputer; +import org.eclipse.xtext.xbase.typesystem.computation.ITypeComputationState; + +public class CheckTypeComputer extends XbaseWithAnnotationsTypeComputer { + + @Override + public void computeTypes(XExpression expression, ITypeComputationState state) { + if (expression instanceof XIssueExpression) { + _computeTypes((XIssueExpression) expression, state); + } else if (expression instanceof XGuardExpression) { + _computeTypes((XGuardExpression) expression, state); + } else if (expression.eContainer() instanceof FormalParameter && expression instanceof XListLiteral && ((XListLiteral) expression).getElements().isEmpty()) { + super.computeTypes(expression, state.withExpectation(state.getReferenceOwner().toLightweightTypeReference(((FormalParameter) expression.eContainer()).getType()))); + } else { + super.computeTypes(expression, state); + } + } + + protected void _computeTypes(XIssueExpression expression, ITypeComputationState state) { + if (expression.getMarkerObject() != null) { + state.withExpectation(getTypeForName(EObject.class, state)).computeTypes(expression.getMarkerObject()); + } + if (expression.getMarkerIndex() != null) { + state.withExpectation(getTypeForName(Integer.class, state)).computeTypes(expression.getMarkerIndex()); + } + if (expression.getMessage() != null) { + state.withExpectation(getTypeForName(String.class, state)).computeTypes(expression.getMessage()); + } + for (XExpression p : expression.getMessageParameters()) { + state.withExpectation(getTypeForName(Object.class, state)).computeTypes(p); + } + for (XExpression d : expression.getIssueData()) { + state.withExpectation(getTypeForName(String.class, state)).computeTypes(d); + } + state.acceptActualType(getPrimitiveVoid(state)); + } + + protected void _computeTypes(XGuardExpression expression, ITypeComputationState state) { + state.withExpectation(getTypeForName(Boolean.class, state)).computeTypes(expression.getGuard()); + state.acceptActualType(getPrimitiveVoid(state)); + } +} diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.xtend deleted file mode 100644 index 1b80a361f0..0000000000 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.xtend +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.typing - -import org.eclipse.xtext.xbase.annotations.typesystem.XbaseWithAnnotationsTypeComputer -import org.eclipse.xtext.xbase.typesystem.computation.ITypeComputationState -import org.eclipse.xtext.xbase.XExpression -import com.avaloq.tools.ddk.check.check.XIssueExpression -import com.avaloq.tools.ddk.check.check.XGuardExpression -import org.eclipse.emf.ecore.EObject -import com.avaloq.tools.ddk.check.check.FormalParameter -import org.eclipse.xtext.xbase.XListLiteral - -class CheckTypeComputer extends XbaseWithAnnotationsTypeComputer { - - override computeTypes(XExpression expression, ITypeComputationState state) { - if (expression instanceof XIssueExpression) { - _computeTypes(expression, state); - } else if (expression instanceof XGuardExpression) { - _computeTypes(expression, state); - } else if (expression.eContainer instanceof FormalParameter && expression instanceof XListLiteral && (expression as XListLiteral).elements.empty) { - super.computeTypes(expression, state.withExpectation(state.referenceOwner.toLightweightTypeReference((expression.eContainer as FormalParameter).type))); - } else { - super.computeTypes(expression, state); - } - } - - protected def _computeTypes(XIssueExpression expression, ITypeComputationState state) { - if (expression.markerObject !== null) { - state.withExpectation(getTypeForName(typeof(EObject), state)).computeTypes(expression.markerObject); - } - if (expression.markerIndex !== null) { - state.withExpectation(getTypeForName(typeof(Integer), state)).computeTypes(expression.markerIndex); - } - if (expression.message !== null) { - state.withExpectation(getTypeForName(typeof(String), state)).computeTypes(expression.message); - } - for (p : expression.messageParameters) { - state.withExpectation(getTypeForName(typeof(Object), state)).computeTypes(p); - } - for (d : expression.issueData) { - state.withExpectation(getTypeForName(typeof(String), state)).computeTypes(d); - } - state.acceptActualType(getPrimitiveVoid (state)); - } - - protected def _computeTypes(XGuardExpression expression, ITypeComputationState state) { - state.withExpectation(getTypeForName(typeof(Boolean), state)).computeTypes(expression.guard); - state.acceptActualType(getPrimitiveVoid (state)); - } - -} From 668482abeebc5f1956ef594523d69beef247e55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Fri, 27 Feb 2026 21:18:03 +0100 Subject: [PATCH 02/23] fix: handle checked CoreException in CheckGeneratorExtensions Xtend doesn't enforce checked exceptions, but Java does. Moved file.getContents() call inside try-with-resources block to properly handle CoreException. Co-Authored-By: Claude Opus 4.6 --- .../ddk/check/generator/CheckGeneratorExtensions.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java index 9e5256c091..7e4fd560d6 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java @@ -263,18 +263,11 @@ public Set getContents(CheckCatalog catalog, String path) { if (project != null) { // In some compiler tests we may not have a project. IFile file = project.getFile(new Path(path)); if (file.exists()) { - InputStreamReader reader = new InputStreamReader(file.getContents()); - try { + try (InputStreamReader reader = new InputStreamReader(file.getContents())) { List content = CharStreams.readLines(reader); return Sets.newTreeSet(content); } catch (Exception e) { throw new RuntimeException(e); - } finally { - try { - reader.close(); - } catch (Exception e) { - // ignore - } } } } From e416bb7801e7fc0d721e08791fd46f152b7b42c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 28 Feb 2026 11:30:29 +0100 Subject: [PATCH 03/23] chore: add migration docs and update project files Co-Authored-By: Claude Opus 4.6 --- AGENTS.md | 45 ++ .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../.project | 30 - .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../.project | 30 - .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../.project | 30 - .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 com.avaloq.tools.ddk.xtext.scope.ide/.project | 30 - .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 .../xtend-gen/.gitignore | 0 com.avaloq.tools.ddk.xtext.valid.ide/.project | 30 - .../xtend-gen/.gitignore | 0 docs/xtend-migration.md | 340 ++++++++++ docs/xtend-to-java-conversion-prompt.md | 631 ++++++++++++++++++ 39 files changed, 1016 insertions(+), 150 deletions(-) delete mode 100644 com.avaloq.tools.ddk.check.core.test/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.check.core/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.check.ide/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.check.test.runtime.tests/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.check.test.runtime/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.check.ui.test/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.check.ui/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.checkcfg.core/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.checkcfg.ide/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.sample.helloworld.ui.test/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.check.generator/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.export.generator/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.export.ide/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.export/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.expression.ide/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.expression/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.format.generator/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.format.ide/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.format.test/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.format.ui/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.format/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.generator.test/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.generator/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.scope.generator/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.scope.ide/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.scope/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.test.core/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.ui.test/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.ui/xtend-gen/.gitignore delete mode 100644 com.avaloq.tools.ddk.xtext.valid.ide/xtend-gen/.gitignore create mode 100644 docs/xtend-migration.md create mode 100644 docs/xtend-to-java-conversion-prompt.md diff --git a/AGENTS.md b/AGENTS.md index 4e52a5404d..86a8aded36 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -116,3 +116,48 @@ xvfb-run mvn verify -f ./ddk-parent/pom.xml -pl :com.avaloq.tools.ddk.xtext.test - **Platform**: GitHub Actions - **Workflow**: `.github/workflows/verify.yml` - Triggers on: push to master, pull requests + +--- + +## Xtend-to-Java Migration (feature/xtend-to-java-migration branch) + +> **TEMPORARY SECTION** — Remove this section and `docs/xtend-to-java-conversion-prompt.md` after the migration branch is merged to master. Check on every push. + +### Overview + +We are migrating all ~94 Xtend source files to idiomatic Java 21. Batch 1 (8 files in `check.core`) is complete. The remaining 86 files are tracked in [`docs/xtend-migration.md`](docs/xtend-migration.md). + +### Key References + +| Document | Purpose | +|----------|---------| +| [`docs/xtend-migration.md`](docs/xtend-migration.md) | Master checklist — per-file status, batch order, build cleanup tasks | +| [`docs/xtend-to-java-conversion-prompt.md`](docs/xtend-to-java-conversion-prompt.md) | Full conversion prompt with 18 sections of rules, checklist, and worked example | + +### Migration Conventions + +- **Java 21** target — use pattern matching, switch expressions where appropriate +- **`StringBuilder`** for Xtend template expressions (no Xtend runtime dependency) +- **No `var` keyword** — always use explicit types (`final ExplicitType`, not `final var`) +- **2-space indentation** to match project convention +- Preserve all comments, copyright headers, and method ordering + +### Per-File Conversion Workflow + +1. Read the `.xtend` source file +2. Read the corresponding `xtend-gen/*.java` file as reference +3. Apply the conversion prompt rules from `docs/xtend-to-java-conversion-prompt.md` +4. Write the `.java` file to `src/` (same package path as the `.xtend` file) +5. Delete the `.xtend` file +6. Delete the `xtend-gen/*.java` file +7. Update the checklist in `docs/xtend-migration.md` + +### Verification After Each Batch + +```bash +# Must pass +mvn clean compile -f ./ddk-parent/pom.xml --batch-mode + +# Must pass (except known macOS UI test) +mvn clean verify -f ./ddk-parent/pom.xml --batch-mode --fail-at-end +``` diff --git a/com.avaloq.tools.ddk.check.core.test/xtend-gen/.gitignore b/com.avaloq.tools.ddk.check.core.test/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.check.core/xtend-gen/.gitignore b/com.avaloq.tools.ddk.check.core/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.check.ide/xtend-gen/.gitignore b/com.avaloq.tools.ddk.check.ide/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/xtend-gen/.gitignore b/com.avaloq.tools.ddk.check.test.runtime.tests/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.check.test.runtime/xtend-gen/.gitignore b/com.avaloq.tools.ddk.check.test.runtime/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.check.ui.test/xtend-gen/.gitignore b/com.avaloq.tools.ddk.check.ui.test/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.check.ui/xtend-gen/.gitignore b/com.avaloq.tools.ddk.check.ui/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/xtend-gen/.gitignore b/com.avaloq.tools.ddk.checkcfg.core.test/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.checkcfg.core/xtend-gen/.gitignore b/com.avaloq.tools.ddk.checkcfg.core/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.checkcfg.ide/xtend-gen/.gitignore b/com.avaloq.tools.ddk.checkcfg.ide/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui.test/xtend-gen/.gitignore b/com.avaloq.tools.ddk.sample.helloworld.ui.test/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.check.generator/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.check.generator/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.export.generator/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.export.generator/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.export.ide/.project b/com.avaloq.tools.ddk.xtext.export.ide/.project index 47ffefb3f5..2d3d91bb56 100644 --- a/com.avaloq.tools.ddk.xtext.export.ide/.project +++ b/com.avaloq.tools.ddk.xtext.export.ide/.project @@ -65,35 +65,5 @@ 1 PARENT-1-PROJECT_LOC/ddk-configuration/.pmd - - .settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - - - .settings/org.eclipse.core.resources.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.resources.prefs - - - .settings/org.eclipse.core.runtime.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.runtime.prefs - - - .settings/org.eclipse.jdt.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.core.prefs - - - .settings/org.eclipse.jdt.ui.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.ui.prefs - - - .settings/org.eclipse.pde.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.pde.core.prefs - diff --git a/com.avaloq.tools.ddk.xtext.export.ide/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.export.ide/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.export/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.export/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.expression.ide/.project b/com.avaloq.tools.ddk.xtext.expression.ide/.project index 0db12dc67d..568dbc3b69 100644 --- a/com.avaloq.tools.ddk.xtext.expression.ide/.project +++ b/com.avaloq.tools.ddk.xtext.expression.ide/.project @@ -65,35 +65,5 @@ 1 PARENT-1-PROJECT_LOC/ddk-configuration/.pmd - - .settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - - - .settings/org.eclipse.core.resources.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.resources.prefs - - - .settings/org.eclipse.core.runtime.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.runtime.prefs - - - .settings/org.eclipse.jdt.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.core.prefs - - - .settings/org.eclipse.jdt.ui.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.ui.prefs - - - .settings/org.eclipse.pde.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.pde.core.prefs - diff --git a/com.avaloq.tools.ddk.xtext.expression.ide/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.expression.ide/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.expression/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.expression/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.format.generator/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.format.generator/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.format.ide/.project b/com.avaloq.tools.ddk.xtext.format.ide/.project index 98bb967ba7..2d78e4bef1 100644 --- a/com.avaloq.tools.ddk.xtext.format.ide/.project +++ b/com.avaloq.tools.ddk.xtext.format.ide/.project @@ -65,35 +65,5 @@ 1 PARENT-1-PROJECT_LOC/ddk-configuration/.pmd - - .settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - - - .settings/org.eclipse.core.resources.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.resources.prefs - - - .settings/org.eclipse.core.runtime.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.runtime.prefs - - - .settings/org.eclipse.jdt.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.core.prefs - - - .settings/org.eclipse.jdt.ui.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.ui.prefs - - - .settings/org.eclipse.pde.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.pde.core.prefs - diff --git a/com.avaloq.tools.ddk.xtext.format.ide/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.format.ide/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.format.test/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.format.test/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.format.ui/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.format.ui/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.format/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.format/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.generator.test/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.generator.test/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.generator/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.generator/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.scope.generator/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.scope.generator/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.scope.ide/.project b/com.avaloq.tools.ddk.xtext.scope.ide/.project index e62b705b8d..345a56ba6d 100644 --- a/com.avaloq.tools.ddk.xtext.scope.ide/.project +++ b/com.avaloq.tools.ddk.xtext.scope.ide/.project @@ -65,35 +65,5 @@ 1 PARENT-1-PROJECT_LOC/ddk-configuration/.pmd - - .settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - - - .settings/org.eclipse.core.resources.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.resources.prefs - - - .settings/org.eclipse.core.runtime.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.runtime.prefs - - - .settings/org.eclipse.jdt.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.core.prefs - - - .settings/org.eclipse.jdt.ui.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.ui.prefs - - - .settings/org.eclipse.pde.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.pde.core.prefs - diff --git a/com.avaloq.tools.ddk.xtext.scope.ide/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.scope.ide/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.scope/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.scope/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.test.core/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.test.core/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.ui.test/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.ui.test/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.ui/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.ui/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.valid.ide/.project b/com.avaloq.tools.ddk.xtext.valid.ide/.project index e6cfc0cb64..95911a5396 100644 --- a/com.avaloq.tools.ddk.xtext.valid.ide/.project +++ b/com.avaloq.tools.ddk.xtext.valid.ide/.project @@ -65,35 +65,5 @@ 1 PARENT-1-PROJECT_LOC/ddk-configuration/.pmd - - .settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - - - .settings/org.eclipse.core.resources.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.resources.prefs - - - .settings/org.eclipse.core.runtime.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.runtime.prefs - - - .settings/org.eclipse.jdt.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.core.prefs - - - .settings/org.eclipse.jdt.ui.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.ui.prefs - - - .settings/org.eclipse.pde.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.pde.core.prefs - diff --git a/com.avaloq.tools.ddk.xtext.valid.ide/xtend-gen/.gitignore b/com.avaloq.tools.ddk.xtext.valid.ide/xtend-gen/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/xtend-migration.md b/docs/xtend-migration.md new file mode 100644 index 0000000000..c781d012b2 --- /dev/null +++ b/docs/xtend-migration.md @@ -0,0 +1,340 @@ +# Xtend-to-Java Migration Tracker + +## Decisions + +- **Target**: Java 21 (pattern matching, switch expressions, text blocks, records) +- **Template strategy**: `StringBuilder` (pure Java, no Xtend runtime dependency) +- **No `var` keyword**: Always use explicit types (`final ExplicitType`, not `final var`) +- **Conversion prompt**: [`docs/xtend-to-java-conversion-prompt.md`](xtend-to-java-conversion-prompt.md) + +## Summary + +| Metric | Value | +|--------|-------| +| Total Xtend source files | 94 | +| Already migrated (Batch 1) | 8 | +| Remaining | 86 | +| Total remaining lines | ~12,874 | +| Modules with remaining Xtend | 24 | + +--- + +## Module Overview + +| Module | Files | Lines | Status | +|--------|-------|-------|--------| +| `check.core` | 8 | ~1,848 | **DONE** (Batch 1) | +| `check.core.test` | 11 | 1,717 | Pending | +| `check.test.runtime` | 1 | 22 | Pending | +| `check.test.runtime.tests` | 3 | 202 | Pending | +| `check.ui` | 2 | 113 | Pending | +| `check.ui.test` | 1 | 200 | Pending | +| `checkcfg.core` | 4 | 303 | Pending | +| `checkcfg.core.test` | 7 | 460 | Pending | +| `sample.helloworld.ui.test` | 3 | 203 | Pending | +| `xtext.check.generator` | 2 | 113 | Pending | +| `xtext.export` | 9 | 1,027 | Pending | +| `xtext.export.generator` | 1 | 86 | Pending | +| `xtext.expression` | 5 | 679 | Pending | +| `xtext.format` | 6 | 1,623 | Pending | +| `xtext.format.generator` | 1 | 239 | Pending | +| `xtext.format.ide` | 2 | 31 | Pending | +| `xtext.format.test` | 1 | 40 | Pending | +| `xtext.format.ui` | 1 | 47 | Pending | +| `xtext.generator` | 18 | 3,450 | Pending | +| `xtext.generator.test` | 1 | 200 | Pending | +| `xtext.scope` | 4 | 852 | Pending | +| `xtext.scope.generator` | 1 | 47 | Pending | +| `xtext.test.core` | 2 | 221 | Pending | +| `xtext.ui` | 1 | 82 | Pending | +| `xtext.ui.test` | 1 | 265 | Pending | + +All module names are prefixed with `com.avaloq.tools.ddk.` (omitted for brevity). + +--- + +## Batch 1 — `check.core` (8 files) — DONE + +- [x] `CheckGeneratorConfig.xtend` (20 lines) — Trivial +- [x] `CheckGeneratorNaming.xtend` (~80 lines) — Easy +- [x] `CheckTypeComputer.xtend` (~80 lines) — Easy +- [x] `CheckScopeProvider.xtend` (~100 lines) — Easy +- [x] `CheckGenerator.xtend` (216 lines) — Hard — templates, `@Inject extension` +- [x] `CheckGeneratorExtensions.xtend` (268 lines) — Hard — dispatch, templates +- [x] `CheckFormatter.xtend` (302 lines) — Hard — dispatch +- [x] `CheckJvmModelInferrer.xtend` (647 lines) — Very Hard — dispatch, templates, extensions + +--- + +## Batch 2 — Trivial files ≤50 lines (~14 files) + +Small setup classes, empty modules, simple overrides. + +### `check.test.runtime` (1 file) +- [ ] `TestLanguageGenerator.xtend` (22 lines) — Trivial — override + +### `xtext.format.ide` (2 files) +- [ ] `FormatIdeModule.xtend` (11 lines) — Trivial — no complex features +- [ ] `FormatIdeSetup.xtend` (20 lines) — Trivial — override + +### `xtext.format` (1 file) +- [ ] `FormatStandaloneSetup.xtend` (15 lines) — Trivial — extension + +### `xtext.expression` (2 files) +- [ ] `GeneratorUtilX.xtend` (29 lines) — Trivial — no complex features +- [ ] `Naming.xtend` (30 lines) — Trivial — no complex features + +### `xtext.check.generator` (1 file) +- [ ] `CheckValidatorFragment2.xtend` (31 lines) — Trivial — extension, !==, override + +### `checkcfg.core.test` (2 files) +- [ ] `CheckCfgTestUtil.xtend` (32 lines) — Trivial — override +- [ ] `CheckCfgModelUtil.xtend` (42 lines) — Trivial — templates + +### `checkcfg.core` (1 file) +- [ ] `CheckCfgJvmModelInferrer.xtend` (45 lines) — Trivial — templates, extension, @Inject + +### `xtext.format.test` (1 file) +- [ ] `FormatParsingTest.xtend` (40 lines) — Trivial — templates, @Inject + +### `xtext.format.ui` (1 file) +- [ ] `FormatUiModule.xtend` (47 lines) — Trivial — override + +### `xtext.generator` (2 files) +- [ ] `BundleVersionStripperFragment.xtend` (47 lines) — Trivial — typeof, @Accessors +- [ ] `ProjectConfig.xtend` (48 lines) — Trivial — templates, @Accessors, switch + +--- + +## Batch 3 — Easy files 50–100 lines (~16 files) + +Simple test files, utilities, small production code. + +### `check.core.test` (3 files) +- [ ] `BugAig830.xtend` (56 lines) — Easy — templates, @Inject +- [ ] `CheckTestUtil.xtend` (72 lines) — Easy — ===, !== +- [ ] `CheckScopingTest.xtend` (81 lines) — Easy — extension, typeof, @Inject + +### `check.test.runtime.tests` (2 files) +- [ ] `IssueLabelTest.xtend` (56 lines) — Easy — #{, override +- [ ] `CheckConfigurationIsAppliedTest.xtend` (64 lines) — Easy — extension, typeof, @Inject, override + +### `check.ui` (2 files) +- [ ] `CheckNewProject.xtend` (50 lines) — Easy — templates, !== +- [ ] `CheckQuickfixProvider.xtend` (63 lines) — Easy — templates + +### `checkcfg.core` (2 files) +- [ ] `CheckCfgGenerator.xtend` (53 lines) — Easy — templates, typeof, @Inject, override +- [ ] `ConfiguredParameterChecks.xtend` (66 lines) — Easy — templates, ===, !==, ?. + +### `checkcfg.core.test` (2 files) +- [ ] `CheckCfgConfiguredParameterValidationsTest.xtend` (63 lines) — Easy — templates, extension, override +- [ ] `CheckCfgTest.xtend` (63 lines) — Easy — templates, typeof, @Inject + +### `sample.helloworld.ui.test` (2 files) +- [ ] `IssueLabelTest.xtend` (56 lines) — Easy — #{, override +- [ ] `CheckConfigurationIsAppliedTest.xtend` (64 lines) — Easy — extension, typeof, @Inject, override + +### `xtext.check.generator` (1 file) +- [ ] `CheckQuickfixProviderFragment2.xtend` (82 lines) — Easy — templates, extension, @Inject + +--- + +## Batch 4 — Medium prod + test files 80–140 lines (~14 files) + +### `check.core.test` (4 files) +- [ ] `ProjectBasedTests.xtend` (88 lines) — Easy — extension, typeof, @Inject, override +- [ ] `IssueCodeValueTest.xtend` (104 lines) — Medium — templates, #{, switch +- [ ] `CheckApiAccessValidationsTest.xtend` (61 lines) — Easy — templates, @Inject +- [ ] `BasicModelTest.xtend` (116 lines) — Medium — extension, typeof, @Inject + +### `check.test.runtime.tests` (1 file) +- [ ] `CheckExecutionEnvironmentProjectTest.xtend` (82 lines) — Easy — extension, typeof, @Inject, override + +### `checkcfg.core` (1 file) +- [ ] `PropertiesInferenceHelper.xtend` (139 lines) — Medium — typeof, ===, !==, switch, create + +### `checkcfg.core.test` (3 files) +- [ ] `CheckCfgContentAssistTest.xtend` (84 lines) — Easy — templates, extension, @Inject, override +- [ ] `CheckCfgScopeProviderTest.xtend` (77 lines) — Easy — templates, ===, #[, override +- [ ] `CheckCfgSyntaxTest.xtend` (99 lines) — Easy — templates, #[, override + +### `sample.helloworld.ui.test` (1 file) +- [ ] `CheckExecutionEnvironmentProjectTest.xtend` (83 lines) — Easy — extension, typeof, @Inject, override + +### `xtext.export.generator` (1 file) +- [ ] `ExportFragment2.xtend` (86 lines) — Medium — templates, extension, !==, @Inject, override + +### `xtext.scope.generator` (1 file) +- [ ] `ScopingFragment2.xtend` (47 lines) — Trivial — extension, !==, override + +### `xtext.test.core` (1 file) +- [ ] `Tag.xtend` (23 lines) — Trivial — typeof + +--- + +## Batch 5 — `xtext.export` module (9 files, 1,027 lines) + +Code generators with templates and some dispatch methods. + +- [ ] `ResourceDescriptionConstantsGenerator.xtend` (54 lines) — Easy — templates, extension, @Inject +- [ ] `ExportFeatureExtensionGenerator.xtend` (77 lines) — Easy — templates, extension, @Inject +- [ ] `ResourceDescriptionManagerGenerator.xtend` (59 lines) — Easy — templates, extension, !==, @Inject +- [ ] `ExportedNamesProviderGenerator.xtend` (96 lines) — Medium — templates, extension, !==, ?., switch +- [ ] `FragmentProviderGenerator.xtend` (94 lines) — Medium — templates, extension, !==, switch +- [ ] `FingerprintComputerGenerator.xtend` (134 lines) — Medium — **dispatch**, templates, extension, @Inject +- [ ] `ExportGenerator.xtend` (136 lines) — Medium — templates, extension, ===, !==, @Inject, override +- [ ] `ExportGeneratorX.xtend` (187 lines) — Hard — **dispatch**, extension, !==, ?., @Inject +- [ ] `ResourceDescriptionStrategyGenerator.xtend` (190 lines) — Hard — templates, extension, ===, !==, @Inject + +--- + +## Batch 6 — `xtext.expression` + `xtext.scope` + remaining small files (~12 files) + +### `xtext.expression` (3 files) +- [ ] `ExpressionExtensionsX.xtend` (87 lines) — Medium — **dispatch**, === +- [ ] `GenModelUtilX.xtend` (160 lines) — Hard — **dispatch**, extension, !==, create +- [ ] `CodeGenerationX.xtend` (373 lines) — Hard — **dispatch**, extension, ===, !==, #[ + +### `xtext.scope` (4 files) +- [ ] `ScopeGenerator.xtend` (83 lines) — Medium — extension, ===, !==, @Inject, override +- [ ] `ScopeNameProviderGenerator.xtend` (136 lines) — Medium — **dispatch**, templates, extension, switch +- [ ] `ScopeProviderX.xtend` (247 lines) — Hard — **dispatch**, extension, ===, !==, @Inject +- [ ] `ScopeProviderGenerator.xtend` (386 lines) — Hard — **dispatch**, templates, extension, ===, !==, #[, switch + +### `xtext.test.core` (1 file) +- [ ] `AbstractResourceDescriptionManagerTest.xtend` (198 lines) — Medium — ===, override, create + +### `xtext.ui` (1 file) +- [ ] `TemplateProposalProviderHelper.xtend` (82 lines) — Medium — templates, #[ + +### `xtext.ui.test` (1 file) +- [ ] `TemplateProposalProviderHelperTest.xtend` (265 lines) — Medium — templates, #[ + +--- + +## Batch 7 — `xtext.format` module (10 files, 1,980 lines) + +Includes the largest file in the project. Heavy use of dispatch, templates, create methods. + +### `xtext.format` (4 files) +- [ ] `FormatRuntimeModule.xtend` (115 lines) — Medium — extension, override +- [ ] `FormatGenerator.xtend` (93 lines) — Medium — **dispatch**, templates, extension, typeof, @Inject, override +- [ ] `FormatScopeProvider.xtend` (258 lines) — Hard — **dispatch**, typeof, ===, !==, create +- [ ] `FormatValidator.xtend` (376 lines) — Hard — ===, !==, override +- [ ] **`FormatJvmModelInferrer.xtend` (766 lines) — Very Hard** — dispatch, templates, extension, typeof, ===, !==, ?., #[, switch, create + +### `xtext.format.generator` (1 file) +- [ ] `FormatFragment2.xtend` (239 lines) — Hard — templates, extension, typeof, !==, ?., @Inject, override + +### Remaining test/ui files (already covered in other batches) + +--- + +## Batch 8 — `xtext.generator` module (18 files, 3,450 lines) + +The largest module. Includes ANTLR grammar generators — the hardest files in the project. + +### Simple (4 files) +- [ ] `PredicatesNaming.xtend` (35 lines) — Trivial — extension, @Inject +- [ ] `ModelInferenceFragment2.xtend` (49 lines) — Trivial — extension, !==, override +- [ ] `DefaultFragmentWithOverride.xtend` (54 lines) — Easy — ?., override, @Accessors +- [ ] `BuilderIntegrationFragment2.xtend` (60 lines) — Easy — templates, extension, !==, override + +### Medium (5 files) +- [ ] `ResourceFactoryFragment2.xtend` (76 lines) — Medium — templates, extension, !==, ?., @Accessors +- [ ] `CompareFragment2.xtend` (99 lines) — Medium — templates, extension, !==, @Inject +- [ ] `LanguageConstantsFragment2.xtend` (144 lines) — Medium — templates, extension, !==, ?., @Accessors +- [ ] `FormatterFragment2.xtend` (147 lines) — Medium — templates, extension, typeof, !==, ?., @Inject +- [ ] `XbaseGeneratorFragmentTest.xtend` (200 lines) — Medium — extension + +### Hard - Builder fragments (2 files) +- [ ] `StandaloneBuilderIntegrationFragment2.xtend` (165 lines) — Hard — templates, extension, @Inject +- [ ] `LspBuilderIntegrationFragment2.xtend` (174 lines) — Hard — templates, extension, @Inject + +### Hard - Content assist (1 file) +- [ ] `AnnotationAwareContentAssistFragment2.xtend` (226 lines) — Hard — **dispatch**, templates, extension, !==, ?., @Accessors + +### Very Hard - ANTLR generators (4 files) +- [ ] `AbstractAnnotationAwareAntlrGrammarGenerator.xtend` (159 lines) — Hard — templates, extension, @Inject +- [ ] `GrammarRuleAnnotations.xtend` (406 lines) — Very Hard — templates, ===, !==, ?., @Data +- [ ] `AnnotationAwareAntlrContentAssistGrammarGenerator.xtend` (489 lines) — Very Hard — **dispatch**, templates, extension, === +- [ ] `AnnotationAwareAntlrGrammarGenerator.xtend` (543 lines) — Very Hard — **dispatch**, templates, extension, !==, @Accessors, switch, create +- [ ] `AnnotationAwareXtextAntlrGeneratorFragment2.xtend` (529 lines) — Very Hard — templates, extension, ===, !==, #[, @Accessors, create + +--- + +## Batch 9 — Remaining test files (~4 files) + +### `check.core.test` (2 files) +- [ ] `IssueCodeToLabelMapGenerationTest.xtend` (130 lines) — Medium — templates, #[, switch +- [ ] `CheckValidationTest.xtend` (342 lines) — Hard — extension, typeof, create + +### `check.core.test` (1 file) +- [ ] `CheckFormattingTest.xtend` (554 lines) — Very Hard — templates, extension, typeof, !==, ?. + +### `check.ui.test` (1 file) +- [ ] `CheckQuickfixTest.xtend` (200 lines) — Medium — templates, #[, override + +--- + +## Build Config Cleanup (after all files migrated) + +- [ ] Remove `xtend-maven-plugin` from `ddk-parent/pom.xml` +- [ ] Remove `xtend.version` property from `ddk-parent/pom.xml` +- [ ] Remove PMD `excludeRoot` for xtend-gen from `ddk-parent/pom.xml` +- [ ] Remove clean plugin xtend-gen fileset from `ddk-parent/pom.xml` +- [ ] Remove `org.eclipse.xtend.lib` from ~10 MANIFEST.MF files +- [ ] Remove `xtend-gen` source entries from ~31 `.classpath` files +- [ ] Remove `xtend-gen` from ~31 `build.properties` files +- [ ] Update `.gitignore` to remove xtend-gen patterns +- [ ] Delete all `xtend-gen/` directories +- [ ] Final full build + test verification + +--- + +## Verification Protocol + +After each batch: + +1. **Compile**: `mvn clean compile -f ./ddk-parent/pom.xml --batch-mode` — must pass +2. **Test**: `mvn clean verify -f ./ddk-parent/pom.xml --batch-mode --fail-at-end` — must pass (except known UI test on macOS) +3. **Update** this checklist — mark converted files as done +4. **Commit** the batch + +--- + +## Conversion Rules Quick Reference + +| Xtend | Java | +|-------|------| +| `val x = expr` | `final ExplicitType x = expr;` | +| `var x = expr` | `ExplicitType x = expr;` | +| `def method()` | `public ReturnType method()` | +| `override method()` | `@Override public ReturnType method()` | +| `typeof(X)` | `X.class` | +| `===` / `!==` | `==` / `!=` | +| `obj?.method()` | null check or ternary | +| `[x \| body]` | `(x) -> body` | +| `dispatch method(T x)` | `_method(T x)` + dispatcher with `instanceof` | +| `@Inject extension Foo` | `@Inject private Foo foo;` + rewrite call sites | +| `'''template «expr»'''` | `StringBuilder` with `.append()` | +| `#[]` / `#{}` | `List.of()` / `Set.of()` | +| `obj.name` (property) | `obj.getName()` | +| `list += x` | `list.add(x)` | +| `a ?: b` | `a != null ? a : b` | +| `expr as Type` | `(Type) expr` or pattern matching | + +Full conversion prompt: [`docs/xtend-to-java-conversion-prompt.md`](xtend-to-java-conversion-prompt.md) + +--- + +## Complexity Legend + +| Rating | Criteria | +|--------|----------| +| **Trivial** | ≤30 lines, no complex Xtend features | +| **Easy** | ≤100 lines, basic features (val, override, @Inject, simple templates) | +| **Medium** | 100–200 lines, or uses templates + extension methods + switch | +| **Hard** | 200–400 lines with dispatch/complex templates/extension methods | +| **Very Hard** | 400+ lines with dispatch + templates + extensions + create methods | diff --git a/docs/xtend-to-java-conversion-prompt.md b/docs/xtend-to-java-conversion-prompt.md new file mode 100644 index 0000000000..ecdcd5e2aa --- /dev/null +++ b/docs/xtend-to-java-conversion-prompt.md @@ -0,0 +1,631 @@ +# Xtend-to-Java Conversion Prompt + +You are an expert Java and Xtend developer. Your task is to convert a single Xtend (.xtend) file into idiomatic Java (.java) targeting Java 21. The file belongs to the dsl-devkit project, an Eclipse/Xtext-based DSL development kit that uses Google Guice for dependency injection. + +## INPUT + +You will receive the complete contents of one `.xtend` file. + +## OUTPUT + +Return the complete, compilable `.java` file. The output must: +- Be valid Java 21 code +- Compile without errors in the context of the dsl-devkit project +- Preserve all original functionality exactly +- Be idiomatic Java (NOT a mechanical translation) +- Include all necessary imports + +--- + +## DECISIONS + +- **Target: Java 21** (pattern matching, switch expressions, text blocks, records) +- **Template strategy: `StringBuilder`** (pure Java, no Xtend runtime dependency) +- **No `var` keyword**: Always use explicit types (no Java 10 `var` / `final var`) + - `val catalog = ...` -> `final CheckCatalog catalog = ...;` (NOT `final var catalog = ...;`) + - `var skip = ...` -> `int skip = ...;` (NOT `var skip = ...;`) + - All local variables, fields, and parameters must have explicit type declarations. + +--- + +## CONVERSION RULES + +Apply these rules systematically, in order. Every rule is mandatory. + +### 1. FILE STRUCTURE AND BASICS + +1.1. **Package declaration**: Keep identical. Add semicolon if missing. + +1.2. **Imports**: Convert all Xtend imports to Java imports. +- `import com.foo.Bar` stays as `import com.foo.Bar;` +- `import static com.foo.Bar.*` stays as `import static com.foo.Bar.*;` +- `import static extension com.foo.Bar.*` becomes `import static com.foo.Bar.*;` (the `extension` keyword is dropped; see Rule 8 for call-site conversion) +- Remove imports for Xtend-specific types that are no longer needed (e.g., `org.eclipse.xtend2.lib.StringConcatenation` if you use StringBuilder instead) +- Add any new imports needed by the Java code (e.g., `java.util.List`, `java.util.ArrayList`, `java.util.stream.*`, `java.util.Objects`) +- Do NOT add wildcard imports. Use explicit imports. +- Remove unused imports. + +1.3. **Class declaration**: +- Xtend classes are `public` by default. Add `public` explicitly. +- `class Foo extends Bar` becomes `public class Foo extends Bar` +- Xtend `interface` stays as `interface` (already public by default in Java too). +- Add `{` and `}` braces as normal Java. + +1.4. **Semicolons**: Add semicolons to all statements. Xtend allows omitting them; Java requires them. + +### 2. VARIABLE DECLARATIONS + +2.1. **`val` (final local variable)**: +- Always use explicit types: `final ExplicitType name = expr;` +- Example: `val catalog = EcoreUtil2.getContainerOfType(context, CheckCatalog.class)` becomes `final CheckCatalog catalog = EcoreUtil2.getContainerOfType(context, CheckCatalog.class);` + +2.2. **`var` (mutable local variable)**: +- Always use explicit types: `ExplicitType name = expr;` +- Example: `var skip = instance - 1` becomes `int skip = instance - 1;` + +2.3. **`val` fields (class-level final fields)**: +- `val String FOO = "bar"` becomes `private final String FOO = "bar";` +- `val static Logger LOGGER = ...` becomes `private static final Logger LOGGER = ...;` +- Always add explicit visibility (`private` unless a different visibility is needed). + +2.4. **`var` fields (class-level mutable fields)**: +- `var String name` becomes `private String name;` +- Add explicit visibility. + +### 3. METHOD DECLARATIONS + +3.1. **`def` methods**: +- `def` means `public` by default. Add explicit `public`. +- `def private`, `def protected`, `def package` keep their visibility. +- Add explicit return type. If the Xtend method omits the return type, infer it from the method body. +- Example: `def outputPath()` with body `'.settings'` becomes `public String outputPath()` + +3.2. **`override` keyword**: +- Replace `override` with `@Override` annotation plus the appropriate visibility modifier. +- `override void doGenerate(...)` becomes: + ```java + @Override + public void doGenerate(...) { + ``` +- `override protected doGenerate()` becomes: + ```java + @Override + protected void doGenerate() { + ``` + +3.3. **Return types and implicit returns**: +- Xtend methods return the value of the last expression. In Java, add explicit `return` statements. +- If a method's last expression is a value, wrap it in `return`. +- For `void` methods, no return is needed. +- Example: Xtend `def foo() { bar }` becomes Java `public SomeType foo() { return bar; }` + +3.4. **Method parameters**: +- Add `final` to parameters in methods that do not reassign them (follow the convention of the existing Java code in the project). +- `extension` parameters: see Rule 8. + +### 4. TYPE REFERENCES + +4.1. **`typeof(X)` to `X.class`**: +- Replace all `typeof(ClassName)` with `ClassName.class`. +- Example: `typeof(CheckCatalog)` becomes `CheckCatalog.class` + +4.2. **Generic type syntax**: Xtend and Java use the same generic syntax. Keep as-is. + +4.3. **Type casting**: `expr as Type` becomes `(Type) expr` or use pattern matching with `instanceof` (Java 21). + +### 5. OPERATORS AND EXPRESSIONS + +5.1. **Identity comparison**: +- `===` (identity equals) becomes `==` in Java. +- `!==` (identity not-equals) becomes `!=` in Java. +- `==` in Xtend is `.equals()`. Convert to `.equals()` or `Objects.equals()` in Java (use `Objects.equals()` when either operand could be null). + +5.2. **Null-safe navigation `?.`**: +- `obj?.method()` becomes a null check. Use one of: + - Ternary: `obj != null ? obj.method() : null` + - If-statement for complex cases + - For chained null-safe calls, nest the ternaries or use local variables: + ```java + // Xtend: resource?.URI + // Java: + final URI uri = resource != null ? resource.getURI() : null; + ``` + - IMPORTANT: If the result of `?.` is used in a comparison against null (e.g., `resource?.URI !== null`), then use: `resource != null && resource.getURI() != null` + +5.3. **Elvis operator `?:`**: +- `a ?: b` becomes `a != null ? a : b` (or `Objects.requireNonNullElse(a, b)` if appropriate). + +5.4. **`=>` operator (with/apply)**: +- `obj => [ body ]` executes `body` with `obj` as `it`, then returns `obj`. +- Convert to: + ```java + { // inline block or extract to a method + ExplicitType temp = obj; + // body, replacing `it` references with `temp` + // return temp; // if the result is used + } + ``` +- For simple cases like `new Foo() => [bar = "baz"]`, convert to: + ```java + Foo foo = new Foo(); + foo.setBar("baz"); + // use foo + ``` + +5.5. **String concatenation `+`**: Same in Java. + +5.6. **Range operator `..`**: `0..n` becomes `IntStream.rangeClosed(0, n)` or a for-loop. + +5.7. **Power operator `**`**: Use `Math.pow()`. + +### 6. LAMBDA EXPRESSIONS + +6.1. **Xtend `[...]` lambda to Java `(...) -> {...}`**: +- `[x | x.name]` becomes `(x) -> x.getName()` or `x -> x.getName()` +- `[it | name]` becomes `(it) -> it.getName()` or simply use a method reference +- `[ body ]` (no parameters, implicit `it`) becomes `(it) -> { body }` where `it` is used, or `() -> { body }` if `it` is not used. +- Single-expression lambdas do not need braces: `x -> x.getName()` +- Multi-statement lambdas need braces and explicit `return`: `(x) -> { doSomething(); return x.getName(); }` + +6.2. **Lambda with `it` as implicit parameter**: +- When a lambda uses properties/methods without a receiver, these reference the implicit `it` parameter. +- `[name]` on a `Function1` becomes `(Foo it) -> it.getName()` or `Foo::getName` +- Xtend: `checks.filter[name !== null]` becomes Java: `checks.stream().filter(c -> c.getName() != null).toList()` + +6.3. **Procedure (void lambda) vs Function (returning lambda)**: +- Xtend uses the same `[...]` syntax for both. +- In Java, determine from context whether it is `Consumer`, `Predicate`, `Function`, etc. +- For Xtext-specific cases: `Procedure1` lambdas like `[noSpace]` become `(IHiddenRegionFormatter it) -> { it.noSpace(); }` or `IHiddenRegionFormatter::noSpace`. + +### 7. DISPATCH METHODS + +This is one of the most complex Xtend features. Dispatch methods implement multiple dispatch (method selection based on runtime type of arguments). + +7.1. **Pattern**: A set of `def dispatch` methods with the same name but different parameter types: +```xtend +def dispatch void format(CheckCatalog c, IFormattableDocument doc) { ... } +def dispatch void format(Category c, IFormattableDocument doc) { ... } +def dispatch void format(EObject obj, IFormattableDocument doc) { ... } +``` + +7.2. **Conversion strategy**: Convert to individual `protected` methods prefixed with `_` (underscore) plus a public dispatcher method: + +```java +protected void _format(CheckCatalog c, IFormattableDocument doc) { ... } +protected void _format(Category c, IFormattableDocument doc) { ... } +protected void _format(EObject obj, IFormattableDocument doc) { ... } + +public void format(Object obj, IFormattableDocument doc) { + if (obj instanceof CheckCatalog c) { + _format(c, doc); + return; + } else if (obj instanceof Category c) { + _format(c, doc); + return; + } else if (obj instanceof EObject e) { + _format(e, doc); + return; + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + obj); + } +} +``` + +7.3. **Important dispatch rules**: +- Order type checks from most specific to least specific. +- If a dispatch method has `override` keyword, add `@Override` to the dispatcher method, not the individual `_` methods. +- The dispatcher parameter type should be the common supertype (usually `Object` or `EObject`). +- If the parent class also has dispatch methods with the same name, the dispatcher must call `super._methodName()` for types not handled locally. +- Use Java 21 pattern matching for instanceof (`if (obj instanceof Foo f)`) in the dispatcher. + +### 8. EXTENSION METHODS + +8.1. **`@Inject extension ClassName fieldName`**: +- Convert to: `@Inject private ClassName fieldName;` +- At every call site where the extension's methods were called as `obj.extensionMethod(args)`, convert to `fieldName.extensionMethod(obj, args)`. +- If the extension field was used without a name (e.g., `@Inject extension CheckGeneratorNaming`), generate a field name following the convention: `_checkGeneratorNaming` (underscore + camelCase class name starting lowercase). + +8.2. **`extension` method parameters** (e.g., `def foo(extension IFormattableDocument document)`): +- Drop the `extension` keyword from the parameter. +- At call sites within the method body, calls that were dispatched to the extension parameter need to be converted to explicit calls: + - `prepend(checkcatalog)[noSpace]` becomes `document.prepend(checkcatalog, (IHiddenRegionFormatter it) -> it.noSpace())` + +8.3. **`static extension` imports** (e.g., `import static extension com.foo.Bar.*`): +- Convert to `import static com.foo.Bar.*;` +- At call sites: `obj.staticExtensionMethod(args)` becomes `Bar.staticExtensionMethod(obj, args)`. +- Example: `import static extension org.eclipse.xtext.GrammarUtil.*` then `grammar.simpleName` becomes `GrammarUtil.getSimpleName(grammar)`. + +8.4. **`extension` keyword on `val`/`var`** (e.g., `val extension naming = contentAssistNaming`): +- Drop `extension` keyword. Keep as a local variable. +- Convert call sites within scope to explicit calls on the variable. + +### 9. TEMPLATE EXPRESSIONS (GUILLEMETS) + +This is the MOST COMPLEX feature. Template expressions use triple single quotes and guillemets (French quotes). + +9.1. **Simple templates** (no control flow, just interpolation): +- If the template is a single line or very short, use string concatenation or `String.format()`: + ```xtend + '''{predicates.«predicate.name»(parserContext)}?=>''' + ``` + becomes: + ```java + "{predicates." + predicate.getName() + "(parserContext)}?=>" + ``` + +9.2. **Multi-line templates generating code/text**: Use `StringBuilder`: +```xtend +def compile(CheckConfiguration config) { + val properties = propertiesGenerator.convertToProperties(config); + ''' + «FOR k:properties.keySet» + «k»=«properties.get(k)» + «ENDFOR» + ''' +} +``` +becomes: +```java +public CharSequence compile(CheckConfiguration config) { + final Properties properties = propertiesGenerator.convertToProperties(config); + final StringBuilder builder = new StringBuilder(); + for (final String k : properties.keySet()) { + builder.append(k).append("=").append(properties.get(k)).append("\n"); + } + return builder; +} +``` + +9.3. **Template control flow**: +- `«IF condition»...«ENDIF»` becomes `if (condition) { builder.append(...); }` +- `«IF condition»...«ELSE»...«ENDIF»` becomes `if-else` +- `«ELSEIF condition»` becomes `else if (condition)` +- `«FOR item : collection»...«ENDFOR»` becomes `for (Type item : collection) { builder.append(...); }` +- `«FOR item : collection SEPARATOR sep»...«ENDFOR»` -- use a boolean flag or `String.join()` or `Collectors.joining()`: + ```java + builder.append(collection.stream() + .map(item -> /* expression */) + .collect(Collectors.joining(sep))); + ``` +- `«val x = expr»` inside a template is a local variable declaration. Declare it before use. + +9.4. **Template indentation**: +- Xtend templates preserve indentation relative to the insertion point. In the Java conversion, you do NOT need to replicate this Xtend-specific whitespace behavior exactly. Instead: + - For code generators producing source code: use explicit `\n` and string indentation as appropriate. + - For simple cases, inline `\n` in the StringBuilder appends. + - For complex generators, consider creating a helper method or using a `StringJoiner`. + +9.5. **Return type**: Methods returning template expressions should return `CharSequence` (to match Xtend's `StringConcatenation` return type, which implements `CharSequence`). Alternatively, return `String` if all callers use it as `String` (add `.toString()` call on the `StringBuilder`). + +9.6. **`«expression»` interpolation**: Convert `«expr»` to the corresponding Java expression inside a `.append()` call. +- `«catalog.name»` becomes `.append(catalog.getName())` +- `«IF grammar !== null»GRAMMAR_NAME,«ENDIF»` becomes: + ```java + if (grammar != null) { + builder.append("GRAMMAR_NAME,"); + } + ``` + +### 10. COLLECTION LITERALS AND OPERATIONS + +10.1. **`#[]` (list literal)**: +- `#["a", "b", "c"]` becomes `List.of("a", "b", "c")` (immutable) or `new ArrayList<>(List.of("a", "b", "c"))` (mutable). +- Empty: `#[]` becomes `List.of()` or `new ArrayList<>()`. +- `newArrayList` becomes `new ArrayList<>()` or `new ArrayList<>(...)`. +- `newArrayList("a", "b")` becomes `new ArrayList<>(List.of("a", "b"))` or `Lists.newArrayList("a", "b")` (if Google Guava is available, which it is in this project). + +10.2. **`#{}` (set literal)**: +- `#{"a", "b"}` becomes `Set.of("a", "b")` or `new HashSet<>(Set.of("a", "b"))`. +- `newHashSet` becomes `new HashSet<>()` or `Sets.newHashSet(...)`. + +10.3. **Collection operations** (Xtend extension methods on Iterable/Collection): +- `.map[expr]` becomes `.stream().map(x -> expr).toList()` or `.stream().map(x -> expr).collect(Collectors.toList())` +- `.filter[expr]` becomes `.stream().filter(x -> expr).toList()` +- `.filter(Type)` becomes `.stream().filter(Type.class::isInstance).map(Type.class::cast).toList()` OR use Guava `Iterables.filter(collection, Type.class)` +- `.exists[expr]` becomes `.stream().anyMatch(x -> expr)` +- `.forall[expr]` becomes `.stream().allMatch(x -> expr)` +- `.findFirst[expr]` becomes `.stream().filter(x -> expr).findFirst().orElse(null)` +- `.head` becomes `.get(0)` (for List) or `.iterator().next()` (for Iterable), with null safety if needed +- `.tail` becomes `.subList(1, list.size())` or `.stream().skip(1).toList()` +- `.toList` becomes `.stream().toList()` or `new ArrayList<>(iterable)` or `IterableExtensions.toList(iterable)` +- `.toSet` becomes `new HashSet<>(collection)` or `.stream().collect(Collectors.toSet())` +- `.flatten` becomes `.stream().flatMap(Collection::stream).toList()` +- `.sortBy[expr]` becomes `.stream().sorted(Comparator.comparing(x -> expr)).toList()` +- `.sort` becomes `.stream().sorted().toList()` or `Collections.sort(list)` for in-place +- `.join(',')` becomes `String.join(",", collection)` or `.stream().collect(Collectors.joining(","))` +- `.indexed` becomes use `IntStream.range(0, list.size())` with index access, or keep Guava if present +- `.reverse` becomes `Collections.reverse(new ArrayList<>(list))` or use `Lists.reverse(list)` (Guava) +- `.isEmpty` / `.empty` becomes `.isEmpty()` +- `.size` becomes `.size()` +- `.forEach[action]` becomes `.forEach(x -> action)` (Java Iterable.forEach or Stream.forEach) +- `.filterNull` becomes `.stream().filter(Objects::nonNull).toList()` + +10.4. **`isNullOrEmpty`**: +- `StringExtensions.isNullOrEmpty(s)` or `s.isNullOrEmpty` becomes `s == null || s.isEmpty()` +- Or use a utility method if the project has one. + +10.5. **`toIterable(iterator)`**: `IteratorExtensions.toIterable(resource.getAllContents())` -- keep this call as-is since it is an Xtext utility, OR convert to: `() -> resource.getAllContents()` (creating an Iterable from Iterator). + +10.6. **`Iterables.filter(iterable, Class)`**: Keep this Guava call as-is -- it is idiomatic in Eclipse/Xtext projects. + +10.7. **Operator overloading on collections**: +- `list += element` becomes `list.add(element)` +- `list += otherList` becomes `list.addAll(otherList)` +- `list -= element` becomes `list.remove(element)` +- `map.get(key)` -- same in Java (Xtend allows `map[key]` syntax which becomes `map.get(key)`) + +### 11. PROPERTY ACCESS SYNTAX + +11.1. Xtend allows property-style access for getters/setters: +- `obj.name` may mean `obj.getName()` -- convert to explicit getter call +- `obj.name = value` may mean `obj.setName(value)` -- convert to explicit setter call +- `obj.isActive` may mean `obj.isActive()` or `obj.getIsActive()` -- determine from context + +11.2. Boolean property access: +- `field.final` means `field.isFinal()` +- `field.static` means `field.isStatic()` + +11.3. **IMPORTANT**: Not all dot-access is property access. If the object actually has a public field, keep field access. Determine from the types involved. + +### 12. SWITCH EXPRESSIONS + +12.1. **Basic switch**: +```xtend +switch(x) { + case "a": doA() + case "b": doB() + default: doDefault() +} +``` +becomes Java switch expression or statement depending on context. + +12.2. **Switch with type guards**: +```xtend +switch obj { + CheckCatalog: obj.name + Category case obj.name !== null: obj.label + default: "unknown" +} +``` +becomes: +```java +if (obj instanceof CheckCatalog checkCatalog) { + return checkCatalog.getName(); +} else if (obj instanceof Category category && category.getName() != null) { + return category.getLabel(); +} else { + return "unknown"; +} +``` + +12.3. Use Java 21 pattern matching for instanceof where applicable. + +### 13. ACTIVE ANNOTATIONS + +13.1. **`@Data`**: This generates `equals()`, `hashCode()`, `toString()`, and getters for all fields (which are final). Convert to a Java `record` if the class has no mutable state and no superclass. Otherwise, manually add: +- All-args constructor +- Getter methods for each field +- `equals()`, `hashCode()`, `toString()` +- Or use `@Override` of these methods if the class extends something. + +For inner static classes annotated with `@Data` that have `val` fields and no superclass (like this project's `NoBacktrack`, `SemanticPredicate`, `GrammarAnnotations`), prefer Java records: +```java +public record SemanticPredicate(String name, String message, String grammar, List keywords) {} +``` + +13.2. **`@Accessors`**: Generates getters (and setters for `var` fields). +- `@Accessors boolean foo` generates `getFoo()` and `setFoo(boolean)`. +- `@Accessors(PUBLIC_SETTER) String bar` generates only a public setter. +- `@Accessors(PROTECTED_GETTER) Foo baz` generates only a protected getter. +- Convert by manually writing the getter/setter methods with the specified visibility. + +13.3. **`@FinalFieldsConstructor`**: Generates a constructor taking all final fields as parameters. Manually write the constructor. + +### 14. SPECIAL XTEND PATTERNS + +14.1. **`it` implicit parameter**: +- When a method declares `Type it` as its first parameter (e.g., `def generate(ExportModel it, ...)`), all unqualified method/property calls in the body refer to `it`. +- Convert: Add the parameter with a proper name (e.g., `exportModel`) and qualify all calls: + - `exports` becomes `exportModel.getExports()` + - `grammar` becomes `exportModel.getGrammar()` (if it's a property of ExportModel) + - `extension` becomes `exportModel.isExtension()` + +14.2. **`this` vs receiver**: In Xtend, method calls without a receiver may go to `this`, an extension, or `it`. You must determine which based on the type hierarchy. Check: + 1. Is it a method on the current class or its superclass? -> `this.method()` or just `method()` + 2. Is it an extension method from an `@Inject extension` field? -> `field.method(obj)` + 3. Is it a static extension method? -> `ExtClass.method(obj)` + 4. Is it on the `it` implicit receiver? -> `it.method()` using the renamed parameter + +14.3. **Multiple return statements**: Xtend methods implicitly return the last expression. You MUST add explicit `return` for ALL non-void return paths. + +14.4. **`class` keyword access**: In Xtend, `SomeClass` by itself in certain contexts refers to the class literal. In Java, use `SomeClass.class`. + +14.5. **Static method access with `::`**: `ClassName::methodName` or `ClassName::FIELD` becomes `ClassName.methodName()` or `ClassName.FIELD` in Java. + +14.6. **Pairs**: `key -> value` becomes `Pair.of(key, value)` or `Map.entry(key, value)` depending on context. + +### 15. GUICE DEPENDENCY INJECTION + +15.1. **`@Inject` fields**: Keep as-is. These are standard Guice annotations. +- `@Inject ClassName fieldName` becomes `@Inject private ClassName fieldName;` +- Add `private` visibility if not already present. +- If the field was an `extension`, see Rule 8. + +15.2. **`@Inject extension`**: See Rule 8.1. + +### 16. COMMENTS AND DOCUMENTATION + +16.1. **Preserve ALL comments**: Copy Javadoc (`/** */`), block comments (`/* */`), and line comments (`//`) exactly as they appear. + +16.2. **Copyright headers**: Keep the exact copyright header from the original file. + +16.3. **`@SuppressWarnings("all")`**: The Xtend compiler adds this. Do NOT add it to the converted Java file unless it was explicitly in the Xtend source. + +### 17. XTEND LIBRARY REPLACEMENTS + +Replace Xtend runtime library calls with Java standard library or Guava equivalents: + +| Xtend Library Call | Java Replacement | +|---|---| +| `IterableExtensions.map(iter, fn)` | `iter.stream().map(fn).toList()` | +| `IterableExtensions.filter(iter, fn)` | `iter.stream().filter(fn).toList()` | +| `IterableExtensions.toList(iter)` | `Lists.newArrayList(iter)` or stream | +| `IterableExtensions.toSet(iter)` | `Sets.newHashSet(iter)` or stream | +| `IterableExtensions.head(iter)` | `iter.iterator().next()` with null check, or `Iterables.getFirst(iter, null)` | +| `IterableExtensions.join(iter, sep)` | `String.join(sep, iter)` or `Joiner.on(sep).join(iter)` | +| `IterableExtensions.exists(iter, fn)` | `iter.stream().anyMatch(fn)` | +| `IterableExtensions.forall(iter, fn)` | `iter.stream().allMatch(fn)` | +| `IterableExtensions.findFirst(iter, fn)` | `iter.stream().filter(fn).findFirst().orElse(null)` | +| `IterableExtensions.sortBy(iter, fn)` | `iter.stream().sorted(Comparator.comparing(fn)).toList()` | +| `IterableExtensions.sort(iter)` | `iter.stream().sorted().toList()` | +| `IterableExtensions.isEmpty(iter)` | `!iter.iterator().hasNext()` or `Iterables.isEmpty(iter)` | +| `IterableExtensions.toMap(iter, keyFn, valFn)` | `iter.stream().collect(Collectors.toMap(keyFn, valFn))` | +| `IteratorExtensions.toIterable(iter)` | Keep as utility or wrap: `(Iterable) () -> iter` | +| `StringExtensions.isNullOrEmpty(s)` | `s == null \|\| s.isEmpty()` | +| `CollectionLiterals.newArrayList(...)` | `new ArrayList<>(List.of(...))` or `Lists.newArrayList(...)` | +| `CollectionLiterals.newHashSet(...)` | `new HashSet<>(Set.of(...))` or `Sets.newHashSet(...)` | +| `CollectionLiterals.newHashMap(...)` | `new HashMap<>(Map.of(...))` or `Maps.newHashMap()` | +| `ObjectExtensions.operator_doubleArrow(obj, fn)` | inline (see Rule 5.4) | +| `Functions.Function1` | `java.util.function.Function` | +| `Procedures.Procedure1` | `java.util.function.Consumer` | + +**IMPORTANT**: If the existing Java code in the project uses Guava (which this project does extensively), prefer Guava utilities over Java streams for consistency. For example, prefer `Iterables.filter(iter, Type.class)` over `iter.stream().filter(...)`. + +### 18. FORMATTING AND STYLE + +18.1. Use standard Java formatting: +- 2-space indentation (to match this project's convention) +- Opening brace on same line +- Spaces around operators +- Blank line between methods + +18.2. Keep the original method ordering from the Xtend file. + +18.3. Use `this.` qualifier only when needed for disambiguation (e.g., with injected fields sharing names with parameters). + +### 19. CHECKED EXCEPTIONS + +19.1. Xtend does not enforce checked exceptions. When converting to Java, methods that call APIs that throw checked exceptions need proper handling: +- Add `throws` declarations to the method signature, OR +- Wrap in try-catch blocks +- Check the actual APIs being called to determine which checked exceptions need handling +- Example: `CoreException` from Eclipse APIs, `IOException` from I/O operations + +--- + +## CHECKLIST + +Before returning the converted file, verify: + +- [ ] All `val` converted to `final ExplicitType` (no `var` keyword) +- [ ] All `var` converted to `ExplicitType` (no `var` keyword) +- [ ] All `def` converted to proper Java method with visibility, return type, and `return` statements +- [ ] All `override` converted to `@Override` annotation +- [ ] All `typeof(X)` converted to `X.class` +- [ ] All `===` / `!==` converted to `==` / `!=` +- [ ] All `?.` null-safe navigation converted to null checks +- [ ] All `[...]` lambdas converted to `(...) -> {...}` +- [ ] All `dispatch` methods converted to dispatcher pattern +- [ ] All `extension` methods converted to explicit calls +- [ ] All `static extension` imports converted to static calls +- [ ] All template expressions `'''...«»...'''` converted to StringBuilder +- [ ] All `«IF»/«FOR»/«SEPARATOR»` converted to Java control flow +- [ ] All `#[]` / `#{}` collection literals converted +- [ ] All `=>` operator usages converted +- [ ] All `@Data` / `@Accessors` active annotations expanded +- [ ] All property access (`.name`) converted to getter/setter calls (`.getName()`) +- [ ] All `isNullOrEmpty` and Xtend library calls replaced +- [ ] All `+=` on collections converted to `.add()` / `.addAll()` +- [ ] All `::` static access converted to `.` +- [ ] Semicolons added to all statements +- [ ] Explicit visibility modifiers on all classes, methods, fields +- [ ] All imports updated (Xtend-specific removed, Java ones added) +- [ ] All comments and Javadoc preserved +- [ ] Copyright header preserved exactly +- [ ] No `@SuppressWarnings("all")` added (unless in original source) +- [ ] Checked exceptions properly handled (throws or try-catch) +- [ ] File compiles as valid Java 21 + +--- + +## EXAMPLE CONVERSION + +### Xtend Input: +```xtend +package com.example + +import com.google.inject.Inject +import org.eclipse.emf.ecore.resource.Resource +import static org.eclipse.xtext.xbase.lib.IteratorExtensions.* +import static extension com.example.NamingExtensions.* + +class MyGenerator { + @Inject extension MyHelper helper + + override void doGenerate(Resource resource) { + val config = getConfig(resource?.URI) + for (model : toIterable(resource.allContents).filter(typeof(MyModel))) { + model.compile + } + } + + def compile(MyModel it) ''' + package «packageName»; + «IF !imports.isNullOrEmpty» + + «FOR imp : imports» + import «imp»; + «ENDFOR» + «ENDIF» + + public class «name» { + } + ''' +} +``` + +### Java Output: +```java +package com.example; + +import com.google.inject.Inject; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.xbase.lib.IteratorExtensions; + +import com.google.common.collect.Iterables; + +public class MyGenerator { + + @Inject + private MyHelper helper; + + @Override + public void doGenerate(final Resource resource) { + final URI uri = resource != null ? resource.getURI() : null; + final MyConfig config = getConfig(uri); + for (final MyModel model : Iterables.filter(IteratorExtensions.toIterable(resource.getAllContents()), MyModel.class)) { + compile(model); + } + } + + public CharSequence compile(final MyModel model) { + final StringBuilder builder = new StringBuilder(); + builder.append("package ").append(model.getPackageName()).append(";\n"); + if (!(model.getImports() == null || model.getImports().isEmpty())) { + builder.append("\n"); + for (final String imp : model.getImports()) { + builder.append("import ").append(imp).append(";\n"); + } + } + builder.append("\n"); + builder.append("public class ").append(NamingExtensions.getName(model)).append(" {\n"); + builder.append("}\n"); + return builder; + } +} +``` + +--- + +Now convert the following Xtend file to idiomatic Java following ALL the rules above: From 9be7c8668117dac33e6cdd4c5a79df6588e86279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 28 Feb 2026 11:40:49 +0100 Subject: [PATCH 04/23] feat: migrate Batch 2+3 Xtend files to Java 21 (28 files) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate 28 Xtend files across 14 modules to idiomatic Java 21. All files are Trivial/Easy complexity (≤100 lines each). Modules touched: check.core.test, check.test.runtime, check.test.runtime.tests, check.ui, checkcfg.core, checkcfg.core.test, sample.helloworld.ui.test, xtext.check.generator, xtext.expression, xtext.format, xtext.format.ide, xtext.format.test, xtext.format.ui, xtext.generator Progress: 36/94 files migrated (38%) Co-Authored-By: Claude Opus 4.6 --- .../tools/ddk/check/core/test/BugAig830.java | 58 +++++++++ .../tools/ddk/check/core/test/BugAig830.xtend | 56 --------- .../ddk/check/core/test/CheckScopingTest.java | 84 +++++++++++++ .../check/core/test/CheckScopingTest.xtend | 81 ------------ .../check/core/test/util/CheckTestUtil.java | 73 +++++++++++ .../check/core/test/util/CheckTestUtil.xtend | 72 ----------- ...d => CheckConfigurationIsAppliedTest.java} | 61 ++++----- .../test/runtime/label/IssueLabelTest.java | 61 +++++++++ .../test/runtime/label/IssueLabelTest.xtend | 56 --------- ...rator.xtend => TestLanguageGenerator.java} | 17 +-- .../ddk/check/ui/wizard/CheckNewProject.java | 52 ++++++++ .../ddk/check/ui/wizard/CheckNewProject.xtend | 50 -------- .../ui/wizard/CheckQuickfixProvider.java | 62 ++++++++++ .../ui/wizard/CheckQuickfixProvider.xtend | 63 ---------- ...ModelUtil.xtend => CheckCfgModelUtil.java} | 28 ++--- .../ddk/checkcfg/util/CheckCfgTestUtil.java | 37 ++++++ .../ddk/checkcfg/util/CheckCfgTestUtil.xtend | 32 ----- ...CfgConfiguredParameterValidationsTest.java | 67 ++++++++++ ...fgConfiguredParameterValidationsTest.xtend | 63 ---------- .../ddk/checkcfg/validation/CheckCfgTest.java | 58 +++++++++ .../checkcfg/validation/CheckCfgTest.xtend | 63 ---------- .../checkcfg/generator/CheckCfgGenerator.java | 55 ++++++++ .../generator/CheckCfgGenerator.xtend | 53 -------- ...er.xtend => CheckCfgJvmModelInferrer.java} | 22 ++-- .../validation/ConfiguredParameterChecks.java | 81 ++++++++++++ .../ConfiguredParameterChecks.xtend | 66 ---------- ...d => CheckConfigurationIsAppliedTest.java} | 61 ++++----- .../helloworld/label/IssueLabelTest.java | 60 +++++++++ .../helloworld/label/IssueLabelTest.xtend | 56 --------- ...nt2.xtend => CheckValidatorFragment2.java} | 29 ++--- .../CheckQuickfixProviderFragment2.java | 117 ++++++++++++++++++ .../CheckQuickfixProviderFragment2.xtend | 82 ------------ .../expression/generator/GeneratorUtilX.java | 30 +++++ .../expression/generator/GeneratorUtilX.xtend | 30 ----- .../generator/{Naming.xtend => Naming.java} | 20 ++- .../ddk/xtext/format/ide/FormatIdeModule.java | 11 ++ .../xtext/format/ide/FormatIdeModule.xtend | 11 -- .../ddk/xtext/format/ide/FormatIdeSetup.java | 21 ++++ .../ddk/xtext/format/ide/FormatIdeSetup.xtend | 20 --- .../ddk/xtext/format/FormatParsingTest.java | 41 ++++++ .../ddk/xtext/format/FormatParsingTest.xtend | 40 ------ .../ddk/xtext/format/ui/FormatUiModule.java | 55 ++++++++ .../ddk/xtext/format/ui/FormatUiModule.xtend | 47 ------- ...Setup.xtend => FormatStandaloneSetup.java} | 8 +- .../BundleVersionStripperFragment.java | 58 +++++++++ .../BundleVersionStripperFragment.xtend | 48 ------- .../model/project/ProjectConfig.java | 94 ++++++++++++++ .../model/project/ProjectConfig.xtend | 49 -------- docs/xtend-migration.md | 96 +++++++------- 49 files changed, 1347 insertions(+), 1208 deletions(-) create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.xtend create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.xtend create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.xtend rename com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/{CheckConfigurationIsAppliedTest.xtend => CheckConfigurationIsAppliedTest.java} (52%) create mode 100644 com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/label/IssueLabelTest.java delete mode 100644 com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/label/IssueLabelTest.xtend rename com.avaloq.tools.ddk.check.test.runtime/src/com/avaloq/tools/ddk/check/generator/{TestLanguageGenerator.xtend => TestLanguageGenerator.java} (57%) create mode 100644 com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java delete mode 100644 com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.xtend create mode 100644 com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java delete mode 100644 com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.xtend rename com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/{CheckCfgModelUtil.xtend => CheckCfgModelUtil.java} (55%) create mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgTestUtil.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgTestUtil.xtend create mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.xtend create mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.xtend create mode 100644 com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.xtend rename com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/{CheckCfgJvmModelInferrer.xtend => CheckCfgJvmModelInferrer.java} (69%) create mode 100644 com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.xtend rename com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/{CheckConfigurationIsAppliedTest.xtend => CheckConfigurationIsAppliedTest.java} (51%) create mode 100644 com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/label/IssueLabelTest.java delete mode 100644 com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/label/IssueLabelTest.xtend rename com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/{CheckValidatorFragment2.xtend => CheckValidatorFragment2.java} (54%) create mode 100644 com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtilX.java delete mode 100644 com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtilX.xtend rename com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/{Naming.xtend => Naming.java} (51%) create mode 100644 com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeModule.java delete mode 100644 com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeModule.xtend create mode 100644 com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeSetup.java delete mode 100644 com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeSetup.xtend create mode 100644 com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.java delete mode 100644 com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.xtend create mode 100644 com.avaloq.tools.ddk.xtext.format.ui/src/com/avaloq/tools/ddk/xtext/format/ui/FormatUiModule.java delete mode 100644 com.avaloq.tools.ddk.xtext.format.ui/src/com/avaloq/tools/ddk/xtext/format/ui/FormatUiModule.xtend rename com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/{FormatStandaloneSetup.xtend => FormatStandaloneSetup.java} (54%) create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/model/project/ProjectConfig.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/model/project/ProjectConfig.xtend diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.java new file mode 100644 index 0000000000..e01d28d99e --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.core.test; + +import com.avaloq.tools.ddk.check.CheckUiInjectorProvider; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import com.google.inject.Inject; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.xbase.XbasePackage; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@InjectWith(CheckUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class BugAig830 { + + @Inject + private ParseHelper parser; + + private String getModel() { + return "package abc\n" + + "import org.eclipse.xtext.xbase.XVariableDeclaration\n" + + "catalog Abc\n" + + "for grammar com.avaloq.tools.ddk.check.Check {\n" + + " live error \"Test\" {\n" + + " for XVariableDeclaration v {\n" + + " issue on v#name\n" + + " }\n" + + " }\n" + + "}\n"; + } + + /* Tests that EPackages which are not of declared target language can be referenced. */ + @Test + public void bugAig830() throws Exception { + final CheckCatalog model = parser.parse(getModel()); + final XIssueExpression issue = EcoreUtil2.getAllContentsOfType(model, XIssueExpression.class).get(0); + assertNotNull(issue.getMarkerFeature()); + assertFalse(issue.getMarkerFeature().eIsProxy()); + assertEquals(XbasePackage.Literals.XVARIABLE_DECLARATION, issue.getMarkerFeature().getEContainingClass()); + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.xtend deleted file mode 100644 index 854dace54c..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.xtend +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.core.test - -import com.avaloq.tools.ddk.check.CheckUiInjectorProvider -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.check.XIssueExpression -import com.google.inject.Inject -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.util.ParseHelper -import org.eclipse.xtext.xbase.XbasePackage -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.^extension.ExtendWith -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* - -@InjectWith(typeof(CheckUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class BugAig830 { - - @Inject - ParseHelper parser - - def private getModel() ''' - package abc - import org.eclipse.xtext.xbase.XVariableDeclaration - catalog Abc - for grammar com.avaloq.tools.ddk.check.Check { - live error "Test" { - for XVariableDeclaration v { - issue on v#name - } - } - } - ''' - - /* Tests that EPackages which are not of declared target language can be referenced. */ - @Test - def void bugAig830() { - val model = parser.parse(getModel()) - val issue = EcoreUtil2::getAllContentsOfType(model, typeof(XIssueExpression)).get(0) - assertNotNull(issue.markerFeature) - assertFalse(issue.markerFeature.eIsProxy) - assertEquals(XbasePackage.Literals::XVARIABLE_DECLARATION, issue.markerFeature.EContainingClass) - } - -} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.java new file mode 100644 index 0000000000..05e454d12d --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.core.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.avaloq.tools.ddk.check.CheckUiInjectorProvider; +import com.avaloq.tools.ddk.check.check.Check; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.Implementation; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import com.avaloq.tools.ddk.check.core.test.util.CheckTestUtil; +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import java.util.List; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@InjectWith(CheckUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class CheckScopingTest extends AbstractCheckTestCase { + + @Inject + private CheckTestUtil util; + + /* + * The model names are deliberately not including file extension, the actual resources + * are also missing them. The reason for this is that if current development instance of + * Eclipse has the Check runtime plugins installed, code will automatically be generated + * for those resources. In order to avoid that the file extensions have been omitted. + */ + public List getRequiredSourceFileNames() { + return Lists.newArrayList("CommonChecks", "SampleChecks"); + } + + public void initializeTestProject() { + // sources are copied into the project and then built by the Xtext builder + addSourcesToWorkspace(CheckScopingTest.class, getRequiredSourceFileNames()); + // wait for build to finish, otherwise included catalog may not be resolvable + IResourcesSetupUtil.waitForBuild(); + } + + /* + * Tests that a catalog may not reference checks (in implementations, 'def') which are + * neither local nor included. + */ + @Test + public void testIllegalDirectionOfReference() throws Exception { + initializeTestProject(); + + // test that our model is available + final CheckCatalog model = (CheckCatalog) getModel("CommonChecks"); + + final Implementation illegalRefImpl = util.getFirstInstanceOf(model, Implementation.class); + final XIssueExpression issueExpr = util.getFirstInstanceOf(illegalRefImpl, XIssueExpression.class); + + assertTrue(issueExpr.getCheck().eIsProxy(), "Referenced check cannot be resolved"); + assertNull(issueExpr.getCheck().getName(), "Referenced check name is null"); + } + + /* + * Tests that a check may be documented using a ML_COMMENT. The documentation is inferred + * in the description field of a check. + */ + @Test + public void testCheckDescriptionIsInferred() throws Exception { + initializeTestProject(); + final Check check = util.getFirstInstanceOf(getModel("CommonChecks"), Check.class); + assertEquals("This check is javadoc-like commented.", check.getDescription(), "Referenced check cannot be resolved"); + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.xtend deleted file mode 100644 index fd8572269a..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.xtend +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.core.test - -import com.avaloq.tools.ddk.check.CheckUiInjectorProvider -import com.avaloq.tools.ddk.check.check.Check -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.check.Implementation -import com.avaloq.tools.ddk.check.check.XIssueExpression -import com.avaloq.tools.ddk.check.core.test.util.CheckTestUtil -import com.google.common.collect.Lists -import com.google.inject.Inject -import java.util.List -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* - -@InjectWith(typeof(CheckUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class CheckScopingTest extends AbstractCheckTestCase { - - @Inject CheckTestUtil util - - /* - * The model names are deliberately not including file extension, the actual resources - * are also missing them. The reason for this is that if current development instance of - * Eclipse has the Check runtime plugins installed, code will automatically be generated - * for those resources. In order to avoid that the file extensions have been omitted. - */ - def List getRequiredSourceFileNames() { - Lists::newArrayList("CommonChecks", "SampleChecks") - } - - def void initializeTestProject() { - // sources are copied into the project and then built by the Xtext builder - addSourcesToWorkspace(typeof(CheckScopingTest), requiredSourceFileNames) - - // wait for build to finish, otherwise included catalog may not be resolvable - IResourcesSetupUtil.waitForBuild - } - - /* - * Tests that a catalog may not reference checks (in implementations, 'def') which are - * neither local nor included. - */ - @Test - def void testIllegalDirectionOfReference() { - initializeTestProject - - // test that our model is available - val model = getModel("CommonChecks") as CheckCatalog - - val illegalRefImpl = util.getFirstInstanceOf(model, typeof(Implementation)) - val issueExpr = util.getFirstInstanceOf(illegalRefImpl, typeof(XIssueExpression)) - - assertTrue(issueExpr.check.eIsProxy, "Referenced check cannot be resolved") - assertNull(issueExpr.check.name, "Referenced check name is null") - } - - /* - * Tests that a check may be documented using a ML_COMMENT. The documentation is inferred - * in the description field of a check. - */ - @Test - def void testCheckDescriptionIsInferred() { - initializeTestProject - val check = util.getFirstInstanceOf(getModel("CommonChecks"), typeof(Check)) - assertEquals("This check is javadoc-like commented.", check.description, "Referenced check cannot be resolved") - } -} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.java new file mode 100644 index 0000000000..2525de8865 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.core.test.util; + +import com.google.common.collect.Lists; +import java.util.ArrayList; +import java.util.List; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.xtext.EcoreUtil2; + +public class CheckTestUtil { + + /* + * Gets the first instance of given type in given context object. + */ + public T getFirstInstanceOf(final EObject context, final Class type) { + return getInstanceOf(context, type, null, null, 1); + } + + /* + * Gets any instance of given type containing a given structural feature with given value using a given context object. + */ + public T getInstanceOf(final EObject context, final Class type, final int instance) { + return getInstanceOf(context, type, null, null, instance); + } + + /* + * Gets the all instances of given type type having given value value on structural feature feature. + */ + public Iterable getAllInstancesOf(final EObject context, final Class type, final EStructuralFeature feature, final Object value) { + final ArrayList result = Lists.newArrayList(); + for (final T candidate : EcoreUtil2.getAllContentsOfType(context, type)) { + Object valueOfFeature = candidate.eGet(feature); + if (valueOfFeature != null && valueOfFeature.equals(value)) { + result.add(candidate); + } + } + return result; + } + + /* + * Gets the first instance of given type containing a given structural feature with given value using a given context object. + */ + public T getFirstInstanceOf(final EObject context, final Class type, final EStructuralFeature feature, final Object value) { + return getInstanceOf(context, type, feature, value, 1); + } + + /* + * Gets any instance of given type containing a given structural feature with given value using a given context object. + */ + public T getInstanceOf(final EObject context, final Class type, final EStructuralFeature feature, final Object value, final int instance) { + int skip = instance - 1; + for (final T candiadate : EcoreUtil2.getAllContentsOfType(context, type)) { + if ((feature == null && value == null) || candiadate.eGet(feature).equals(value)) { + if (skip == 0) { + return candiadate; + } else { + skip = skip - 1; + } + } + } + return null; + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.xtend deleted file mode 100644 index 9dc87019a4..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.xtend +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.core.test.util - -import com.google.common.collect.Lists -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.EStructuralFeature -import org.eclipse.xtext.EcoreUtil2 - -class CheckTestUtil { - - /* - * Gets the first instance of given type in given context object. - */ - def T getFirstInstanceOf(EObject context, Class type) { - return getInstanceOf(context, type, null, null, 1) - } - - /* - * Gets any instance of given type containing a given structural feature with given value using a given context object. - */ - def T getInstanceOf(EObject context, Class type, int instance) { - return getInstanceOf(context, type, null, null, instance) - } - - /* - * Gets the all instances of given type type having given value value on structural feature feature. - */ - def Iterable getAllInstancesOf(EObject context, Class type, EStructuralFeature feature, Object value) { - val result = Lists::newArrayList - for (candidate : EcoreUtil2::getAllContentsOfType(context, type)) { - var valueOfFeature = candidate.eGet(feature); - if (valueOfFeature !== null && valueOfFeature.equals(value)) { - result.add(candidate); - } - } - return result; - } - - /* - * Gets the first instance of given type containing a given structural feature with given value using a given context object. - */ - def T getFirstInstanceOf(EObject context, Class type, EStructuralFeature feature, Object value) { - return getInstanceOf(context, type, feature, value, 1); - } - - /* - * Gets any instance of given type containing a given structural feature with given value using a given context object. - */ - def T getInstanceOf(EObject context, Class type, EStructuralFeature feature, Object value, int instance) { - var skip = instance - 1; - for (candiadate : EcoreUtil2::getAllContentsOfType(context, type)) { - if ((feature === null && value === null) || candiadate.eGet(feature).equals(value)) { - if (skip == 0) { - return candiadate; - } else { - skip = skip-1 - } - } - } - return null; - } - -} diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckConfigurationIsAppliedTest.xtend b/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckConfigurationIsAppliedTest.java similarity index 52% rename from com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckConfigurationIsAppliedTest.xtend rename to com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckConfigurationIsAppliedTest.java index c27822ac24..1d4298025e 100644 --- a/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckConfigurationIsAppliedTest.xtend +++ b/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckConfigurationIsAppliedTest.java @@ -8,33 +8,36 @@ * Contributors: * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.check.test.runtime +package com.avaloq.tools.ddk.check.test.runtime; -import com.avaloq.tools.ddk.check.TestLanguageUiInjectorProvider -import com.avaloq.tools.ddk.check.core.test.AbstractCheckTestCase -import com.avaloq.tools.ddk.check.testLanguage.Model -import com.avaloq.tools.ddk.check.testLanguage.TestLanguagePackage -import com.avaloq.tools.ddk.check.ui.internal.TestLanguageActivator -import com.avaloq.tools.ddk.check.validation.ExecutionEnvironmentIssueCodes -import com.google.common.collect.Lists -import com.google.inject.Inject -import java.util.List -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.validation.ValidationTestHelper -import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil -import org.junit.jupiter.api.Test -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.^extension.ExtendWith +import java.util.List; -@InjectWith(typeof(TestLanguageUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class CheckConfigurationIsAppliedTest extends AbstractCheckTestCase { +import com.avaloq.tools.ddk.check.TestLanguageUiInjectorProvider; +import com.avaloq.tools.ddk.check.core.test.AbstractCheckTestCase; +import com.avaloq.tools.ddk.check.testLanguage.Model; +import com.avaloq.tools.ddk.check.testLanguage.TestLanguagePackage; +import com.avaloq.tools.ddk.check.ui.internal.TestLanguageActivator; +import com.avaloq.tools.ddk.check.validation.ExecutionEnvironmentIssueCodes; +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import com.google.inject.Injector; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@InjectWith(TestLanguageUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class CheckConfigurationIsAppliedTest extends AbstractCheckTestCase { @Inject - ValidationTestHelper helper + private ValidationTestHelper helper; - override getInjector() { - TestLanguageActivator::instance.getInjector(TestLanguageActivator::COM_AVALOQ_TOOLS_DDK_CHECK_TESTLANGUAGE) + @Override + public Injector getInjector() { + return TestLanguageActivator.getInstance().getInjector(TestLanguageActivator.COM_AVALOQ_TOOLS_DDK_CHECK_TESTLANGUAGE); } /* @@ -43,8 +46,8 @@ override getInjector() { * Eclipse has the Check runtime plugins installed, code will automatically be generated * for those resources. In order to avoid that the file extensions have been ommitted. */ - def List getRequiredSourceFileNames() { - Lists::newArrayList('.settings/com.avaloq.tools.ddk.checkcfg.core.prefs', 'Greetings') + public List getRequiredSourceFileNames() { + return Lists.newArrayList(".settings/com.avaloq.tools.ddk.checkcfg.core.prefs", "Greetings"); } /* @@ -52,13 +55,13 @@ def List getRequiredSourceFileNames() { * and applied: the severity is changed from ERROR to WARNING. */ @Test - def void testCheckConfigurationIsApplied() { + public void testCheckConfigurationIsApplied() throws Exception { // sources are copied into the project and then built by the Xtext builder - addSourcesToWorkspace(typeof(CheckConfigurationIsAppliedTest), requiredSourceFileNames) + addSourcesToWorkspace(CheckConfigurationIsAppliedTest.class, getRequiredSourceFileNames()); // wait for build to finish, otherwise included catalog may not be resolvable - IResourcesSetupUtil::waitForBuild - val model = getModel("Greetings") as Model - helper.assertWarning(model.greetings.get(0), TestLanguagePackage$Literals::GREETING, ExecutionEnvironmentIssueCodes::FRANZNAME) + IResourcesSetupUtil.waitForBuild(); + final Model model = (Model) getModel("Greetings"); + helper.assertWarning(model.getGreetings().get(0), TestLanguagePackage.Literals.GREETING, ExecutionEnvironmentIssueCodes.FRANZNAME); } } diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/label/IssueLabelTest.java b/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/label/IssueLabelTest.java new file mode 100644 index 0000000000..9fa09e7a78 --- /dev/null +++ b/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/label/IssueLabelTest.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.check.test.runtime.label; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.Map; + +import com.avaloq.tools.ddk.check.runtime.label.ICheckRuleLabelProvider; +import com.avaloq.tools.ddk.check.validation.LibraryChecksIssueCodes; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import org.junit.jupiter.api.Test; + +/** + * End-to-end test for getting Check labels. + */ +public class IssueLabelTest { + + /** + * End-to-end test for getting Check labels. + */ + @Test + public void testGetLabel() { + + // ARRANGE + final ICheckRuleLabelProvider checkRuleLabelProvider = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + } + }).getInstance(ICheckRuleLabelProvider.class); + + final Map expectedMap = Map.of( + // @Format-Off + LibraryChecksIssueCodes.CACHE_DOESNT_WORK, "Cache doesn't work", + LibraryChecksIssueCodes.CACHE_INJECTION_FAILED, "Cache injection failed", + LibraryChecksIssueCodes.CHECK_CATALOG_IS_ACTIVE, "Check catalog is active", + LibraryChecksIssueCodes.FORMAL_PARAMETERS, "Formal Parameters" + // @Format-On + ); + + for (final Map.Entry entry : expectedMap.entrySet()) { + // ACT + final String label = checkRuleLabelProvider.getLabel(entry.getKey()); + + // ASSERT + assertNotNull(label, "Label should be returned for key " + entry.getKey()); + assertEquals(entry.getValue(), label, "Correct label should be returned for key " + entry.getKey()); + } + } +} diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/label/IssueLabelTest.xtend b/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/label/IssueLabelTest.xtend deleted file mode 100644 index 5471340a03..0000000000 --- a/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/label/IssueLabelTest.xtend +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.check.test.runtime.label - -import com.avaloq.tools.ddk.check.runtime.label.ICheckRuleLabelProvider -import com.avaloq.tools.ddk.check.validation.LibraryChecksIssueCodes -import com.google.inject.AbstractModule -import com.google.inject.Guice -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertEquals; - -/** - * End-to-end test for getting Check labels. - */ -class IssueLabelTest { - - /** - * End-to-end test for getting Check labels. - */ - @Test - def testGetLabel() { - - // ARRANGE - val checkRuleLabelProvider = Guice.createInjector(new AbstractModule() { - protected override configure() {} - }).getInstance(ICheckRuleLabelProvider); - - val expectedMap = #{ - // @Format-Off - LibraryChecksIssueCodes.CACHE_DOESNT_WORK -> "Cache doesn't work", - LibraryChecksIssueCodes.CACHE_INJECTION_FAILED -> "Cache injection failed", - LibraryChecksIssueCodes.CHECK_CATALOG_IS_ACTIVE -> "Check catalog is active", - LibraryChecksIssueCodes.FORMAL_PARAMETERS -> "Formal Parameters" - // @Format-On - } - - for (entry : expectedMap.entrySet) { - // ACT - val label = checkRuleLabelProvider.getLabel(entry.key); - - // ASSERT - assertNotNull(label, "Label should be returned for key " + entry.key); - assertEquals( entry.value, label, "Correct label should be returned for key " + entry.key); - } - } -} diff --git a/com.avaloq.tools.ddk.check.test.runtime/src/com/avaloq/tools/ddk/check/generator/TestLanguageGenerator.xtend b/com.avaloq.tools.ddk.check.test.runtime/src/com/avaloq/tools/ddk/check/generator/TestLanguageGenerator.java similarity index 57% rename from com.avaloq.tools.ddk.check.test.runtime/src/com/avaloq/tools/ddk/check/generator/TestLanguageGenerator.xtend rename to com.avaloq.tools.ddk.check.test.runtime/src/com/avaloq/tools/ddk/check/generator/TestLanguageGenerator.java index 99d7b4e6a6..c022af5d6f 100644 --- a/com.avaloq.tools.ddk.check.test.runtime/src/com/avaloq/tools/ddk/check/generator/TestLanguageGenerator.xtend +++ b/com.avaloq.tools.ddk.check.test.runtime/src/com/avaloq/tools/ddk/check/generator/TestLanguageGenerator.java @@ -8,15 +8,16 @@ * Contributors: * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.check.generator +package com.avaloq.tools.ddk.check.generator; -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.IGenerator -import org.eclipse.xtext.generator.IFileSystemAccess +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.generator.IFileSystemAccess; +import org.eclipse.xtext.generator.IGenerator; -class TestLanguageGenerator implements IGenerator { +public class TestLanguageGenerator implements IGenerator { - override void doGenerate(Resource resource, IFileSystemAccess fsa) { - //TODO implment me - } + @Override + public void doGenerate(final Resource resource, final IFileSystemAccess fsa) { + // TODO implement me + } } diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java new file mode 100644 index 0000000000..e008b56e83 --- /dev/null +++ b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.ui.wizard; + +import org.eclipse.xtext.generator.IFileSystemAccess; + +public class CheckNewProject { + + public void doGenerate(final CheckProjectInfo info, final IFileSystemAccess fsa) { + fsa.generateFile(fileName(info), fileContent(info)); + } + + public String fileName(final CheckProjectInfo info) { + return info.getPath() + info.getCatalogName() + ".check"; + } + + public CharSequence fileContent(final CheckProjectInfo info) { + final StringBuilder builder = new StringBuilder(); + builder.append("package ").append(info.getPackageName()).append("\n"); + builder.append("\n"); + builder.append(fileImports(info)); + builder.append("\n"); + builder.append("\n"); + builder.append("/**\n"); + builder.append(" * Check catalog for ").append(info.getGrammar().getName()).append("\n"); + builder.append(" */\n"); + builder.append("catalog ").append(info.getCatalogName()).append("\n"); + builder.append("for grammar ").append(info.getGrammar().getName()).append(" {\n"); + builder.append("\n"); + builder.append(" // Add categories and checks\n"); + builder.append("\n"); + builder.append("}\n"); + return builder; + } + + public CharSequence fileImports(final CheckProjectInfo info) { + // package where top-level grammar rule interfaces are defined + if (info.getDefaultPackageImport() != null) { + return "import " + info.getDefaultPackageImport() + ".* "; + } else { + return ""; + } + } +} diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.xtend b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.xtend deleted file mode 100644 index 4b7fa3180b..0000000000 --- a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.xtend +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.ui.wizard - -import org.eclipse.xtext.generator.IFileSystemAccess - -class CheckNewProject { - - def doGenerate(CheckProjectInfo info, IFileSystemAccess fsa){ - fsa.generateFile(info.fileName, info.fileContent) - } - - def String fileName(CheckProjectInfo info){ - '''«info.path + info.catalogName + ".check"»''' - } - - def fileContent(CheckProjectInfo info){ - ''' - package «info.packageName» - - «info.fileImports» - - /** - * Check catalog for «info.grammar.name» - */ - catalog «info.catalogName» - for grammar «info.grammar.name» { - - // Add categories and checks - - } - ''' - } - - def fileImports(CheckProjectInfo info) { - // package where top-level grammar rule interfaces are defined - if(info.defaultPackageImport !== null) - '''import «info.defaultPackageImport».* ''' - else "" - } - -} diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java new file mode 100644 index 0000000000..01812e8f79 --- /dev/null +++ b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.ui.wizard; + +import org.eclipse.xtext.generator.IFileSystemAccess; + +public class CheckQuickfixProvider { + + public void doGenerate(final CheckProjectInfo info, final IFileSystemAccess fsa) { + fsa.generateFile(fileName(info), fileContent(info)); + } + + public String fileName(final CheckProjectInfo info) { + return info.getPath() + info.getCatalogName() + "QuickfixProvider.java"; + } + + public CharSequence fileContent(final CheckProjectInfo info) { + final StringBuilder builder = new StringBuilder(); + builder.append("package ").append(info.getPackageName()).append(";\n"); + builder.append("\n"); + builder.append("import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreQuickfixProvider;\n"); + builder.append("\n"); + builder.append("/**\n"); + builder.append(" * Default quickfix provider for ").append(info.getCatalogName()).append(".\n"); + builder.append(" *

\n"); + builder.append(" * Note that this class name must start with the catalog name and have QuickfixProvider\n"); + builder.append(" * as suffix. It must be located in the same Java package as the catalog file.\n"); + builder.append(" *

\n"); + builder.append(" */\n"); + builder.append("public class ").append(info.getCatalogName()).append("QuickfixProvider implements ICoreQuickfixProvider {\n"); + builder.append("\n"); + builder.append("// @CoreFix(value = MyIssueCodes.NAME_ENTITY_0)\n"); + builder.append("// public void fixEntityNameFirstUpper(final Issue issue,\n"); + builder.append("// ICoreIssueResolutionAcceptor acceptor) {\n"); + builder.append("// acceptor.accept(issue, \"Correct entity name\",\n"); + builder.append("// \"Correct name by setting first letter to upper case.\",\n"); + builder.append("// null, new ICoreSemanticModification() {\n"); + builder.append("// public void apply(EObject element, ICoreModificationContext context) {\n"); + builder.append("// if (element instanceof Entity) {\n"); + builder.append("// final Entity entity = (Entity) element;\n"); + builder.append("// String newName = String.valueOf(entity.getName().charAt(0)).toUpperCase();\n"); + builder.append("// if (entity.getName().length() > 1) {\n"); + builder.append("// newName += entity.getName().substring(1, entity.getName().length());\n"); + builder.append("// }\n"); + builder.append("// entity.setName(newName);\n"); + builder.append("// }\n"); + builder.append("// }\n"); + builder.append("// });\n"); + builder.append("// }\n"); + builder.append("\n"); + builder.append("}\n"); + return builder; + } +} diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.xtend b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.xtend deleted file mode 100644 index 665917b4a1..0000000000 --- a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.xtend +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.ui.wizard - -import org.eclipse.xtext.generator.IFileSystemAccess - -class CheckQuickfixProvider { - - def doGenerate(CheckProjectInfo info, IFileSystemAccess fsa){ - fsa.generateFile(info.fileName, info.fileContent) - } - - def String fileName(CheckProjectInfo info){ - '''«info.path + info.catalogName + "QuickfixProvider.java"»''' - } - - def fileContent(CheckProjectInfo info){ - ''' - package «info.packageName»; - - import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreQuickfixProvider; - - /** - * Default quickfix provider for «info.catalogName». - *

- * Note that this class name must start with the catalog name and have QuickfixProvider - * as suffix. It must be located in the same Java package as the catalog file. - *

- */ - public class «info.catalogName»QuickfixProvider implements ICoreQuickfixProvider { - - // @CoreFix(value = MyIssueCodes.NAME_ENTITY_0) - // public void fixEntityNameFirstUpper(final Issue issue, - // ICoreIssueResolutionAcceptor acceptor) { - // acceptor.accept(issue, "Correct entity name", - // "Correct name by setting first letter to upper case.", - // null, new ICoreSemanticModification() { - // public void apply(EObject element, ICoreModificationContext context) { - // if (element instanceof Entity) { - // final Entity entity = (Entity) element; - // String newName = String.valueOf(entity.getName().charAt(0)).toUpperCase(); - // if (entity.getName().length() > 1) { - // newName += entity.getName().substring(1, entity.getName().length()); - // } - // entity.setName(newName); - // } - // } - // }); - // } - - } - ''' - } - -} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgModelUtil.xtend b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgModelUtil.java similarity index 55% rename from com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgModelUtil.xtend rename to com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgModelUtil.java index c68e0791af..0ae7d73389 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgModelUtil.xtend +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgModelUtil.java @@ -8,35 +8,31 @@ * Contributors: * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.checkcfg.util +package com.avaloq.tools.ddk.checkcfg.util; /* * Provides utility operations for Check Configuration model stubs. Only partial models * are returned as strings. */ -class CheckCfgModelUtil { +public class CheckCfgModelUtil { - def String basicModel(String name) {''' - check configuration «name» {'''.toString + public String basicModel(final String name) { + return "check configuration " + name + " {"; } - def String basicModel() { - basicModel("testing") + public String basicModel() { + return basicModel("testing"); } - def String basicModelWithCatalog() { - basicModel + ''' - catalog Sample {'''.toString + public String basicModelWithCatalog() { + return basicModel() + "catalog Sample {"; } - def String basicModelWithTest() { - basicModelWithCatalog + ''' - Test'''.toString + public String basicModelWithTest() { + return basicModelWithCatalog() + "Test"; } - def String basicModelWithDisabledTest() { - basicModelWithCatalog + ''' - ignore Test'''.toString + public String basicModelWithDisabledTest() { + return basicModelWithCatalog() + "ignore Test"; } - } diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgTestUtil.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgTestUtil.java new file mode 100644 index 0000000000..57e1203786 --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgTestUtil.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.checkcfg.util; + +import com.avaloq.tools.ddk.checkcfg.ui.internal.CheckcfgActivator; +import com.avaloq.tools.ddk.xtext.test.ITestProjectManager; +import com.avaloq.tools.ddk.xtext.test.PluginTestProjectManager; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextTestUtil; +import com.google.inject.Injector; + +public class CheckCfgTestUtil extends AbstractXtextTestUtil { + + private static final AbstractXtextTestUtil UTIL_INSTANCE = new CheckCfgTestUtil(); + + public static AbstractXtextTestUtil getInstance() { + return UTIL_INSTANCE; + } + + @Override + protected Injector getInjector() { + return CheckcfgActivator.getInstance().getInjector(CheckcfgActivator.COM_AVALOQ_TOOLS_DDK_CHECKCFG_CHECKCFG); + } + + @Override + protected ITestProjectManager createTestProjectManager() { + return new PluginTestProjectManager(getInjector()); + } +} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgTestUtil.xtend b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgTestUtil.xtend deleted file mode 100644 index 9e82cc1f0d..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/util/CheckCfgTestUtil.xtend +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.checkcfg.util - -import com.avaloq.tools.ddk.xtext.test.PluginTestProjectManager -import com.avaloq.tools.ddk.xtext.test.ITestProjectManager -import com.avaloq.tools.ddk.checkcfg.ui.internal.CheckcfgActivator -import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextTestUtil - -class CheckCfgTestUtil extends AbstractXtextTestUtil{ - - - static AbstractXtextTestUtil UTIL_INSTANCE = new CheckCfgTestUtil() - def static AbstractXtextTestUtil getInstance(){UTIL_INSTANCE} - - override protected getInjector() { - CheckcfgActivator.getInstance().getInjector(CheckcfgActivator.COM_AVALOQ_TOOLS_DDK_CHECKCFG_CHECKCFG) - } - - override protected ITestProjectManager createTestProjectManager() { - new PluginTestProjectManager(getInjector()); - } -} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.java new file mode 100644 index 0000000000..6997192f55 --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.checkcfg.validation; + +import static com.avaloq.tools.ddk.checkcfg.CheckCfgConstants.PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE; +import static com.avaloq.tools.ddk.checkcfg.CheckCfgConstants.PROPERTY_EXTENSION_POINT; + +import java.util.List; + +import com.avaloq.tools.ddk.checkcfg.util.CheckCfgTestUtil; +import com.avaloq.tools.ddk.test.checkcfg.TestPropertySpecificationWithExpectedValues; +import com.avaloq.tools.ddk.test.checkcfg.TestPropertySpecificationWithOutExpectedValues; +import com.avaloq.tools.ddk.test.core.mock.ExtensionRegistryMock; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractValidationTest; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextTestUtil; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Test; + +public class CheckCfgConfiguredParameterValidationsTest extends AbstractValidationTest { + + @Override + protected AbstractXtextTestUtil getXtextTestUtil() { + return CheckCfgTestUtil.getInstance(); + } + + @Override + protected List getRequiredSourceFileNames() { + return Lists.newArrayListWithCapacity(0); + } + + @Override + protected void beforeAllTests() { + ExtensionRegistryMock.mockExecutableExtension(ExtensionRegistryMock.mockConfigurationElement(PROPERTY_EXTENSION_POINT), PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE, TestPropertySpecificationWithExpectedValues.INSTANCE); + ExtensionRegistryMock.mockExecutableExtension(ExtensionRegistryMock.mockConfigurationElement(PROPERTY_EXTENSION_POINT), PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE, TestPropertySpecificationWithOutExpectedValues.INSTANCE); + super.beforeAllTests(); + } + + @Override + protected void afterAllTests() { + super.afterAllTests(); + ExtensionRegistryMock.unMock(PROPERTY_EXTENSION_POINT); + } + + @Test + public void testConfiguredParameterValues() { + final TestPropertySpecificationWithExpectedValues allowedOnly = TestPropertySpecificationWithExpectedValues.INSTANCE; + final TestPropertySpecificationWithOutExpectedValues acceptsAny = TestPropertySpecificationWithOutExpectedValues.INSTANCE; + final StringBuilder builder = new StringBuilder(); + builder.append("check configuration Test\n"); + builder.append(" ").append(allowedOnly.getName()).append(" = ").append(error(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)).append("\"notAllowed\"\n"); + builder.append(" for com.avaloq.tools.ddk.^check.TestLanguage {\n"); + builder.append(" ").append(allowedOnly.getName()).append(" = ").append(noDiagnostic(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)).append("\"").append(allowedOnly.getExpectedValues()[0]).append("\"\n"); + builder.append(" ").append(acceptsAny.getName()).append(" = ").append(noDiagnostic(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)).append("\"whatever\"\n"); + builder.append(" }\n"); + validateKernelSourceStrictly("ConfiguredParameterValues.checkcfg", builder); + } + +} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.xtend b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.xtend deleted file mode 100644 index 32b1f4b56c..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.xtend +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.checkcfg.validation - -import com.avaloq.tools.ddk.checkcfg.util.CheckCfgTestUtil -import com.avaloq.tools.ddk.test.checkcfg.TestPropertySpecificationWithExpectedValues -import com.avaloq.tools.ddk.test.checkcfg.TestPropertySpecificationWithOutExpectedValues -import com.google.common.collect.Lists - -import static com.avaloq.tools.ddk.checkcfg.CheckCfgConstants.PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE -import static com.avaloq.tools.ddk.checkcfg.CheckCfgConstants.PROPERTY_EXTENSION_POINT - -import static extension com.avaloq.tools.ddk.test.core.mock.ExtensionRegistryMock.mockConfigurationElement -import static extension com.avaloq.tools.ddk.test.core.mock.ExtensionRegistryMock.mockExecutableExtension -import static extension com.avaloq.tools.ddk.test.core.mock.ExtensionRegistryMock.unMock -import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractValidationTest -import org.junit.jupiter.api.Test - -class CheckCfgConfiguredParameterValidationsTest extends AbstractValidationTest { - - override protected getXtextTestUtil() { - return CheckCfgTestUtil.instance - } - - override protected getRequiredSourceFileNames() { - Lists.newArrayListWithCapacity(0) - } - - override protected beforeAllTests() { - PROPERTY_EXTENSION_POINT.mockConfigurationElement.mockExecutableExtension(PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE, TestPropertySpecificationWithExpectedValues.INSTANCE) - PROPERTY_EXTENSION_POINT.mockConfigurationElement.mockExecutableExtension(PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE, TestPropertySpecificationWithOutExpectedValues.INSTANCE) - super.beforeAllTests() - } - - override protected afterAllTests() { - super.afterAllTests() - PROPERTY_EXTENSION_POINT.unMock - } - - @Test - def testConfiguredParameterValues() { - val allowedOnly = TestPropertySpecificationWithExpectedValues.INSTANCE - val acceptsAny = TestPropertySpecificationWithOutExpectedValues.INSTANCE - validateKernelSourceStrictly("ConfiguredParameterValues.checkcfg", ''' - check configuration Test - «allowedOnly.name» = «error(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)»"notAllowed" - for com.avaloq.tools.ddk.^check.TestLanguage { - «allowedOnly.name» = «noDiagnostic(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)»"«allowedOnly.expectedValues.head»" - «acceptsAny.name» = «noDiagnostic(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)»"whatever" - } - ''') - } - -} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java new file mode 100644 index 0000000000..233f50a70f --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.checkcfg.validation; + +import com.avaloq.tools.ddk.checkcfg.CheckCfgUiInjectorProvider; +import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckConfiguration; +import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckcfgPackage; +import com.google.inject.Inject; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@InjectWith(CheckCfgUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class CheckCfgTest { + + @Inject + private ValidationTestHelper helper; + + @Inject + private ParseHelper parser; + + @Test + public void testValidLanguageOk() throws Exception { + final CheckConfiguration model = parser.parse( + "check configuration Test\n" + + "\n" + + "for com.avaloq.tools.ddk.^check.TestLanguage {\n" + + "\n" + + "}\n" + + "\n"); + helper.assertNoIssues(model); + } + + @Test + public void testUnknownLanguageNotOk() throws Exception { + final CheckConfiguration model = parser.parse( + "check configuration Test\n" + + "\n" + + "for com.avaloq.tools.ddk.^check.Unknown {\n" + + "\n" + + "}\n" + + "\n"); + helper.assertError(model, CheckcfgPackage.Literals.CONFIGURED_LANGUAGE_VALIDATOR, IssueCodes.UNKNOWN_LANGUAGE); + } + +} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.xtend b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.xtend deleted file mode 100644 index 58b57e1764..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.xtend +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.checkcfg.validation - -import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckConfiguration -import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckcfgPackage -import com.google.inject.Inject -import org.eclipse.xtext.testing.util.ParseHelper -import org.eclipse.xtext.testing.validation.ValidationTestHelper -import org.eclipse.xtext.testing.InjectWith -import com.avaloq.tools.ddk.checkcfg.CheckCfgUiInjectorProvider -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension - -@InjectWith(typeof(CheckCfgUiInjectorProvider)) -@ExtendWith(InjectionExtension) -class CheckCfgTest { - - - @Inject - ValidationTestHelper helper; - - @Inject - ParseHelper parser; - - @Test - def testValidLanguageOk() { - - val model = parser.parse(''' - check configuration Test - - for com.avaloq.tools.ddk.^check.TestLanguage { - - } - - '''); - helper.assertNoIssues(model); - } - - @Test - def testUnknownLanguageNotOk() { - - val model = parser.parse(''' - check configuration Test - - for com.avaloq.tools.ddk.^check.Unknown { - - } - - '''); - helper.assertError(model, CheckcfgPackage.Literals::CONFIGURED_LANGUAGE_VALIDATOR, IssueCodes.UNKNOWN_LANGUAGE); - } - -} diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.java new file mode 100644 index 0000000000..040e857ede --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.checkcfg.generator; + +import com.avaloq.tools.ddk.check.runtime.configuration.ICheckConfigurationStoreService; +import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckConfiguration; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; +import java.util.Properties; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.generator.AbstractFileSystemAccess; +import org.eclipse.xtext.generator.IFileSystemAccess; +import org.eclipse.xtext.generator.IGenerator; +import org.eclipse.xtext.xbase.lib.IteratorExtensions; + +public class CheckCfgGenerator implements IGenerator { + + @Inject + private CheckConfigurationPropertiesGenerator propertiesGenerator; + + public String outputPath() { + return ".settings"; + } + + public String fileName(final CheckConfiguration configuration) { + return ICheckConfigurationStoreService.DEFAULT_CHECK_CONFIGURATION_NODE + ".prefs"; + } + + @Override + public void doGenerate(final Resource resource, final IFileSystemAccess fsa) { + if (fsa instanceof AbstractFileSystemAccess abstractFsa) { + abstractFsa.setOutputPath(outputPath()); + } + for (final CheckConfiguration configuration : Iterables.filter(IteratorExtensions.toIterable(resource.getAllContents()), CheckConfiguration.class)) { + fsa.generateFile(fileName(configuration), compile(configuration)); + } + } + + public CharSequence compile(final CheckConfiguration config) { + final Properties properties = propertiesGenerator.convertToProperties(config); + final StringBuilder builder = new StringBuilder(); + for (final Object k : properties.keySet()) { + builder.append(k).append("=").append(properties.get(k)).append("\n"); + } + return builder; + } +} diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.xtend b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.xtend deleted file mode 100644 index 1b5537e5a8..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.xtend +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.checkcfg.generator - -import com.avaloq.tools.ddk.check.runtime.configuration.ICheckConfigurationStoreService -import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckConfiguration -import com.google.inject.Inject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.AbstractFileSystemAccess -import org.eclipse.xtext.generator.IFileSystemAccess -import org.eclipse.xtext.generator.IGenerator - -import static org.eclipse.xtext.xbase.lib.IteratorExtensions.* - -class CheckCfgGenerator implements IGenerator { - - @Inject - CheckConfigurationPropertiesGenerator propertiesGenerator; - - def outputPath() { - '.settings' - } - - def fileName(CheckConfiguration configuration) { - ICheckConfigurationStoreService.DEFAULT_CHECK_CONFIGURATION_NODE + '.prefs' - } - - override void doGenerate(Resource resource, IFileSystemAccess fsa) { - if (fsa instanceof AbstractFileSystemAccess) { - fsa.setOutputPath(outputPath) - } - for (configuration:toIterable(resource.allContents).filter(typeof(CheckConfiguration))) { - fsa.generateFile(configuration.fileName, configuration.compile) - } - } - - def compile(CheckConfiguration config) { - val properties = propertiesGenerator.convertToProperties(config); - ''' - «FOR k:properties.keySet» - «k»=«properties.get(k)» - «ENDFOR» - ''' - } -} diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.xtend b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.java similarity index 69% rename from com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.xtend rename to com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.java index 65c97bf1a3..2ac14f51c1 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.xtend +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.java @@ -8,13 +8,13 @@ * Contributors: * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.checkcfg.jvmmodel +package com.avaloq.tools.ddk.checkcfg.jvmmodel; -import org.eclipse.emf.ecore.EObject -import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer -import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor -import com.google.inject.Inject -import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder +import com.google.inject.Inject; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer; +import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor; +import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder; /** *

Infers a JVM model from the source model.

@@ -22,13 +22,15 @@ *

The JVM model should contain all elements that would appear in the Java code * which is generated from the source model. Other models link against the JVM model rather than the source model.

*/ -class CheckCfgJvmModelInferrer extends AbstractModelInferrer { +public class CheckCfgJvmModelInferrer extends AbstractModelInferrer { - @Inject extension JvmTypesBuilder + @Inject + private JvmTypesBuilder jvmTypesBuilder; - override void _infer(EObject element, IJvmDeclaredTypeAcceptor acceptor, boolean preIndexingPhase) { + @Override + public void _infer(final EObject element, final IJvmDeclaredTypeAcceptor acceptor, final boolean preIndexingPhase) { // Infer dummy class as type resolver expects at least one root Java type - acceptor.accept(element.toClass("xxxyyyzzz.dummy.class.name")[]) + acceptor.accept(jvmTypesBuilder.toClass(element, "xxxyyyzzz.dummy.class.name", (it) -> {})); } // Here you explain how your model is mapped to Java elements, by writing the actual translation code. diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.java new file mode 100644 index 0000000000..5e2bd8b823 --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * Contributors: + * Avaloq Group AG - initial API and implementation + */ +package com.avaloq.tools.ddk.checkcfg.validation; + +import com.avaloq.tools.ddk.check.check.FormalParameter; +import com.avaloq.tools.ddk.check.validation.FormalParameterCheckBase; +import com.avaloq.tools.ddk.checkcfg.CheckCfgUtil; +import com.avaloq.tools.ddk.checkcfg.ICheckCfgPropertySpecification; +import com.avaloq.tools.ddk.checkcfg.checkcfg.ConfiguredParameter; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import org.eclipse.xtext.validation.Check; +import org.eclipse.xtext.xbase.XExpression; +import org.eclipse.xtext.xbase.XListLiteral; +import org.eclipse.xtext.xbase.XStringLiteral; + +/** + * Checkcfg formal parameter checks. + */ +public class ConfiguredParameterChecks extends FormalParameterCheckBase { + + private static Map> allowedPropertyValues = Maps.newHashMap(); + + /** + * Verifies that numeric literals in the default values of formal parameters are all integral values. + * @param parameterto check. + */ + @Check + public void checkFormalParameterNumbersAreIntegers(final ConfiguredParameter parameter) { + checkRightHandSideHasOnlyIntegralNumbers(parameter.getNewValue(), IssueCodes.FORMAL_PARAMETER_MUST_BE_INTEGER); + } + + /** + * Verifies that formal parameters defined via extension point only set values expected by the extension. + * @param parameter to check. + */ + @Check + public void checkFormalParameterValuesAreValid(final ConfiguredParameter parameter) { + FormalParameter formalParam = parameter.getParameter(); + String name = formalParam != null ? formalParam.getName() : null; + final String propertyName = name != null ? name.toLowerCase(Locale.ENGLISH) : null; + if (propertyName != null) { + Set permitted = allowedPropertyValues.get(propertyName); + if (permitted == null) { + ICheckCfgPropertySpecification spec = CheckCfgUtil.getPropertySpecification(propertyName); + String[] expected = spec != null ? spec.getExpectedValues() : null; + if (expected == null) { + expected = new String[0]; + } + permitted = Sets.newHashSet(expected); + allowedPropertyValues.put(propertyName, permitted); + } + final XExpression value = parameter.getNewValue(); + if (!permitted.isEmpty() && value != null) { + List expressions; + if (value instanceof XListLiteral xListLiteral) { + expressions = xListLiteral.getElements(); + } else { + expressions = Collections.singletonList(value); + } + for (XExpression expression : expressions) { + if (!(expression instanceof XStringLiteral) || !permitted.contains(((XStringLiteral) expression).getValue().toLowerCase(Locale.ENGLISH))) { + error("Not a meaningful value for " + propertyName, expression, null, IssueCodes.PARAMETER_VALUE_NOT_ALLOWED); + } + } + } + } + } +} diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.xtend b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.xtend deleted file mode 100644 index 073c6856e0..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.xtend +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * Contributors: - * Avaloq Group AG - initial API and implementation - */ -package com.avaloq.tools.ddk.checkcfg.validation - -import com.avaloq.tools.ddk.check.validation.FormalParameterCheckBase -import com.avaloq.tools.ddk.checkcfg.CheckCfgUtil -import com.avaloq.tools.ddk.checkcfg.checkcfg.ConfiguredParameter -import com.google.common.collect.Maps -import com.google.common.collect.Sets -import java.util.Collections -import java.util.Locale -import java.util.Map -import java.util.Set -import org.eclipse.xtext.validation.Check -import org.eclipse.xtext.xbase.XListLiteral -import org.eclipse.xtext.xbase.XStringLiteral - -/** - * Checkcfg formal parameter checks. - */ -class ConfiguredParameterChecks extends FormalParameterCheckBase { - static Map> allowedPropertyValues = Maps.newHashMap() - - /** - * Verifies that numeric literals in the default values of formal parameters are all integral values. - * @param parameterto check. - */ - @Check - def checkFormalParameterNumbersAreIntegers(ConfiguredParameter parameter) { - checkRightHandSideHasOnlyIntegralNumbers(parameter.getNewValue(), IssueCodes.FORMAL_PARAMETER_MUST_BE_INTEGER) - } - - /** - * Verifies that formal parameters defined via extension point only set values expected by the extension. - * @param parameter to check. - */ - @Check - def checkFormalParameterValuesAreValid(ConfiguredParameter parameter) { - val propertyName = parameter.parameter?.name?.toLowerCase(Locale.ENGLISH) - if (propertyName !== null) { - var permitted = allowedPropertyValues.get(propertyName) - if (permitted === null) { - val expected = CheckCfgUtil.getPropertySpecification(propertyName)?.expectedValues ?: newArrayOfSize(0) - permitted = Sets.newHashSet(expected) - allowedPropertyValues.put(propertyName, permitted) - } - val value = parameter.newValue - if (!permitted.isNullOrEmpty && value !== null) { - val expressions = if (value instanceof XListLiteral) value.elements else Collections.singletonList(value) - for (expression : expressions) { - if (!(expression instanceof XStringLiteral) || !permitted.contains((expression as XStringLiteral).value.toLowerCase(Locale.ENGLISH))) { - error('''Not a meaningful value for «propertyName»''', expression, null, IssueCodes.PARAMETER_VALUE_NOT_ALLOWED) - } - } - } - } - } - -} diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckConfigurationIsAppliedTest.xtend b/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckConfigurationIsAppliedTest.java similarity index 51% rename from com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckConfigurationIsAppliedTest.xtend rename to com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckConfigurationIsAppliedTest.java index 60376ba251..41b238cead 100644 --- a/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckConfigurationIsAppliedTest.xtend +++ b/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckConfigurationIsAppliedTest.java @@ -8,33 +8,35 @@ * Contributors: * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.sample.helloworld.check +package com.avaloq.tools.ddk.sample.helloworld.check; -import com.avaloq.tools.ddk.check.core.test.AbstractCheckTestCase -import com.google.common.collect.Lists -import com.google.inject.Inject -import java.util.List -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.validation.ValidationTestHelper -import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil -import com.avaloq.tools.ddk.sample.helloworld.helloWorld.Model -import com.avaloq.tools.ddk.sample.helloworld.ui.internal.HelloworldActivator -import com.avaloq.tools.ddk.sample.helloworld.helloWorld.HelloWorldPackage -import com.avaloq.tools.ddk.sample.helloworld.validation.ExecutionEnvironmentIssueCodes -import com.avaloq.tools.ddk.sample.helloworld.ui.HelloWorldUiInjectorProvider -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test +import com.avaloq.tools.ddk.check.core.test.AbstractCheckTestCase; +import com.avaloq.tools.ddk.sample.helloworld.helloWorld.HelloWorldPackage; +import com.avaloq.tools.ddk.sample.helloworld.helloWorld.Model; +import com.avaloq.tools.ddk.sample.helloworld.ui.HelloWorldUiInjectorProvider; +import com.avaloq.tools.ddk.sample.helloworld.ui.internal.HelloworldActivator; +import com.avaloq.tools.ddk.sample.helloworld.validation.ExecutionEnvironmentIssueCodes; +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import com.google.inject.Injector; +import java.util.List; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; -@InjectWith(typeof(HelloWorldUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class CheckConfigurationIsAppliedTest extends AbstractCheckTestCase { +@InjectWith(HelloWorldUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class CheckConfigurationIsAppliedTest extends AbstractCheckTestCase { @Inject - ValidationTestHelper helper + private ValidationTestHelper helper; - override getInjector() { - HelloworldActivator::instance.getInjector(HelloworldActivator::COM_AVALOQ_TOOLS_DDK_SAMPLE_HELLOWORLD_HELLOWORLD) + @Override + public Injector getInjector() { + return HelloworldActivator.getInstance().getInjector(HelloworldActivator.COM_AVALOQ_TOOLS_DDK_SAMPLE_HELLOWORLD_HELLOWORLD); } /* @@ -43,8 +45,8 @@ override getInjector() { * Eclipse has the Check runtime plugins installed, code will automatically be generated * for those resources. In order to avoid that the file extensions have been ommitted. */ - def List getRequiredSourceFileNames() { - Lists::newArrayList('.settings/com.avaloq.tools.ddk.checkcfg.core.prefs', 'Greetings') + public List getRequiredSourceFileNames() { + return Lists.newArrayList(".settings/com.avaloq.tools.ddk.checkcfg.core.prefs", "Greetings"); } /* @@ -52,13 +54,12 @@ def List getRequiredSourceFileNames() { * and applied: the severity is changed from ERROR to WARNING. */ @Test - def void testCheckConfigurationIsApplied() { + public void testCheckConfigurationIsApplied() throws Exception { // sources are copied into the project and then built by the Xtext builder - addSourcesToWorkspace(typeof(CheckConfigurationIsAppliedTest), requiredSourceFileNames) + addSourcesToWorkspace(CheckConfigurationIsAppliedTest.class, getRequiredSourceFileNames()); // wait for build to finish, otherwise included catalog may not be resolvable - IResourcesSetupUtil::waitForBuild - val model = getModel("Greetings") as Model - helper.assertWarning(model.greetings.get(0), HelloWorldPackage$Literals::GREETING, ExecutionEnvironmentIssueCodes::FRANZNAME) + IResourcesSetupUtil.waitForBuild(); + final Model model = (Model) getModel("Greetings"); + helper.assertWarning(model.getGreetings().get(0), HelloWorldPackage.Literals.GREETING, ExecutionEnvironmentIssueCodes.FRANZNAME); } - } diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/label/IssueLabelTest.java b/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/label/IssueLabelTest.java new file mode 100644 index 0000000000..601ae7ef7c --- /dev/null +++ b/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/label/IssueLabelTest.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.sample.helloworld.label; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.Map; + +import com.avaloq.tools.ddk.check.runtime.label.ICheckRuleLabelProvider; +import com.avaloq.tools.ddk.sample.helloworld.validation.LibraryChecksIssueCodes; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import org.junit.jupiter.api.Test; + +/** + * End-to-end test for getting Check labels. + */ +public class IssueLabelTest { + + /** + * End-to-end test for getting Check labels. + */ + @Test + public void testGetLabel() { + + // ARRANGE + final ICheckRuleLabelProvider checkRuleLabelProvider = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + } + }).getInstance(ICheckRuleLabelProvider.class); + + final Map expectedMap = Map.of( + // @Format-Off + LibraryChecksIssueCodes.CACHE_DOESNT_WORK, "Cache doesn't work", + LibraryChecksIssueCodes.CACHE_INJECTION_FAILED, "Cache injection failed", + LibraryChecksIssueCodes.CHECK_CATALOG_IS_ACTIVE, "Check catalog is active", + LibraryChecksIssueCodes.FORMAL_PARAMETERS, "Formal Parameters" + // @Format-On + ); + + for (final Map.Entry entry : expectedMap.entrySet()) { + // ACT + final String label = checkRuleLabelProvider.getLabel(entry.getKey()); + + // ASSERT + assertNotNull(label, "Label should be returned for key " + entry.getKey()); + assertEquals(entry.getValue(), label, "Correct label should be returned for key " + entry.getKey()); + } + } +} diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/label/IssueLabelTest.xtend b/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/label/IssueLabelTest.xtend deleted file mode 100644 index 3cf4767ff0..0000000000 --- a/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/label/IssueLabelTest.xtend +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.sample.helloworld.label - -import com.google.inject.AbstractModule -import com.google.inject.Guice - -import com.avaloq.tools.ddk.sample.helloworld.validation.LibraryChecksIssueCodes -import com.avaloq.tools.ddk.check.runtime.label.ICheckRuleLabelProvider -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.assertNotNull -import static org.junit.jupiter.api.Assertions.assertEquals - -/** - * End-to-end test for getting Check labels. - */ -class IssueLabelTest { - - /** - * End-to-end test for getting Check labels. - */ - @Test - def testGetLabel() { - - // ARRANGE - val checkRuleLabelProvider = Guice.createInjector(new AbstractModule() { - protected override configure() {} - }).getInstance(ICheckRuleLabelProvider); - - val expectedMap = #{ - // @Format-Off - LibraryChecksIssueCodes.CACHE_DOESNT_WORK -> "Cache doesn't work", - LibraryChecksIssueCodes.CACHE_INJECTION_FAILED -> "Cache injection failed", - LibraryChecksIssueCodes.CHECK_CATALOG_IS_ACTIVE -> "Check catalog is active", - LibraryChecksIssueCodes.FORMAL_PARAMETERS -> "Formal Parameters" - // @Format-On - } - - for (entry : expectedMap.entrySet) { - // ACT - val label = checkRuleLabelProvider.getLabel(entry.key); - - // ASSERT - assertNotNull(label,"Label should be returned for key " + entry.key); - assertEquals(entry.value, label, "Correct label should be returned for key " + entry.key); - } - } -} diff --git a/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/CheckValidatorFragment2.xtend b/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/CheckValidatorFragment2.java similarity index 54% rename from com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/CheckValidatorFragment2.xtend rename to com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/CheckValidatorFragment2.java index 64899f75c7..f313d2b848 100644 --- a/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/CheckValidatorFragment2.xtend +++ b/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/CheckValidatorFragment2.java @@ -9,24 +9,25 @@ * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.check.generator +package com.avaloq.tools.ddk.xtext.check.generator; -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess -import com.avaloq.tools.ddk.check.runtime.validation.AbstractCheckValidator -import com.avaloq.tools.ddk.check.runtime.validation.DefaultCheckValidator +import com.avaloq.tools.ddk.check.runtime.validation.AbstractCheckValidator; +import com.avaloq.tools.ddk.check.runtime.validation.DefaultCheckValidator; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; -class CheckValidatorFragment2 extends AbstractXtextGeneratorFragment { +public class CheckValidatorFragment2 extends AbstractXtextGeneratorFragment { - static val RUNTIME_PLUGIN = "com.avaloq.tools.ddk.check.runtime.core" + private static final String RUNTIME_PLUGIN = "com.avaloq.tools.ddk.check.runtime.core"; - override generate() { - new GuiceModuleAccess.BindingFactory().addTypeToTypeEagerSingleton(AbstractCheckValidator.typeRef, - DefaultCheckValidator.typeRef).contributeTo(language.runtimeGenModule) + @Override + public void generate() { + new GuiceModuleAccess.BindingFactory().addTypeToTypeEagerSingleton(TypeReference.typeRef(AbstractCheckValidator.class), + TypeReference.typeRef(DefaultCheckValidator.class)).contributeTo(getLanguage().getRuntimeGenModule()); - if (projectConfig.runtime.manifest !== null) { - projectConfig.runtime.manifest.requiredBundles += RUNTIME_PLUGIN + if (getProjectConfig().getRuntime().getManifest() != null) { + getProjectConfig().getRuntime().getManifest().getRequiredBundles().add(RUNTIME_PLUGIN); } } -} \ No newline at end of file +} diff --git a/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.java b/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.java new file mode 100644 index 0000000000..ff64e4e9cc --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.check.generator.quickfix; + +import com.google.inject.Inject; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; +import org.eclipse.xtext.xtext.generator.model.FileAccessFactory; +import org.eclipse.xtext.xtext.generator.model.TypeReference; + +public class CheckQuickfixProviderFragment2 extends AbstractXtextGeneratorFragment { + + private static final String UI_PLUGIN = "com.avaloq.tools.ddk.check.runtime.ui"; + + @Inject + private XtextGeneratorNaming xtextGeneratorNaming; + + @Inject + private FileAccessFactory fileAccessFactory; + + protected TypeReference getQuickfixProviderClass(final Grammar g) { + return new TypeReference( + xtextGeneratorNaming.getEclipsePluginBasePackage(g) + ".quickfix." + GrammarUtil.getSimpleName(g) + "QuickfixProvider" + ); + } + + @Override + public void generate() { + if (getProjectConfig().getEclipsePlugin().getManifest() != null) { + getProjectConfig().getEclipsePlugin().getManifest().getRequiredBundles().add(UI_PLUGIN); + } + + if (getProjectConfig().getEclipsePlugin().getSrc() != null) { + generateQuickfixProvider(); + } + + if (getProjectConfig().getEclipsePlugin().getPluginXml() != null) { + addRegistrationToPluginXml(); + } + } + + protected void generateQuickfixProvider() { + StringConcatenationClient content = new StringConcatenationClient() { + @Override + protected void appendTo(final TargetStringConcatenation builder) { + builder.append("public class "); + builder.append(getQuickfixProviderClass(getGrammar()).getSimpleName()); + builder.append(" extends DefaultCheckQuickfixProvider {"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append("// @Fix(MyJavaValidator.INVALID_NAME)"); + builder.newLine(); + builder.append("// public void capitalizeName(final Issue issue, IssueResolutionAcceptor acceptor) {"); + builder.newLine(); + builder.append("// acceptor.accept(issue, \"Capitalize name\", \"Capitalize the name.\", \"upcase.png\", new IModification() {"); + builder.newLine(); + builder.append("// public void apply(IModificationContext context) throws BadLocationException {"); + builder.newLine(); + builder.append("// IXtextDocument xtextDocument = context.getXtextDocument();"); + builder.newLine(); + builder.append("// String firstLetter = xtextDocument.get(issue.getOffset(), 1);"); + builder.newLine(); + builder.append("// xtextDocument.replace(issue.getOffset(), 1, firstLetter.toUpperCase());"); + builder.newLine(); + builder.append("// }"); + builder.newLine(); + builder.append("// });"); + builder.newLine(); + builder.append("// }"); + builder.newLine(); + builder.newLine(); + builder.append("}"); + builder.newLine(); + } + }; + fileAccessFactory.createJavaFile(getQuickfixProviderClass(getGrammar()), content).writeTo(getProjectConfig().getEclipsePlugin().getSrc()); + } + + protected void addRegistrationToPluginXml() { + final TypeReference executableExtensionFactory = xtextGeneratorNaming.getEclipsePluginExecutableExtensionFactory(getGrammar()); + StringConcatenation builder = new StringConcatenation(); + builder.append(""); + builder.newLine(); + builder.append(""); + builder.newLine(); + builder.append(" "); + builder.append(""); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(""); + builder.newLine(); + builder.append(""); + builder.newLine(); + getProjectConfig().getEclipsePlugin().getPluginXml().getEntries().add(builder.toString()); + } +} diff --git a/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.xtend b/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.xtend deleted file mode 100644 index 1d8885c764..0000000000 --- a/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.xtend +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.check.generator.quickfix - -import com.google.inject.Inject -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming -import org.eclipse.xtext.xtext.generator.model.FileAccessFactory -import org.eclipse.xtext.xtext.generator.model.TypeReference - -import static extension org.eclipse.xtext.GrammarUtil.* - -class CheckQuickfixProviderFragment2 extends AbstractXtextGeneratorFragment { - - static val UI_PLUGIN = "com.avaloq.tools.ddk.check.runtime.ui" - - @Inject extension XtextGeneratorNaming - - @Inject FileAccessFactory fileAccessFactory - - def protected TypeReference getQuickfixProviderClass(Grammar g) { - return new TypeReference( - g.eclipsePluginBasePackage + ".quickfix." + g.simpleName + "QuickfixProvider" - ) - } - - override generate() { - if (projectConfig.eclipsePlugin.manifest !== null) { - projectConfig.eclipsePlugin.manifest.requiredBundles += UI_PLUGIN - } - - if (projectConfig.eclipsePlugin.src !== null) { - generateQuickfixProvider - } - - if (projectConfig.eclipsePlugin.pluginXml !== null) { - addRegistrationToPluginXml - } - } - - protected def generateQuickfixProvider() { - fileAccessFactory.createJavaFile(grammar.quickfixProviderClass, ''' - public class «grammar.quickfixProviderClass.simpleName» extends DefaultCheckQuickfixProvider { - - // @Fix(MyJavaValidator.INVALID_NAME) - // public void capitalizeName(final Issue issue, IssueResolutionAcceptor acceptor) { - // acceptor.accept(issue, "Capitalize name", "Capitalize the name.", "upcase.png", new IModification() { - // public void apply(IModificationContext context) throws BadLocationException { - // IXtextDocument xtextDocument = context.getXtextDocument(); - // String firstLetter = xtextDocument.get(issue.getOffset(), 1); - // xtextDocument.replace(issue.getOffset(), 1, firstLetter.toUpperCase()); - // } - // }); - // } - - } - ''').writeTo(projectConfig.eclipsePlugin.src) - } - - protected def addRegistrationToPluginXml() { - val executableExtensionFactory = grammar.eclipsePluginExecutableExtensionFactory - projectConfig.eclipsePlugin.pluginXml.entries += ''' - - - - - - ''' - } -} diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtilX.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtilX.java new file mode 100644 index 0000000000..77a9fd3ae9 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtilX.java @@ -0,0 +1,30 @@ +package com.avaloq.tools.ddk.xtext.expression.generator; + +import java.util.Set; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.Grammar; +import com.avaloq.tools.ddk.xtext.util.EObjectUtil; + +public class GeneratorUtilX { + + public String xmlContributorComment(final String source) { + return ""; + } + + public String javaContributorComment(final String source) { + return "// contributed by " + source; + } + + public String location(final EObject obj) { + return EObjectUtil.getFileLocation(obj); + } + + public Set allInstantiatedTypes(final Grammar grammar) { + return GeneratorUtil.allInstantiatedTypes(grammar); + } + + public boolean canContain(final EClass eClass, final Set others, final Grammar g) { + return GeneratorUtil.canContain(eClass, others, g); + } +} diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtilX.xtend b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtilX.xtend deleted file mode 100644 index 90f780a714..0000000000 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GeneratorUtilX.xtend +++ /dev/null @@ -1,30 +0,0 @@ -package com.avaloq.tools.ddk.xtext.expression.generator - -import java.util.Set -import org.eclipse.emf.ecore.EClass -import org.eclipse.emf.ecore.EObject -import org.eclipse.xtext.Grammar -import com.avaloq.tools.ddk.xtext.util.EObjectUtil - -class GeneratorUtilX { - - def String xmlContributorComment(String source) { - '' - } - - def String javaContributorComment(String source) { - '// contributed by ' + source - } - - def String location(EObject obj) { - EObjectUtil.getFileLocation(obj) - } - - def Set allInstantiatedTypes(Grammar it) { - GeneratorUtil.allInstantiatedTypes(it) - } - - def boolean canContain(EClass it, Set others, Grammar g) { - GeneratorUtil.canContain(it, others, g) - } -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.xtend b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.java similarity index 51% rename from com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.xtend rename to com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.java index 953814b6bc..831c45a721 100644 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.xtend +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.java @@ -8,23 +8,21 @@ * Contributors: * Avaloq Group AG - initial API and implementation *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.expression.generator; -package com.avaloq.tools.ddk.xtext.expression.generator +import org.eclipse.xtext.util.Strings; -import org.eclipse.xtext.util.Strings +public class Naming { -class Naming { - - def toFileName(String qualifiedName) { - qualifiedName.toJavaPackage.replace('.', '/') + '/' + qualifiedName.toSimpleName + ".java" + public String toFileName(final String qualifiedName) { + return toJavaPackage(qualifiedName).replace('.', '/') + '/' + toSimpleName(qualifiedName) + ".java"; } - def toJavaPackage(String qualifiedName) { - Strings.skipLastToken(qualifiedName, '.') + public String toJavaPackage(final String qualifiedName) { + return Strings.skipLastToken(qualifiedName, "."); } - def toSimpleName(String qualifiedName) { - Strings.lastToken(qualifiedName, '.') + public String toSimpleName(final String qualifiedName) { + return Strings.lastToken(qualifiedName, "."); } - } diff --git a/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeModule.java b/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeModule.java new file mode 100644 index 0000000000..857ceeac50 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeModule.java @@ -0,0 +1,11 @@ +/* + * generated by Xtext 2.26 + */ +package com.avaloq.tools.ddk.xtext.format.ide; + + +/** + * Use this class to register ide components. + */ +public class FormatIdeModule extends AbstractFormatIdeModule { +} diff --git a/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeModule.xtend b/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeModule.xtend deleted file mode 100644 index e64de3e6d2..0000000000 --- a/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeModule.xtend +++ /dev/null @@ -1,11 +0,0 @@ -/* - * generated by Xtext 2.26 - */ -package com.avaloq.tools.ddk.xtext.format.ide - - -/** - * Use this class to register ide components. - */ -class FormatIdeModule extends AbstractFormatIdeModule { -} diff --git a/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeSetup.java b/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeSetup.java new file mode 100644 index 0000000000..d62207f5cd --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeSetup.java @@ -0,0 +1,21 @@ +/* + * generated by Xtext 2.25.0 + */ +package com.avaloq.tools.ddk.xtext.format.ide; + +import com.avaloq.tools.ddk.xtext.format.FormatRuntimeModule; +import com.avaloq.tools.ddk.xtext.format.FormatStandaloneSetup; +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.eclipse.xtext.util.Modules2; + +/** + * Initialization support for running Xtext languages as language servers. + */ +public class FormatIdeSetup extends FormatStandaloneSetup { + + @Override + public Injector createInjector() { + return Guice.createInjector(Modules2.mixin(new FormatRuntimeModule(), new FormatIdeModule())); + } +} diff --git a/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeSetup.xtend b/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeSetup.xtend deleted file mode 100644 index 97f5bdd664..0000000000 --- a/com.avaloq.tools.ddk.xtext.format.ide/src/com/avaloq/tools/ddk/xtext/format/ide/FormatIdeSetup.xtend +++ /dev/null @@ -1,20 +0,0 @@ -/* - * generated by Xtext 2.25.0 - */ -package com.avaloq.tools.ddk.xtext.format.ide - -import com.avaloq.tools.ddk.xtext.format.FormatRuntimeModule -import com.avaloq.tools.ddk.xtext.format.FormatStandaloneSetup -import com.google.inject.Guice -import org.eclipse.xtext.util.Modules2 - -/** - * Initialization support for running Xtext languages as language servers. - */ -class FormatIdeSetup extends FormatStandaloneSetup { - - override createInjector() { - Guice.createInjector(Modules2.mixin(new FormatRuntimeModule, new FormatIdeModule)) - } - -} diff --git a/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.java b/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.java new file mode 100644 index 0000000000..68171d233a --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.java @@ -0,0 +1,41 @@ +/* + * generated by Xtext 2.14.0 + */ +package com.avaloq.tools.ddk.xtext.format; + +import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration; +import com.google.inject.Inject; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@ExtendWith(InjectionExtension.class) +@InjectWith(FormatInjectorProvider.class) +public class FormatParsingTest { + + @Inject + private ParseHelper parseHelper; + + @Test + public void loadModel() throws Exception { + String input = "formatter for MyDsl\n" + + "\n" + + "const String SOME_STRING = \"\";\n" + + "const int SOME_INT = 2;\n" + + "\n" + + "Person {\n" + + "} "; + final FormatConfiguration result = parseHelper.parse(input); + assertNotNull(result); + boolean hasSyntaxErrors = ((XtextResource) result.eResource()).getParseResult().hasSyntaxErrors(); + assertFalse(hasSyntaxErrors, + "Unexpected errors: " + String.join(", ", + result.eResource().getErrors().stream().map(Object::toString).toList())); + } +} diff --git a/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.xtend b/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.xtend deleted file mode 100644 index e061f64b2e..0000000000 --- a/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.xtend +++ /dev/null @@ -1,40 +0,0 @@ -/* - * generated by Xtext 2.14.0 - */ -package com.avaloq.tools.ddk.xtext.format - -import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration -import com.google.inject.Inject -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.util.ParseHelper - -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.assertNotNull -import static org.junit.jupiter.api.Assertions.assertFalse -import org.eclipse.xtext.resource.XtextResource - -@ExtendWith(InjectionExtension) -@InjectWith(FormatInjectorProvider) -class FormatParsingTest { - @Inject - ParseHelper parseHelper - - @Test - def void loadModel() { - val result = parseHelper.parse(''' - formatter for MyDsl - - const String SOME_STRING = ""; - const int SOME_INT = 2; - - Person { - } ''' - ) - assertNotNull(result) - assertFalse( - ((result.eResource) as XtextResource).getParseResult. - hasSyntaxErrors, '''Unexpected errors: «result.eResource.errors.join(", ")»''') - } -} diff --git a/com.avaloq.tools.ddk.xtext.format.ui/src/com/avaloq/tools/ddk/xtext/format/ui/FormatUiModule.java b/com.avaloq.tools.ddk.xtext.format.ui/src/com/avaloq/tools/ddk/xtext/format/ui/FormatUiModule.java new file mode 100644 index 0000000000..ec4bec973b --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format.ui/src/com/avaloq/tools/ddk/xtext/format/ui/FormatUiModule.java @@ -0,0 +1,55 @@ +/* + * generated by Xtext 2.14.0 + */ +package com.avaloq.tools.ddk.xtext.format.ui; + +import com.avaloq.tools.ddk.xtext.format.ui.builder.FormatBuilderParticipant; +import com.avaloq.tools.ddk.xtext.format.ui.hyperlinking.FormatHyperlinkHelper; +import com.avaloq.tools.ddk.xtext.ui.templates.KeywordAwareCrossReferenceTemplateVariableResolver; +import com.google.inject.Binder; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.xtext.builder.IXtextBuilderParticipant; +import org.eclipse.xtext.ui.editor.hyperlinking.IHyperlinkHelper; +import org.eclipse.xtext.ui.editor.templates.CrossReferenceTemplateVariableResolver; +import org.eclipse.xtext.xtext.generator.model.project.IXtextProjectConfig; +import org.eclipse.xtext.xtext.generator.model.project.XtextProjectConfig; + +/** + * Use this class to register components to be used within the Eclipse IDE. + */ +public class FormatUiModule extends AbstractFormatUiModule { + + public FormatUiModule(final AbstractUIPlugin plugin) { + super(plugin); + } + + /** + * Binds a {@link CrossReferenceTemplateVariableResolver} which prefixes keywords with escape characters. + * + * @return {@link KeywordAwareCrossReferenceTemplateVariableResolver} + */ + public Class bindCrossReferenceTemplateVariableResolver() { + return KeywordAwareCrossReferenceTemplateVariableResolver.class; + } + + /** + * Bind hyperlink helper to provide hyperlinking from "override" keyword to extended rule. + * + * @return FormatHyperlinkHelper.class + */ + @Override + public Class bindIHyperlinkHelper() { + return FormatHyperlinkHelper.class; + } + + @Override + public Class bindIXtextBuilderParticipant() { + return FormatBuilderParticipant.class; + } + + @Override + public void configure(final Binder binder) { + super.configure(binder); + binder.bind(IXtextProjectConfig.class).to(XtextProjectConfig.class); + } +} diff --git a/com.avaloq.tools.ddk.xtext.format.ui/src/com/avaloq/tools/ddk/xtext/format/ui/FormatUiModule.xtend b/com.avaloq.tools.ddk.xtext.format.ui/src/com/avaloq/tools/ddk/xtext/format/ui/FormatUiModule.xtend deleted file mode 100644 index e9ff58f92c..0000000000 --- a/com.avaloq.tools.ddk.xtext.format.ui/src/com/avaloq/tools/ddk/xtext/format/ui/FormatUiModule.xtend +++ /dev/null @@ -1,47 +0,0 @@ -/* - * generated by Xtext 2.14.0 - */ -package com.avaloq.tools.ddk.xtext.format.ui - -import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor -import org.eclipse.xtext.ui.editor.templates.CrossReferenceTemplateVariableResolver -import com.avaloq.tools.ddk.xtext.ui.templates.KeywordAwareCrossReferenceTemplateVariableResolver -import com.avaloq.tools.ddk.xtext.format.ui.hyperlinking.FormatHyperlinkHelper -import com.avaloq.tools.ddk.xtext.format.ui.builder.FormatBuilderParticipant -import org.eclipse.xtext.xtext.generator.model.project.IXtextProjectConfig -import org.eclipse.xtext.xtext.generator.model.project.XtextProjectConfig -import com.google.inject.Binder - -/** - * Use this class to register components to be used within the Eclipse IDE. - */ -@FinalFieldsConstructor -class FormatUiModule extends AbstractFormatUiModule { - - /** - * Binds a {@link CrossReferenceTemplateVariableResolver} which prefixes keywords with escape characters. - * - * @return {@link KeywordAwareCrossReferenceTemplateVariableResolver} - */ - def Class bindCrossReferenceTemplateVariableResolver() { - return KeywordAwareCrossReferenceTemplateVariableResolver - } - - /** - * Bind hyperlink helper to provide hyperlinking from "override" keyword to extended rule. - * - * @return FormatHyperlinkHelper.class - */ - override bindIHyperlinkHelper() { - return FormatHyperlinkHelper - } - - override bindIXtextBuilderParticipant() { - return FormatBuilderParticipant - } - - override configure(Binder binder) { - super.configure(binder); - binder.bind(IXtextProjectConfig).to(XtextProjectConfig); - } -} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatStandaloneSetup.xtend b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatStandaloneSetup.java similarity index 54% rename from com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatStandaloneSetup.xtend rename to com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatStandaloneSetup.java index 352e2d59f3..f24c0d5ebe 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatStandaloneSetup.xtend +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatStandaloneSetup.java @@ -1,15 +1,15 @@ /* * generated by Xtext 2.14.0 */ -package com.avaloq.tools.ddk.xtext.format +package com.avaloq.tools.ddk.xtext.format; /** * Initialization support for running Xtext languages without Equinox extension registry. */ -class FormatStandaloneSetup extends FormatStandaloneSetupGenerated { +public class FormatStandaloneSetup extends FormatStandaloneSetupGenerated { - def static void doSetup() { - new FormatStandaloneSetup().createInjectorAndDoEMFRegistration() + public static void doSetup() { + new FormatStandaloneSetup().createInjectorAndDoEMFRegistration(); } } diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.java new file mode 100644 index 0000000000..e3288834bf --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) Avaloq Group AG + * Schwerzistrasse 6, 8807 Freienbach, Switzerland, http://www.avaloq.com + * All Rights Reserved. + * + * This software is the confidential and proprietary information of Avaloq Group AG. + * You shall not disclose whole or parts of it and shall use it only in accordance with the terms of the + * licence agreement you entered into with Avaloq Group AG. + */ + +package com.avaloq.tools.ddk.xtext.generator; + +import com.google.common.collect.Iterables; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.model.ManifestAccess; +import org.eclipse.xtext.xtext.generator.model.project.IBundleProjectConfig; + +/** + * Removes the bundle-version from specific bundles in generated manifests + * + * In some projects, we choose not to include bundle-versions in the manifest, but various fragments generate them anyway. + * Run this fragment at the end to remove versions for specific bundles + */ +public class BundleVersionStripperFragment extends AbstractXtextGeneratorFragment { + + private final List bundles = new ArrayList<>(); + + public void addBundle(final String bundleName) { + bundles.add(bundleName); + } + + @Override + public void generate() { + for (IBundleProjectConfig project : Iterables.filter(getProjectConfig().getEnabledProjects(), IBundleProjectConfig.class)) { + ManifestAccess manifest = project.getManifest(); + if (manifest != null) { + stripBundleVersions(manifest); + } + } + } + + public void stripBundleVersions(final ManifestAccess manifest) { + for (String bundleName : bundles) { + if (manifest.getRequiredBundles().removeIf(it -> it.startsWith(bundleName))) { + manifest.getRequiredBundles().add(bundleName); + } + } + } + + protected List getBundles() { + return bundles; + } +} + +/* Copyright (c) Avaloq Group AG */ diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.xtend deleted file mode 100644 index 2a26eb1198..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.xtend +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) Avaloq Group AG - * Schwerzistrasse 6, 8807 Freienbach, Switzerland, http://www.avaloq.com - * All Rights Reserved. - * - * This software is the confidential and proprietary information of Avaloq Group AG. - * You shall not disclose whole or parts of it and shall use it only in accordance with the terms of the - * licence agreement you entered into with Avaloq Group AG. - */ - -package com.avaloq.tools.ddk.xtext.generator - -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtend.lib.annotations.Accessors -import java.util.List -import org.eclipse.xtext.xtext.generator.model.ManifestAccess -import org.eclipse.xtext.xtext.generator.model.project.IBundleProjectConfig - -/** - * Removes the bundle-version from specific bundles in generated manifests - * - * In some projects, we choose not to include bundle-versions in the manifest, but various fragments generate them anyway. - * Run this fragment at the end to remove versions for specific bundles - */ -class BundleVersionStripperFragment extends AbstractXtextGeneratorFragment { - - @Accessors(PROTECTED_GETTER) - val List bundles = newArrayList - - def void addBundle(String bundleName) { - bundles.add(bundleName) - } - - override generate() { - projectConfig.enabledProjects.filter(typeof(IBundleProjectConfig)).map[manifest].filterNull.forEach[stripBundleVersions] - } - - def stripBundleVersions(ManifestAccess manifest) { - bundles.forEach[ bundleName | - if (manifest.requiredBundles.removeIf([it.startsWith(bundleName)])) { - manifest.requiredBundles.add(bundleName) - } - ] - } - -} - -/* Copyright (c) Avaloq Group AG */ \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/model/project/ProjectConfig.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/model/project/ProjectConfig.java new file mode 100644 index 0000000000..a51cd7fb80 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/model/project/ProjectConfig.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.model.project; + +import org.eclipse.xtext.xtext.generator.model.project.StandardProjectConfig; +import org.eclipse.xtext.xtext.generator.model.project.SubProjectConfig; + +public class ProjectConfig extends StandardProjectConfig { + + private String runtimeSuffix = ""; + private String testSuffix = "test"; + private String eclipsePluginSuffix = "ui"; + private String genericIdeSuffix = "ide"; + private boolean forceDisableIdeProject = true; + + @Override + protected String computeName(final SubProjectConfig project) { + if (isMavenLayout()) { + return super.computeName(project); + } + if (project == getRuntime()) { + return runtimeSuffix.isEmpty() ? getBaseName() : getBaseName() + "." + runtimeSuffix; + } else if (project == getRuntimeTest()) { + return runtimeSuffix.isEmpty() ? getBaseName() + "." + testSuffix : getBaseName() + "." + runtimeSuffix + "." + testSuffix; + } else if (project == getGenericIde()) { + return getBaseName() + "." + genericIdeSuffix; + } else if (project == getEclipsePlugin()) { + return getBaseName() + "." + eclipsePluginSuffix; + } else if (project == getEclipsePluginTest()) { + return getBaseName() + "." + eclipsePluginSuffix + "." + testSuffix; + } else { + return super.computeName(project); + } + } + + @Override + public void setDefaults() { + super.setDefaults(); + if (forceDisableIdeProject) { + getGenericIde().setEnabled(false); + } + } + + public String getRuntimeSuffix() { + return runtimeSuffix; + } + + public void setRuntimeSuffix(final String runtimeSuffix) { + this.runtimeSuffix = runtimeSuffix; + } + + public String getTestSuffix() { + return testSuffix; + } + + public void setTestSuffix(final String testSuffix) { + this.testSuffix = testSuffix; + } + + public String getEclipsePluginSuffix() { + return eclipsePluginSuffix; + } + + public void setEclipsePluginSuffix(final String eclipsePluginSuffix) { + this.eclipsePluginSuffix = eclipsePluginSuffix; + } + + public String getGenericIdeSuffix() { + return genericIdeSuffix; + } + + public void setGenericIdeSuffix(final String genericIdeSuffix) { + this.genericIdeSuffix = genericIdeSuffix; + } + + public boolean isForceDisableIdeProject() { + return forceDisableIdeProject; + } + + public void setForceDisableIdeProject(final boolean forceDisableIdeProject) { + this.forceDisableIdeProject = forceDisableIdeProject; + } +} + +/* Copyright (c) Avaloq Group AG */ diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/model/project/ProjectConfig.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/model/project/ProjectConfig.xtend deleted file mode 100644 index 47cbc2593d..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/model/project/ProjectConfig.xtend +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.model.project - -import org.eclipse.xtend.lib.annotations.Accessors -import org.eclipse.xtext.xtext.generator.model.project.StandardProjectConfig -import org.eclipse.xtext.xtext.generator.model.project.SubProjectConfig - -class ProjectConfig extends StandardProjectConfig { - - @Accessors var String runtimeSuffix = "" - @Accessors var String testSuffix = "test" - @Accessors var String eclipsePluginSuffix = "ui" - @Accessors var String genericIdeSuffix = "ide" - @Accessors var boolean forceDisableIdeProject = true - - override protected computeName(SubProjectConfig project) { - if (mavenLayout) { - return super.computeName(project) - } - switch project { - case runtime: runtimeSuffix.empty ? '''«baseName»''':'''«baseName».«runtimeSuffix»''' - case runtimeTest: runtimeSuffix.empty ? '''«baseName».«testSuffix»''' : '''«baseName».«runtimeSuffix».«testSuffix»''' - case genericIde: '''«baseName».«genericIdeSuffix»''' - case eclipsePlugin: '''«baseName».«eclipsePluginSuffix»''' - case eclipsePluginTest: '''«baseName».«eclipsePluginSuffix».«testSuffix»''' - default: super.computeName(project) - } - } - - override setDefaults() { - super.setDefaults - if (forceDisableIdeProject) { - genericIde.enabled = false - } - } - -} - -/* Copyright (c) Avaloq Group AG */ \ No newline at end of file diff --git a/docs/xtend-migration.md b/docs/xtend-migration.md index c781d012b2..717f7b4f95 100644 --- a/docs/xtend-migration.md +++ b/docs/xtend-migration.md @@ -12,10 +12,10 @@ | Metric | Value | |--------|-------| | Total Xtend source files | 94 | -| Already migrated (Batch 1) | 8 | -| Remaining | 86 | -| Total remaining lines | ~12,874 | -| Modules with remaining Xtend | 24 | +| Already migrated (Batch 1–3) | 36 | +| Remaining | 58 | +| Total remaining lines | ~11,494 | +| Modules with remaining Xtend | 19 | --- @@ -24,24 +24,24 @@ | Module | Files | Lines | Status | |--------|-------|-------|--------| | `check.core` | 8 | ~1,848 | **DONE** (Batch 1) | -| `check.core.test` | 11 | 1,717 | Pending | -| `check.test.runtime` | 1 | 22 | Pending | -| `check.test.runtime.tests` | 3 | 202 | Pending | -| `check.ui` | 2 | 113 | Pending | +| `check.core.test` | 8 | 1,508 | 3 done (Batch 2–3), 5 pending | +| `check.test.runtime` | 1 | 22 | **DONE** (Batch 2) | +| `check.test.runtime.tests` | 3 | 202 | 2 done (Batch 3), 1 pending | +| `check.ui` | 2 | 113 | **DONE** (Batch 3) | | `check.ui.test` | 1 | 200 | Pending | -| `checkcfg.core` | 4 | 303 | Pending | -| `checkcfg.core.test` | 7 | 460 | Pending | -| `sample.helloworld.ui.test` | 3 | 203 | Pending | -| `xtext.check.generator` | 2 | 113 | Pending | +| `checkcfg.core` | 4 | 303 | 3 done (Batch 2–3), 1 pending | +| `checkcfg.core.test` | 7 | 460 | 4 done (Batch 2–3), 3 pending | +| `sample.helloworld.ui.test` | 3 | 203 | 2 done (Batch 3), 1 pending | +| `xtext.check.generator` | 2 | 113 | **DONE** (Batch 2–3) | | `xtext.export` | 9 | 1,027 | Pending | | `xtext.export.generator` | 1 | 86 | Pending | -| `xtext.expression` | 5 | 679 | Pending | -| `xtext.format` | 6 | 1,623 | Pending | +| `xtext.expression` | 5 | 679 | 2 done (Batch 2), 3 pending | +| `xtext.format` | 6 | 1,623 | 1 done (Batch 2), 5 pending | | `xtext.format.generator` | 1 | 239 | Pending | -| `xtext.format.ide` | 2 | 31 | Pending | -| `xtext.format.test` | 1 | 40 | Pending | -| `xtext.format.ui` | 1 | 47 | Pending | -| `xtext.generator` | 18 | 3,450 | Pending | +| `xtext.format.ide` | 2 | 31 | **DONE** (Batch 2) | +| `xtext.format.test` | 1 | 40 | **DONE** (Batch 3) | +| `xtext.format.ui` | 1 | 47 | **DONE** (Batch 2) | +| `xtext.generator` | 18 | 3,450 | 2 done (Batch 2), 16 pending | | `xtext.generator.test` | 1 | 200 | Pending | | `xtext.scope` | 4 | 852 | Pending | | `xtext.scope.generator` | 1 | 47 | Pending | @@ -66,77 +66,77 @@ All module names are prefixed with `com.avaloq.tools.ddk.` (omitted for brevity) --- -## Batch 2 — Trivial files ≤50 lines (~14 files) +## Batch 2 — Trivial files ≤50 lines (~14 files) — DONE Small setup classes, empty modules, simple overrides. ### `check.test.runtime` (1 file) -- [ ] `TestLanguageGenerator.xtend` (22 lines) — Trivial — override +- [x] `TestLanguageGenerator.xtend` (22 lines) — Trivial — override ### `xtext.format.ide` (2 files) -- [ ] `FormatIdeModule.xtend` (11 lines) — Trivial — no complex features -- [ ] `FormatIdeSetup.xtend` (20 lines) — Trivial — override +- [x] `FormatIdeModule.xtend` (11 lines) — Trivial — no complex features +- [x] `FormatIdeSetup.xtend` (20 lines) — Trivial — override ### `xtext.format` (1 file) -- [ ] `FormatStandaloneSetup.xtend` (15 lines) — Trivial — extension +- [x] `FormatStandaloneSetup.xtend` (15 lines) — Trivial — extension ### `xtext.expression` (2 files) -- [ ] `GeneratorUtilX.xtend` (29 lines) — Trivial — no complex features -- [ ] `Naming.xtend` (30 lines) — Trivial — no complex features +- [x] `GeneratorUtilX.xtend` (29 lines) — Trivial — no complex features +- [x] `Naming.xtend` (30 lines) — Trivial — no complex features ### `xtext.check.generator` (1 file) -- [ ] `CheckValidatorFragment2.xtend` (31 lines) — Trivial — extension, !==, override +- [x] `CheckValidatorFragment2.xtend` (31 lines) — Trivial — extension, !==, override ### `checkcfg.core.test` (2 files) -- [ ] `CheckCfgTestUtil.xtend` (32 lines) — Trivial — override -- [ ] `CheckCfgModelUtil.xtend` (42 lines) — Trivial — templates +- [x] `CheckCfgTestUtil.xtend` (32 lines) — Trivial — override +- [x] `CheckCfgModelUtil.xtend` (42 lines) — Trivial — templates ### `checkcfg.core` (1 file) -- [ ] `CheckCfgJvmModelInferrer.xtend` (45 lines) — Trivial — templates, extension, @Inject +- [x] `CheckCfgJvmModelInferrer.xtend` (45 lines) — Trivial — templates, extension, @Inject ### `xtext.format.test` (1 file) -- [ ] `FormatParsingTest.xtend` (40 lines) — Trivial — templates, @Inject +- [x] `FormatParsingTest.xtend` (40 lines) — Trivial — templates, @Inject ### `xtext.format.ui` (1 file) -- [ ] `FormatUiModule.xtend` (47 lines) — Trivial — override +- [x] `FormatUiModule.xtend` (47 lines) — Trivial — override ### `xtext.generator` (2 files) -- [ ] `BundleVersionStripperFragment.xtend` (47 lines) — Trivial — typeof, @Accessors -- [ ] `ProjectConfig.xtend` (48 lines) — Trivial — templates, @Accessors, switch +- [x] `BundleVersionStripperFragment.xtend` (47 lines) — Trivial — typeof, @Accessors +- [x] `ProjectConfig.xtend` (48 lines) — Trivial — templates, @Accessors, switch --- -## Batch 3 — Easy files 50–100 lines (~16 files) +## Batch 3 — Easy files 50–100 lines (~14 files) — DONE Simple test files, utilities, small production code. ### `check.core.test` (3 files) -- [ ] `BugAig830.xtend` (56 lines) — Easy — templates, @Inject -- [ ] `CheckTestUtil.xtend` (72 lines) — Easy — ===, !== -- [ ] `CheckScopingTest.xtend` (81 lines) — Easy — extension, typeof, @Inject +- [x] `BugAig830.xtend` (56 lines) — Easy — templates, @Inject +- [x] `CheckTestUtil.xtend` (72 lines) — Easy — ===, !== +- [x] `CheckScopingTest.xtend` (81 lines) — Easy — extension, typeof, @Inject ### `check.test.runtime.tests` (2 files) -- [ ] `IssueLabelTest.xtend` (56 lines) — Easy — #{, override -- [ ] `CheckConfigurationIsAppliedTest.xtend` (64 lines) — Easy — extension, typeof, @Inject, override +- [x] `IssueLabelTest.xtend` (56 lines) — Easy — #{, override +- [x] `CheckConfigurationIsAppliedTest.xtend` (64 lines) — Easy — extension, typeof, @Inject, override ### `check.ui` (2 files) -- [ ] `CheckNewProject.xtend` (50 lines) — Easy — templates, !== -- [ ] `CheckQuickfixProvider.xtend` (63 lines) — Easy — templates +- [x] `CheckNewProject.xtend` (50 lines) — Easy — templates, !== +- [x] `CheckQuickfixProvider.xtend` (63 lines) — Easy — templates ### `checkcfg.core` (2 files) -- [ ] `CheckCfgGenerator.xtend` (53 lines) — Easy — templates, typeof, @Inject, override -- [ ] `ConfiguredParameterChecks.xtend` (66 lines) — Easy — templates, ===, !==, ?. +- [x] `CheckCfgGenerator.xtend` (53 lines) — Easy — templates, typeof, @Inject, override +- [x] `ConfiguredParameterChecks.xtend` (66 lines) — Easy — templates, ===, !==, ?. ### `checkcfg.core.test` (2 files) -- [ ] `CheckCfgConfiguredParameterValidationsTest.xtend` (63 lines) — Easy — templates, extension, override -- [ ] `CheckCfgTest.xtend` (63 lines) — Easy — templates, typeof, @Inject +- [x] `CheckCfgConfiguredParameterValidationsTest.xtend` (63 lines) — Easy — templates, extension, override +- [x] `CheckCfgTest.xtend` (63 lines) — Easy — templates, typeof, @Inject ### `sample.helloworld.ui.test` (2 files) -- [ ] `IssueLabelTest.xtend` (56 lines) — Easy — #{, override -- [ ] `CheckConfigurationIsAppliedTest.xtend` (64 lines) — Easy — extension, typeof, @Inject, override +- [x] `IssueLabelTest.xtend` (56 lines) — Easy — #{, override +- [x] `CheckConfigurationIsAppliedTest.xtend` (64 lines) — Easy — extension, typeof, @Inject, override ### `xtext.check.generator` (1 file) -- [ ] `CheckQuickfixProviderFragment2.xtend` (82 lines) — Easy — templates, extension, @Inject +- [x] `CheckQuickfixProviderFragment2.xtend` (82 lines) — Easy — templates, extension, @Inject --- From 13e0fd99cf154ecbc3606dc83839e35ea6328daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 28 Feb 2026 13:34:05 +0100 Subject: [PATCH 05/23] feat: migrate Batch 4 Xtend files to Java 21 (13 files) Migrate 13 Xtend files across 8 modules: - check.core.test: CheckApiAccessValidationsTest, ProjectBasedTests, IssueCodeValueTest, BasicModelTest - check.test.runtime.tests: CheckExecutionEnvironmentProjectTest - sample.helloworld.ui.test: CheckExecutionEnvironmentProjectTest - checkcfg.core: PropertiesInferenceHelper - checkcfg.core.test: CheckCfgScopeProviderTest, CheckCfgContentAssistTest, CheckCfgSyntaxTest - xtext.export.generator: ExportFragment2 - xtext.scope.generator: ScopingFragment2 - xtext.test.core: Tag Progress: 49/94 files migrated (52%). Co-Authored-By: Claude Opus 4.6 --- .../core/generator/IssueCodeValueTest.java | 115 +++++++++++++ .../core/generator/IssueCodeValueTest.xtend | 104 ------------ .../ddk/check/core/test/BasicModelTest.java | 120 +++++++++++++ .../ddk/check/core/test/BasicModelTest.xtend | 116 ------------- .../check/core/test/ProjectBasedTests.java | 100 +++++++++++ .../check/core/test/ProjectBasedTests.xtend | 88 ---------- .../CheckApiAccessValidationsTest.java | 61 +++++++ .../CheckApiAccessValidationsTest.xtend | 61 ------- .../CheckExecutionEnvironmentProjectTest.java | 84 +++++++++ ...CheckExecutionEnvironmentProjectTest.xtend | 82 --------- .../CheckCfgContentAssistTest.java | 84 +++++++++ .../CheckCfgContentAssistTest.xtend | 84 --------- .../scoping/CheckCfgScopeProviderTest.java | 85 ++++++++++ .../scoping/CheckCfgScopeProviderTest.xtend | 77 --------- .../checkcfg/syntax/CheckCfgSyntaxTest.java | 101 +++++++++++ .../checkcfg/syntax/CheckCfgSyntaxTest.xtend | 99 ----------- .../util/PropertiesInferenceHelper.java | 160 ++++++++++++++++++ .../util/PropertiesInferenceHelper.xtend | 140 --------------- .../CheckExecutionEnvironmentProjectTest.java | 85 ++++++++++ ...CheckExecutionEnvironmentProjectTest.xtend | 83 --------- .../export/generator/ExportFragment2.java | 86 ++++++++++ .../export/generator/ExportFragment2.xtend | 87 ---------- .../scope/generator/ScopingFragment2.java | 47 +++++ .../scope/generator/ScopingFragment2.xtend | 48 ------ .../ddk/xtext/test/{Tag.xtend => Tag.java} | 8 +- docs/xtend-migration.md | 52 +++--- 26 files changed, 1158 insertions(+), 1099 deletions(-) create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.xtend create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.xtend create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.xtend create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.xtend create mode 100644 com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckExecutionEnvironmentProjectTest.java delete mode 100644 com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckExecutionEnvironmentProjectTest.xtend create mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.xtend create mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.xtend create mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.xtend create mode 100644 com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java delete mode 100644 com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.xtend create mode 100644 com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckExecutionEnvironmentProjectTest.java delete mode 100644 com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckExecutionEnvironmentProjectTest.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.scope.generator/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopingFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.scope.generator/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopingFragment2.xtend rename com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/{Tag.xtend => Tag.java} (79%) diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java new file mode 100644 index 0000000000..2e5d74ef04 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Evolution AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.check.core.generator; + +import java.io.ByteArrayInputStream; +import java.util.List; +import java.util.Map; + +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.xbase.testing.JavaSource; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import com.avaloq.tools.ddk.check.CheckInjectorProvider; +import com.avaloq.tools.ddk.check.core.test.AbstractCheckGenerationTestCase; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@InjectWith(CheckInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class IssueCodeValueTest extends AbstractCheckGenerationTestCase { + + private static final String PACKAGE_NAME = "mypackage"; + private static final String CATALOG_NAME = "MyCatalog"; + + /** + * Test the map generated from a catalog with checks. + */ + @Test + public void testIssueCodeValue() throws Exception { + // ARRANGE + // @Format-Off + String source = "package " + PACKAGE_NAME + "\n" + + "\n" + + "import com.avaloq.tools.ddk.check.check.Check\n" + + "import com.avaloq.tools.ddk.check.check.Context\n" + + "import com.avaloq.tools.ddk.check.check.Documented\n" + + "\n" + + "catalog " + CATALOG_NAME + "\n" + + "for grammar com.avaloq.tools.ddk.check.Check {\n" + + "\n" + + " live error MyCheck1 \"Label 1\"\n" + + " message \"Message 1\" {\n" + + " for Documented elem {\n" + + " switch elem {\n" + + " Context : issue on elem\n" + + " Check : issue on elem\n" + + " }\n" + + " }\n" + + " }\n" + + "\n" + + " live error MyCheck_2 \"Label 2\"\n" + + " message \"Message 2\" {\n" + + " for Documented elem {\n" + + " switch elem {\n" + + " Context : issue on elem\n" + + " Check : issue on elem\n" + + " }\n" + + " }\n" + + " }\n" + + "\n" + + " live error MYCheck3 \"Label 3\"\n" + + " message \"Message 3\" {\n" + + " for Documented elem {\n" + + " switch elem {\n" + + " Context : issue on elem\n" + + " Check : issue on elem\n" + + " }\n" + + " }\n" + + " }\n" + + "}\n"; + // @Format-On + + Map expectedIssueCodeValues = Map.of( + "MY_CHECK_1", "MyCheck1", + "MY_CHECK_2", "MyCheck2", + "MY_CHECK_3", "MyCheck3"); + + // ACT + List compiledClassesList; + ByteArrayInputStream sourceStream = new ByteArrayInputStream(source.getBytes()); + try { + compiledClassesList = generateAndCompile(sourceStream); + } finally { + sourceStream.close(); + } + + // ASSERT + String issueCodesClassName = CATALOG_NAME + ISSUE_CODES_SUFFIX; + + String issueCodesClass = compiledClassesList.stream() + .filter(s -> s.getFileName().equals(issueCodesClassName)) + .findFirst() + .orElse(null) + .getCode(); + + for (Map.Entry issueCode : expectedIssueCodeValues.entrySet()) { + String expectedIssueCodeAssignment = "public static final String " + issueCode.getKey() + + " = \"" + PACKAGE_NAME + "." + CATALOG_NAME + ISSUE_CODES_SUFFIX + "." + issueCode.getValue() + "\";"; + assertTrue(issueCodesClass.contains(expectedIssueCodeAssignment), + issueCodesClassName + " contains correct initialization of " + issueCode.getKey()); + } + } + +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.xtend deleted file mode 100644 index 7a53cffd08..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.xtend +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Evolution AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.check.core.generator - -import org.eclipse.xtext.testing.InjectWith -import com.avaloq.tools.ddk.check.CheckInjectorProvider -import com.avaloq.tools.ddk.check.core.test.AbstractCheckGenerationTestCase -import java.util.List -import org.eclipse.xtext.xbase.testing.JavaSource -import java.io.ByteArrayInputStream -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.assertTrue - -@InjectWith(CheckInjectorProvider) -@ExtendWith(InjectionExtension) -class IssueCodeValueTest extends AbstractCheckGenerationTestCase { - - static final String PACKAGE_NAME = "mypackage" - static final String CATALOG_NAME = "MyCatalog" - - /** - * Test the map generated from a catalog with checks. - */ - @Test - def void testIssueCodeValue() { - // ARRANGE - // @Format-Off - val source = ''' - package «PACKAGE_NAME» - - import com.avaloq.tools.ddk.check.check.Check - import com.avaloq.tools.ddk.check.check.Context - import com.avaloq.tools.ddk.check.check.Documented - - catalog «CATALOG_NAME» - for grammar com.avaloq.tools.ddk.check.Check { - - live error MyCheck1 "Label 1" - message "Message 1" { - for Documented elem { - switch elem { - Context : issue on elem - Check : issue on elem - } - } - } - - live error MyCheck_2 "Label 2" - message "Message 2" { - for Documented elem { - switch elem { - Context : issue on elem - Check : issue on elem - } - } - } - - live error MYCheck3 "Label 3" - message "Message 3" { - for Documented elem { - switch elem { - Context : issue on elem - Check : issue on elem - } - } - } - } - '''; - // @Format-On - - val expectedIssueCodeValues = #{'MY_CHECK_1' -> 'MyCheck1', 'MY_CHECK_2' -> 'MyCheck2', 'MY_CHECK_3' -> 'MyCheck3'} - - // ACT - var List compiledClassesList - val sourceStream = new ByteArrayInputStream(source.getBytes()); - try { - compiledClassesList = generateAndCompile(sourceStream); - } finally { - sourceStream.close - } - - // ASSERT - val issueCodesClassName = '''«CATALOG_NAME»«ISSUE_CODES_SUFFIX»''' - - val issueCodesClass = compiledClassesList.findFirst[s | s.fileName.equals(issueCodesClassName)].code; - - for (issueCode: expectedIssueCodeValues.entrySet) { - val expectedIssueCodeAssignment = '''public static final String «issueCode.key» = "«PACKAGE_NAME».«CATALOG_NAME»«ISSUE_CODES_SUFFIX».«issueCode.value»";''' - assertTrue(issueCodesClass.contains(expectedIssueCodeAssignment), '''«issueCodesClassName» contains correct initialization of «issueCode.key»''') - } - } - -} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.java new file mode 100644 index 0000000000..7acf251db5 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.core.test; + +import com.avaloq.tools.ddk.check.CheckUiInjectorProvider; +import com.avaloq.tools.ddk.check.check.Check; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.XIssueExpression; +import com.avaloq.tools.ddk.check.core.test.util.CheckModelUtil; +import com.avaloq.tools.ddk.check.core.test.util.CheckTestUtil; +import com.google.inject.Inject; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +@InjectWith(CheckUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class BasicModelTest { + + @Inject + private ParseHelper parser; + + @Inject + private CheckTestUtil util; + + @Inject + private CheckModelUtil modelUtil; + + /** + * Tests that an empty model based on EPackage model reference can be created. + */ + @Test + public void testCreateEmptyModelWithPackageReference() throws Exception { + CheckCatalog model = parser.parse("package p catalog c {}"); + assertNotNull(model, "CheckCatalog with EPackage reference successfully created"); + } + + /** + * Tests that an empty model based on model reference by Xtext Grammar can be created. + */ + @Test + public void testCreateEmptyModelWithGrammarReference() throws Exception { + CheckCatalog model = parser.parse("package p catalog c for grammar com.avaloq.tools.ddk.check.Check {}"); + assertNotNull(model, "CheckCatalog with Grammar reference successfully created"); + } + + /* Tests that an XIssueExpression takes message parameters. */ + @Test + public void testXIssueExpressionMessageParameters() throws Exception { + CheckCatalog model = parser.parse(modelUtil.modelWithContext() + "issue A on it bind (\"mp0\", \"mp1\")"); + assertEquals(2, util.getFirstInstanceOf(model, XIssueExpression.class).getMessageParameters().size()); + } + + /* Tests that an XIssueExpression takes message parameters when a marker feature has been specified. */ + @Test + public void testXIssueExpressionWithMarkerFeatureMessageParameters() throws Exception { + CheckCatalog model = parser.parse(modelUtil.modelWithContext() + "issue A on x#name bind (\"mp0\", \"mp1\")"); + assertEquals(2, util.getFirstInstanceOf(model, XIssueExpression.class).getMessageParameters().size()); + } + + /* Tests that Checks documented with ML_COMMENTs have an inferred description field. */ + @Test + @Disabled("Fails because DocumentedImplCustom uses the null resource description provider to get the document provider") + public void testInferingOfDescription() throws Exception { + Check check = util.getFirstInstanceOf(parser.parse(modelUtil.modelWithCheck()), Check.class); + assertEquals(check.getDescription(), "No documentation."); + } + + /* Tests that Checks have an implicit name which matches the ID. */ + @Test + public void testCheckNameIDIsPresent() throws Exception { + String id = "CheckID"; + Check check = util.getFirstInstanceOf(parser.parse(modelUtil.modelWithCheck(id)), Check.class); + assertEquals(check.getId(), check.getName(), "Check name field matches ID field"); + assertEquals(id, check.getName(), "Check name field matches supplied ID"); + } + + /* Tests that Checks have an implicit name which matches the ID even when the ID is missing. */ + @Test + public void testCheckNameIDIsMissing() throws Exception { + Check check = util.getFirstInstanceOf(parser.parse(modelUtil.modelWithCheck("")), Check.class); + assertNull(check.getName(), "Check name is null"); + } + + /* Tests that multi- and single-line comments are parsed in a model. */ + @Test + public void testCommentsInModelParse() throws Exception { + CheckCatalog model = parser.parse(modelUtil.modelWithComments()); + assertFalse(((XtextResource) model.eResource()).getParseResult().hasSyntaxErrors(), + "Syntax errors not expected but occurred"); + } + + /* Tests that t.message is allowed, despite "message" being a keyword. */ + @Test + public void testKeywordAsIdentifier() throws Exception { + CheckCatalog model = parser.parse( + modelUtil.modelWithContext() + + "try { issue bind (\"mp0\", \"mp1\"); } catch (java.lang.Throwable t) { issue bind (t.message, \"foo\"); }" + + "}}}}"); + assertFalse(((XtextResource) model.eResource()).getParseResult().hasSyntaxErrors(), + "Syntax errors not expected but occurred"); + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.xtend deleted file mode 100644 index 42aad415be..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.xtend +++ /dev/null @@ -1,116 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.core.test - -import com.avaloq.tools.ddk.check.CheckUiInjectorProvider -import com.avaloq.tools.ddk.check.check.Check -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.check.XIssueExpression -import com.avaloq.tools.ddk.check.core.test.util.CheckModelUtil -import com.avaloq.tools.ddk.check.core.test.util.CheckTestUtil -import com.google.inject.Inject -import org.eclipse.xtext.resource.XtextResource -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.util.ParseHelper -import org.junit.jupiter.api.Test -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.^extension.ExtendWith -import static org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Disabled - -@InjectWith(typeof(CheckUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class BasicModelTest { - - @Inject - ParseHelper parser - - @Inject - CheckTestUtil util - - @Inject - CheckModelUtil modelUtil - - /** - * Tests that an empty model based on EPackage model reference can be created. - */ - @Test - def void testCreateEmptyModelWithPackageReference() { - val model = parser.parse("package p catalog c {}") - assertNotNull(model, "CheckCatalog with EPackage reference successfully created") - } - - /** - * Tests that an empty model based on model reference by Xtext Grammar can be created. - */ - @Test - def void testCreateEmptyModelWithGrammarReference() { - val model = parser.parse("package p catalog c for grammar com.avaloq.tools.ddk.check.Check {}") - assertNotNull(model, "CheckCatalog with Grammar reference successfully created") - } - - /* Tests that an XIssueExpression takes message parameters. */ - @Test - def void testXIssueExpressionMessageParameters() { - val model = parser.parse(modelUtil.modelWithContext + "issue A on it bind (\"mp0\", \"mp1\")") - assertEquals(2, util.getFirstInstanceOf(model, typeof(XIssueExpression)).messageParameters.size) - } - - /* Tests that an XIssueExpression takes message parameters when a marker feature has been specified. */ - @Test - def void testXIssueExpressionWithMarkerFeatureMessageParameters() { - val model = parser.parse(modelUtil.modelWithContext + "issue A on x#name bind (\"mp0\", \"mp1\")") - assertEquals(2, util.getFirstInstanceOf(model, typeof(XIssueExpression)).messageParameters.size) - } - - /* Tests that Checks documented with ML_COMMENTs have an inferred description field. */ - @Test - @Disabled("Fails because DocumentedImplCustom uses the null resource description provider to get the document provider") - def void testInferingOfDescription() { - val check = util.getFirstInstanceOf(parser.parse(modelUtil.modelWithCheck), typeof(Check)) - assertEquals(check.description, "No documentation.") - } - - /* Tests that Checks have an implicit name which matches the ID. */ - @Test - def void testCheckNameIDIsPresent() { - val id = "CheckID" - val check = util.getFirstInstanceOf(parser.parse(modelUtil.modelWithCheck(id)), typeof(Check)) - assertEquals(check.id, check.name, "Check name field matches ID field") - assertEquals(id, check.name, "Check name field matches supplied ID") - } - - /* Tests that Checks have an implicit name which matches the ID even when the ID is missing. */ - @Test - def void testCheckNameIDIsMissing() { - val check = util.getFirstInstanceOf(parser.parse(modelUtil.modelWithCheck("")), typeof(Check)) - assertNull(check.name, "Check name is null") - } - - /* Tests that multi- and single-line comments are parsed in a model. */ - @Test - def void testCommentsInModelParse() { - val model = parser.parse(modelUtil.modelWithComments) - assertFalse((model.eResource as XtextResource).parseResult.hasSyntaxErrors, - "Syntax errors not expected but occurred") - } - - /* Tests that t.message is allowed, despite "message" being a keyword. */ - @Test - def void testKeywordAsIdentifier() { - val model = parser.parse( - modelUtil.modelWithContext + - "try { issue bind (\"mp0\", \"mp1\"); } catch (java.lang.Throwable t) { issue bind (t.message, \"foo\"); }" + - "}}}}"); - assertFalse((model.eResource as XtextResource).parseResult.hasSyntaxErrors, - "Syntax errors not expected but occurred") - } -} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.java new file mode 100644 index 0000000000..e11cba04f4 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.core.test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.InputStream; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import com.avaloq.tools.ddk.check.CheckUiInjectorProvider; +import com.google.common.collect.Lists; + + +@InjectWith(CheckUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class ProjectBasedTests extends AbstractCheckTestCase { + + private boolean initialized; + + public List getRequiredSourceFileNames() { + // No file extension to prevent code generation in development workbench. Will get .check extension when copied into + // runtime workspace the test runs in. + return Lists.newArrayList("bugdsl27/BugDsl27", "bugdsl281/BugDsl281"); + } + + @Override + protected String getFullFileName(final String fileName) { + // Make sure it is put into the src folder even if the name contains a dash! + return getSourceFolderPath() + getFileName(fileName); + } + + public void initializeTestProject() { + if (!initialized) { + initialized = true; + // sources are copied into the project and then built by the Xtext builder + addSourcesToWorkspace(ProjectBasedTests.class, getRequiredSourceFileNames()); + + // wait for build to finish, otherwise included catalog may not be resolvable + IResourcesSetupUtil.waitForBuild(); + } + } + + private boolean isEmpty(final IFile file) throws CoreException { + final InputStream s = file.getContents(); + try { + return s.read() < 0; + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + try { + s.close(); + } catch (Exception e) { + // ignore + } + } + } + + private void assertGeneratedJavaCodeHasNoErrorMarkers(final String fileName) throws CoreException { + final IProject project = getOrCreatePluginProject(); + final IFile file = project.getFile(fileName); + // enumerateContents(project); + assertTrue(file.exists(), "Generated file should exist"); + assertFalse(isEmpty(file), "Generated file should not be empty"); + assertTrue(file.findMaxProblemSeverity(null, true, IResource.DEPTH_INFINITE) < IMarker.SEVERITY_ERROR, "Generated file should not have errors"); + } + + @Test + public void testBugDsl27CanCompile() throws CoreException { + initializeTestProject(); + + assertGeneratedJavaCodeHasNoErrorMarkers("src-gen/bugdsl27/BugDsl27CheckImpl.java"); + } + + @Test + public void testBugDsl281EmptyList() throws CoreException { + initializeTestProject(); + + assertGeneratedJavaCodeHasNoErrorMarkers("src-gen/bugdsl281/BugDsl281PreferenceInitializer.java"); + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.xtend deleted file mode 100644 index 540d405e8c..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.xtend +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.core.test - -import com.avaloq.tools.ddk.check.CheckUiInjectorProvider -import com.google.common.collect.Lists -import java.io.InputStream -import java.util.List -import org.eclipse.core.resources.IFile -import org.eclipse.core.resources.IMarker -import org.eclipse.core.resources.IProject -import org.eclipse.core.resources.IResource -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.* - -@InjectWith(typeof(CheckUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class ProjectBasedTests extends AbstractCheckTestCase { - - boolean initialized; - - def List getRequiredSourceFileNames() { - // No file extension to prevent code generation in development workbench. Will get .check extension when copied into - // runtime workspace the test runs in. - Lists::newArrayList("bugdsl27/BugDsl27", "bugdsl281/BugDsl281") - } - - override getFullFileName(String fileName) { - // Make sure it is put into the src folder even if the name contains a dash! - return getSourceFolderPath() + getFileName(fileName); - } - - def void initializeTestProject() { - if (!initialized) { - initialized = true; - // sources are copied into the project and then built by the Xtext builder - addSourcesToWorkspace(typeof(ProjectBasedTests), requiredSourceFileNames) - - // wait for build to finish, otherwise included catalog may not be resolvable - IResourcesSetupUtil.waitForBuild - } - } - - private def boolean isEmpty(IFile file) { - val InputStream s = file.getContents(); - try { - return s.read < 0; - } finally { - s.close; - } - } - - def private void assertGeneratedJavaCodeHasNoErrorMarkers(String fileName) { - val IProject project = getOrCreatePluginProject() - val IFile file = project.getFile(fileName); - // enumerateContents(project); - assertTrue( file.exists,"Generated file should exist") - assertFalse( isEmpty(file),"Generated file should not be empty") - assertTrue( file.findMaxProblemSeverity(null, true, IResource::DEPTH_INFINITE) < IMarker::SEVERITY_ERROR,"Generated file should not have errors") - - } - - @Test - def void testBugDsl27CanCompile() { - initializeTestProject(); - - assertGeneratedJavaCodeHasNoErrorMarkers("src-gen/bugdsl27/BugDsl27CheckImpl.java"); - } - - @Test - def void testBugDsl281EmptyList() { - initializeTestProject(); - - assertGeneratedJavaCodeHasNoErrorMarkers("src-gen/bugdsl281/BugDsl281PreferenceInitializer.java"); - } -} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java new file mode 100644 index 0000000000..c7b4cc7e35 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * Contributors: + * Avaloq Group AG - initial API and implementation + */ +package com.avaloq.tools.ddk.check.validation; + +import com.avaloq.tools.ddk.check.CheckUiInjectorProvider; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.google.inject.Inject; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.eclipse.xtext.xtype.XtypePackage; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + + +@InjectWith(CheckUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class CheckApiAccessValidationsTest { + + @Inject + private ParseHelper parser; + + @Inject + private ValidationTestHelper helper; + + private CheckCatalog getTestSource(final String importText) throws Exception { + return parser.parse( + "package com.avaloq.example.stuff.checks\n" + + "import " + importText + "\n" + + "catalog CommonChecks\n" + + "for grammar com.avaloq.tools.ddk.check.TestLanguage\n" + + "{\n" + + "}"); + } + + @Test + public void testNonApiAccessDisallowed() throws Exception { + final CheckCatalog model = getTestSource("com.avaloq.tools.ddk.check.check.impl.CheckImpl"); //Not OK - impl not defined as API. + helper.assertWarning(model, XtypePackage.Literals.XIMPORT_DECLARATION, IssueCodes.NON_API_IMPORTED); + } + + @Test + public void testDefinedApiAccessable() throws Exception { + final CheckCatalog model = getTestSource("com.avaloq.tools.ddk.check.check.Check"); //OK! There's an API spec in this plugin's plugin.xml + helper.assertNoIssue(model, XtypePackage.Literals.XIMPORT_DECLARATION, IssueCodes.NON_API_IMPORTED); + } + + @Test + public void testNonAvaloqTypeAccessable() throws Exception { + final CheckCatalog model = getTestSource("java.util.HashMap"); //OK! Not in com.avaloq.* + helper.assertNoIssue(model, XtypePackage.Literals.XIMPORT_DECLARATION, IssueCodes.NON_API_IMPORTED); + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.xtend deleted file mode 100644 index 0c9f980703..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.xtend +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * Contributors: - * Avaloq Group AG - initial API and implementation - */ -package com.avaloq.tools.ddk.check.validation - -import org.eclipse.xtext.testing.InjectWith -import com.avaloq.tools.ddk.check.CheckUiInjectorProvider -import com.google.inject.Inject -import org.eclipse.xtext.testing.util.ParseHelper -import com.avaloq.tools.ddk.check.check.CheckCatalog -import org.eclipse.xtext.testing.validation.ValidationTestHelper -import org.eclipse.xtext.xtype.XtypePackage -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test - -@InjectWith(typeof(CheckUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class CheckApiAccessValidationsTest{ - - @Inject - ParseHelper parser - - @Inject - ValidationTestHelper helper - - def private getTestSource(String importText){ - return parser.parse(''' - package com.avaloq.example.stuff.checks - import «importText» - catalog CommonChecks - for grammar com.avaloq.tools.ddk.check.TestLanguage - { - }''' - ) - } - - @Test - def void testNonApiAccessDisallowed() { - val model = getTestSource("com.avaloq.tools.ddk.check.check.impl.CheckImpl") //Not OK - impl not defined as API. - helper.assertWarning(model, XtypePackage.Literals.XIMPORT_DECLARATION, IssueCodes.NON_API_IMPORTED) - } - - @Test - def void testDefinedApiAccessable() { - val model = getTestSource("com.avaloq.tools.ddk.check.check.Check") //OK! There's an API spec in this plugin's plugin.xml - helper.assertNoIssue(model, XtypePackage.Literals.XIMPORT_DECLARATION, IssueCodes.NON_API_IMPORTED) - } - - @Test - def void testNonAvaloqTypeAccessable() { - val model = getTestSource("java.util.HashMap") //OK! Not in com.avaloq.* - helper.assertNoIssue(model, XtypePackage.Literals.XIMPORT_DECLARATION, IssueCodes.NON_API_IMPORTED) - } -} diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckExecutionEnvironmentProjectTest.java b/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckExecutionEnvironmentProjectTest.java new file mode 100644 index 0000000000..dee5d01670 --- /dev/null +++ b/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckExecutionEnvironmentProjectTest.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.test.runtime; + +import com.avaloq.tools.ddk.check.TestLanguageUiInjectorProvider; +import com.avaloq.tools.ddk.check.core.test.AbstractCheckTestCase; +import com.avaloq.tools.ddk.check.testLanguage.Model; +import com.avaloq.tools.ddk.check.testLanguage.TestLanguagePackage; +import com.avaloq.tools.ddk.check.ui.internal.TestLanguageActivator; +import com.avaloq.tools.ddk.check.validation.ExecutionEnvironmentIssueCodes; +import com.avaloq.tools.ddk.check.validation.LibraryChecksIssueCodes; +import com.google.inject.Inject; +import com.google.inject.Injector; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + + +@InjectWith(TestLanguageUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class CheckExecutionEnvironmentProjectTest extends AbstractCheckTestCase { + + @Inject + private ValidationTestHelper helper; + + @Inject + private ParseHelper parser; + + @Override + protected Injector getInjector() { + return TestLanguageActivator.getInstance().getInjector(TestLanguageActivator.COM_AVALOQ_TOOLS_DDK_CHECK_TESTLANGUAGE); + } + + @Test + public void testFranz() throws Exception { + final Model model = parser.parse("Hello Franz!"); + helper.assertError(model, TestLanguagePackage.Literals.GREETING, ExecutionEnvironmentIssueCodes.FRANZNAME); + } + + @Test + public void testFrans() throws Exception { + final Model model = parser.parse("Hello Frans!"); + helper.assertNoError(model, ExecutionEnvironmentIssueCodes.FRANZNAME); + helper.assertNoError(model, ExecutionEnvironmentIssueCodes.NAMELENGTH); + } + + @Test + public void testGreetingNameIssue() throws Exception { + final Model model = parser.parse("Hello GreetingNameTooLong!"); + helper.assertError(model, TestLanguagePackage.Literals.GREETING, ExecutionEnvironmentIssueCodes.NAMELENGTH); + } + + /* + * Tests that both validations emerging from the Java validator as well as such emerging from the check based + * validator appear. (Fixed by CheckCompositeEValidator). + */ + @Test + //@BugTest("AIG-709") // this plugin should be ACF independent + public void testBugAig709() throws Exception { + final Model model = parser.parse("Hello GreetingNameTooLong!"); + helper.assertError(model, TestLanguagePackage.Literals.GREETING, ExecutionEnvironmentIssueCodes.NAMELENGTH); + helper.assertWarning(model, TestLanguagePackage.Literals.GREETING, IssueCodesConstants.GREETING_NAME_PREFIX); + } + + @Test + public void testLibraryInjection() throws Exception { + final Model model = parser.parse("Hello Peter!"); + helper.assertWarning(model, TestLanguagePackage.Literals.GREETING, LibraryChecksIssueCodes.CHECK_CATALOG_IS_ACTIVE); + helper.assertNoError(model, LibraryChecksIssueCodes.CACHE_DOESNT_WORK); + helper.assertNoError(model, LibraryChecksIssueCodes.CACHE_INJECTION_FAILED); + helper.assertNoError(model, LibraryChecksIssueCodes.FORMAL_PARAMETERS); + } +} diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckExecutionEnvironmentProjectTest.xtend b/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckExecutionEnvironmentProjectTest.xtend deleted file mode 100644 index bd0bff2858..0000000000 --- a/com.avaloq.tools.ddk.check.test.runtime.tests/src/com/avaloq/tools/ddk/check/test/runtime/CheckExecutionEnvironmentProjectTest.xtend +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.test.runtime - -import com.avaloq.tools.ddk.check.TestLanguageUiInjectorProvider -import com.avaloq.tools.ddk.check.core.test.AbstractCheckTestCase -import com.avaloq.tools.ddk.check.testLanguage.Model -import com.avaloq.tools.ddk.check.testLanguage.TestLanguagePackage -import com.avaloq.tools.ddk.check.ui.internal.TestLanguageActivator -import com.avaloq.tools.ddk.check.validation.ExecutionEnvironmentIssueCodes -import com.avaloq.tools.ddk.check.validation.LibraryChecksIssueCodes -import com.google.inject.Inject -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.util.ParseHelper -import org.eclipse.xtext.testing.validation.ValidationTestHelper -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test - - -@InjectWith(typeof(TestLanguageUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class CheckExecutionEnvironmentProjectTest extends AbstractCheckTestCase { - - @Inject - ValidationTestHelper helper - - @Inject - ParseHelper parser - - override getInjector() { - TestLanguageActivator::instance.getInjector(TestLanguageActivator::COM_AVALOQ_TOOLS_DDK_CHECK_TESTLANGUAGE) - } - - @Test - def void testFranz() { - val model = parser.parse("Hello Franz!") - helper.assertError(model, TestLanguagePackage.Literals::GREETING, ExecutionEnvironmentIssueCodes::FRANZNAME) - } - - @Test - def void testFrans() { - val model = parser.parse("Hello Frans!") - helper.assertNoError(model, ExecutionEnvironmentIssueCodes::FRANZNAME) - helper.assertNoError(model, ExecutionEnvironmentIssueCodes::NAMELENGTH) - } - - @Test - def void testGreetingNameIssue() { - val model = parser.parse("Hello GreetingNameTooLong!") - helper.assertError(model, TestLanguagePackage.Literals::GREETING, ExecutionEnvironmentIssueCodes::NAMELENGTH) - } - - /* - * Tests that both validations emerging from the Java validator as well as such emerging from the check based - * validator appear. (Fixed by CheckCompositeEValidator). - */ - @Test - //@BugTest("AIG-709") // this plugin should be ACF independent - def void testBugAig709() { - val model = parser.parse("Hello GreetingNameTooLong!") - helper.assertError(model, TestLanguagePackage.Literals::GREETING, ExecutionEnvironmentIssueCodes::NAMELENGTH) - helper.assertWarning(model, TestLanguagePackage.Literals::GREETING, IssueCodesConstants::GREETING_NAME_PREFIX) - } - - @Test - def void testLibraryInjection() { - val model = parser.parse("Hello Peter!"); - helper.assertWarning(model, TestLanguagePackage.Literals::GREETING, LibraryChecksIssueCodes::CHECK_CATALOG_IS_ACTIVE); - helper.assertNoError(model, LibraryChecksIssueCodes::CACHE_DOESNT_WORK); - helper.assertNoError(model, LibraryChecksIssueCodes::CACHE_INJECTION_FAILED); - helper.assertNoError(model, LibraryChecksIssueCodes::FORMAL_PARAMETERS); - } -} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java new file mode 100644 index 0000000000..7090d26552 --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.checkcfg.contentassist; + +import com.avaloq.tools.ddk.checkcfg.CheckCfgUiInjectorProvider; +import com.avaloq.tools.ddk.checkcfg.util.CheckCfgTestUtil; +import com.avaloq.tools.ddk.test.checkcfg.TestPropertySpecificationWithExpectedValues; +import com.avaloq.tools.ddk.test.checkcfg.TestPropertySpecificationWithOutExpectedValues; +import com.avaloq.tools.ddk.test.core.jupiter.BugTest; +import com.avaloq.tools.ddk.test.core.mock.ExtensionRegistryMock; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractAcfContentAssistTest; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextTestUtil; +import com.google.common.collect.Lists; +import java.util.List; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static com.avaloq.tools.ddk.checkcfg.CheckCfgConstants.PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE; +import static com.avaloq.tools.ddk.checkcfg.CheckCfgConstants.PROPERTY_EXTENSION_POINT; + +@ExtendWith(InjectionExtension.class) +@InjectWith(CheckCfgUiInjectorProvider.class) +public class CheckCfgContentAssistTest extends AbstractAcfContentAssistTest { + + @Override + protected AbstractXtextTestUtil getXtextTestUtil() { + return CheckCfgTestUtil.getInstance(); + } + + @Override + protected List getRequiredSourceFileNames() { + return Lists.newArrayListWithCapacity(0); + } + + @Override + protected void beforeAllTests() { + ExtensionRegistryMock.mockExecutableExtension(ExtensionRegistryMock.mockConfigurationElement(PROPERTY_EXTENSION_POINT), PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE, TestPropertySpecificationWithExpectedValues.INSTANCE); + ExtensionRegistryMock.mockExecutableExtension(ExtensionRegistryMock.mockConfigurationElement(PROPERTY_EXTENSION_POINT), PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE, TestPropertySpecificationWithOutExpectedValues.INSTANCE); + super.beforeAllTests(); + } + + @Override + protected void afterAllTests() { + super.afterAllTests(); + ExtensionRegistryMock.unMock(PROPERTY_EXTENSION_POINT); + } + + @Test + public void testConfiguredParameterProposals() { + final StringBuilder builder = new StringBuilder(); + builder.append("check configuration Test {\n"); + builder.append(" catalog TestChecks {\n"); + builder.append(" default Test (\n"); + builder.append(" ").append(TestPropertySpecificationWithExpectedValues.INSTANCE.getName()).append(" = ").append(expected(TestPropertySpecificationWithExpectedValues.INSTANCE.getExpectedValues())).append("\"banana\"\n"); + builder.append(" )\n"); + builder.append(" }\n"); + builder.append("}\n"); + assertKernelSourceProposals("ConfiguredParameterProposals.checkcfg", builder); + } + + @BugTest(value = "DSL-1811", unresolved = true) + public void testNoTypeMismatchedParameterValueProposals() { + final StringBuilder builder = new StringBuilder(); + builder.append("check configuration Test {\n"); + builder.append(" catalog TestChecks {\n"); + builder.append(" default Test (\n"); + builder.append(" ").append(TestPropertySpecificationWithExpectedValues.INSTANCE.getName()).append(" = ").append(expectedExactly(TestPropertySpecificationWithExpectedValues.INSTANCE.getExpectedValues())).append("\"banana\"\n"); + builder.append(" )\n"); + builder.append(" }\n"); + builder.append("}\n"); + assertKernelSourceProposals("NoTypeMismatchedParameterValueProposals.checkcfg", builder); + } +} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.xtend b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.xtend deleted file mode 100644 index c94d565e21..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.xtend +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.checkcfg.contentassist - -import com.avaloq.tools.ddk.test.checkcfg.TestPropertySpecificationWithExpectedValues -import com.avaloq.tools.ddk.test.checkcfg.TestPropertySpecificationWithOutExpectedValues -import com.google.common.collect.Lists - -import static com.avaloq.tools.ddk.checkcfg.CheckCfgConstants.PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE -import static com.avaloq.tools.ddk.checkcfg.CheckCfgConstants.PROPERTY_EXTENSION_POINT - -import static extension com.avaloq.tools.ddk.test.core.mock.ExtensionRegistryMock.mockConfigurationElement -import static extension com.avaloq.tools.ddk.test.core.mock.ExtensionRegistryMock.mockExecutableExtension -import static extension com.avaloq.tools.ddk.test.core.mock.ExtensionRegistryMock.unMock -import com.avaloq.tools.ddk.test.core.jupiter.BugTest -import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractAcfContentAssistTest -import org.junit.jupiter.api.Test -import com.avaloq.tools.ddk.checkcfg.util.CheckCfgTestUtil -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import com.avaloq.tools.ddk.checkcfg.CheckCfgUiInjectorProvider -import org.eclipse.xtext.testing.InjectWith - -@ExtendWith(InjectionExtension) -@InjectWith(CheckCfgUiInjectorProvider) -class CheckCfgContentAssistTest extends AbstractAcfContentAssistTest { - - override protected getXtextTestUtil() { - return CheckCfgTestUtil.instance - } - - override protected getRequiredSourceFileNames() { - Lists.newArrayListWithCapacity(0) - } - - override protected beforeAllTests() { - PROPERTY_EXTENSION_POINT.mockConfigurationElement.mockExecutableExtension(PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE, TestPropertySpecificationWithExpectedValues.INSTANCE) - PROPERTY_EXTENSION_POINT.mockConfigurationElement.mockExecutableExtension(PROPERTY_EXECUTABLE_EXTENSION_ATTRIBUTE, TestPropertySpecificationWithOutExpectedValues.INSTANCE) - super.beforeAllTests() - } - - override protected afterAllTests() { - super.afterAllTests() - PROPERTY_EXTENSION_POINT.unMock - } - - @Test - def testConfiguredParameterProposals() { - assertKernelSourceProposals("ConfiguredParameterProposals.checkcfg", ''' - check configuration Test { - catalog TestChecks { - default Test ( - «TestPropertySpecificationWithExpectedValues.INSTANCE.name» = «expected(TestPropertySpecificationWithExpectedValues.INSTANCE.expectedValues)»"banana" - ) - } - } - ''') - } - - @BugTest(value="DSL-1811", unresolved=true) - def testNoTypeMismatchedParameterValueProposals() { - assertKernelSourceProposals("NoTypeMismatchedParameterValueProposals.checkcfg", ''' - check configuration Test { - catalog TestChecks { - default Test ( - «TestPropertySpecificationWithExpectedValues.INSTANCE.name» = «expectedExactly(TestPropertySpecificationWithExpectedValues.INSTANCE.expectedValues)»"banana" - ) - } - } - ''') - } - - - -} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java new file mode 100644 index 0000000000..7b9c59886a --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.checkcfg.scoping; + +import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckcfgPackage; +import com.avaloq.tools.ddk.checkcfg.util.CheckCfgTestUtil; +import com.avaloq.tools.ddk.test.core.jupiter.BugTest; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractScopingTest; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextTestUtil; +import java.util.List; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.scoping.IScopeProvider; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +public final class CheckCfgScopeProviderTest extends AbstractScopingTest { + + private final IScopeProvider scopeProvider = getScopeProvider(); + + /** {@inheritDoc} */ + @Override + protected AbstractXtextTestUtil getXtextTestUtil() { + return CheckCfgTestUtil.getInstance(); + } + + /** {@inheritDoc} */ + @Override + protected void registerRequiredSources() { + } + + /** + * Regression test for DSL-1498 Incorrect Catalog Name inserted by Content Assist + *

+ * All catalogs supplied to Context Assist should be in the correct fully-qualified package. + *

+ */ + @BugTest(value = "DSL-1498") + public void testCatalogsAreInCorrectPackage() throws Exception { + + // ARRANGE + + final List EXP_PACKAGE_NAME_PREFIX = List.of("com", "avaloq", "tools", "ddk"); + + // Define test data + final int CURSOR_POS = getTag(); + final StringBuilder sourceBuilder = new StringBuilder(); + sourceBuilder.append("check configuration testCheckCfg {\n"); + sourceBuilder.append(" ").append(mark(CURSOR_POS)).append("\n"); + sourceBuilder.append("}\n"); + final String SOURCE_CONTENT = sourceBuilder.toString(); + + // Register a check configuration source, and get a context model + registerModel(getTestSourceFileName(), SOURCE_CONTENT); + final EObject context = getMarkerTagsInfo().getModel(CURSOR_POS); + if (null == context) { + throw new NullPointerException("Got null context model"); + } + + // ACT + + // Get catalogs + final Iterable elements = scopeProvider.getScope(context, CheckcfgPackage.Literals.CONFIGURED_CATALOG__CATALOG).getAllElements(); + if (!elements.iterator().hasNext()) { + throw new Exception("Scope has no elements"); + } + + // ASSERT + + elements.forEach((IEObjectDescription element) -> { + // Check catalog has the correct fully-qualified package name + final List actualName = element.getName().getSegments(); + final List actualPackageName = actualName.subList(0, EXP_PACKAGE_NAME_PREFIX.size()); + assertArrayEquals(EXP_PACKAGE_NAME_PREFIX.toArray(), actualPackageName.toArray(), "Catalog must have the correct fully-qualified package name"); + }); + } +} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.xtend b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.xtend deleted file mode 100644 index c4a5c076b3..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.xtend +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.checkcfg.scoping - -import com.avaloq.tools.ddk.test.core.jupiter.BugTest -import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckcfgPackage -import com.avaloq.tools.ddk.checkcfg.util.CheckCfgTestUtil -import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractScopingTest -import static org.junit.jupiter.api.Assertions.assertArrayEquals - -final class CheckCfgScopeProviderTest extends AbstractScopingTest { - - val scopeProvider = getScopeProvider(); - - /** {@inheritDoc} */ - override protected getXtextTestUtil() { - return CheckCfgTestUtil.getInstance; - } - - /** {@inheritDoc} */ - override protected registerRequiredSources() {} - - /** - * Regression test for DSL-1498 Incorrect Catalog Name inserted by Content Assist - *

- * All catalogs supplied to Context Assist should be in the correct fully-qualified package. - *

- */ - @BugTest(value="DSL-1498") - def testCatalogsAreInCorrectPackage() { - - // ARRANGE - - val EXP_PACKAGE_NAME_PREFIX = #["com", "avaloq", "tools", "ddk"]; - - // Define test data - val CURSOR_POS = getTag; - val SOURCE_CONTENT = ''' - check configuration testCheckCfg { - «mark(CURSOR_POS)» - } - '''; - - // Register a check configuration source, and get a context model - registerModel(getTestSourceFileName, SOURCE_CONTENT); - val context = getMarkerTagsInfo().getModel(CURSOR_POS); - if (null === context) { - throw new NullPointerException("Got null context model"); - } - - // ACT - - // Get catalogs - val elements = scopeProvider.getScope(context, CheckcfgPackage.Literals.CONFIGURED_CATALOG__CATALOG).getAllElements; - if (elements.empty) { - throw new Exception("Scope has no elements"); - } - - // ASSERT - - elements.forEach[element | - // Check catalog has the correct fully-qualified package name - val actualName = element.name.segments; - val actualPackageName = actualName.take(EXP_PACKAGE_NAME_PREFIX.size); - assertArrayEquals(EXP_PACKAGE_NAME_PREFIX, actualPackageName, "Catalog must have the correct fully-qualified package name"); - ] - } -} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java new file mode 100644 index 0000000000..4f4e2f33f4 --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.checkcfg.syntax; + +import com.avaloq.tools.ddk.checkcfg.util.CheckCfgTestUtil; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractValidationTest; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextTestUtil; +import java.util.LinkedList; +import java.util.List; +import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class CheckCfgSyntaxTest extends AbstractValidationTest { + + @Override + protected AbstractXtextTestUtil getXtextTestUtil() { + return CheckCfgTestUtil.getInstance(); + } + + @Override + protected List getRequiredSourceFileNames() { + return new LinkedList(); + } + + @BeforeAll + public void setup() { + final StringBuilder builder = new StringBuilder(); + builder.append("package checkcfgtest\n"); + builder.append("\n"); + builder.append("import com.avaloq.tools.ddk.check.check.Check\n"); + builder.append("\n"); + builder.append("catalog CheckCfgTestChecks\n"); + builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); + builder.append(" /**\n"); + builder.append(" * Test Error Documentation\n"); + builder.append(" */\n"); + builder.append(" live error TestError \"Test Error\"\n"); + builder.append(" message \"Test Error message.\" {\n"); + builder.append(" for Check c {\n"); + builder.append(" issue on c#name;\n"); + builder.append(" }\n"); + builder.append(" }\n"); + builder.append("}\n"); + final String checkSource = builder.toString(); + addCustomerSourceToWorkspace("customer$sca_testchecks.check", checkSource); + IResourcesSetupUtil.waitForBuild(); + } + + @Test + public void testSyntax() { + final StringBuilder builder = new StringBuilder(); + builder.append("check configuration checkconfiguration {\n"); + builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); + builder.append(" default TestError\n"); + builder.append(" }\n"); + builder.append("}\n"); + final String checkcfgSource = builder.toString(); + validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource); + } + + @Test + public void testSyntaxConfiguredLanguage() { + final StringBuilder builder = new StringBuilder(); + builder.append("check configuration checkconfiguration\n"); + builder.append(" for com.avaloq.tools.ddk.^check.TestLanguage {\n"); + builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); + builder.append(" default TestError\n"); + builder.append(" }\n"); + builder.append(" }\n"); + final String checkcfgSource = builder.toString(); + validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource); + } + + @Test + public void testPropertiesOnAllLevels() { + final StringBuilder builder = new StringBuilder(); + builder.append("check configuration checkconfiguration\n"); + builder.append(" integrationRelevant = true\n"); + builder.append(" testBooleanList = #[true, false, false]\n"); + builder.append("\n"); + builder.append(" for com.avaloq.tools.ddk.^check.TestLanguage {\n"); + builder.append(" nameOverrides = #['altName1', 'altName2']\n"); + builder.append("\n"); + builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); + builder.append(" default TestError(testNumber = 3, testNumberList = #[1, 2, 3])\n"); + builder.append(" }\n"); + builder.append(" }\n"); + final String checkcfgSource = builder.toString(); + validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource); + } +} diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.xtend b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.xtend deleted file mode 100644 index 7349296e2c..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.xtend +++ /dev/null @@ -1,99 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.checkcfg.syntax - -import com.avaloq.tools.ddk.checkcfg.util.CheckCfgTestUtil -import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractValidationTest -import java.util.LinkedList -import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.BeforeAll - -class CheckCfgSyntaxTest extends AbstractValidationTest { - - override protected getXtextTestUtil() { - CheckCfgTestUtil.instance - } - - override protected getRequiredSourceFileNames() { - new LinkedList - } - - @BeforeAll - def void setup() { - val checkSource = ''' - package checkcfgtest - - import com.avaloq.tools.ddk.check.check.Check - - catalog CheckCfgTestChecks - for grammar com.avaloq.tools.ddk.check.Check { - /** - * Test Error Documentation - */ - live error TestError "Test Error" - message "Test Error message." { - for Check c { - issue on c#name; - } - } - } - ''' - addCustomerSourceToWorkspace("customer$sca_testchecks.check", checkSource) - IResourcesSetupUtil.waitForBuild - } - - - @Test - def void testSyntax() { - val checkcfgSource = ''' - check configuration checkconfiguration { - catalog checkcfgtest.CheckCfgTestChecks { - default TestError - } - } - ''' - validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource) - - } - - @Test - def void testSyntaxConfiguredLanguage() { - val checkcfgSource = ''' - check configuration checkconfiguration - for com.avaloq.tools.ddk.^check.TestLanguage { - catalog checkcfgtest.CheckCfgTestChecks { - default TestError - } - } - ''' - validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource) -} - - @Test - def void testPropertiesOnAllLevels() { - val checkcfgSource = ''' - check configuration checkconfiguration - integrationRelevant = true - testBooleanList = #[true, false, false] - - for com.avaloq.tools.ddk.^check.TestLanguage { - nameOverrides = #['altName1', 'altName2'] - - catalog checkcfgtest.CheckCfgTestChecks { - default TestError(testNumber = 3, testNumberList = #[1, 2, 3]) - } - } - ''' - validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource) - } -} diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java new file mode 100644 index 0000000000..109526bfb0 --- /dev/null +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.checkcfg.util; + +import com.avaloq.tools.ddk.check.check.FormalParameter; +import com.avaloq.tools.ddk.check.check.impl.CheckFactoryImpl; +import com.avaloq.tools.ddk.checkcfg.CheckCfgUtil; +import com.avaloq.tools.ddk.checkcfg.ICheckCfgPropertySpecification; +import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckConfiguration; +import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckcfgPackage; +import com.avaloq.tools.ddk.checkcfg.checkcfg.ConfigurableSection; +import com.avaloq.tools.ddk.checkcfg.checkcfg.ConfiguredParameter; +import com.avaloq.tools.ddk.xtext.util.ParseTreeUtil; +import com.google.inject.Inject; +import java.util.Collection; +import java.util.List; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.common.types.JvmTypeReference; +import org.eclipse.xtext.resource.IResourceServiceProvider; +import org.eclipse.xtext.xbase.XBooleanLiteral; +import org.eclipse.xtext.xbase.XExpression; +import org.eclipse.xtext.xbase.XListLiteral; +import org.eclipse.xtext.xbase.XNumberLiteral; +import org.eclipse.xtext.xbase.XStringLiteral; +import org.eclipse.xtext.xbase.jvmmodel.JvmTypeReferenceBuilder; + +public class PropertiesInferenceHelper { + + @Inject + private JvmTypeReferenceBuilder.Factory typeRefBuilderFactory; + + private static final String BOOLEAN = "boolean"; + private static final String STRING = "java.lang.String"; + private static final String NUMBER = "int"; + private static final String STRING_LIST = "List"; + private static final String NUMBER_LIST = "List"; + private static final String BOOLEAN_LIST = "List"; + + public EList getProperties(final CheckConfiguration checkConfiguration, final EList properties) { + final JvmTypeReferenceBuilder referenceBuilder = typeRefBuilderFactory.create(checkConfiguration.eResource().getResourceSet()); + + // get all ConfigurableSections + final List configurableSections = EcoreUtil2.getAllContentsOfType(checkConfiguration, ConfigurableSection.class); + // the CheckConfiguration itself is a configurable section + configurableSections.add(0, checkConfiguration); + + // infer properties for all sections + for (final ConfigurableSection section : configurableSections) { + final EList parameters = section.getParameterConfigurations(); + for (final ConfiguredParameter parameter : parameters) { + final FormalParameter formalParameter = inferFormalParameter(parameter, referenceBuilder); + if (formalParameter != null) { + properties.add(formalParameter); + } + } + } + + // add contributed properties + final Collection contributions = CheckCfgUtil.getAllPropertyContributions(); + for (final ICheckCfgPropertySpecification contribution : contributions) { + final FormalParameter formalParameter = inferFormalParameter(contribution, referenceBuilder); + if (formalParameter != null) { + properties.add(formalParameter); + } + } + return properties; + } + + public JvmTypeReference inferType(final ICheckCfgPropertySpecification contribution, final JvmTypeReferenceBuilder referenceBuilder) { + switch (contribution.getType()) { + case BOOLEAN: + return referenceBuilder.typeRef(BOOLEAN); + case NUMBER: + return referenceBuilder.typeRef(NUMBER); + case STRING: + return referenceBuilder.typeRef(STRING); + case NUMBERS: + return referenceBuilder.typeRef(NUMBER_LIST); + case STRINGS: + return referenceBuilder.typeRef(STRING_LIST); + case BOOLEANS: + return referenceBuilder.typeRef(BOOLEAN_LIST); + default: + return null; + } + } + + public JvmTypeReference inferListType(final XListLiteral newValue, final JvmTypeReferenceBuilder referenceBuilder) { + if (newValue.getElements().size() < 1) { + return null; + } + final XExpression firstElement = newValue.getElements().get(0); + if (firstElement instanceof XBooleanLiteral) { + return referenceBuilder.typeRef(BOOLEAN_LIST); + } else if (firstElement instanceof XNumberLiteral) { + return referenceBuilder.typeRef(NUMBER_LIST); + } else if (firstElement instanceof XStringLiteral) { + return referenceBuilder.typeRef(STRING_LIST); + } else { + return null; + } + } + + public JvmTypeReference inferType(final ConfiguredParameter parameter, final JvmTypeReferenceBuilder referenceBuilder) { + final XExpression newValue = parameter.getNewValue(); + if (newValue instanceof XBooleanLiteral) { + return referenceBuilder.typeRef(BOOLEAN); + } else if (newValue instanceof XNumberLiteral) { + return referenceBuilder.typeRef(NUMBER); + } else if (newValue instanceof XStringLiteral) { + return referenceBuilder.typeRef(STRING); + } else if (newValue instanceof XListLiteral xListLiteral) { + return inferListType(xListLiteral, referenceBuilder); + } else { + return null; + } + } + + public FormalParameter inferFormalParameter(final ConfiguredParameter parameter, final JvmTypeReferenceBuilder referenceBuilder) { + if (parameter == null) { + return null; + } + return inferFormalParameter(ParseTreeUtil.getParsedString(parameter, CheckcfgPackage.Literals.CONFIGURED_PARAMETER__PARAMETER), + inferType(parameter, referenceBuilder)); + } + + public FormalParameter inferFormalParameter(final ICheckCfgPropertySpecification contribution, final JvmTypeReferenceBuilder referenceBuilder) { + if (contribution == null) { + return null; + } + return inferFormalParameter(contribution.getName(), inferType(contribution, referenceBuilder)); + } + + public FormalParameter inferFormalParameter(final String name, final JvmTypeReference type) { + if (type == null) { + return null; + } + final FormalParameter formalParameter = CheckFactoryImpl.eINSTANCE.createFormalParameter(); + formalParameter.setName(name); + formalParameter.setType(type); + return formalParameter; + } + + public static PropertiesInferenceHelper getHelper() { + return IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(URI.createURI("DUMMY.checkcfg")).get( + PropertiesInferenceHelper.class); + } + +} diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.xtend b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.xtend deleted file mode 100644 index ca58fb18a2..0000000000 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.xtend +++ /dev/null @@ -1,140 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.checkcfg.util - -import com.avaloq.tools.ddk.check.check.FormalParameter -import com.avaloq.tools.ddk.check.check.impl.CheckFactoryImpl -import com.avaloq.tools.ddk.checkcfg.CheckCfgUtil -import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckConfiguration -import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckcfgPackage -import com.avaloq.tools.ddk.checkcfg.checkcfg.ConfigurableSection -import com.avaloq.tools.ddk.checkcfg.checkcfg.ConfiguredParameter -import com.avaloq.tools.ddk.xtext.util.ParseTreeUtil -import com.google.inject.Inject -import org.eclipse.emf.common.util.EList -import org.eclipse.emf.common.util.URI -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.common.types.JvmTypeReference -import org.eclipse.xtext.resource.IResourceServiceProvider -import org.eclipse.xtext.xbase.XBooleanLiteral -import org.eclipse.xtext.xbase.XNumberLiteral -import org.eclipse.xtext.xbase.XStringLiteral -import org.eclipse.xtext.xbase.jvmmodel.JvmTypeReferenceBuilder -import com.avaloq.tools.ddk.checkcfg.ICheckCfgPropertySpecification -import org.eclipse.xtext.xbase.XListLiteral - -class PropertiesInferenceHelper { - @Inject JvmTypeReferenceBuilder.Factory typeRefBuilderFactory; - - static val BOOLEAN = "boolean" - static val STRING = "java.lang.String" - static val NUMBER = "int" - static val STRING_LIST = "List" - static val NUMBER_LIST = "List" - static val BOOLEAN_LIST = "List" - - def getProperties(CheckConfiguration checkConfiguration, EList properties) { - val referenceBuilder = typeRefBuilderFactory.create(checkConfiguration.eResource().resourceSet) - - // get all ConfigurableSections - val configurableSections = EcoreUtil2.getAllContentsOfType(checkConfiguration, typeof(ConfigurableSection)) - // the CheckConfiguration itself is a configurable section - configurableSections.add(0, checkConfiguration) - - // infer properties for all sections - for (section : configurableSections) { - val parameters = section.parameterConfigurations; - for (parameter : parameters) { - val formalParameter = parameter.inferFormalParameter(referenceBuilder) - if (formalParameter !== null) { - properties.add(formalParameter) - } - } - } - - // add contributed properties - val contributions = CheckCfgUtil.allPropertyContributions - for (contribution : contributions) { - val formalParameter = contribution.inferFormalParameter(referenceBuilder) - if (formalParameter !== null) { - properties.add(formalParameter) - } - } - properties - } - - def inferType(ICheckCfgPropertySpecification contribution, JvmTypeReferenceBuilder referenceBuilder) { - switch contribution.type { - case ICheckCfgPropertySpecification.PropertyType.BOOLEAN: referenceBuilder.typeRef(BOOLEAN) - case ICheckCfgPropertySpecification.PropertyType.NUMBER: referenceBuilder.typeRef(NUMBER) - case ICheckCfgPropertySpecification.PropertyType.STRING: referenceBuilder.typeRef(STRING) - case ICheckCfgPropertySpecification.PropertyType.NUMBERS: referenceBuilder.typeRef(NUMBER_LIST) - case ICheckCfgPropertySpecification.PropertyType.STRINGS: referenceBuilder.typeRef(STRING_LIST) - case ICheckCfgPropertySpecification.PropertyType.BOOLEANS: referenceBuilder.typeRef(BOOLEAN_LIST) - default: null - } - } - - def inferListType(XListLiteral newValue, JvmTypeReferenceBuilder referenceBuilder) { - if (newValue.elements.size < 1) { - return null - } - switch newValue.elements.get(0) { - XBooleanLiteral: referenceBuilder.typeRef(BOOLEAN_LIST) - XNumberLiteral: referenceBuilder.typeRef(NUMBER_LIST) - XStringLiteral: referenceBuilder.typeRef(STRING_LIST) - default: null - } - } - - def inferType(ConfiguredParameter parameter, JvmTypeReferenceBuilder referenceBuilder) { - val newValue = parameter.newValue - switch newValue { - XBooleanLiteral: referenceBuilder.typeRef(BOOLEAN) - XNumberLiteral: referenceBuilder.typeRef(NUMBER) - XStringLiteral: referenceBuilder.typeRef(STRING) - XListLiteral: inferListType(newValue, referenceBuilder) - default: null - } - } - - def inferFormalParameter(ConfiguredParameter parameter, JvmTypeReferenceBuilder referenceBuilder) { - if (parameter === null) { - return null - } - inferFormalParameter(ParseTreeUtil.getParsedString(parameter, CheckcfgPackage.Literals.CONFIGURED_PARAMETER__PARAMETER), - inferType(parameter, referenceBuilder)) - } - - def inferFormalParameter(ICheckCfgPropertySpecification contribution, JvmTypeReferenceBuilder referenceBuilder) { - if (contribution === null) { - return null - } - inferFormalParameter(contribution.name, inferType(contribution, referenceBuilder)) - } - - def inferFormalParameter(String name, JvmTypeReference type) { - if (type === null) { - return null - } - val formalParameter = CheckFactoryImpl.eINSTANCE.createFormalParameter(); - formalParameter.name = name - formalParameter.type = type - formalParameter - } - - def static getHelper() { - IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(URI.createURI("DUMMY.checkcfg")).get( - typeof(PropertiesInferenceHelper)); - } - -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckExecutionEnvironmentProjectTest.java b/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckExecutionEnvironmentProjectTest.java new file mode 100644 index 0000000000..9fd0ae2887 --- /dev/null +++ b/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckExecutionEnvironmentProjectTest.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.sample.helloworld.check; + +import com.avaloq.tools.ddk.check.core.test.AbstractCheckTestCase; +import com.avaloq.tools.ddk.sample.helloworld.helloWorld.HelloWorldPackage; +import com.avaloq.tools.ddk.sample.helloworld.helloWorld.Model; +import com.avaloq.tools.ddk.sample.helloworld.ui.HelloWorldUiInjectorProvider; +import com.avaloq.tools.ddk.sample.helloworld.ui.internal.HelloworldActivator; +import com.avaloq.tools.ddk.sample.helloworld.validation.ExecutionEnvironmentIssueCodes; +import com.avaloq.tools.ddk.sample.helloworld.validation.IssueCodes; +import com.avaloq.tools.ddk.sample.helloworld.validation.LibraryChecksIssueCodes; +import com.google.inject.Inject; +import com.google.inject.Injector; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + + +@InjectWith(HelloWorldUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class CheckExecutionEnvironmentProjectTest extends AbstractCheckTestCase { + + @Inject + private ValidationTestHelper helper; + + @Inject + private ParseHelper parser; + + @Override + protected Injector getInjector() { + return HelloworldActivator.getInstance().getInjector(HelloworldActivator.COM_AVALOQ_TOOLS_DDK_SAMPLE_HELLOWORLD_HELLOWORLD); + } + + @Test + public void testFranz() throws Exception { + final Model model = parser.parse("Hello Franz!"); + helper.assertError(model, HelloWorldPackage.Literals.GREETING, ExecutionEnvironmentIssueCodes.FRANZNAME); + } + + @Test + public void testFrans() throws Exception { + final Model model = parser.parse("Hello Frans!"); + helper.assertNoError(model, ExecutionEnvironmentIssueCodes.FRANZNAME); + helper.assertNoError(model, ExecutionEnvironmentIssueCodes.NAMELENGTH); + } + + @Test + public void testGreetingNameIssue() throws Exception { + final Model model = parser.parse("Hello GreetingNameTooLong!"); + helper.assertError(model, HelloWorldPackage.Literals.GREETING, ExecutionEnvironmentIssueCodes.NAMELENGTH); + } + + /* + * Tests that both validations emerging from the Java validator as well as such emerging from the check based + * validator appear. (Fixed by CheckCompositeEValidator). + */ + @Test + //@BugTest("AIG-709") // this plugin should be ACF independent + public void testBugAig709() throws Exception { + final Model model = parser.parse("Hello GreetingNameTooLong!"); + helper.assertError(model, HelloWorldPackage.Literals.GREETING, ExecutionEnvironmentIssueCodes.NAMELENGTH); + helper.assertWarning(model, HelloWorldPackage.Literals.GREETING, IssueCodes.GREETING_NAME_PREFIX); + } + + @Test + public void testLibraryInjection() throws Exception { + final Model model = parser.parse("Hello Peter!"); + helper.assertWarning(model, HelloWorldPackage.Literals.GREETING, LibraryChecksIssueCodes.CHECK_CATALOG_IS_ACTIVE); + helper.assertNoError(model, LibraryChecksIssueCodes.CACHE_DOESNT_WORK); + helper.assertNoError(model, LibraryChecksIssueCodes.CACHE_INJECTION_FAILED); + helper.assertNoError(model, LibraryChecksIssueCodes.FORMAL_PARAMETERS); + } +} diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckExecutionEnvironmentProjectTest.xtend b/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckExecutionEnvironmentProjectTest.xtend deleted file mode 100644 index e3df63d53d..0000000000 --- a/com.avaloq.tools.ddk.sample.helloworld.ui.test/src/com/avaloq/tools/ddk/sample/helloworld/check/CheckExecutionEnvironmentProjectTest.xtend +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.sample.helloworld.check - -import com.avaloq.tools.ddk.check.core.test.AbstractCheckTestCase -import com.google.inject.Inject -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.util.ParseHelper -import org.eclipse.xtext.testing.validation.ValidationTestHelper -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test - -import com.avaloq.tools.ddk.sample.helloworld.ui.internal.HelloworldActivator -import com.avaloq.tools.ddk.sample.helloworld.helloWorld.Model -import com.avaloq.tools.ddk.sample.helloworld.helloWorld.HelloWorldPackage -import com.avaloq.tools.ddk.sample.helloworld.validation.ExecutionEnvironmentIssueCodes -import com.avaloq.tools.ddk.sample.helloworld.validation.LibraryChecksIssueCodes -import com.avaloq.tools.ddk.sample.helloworld.validation.IssueCodes -import com.avaloq.tools.ddk.sample.helloworld.ui.HelloWorldUiInjectorProvider - -@InjectWith(HelloWorldUiInjectorProvider) -@ExtendWith(typeof(InjectionExtension)) -class CheckExecutionEnvironmentProjectTest extends AbstractCheckTestCase { - - @Inject - ValidationTestHelper helper - - @Inject - ParseHelper parser - - override getInjector() { - HelloworldActivator::instance.getInjector(HelloworldActivator::COM_AVALOQ_TOOLS_DDK_SAMPLE_HELLOWORLD_HELLOWORLD) - } - - @Test - def void testFranz() { - val model = parser.parse("Hello Franz!") - helper.assertError(model, HelloWorldPackage.Literals::GREETING, ExecutionEnvironmentIssueCodes::FRANZNAME) - } - - @Test - def void testFrans() { - val model = parser.parse("Hello Frans!") - helper.assertNoError(model, ExecutionEnvironmentIssueCodes::FRANZNAME) - helper.assertNoError(model, ExecutionEnvironmentIssueCodes::NAMELENGTH) - } - - @Test - def void testGreetingNameIssue() { - val model = parser.parse("Hello GreetingNameTooLong!") - helper.assertError(model, HelloWorldPackage.Literals::GREETING, ExecutionEnvironmentIssueCodes::NAMELENGTH) - } - - /* - * Tests that both validations emerging from the Java validator as well as such emerging from the check based - * validator appear. (Fixed by CheckCompositeEValidator). - */ - @Test - //@BugTest("AIG-709") // this plugin should be ACF independent - def void testBugAig709() { - val model = parser.parse("Hello GreetingNameTooLong!") - helper.assertError(model, HelloWorldPackage.Literals::GREETING, ExecutionEnvironmentIssueCodes::NAMELENGTH) - helper.assertWarning(model, HelloWorldPackage.Literals::GREETING, IssueCodes::GREETING_NAME_PREFIX) - } - - @Test - def void testLibraryInjection() { - val model = parser.parse("Hello Peter!"); - helper.assertWarning(model, HelloWorldPackage.Literals::GREETING, LibraryChecksIssueCodes::CHECK_CATALOG_IS_ACTIVE); - helper.assertNoError(model, LibraryChecksIssueCodes::CACHE_DOESNT_WORK); - helper.assertNoError(model, LibraryChecksIssueCodes::CACHE_INJECTION_FAILED); - helper.assertNoError(model, LibraryChecksIssueCodes::FORMAL_PARAMETERS); - } -} diff --git a/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.java b/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.java new file mode 100644 index 0000000000..093fb16267 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.export.generator; + +import com.avaloq.tools.ddk.xtext.export.ExportStandaloneSetup; +import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer; +import com.google.inject.Inject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.naming.IQualifiedNameProvider; +import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy; +import org.eclipse.xtext.resource.IFragmentProvider; +import org.eclipse.xtext.resource.IResourceDescription; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; + +public class ExportFragment2 extends AbstractXtextGeneratorFragment { + + @Inject + private XtextGeneratorNaming _xtextGeneratorNaming; + + private boolean hasExports = true; + + /** + * Class-wide logger. + */ + private static final Logger LOGGER = LogManager.getLogger(ExportFragment2.class); + + private final String DDK_XTEXT_RUNTIME_BUNDLE = "com.avaloq.tools.ddk.xtext"; + + public void setHasExports(boolean hasExports) { + this.hasExports = hasExports; + } + + @Override + public void generate() { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("executing generate for " + getClass().getName()); + } + final String namingPackage = _xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".naming"; + final String namingPrefix = namingPackage + "." + GrammarUtil.getSimpleName(getGrammar()); + final String resourcePackage = _xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".resource"; + final String resourcePrefix = resourcePackage + "." + GrammarUtil.getSimpleName(getGrammar()); + + if (hasExports) { + new GuiceModuleAccess.BindingFactory() + .addTypeToType(TypeReference.typeRef(IQualifiedNameProvider.class), new TypeReference(namingPrefix + "ExportedNamesProvider")) + .addTypeToType(TypeReference.typeRef(IFingerprintComputer.class), new TypeReference(resourcePrefix + "FingerprintComputer")) + .addTypeToType(TypeReference.typeRef(IDefaultResourceDescriptionStrategy.class), new TypeReference(resourcePrefix + "ResourceDescriptionStrategy")) + .addTypeToType(TypeReference.typeRef(IFragmentProvider.class), new TypeReference(resourcePrefix + "FragmentProvider")) + .addTypeToType(TypeReference.typeRef(IResourceDescription.Manager.class), new TypeReference(resourcePrefix + "ResourceDescriptionManager")) + .contributeTo(getLanguage().getRuntimeGenModule()); + } else { + new GuiceModuleAccess.BindingFactory() + .addTypeToType(TypeReference.typeRef(IResourceDescription.Manager.class), new TypeReference(resourcePrefix + "ResourceDescriptionManager")) + .contributeTo(getLanguage().getRuntimeGenModule()); + } + + if (getProjectConfig().getRuntime().getManifest() != null) { + getProjectConfig().getRuntime().getManifest().getRequiredBundles().add("org.eclipse.emf.ecore"); + getProjectConfig().getRuntime().getManifest().getRequiredBundles().add(DDK_XTEXT_RUNTIME_BUNDLE); + if (hasExports) { + getProjectConfig().getRuntime().getManifest().getExportedPackages().add(namingPackage); + } + + getProjectConfig().getRuntime().getManifest().getExportedPackages().add(resourcePackage); + } + if (getProjectConfig().getEclipsePlugin().getManifest() != null) { + getProjectConfig().getEclipsePlugin().getManifest().getRequiredBundles().add(DDK_XTEXT_RUNTIME_BUNDLE); + } + + ExportStandaloneSetup.doSetup(); + } +} diff --git a/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.xtend b/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.xtend deleted file mode 100644 index 574c429435..0000000000 --- a/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.xtend +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.ExportStandaloneSetup -import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer -import com.google.inject.Inject -import org.apache.logging.log4j.Logger -import org.apache.logging.log4j.LogManager; -import org.eclipse.xtext.naming.IQualifiedNameProvider -import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy -import org.eclipse.xtext.resource.IFragmentProvider -import org.eclipse.xtext.resource.IResourceDescription -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess -import org.eclipse.xtext.xtext.generator.model.TypeReference - -import static org.eclipse.xtext.GrammarUtil.* - -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* - -class ExportFragment2 extends AbstractXtextGeneratorFragment { - - @Inject extension XtextGeneratorNaming - var hasExports = true - /** - * Class-wide logger. - */ - static final Logger LOGGER = LogManager::getLogger(ExportFragment2) - - val DDK_XTEXT_RUNTIME_BUNDLE = "com.avaloq.tools.ddk.xtext" - - def setHasExports (boolean hasExports) { - this.hasExports = hasExports - } - - override void generate() { - if (LOGGER.isInfoEnabled()) { - LOGGER.info('''executing generate for «getClass().getName()»'''.toString) - } - val namingPackage = grammar.runtimeBasePackage + '.naming' - val namingPrefix = namingPackage + '.' + getSimpleName(grammar) - val resourcePackage = grammar.runtimeBasePackage + '.resource' - val resourcePrefix = resourcePackage + '.' + getSimpleName(grammar) - - if (hasExports) { - new GuiceModuleAccess.BindingFactory() - .addTypeToType(IQualifiedNameProvider.typeRef, new TypeReference(namingPrefix + "ExportedNamesProvider")) - .addTypeToType(IFingerprintComputer.typeRef, new TypeReference(resourcePrefix + "FingerprintComputer")) - .addTypeToType(IDefaultResourceDescriptionStrategy.typeRef, new TypeReference(resourcePrefix + "ResourceDescriptionStrategy")) - .addTypeToType(IFragmentProvider.typeRef, new TypeReference(resourcePrefix + "FragmentProvider")) - .addTypeToType(IResourceDescription.Manager.typeRef, new TypeReference(resourcePrefix + "ResourceDescriptionManager")) - .contributeTo(language.runtimeGenModule) - } - else { - new GuiceModuleAccess.BindingFactory() - .addTypeToType(IResourceDescription.Manager.typeRef, new TypeReference(resourcePrefix + "ResourceDescriptionManager")) - .contributeTo(language.runtimeGenModule) - } - - if (projectConfig.runtime.manifest !== null) { - projectConfig.runtime.manifest.requiredBundles += "org.eclipse.emf.ecore" - projectConfig.runtime.manifest.requiredBundles += DDK_XTEXT_RUNTIME_BUNDLE - if (hasExports) { - projectConfig.runtime.manifest.exportedPackages += namingPackage - } - - projectConfig.runtime.manifest.exportedPackages += resourcePackage - } - if (projectConfig.eclipsePlugin.manifest !== null) { - projectConfig.eclipsePlugin.manifest.requiredBundles += DDK_XTEXT_RUNTIME_BUNDLE - } - - ExportStandaloneSetup.doSetup() - } -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.scope.generator/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopingFragment2.java b/com.avaloq.tools.ddk.xtext.scope.generator/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopingFragment2.java new file mode 100644 index 0000000000..dfb794645f --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.scope.generator/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopingFragment2.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.scope.generator; + +import com.avaloq.tools.ddk.xtext.linking.LinkingService; +import com.avaloq.tools.ddk.xtext.scoping.IScopeNameProvider; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.linking.ILinkingService; +import org.eclipse.xtext.scoping.IScopeProvider; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; + +public class ScopingFragment2 extends AbstractXtextGeneratorFragment { + + private static final String RUNTIME_PLUGIN = "com.avaloq.tools.ddk.xtext"; + + @Override + public void generate() { + final String prefix = GrammarUtil.getNamespace(getGrammar()) + ".scoping." + GrammarUtil.getSimpleName(getGrammar()); + new GuiceModuleAccess.BindingFactory() + .addTypeToType(TypeReference.typeRef(IScopeProvider.class), new TypeReference(prefix + "ScopeProvider")) + .addTypeToType(TypeReference.typeRef(IScopeNameProvider.class), new TypeReference(prefix + "ScopeNameProvider")) + .addTypeToType(TypeReference.typeRef(ILinkingService.class), TypeReference.typeRef(LinkingService.class)) + .contributeTo(getLanguage().getRuntimeGenModule()); + + if (getProjectConfig().getRuntime().getManifest() != null) { + getProjectConfig().getRuntime().getManifest().getRequiredBundles().add("org.eclipse.emf.ecore"); + getProjectConfig().getRuntime().getManifest().getRequiredBundles().add(RUNTIME_PLUGIN); + getProjectConfig().getRuntime().getManifest().getExportedPackages().add(GrammarUtil.getNamespace(getGrammar()) + ".scoping"); + getProjectConfig().getRuntime().getManifest().getImportedPackages().add("org.apache.logging.log4j"); + } + + if (getProjectConfig().getEclipsePlugin().getManifest() != null) { + getProjectConfig().getRuntime().getManifest().getRequiredBundles().add(RUNTIME_PLUGIN); + } + } +} diff --git a/com.avaloq.tools.ddk.xtext.scope.generator/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopingFragment2.xtend b/com.avaloq.tools.ddk.xtext.scope.generator/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopingFragment2.xtend deleted file mode 100644 index 495c668d98..0000000000 --- a/com.avaloq.tools.ddk.xtext.scope.generator/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopingFragment2.xtend +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.scope.generator - -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess - -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* -import static extension org.eclipse.xtext.GrammarUtil.* -import org.eclipse.xtext.scoping.IScopeProvider -import com.avaloq.tools.ddk.xtext.scoping.IScopeNameProvider -import org.eclipse.xtext.linking.ILinkingService -import org.eclipse.xtext.xtext.generator.model.TypeReference -import com.avaloq.tools.ddk.xtext.linking.LinkingService - -class ScopingFragment2 extends AbstractXtextGeneratorFragment { - - static val RUNTIME_PLUGIN = "com.avaloq.tools.ddk.xtext" - - override generate() { - val prefix = grammar.namespace + ".scoping." + grammar.simpleName - new GuiceModuleAccess.BindingFactory() - .addTypeToType(IScopeProvider.typeRef, new TypeReference(prefix + "ScopeProvider")) - .addTypeToType(IScopeNameProvider.typeRef, new TypeReference(prefix + "ScopeNameProvider")) - .addTypeToType(ILinkingService.typeRef, LinkingService.typeRef) - .contributeTo(language.runtimeGenModule) - - if (projectConfig.runtime.manifest !== null) { - projectConfig.runtime.manifest.requiredBundles += "org.eclipse.emf.ecore" - projectConfig.runtime.manifest.requiredBundles += RUNTIME_PLUGIN - projectConfig.runtime.manifest.exportedPackages += grammar.namespace + ".scoping" - projectConfig.runtime.manifest.importedPackages += "org.apache.logging.log4j" - } - - if (projectConfig.eclipsePlugin.manifest !== null) { - projectConfig.runtime.manifest.requiredBundles += RUNTIME_PLUGIN - } - } -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/Tag.xtend b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/Tag.java similarity index 79% rename from com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/Tag.xtend rename to com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/Tag.java index c3d18b00c8..dcaf3c9c81 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/Tag.xtend +++ b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/Tag.java @@ -8,16 +8,16 @@ * Contributors: * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test +package com.avaloq.tools.ddk.xtext.test; -import org.eclipse.xtend.lib.macro.Active +import org.eclipse.xtend.lib.macro.Active; /** * Initializes global tags in linking tests. * The annotated field must be of integer type. * Usage example: @Tag int MEM_DOC */ -@Active(typeof(TagCompilationParticipant)) -annotation Tag { +@Active(TagCompilationParticipant.class) +public @interface Tag { } diff --git a/docs/xtend-migration.md b/docs/xtend-migration.md index 717f7b4f95..4f6a228d3e 100644 --- a/docs/xtend-migration.md +++ b/docs/xtend-migration.md @@ -12,10 +12,10 @@ | Metric | Value | |--------|-------| | Total Xtend source files | 94 | -| Already migrated (Batch 1–3) | 36 | -| Remaining | 58 | -| Total remaining lines | ~11,494 | -| Modules with remaining Xtend | 19 | +| Already migrated (Batch 1–4) | 49 | +| Remaining | 45 | +| Total remaining lines | ~10,404 | +| Modules with remaining Xtend | 14 | --- @@ -24,17 +24,17 @@ | Module | Files | Lines | Status | |--------|-------|-------|--------| | `check.core` | 8 | ~1,848 | **DONE** (Batch 1) | -| `check.core.test` | 8 | 1,508 | 3 done (Batch 2–3), 5 pending | +| `check.core.test` | 8 | 1,508 | 7 done (Batch 2–4), 1 pending | | `check.test.runtime` | 1 | 22 | **DONE** (Batch 2) | -| `check.test.runtime.tests` | 3 | 202 | 2 done (Batch 3), 1 pending | +| `check.test.runtime.tests` | 3 | 202 | **DONE** (Batch 3–4) | | `check.ui` | 2 | 113 | **DONE** (Batch 3) | | `check.ui.test` | 1 | 200 | Pending | -| `checkcfg.core` | 4 | 303 | 3 done (Batch 2–3), 1 pending | -| `checkcfg.core.test` | 7 | 460 | 4 done (Batch 2–3), 3 pending | -| `sample.helloworld.ui.test` | 3 | 203 | 2 done (Batch 3), 1 pending | +| `checkcfg.core` | 4 | 303 | **DONE** (Batch 2–4) | +| `checkcfg.core.test` | 7 | 460 | **DONE** (Batch 2–4) | +| `sample.helloworld.ui.test` | 3 | 203 | **DONE** (Batch 3–4) | | `xtext.check.generator` | 2 | 113 | **DONE** (Batch 2–3) | | `xtext.export` | 9 | 1,027 | Pending | -| `xtext.export.generator` | 1 | 86 | Pending | +| `xtext.export.generator` | 1 | 86 | **DONE** (Batch 4) | | `xtext.expression` | 5 | 679 | 2 done (Batch 2), 3 pending | | `xtext.format` | 6 | 1,623 | 1 done (Batch 2), 5 pending | | `xtext.format.generator` | 1 | 239 | Pending | @@ -44,8 +44,8 @@ | `xtext.generator` | 18 | 3,450 | 2 done (Batch 2), 16 pending | | `xtext.generator.test` | 1 | 200 | Pending | | `xtext.scope` | 4 | 852 | Pending | -| `xtext.scope.generator` | 1 | 47 | Pending | -| `xtext.test.core` | 2 | 221 | Pending | +| `xtext.scope.generator` | 1 | 47 | **DONE** (Batch 4) | +| `xtext.test.core` | 2 | 221 | 1 done (Batch 4), 1 pending | | `xtext.ui` | 1 | 82 | Pending | | `xtext.ui.test` | 1 | 265 | Pending | @@ -140,36 +140,36 @@ Simple test files, utilities, small production code. --- -## Batch 4 — Medium prod + test files 80–140 lines (~14 files) +## Batch 4 — Medium prod + test files 80–140 lines (13 files) — DONE ### `check.core.test` (4 files) -- [ ] `ProjectBasedTests.xtend` (88 lines) — Easy — extension, typeof, @Inject, override -- [ ] `IssueCodeValueTest.xtend` (104 lines) — Medium — templates, #{, switch -- [ ] `CheckApiAccessValidationsTest.xtend` (61 lines) — Easy — templates, @Inject -- [ ] `BasicModelTest.xtend` (116 lines) — Medium — extension, typeof, @Inject +- [x] `ProjectBasedTests.xtend` (88 lines) — Easy — extension, typeof, @Inject, override +- [x] `IssueCodeValueTest.xtend` (104 lines) — Medium — templates, #{, switch +- [x] `CheckApiAccessValidationsTest.xtend` (61 lines) — Easy — templates, @Inject +- [x] `BasicModelTest.xtend` (116 lines) — Medium — extension, typeof, @Inject ### `check.test.runtime.tests` (1 file) -- [ ] `CheckExecutionEnvironmentProjectTest.xtend` (82 lines) — Easy — extension, typeof, @Inject, override +- [x] `CheckExecutionEnvironmentProjectTest.xtend` (82 lines) — Easy — extension, typeof, @Inject, override ### `checkcfg.core` (1 file) -- [ ] `PropertiesInferenceHelper.xtend` (139 lines) — Medium — typeof, ===, !==, switch, create +- [x] `PropertiesInferenceHelper.xtend` (139 lines) — Medium — typeof, ===, !==, switch, create ### `checkcfg.core.test` (3 files) -- [ ] `CheckCfgContentAssistTest.xtend` (84 lines) — Easy — templates, extension, @Inject, override -- [ ] `CheckCfgScopeProviderTest.xtend` (77 lines) — Easy — templates, ===, #[, override -- [ ] `CheckCfgSyntaxTest.xtend` (99 lines) — Easy — templates, #[, override +- [x] `CheckCfgContentAssistTest.xtend` (84 lines) — Easy — templates, extension, @Inject, override +- [x] `CheckCfgScopeProviderTest.xtend` (77 lines) — Easy — templates, ===, #[, override +- [x] `CheckCfgSyntaxTest.xtend` (99 lines) — Easy — templates, #[, override ### `sample.helloworld.ui.test` (1 file) -- [ ] `CheckExecutionEnvironmentProjectTest.xtend` (83 lines) — Easy — extension, typeof, @Inject, override +- [x] `CheckExecutionEnvironmentProjectTest.xtend` (83 lines) — Easy — extension, typeof, @Inject, override ### `xtext.export.generator` (1 file) -- [ ] `ExportFragment2.xtend` (86 lines) — Medium — templates, extension, !==, @Inject, override +- [x] `ExportFragment2.xtend` (86 lines) — Medium — templates, extension, !==, @Inject, override ### `xtext.scope.generator` (1 file) -- [ ] `ScopingFragment2.xtend` (47 lines) — Trivial — extension, !==, override +- [x] `ScopingFragment2.xtend` (47 lines) — Trivial — extension, !==, override ### `xtext.test.core` (1 file) -- [ ] `Tag.xtend` (23 lines) — Trivial — typeof +- [x] `Tag.xtend` (23 lines) — Trivial — typeof --- From 0a4964206c766ad2f3e60aba8469d5fc73a70efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 28 Feb 2026 19:36:40 +0100 Subject: [PATCH 06/23] feat: migrate Batch 5 Xtend files to Java 21 (9 files) Migrate all 9 remaining Xtend files in the xtext.export module to idiomatic Java 21, completing the module. Includes template expressions converted to StringBuilder, dispatch methods with Java 21 pattern matching, and @Inject extension rewrites. Files: ResourceDescriptionConstantsGenerator, ExportFeatureExtensionGenerator, ResourceDescriptionManagerGenerator, ExportedNamesProviderGenerator, FragmentProviderGenerator, ExportGenerator, FingerprintComputerGenerator, ExportGeneratorX, ResourceDescriptionStrategyGenerator. Progress: 58/94 files migrated (62%). Co-Authored-By: Claude Opus 4.6 --- .../ExportFeatureExtensionGenerator.java | 94 +++++++ .../ExportFeatureExtensionGenerator.xtend | 77 ------ .../export/generator/ExportGenerator.java | 142 ++++++++++ .../export/generator/ExportGenerator.xtend | 136 ---------- .../export/generator/ExportGeneratorX.java | 219 ++++++++++++++++ .../export/generator/ExportGeneratorX.xtend | 187 ------------- .../ExportedNamesProviderGenerator.java | 133 ++++++++++ .../ExportedNamesProviderGenerator.xtend | 96 ------- .../FingerprintComputerGenerator.java | 180 +++++++++++++ .../FingerprintComputerGenerator.xtend | 134 ---------- .../generator/FragmentProviderGenerator.java | 113 ++++++++ .../generator/FragmentProviderGenerator.xtend | 94 ------- ...ResourceDescriptionConstantsGenerator.java | 83 ++++++ ...esourceDescriptionConstantsGenerator.xtend | 55 ---- .../ResourceDescriptionManagerGenerator.java | 83 ++++++ .../ResourceDescriptionManagerGenerator.xtend | 60 ----- .../ResourceDescriptionStrategyGenerator.java | 245 ++++++++++++++++++ ...ResourceDescriptionStrategyGenerator.xtend | 190 -------------- docs/xtend-migration.md | 30 +-- 19 files changed, 1307 insertions(+), 1044 deletions(-) create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.xtend diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.java new file mode 100644 index 0000000000..b5e4de83a1 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.export.generator; + +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.inject.Inject; + + +public class ExportFeatureExtensionGenerator { + + @Inject + private Naming naming; + + @Inject + private ExportGeneratorX exportGeneratorX; + + public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { + final StringBuilder sb = new StringBuilder(); + sb.append("package "); + sb.append(naming.toJavaPackage(exportGeneratorX.getExportFeatureExtension(it))); + sb.append(";\n"); + sb.append("\n"); + sb.append("import org.eclipse.xtext.naming.IQualifiedNameProvider;\n"); + sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractExportFeatureExtension;\n"); + sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractResourceDescriptionStrategy;\n"); + sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractSelectorFragmentProvider;\n"); + sb.append("import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer;\n"); + sb.append("import com.google.inject.Inject;\n"); + sb.append("\n"); + sb.append("import "); + sb.append(exportGeneratorX.getExportedNamesProvider(it)); + sb.append(";\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("public class "); + sb.append(naming.toSimpleName(exportGeneratorX.getExportFeatureExtension(it))); + sb.append(" extends AbstractExportFeatureExtension {\n"); + sb.append("\n"); + sb.append(" @Inject\n"); + sb.append(" private "); + sb.append(naming.toSimpleName(exportGeneratorX.getExportedNamesProvider(it))); + sb.append(" namesProvider;\n"); + sb.append("\n"); + sb.append(" @Inject\n"); + sb.append(" private "); + sb.append(naming.toSimpleName(exportGeneratorX.getFingerprintComputer(it))); + sb.append(" fingerprintComputer;\n"); + sb.append("\n"); + sb.append(" @Inject\n"); + sb.append(" private "); + sb.append(naming.toSimpleName(exportGeneratorX.getFragmentProvider(it))); + sb.append(" fragmentProvider;\n"); + sb.append("\n"); + sb.append(" @Inject\n"); + sb.append(" private "); + sb.append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionStrategy(it))); + sb.append(" resourceDescriptionStrategy;\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" protected IQualifiedNameProvider getNamesProvider() {\n"); + sb.append(" return namesProvider;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" protected IFingerprintComputer getFingerprintComputer() {\n"); + sb.append(" return fingerprintComputer;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" protected AbstractSelectorFragmentProvider getFragmentProvider() {\n"); + sb.append(" return fragmentProvider;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" protected AbstractResourceDescriptionStrategy getResourceDescriptionStrategy() {\n"); + sb.append(" return resourceDescriptionStrategy;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append("}\n"); + return sb; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.xtend deleted file mode 100644 index a357b85f3b..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.xtend +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.inject.Inject - -class ExportFeatureExtensionGenerator { - - @Inject extension Naming - @Inject extension ExportGeneratorX - - def generate(ExportModel it, CompilationContext ctx, extension GenModelUtilX genModelUtil) { - ''' - package «exportFeatureExtension.toJavaPackage»; - - import org.eclipse.xtext.naming.IQualifiedNameProvider; - import com.avaloq.tools.ddk.xtext.resource.AbstractExportFeatureExtension; - import com.avaloq.tools.ddk.xtext.resource.AbstractResourceDescriptionStrategy; - import com.avaloq.tools.ddk.xtext.resource.AbstractSelectorFragmentProvider; - import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer; - import com.google.inject.Inject; - - import «exportedNamesProvider»; - - - public class «exportFeatureExtension.toSimpleName» extends AbstractExportFeatureExtension { - - @Inject - private «exportedNamesProvider.toSimpleName» namesProvider; - - @Inject - private «fingerprintComputer.toSimpleName» fingerprintComputer; - - @Inject - private «fragmentProvider.toSimpleName» fragmentProvider; - - @Inject - private «resourceDescriptionStrategy.toSimpleName» resourceDescriptionStrategy; - - @Override - protected IQualifiedNameProvider getNamesProvider() { - return namesProvider; - } - - @Override - protected IFingerprintComputer getFingerprintComputer() { - return fingerprintComputer; - } - - @Override - protected AbstractSelectorFragmentProvider getFragmentProvider() { - return fragmentProvider; - } - - @Override - protected AbstractResourceDescriptionStrategy getResourceDescriptionStrategy() { - return resourceDescriptionStrategy; - } - - } - ''' - } - -} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java new file mode 100644 index 0000000000..c035776298 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java @@ -0,0 +1,142 @@ +/* + * generated by Xtext + */ +package com.avaloq.tools.ddk.xtext.export.generator; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.generator.IFileSystemAccess; +import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.eclipse.xtext.generator.IGenerator2; +import org.eclipse.xtext.generator.IGeneratorContext; + +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.inject.Inject; + + +/** + * Generates code from your model files on save. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +public class ExportGenerator implements IGenerator2 { + + @Inject + private ExportGeneratorSupport generatorSupport; + @Inject + private Naming naming; + @Inject + private ExportGeneratorX exportGeneratorX; + + @Inject + private GenModelUtilX genModelUtil; + + @Inject + private ExportedNamesProviderGenerator exportedNamesProviderGenerator; + @Inject + private ResourceDescriptionManagerGenerator resourceDescriptionManagerGenerator; + @Inject + private ResourceDescriptionStrategyGenerator resourceDescriptionStrategyGenerator; + @Inject + private ResourceDescriptionConstantsGenerator resourceDescriptionConstantsGenerator; + @Inject + private FingerprintComputerGenerator fingerprintComputerGenerator; + @Inject + private FragmentProviderGenerator fragmentProviderGenerator; + @Inject + private ExportFeatureExtensionGenerator exportFeatureExtensionGenerator; + + private CompilationContext compilationContext; + + @Override + public void doGenerate(final Resource input, final IFileSystemAccess2 fsa, final IGeneratorContext context) { + if (input == null || input.getContents().isEmpty() || !(input.getContents().get(0) instanceof ExportModel)) { + return; + } + final ExportModel model = (ExportModel) input.getContents().get(0); + genModelUtil.setResource(model.eResource()); + IProject project = null; + if (input.getURI().isPlatformResource()) { + final org.eclipse.core.resources.IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(input.getURI().toPlatformString(true)); + if (res != null) { + project = res.getProject(); + } + } + + generatorSupport.executeWithProjectResourceLoader(project, () -> { + compilationContext = generatorSupport.getCompilationContext(model, genModelUtil); + + generateExportedNamesProvider(model, fsa); + generateResourceDescriptionManager(model, fsa); + generateResourceDescriptionStrategy(model, fsa); + generateResourceDescriptionConstants(model, fsa); + generateFingerprintComputer(model, fsa); + generateFragmentProvider(model, fsa); + generateFeatureExtension(model, fsa); + }); + } + + public void generateExportedNamesProvider(final ExportModel model, final IFileSystemAccess fsa) { + final String fileName = naming.toFileName(exportGeneratorX.getExportedNamesProvider(model)); + fsa.generateFile(fileName, exportedNamesProviderGenerator.generate(model, compilationContext, genModelUtil)); + } + + public void generateResourceDescriptionManager(final ExportModel model, final IFileSystemAccess fsa) { + if (!model.isExtension()) { + final String fileName = naming.toFileName(exportGeneratorX.getResourceDescriptionManager(model)); + fsa.generateFile(fileName, ExportOutputConfigurationProvider.STUB_OUTPUT, resourceDescriptionManagerGenerator.generate(model, compilationContext, genModelUtil)); + } + } + + public void generateResourceDescriptionStrategy(final ExportModel model, final IFileSystemAccess fsa) { + final String fileName = naming.toFileName(exportGeneratorX.getResourceDescriptionStrategy(model)); + fsa.generateFile(fileName, resourceDescriptionStrategyGenerator.generate(model, compilationContext, genModelUtil)); + } + + public void generateResourceDescriptionConstants(final ExportModel model, final IFileSystemAccess fsa) { + final String fileName = naming.toFileName(exportGeneratorX.getResourceDescriptionConstants(model)); + fsa.generateFile(fileName, resourceDescriptionConstantsGenerator.generate(model, compilationContext, genModelUtil)); + } + + public void generateFingerprintComputer(final ExportModel model, final IFileSystemAccess fsa) { + final String fileName = naming.toFileName(exportGeneratorX.getFingerprintComputer(model)); + fsa.generateFile(fileName, fingerprintComputerGenerator.generate(model, compilationContext, genModelUtil)); + } + + public void generateFragmentProvider(final ExportModel model, final IFileSystemAccess fsa) { + final String fileName = naming.toFileName(exportGeneratorX.getFragmentProvider(model)); + if (model.getExports().stream().anyMatch(e -> e.isFingerprint() && e.getFragmentAttribute() != null) || model.isExtension()) { + fsa.generateFile(fileName, fragmentProviderGenerator.generate(model, compilationContext, genModelUtil)); + } else if (!model.getExports().isEmpty()) { + final StringBuilder sb = new StringBuilder(); + sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getFragmentProvider(model))).append(";\n"); + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.xtext.linking.ShortFragmentProvider;\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getFragmentProvider(model))).append(" extends ShortFragmentProvider {\n"); + sb.append("\n"); + sb.append("}\n"); + fsa.generateFile(fileName, sb); + } + } + + public void generateFeatureExtension(final ExportModel model, final IFileSystemAccess fsa) { + if (model.isExtension()) { + final String fileName = naming.toFileName(exportGeneratorX.getExportFeatureExtension(model)); + fsa.generateFile(fileName, exportFeatureExtensionGenerator.generate(model, compilationContext, genModelUtil)); + } + } + + @Override + public void afterGenerate(final Resource input, final IFileSystemAccess2 fsa, final IGeneratorContext context) { + } + + @Override + public void beforeGenerate(final Resource input, final IFileSystemAccess2 fsa, final IGeneratorContext context) { + } +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.xtend deleted file mode 100644 index 18a87369e2..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.xtend +++ /dev/null @@ -1,136 +0,0 @@ -/* - * generated by Xtext - */ -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.inject.Inject -import org.eclipse.core.resources.IProject -import org.eclipse.core.resources.ResourcesPlugin -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.IFileSystemAccess -import org.eclipse.xtext.generator.IGenerator2 -import org.eclipse.xtext.generator.IGeneratorContext -import org.eclipse.xtext.generator.IFileSystemAccess2 - -/** - * Generates code from your model files on save. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation - */ -class ExportGenerator implements IGenerator2 { - - @Inject - extension ExportGeneratorSupport generatorSupport - @Inject - extension Naming - @Inject - extension ExportGeneratorX - - @Inject - GenModelUtilX genModelUtil - - @Inject - ExportedNamesProviderGenerator exportedNamesProviderGenerator - @Inject - ResourceDescriptionManagerGenerator resourceDescriptionManagerGenerator - @Inject - ResourceDescriptionStrategyGenerator resourceDescriptionStrategyGenerator - @Inject - ResourceDescriptionConstantsGenerator resourceDescriptionConstantsGenerator - @Inject - FingerprintComputerGenerator fingerprintComputerGenerator - @Inject - FragmentProviderGenerator fragmentProviderGenerator - @Inject - ExportFeatureExtensionGenerator exportFeatureExtensionGenerator - - CompilationContext compilationContext - - override void doGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) { - if (input === null || input.contents.empty || !(input.contents.head instanceof ExportModel)) { - return - } - val model = input.contents.head as ExportModel - genModelUtil.resource = model.eResource - var IProject project = null - if (input.URI.isPlatformResource) { - val res = ResourcesPlugin.workspace.root.findMember(input.URI.toPlatformString(true)) - if (res !== null) { - project = res.project - } - } - - generatorSupport.executeWithProjectResourceLoader(project, [ - compilationContext = generatorSupport.getCompilationContext(model, genModelUtil) - - generateExportedNamesProvider(model, fsa) - generateResourceDescriptionManager(model, fsa) - generateResourceDescriptionStrategy(model, fsa) - generateResourceDescriptionConstants(model, fsa) - generateFingerprintComputer(model, fsa) - generateFragmentProvider(model, fsa) - generateFeatureExtension(model, fsa) - ]) - } - - def generateExportedNamesProvider(ExportModel model, IFileSystemAccess fsa) { - val fileName = model.exportedNamesProvider.toFileName - fsa.generateFile(fileName, exportedNamesProviderGenerator.generate(model, compilationContext, genModelUtil)) - } - - def generateResourceDescriptionManager(ExportModel model, IFileSystemAccess fsa) { - if(!model.extension){ - val fileName = model.resourceDescriptionManager.toFileName - fsa.generateFile(fileName, ExportOutputConfigurationProvider.STUB_OUTPUT, resourceDescriptionManagerGenerator.generate(model, compilationContext, genModelUtil)) - } - } - - def generateResourceDescriptionStrategy(ExportModel model, IFileSystemAccess fsa) { - val fileName = model.resourceDescriptionStrategy.toFileName - fsa.generateFile(fileName, resourceDescriptionStrategyGenerator.generate(model, compilationContext, genModelUtil)) - } - - def generateResourceDescriptionConstants(ExportModel model, IFileSystemAccess fsa) { - val fileName = model.resourceDescriptionConstants.toFileName - fsa.generateFile(fileName, resourceDescriptionConstantsGenerator.generate(model, compilationContext, genModelUtil)) - } - - def generateFingerprintComputer(ExportModel model, IFileSystemAccess fsa) { - val fileName = model.fingerprintComputer.toFileName - fsa.generateFile(fileName, fingerprintComputerGenerator.generate(model, compilationContext, genModelUtil)) - } - - def generateFragmentProvider(ExportModel model, IFileSystemAccess fsa) { - val fileName = model.fragmentProvider.toFileName - if (model.exports.exists(e|e.fingerprint && e.fragmentAttribute !== null) || model.isExtension) { - fsa.generateFile(fileName, fragmentProviderGenerator.generate(model, compilationContext, genModelUtil)) - } else if (!model.exports.empty){ - fsa.generateFile(fileName, ''' - package «model.fragmentProvider.toJavaPackage»; - - import com.avaloq.tools.ddk.xtext.linking.ShortFragmentProvider; - - - public class «model.fragmentProvider.toSimpleName» extends ShortFragmentProvider { - - } - ''') - } - } - - def generateFeatureExtension(ExportModel model, IFileSystemAccess fsa) { - if (model.extension) { - val fileName = model.exportFeatureExtension.toFileName - fsa.generateFile(fileName, exportFeatureExtensionGenerator.generate(model, compilationContext, genModelUtil)) - } - } - - override afterGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {} - - override beforeGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {} - -} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.java new file mode 100644 index 0000000000..d459f56c44 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.export.generator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.xtext.Grammar; + +import com.avaloq.tools.ddk.xtext.export.export.Export; +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.export.export.Interface; +import com.avaloq.tools.ddk.xtext.export.export.UserData; +import com.avaloq.tools.ddk.xtext.expression.generator.EClassComparator; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtil2; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtil; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.common.collect.ListMultimap; +import com.google.inject.Inject; + + +public class ExportGeneratorX { + + @Inject + private Naming naming; + + public String getName(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + return uri.trimFileExtension().lastSegment(); + } + + public Grammar getGrammar(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + // Grammar should be set correctly for export extensions, not yet for normal export sources + if (model.getTargetGrammar() != null) { + return model.getTargetGrammar(); + } + final org.eclipse.emf.ecore.resource.Resource grammarResource = model.eResource().getResourceSet().getResource( + uri.trimSegments(1).appendSegment(uri.trimFileExtension().lastSegment() + ".xtext"), true); + return grammarResource != null && !grammarResource.getContents().isEmpty() + ? (Grammar) grammarResource.getContents().get(0) + : null; + } + + public String getExportedNamesProvider(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) + return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".naming." + getName(model) + "ExportedNamesProvider"; + } + + public String getResourceDescriptionManager(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) + return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionManager"; + } + + public String getResourceDescriptionManager(Grammar grammar) { + return naming.toJavaPackage(grammar.getName()) + ".resource." + naming.toSimpleName(grammar.getName()) + "ResourceDescriptionManager"; + } + + public String getResourceDescriptionStrategy(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) + return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionStrategy"; + } + + public String getResourceDescriptionConstants(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) + return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionConstants"; + } + + public String getFingerprintComputer(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) + return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FingerprintComputer"; + } + + public String getFragmentProvider(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) + return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FragmentProvider"; + } + + public String getExportFeatureExtension(ExportModel model) { + final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); + // TODO we still need to add a package to the models. Extension models already have a name in contrast to cases above + return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + model.getName() + "ExportFeatureExtension"; + } + + /** + * Return the export specification for a type's supertype, if any, or null otherwise. + */ + public Export superType(Export it) { + if (it.getType().getESuperTypes().isEmpty()) { + return null; + } else { + return exportForType((ExportModel) it.eContainer(), it.getType().getESuperTypes().get(0)); + } + } + + /** + * Return the export specification for a given type. + */ + public Export exportForType(ExportModel it, EClassifier type) { + return it.getExports().stream() + .filter(c -> c.getType().getName().equals(type.getName()) && c.getType().getEPackage().getNsURI().equals(type.getEPackage().getNsURI())) + .findFirst() + .orElse(null); + } + + /** + * Return a combined list of all user data specifications; including those on supertypes. + * + *

Public dispatcher for the dispatch methods.

+ */ + public List allUserData(Object it) { + if (it instanceof Export e) { + return _allUserData(e); + } else if (it == null) { + return _allUserData((Void) null); + } else { + throw new IllegalArgumentException("Unhandled parameter type: " + it); + } + } + + /** + * Return a combined list of all user data specifications; including those on supertypes. + */ + protected List _allUserData(Export it) { + final List result = allUserData(superType(it)); + result.addAll(it.getUserData()); + return result; + } + + /** + * Sentinel for the above. + */ + protected List _allUserData(Void it) { + return new ArrayList<>(); + } + + /** + * Return all the interface specification for the supertypes of a type. + */ + public List getSuperInterfaces(Interface it, EClass type) { + if (type.getESuperTypes().isEmpty()) { + return new ArrayList<>(); + } else { + return getInterfacesForType((ExportModel) it.eContainer(), type.getESuperTypes().get(0)); + } + } + + /** + * Return all interface specifications that apply to a certain type; including those that are defined for supertypes. + */ + public List getInterfacesForType(ExportModel it, EClass type) { + final List filtered = it.getInterfaces().stream() + .filter(f -> f.getType() == type) + .collect(java.util.stream.Collectors.toList()); + final List result = filtered.isEmpty() ? new ArrayList<>() : new ArrayList<>(List.of(filtered.get(0))); + if (!type.getESuperTypes().isEmpty()) { + result.addAll(getInterfacesForType(it, type.getESuperTypes().get(0))); + } + return result; + } + + /** + * Returns a constant name for an Attribute field. + */ + public String constantName(EAttribute attribute, EClass exportType) { + return (GenModelUtil2.format(exportType.getName()) + "__" + GenModelUtil2.format(attribute.getName())).toUpperCase(); + } + + /** + * Returns a constant name for a UserData field. + */ + public String constantName(UserData data, EClass exportType) { + return (GenModelUtil2.format(exportType.getName()) + "__" + GenModelUtil2.format(data.getName())).toUpperCase(); + } + + /** + * Sort exports according to package and type (more specific rules must come first). + * + * @param exports + * exports to sort + * @return sorted map of all exports + */ + public ListMultimap sortedExportsByEPackage(Collection exports) { + return EClassComparator.sortedEPackageGroups(exports, e -> e.getType()); + } + + /** + * Returns a type map for the given exports. + * + * @param exports + * export objects to map + * @param grammar + * Xtext grammar + * @return mappings + */ + public Map typeMap(Collection exports, Grammar grammar) { + return GeneratorUtil.typeMap(exports, grammar, e -> e.getType()); + } +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.xtend deleted file mode 100644 index b88fbe9000..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.xtend +++ /dev/null @@ -1,187 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.Export -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.export.export.Interface -import com.avaloq.tools.ddk.xtext.export.export.UserData -import com.avaloq.tools.ddk.xtext.expression.generator.EClassComparator -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtil2 -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtil -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.common.collect.ListMultimap -import com.google.inject.Inject -import java.util.Collection -import java.util.List -import java.util.Map -import org.eclipse.emf.ecore.EAttribute -import org.eclipse.emf.ecore.EClass -import org.eclipse.emf.ecore.EClassifier -import org.eclipse.emf.ecore.EPackage -import org.eclipse.xtext.Grammar - -class ExportGeneratorX { - - @Inject - extension Naming - - def String getName(ExportModel model) { - val uri = model.eResource().getURI(); - return uri.trimFileExtension().lastSegment(); - } - - def Grammar getGrammar(ExportModel model) { - val uri = model.eResource.URI - // Grammar should be set correctly for export extensions, not yet for normal export sources - if(model.targetGrammar !== null) { - return model.targetGrammar; - } - val grammarResource = model.eResource.resourceSet.getResource(uri.trimSegments(1).appendSegment(uri.trimFileExtension.lastSegment + '.xtext'), true) - return grammarResource?.contents.head as Grammar - } - - def String getExportedNamesProvider(ExportModel model) { - val uri = model.eResource().getURI(); - // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".naming." + getName(model) + "ExportedNamesProvider"; - } - - def String getResourceDescriptionManager(ExportModel model) { - val uri = model.eResource().getURI(); - // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionManager"; - } - - def String getResourceDescriptionManager(Grammar grammar) { - return grammar.name.toJavaPackage + ".resource." + grammar.name.toSimpleName + "ResourceDescriptionManager"; - } - - def String getResourceDescriptionStrategy(ExportModel model) { - val uri = model.eResource().getURI(); - // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionStrategy"; - } - - def String getResourceDescriptionConstants(ExportModel model) { - val uri = model.eResource().getURI(); - // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionConstants"; - } - - def String getFingerprintComputer(ExportModel model) { - val uri = model.eResource().getURI(); - // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FingerprintComputer"; - } - - def String getFragmentProvider(ExportModel model) { - val uri = model.eResource().getURI(); - // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FragmentProvider"; - } - - def String getExportFeatureExtension(ExportModel model) { - val uri = model.eResource().getURI(); - // TODO we still need to add a package to the models. Extension models already have a name in contrast to cases above - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + model.name + "ExportFeatureExtension"; - } - - /** - * Return the export specification for a type's supertype, if any, or null otherwise. - */ - def Export superType(Export it) { - if (type.ESuperTypes.isEmpty) null else (eContainer() as ExportModel).exportForType(type.ESuperTypes.get(0)) - } - - /** - * Return the export specification for a given type. - */ - def Export exportForType(ExportModel it, EClassifier type) { - exports.findFirst(c|c.type.name == type.name && c.type.EPackage.nsURI == type.EPackage.nsURI) - } - - /** - * Return a combined list of all user data specifications; including those on supertypes. - */ - def dispatch List allUserData(Export it) { - val result = superType.allUserData() - result.addAll(it.userData) - return result - } - - /** - * Sentinel for the above. - */ - def dispatch List allUserData(Void it) { - newArrayList - } - - /** - * Return all the interface specification for the supertypes of a type. - */ - def List getSuperInterfaces(Interface it, EClass type) { - if (type.ESuperTypes.isEmpty) newArrayList else (eContainer() as ExportModel).getInterfacesForType(type.ESuperTypes.get(0)) - } - - /** - * Return all interface specifications that apply to a certain type; including those that are defined for supertypes. - */ - def List getInterfacesForType(ExportModel it, EClass type) { - val f = interfaces.filter(f|f.type == type) - val result = if (f.isEmpty) newArrayList else newArrayList(f.get(0)) - if (!type.ESuperTypes.isEmpty) { - result.addAll(getInterfacesForType(type.ESuperTypes.get(0))) - } - return result - } - - /** - * Returns a constant name for an Attribute field - */ - def String constantName(EAttribute attribute, EClass exportType) { - (GenModelUtil2.format(exportType.name) + "__" + GenModelUtil2.format(attribute.name)).toUpperCase() - } - - - /** - * Returns a constant name for a UserData field - */ - def String constantName(UserData data, EClass exportType) { - (GenModelUtil2.format(exportType.name) + "__" + GenModelUtil2.format(data.name)).toUpperCase() - } - - /** - * Sort exports according to package and type (more specific rules must come first). - * - * @param exports - * exports to sort - * @return sorted map of all exports - */ - def ListMultimap sortedExportsByEPackage(Collection exports) { - return EClassComparator.sortedEPackageGroups(exports, [e|e.type]) - } - - /** - * Returns a type map for the given exports. - * - * @param exports - * export objects to map - * @param grammar - * Xtext grammar - * @return mappings - */ - def Map typeMap(Collection exports, Grammar grammar) { - return GeneratorUtil.typeMap(exports, grammar, [e|e.type]) - } - -} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.java new file mode 100644 index 0000000000..4ec9f4e776 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.export.generator; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.xtext.Grammar; + +import com.avaloq.tools.ddk.xtext.export.export.Export; +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.common.collect.ListMultimap; +import com.google.inject.Inject; + + +public class ExportedNamesProviderGenerator { + + @Inject + private CodeGenerationX codeGenerationX; + @Inject + private GeneratorUtilX generatorUtilX; + @Inject + private Naming naming; + @Inject + private ExportGeneratorX exportGeneratorX; + + public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { + final Grammar grammar = exportGeneratorX.getGrammar(it); + final StringBuilder sb = new StringBuilder(); + sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getExportedNamesProvider(it))).append(";\n"); + sb.append("\n"); + sb.append("import org.eclipse.emf.ecore.EClass;\n"); + sb.append("import org.eclipse.emf.ecore.EObject;\n"); + sb.append("import org.eclipse.emf.ecore.EPackage;\n"); + sb.append("import org.eclipse.xtext.naming.QualifiedName;\n"); + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.xtext.naming.AbstractExportedNameProvider;\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("/**\n"); + sb.append(" * Qualified name provider for grammar "); + String grammarName = grammar != null ? grammar.getName() : null; + sb.append(grammarName != null ? grammarName : naming.toSimpleName(exportGeneratorX.getExportedNamesProvider(it))); + sb.append(" providing the qualified names for exported objects.\n"); + sb.append(" */\n"); + sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getExportedNamesProvider(it))).append(" extends AbstractExportedNameProvider {\n"); + sb.append("\n"); + if (!it.getExports().isEmpty()) { + final List types = it.getExports(); + sb.append(" @Override\n"); + sb.append(" public QualifiedName qualifiedName(final EObject object) {\n"); + sb.append(" EClass eClass = object.eClass();\n"); + sb.append(" EPackage ePackage = eClass.getEPackage();\n"); + final Set exportedEClasses = types.stream().map(Export::getType).collect(Collectors.toSet()); + final ListMultimap exportsMap = exportGeneratorX.sortedExportsByEPackage(types); + List sortedPackages = exportsMap.keySet().stream() + .sorted((a, b) -> a.getNsURI().compareTo(b.getNsURI())) + .collect(Collectors.toList()); + for (EPackage p : sortedPackages) { + sb.append(" if (ePackage == ").append(genModelUtil.qualifiedPackageInterfaceName(p)).append(".eINSTANCE) {\n"); + sb.append(" int classifierID = eClass.getClassifierID();\n"); + sb.append(" switch (classifierID) {\n"); + for (EClassifier classifier : p.getEClassifiers()) { + if (classifier instanceof EClass c) { + if (exportedEClasses.stream().anyMatch(e -> e.isSuperTypeOf(c))) { + sb.append(" case ").append(genModelUtil.classifierIdLiteral(c)).append(": {\n"); + sb.append(" return qualifiedName((").append(genModelUtil.instanceClassName(c)).append(") object);\n"); + sb.append(" }\n"); + } + } + } + sb.append(" default:\n"); + sb.append(" return null;\n"); + sb.append(" }\n"); + sb.append(" }\n"); + } + sb.append(" return null;\n"); + sb.append(" }\n"); + sb.append("\n"); + for (Export c : types) { + sb.append(" /**\n"); + sb.append(" * Return the qualified name under which a ").append(c.getType().getName()).append(" object is exported, or null if the object should not be exported.\n"); + sb.append(" *\n"); + sb.append(" * @param obj\n"); + sb.append(" * The object to be exported\n"); + sb.append(" * @return The object's qualified name, or null if the object is not to be exported\n"); + sb.append(" */\n"); + sb.append(" protected QualifiedName qualifiedName(final ").append(genModelUtil.instanceClassName(c.getType())).append(" obj) {\n"); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c))).append("\n"); + if (c.getNaming() != null) { + sb.append(" final Object name = ").append(codeGenerationX.javaExpression(c.getNaming(), ctx.clone("obj", c.getType()))).append(";\n"); + sb.append(" return name != null ? "); + if (c.isQualifiedName()) { + sb.append("getConverter().toQualifiedName(String.valueOf(name))"); + } else { + sb.append("qualifyWithContainerName(obj, String.valueOf(name))"); + } + sb.append(" : null;\n"); + } else { + sb.append(" return "); + if (c.isQualifiedName()) { + sb.append("getConverter().toQualifiedName(getResolver().apply(obj))"); + } else { + sb.append("qualifyWithContainerName(obj, getResolver().apply(obj))"); + } + sb.append("; // \"name\" attribute by default\n"); + } + sb.append(" }\n"); + sb.append("\n"); + } + } + sb.append("}\n"); + return sb; + } +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.xtend deleted file mode 100644 index 7b4fe1bdca..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.xtend +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.inject.Inject -import org.eclipse.emf.ecore.EClass - -class ExportedNamesProviderGenerator { - - @Inject extension CodeGenerationX - @Inject extension GeneratorUtilX - @Inject extension Naming - @Inject extension ExportGeneratorX - - def generate(ExportModel it, CompilationContext ctx, extension GenModelUtilX genModelUtil) { - val grammar = grammar - ''' - package «exportedNamesProvider.toJavaPackage()»; - - import org.eclipse.emf.ecore.EClass; - import org.eclipse.emf.ecore.EObject; - import org.eclipse.emf.ecore.EPackage; - import org.eclipse.xtext.naming.QualifiedName; - - import com.avaloq.tools.ddk.xtext.naming.AbstractExportedNameProvider; - - - /** - * Qualified name provider for grammar «grammar?.name?:exportedNamesProvider.toSimpleName» providing the qualified names for exported objects. - */ - public class «exportedNamesProvider.toSimpleName» extends AbstractExportedNameProvider { - - «IF !exports.isEmpty» - «val types = exports» - @Override - public QualifiedName qualifiedName(final EObject object) { - EClass eClass = object.eClass(); - EPackage ePackage = eClass.getEPackage(); - «val exportedEClasses = types.map[type].toSet()» - «val exportsMap = types.sortedExportsByEPackage()» - «FOR p : exportsMap.keySet().sortBy[nsURI]» - if (ePackage == «p.qualifiedPackageInterfaceName()».eINSTANCE) { - int classifierID = eClass.getClassifierID(); - switch (classifierID) { - «FOR c : p.EClassifiers.filter(EClass).filter(c|exportedEClasses.exists(e|e.isSuperTypeOf(c)))» - case «c.classifierIdLiteral()»: { - return qualifiedName((«c.instanceClassName()») object); - } - «ENDFOR» - default: - return null; - } - } - «ENDFOR» - return null; - } - - «FOR c : types» - /** - * Return the qualified name under which a «c.type.name» object is exported, or null if the object should not be exported. - * - * @param obj - * The object to be exported - * @return The object's qualified name, or null if the object is not to be exported - */ - protected QualifiedName qualifiedName(final «c.type.instanceClassName()» obj) { - «javaContributorComment(c.location())» - «IF c.naming !== null» - final Object name = «c.naming.javaExpression(ctx.clone('obj', c.type))»; - return name != null ? «IF c.qualifiedName»getConverter().toQualifiedName(String.valueOf(name))«ELSE»qualifyWithContainerName(obj, String.valueOf(name))«ENDIF» : null; - «ELSE» - return «IF c.qualifiedName»getConverter().toQualifiedName(getResolver().apply(obj))«ELSE»qualifyWithContainerName(obj, getResolver().apply(obj))«ENDIF»; // "name" attribute by default - «ENDIF» - } - - «ENDFOR» - «ENDIF» - } - ''' - } -} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.java new file mode 100644 index 0000000000..b466720964 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.export.generator; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EPackage; + +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.export.export.Interface; +import com.avaloq.tools.ddk.xtext.export.export.InterfaceExpression; +import com.avaloq.tools.ddk.xtext.export.export.InterfaceField; +import com.avaloq.tools.ddk.xtext.export.export.InterfaceItem; +import com.avaloq.tools.ddk.xtext.export.export.InterfaceNavigation; +import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.inject.Inject; + + +public class FingerprintComputerGenerator { + + @Inject + private CodeGenerationX codeGenerationX; + @Inject + private GeneratorUtilX generatorUtilX; + @Inject + private Naming naming; + @Inject + private ExportGeneratorX exportGeneratorX; + + public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUtilX genModelUtil) { + final StringBuilder sb = new StringBuilder(); + sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getFingerprintComputer(it))).append(";\n"); + sb.append("\n"); + sb.append("import org.eclipse.emf.ecore.EObject;\n"); + if (!it.getInterfaces().isEmpty()) { + sb.append("import org.eclipse.emf.ecore.EPackage;\n"); + sb.append("import org.eclipse.emf.ecore.util.Switch;\n"); + } + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractStreamingFingerprintComputer;\n"); + sb.append("\n"); + sb.append("import com.google.common.hash.Hasher;\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getFingerprintComputer(it))).append(" extends AbstractStreamingFingerprintComputer {\n"); + sb.append("\n"); + if (it.getInterfaces().isEmpty()) { + sb.append(" // no fingerprint defined\n"); + sb.append(" @Override\n"); + sb.append(" public String computeFingerprint(final org.eclipse.emf.ecore.resource.Resource resource) {\n"); + sb.append(" return null;\n"); + sb.append(" }\n"); + sb.append("\n"); + } + sb.append(" private ThreadLocal hasherAccess = new ThreadLocal();\n"); + sb.append("\n"); + + final Set packages = it.getInterfaces().stream() + .map(f -> f.getType().getEPackage()) + .collect(Collectors.toCollection(java.util.LinkedHashSet::new)); + final List sortedPackages = packages.stream() + .sorted((a, b) -> a.getNsURI().compareTo(b.getNsURI())) + .collect(Collectors.toList()); + + for (EPackage p : sortedPackages) { + sb.append(" private final Switch ").append(p.getName()).append("Switch = new ").append(genModelUtil.qualifiedSwitchClassName(p)).append("() {\n"); + final List interfacesForPackage = it.getInterfaces().stream() + .filter(f -> f.getType().getEPackage() == p) + .collect(Collectors.toList()); + for (Interface f : interfacesForPackage) { + sb.append("\n"); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(f))).append("\n"); + sb.append(" @Override\n"); + sb.append(" public Hasher case").append(f.getType().getName()).append("(final ").append(genModelUtil.instanceClassName(f.getType())).append(" obj) {\n"); + sb.append(" final Hasher hasher = hasherAccess.get();\n"); + if (f.getGuard() != null) { + sb.append(" if (!(").append(codeGenerationX.javaExpression(f.getGuard(), ctx.clone("obj", f.getType()))).append(")) {\n"); + sb.append(" return hasher;\n"); + sb.append(" }\n"); + } + sb.append(" hasher.putUnencodedChars(obj.eClass().getName()).putChar(ITEM_SEP);\n"); + final List superFPs = exportGeneratorX.getSuperInterfaces(f, f.getType()); + for (Interface superFingerprint : superFPs) { + for (InterfaceItem superItem : superFingerprint.getItems()) { + sb.append(" ").append(doProfile(superItem, ctx, genModelUtil, superFingerprint.getType())); + } + } + for (InterfaceItem item : f.getItems()) { + sb.append(" ").append(doProfile(item, ctx, genModelUtil, f.getType())); + } + sb.append(" return hasher;\n"); + sb.append(" }\n"); + } + sb.append(" };\n"); + sb.append("\n"); + } + + sb.append(" @Override\n"); + sb.append(" protected void fingerprint(final EObject object, Hasher hasher) {\n"); + sb.append(" hasherAccess.set(hasher);\n"); + if (!it.getInterfaces().isEmpty()) { + sb.append(" final EPackage ePackage = object.eClass().getEPackage();\n"); + for (EPackage p : sortedPackages) { + sb.append(" if (ePackage == ").append(genModelUtil.qualifiedPackageInterfaceName(p)).append(".eINSTANCE) {\n"); + sb.append(" ").append(p.getName()).append("Switch.doSwitch(object);\n"); + sb.append(" }\n"); + } + } + sb.append(" hasherAccess.set(null);\n"); + sb.append(" }\n"); + sb.append("}\n"); + return sb; + } + + /** + * Public dispatcher for doProfile. + */ + public CharSequence doProfile(InterfaceItem it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { + if (it instanceof InterfaceExpression interfaceExpression) { + return _doProfile(interfaceExpression, ctx, genModelUtil, type); + } else if (it instanceof InterfaceField interfaceField) { + return _doProfile(interfaceField, ctx, genModelUtil, type); + } else if (it instanceof InterfaceNavigation interfaceNavigation) { + return _doProfile(interfaceNavigation, ctx, genModelUtil, type); + } else { + return _doProfileDefault(it, ctx, genModelUtil, type); + } + } + + protected CharSequence _doProfileDefault(InterfaceItem it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { + return "ERROR" + it.toString() + " " + generatorUtilX.javaContributorComment(generatorUtilX.location(it)); + } + + protected CharSequence _doProfile(InterfaceField it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { + final StringBuilder sb = new StringBuilder(); + if (it.getField().isMany() && (it.isUnordered() == true)) { + sb.append("fingerprintFeature(obj, ").append(genModelUtil.literalIdentifier(it.getField())).append(", FingerprintOrder.UNORDERED, hasher);\n"); + } else { + sb.append("fingerprintFeature(obj, ").append(genModelUtil.literalIdentifier(it.getField())).append(", hasher);\n"); + } + sb.append("hasher.putChar(ITEM_SEP);\n"); + return sb; + } + + protected CharSequence _doProfile(InterfaceNavigation it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { + final StringBuilder sb = new StringBuilder(); + if (it.getRef().isMany() && (it.isUnordered() == true)) { + sb.append("fingerprintRef(obj, ").append(genModelUtil.literalIdentifier(it.getRef())).append(", FingerprintOrder.UNORDERED, hasher);\n"); + } else { + sb.append("fingerprintRef(obj, ").append(genModelUtil.literalIdentifier(it.getRef())).append(", hasher);\n"); + } + sb.append("hasher.putChar(ITEM_SEP);\n"); + return sb; + } + + protected CharSequence _doProfile(InterfaceExpression it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { + final StringBuilder sb = new StringBuilder(); + sb.append("fingerprintExpr(").append(codeGenerationX.javaExpression(it.getExpr(), ctx.clone("obj", type))) + .append(", obj, FingerprintOrder.").append(it.isUnordered() ? "UNORDERED" : "ORDERED") + .append(", FingerprintIndirection.").append(it.isRef() ? "INDIRECT" : "DIRECT") + .append(", hasher);\n"); + sb.append("hasher.putChar(ITEM_SEP);\n"); + return sb; + } +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.xtend deleted file mode 100644 index b0eeb2641c..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.xtend +++ /dev/null @@ -1,134 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.export.export.InterfaceExpression -import com.avaloq.tools.ddk.xtext.export.export.InterfaceField -import com.avaloq.tools.ddk.xtext.export.export.InterfaceItem -import com.avaloq.tools.ddk.xtext.export.export.InterfaceNavigation -import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.inject.Inject -import org.eclipse.emf.ecore.EClass - -class FingerprintComputerGenerator { - - @Inject extension CodeGenerationX - @Inject extension GeneratorUtilX - @Inject extension Naming - @Inject extension ExportGeneratorX - - def generate(ExportModel it, CompilationContext ctx, extension GenModelUtilX genModelUtil) { - ''' - package «fingerprintComputer.toJavaPackage»; - - import org.eclipse.emf.ecore.EObject; - «IF !interfaces.isEmpty» - import org.eclipse.emf.ecore.EPackage; - import org.eclipse.emf.ecore.util.Switch; - «ENDIF» - - import com.avaloq.tools.ddk.xtext.resource.AbstractStreamingFingerprintComputer; - - import com.google.common.hash.Hasher; - - - public class «fingerprintComputer.toSimpleName» extends AbstractStreamingFingerprintComputer { - - «IF interfaces.isEmpty» - // no fingerprint defined - @Override - public String computeFingerprint(final org.eclipse.emf.ecore.resource.Resource resource) { - return null; - } - - «ENDIF» - private ThreadLocal hasherAccess = new ThreadLocal(); - - «FOR p : interfaces.map[type.EPackage].toSet.sortBy[nsURI]» - private final Switch «p.name»Switch = new «p.qualifiedSwitchClassName()»() { - «FOR f : interfaces.filter[type.EPackage == p]» - - «javaContributorComment(f.location())» - @Override - public Hasher case«f.type.name»(final «f.type.instanceClassName()» obj) { - final Hasher hasher = hasherAccess.get(); - «IF f.guard !== null» - if (!(«f.guard.javaExpression(ctx.clone('obj', f.type))»)) { - return hasher; - } - «ENDIF» - hasher.putUnencodedChars(obj.eClass().getName()).putChar(ITEM_SEP); - «val superFPs = f.getSuperInterfaces(f.type)» - «FOR superFingerprint : superFPs» - «FOR superItem : superFingerprint.items» - «doProfile(superItem, ctx, genModelUtil, superFingerprint.type)» - «ENDFOR» - «ENDFOR» - «FOR item : f.items» - «doProfile(item, ctx, genModelUtil, f.type)» - «ENDFOR» - return hasher; - } - «ENDFOR» - }; - - «ENDFOR» - @Override - protected void fingerprint(final EObject object, Hasher hasher) { - hasherAccess.set(hasher); - «IF !interfaces.isEmpty» - final EPackage ePackage = object.eClass().getEPackage(); - «FOR p : interfaces.map[type.EPackage].toSet().sortBy[nsURI]» - if (ePackage == «p.qualifiedPackageInterfaceName()».eINSTANCE) { - «p.name»Switch.doSwitch(object); - } - «ENDFOR» - «ENDIF» - hasherAccess.set(null); - } - } - ''' - } - - def dispatch doProfile(InterfaceItem it, CompilationContext ctx, extension GenModelUtilX genModelUtil, EClass type) { - 'ERROR' + it.toString + ' ' + javaContributorComment(it.location()) - } - - def dispatch doProfile(InterfaceField it, CompilationContext ctx, extension GenModelUtilX genModelUtil, EClass type) ''' - «IF field.many && (unordered == true) » - fingerprintFeature(obj, «field.literalIdentifier()», FingerprintOrder.UNORDERED, hasher); - «ELSE» - fingerprintFeature(obj, «field.literalIdentifier()», hasher); - «ENDIF» - hasher.putChar(ITEM_SEP); - ''' - - def dispatch doProfile(InterfaceNavigation it, CompilationContext ctx, extension GenModelUtilX genModelUtil, EClass type) ''' - «IF ref.many && (unordered == true) » - fingerprintRef(obj, «ref.literalIdentifier()», FingerprintOrder.UNORDERED, hasher); - «ELSE» - fingerprintRef(obj, «ref.literalIdentifier()», hasher); - «ENDIF» - hasher.putChar(ITEM_SEP); - ''' - - def dispatch doProfile(InterfaceExpression it, CompilationContext ctx, extension GenModelUtilX genModelUtil, EClass type) ''' - fingerprintExpr(«expr.javaExpression(ctx.clone('obj', type))», obj, FingerprintOrder.«if (unordered) "UNORDERED" else "ORDERED"», FingerprintIndirection.«if (ref) "INDIRECT" else "DIRECT"», hasher); - hasher.putChar(ITEM_SEP); - ''' - -} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.java new file mode 100644 index 0000000000..ac623994a1 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.export.generator; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.xtext.Grammar; + +import com.avaloq.tools.ddk.xtext.export.export.Export; +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.common.collect.ListMultimap; +import com.google.inject.Inject; + + +public class FragmentProviderGenerator { + + @Inject + private GeneratorUtilX generatorUtilX; + @Inject + private Naming naming; + @Inject + private ExportGeneratorX exportGeneratorX; + + public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { + final Grammar grammar = exportGeneratorX.getGrammar(it); + final List fingerprintedExports = it.getExports().stream() + .filter(e -> e.isFingerprint() && e.getFragmentAttribute() != null) + .collect(Collectors.toList()); + final StringBuilder sb = new StringBuilder(); + sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getFragmentProvider(it))).append(";\n"); + sb.append("\n"); + if (!fingerprintedExports.isEmpty()) { + sb.append("import org.eclipse.emf.ecore.EClass;\n"); + } + if (!fingerprintedExports.isEmpty() || it.isExtension()) { + sb.append("import org.eclipse.emf.ecore.EObject;\n"); + } + if (!fingerprintedExports.isEmpty()) { + sb.append("import org.eclipse.emf.ecore.EPackage;\n"); + } + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractSelectorFragmentProvider;\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getFragmentProvider(it))).append(" extends AbstractSelectorFragmentProvider {\n"); + sb.append("\n"); + if (!fingerprintedExports.isEmpty()) { + sb.append(" @Override\n"); + sb.append(" public boolean appendFragmentSegment(final EObject object, StringBuilder builder) {\n"); + sb.append(" EClass eClass = object.eClass();\n"); + sb.append(" EPackage ePackage = eClass.getEPackage();\n"); + final Map typeMap = exportGeneratorX.typeMap(fingerprintedExports, grammar); + final ListMultimap sortedExportsMap = exportGeneratorX.sortedExportsByEPackage(fingerprintedExports); + for (EPackage p : sortedExportsMap.keySet()) { + sb.append(" if (ePackage == ").append(genModelUtil.qualifiedPackageInterfaceName(p)).append(".eINSTANCE) {\n"); + sb.append(" int classifierID = eClass.getClassifierID();\n"); + sb.append(" switch (classifierID) {\n"); + for (EClassifier classifier : p.getEClassifiers()) { + if (classifier instanceof EClass c) { + if (fingerprintedExports.stream().map(Export::getType).anyMatch(e -> e.isSuperTypeOf(c))) { + final Export e = typeMap.get(c); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(e))).append("\n"); + sb.append(" case ").append(genModelUtil.classifierIdLiteral(c)).append(": {\n"); + sb.append(" return appendFragmentSegment((").append(genModelUtil.instanceClassName(c)).append(") object, builder);\n"); + sb.append(" }\n"); + } + } + } + sb.append(" default:\n"); + sb.append(" return super.appendFragmentSegment(object, builder);\n"); + sb.append(" }\n"); + sb.append(" }\n"); + } + sb.append(" return super.appendFragmentSegment(object, builder);\n"); + sb.append(" }\n"); + } + sb.append("\n"); + if (it.isExtension()) { + sb.append(" @Override\n"); + sb.append(" protected boolean appendFragmentSegmentFallback(final EObject object, StringBuilder builder) {\n"); + sb.append(" // For export extension we must return false, so the logic will try other extensions\n"); + sb.append(" return false;\n"); + sb.append(" }\n"); + sb.append("\n"); + } + for (Export e : fingerprintedExports) { + sb.append(" protected boolean appendFragmentSegment(final ").append(genModelUtil.instanceClassName(e.getType())).append(" obj, StringBuilder builder) {\n"); + sb.append(" return computeSelectorFragmentSegment(obj, ").append(genModelUtil.literalIdentifier(e.getFragmentAttribute())).append(", ").append(e.isFragmentUnique()).append(", builder);\n"); + sb.append(" }\n"); + sb.append("\n"); + } + sb.append("}\n"); + return sb; + } +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.xtend deleted file mode 100644 index c91937bbb5..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.xtend +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.inject.Inject -import org.eclipse.emf.ecore.EClass - -class FragmentProviderGenerator { - - @Inject extension GeneratorUtilX - @Inject extension Naming - @Inject extension ExportGeneratorX - - def generate(ExportModel it, CompilationContext ctx, extension GenModelUtilX genModelUtil) { - val grammar = grammar - val fingerprintedExports = exports.filter[fingerprint && fragmentAttribute !== null].toList - ''' - package «fragmentProvider.toJavaPackage»; - - «IF !fingerprintedExports.isEmpty» - import org.eclipse.emf.ecore.EClass; - «ENDIF» - «IF !fingerprintedExports.isEmpty || it.extension» - import org.eclipse.emf.ecore.EObject; - «ENDIF» - «IF !fingerprintedExports.isEmpty» - import org.eclipse.emf.ecore.EPackage; - «ENDIF» - - import com.avaloq.tools.ddk.xtext.resource.AbstractSelectorFragmentProvider; - - - public class «getFragmentProvider().toSimpleName()» extends AbstractSelectorFragmentProvider { - - «IF !fingerprintedExports.isEmpty» - @Override - public boolean appendFragmentSegment(final EObject object, StringBuilder builder) { - EClass eClass = object.eClass(); - EPackage ePackage = eClass.getEPackage(); - «val typeMap = fingerprintedExports.typeMap(grammar)» - «val sortedExportsMap = fingerprintedExports.sortedExportsByEPackage()» - «FOR p : sortedExportsMap.keySet()» - if (ePackage == «p.qualifiedPackageInterfaceName()».eINSTANCE) { - int classifierID = eClass.getClassifierID(); - switch (classifierID) { - «FOR c : p.EClassifiers.filter(EClass).filter(c|fingerprintedExports.map[type].exists(e|e.isSuperTypeOf(c)))» - «val e = typeMap.get(c)» - «javaContributorComment(e.location())» - case «c.classifierIdLiteral()»: { - return appendFragmentSegment((«c.instanceClassName()») object, builder); - } - «ENDFOR» - default: - return super.appendFragmentSegment(object, builder); - } - } - «ENDFOR» - return super.appendFragmentSegment(object, builder); - } - «ENDIF» - - «IF it.extension» - @Override - protected boolean appendFragmentSegmentFallback(final EObject object, StringBuilder builder) { - // For export extension we must return false, so the logic will try other extensions - return false; - } - - «ENDIF» - «FOR e : fingerprintedExports» - protected boolean appendFragmentSegment(final «e.type.instanceClassName()» obj, StringBuilder builder) { - return computeSelectorFragmentSegment(obj, «e.fragmentAttribute.literalIdentifier()», «e.fragmentUnique», builder); - } - - «ENDFOR» - } - ''' - } - -} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.java new file mode 100644 index 0000000000..ba2b72d312 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.export.generator; + +import java.util.List; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EAttribute; + +import com.avaloq.tools.ddk.xtext.export.export.Export; +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.export.export.UserData; +import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.inject.Inject; + + +public class ResourceDescriptionConstantsGenerator { + + @Inject + private CodeGenerationX codeGenerationX; + + @Inject + private Naming naming; + + @Inject + private ExportGeneratorX exportGeneratorX; + + public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { + final StringBuilder sb = new StringBuilder(); + sb.append("package "); + sb.append(naming.toJavaPackage(exportGeneratorX.getResourceDescriptionConstants(it))); + sb.append(";\n"); + sb.append("\n"); + sb.append("public interface "); + sb.append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionConstants(it))); + sb.append(" {\n"); + final EList types = it.getExports(); + for (final Export c : types) { + if (!c.getType().isAbstract()) { + final EList a = c.getAllEAttributes(); + final List d = exportGeneratorX.allUserData(c); + if (!a.isEmpty() || !d.isEmpty()) { + sb.append(" // Export "); + sb.append(c.getType().getName()); + sb.append("\n"); + if (!a.isEmpty()) { + for (final EAttribute attr : a) { + sb.append(" public static final String "); + sb.append(exportGeneratorX.constantName(attr, c.getType())); + sb.append(" = \""); + sb.append(codeGenerationX.javaEncode(attr.getName())); + sb.append("\"; //$NON-NLS-1$\n"); + } + } + if (!d.isEmpty()) { + for (final UserData data : d) { + sb.append(" public static final String "); + sb.append(exportGeneratorX.constantName(data, c.getType())); + sb.append(" = \""); + sb.append(codeGenerationX.javaEncode(data.getName())); + sb.append("\"; //$NON-NLS-1$\n"); + } + } + sb.append("\n"); + } + } + } + sb.append("}\n"); + return sb; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.xtend deleted file mode 100644 index 8b7280a4b0..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.xtend +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.inject.Inject - -class ResourceDescriptionConstantsGenerator { - - @Inject extension CodeGenerationX - @Inject extension Naming - @Inject extension ExportGeneratorX - - def generate(ExportModel it, CompilationContext ctx, extension GenModelUtilX genModelUtil) { - ''' - package «getResourceDescriptionConstants().toJavaPackage()»; - - public interface «getResourceDescriptionConstants().toSimpleName()» { - «val types = it.exports» - «FOR c : types.filter[!it.type.abstract]» - «val a = c.allEAttributes» - «val d = c.allUserData()» - «IF !a.isEmpty || !d.isEmpty» - // Export «c.type.name» - «IF !a.isEmpty» - «FOR attr : a» - public static final String «attr.constantName(c.type)» = "«attr.name.javaEncode()»"; //$NON-NLS-1$ - «ENDFOR» - «ENDIF» - «IF !d.isEmpty» - «FOR data : d» - public static final String «data.constantName(c.type)» = "«data.name.javaEncode()»"; //$NON-NLS-1$ - «ENDFOR» - «ENDIF» - - «ENDIF» - «ENDFOR» - } - ''' - } - -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.java new file mode 100644 index 0000000000..6d3b7e0493 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.export.generator; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.xtext.Grammar; + +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.inject.Inject; + + +public class ResourceDescriptionManagerGenerator { + + @Inject + private Naming naming; + + @Inject + private ExportGeneratorX exportGeneratorX; + + public CharSequence generate(final ExportModel model, final CompilationContext ctx, final GenModelUtilX genModelUtil) { + final Grammar grammar = exportGeneratorX.getGrammar(model); + final List usedGrammars = grammar != null ? grammar.getUsedGrammars() : new ArrayList<>(); + final Grammar extendedGrammar = (usedGrammars.isEmpty() || usedGrammars.get(0).getName().endsWith(".Terminals")) ? null : usedGrammars.get(0); + final StringBuilder sb = new StringBuilder(); + sb.append("package "); + sb.append(naming.toJavaPackage(exportGeneratorX.getResourceDescriptionManager(model))); + sb.append(";\n"); + sb.append("\n"); + sb.append("import java.util.Set;\n"); + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractCachingResourceDescriptionManager;\n"); + if (extendedGrammar != null) { + sb.append("import "); + sb.append(exportGeneratorX.getResourceDescriptionManager(extendedGrammar)); + sb.append(";\n"); + sb.append("import com.google.common.collect.ImmutableSet;\n"); + sb.append("import com.google.common.collect.Sets;\n"); + } + sb.append("import com.google.inject.Singleton;\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("/**\n"); + sb.append(" * Resource description manager for "); + sb.append(exportGeneratorX.getName(model)); + sb.append(" resources.\n"); + sb.append(" */\n"); + sb.append("@Singleton\n"); + sb.append("public class "); + sb.append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionManager(model))); + sb.append(" extends AbstractCachingResourceDescriptionManager {\n"); + sb.append("\n"); + sb.append(" public static final Set INTERESTING_EXTS = "); + if (extendedGrammar != null) { + sb.append("ImmutableSet.copyOf(Sets.union("); + sb.append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionManager(extendedGrammar))); + sb.append(".INTERESTING_EXTS, of(/*add extensions here*/)));\n"); + } else { + sb.append("all();\n"); + } + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" protected Set getInterestingExtensions() {\n"); + sb.append(" return INTERESTING_EXTS;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append("}\n"); + return sb; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.xtend deleted file mode 100644 index b449d4a6c0..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.xtend +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.inject.Inject - -class ResourceDescriptionManagerGenerator { - - @Inject extension Naming - @Inject extension ExportGeneratorX - - def generate(ExportModel model, CompilationContext ctx, extension GenModelUtilX genModelUtil) { - val grammar = model.grammar - val usedGrammars = if (grammar !== null) grammar.usedGrammars else newArrayList - val extendedGrammar = if (usedGrammars.isEmpty || usedGrammars.head.name.endsWith('.Terminals')) null else usedGrammars.head - ''' - package «model.resourceDescriptionManager.toJavaPackage»; - - import java.util.Set; - - import com.avaloq.tools.ddk.xtext.resource.AbstractCachingResourceDescriptionManager; - «IF extendedGrammar !== null» - import «extendedGrammar.resourceDescriptionManager»; - import com.google.common.collect.ImmutableSet; - import com.google.common.collect.Sets; - «ENDIF» - import com.google.inject.Singleton; - - - /** - * Resource description manager for «model.name» resources. - */ - @Singleton - public class «model.resourceDescriptionManager.toSimpleName» extends AbstractCachingResourceDescriptionManager { - - public static final Set INTERESTING_EXTS = «IF extendedGrammar !== null»ImmutableSet.copyOf(Sets.union(«extendedGrammar.resourceDescriptionManager.toSimpleName».INTERESTING_EXTS, of(/*add extensions here*/)));«ELSE»all();«ENDIF» - - @Override - protected Set getInterestingExtensions() { - return INTERESTING_EXTS; - } - - } - ''' - } - -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.java new file mode 100644 index 0000000000..931fb078a0 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.java @@ -0,0 +1,245 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.export.generator; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EPackage; + +import com.avaloq.tools.ddk.xtext.export.export.Export; +import com.avaloq.tools.ddk.xtext.export.export.ExportModel; +import com.avaloq.tools.ddk.xtext.export.export.UserData; +import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.google.inject.Inject; + + +public class ResourceDescriptionStrategyGenerator { + + @Inject + private CodeGenerationX codeGenerationX; + @Inject + private GeneratorUtilX generatorUtilX; + @Inject + private Naming naming; + @Inject + private ExportGeneratorX exportGeneratorX; + + public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUtilX genModelUtil) { + final StringBuilder sb = new StringBuilder(); + sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getResourceDescriptionStrategy(it))).append(";\n"); + sb.append("\n"); + sb.append("import java.util.Map;\n"); + sb.append("import java.util.Set;\n"); + sb.append("\n"); + sb.append("import org.eclipse.emf.ecore.EClass;\n"); + sb.append("import org.eclipse.emf.ecore.EObject;\n"); + sb.append("import org.eclipse.emf.ecore.EPackage;\n"); + sb.append("import org.eclipse.emf.ecore.resource.Resource;\n"); + sb.append("import org.eclipse.emf.ecore.util.Switch;\n"); + sb.append("import org.eclipse.xtext.resource.IEObjectDescription;\n"); + sb.append("import org.eclipse.xtext.util.IAcceptor;\n"); + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractResourceDescriptionStrategy;\n"); + if (it.getExports().stream().anyMatch(e -> e.isFingerprint() || e.isResourceFingerprint())) { + sb.append("import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer;\n"); + } + if (it.getExports().stream().anyMatch(e -> e.isLookup())) { + sb.append("import com.avaloq.tools.ddk.xtext.resource.DetachableEObjectDescription;\n"); + } + sb.append("import com.avaloq.tools.ddk.xtext.resource.extensions.AbstractForwardingResourceDescriptionStrategyMap;\n"); + sb.append("import com.google.common.collect.ImmutableMap;\n"); + sb.append("import com.google.common.collect.ImmutableSet;\n"); + + final Collection types = it.getExports(); + sb.append("\n"); + sb.append("\n"); + sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionStrategy(it))).append(" extends AbstractResourceDescriptionStrategy {\n"); + sb.append("\n"); + + // EXPORTED_ECLASSES + sb.append(" private static final Set EXPORTED_ECLASSES = ImmutableSet.copyOf(new EClass[] {\n"); + final Map e = exportGeneratorX.typeMap(types, exportGeneratorX.getGrammar(it)); + final List sortedKeys = e.keySet().stream() + .sorted((a, b) -> genModelUtil.literalIdentifier(a).compareTo(genModelUtil.literalIdentifier(b))) + .collect(Collectors.toList()); + for (int i = 0; i < sortedKeys.size(); i++) { + sb.append(" ").append(genModelUtil.literalIdentifier(sortedKeys.get(i))); + if (i < sortedKeys.size() - 1) { + sb.append(","); + } + sb.append("\n"); + } + sb.append(" });\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public Set getExportedEClasses(final Resource resource) {\n"); + sb.append(" return EXPORTED_ECLASSES;\n"); + sb.append(" }\n"); + sb.append("\n"); + + if (!types.isEmpty()) { + sb.append(" private final ThreadLocal> acceptor = new ThreadLocal>();\n"); + sb.append("\n"); + + final Set packageSet = types.stream() + .filter(c -> !c.getType().isAbstract()) + .map(c -> c.getType().getEPackage()) + .collect(Collectors.toCollection(LinkedHashSet::new)); + final List sortedPackages = packageSet.stream() + .sorted((a, b) -> a.getNsURI().compareTo(b.getNsURI())) + .collect(Collectors.toList()); + + for (EPackage p : sortedPackages) { + sb.append(" private final Switch ").append(p.getName()).append("ExportSwitch = new ").append(genModelUtil.qualifiedSwitchClassName(p)).append("() {\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public Boolean defaultCase(final EObject obj) {\n"); + sb.append(" return true;\n"); + sb.append(" }\n"); + + final List exportsForPackage = types.stream() + .filter(c -> !c.getType().isAbstract() && c.getType().getEPackage() == p) + .collect(Collectors.toList()); + + for (Export c : exportsForPackage) { + sb.append("\n"); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c))).append("\n"); + sb.append(" @Override\n"); + sb.append(" public Boolean case").append(c.getType().getName()).append("(final ").append(genModelUtil.instanceClassName(c.getType())).append(" obj) {\n"); + final String guard = codeGenerationX.javaExpression(c.getGuard(), ctx.clone("obj", c.getType())); + if (c.getGuard() == null) { + sb.append(generateCaseBody(it, c, ctx, genModelUtil)); + } else if (!guard.equalsIgnoreCase("false")) { + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c.getGuard()))).append("\n"); + sb.append(" if (").append(guard).append(") {\n"); + sb.append(generateCaseBody(it, c, ctx, genModelUtil)); + sb.append(" }\n"); + } + sb.append("\n"); + + // can Type contain any nested types ? + final Set nonAbstractTypeNames = types.stream() + .map(t -> t.getType()) + .filter(t -> !t.isAbstract()) + .map(t -> t.getName()) + .collect(Collectors.toSet()); + sb.append(" // can ").append(c.getType().getName()).append(" contain any nested ").append(nonAbstractTypeNames).append(" objects ?\n"); + final Set nonAbstractTypes = types.stream() + .map(t -> t.getType()) + .filter(t -> !t.isAbstract()) + .collect(Collectors.toSet()); + sb.append(" return ").append(generatorUtilX.canContain(c.getType(), nonAbstractTypes, exportGeneratorX.getGrammar(it))).append(";\n"); + sb.append(" }\n"); + } + sb.append(" };\n"); + sb.append("\n"); + } + + sb.append(" @Override\n"); + sb.append(" protected boolean doCreateEObjectDescriptions(final EObject object, final IAcceptor acceptor) {\n"); + sb.append(" try {\n"); + sb.append(" this.acceptor.set(acceptor);\n"); + sb.append(" final EPackage ePackage = object.eClass().getEPackage();\n"); + for (EPackage p : sortedPackages) { + sb.append(" if (ePackage == ").append(genModelUtil.qualifiedPackageInterfaceName(p)).append(".eINSTANCE) {\n"); + sb.append(" return ").append(p.getName()).append("ExportSwitch.doSwitch(object);\n"); + sb.append(" }\n"); + } + if (it.isExtension()) { + sb.append(" // Extension does not have to cover all EPackages of the language\n"); + sb.append(" return false;\n"); + } else { + sb.append(" // TODO: generate code for other possible epackages (as defined by grammar)\n"); + sb.append(" return true;\n"); + } + sb.append(" } finally {\n"); + sb.append(" this.acceptor.set(null);\n"); + sb.append(" }\n"); + sb.append(" }\n"); + sb.append("\n"); + } + sb.append("}\n"); + return sb; + } + + public CharSequence generateCaseBody(ExportModel it, Export c, CompilationContext ctx, GenModelUtilX genModelUtil) { + final List a = c.getAllEAttributes(); + final List d = exportGeneratorX.allUserData(c); + final StringBuilder sb = new StringBuilder(); + if (!a.isEmpty() || !d.isEmpty() || c.isFingerprint() || c.isResourceFingerprint() || c.isLookup()) { + sb.append(" // Use a forwarding map to delay calculation as much as possible; otherwise we may get recursive EObject resolution attempts\n"); + sb.append(" Map data = new AbstractForwardingResourceDescriptionStrategyMap() {\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" protected void fill(final ImmutableMap.Builder builder) {\n"); + sb.append(" Object value = null;\n"); + if (c.isFingerprint()) { + sb.append(" // Fingerprint\n"); + sb.append(" value = getFingerprint(obj);\n"); + sb.append(" if (value != null) {\n"); + sb.append(" builder.put(IFingerprintComputer.OBJECT_FINGERPRINT, value.toString());\n"); + sb.append(" }\n"); + } else if (c.isResourceFingerprint()) { + sb.append(" // Resource fingerprint\n"); + sb.append(" value = getFingerprint(obj);\n"); + sb.append(" if (value != null) {\n"); + sb.append(" builder.put(IFingerprintComputer.RESOURCE_FINGERPRINT, value.toString());\n"); + sb.append(" }\n"); + } + if (c.isLookup()) { + sb.append(" // Allow lookups\n"); + if (c.getLookupPredicate() != null) { + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c.getLookupPredicate()))).append("\n"); + sb.append(" if (").append(codeGenerationX.javaExpression(c.getLookupPredicate(), ctx.clone("obj", c.getType()))).append(") {\n"); + sb.append(" builder.put(DetachableEObjectDescription.ALLOW_LOOKUP, Boolean.TRUE.toString());\n"); + sb.append(" }\n"); + } else { + sb.append(" builder.put(DetachableEObjectDescription.ALLOW_LOOKUP, Boolean.TRUE.toString());\n"); + } + } + if (!a.isEmpty()) { + sb.append(" // Exported attributes\n"); + for (EAttribute attr : a) { + sb.append(" value = obj.eGet(").append(genModelUtil.literalIdentifier(attr)).append(", false);\n"); + sb.append(" if (value != null) {\n"); + sb.append(" builder.put(").append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionConstants(it))).append(".").append(exportGeneratorX.constantName(attr, c.getType())).append(", value.toString());\n"); + sb.append(" }\n"); + } + } + if (!d.isEmpty()) { + sb.append(" // User data\n"); + for (UserData data : d) { + sb.append(" value = ").append(codeGenerationX.javaExpression(data.getExpr(), ctx.clone("obj", c.getType()))).append(";\n"); + sb.append(" if (value != null) {\n"); + sb.append(" builder.put(").append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionConstants(it))).append(".").append(exportGeneratorX.constantName(data, c.getType())).append(", value.toString());\n"); + sb.append(" }\n"); + } + } + sb.append(" }\n"); + sb.append(" };\n"); + sb.append(" acceptEObjectDescription(obj, data, acceptor.get());\n"); + } else { + sb.append(" acceptEObjectDescription(obj, acceptor.get());\n"); + } + return sb; + } +} diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.xtend b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.xtend deleted file mode 100644 index d3ab3e3c69..0000000000 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.xtend +++ /dev/null @@ -1,190 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.export.generator - -import com.avaloq.tools.ddk.xtext.export.export.Export -import com.avaloq.tools.ddk.xtext.export.export.ExportModel -import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.google.inject.Inject - -class ResourceDescriptionStrategyGenerator { - - @Inject extension CodeGenerationX - @Inject extension GeneratorUtilX - @Inject extension Naming - @Inject extension ExportGeneratorX - - def generate(ExportModel it, CompilationContext ctx, extension GenModelUtilX genModelUtil) { - ''' - package «resourceDescriptionStrategy.toJavaPackage»; - - import java.util.Map; - import java.util.Set; - - import org.eclipse.emf.ecore.EClass; - import org.eclipse.emf.ecore.EObject; - import org.eclipse.emf.ecore.EPackage; - import org.eclipse.emf.ecore.resource.Resource; - import org.eclipse.emf.ecore.util.Switch; - import org.eclipse.xtext.resource.IEObjectDescription; - import org.eclipse.xtext.util.IAcceptor; - - import com.avaloq.tools.ddk.xtext.resource.AbstractResourceDescriptionStrategy; - «IF exports.exists[e|e.fingerprint||e.resourceFingerprint]» - import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer; - «ENDIF» - «IF exports.exists(e|e.lookup)» - import com.avaloq.tools.ddk.xtext.resource.DetachableEObjectDescription; - «ENDIF» - import com.avaloq.tools.ddk.xtext.resource.extensions.AbstractForwardingResourceDescriptionStrategyMap; - import com.google.common.collect.ImmutableMap; - import com.google.common.collect.ImmutableSet; - «val types = exports» - - - public class «resourceDescriptionStrategy.toSimpleName» extends AbstractResourceDescriptionStrategy { - - private static final Set EXPORTED_ECLASSES = ImmutableSet.copyOf(new EClass[] { - «val e = types.typeMap(grammar)» - «FOR c : e.keySet.sortBy[literalIdentifier] SEPARATOR ',\n'»«c.literalIdentifier»«ENDFOR» - }); - - @Override - public Set getExportedEClasses(final Resource resource) { - return EXPORTED_ECLASSES; - } - - «IF !types.isEmpty» - private final ThreadLocal> acceptor = new ThreadLocal>(); - - «FOR p : types.filter[!type.abstract].map[type.EPackage].toSet.sortBy[nsURI]» - private final Switch «p.name»ExportSwitch = new «p.qualifiedSwitchClassName»() { - - @Override - public Boolean defaultCase(final EObject obj) { - return true; - } - «FOR c : types.filter[!type.abstract && type.EPackage == p]» - - «javaContributorComment(c.location)» - @Override - public Boolean case«c.type.name»(final «c.type.instanceClassName()» obj) { - «val guard = c.guard.javaExpression(ctx.clone('obj', c.type))» - «IF c.guard === null» - «generateCaseBody(c, ctx, genModelUtil)» - «ELSEIF !guard.equalsIgnoreCase("false")» - «javaContributorComment(c.guard.location)» - if («guard») { - «generateCaseBody(c, ctx, genModelUtil)» - } - «ENDIF» - - // can «c.type.name» contain any nested «types.map[type].filter[!abstract].map[name].toSet» objects ? - return «c.type.canContain(types.map[type].filter[!abstract].toSet, grammar)»; - } - «ENDFOR» - }; - - «ENDFOR» - @Override - protected boolean doCreateEObjectDescriptions(final EObject object, final IAcceptor acceptor) { - try { - this.acceptor.set(acceptor); - final EPackage ePackage = object.eClass().getEPackage(); - «FOR p : types.filter[!type.abstract].map[type.EPackage].toSet.sortBy[nsURI]» - if (ePackage == «p.qualifiedPackageInterfaceName».eINSTANCE) { - return «p.name»ExportSwitch.doSwitch(object); - } - «ENDFOR» - «IF it.extension» - // Extension does not have to cover all EPackages of the language - return false; - «ELSE» - // TODO: generate code for other possible epackages (as defined by grammar) - return true; - «ENDIF» - } finally { - this.acceptor.set(null); - } - } - - «ENDIF» - } - ''' - } - - def generateCaseBody(ExportModel it, Export c, CompilationContext ctx, extension GenModelUtilX genModelUtil) { - val a = c.allEAttributes - val d = c.allUserData - ''' - «IF !a.isEmpty || !d.isEmpty || c.fingerprint || c.resourceFingerprint || c.lookup » - // Use a forwarding map to delay calculation as much as possible; otherwise we may get recursive EObject resolution attempts - Map data = new AbstractForwardingResourceDescriptionStrategyMap() { - - @Override - protected void fill(final ImmutableMap.Builder builder) { - Object value = null; - «IF c.fingerprint» - // Fingerprint - value = getFingerprint(obj); - if (value != null) { - builder.put(IFingerprintComputer.OBJECT_FINGERPRINT, value.toString()); - } - «ELSEIF c.resourceFingerprint» - // Resource fingerprint - value = getFingerprint(obj); - if (value != null) { - builder.put(IFingerprintComputer.RESOURCE_FINGERPRINT, value.toString()); - } - «ENDIF» - «IF c.lookup» - // Allow lookups - «IF c.lookupPredicate !== null» - «javaContributorComment(c.lookupPredicate.location)» - if («c.lookupPredicate.javaExpression(ctx.clone('obj', c.type))») { - builder.put(DetachableEObjectDescription.ALLOW_LOOKUP, Boolean.TRUE.toString()); - } - «ELSE» - builder.put(DetachableEObjectDescription.ALLOW_LOOKUP, Boolean.TRUE.toString()); - «ENDIF» - «ENDIF» - «IF !a.isEmpty » - // Exported attributes - «FOR attr : a» - value = obj.eGet(«attr.literalIdentifier», false); - if (value != null) { - builder.put(«resourceDescriptionConstants.toSimpleName».«attr.constantName(c.type)», value.toString()); - } - «ENDFOR» - «ENDIF» - «IF !d.isEmpty » - // User data - «FOR data : d» - value = «data.expr.javaExpression(ctx.clone('obj', c.type))»; - if (value != null) { - builder.put(«resourceDescriptionConstants.toSimpleName».«data.constantName(c.type)», value.toString()); - } - «ENDFOR» - «ENDIF» - } - }; - acceptEObjectDescription(obj, data, acceptor.get()); - «ELSE» - acceptEObjectDescription(obj, acceptor.get()); - «ENDIF» - ''' - } -} diff --git a/docs/xtend-migration.md b/docs/xtend-migration.md index 4f6a228d3e..bf84e45ed3 100644 --- a/docs/xtend-migration.md +++ b/docs/xtend-migration.md @@ -12,10 +12,10 @@ | Metric | Value | |--------|-------| | Total Xtend source files | 94 | -| Already migrated (Batch 1–4) | 49 | -| Remaining | 45 | -| Total remaining lines | ~10,404 | -| Modules with remaining Xtend | 14 | +| Already migrated (Batch 1–5) | 58 | +| Remaining | 36 | +| Total remaining lines | ~9,377 | +| Modules with remaining Xtend | 13 | --- @@ -33,7 +33,7 @@ | `checkcfg.core.test` | 7 | 460 | **DONE** (Batch 2–4) | | `sample.helloworld.ui.test` | 3 | 203 | **DONE** (Batch 3–4) | | `xtext.check.generator` | 2 | 113 | **DONE** (Batch 2–3) | -| `xtext.export` | 9 | 1,027 | Pending | +| `xtext.export` | 9 | 1,027 | **DONE** (Batch 5) | | `xtext.export.generator` | 1 | 86 | **DONE** (Batch 4) | | `xtext.expression` | 5 | 679 | 2 done (Batch 2), 3 pending | | `xtext.format` | 6 | 1,623 | 1 done (Batch 2), 5 pending | @@ -173,19 +173,19 @@ Simple test files, utilities, small production code. --- -## Batch 5 — `xtext.export` module (9 files, 1,027 lines) +## Batch 5 — `xtext.export` module (9 files, 1,027 lines) — DONE Code generators with templates and some dispatch methods. -- [ ] `ResourceDescriptionConstantsGenerator.xtend` (54 lines) — Easy — templates, extension, @Inject -- [ ] `ExportFeatureExtensionGenerator.xtend` (77 lines) — Easy — templates, extension, @Inject -- [ ] `ResourceDescriptionManagerGenerator.xtend` (59 lines) — Easy — templates, extension, !==, @Inject -- [ ] `ExportedNamesProviderGenerator.xtend` (96 lines) — Medium — templates, extension, !==, ?., switch -- [ ] `FragmentProviderGenerator.xtend` (94 lines) — Medium — templates, extension, !==, switch -- [ ] `FingerprintComputerGenerator.xtend` (134 lines) — Medium — **dispatch**, templates, extension, @Inject -- [ ] `ExportGenerator.xtend` (136 lines) — Medium — templates, extension, ===, !==, @Inject, override -- [ ] `ExportGeneratorX.xtend` (187 lines) — Hard — **dispatch**, extension, !==, ?., @Inject -- [ ] `ResourceDescriptionStrategyGenerator.xtend` (190 lines) — Hard — templates, extension, ===, !==, @Inject +- [x] `ResourceDescriptionConstantsGenerator.xtend` (54 lines) — Easy — templates, extension, @Inject +- [x] `ExportFeatureExtensionGenerator.xtend` (77 lines) — Easy — templates, extension, @Inject +- [x] `ResourceDescriptionManagerGenerator.xtend` (59 lines) — Easy — templates, extension, !==, @Inject +- [x] `ExportedNamesProviderGenerator.xtend` (96 lines) — Medium — templates, extension, !==, ?., switch +- [x] `FragmentProviderGenerator.xtend` (94 lines) — Medium — templates, extension, !==, switch +- [x] `FingerprintComputerGenerator.xtend` (134 lines) — Medium — **dispatch**, templates, extension, @Inject +- [x] `ExportGenerator.xtend` (136 lines) — Medium — templates, extension, ===, !==, @Inject, override +- [x] `ExportGeneratorX.xtend` (187 lines) — Hard — **dispatch**, extension, !==, ?., @Inject +- [x] `ResourceDescriptionStrategyGenerator.xtend` (190 lines) — Hard — templates, extension, ===, !==, @Inject --- From 49e886eaf28df92f99195480d51da65a2cdbcee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 28 Feb 2026 21:12:29 +0100 Subject: [PATCH 07/23] feat: migrate Batch 6 Xtend files to Java 21 (10 files) Migrate 10 Xtend files across 5 modules: xtext.expression (3), xtext.scope (4), xtext.test.core (1), xtext.ui (1), xtext.ui.test (1). Heavy use of dispatch methods (ExpressionExtensionsX, GenModelUtilX, CodeGenerationX, ScopeNameProviderGenerator, ScopeProviderX, ScopeProviderGenerator) converted to Java 21 pattern matching dispatchers. Template expressions converted to StringBuilder. Modules fully migrated: xtext.expression, xtext.scope, xtext.test.core, xtext.ui, xtext.ui.test. Progress: 68/94 files migrated (72%). Co-Authored-By: Claude Opus 4.6 --- .../expression/generator/CodeGenerationX.java | 594 +++++++++++++++++ .../generator/CodeGenerationX.xtend | 373 ----------- .../generator/ExpressionExtensionsX.java | 139 ++++ .../generator/ExpressionExtensionsX.xtend | 88 --- .../expression/generator/GenModelUtilX.java | 208 ++++++ .../expression/generator/GenModelUtilX.xtend | 160 ----- .../xtext/scope/generator/ScopeGenerator.java | 93 +++ .../scope/generator/ScopeGenerator.xtend | 83 --- .../generator/ScopeNameProviderGenerator.java | 200 ++++++ .../ScopeNameProviderGenerator.xtend | 136 ---- .../generator/ScopeProviderGenerator.java | 604 ++++++++++++++++++ .../generator/ScopeProviderGenerator.xtend | 386 ----------- .../xtext/scope/generator/ScopeProviderX.java | 379 +++++++++++ .../scope/generator/ScopeProviderX.xtend | 248 ------- ...stractResourceDescriptionManagerTest.java} | 100 +-- .../TemplateProposalProviderHelperTest.java | 271 ++++++++ .../TemplateProposalProviderHelperTest.xtend | 265 -------- .../TemplateProposalProviderHelper.java | 87 +++ .../TemplateProposalProviderHelper.xtend | 82 --- docs/xtend-migration.md | 40 +- 20 files changed, 2651 insertions(+), 1885 deletions(-) create mode 100644 com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java delete mode 100644 com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.xtend create mode 100644 com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.java delete mode 100644 com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.xtend create mode 100644 com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.java delete mode 100644 com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.xtend create mode 100644 com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.java delete mode 100644 com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.xtend rename com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/resource/{AbstractResourceDescriptionManagerTest.xtend => AbstractResourceDescriptionManagerTest.java} (59%) create mode 100644 com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java delete mode 100644 com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.xtend create mode 100644 com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.java delete mode 100644 com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.xtend diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java new file mode 100644 index 0000000000..9d1b49e452 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java @@ -0,0 +1,594 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.expression.generator; + +import java.util.ArrayList; +import java.util.List; + +import com.avaloq.tools.ddk.xtext.expression.expression.BooleanLiteral; +import com.avaloq.tools.ddk.xtext.expression.expression.BooleanOperation; +import com.avaloq.tools.ddk.xtext.expression.expression.CastedExpression; +import com.avaloq.tools.ddk.xtext.expression.expression.CollectionExpression; +import com.avaloq.tools.ddk.xtext.expression.expression.Expression; +import com.avaloq.tools.ddk.xtext.expression.expression.FeatureCall; +import com.avaloq.tools.ddk.xtext.expression.expression.Identifier; +import com.avaloq.tools.ddk.xtext.expression.expression.IfExpression; +import com.avaloq.tools.ddk.xtext.expression.expression.IntegerLiteral; +import com.avaloq.tools.ddk.xtext.expression.expression.ListLiteral; +import com.avaloq.tools.ddk.xtext.expression.expression.Literal; +import com.avaloq.tools.ddk.xtext.expression.expression.NullLiteral; +import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall; +import com.avaloq.tools.ddk.xtext.expression.expression.RealLiteral; +import com.avaloq.tools.ddk.xtext.expression.expression.StringLiteral; +import com.avaloq.tools.ddk.xtext.expression.expression.SyntaxElement; +import com.avaloq.tools.ddk.xtext.expression.expression.TypeSelectExpression; + +public class CodeGenerationX { + + private ExpressionExtensionsX expressionExtensionsX = new ExpressionExtensionsX(); + + ////////////////////////////////////////////////// + // ENTRY POINTS + ////////////////////////////////////////////////// + public boolean isCompilable(final Expression it, final CompilationContext ctx) { + final String expr = javaExpression(it, ctx); + return expr != null && !expr.contains("/* NOT COMPILABLE: "); + } + + // dispatch javaExpression + protected String _javaExpression(final Void it, final CompilationContext ctx) { + return ""; + } + + protected String _javaExpression(final Expression it, final CompilationContext ctx) { + return notCompilable(it); + } + + public String notCompilable(final Expression it) { + return "/* NOT COMPILABLE: Complex expressions like \"" + expressionExtensionsX.serialize(it) + "\" cannot be translated to Java. Consider rewriting the expression or using a JAVA extension. */"; + } + + ////////////////////////////////////////////////// + // LITERALS + ////////////////////////////////////////////////// + protected String _javaExpression(final StringLiteral it, final CompilationContext ctx) { + return "\"" + javaEncode(it.getVal()) + "\""; + } + + protected String _javaExpression(final BooleanLiteral it, final CompilationContext ctx) { + return it.getVal(); + } + + protected String _javaExpression(final IntegerLiteral it, final CompilationContext ctx) { + return Integer.toString(it.getVal()); + } + + protected String _javaExpression(final NullLiteral it, final CompilationContext ctx) { + return "null"; + } + + protected String _javaExpression(final RealLiteral it, final CompilationContext ctx) { + return it.getVal(); + } + + protected String _javaExpression(final ListLiteral it, final CompilationContext ctx) { + if (it.getElements().isEmpty()) { + return "java.util.Collections.<" + ctx.javaType(ctx.getRequiredType().getName()) + "> emptyList()"; + } else if (it.getElements().size() == 1) { + return "java.util.Collections.singletonList(" + javaExpression(it.getElements().get(0), ctx) + ")"; + } else { + final List mapped = new ArrayList<>(); + for (final Expression e : it.getElements()) { + mapped.add(javaExpression(e, ctx)); + } + return "com.google.common.collect.Lists.newArrayList(" + join(", ", mapped) + ")"; + } + } + + ////////////////////////////////////////////////// + // TYPES AND VARIABLES + ////////////////////////////////////////////////// + protected String _javaExpression(final Identifier it, final CompilationContext ctx) { + if (isThis(it)) { + return ctx.getImplicitVariable(); + } else { + return join("::", it.getId()); + } + } + + public boolean isType(final FeatureCall it, final CompilationContext ctx) { + return it.getName() == null && it.getType() != null && ctx.isType(javaExpression(it.getType(), ctx)); + } + + public boolean isVariable(final Expression it, final CompilationContext ctx) { + return false; + } + + public boolean isVariable(final FeatureCall it, final CompilationContext ctx) { + return it.getTarget() == null && it.getName() == null && ctx.isVariable(javaExpression(it.getType(), ctx)); + } + + public String featureCallTarget(final FeatureCall it, final CompilationContext ctx) { + if (it.getTarget() == null || isThisCall(it.getTarget())) { + return ctx.getImplicitVariable(); + } else { + return javaExpression(it.getTarget(), ctx); + } + } + + ////////////////////////////////////////////////// + // BOOLEAN OPERATIONS + ////////////////////////////////////////////////// + protected String _javaExpression(final BooleanOperation it, final CompilationContext ctx) { + return autoBracket(it, javaExpression(it.getLeft(), ctx) + " " + it.getOperator() + " " + javaExpression(it.getRight(), ctx), ctx); + } + + ////////////////////////////////////////////////// + // COLLECTION OPERATIONS + ////////////////////////////////////////////////// + // TODO finish + protected String _javaExpression(final CollectionExpression it, final CompilationContext ctx) { + if ("select".equals(it.getName())) { + return "com.google.common.collect.Iterables.filter(" + javaExpression(it.getTarget(), ctx) + + ", new com.google.common.base.Predicate() { public boolean apply(Object " + + (it.getVar() != null ? it.getVar() : "e") + ") {return " + + javaExpression(it.getExp(), ctx) + ";} })"; + } else { + return notCompilable(it); + } + } + + protected String _javaExpression(final TypeSelectExpression it, final CompilationContext ctx) { + if (isSimpleNavigation(it, ctx)) { + return "com.google.common.collect.Iterables.filter(" + javaExpression(it.getTarget(), ctx) + ", " + ctx.javaType(javaExpression(it.getType(), ctx)) + ".class)"; + } else { + return notCompilable(it); + } + } + + ////////////////////////////////////////////////// + // TYPE CAST + ////////////////////////////////////////////////// + protected String _javaExpression(final CastedExpression it, final CompilationContext ctx) { + return "((" + ctx.javaType(javaExpression(it.getType(), ctx)) + ") " + javaExpression(it.getTarget(), ctx) + ")"; + } + + ////////////////////////////////////////////////// + // IF EXPRESSIONS + ////////////////////////////////////////////////// + protected String _javaExpression(final IfExpression it, final CompilationContext ctx) { + return autoBracket(it, javaExpression(it.getCondition(), ctx) + " ? " + javaExpression(it.getThenPart(), ctx) + " : " + javaExpression(it.getElsePart(), ctx), ctx); + } + + ////////////////////////////////////////////////// + // FEATURE CALLS + ////////////////////////////////////////////////// + protected String _javaExpression(final FeatureCall it, final CompilationContext ctx) { + if (isThisCall(it)) { + return ctx.getImplicitVariable(); + } else if (isVariable(it, ctx)) { + return javaExpression(it.getType(), ctx); + } else if (isType(it, ctx)) { + return ctx.javaType(javaExpression(it.getType(), ctx)); + } else if (isSimpleFeatureCall(it, ctx)) { + final String cf = expressionExtensionsX.calledFeature(it); + final String suffix; + if ("eContainer".equals(cf)) { + suffix = "eContainer"; + } else if ("isEmpty".equals(cf)) { + suffix = "isEmpty"; + } else { + suffix = featureCallName(toFirstUpper(cf)); + } + return featureCallTarget(it, ctx) + "." + suffix + "()"; + } else if (isSimpleNavigation(it, ctx)) { + return notCompilable(it); + } else { + final String cf = expressionExtensionsX.calledFeature(it); + final String suffix; + if ("eContainer".equals(cf)) { + suffix = "eContainer"; + } else if ("isEmpty".equals(cf)) { + suffix = "isEmpty"; + } else { + suffix = featureCallName(toFirstUpper(cf)); + } + return featureCallTarget(it, ctx) + "." + suffix + "()"; + } + } + + // TODO: actually, we should look at the feature and return "is" only if it has a boolean value... Can this be done?? + public String featureCallName(final String it) { + if (it.startsWith("^")) { + return featureCallName(toFirstUpper(it.substring(1, it.length()))); + } else { + return (it.startsWith("Is") ? "is" : "get") + it; + } + } + + public boolean isSimpleFeatureCall(final Expression it, final CompilationContext ctx) { + return false; + } + + public boolean isSimpleFeatureCall(final FeatureCall it, final CompilationContext ctx) { + return it.eClass().getName().contains("FeatureCall") && it.getName() == null && isFeature(it.getType()) && (it.getTarget() == null || isVariable(it.getTarget(), ctx) || isThisCall(it.getTarget())); + } + + // dispatch isSimpleNavigation + protected boolean _isSimpleNavigation(final Expression it, final CompilationContext ctx) { + return false; + } + + protected boolean _isSimpleNavigation(final TypeSelectExpression it, final CompilationContext ctx) { + return true; + } + + protected boolean _isSimpleNavigation(final FeatureCall it, final CompilationContext ctx) { + return it.getName() == null && isFeature(it.getType()) && (it.getTarget() == null || isVariable(it.getTarget(), ctx) || isThisCall(it.getTarget()) || isSimpleNavigation(it.getTarget(), ctx)); + } + + public boolean isSimpleNavigation(final Expression it, final CompilationContext ctx) { + if (it instanceof TypeSelectExpression typeSelectExpression) { + return _isSimpleNavigation(typeSelectExpression, ctx); + } else if (it instanceof FeatureCall featureCall) { + return _isSimpleNavigation(featureCall, ctx); + } else if (it != null) { + return _isSimpleNavigation(it, ctx); + } else { + return false; + } + } + + // dispatch navigationRoot + protected String _navigationRoot(final Void it, final CompilationContext ctx) { + return ""; + } + + protected String _navigationRootExpression(final Expression it, final CompilationContext ctx) { + return ""; + } + + protected String _navigationRoot(final FeatureCall it, final CompilationContext ctx) { + if (it.getTarget() != null) { + return navigationRoot(it.getTarget(), ctx); + } else { + if (isVariable(it, ctx)) { + return javaExpression(it, ctx); + } else { + return ctx.getImplicitVariable(); + } + } + } + + public String navigationRoot(final Expression it, final CompilationContext ctx) { + if (it instanceof FeatureCall featureCall) { + return _navigationRoot(featureCall, ctx); + } else if (it != null) { + return _navigationRootExpression(it, ctx); + } else { + return _navigationRoot((Void) null, ctx); + } + } + + // dispatch navigations + protected List _navigationsVoid(final Void it, final CompilationContext ctx) { + return new ArrayList<>(); + } + + protected List _navigationsExpression(final Expression it, final CompilationContext ctx) { + return new ArrayList<>(); + } + + protected List _navigations(final FeatureCall it, final CompilationContext ctx) { + final List navs = navigations(it.getTarget(), ctx); + if (navs.isEmpty() && (isThisCall(it) || isVariable(it, ctx))) { + return List.of(); + } else { + navs.add(expressionExtensionsX.calledFeature(it)); + return navs; + } + } + + protected List _navigations(final TypeSelectExpression it, final CompilationContext ctx) { + final List navs = navigations(it.getTarget(), ctx); + navs.add("typeSelect(" + qualifiedTypeName(it.getType(), ctx) + ")"); + return navs; + } + + public List navigations(final Expression it, final CompilationContext ctx) { + if (it instanceof TypeSelectExpression typeSelectExpression) { + return _navigations(typeSelectExpression, ctx); + } else if (it instanceof FeatureCall featureCall) { + return _navigations(featureCall, ctx); + } else if (it != null) { + return _navigationsExpression(it, ctx); + } else { + return _navigationsVoid(null, ctx); + } + } + + ////////////////////////////////////////////////// + // OPERATION CALLS + ////////////////////////////////////////////////// + // TODO handle eClass() + // TODO work out if 'this' should be added or not + protected String _javaExpression(final OperationCall it, final CompilationContext ctx) { + if ((it.getTarget() == null || isThisCall(it.getTarget())) && ctx.targetHasOperation(it)) { + final List mapped = new ArrayList<>(); + for (final Expression p : it.getParams()) { + mapped.add(javaExpression(p, ctx)); + } + return (it.getTarget() != null ? javaExpression(it.getTarget(), ctx) + "." : "") + it.getName() + "(" + join(", ", mapped) + ")"; + } else if (isJavaExtensionCall(it, ctx)) { + final List allParams; + if (it.getTarget() != null) { + allParams = new ArrayList<>(); + allParams.add(it.getTarget()); + allParams.addAll(it.getParams()); + } else { + allParams = it.getParams(); + } + final List mapped = new ArrayList<>(); + for (final Expression p : allParams) { + mapped.add(javaExpression(p, ctx)); + } + return calledJavaMethod(it, ctx) + "(" + join(", ", mapped) + ")"; + } else if (expressionExtensionsX.isArithmeticOperatorCall(it, ctx)) { + final List mapped = new ArrayList<>(); + for (final Expression e : it.getParams()) { + mapped.add(javaExpression(e, ctx)); + } + return autoBracket(it, join(" " + it.getName() + " ", mapped), ctx); + } else if (expressionExtensionsX.isSimpleConcatCall(it)) { + final List mapped = new ArrayList<>(); + for (final Expression e : it.getParams()) { + mapped.add(javaExpression(e, ctx)); + } + return join(" + ", mapped); + } else if (expressionExtensionsX.isPrefixExpression(it, ctx)) { + return autoBracket(it, it.getName() + javaExpression(it.getParams().get(0), ctx), ctx); + } else if ("first".equals(it.getName()) && it.getParams().isEmpty() && it.getTarget() != null) { + return javaExpression(it.getTarget(), ctx) + ".get(0)"; + } else if ("isInstance".equals(it.getName()) && it.getParams().size() == 1 && it.getTarget() instanceof FeatureCall && isType((FeatureCall) it.getTarget(), ctx)) { + return autoBracket(it, javaExpression(it.getParams().get(0), ctx) + " instanceof " + javaExpression(it.getTarget(), ctx), ctx); + } else if ("eContainer".equals(it.getName()) && it.getParams().isEmpty()) { + return javaExpression(it.getTarget(), ctx) + ".eContainer()"; + } else if (ctx.isExtension(it.getName())) { + return notCompilable(it); + } else { + final List mapped = new ArrayList<>(); + for (final Expression p : it.getParams()) { + mapped.add(javaExpression(p, ctx)); + } + return (it.getTarget() != null ? javaExpression(it.getTarget(), ctx) + "." : "") + it.getName() + "(" + (it.getParams().isEmpty() ? "" : join(", ", mapped)) + ")"; + } + } + + public boolean isJavaExtensionCall(final Expression it) { + return false; + } + + public boolean isJavaExtensionCall(final OperationCall it, final CompilationContext ctx) { + return !("isInstance".equals(it.getName())) && isSimpleCall(it, ctx) && calledJavaMethod(it, ctx) != null; + } + + public boolean isSimpleCall(final OperationCall it, final CompilationContext ctx) { + return (it.getTarget() == null || isCompilable(it.getTarget(), ctx)) && it.getParams().stream().allMatch(p -> isCompilable(p, ctx)); + } + + public String calledJavaMethod(final OperationCall it, final CompilationContext ctx) { + return ctx.getCalledJavaMethod(it); + } + + ////////////////////////////////////////////////// + // EXPRESSION BRACKETING + ////////////////////////////////////////////////// + public String autoBracket(final Expression it, final String javaCode, final CompilationContext ctx) { + if (requiresBracketing(it, ctx)) { + return "(" + javaCode + ")"; + } else { + return javaCode; + } + } + + // dispatch requiresBracketing (1 param: Expression, ctx) + protected boolean _requiresBracketing(final Expression it, final CompilationContext ctx) { + return (expressionExtensionsX.isPrefixExpression(it, ctx) || expressionExtensionsX.isInfixExpression(it, ctx)) && it.eContainer() != null && requiresBracketing(it, it.eContainer(), ctx); + } + + protected boolean _requiresBracketing(final Literal it, final CompilationContext ctx) { + return false; + } + + public boolean requiresBracketing(final Expression it, final CompilationContext ctx) { + if (it instanceof Literal literal) { + return _requiresBracketing(literal, ctx); + } else if (it != null) { + return _requiresBracketing(it, ctx); + } else { + return false; + } + } + + // dispatch requiresBracketing (2 params: Expression, parent, ctx) + protected boolean _requiresBracketingWithObject(final Expression it, final Object parent, final CompilationContext ctx) { + return false; + } + + protected boolean _requiresBracketingWithExpression(final Expression it, final Expression parent, final CompilationContext ctx) { + return expressionExtensionsX.isPrefixExpression(it, ctx) && expressionExtensionsX.isPrefixExpression(parent, ctx) + || (expressionExtensionsX.isInfixExpression(it, ctx) && (expressionExtensionsX.isPrefixExpression(parent, ctx) || expressionExtensionsX.isInfixExpression(parent, ctx))); + } + + protected boolean _requiresBracketing(final OperationCall it, final OperationCall parent, final CompilationContext ctx) { + return expressionExtensionsX.isPrefixExpression(it, ctx) && expressionExtensionsX.isPrefixExpression(parent, ctx) + || (expressionExtensionsX.isInfixExpression(it, ctx) && (expressionExtensionsX.isPrefixExpression(parent, ctx) || (expressionExtensionsX.isInfixExpression(parent, ctx) && !it.getName().equals(parent.getName())))); + } + + protected boolean _requiresBracketing(final BooleanOperation it, final BooleanOperation parent, final CompilationContext ctx) { + return !it.getOperator().equals(parent.getOperator()); + } + + public boolean requiresBracketing(final Expression it, final Object parent, final CompilationContext ctx) { + if (it instanceof OperationCall operationCall && parent instanceof OperationCall parentOp) { + return _requiresBracketing(operationCall, parentOp, ctx); + } else if (it instanceof BooleanOperation boolOp && parent instanceof BooleanOperation parentBool) { + return _requiresBracketing(boolOp, parentBool, ctx); + } else if (it instanceof Expression && parent instanceof Expression parentExpr) { + return _requiresBracketingWithExpression(it, parentExpr, ctx); + } else { + return _requiresBracketingWithObject(it, parent, ctx); + } + } + + ////////////////////////////////////////////////// + // HELPER FUNCTIONS + ////////////////////////////////////////////////// + // dispatch isThisCall + protected boolean _isThisCall(final Expression it) { + return false; + } + + protected boolean _isThisCall(final FeatureCall it) { + return it.getName() == null && isThis(it.getType()); + } + + public boolean isThisCall(final Expression it) { + if (it instanceof FeatureCall featureCall) { + return _isThisCall(featureCall); + } else if (it != null) { + return _isThisCall(it); + } else { + return false; + } + } + + public boolean isFeature(final Identifier it) { + return it.getId() != null && it.getId().size() == 1; + } + + // dispatch isThis + protected boolean _isThis(final Expression it) { + return false; + } + + protected boolean _isThis(final Identifier it) { + return it.getId() != null && it.getId().size() == 1 && "this".equals(it.getId().get(0)); + } + + public boolean isThis(final SyntaxElement it) { + if (it instanceof Identifier identifier) { + return _isThis(identifier); + } else if (it instanceof Expression expression) { + return _isThis(expression); + } else { + return false; + } + } + + public String qualifiedTypeName(final Identifier it, final CompilationContext ctx) { + if (it.getId().size() == 2) { + return it.getId().get(0) + "::" + it.getId().get(1); + } else { + return qualifiedTypeName(ctx, it.getId().get(0)); + } + } + + public /*cached*/ String qualifiedTypeName(final CompilationContext it, final String name) { + return it.getQualifiedTypeName(name); + } + + // dispatch javaEncode + protected String _javaEncode(final Expression it) { + return javaEncode(expressionExtensionsX.serialize(it)); + } + + protected String _javaEncode(final String it) { + return org.eclipse.xtext.util.Strings.convertToJavaString(it); + } + + public String javaEncode(final Object it) { + if (it instanceof String s) { + return _javaEncode(s); + } else if (it instanceof Expression expr) { + return _javaEncode(expr); + } else { + return ""; + } + } + + public String join(final String separator, final List strings) { + if (strings.isEmpty()) { + return ""; + } else { + return internalJoin(separator, strings); + } + } + + private String internalJoin(final String separator, final List strings) { + return org.eclipse.xtext.util.Strings.concat(separator, strings); + } + + public String join(final String separator, final String strings) { + return strings; + } + + public String join(final String separator, final Void strings) { + return ""; + } + + // Public dispatcher for javaExpression + public String javaExpression(final SyntaxElement it, final CompilationContext ctx) { + if (it instanceof OperationCall operationCall) { + return _javaExpression(operationCall, ctx); + } else if (it instanceof CollectionExpression collectionExpression) { + return _javaExpression(collectionExpression, ctx); + } else if (it instanceof TypeSelectExpression typeSelectExpression) { + return _javaExpression(typeSelectExpression, ctx); + } else if (it instanceof FeatureCall featureCall) { + return _javaExpression(featureCall, ctx); + } else if (it instanceof BooleanOperation booleanOperation) { + return _javaExpression(booleanOperation, ctx); + } else if (it instanceof CastedExpression castedExpression) { + return _javaExpression(castedExpression, ctx); + } else if (it instanceof IfExpression ifExpression) { + return _javaExpression(ifExpression, ctx); + } else if (it instanceof StringLiteral stringLiteral) { + return _javaExpression(stringLiteral, ctx); + } else if (it instanceof BooleanLiteral booleanLiteral) { + return _javaExpression(booleanLiteral, ctx); + } else if (it instanceof IntegerLiteral integerLiteral) { + return _javaExpression(integerLiteral, ctx); + } else if (it instanceof NullLiteral nullLiteral) { + return _javaExpression(nullLiteral, ctx); + } else if (it instanceof RealLiteral realLiteral) { + return _javaExpression(realLiteral, ctx); + } else if (it instanceof ListLiteral listLiteral) { + return _javaExpression(listLiteral, ctx); + } else if (it instanceof Identifier identifier) { + return _javaExpression(identifier, ctx); + } else if (it instanceof Expression expression) { + return _javaExpression(expression, ctx); + } else if (it != null) { + return ""; + } else { + return _javaExpression((Void) null, ctx); + } + } + + private String toFirstUpper(final String s) { + if (s == null || s.isEmpty()) { + return s; + } + return Character.toUpperCase(s.charAt(0)) + s.substring(1); + } +} diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.xtend b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.xtend deleted file mode 100644 index 010a927aa0..0000000000 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.xtend +++ /dev/null @@ -1,373 +0,0 @@ - -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.expression.generator - -import com.avaloq.tools.ddk.xtext.expression.expression.Expression -import com.avaloq.tools.ddk.xtext.expression.expression.StringLiteral -import com.avaloq.tools.ddk.xtext.expression.expression.BooleanLiteral -import com.avaloq.tools.ddk.xtext.expression.expression.IntegerLiteral -import com.avaloq.tools.ddk.xtext.expression.expression.NullLiteral -import com.avaloq.tools.ddk.xtext.expression.expression.RealLiteral -import com.avaloq.tools.ddk.xtext.expression.expression.ListLiteral -import com.avaloq.tools.ddk.xtext.expression.expression.Identifier -import com.avaloq.tools.ddk.xtext.expression.expression.FeatureCall -import com.avaloq.tools.ddk.xtext.expression.expression.BooleanOperation -import com.avaloq.tools.ddk.xtext.expression.expression.CollectionExpression -import com.avaloq.tools.ddk.xtext.expression.expression.TypeSelectExpression -import com.avaloq.tools.ddk.xtext.expression.expression.CastedExpression -import com.avaloq.tools.ddk.xtext.expression.expression.IfExpression -import java.util.List -import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall -import com.avaloq.tools.ddk.xtext.expression.expression.Literal - -class CodeGenerationX { - - extension ExpressionExtensionsX = new ExpressionExtensionsX - - ////////////////////////////////////////////////// - // ENTRY POINTS - ////////////////////////////////////////////////// - def boolean isCompilable(Expression it, CompilationContext ctx) { - val expr = javaExpression(ctx) - expr !== null && !expr.contains('/* NOT COMPILABLE: ') - } - - def dispatch String javaExpression(Void it, CompilationContext ctx) { - '' - } - - def dispatch String javaExpression(Expression it, CompilationContext ctx) { - notCompilable - } - - def String notCompilable(Expression it) { - '/* NOT COMPILABLE: Complex expressions like "' + serialize() + '" cannot be translated to Java. Consider rewriting the expression or using a JAVA extension. */' - } - - ////////////////////////////////////////////////// - // LITERALS - ////////////////////////////////////////////////// - def dispatch String javaExpression(StringLiteral it, CompilationContext ctx) { - '"' + javaEncode(^val) + '"' - } - - def dispatch String javaExpression(BooleanLiteral it, CompilationContext ctx) { - ^val - } - - def dispatch String javaExpression(IntegerLiteral it, CompilationContext ctx) { - ^val.toString() - } - - def dispatch String javaExpression(NullLiteral it, CompilationContext ctx) { - "null" - } - - def dispatch String javaExpression(RealLiteral it, CompilationContext ctx) { - ^val.toString() - } - - def dispatch String javaExpression(ListLiteral it, CompilationContext ctx) { - if (elements.empty) { - "java.util.Collections.<" + ctx.javaType(ctx.requiredType.name) + "> emptyList()" - } else if (elements.size == 1) { - "java.util.Collections.singletonList(" + elements.head.javaExpression(ctx) + ")" - } else { - "com.google.common.collect.Lists.newArrayList(" + ', '.join(elements.map[javaExpression(ctx)]) + ")" - } - } - - ////////////////////////////////////////////////// - // TYPES AND VARIABLES - ////////////////////////////////////////////////// - def dispatch String javaExpression(Identifier it, CompilationContext ctx) { - if (isThis()) ctx.implicitVariable else '::'.join(id) - } - - def boolean isType(FeatureCall it, CompilationContext ctx) { - name === null && type !== null && ctx.isType(type.javaExpression(ctx)) - } - - def boolean isVariable(Expression it, CompilationContext ctx) { - false - } - - def boolean isVariable(FeatureCall it, CompilationContext ctx) { - target === null && name === null && ctx.isVariable(type.javaExpression(ctx)) - } - - def String featureCallTarget(FeatureCall it, CompilationContext ctx) { - if (target === null || target.isThisCall()) - ctx.implicitVariable - else - target.javaExpression(ctx) - } - - ////////////////////////////////////////////////// - // BOOLEAN OPERATIONS - ////////////////////////////////////////////////// - def dispatch String javaExpression(BooleanOperation it, CompilationContext ctx) { - autoBracket(left.javaExpression(ctx) + ' ' + operator + ' ' + right.javaExpression(ctx), ctx) - } - - ////////////////////////////////////////////////// - // COLLECTION OPERATIONS - ////////////////////////////////////////////////// - // TODO finish - def dispatch String javaExpression(CollectionExpression it, CompilationContext ctx) { - if ('select' == name) { - 'com.google.common.collect.Iterables.filter(' + target.javaExpression(ctx) + - ', new com.google.common.base.Predicate() { public boolean apply(Object ' + - (if (^var !== null) ^var else 'e') + ') {return ' + - exp.javaExpression(ctx) + ';} })' - } else { - notCompilable() - } - } - - def dispatch String javaExpression(TypeSelectExpression it, CompilationContext ctx) { - if (isSimpleNavigation(ctx)) - 'com.google.common.collect.Iterables.filter(' + target.javaExpression(ctx) + ', ' + ctx.javaType(type.javaExpression(ctx)) + '.class)' - else notCompilable() - } - - ////////////////////////////////////////////////// - // TYPE CAST - ////////////////////////////////////////////////// - def dispatch String javaExpression(CastedExpression it, CompilationContext ctx) { - '((' + ctx.javaType(type.javaExpression(ctx)) + ') ' + target.javaExpression(ctx) + ')' - } - - ////////////////////////////////////////////////// - // IF EXPRESSIONS - ////////////////////////////////////////////////// - def dispatch String javaExpression(IfExpression it, CompilationContext ctx) { - autoBracket(condition.javaExpression(ctx) + ' ? ' + thenPart.javaExpression(ctx) + ' : ' + elsePart.javaExpression(ctx), ctx) - } - - ////////////////////////////////////////////////// - // FEATURE CALLS - ////////////////////////////////////////////////// - def dispatch String javaExpression(FeatureCall it, CompilationContext ctx) { - if (isThisCall()) { - ctx.implicitVariable - } else if (isVariable(ctx)) { - type.javaExpression(ctx) - } else if (isType(ctx)) { - ctx.javaType(type.javaExpression(ctx)) - } else if (isSimpleFeatureCall(ctx)) { - featureCallTarget(ctx) + '.' + (if (calledFeature() == 'eContainer') 'eContainer' else (if (calledFeature() == 'isEmpty') 'isEmpty' else calledFeature().toFirstUpper().featureCallName())) + '()' - } else if (isSimpleNavigation(ctx)) { - notCompilable() - } else { - featureCallTarget(ctx) + '.' + (if (calledFeature() == 'eContainer') 'eContainer' else (if (calledFeature() == 'isEmpty') 'isEmpty' else calledFeature().toFirstUpper().featureCallName())) + '()' - } - } - - // TODO: actually, we should look at the feature and return "is" only if it has a boolean value... Can this be done?? - def String featureCallName(String it) { - if (it.startsWith('^')) - it.substring(1, it.length).toFirstUpper().featureCallName() - else - (if (it.startsWith('Is')) 'is' else 'get') + it - } - - def boolean isSimpleFeatureCall(Expression it, CompilationContext ctx) { - false - } - - def boolean isSimpleFeatureCall(FeatureCall it, CompilationContext ctx) { - eClass.name.contains('FeatureCall') && name === null && type.isFeature() && (target === null || target.isVariable(ctx) || target.isThisCall()) - } - - def dispatch boolean isSimpleNavigation(Expression it, CompilationContext ctx) { - false - } - - def dispatch boolean isSimpleNavigation(TypeSelectExpression it, CompilationContext ctx) { - true - } - - def dispatch boolean isSimpleNavigation(FeatureCall it, CompilationContext ctx) { - name === null && type.isFeature() && (target === null || target.isVariable(ctx) || target.isThisCall() || target.isSimpleNavigation(ctx)) - } - - def dispatch String navigationRoot(Void it, CompilationContext ctx) { - '' - } - - def dispatch String navigationRoot(Expression it, CompilationContext ctx) { - '' - } - - def dispatch String navigationRoot(FeatureCall it, CompilationContext ctx) { - if (target !== null) target.navigationRoot(ctx) else (if (isVariable(ctx)) javaExpression(ctx) else ctx.implicitVariable) - } - - def dispatch List navigations(Void it, CompilationContext ctx) { - {} - } - - def dispatch List navigations(Expression it, CompilationContext ctx) { - {} - } - - def dispatch List navigations(FeatureCall it, CompilationContext ctx) { - val navs = target.navigations(ctx) - if (navs.isEmpty && (isThisCall() || isVariable(ctx))) #[] else { navs.add(calledFeature()); navs } - } - - def dispatch List navigations(TypeSelectExpression it, CompilationContext ctx) { - val navs = target.navigations(ctx) - navs.add("typeSelect(" + type.qualifiedTypeName(ctx) + ")") - navs - } - - ////////////////////////////////////////////////// - // OPERATION CALLS - ////////////////////////////////////////////////// - // TODO handle eClass() - // TODO work out if 'this' should be added or not - def dispatch String javaExpression(OperationCall it, CompilationContext ctx) { - if ((target === null || target.isThisCall()) && ctx.targetHasOperation(it)) { - (if (target !== null) target.javaExpression(ctx) + '.' else '') + name + '(' + ', '.join(params.map[javaExpression(ctx)]) + ')' - } else if (isJavaExtensionCall(ctx)) { - calledJavaMethod(ctx) + '(' + ', '.join((if (target !== null) { val l = newArrayList(target); l.addAll(params); l } else params).map[javaExpression(ctx)]) + ')' - } else if (isArithmeticOperatorCall(ctx)) { - autoBracket((' ' + name + ' ').join(params.map(e|e.javaExpression(ctx))), ctx) - } else if (isSimpleConcatCall()) { - (' + ').join(params.map(e|e.javaExpression(ctx))) - } else if (isPrefixExpression(ctx)) { - autoBracket(name + params.head.javaExpression(ctx), ctx) - } else if ('first' == name && params.isEmpty && target !== null) { - target.javaExpression(ctx) + '.get(0)' - } else if ('isInstance' == name && params.size == 1 && target instanceof FeatureCall && (target as FeatureCall).isType(ctx)) { - autoBracket(params.head.javaExpression(ctx) + ' instanceof ' + target.javaExpression(ctx), ctx) - } else if ('eContainer' == name && params.isEmpty) { - target.javaExpression(ctx) + '.eContainer()' - } else if (ctx.isExtension(name)) { - notCompilable() - } else { - (if (target !== null) target.javaExpression(ctx) + '.' else '') + name + '(' + (if (params.isEmpty) '' else ', '.join(params.map[javaExpression(ctx)])) + ')' - } - } - - def boolean isJavaExtensionCall(Expression it) { - false - } - - def boolean isJavaExtensionCall(OperationCall it, CompilationContext ctx) { - name != 'isInstance' && isSimpleCall(ctx) && calledJavaMethod(ctx) !== null - } - - def boolean isSimpleCall(OperationCall it, CompilationContext ctx) { - (target === null || target.isCompilable(ctx)) && params.forall(p|p.isCompilable(ctx)) - } - - def String calledJavaMethod(OperationCall it, CompilationContext ctx) { - ctx.calledJavaMethod(it) - } - - def /*cached*/ String calledJavaMethod(CompilationContext it, OperationCall call) { - getCalledJavaMethod(call) - } - - ////////////////////////////////////////////////// - // EXPRESSION BRACKETING - ////////////////////////////////////////////////// - def String autoBracket(Expression it, String javaCode, CompilationContext ctx) { - if (requiresBracketing(ctx)) '(' + javaCode + ')' else javaCode - } - - def dispatch boolean requiresBracketing(Expression it, CompilationContext ctx) { - (isPrefixExpression(ctx) || isInfixExpression(ctx)) && eContainer() !== null && requiresBracketing(it, eContainer(), ctx) - } - - def dispatch boolean requiresBracketing(Literal it, CompilationContext ctx) { - false - } - - def dispatch boolean requiresBracketing(Expression it, Object parent, CompilationContext ctx) { - false - } - - def dispatch boolean requiresBracketing(Expression it, Expression parent, CompilationContext ctx) { - isPrefixExpression(ctx) && parent.isPrefixExpression(ctx) || - (isInfixExpression(ctx) && (parent.isPrefixExpression(ctx) || parent.isInfixExpression(ctx))) - } - - def dispatch boolean requiresBracketing(OperationCall it, OperationCall parent, CompilationContext ctx) { - isPrefixExpression(ctx) && parent.isPrefixExpression(ctx) || - (isInfixExpression(ctx) && (parent.isPrefixExpression(ctx) || (parent.isInfixExpression(ctx) && name != parent.name))) - } - - def dispatch boolean requiresBracketing(BooleanOperation it, BooleanOperation parent, CompilationContext ctx) { - operator != parent.operator - } - - ////////////////////////////////////////////////// - // HELPER FUNCTIONS - ////////////////////////////////////////////////// - def dispatch boolean isThisCall(Expression it) { - false - } - - def dispatch boolean isThisCall(FeatureCall it) { - name === null && type.isThis() - } - - def boolean isFeature(Identifier it) { - id !== null && id.size == 1 - } - - def dispatch boolean isThis(Expression it) { - false - } - - def dispatch boolean isThis(Identifier it) { - id !== null && id.size == 1 && id.head == "this" - } - - def String qualifiedTypeName(Identifier it, CompilationContext ctx) { - if (id.size == 2) id.get(0) + "::" + id.get(1) else ctx.qualifiedTypeName(id.head) - } - - def /*cached*/ String qualifiedTypeName(CompilationContext it, String name) { - getQualifiedTypeName(name) - } - - def dispatch String javaEncode(Expression it) { - javaEncode(serialize()) - } - - def dispatch String javaEncode(String it) { - org.eclipse.xtext.util.Strings.convertToJavaString(it) - } - - def String join(String it, List strings) { - if (strings.isEmpty) '' else internalJoin(strings) - } - - private def String internalJoin(String it, List strings) { - org.eclipse.xtext.util.Strings.concat(it, strings) - } - - def String join(String it, String strings) { - strings - } - - def String join(String it, Void strings) { - '' - } - -} diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.java new file mode 100644 index 0000000000..14e9d6619d --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. it program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies it distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.expression.generator; + +import com.avaloq.tools.ddk.xtext.expression.expression.BooleanOperation; +import com.avaloq.tools.ddk.xtext.expression.expression.Expression; +import com.avaloq.tools.ddk.xtext.expression.expression.FeatureCall; +import com.avaloq.tools.ddk.xtext.expression.expression.IfExpression; +import com.avaloq.tools.ddk.xtext.expression.expression.ListLiteral; +import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall; +import org.eclipse.emf.ecore.EObject; + +public class ExpressionExtensionsX { + + protected String _serialize(final EObject it) { + return ExpressionExtensions.serialize(it); + } + + protected String _serialize(final Void it) { + return null; + } + + public String serialize(final Object it) { + if (it == null) { + return _serialize((Void) null); + } else if (it instanceof EObject eObject) { + return _serialize(eObject); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + it); + } + } + + protected boolean _isEmptyList(final Expression it) { + return false; + } + + protected boolean _isEmptyList(final ListLiteral it) { + return it.getElements().isEmpty(); + } + + public boolean isEmptyList(final Expression it) { + if (it instanceof ListLiteral listLiteral) { + return _isEmptyList(listLiteral); + } else { + return _isEmptyList(it); + } + } + + public boolean isSimpleConcatCall(final OperationCall it) { + return "+".equals(it.getName()) && it.getType() == null && it.getTarget() == null && !it.getParams().isEmpty(); + } + + public boolean isNumber(final Expression it, final CompilationContext ctx) { + return ctx.findType("Real").isAssignableFrom(ctx.analyze(it)); + } + + protected boolean _isArithmeticOperatorCall(final OperationCall it, final CompilationContext ctx) { + return it.getType() == null && it.getTarget() == null && it.getParams().size() > 1 + && ("+".equals(it.getName()) || "-".equals(it.getName()) || "*".equals(it.getName()) || "/".equals(it.getName())) + && it.getParams().stream().allMatch(p -> isNumber(p, ctx)); + } + + protected boolean _isArithmeticOperatorCall(final Expression it, final CompilationContext ctx) { + return false; + } + + public boolean isArithmeticOperatorCall(final Expression it, final CompilationContext ctx) { + if (it instanceof OperationCall operationCall) { + return _isArithmeticOperatorCall(operationCall, ctx); + } else { + return _isArithmeticOperatorCall(it, ctx); + } + } + + protected boolean _isPrefixExpression(final Expression it, final CompilationContext ctx) { + return false; + } + + protected boolean _isPrefixExpression(final OperationCall it, final CompilationContext ctx) { + return it.getType() == null && it.getTarget() == null && it.getParams().size() == 1 + && ("-".equals(it.getName()) || "!".equals(it.getName())); + } + + public boolean isPrefixExpression(final Expression it, final CompilationContext ctx) { + if (it instanceof OperationCall operationCall) { + return _isPrefixExpression(operationCall, ctx); + } else { + return _isPrefixExpression(it, ctx); + } + } + + protected boolean _isInfixExpression(final Void it, final CompilationContext ctx) { + return false; + } + + protected boolean _isInfixExpression(final Expression it, final CompilationContext ctx) { + return false; + } + + protected boolean _isInfixExpression(final OperationCall it, final CompilationContext ctx) { + return isArithmeticOperatorCall(it, ctx) || "isInstance".equals(it.getName()); + } + + protected boolean _isInfixExpression(final IfExpression it, final CompilationContext ctx) { + return true; + } + + protected boolean _isInfixExpression(final BooleanOperation it, final CompilationContext ctx) { + return true; + } + + public boolean isInfixExpression(final Expression it, final CompilationContext ctx) { + if (it == null) { + return _isInfixExpression((Void) null, ctx); + } else if (it instanceof BooleanOperation booleanOperation) { + return _isInfixExpression(booleanOperation, ctx); + } else if (it instanceof IfExpression ifExpression) { + return _isInfixExpression(ifExpression, ctx); + } else if (it instanceof OperationCall operationCall) { + return _isInfixExpression(operationCall, ctx); + } else { + return _isInfixExpression(it, ctx); + } + } + + public String calledFeature(final FeatureCall it) { + return it.getType().getId().get(0); + } + +} diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.xtend b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.xtend deleted file mode 100644 index e8341936ad..0000000000 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.xtend +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. it program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies it distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.expression.generator - -import com.avaloq.tools.ddk.xtext.expression.expression.BooleanOperation -import com.avaloq.tools.ddk.xtext.expression.expression.Expression -import com.avaloq.tools.ddk.xtext.expression.expression.FeatureCall -import com.avaloq.tools.ddk.xtext.expression.expression.IfExpression -import com.avaloq.tools.ddk.xtext.expression.expression.ListLiteral -import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall -import org.eclipse.emf.ecore.EObject - -class ExpressionExtensionsX { - - def dispatch String serialize(EObject it) { - ExpressionExtensions.serialize(it) - } - - def dispatch String serialize(Void it) { - null - } - - def dispatch boolean isEmptyList(Expression it) { - false - } - - def dispatch boolean isEmptyList(ListLiteral it) { - elements.isEmpty - } - - def boolean isSimpleConcatCall(OperationCall it) { - name == '+' && type === null && target === null && !params.isEmpty - } - - def boolean isNumber(Expression it, CompilationContext ctx) { - ctx.findType('Real').isAssignableFrom(ctx.analyze(it)) - } - - def dispatch boolean isArithmeticOperatorCall(OperationCall it, CompilationContext ctx) { - type === null && target === null && params.size > 1 && (name == '+' || name == '-' || name == '*' || name == '/') && params.forall(p|p.isNumber(ctx)) - } - - def dispatch boolean isArithmeticOperatorCall(Expression it, CompilationContext ctx) { - false - } - - def dispatch boolean isPrefixExpression(Expression it, CompilationContext ctx) { - false - } - - def dispatch boolean isPrefixExpression(OperationCall it, CompilationContext ctx) { - type === null && target === null && params.size == 1 && (name == '-' || name == '!') - } - - def dispatch boolean isInfixExpression(Void it, CompilationContext ctx) { - false - } - - def dispatch boolean isInfixExpression(Expression it, CompilationContext ctx) { - false - } - - def dispatch boolean isInfixExpression(OperationCall it, CompilationContext ctx) { - isArithmeticOperatorCall(ctx) || 'isInstance' == name - } - - def dispatch boolean isInfixExpression(IfExpression it, CompilationContext ctx) { - true - } - - def dispatch boolean isInfixExpression(BooleanOperation it, CompilationContext ctx) { - true - } - - def String calledFeature(FeatureCall it) { - type.id.head - } - -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.java new file mode 100644 index 0000000000..6c50e2416f --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.java @@ -0,0 +1,208 @@ +package com.avaloq.tools.ddk.xtext.expression.generator; + +import com.google.inject.Inject; +import java.util.Iterator; +import java.util.Objects; +import org.eclipse.emf.codegen.ecore.genmodel.GenClass; +import org.eclipse.emf.codegen.ecore.genmodel.GenDataType; +import org.eclipse.emf.codegen.ecore.genmodel.GenModel; +import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage; +import org.eclipse.emf.codegen.ecore.genmodel.GenPackage; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.impl.EPackageImpl; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.resource.IResourceDescriptions; +import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider; +import org.eclipse.xtext.scoping.IGlobalScopeProvider; +import org.eclipse.xtext.scoping.IScope; +import org.eclipse.xtext.xbase.lib.StringExtensions; + + +public class GenModelUtilX { + + @Inject + private Naming _naming; + + @Inject + private IGlobalScopeProvider globalScopeProvider; + + @Inject + private ResourceDescriptionsProvider resourceDescriptionsProvider; + + private Resource context; + + public void setResource(final Resource context) { + this.context = context; + } + + public /* cached */ String qualifiedPackageInterfaceName(final EPackage it) { + final GenPackage genPackage = genPackage(it); + if (genPackage != null) { + return genPackage.getQualifiedPackageInterfaceName(); + } else if (!Objects.equals(it.getClass(), EPackageImpl.class)) { + return it.getClass().getInterfaces()[0].getName(); + } + return null; + } + + public String qualifiedSwitchClassName(final EPackage it) { + final GenPackage genPackage = genPackage(it); + if (genPackage != null && genPackage.isLiteralsInterface()) { + return genPackage.getUtilitiesPackageName() + "." + genPackage.getSwitchClassName(); + } else { + return _naming.toJavaPackage(qualifiedPackageInterfaceName(it)) + ".util." + StringExtensions.toFirstUpper(it.getName()) + "Switch"; // heuristic + } + } + + protected /* cached */ String _literalIdentifier(final EStructuralFeature it) { + final EClass eClass = it.getEContainingClass(); + final EPackage ePackage = eClass.getEPackage(); + final GenPackage genPackage = genPackage(ePackage); + if (genPackage != null && genPackage.isLiteralsInterface()) { + return literalIdentifier(eClass) + "__" + format(it.getName()).toUpperCase(); + } else { + return qualifiedPackageInterfaceName(ePackage) + ".eINSTANCE.get" + eClass.getName() + "_" + StringExtensions.toFirstUpper(it.getName()) + "()"; + } + } + + protected /* cached */ String _literalIdentifier(final EClass it) { + final GenPackage genPackage = genPackage(it.getEPackage()); + if (genPackage != null && genPackage.isLiteralsInterface()) { + return genPackage.getQualifiedPackageInterfaceName() + ".Literals." + format(it.getName()).toUpperCase(); + } else { + return qualifiedPackageInterfaceName(it.getEPackage()) + ".eINSTANCE.get" + it.getName() + "()"; + } + } + + // defined to simplify debugging generator problems + protected /* cached */ String _literalIdentifier(final ENamedElement it) { + return "DOES_NOT_EXIST"; + } + + // defined to simplify debugging generator problems + protected /* cached */ String _literalIdentifier(final Void it) { + return "DOES_NOT_EXIST"; + } + + // e.g. EcorePackage.ENAMED_ELEMENT + public /* cached */ String classifierIdLiteral(final EClass it) { + return qualifiedPackageInterfaceName(it.getEPackage()) + "." + format(it.getName()).toUpperCase(); + } + + protected /* cached */ String _instanceClassName(final Void it) { + return ""; + } + + protected /* cached */ String _instanceClassName(final EClassifier it) { + if (it.getInstanceClassName() != null) { + return it.getInstanceClassName(); + } + return it.getName(); + } + + protected /* cached */ String _instanceClassName(final EDataType it) { + if (it.getInstanceClassName() != null) { + return it.getInstanceClassName(); + } + return genDataType(it).getQualifiedInstanceClassName(); + } + + protected /* cached */ String _instanceClassName(final EClass it) { + if (it.getInstanceClassName() != null) { + return it.getInstanceClassName(); + } + return genClass(it).getQualifiedInterfaceName(); + } + + public /* cached */ GenPackage genPackage(final EModelElement it) { + final EPackage ePackage = EcoreUtil2.getContainerOfType(it, EPackage.class); + if (globalScopeProvider != null && context != null) { + final IScope scope = globalScopeProvider.getScope(context, GenModelPackage.Literals.GEN_MODEL__GEN_PACKAGES, null); + if (scope != null && ePackage != null) { + final IEObjectDescription desc = scope.getSingleElement(QualifiedName.create(ePackage.getNsURI())); + if (desc != null) { + return (GenPackage) EcoreUtil.resolve(desc.getEObjectOrProxy(), context); + } else { + final IResourceDescriptions resourceDescriptions = resourceDescriptionsProvider.getResourceDescriptions(context); + final Iterator descs = resourceDescriptions.getExportedObjects(GenModelPackage.Literals.GEN_PACKAGE, QualifiedName.create(ePackage.getNsURI()), false).iterator(); + if (descs.hasNext()) { + return (GenPackage) EcoreUtil.resolve(descs.next().getEObjectOrProxy(), context); + } + // In case Xcore is installed GenPackages will be indexed using GenPackage#getQualifiedPackageName() + for (final IEObjectDescription candidate : resourceDescriptions.getExportedObjectsByType(GenModelPackage.Literals.GEN_PACKAGE)) { + if (Objects.equals(candidate.getName().getLastSegment(), ePackage.getName())) { + final GenPackage resolvedCanidate = (GenPackage) EcoreUtil.resolve(candidate.getEObjectOrProxy(), context); + if (!resolvedCanidate.eIsProxy() && Objects.equals(resolvedCanidate.getEcorePackage(), ePackage)) { + return resolvedCanidate; + } + } + } + } + } + } + ResourceSet resourceSet; + if (context != null) { + resourceSet = context.getResourceSet(); + } else if (it.eResource().getResourceSet() != null) { + resourceSet = it.eResource().getResourceSet(); + } else { + resourceSet = new ResourceSetImpl(); + } + return ePackage != null ? GenModelUtil2.findGenPackage(ePackage, resourceSet) : null; + } + + public /* cached */ GenModel genModel(final EModelElement it) { + final GenPackage genPackage = genPackage(it); + return genPackage != null ? genPackage.getGenModel() : null; + } + + public /* cached */ GenClass genClass(final EClass it) { + final GenPackage genPackage = genPackage(it); + return genPackage != null ? (GenClass) genPackage.getGenModel().findGenClassifier(it) : null; + } + + public /* cached */ GenDataType genDataType(final EDataType it) { + final GenPackage genPackage = genPackage(it); + return genPackage != null ? (GenDataType) genPackage.getGenModel().findGenClassifier(it) : null; + } + + public /* cached */ String format(final String name) { + return GenModelUtil2.format(name); + } + + public String literalIdentifier(final ENamedElement it) { + if (it instanceof EClass eClass) { + return _literalIdentifier(eClass); + } else if (it instanceof EStructuralFeature eStructuralFeature) { + return _literalIdentifier(eStructuralFeature); + } else if (it != null) { + return _literalIdentifier(it); + } else { + return _literalIdentifier((Void) null); + } + } + + public String instanceClassName(final EClassifier it) { + if (it instanceof EClass eClass) { + return _instanceClassName(eClass); + } else if (it instanceof EDataType eDataType) { + return _instanceClassName(eDataType); + } else if (it != null) { + return _instanceClassName(it); + } else { + return _instanceClassName((Void) null); + } + } +} diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.xtend b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.xtend deleted file mode 100644 index b86febc268..0000000000 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.xtend +++ /dev/null @@ -1,160 +0,0 @@ -package com.avaloq.tools.ddk.xtext.expression.generator - -import com.google.inject.Inject -import org.eclipse.emf.codegen.ecore.genmodel.GenClass -import org.eclipse.emf.codegen.ecore.genmodel.GenDataType -import org.eclipse.emf.codegen.ecore.genmodel.GenModel -import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage -import org.eclipse.emf.codegen.ecore.genmodel.GenPackage -import org.eclipse.emf.ecore.EClass -import org.eclipse.emf.ecore.EClassifier -import org.eclipse.emf.ecore.EDataType -import org.eclipse.emf.ecore.EModelElement -import org.eclipse.emf.ecore.ENamedElement -import org.eclipse.emf.ecore.EPackage -import org.eclipse.emf.ecore.EStructuralFeature -import org.eclipse.emf.ecore.impl.EPackageImpl -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl -import org.eclipse.emf.ecore.util.EcoreUtil -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.naming.QualifiedName -import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider -import org.eclipse.xtext.scoping.IGlobalScopeProvider - -class GenModelUtilX { - - @Inject - extension Naming - - @Inject - IGlobalScopeProvider globalScopeProvider - @Inject - ResourceDescriptionsProvider resourceDescriptionsProvider - - var Resource context - - def setResource(Resource context) { - this.context = context - } - - def /*cached*/ String qualifiedPackageInterfaceName(EPackage it) { - val genPackage = genPackage() - if (genPackage !== null) - return genPackage.qualifiedPackageInterfaceName - else if (it.class != EPackageImpl) - return it.class.interfaces.head.name - return null - } - - def String qualifiedSwitchClassName(EPackage it) { - val genPackage = genPackage() - if (genPackage !== null && genPackage.literalsInterface) - genPackage.utilitiesPackageName + "." + genPackage.switchClassName - else - qualifiedPackageInterfaceName().toJavaPackage + '.util.' + name.toFirstUpper + 'Switch' // heuristic - } - - def /*cached*/ dispatch String literalIdentifier(EStructuralFeature it) { - val eClass = EContainingClass - val ePackage = eClass.EPackage - val genPackage = ePackage.genPackage() - if (genPackage !== null && genPackage.literalsInterface) - eClass.literalIdentifier() + "__" + name.format().toUpperCase() - else - ePackage.qualifiedPackageInterfaceName() + ".eINSTANCE.get" + eClass.name + "_" + name.toFirstUpper() + "()" - } - - def /*cached*/ dispatch String literalIdentifier(EClass it) { - val genPackage = EPackage.genPackage() - if (genPackage !== null && genPackage.literalsInterface) - genPackage.qualifiedPackageInterfaceName + ".Literals." + name.format().toUpperCase() - else - EPackage.qualifiedPackageInterfaceName() + ".eINSTANCE.get" + name + "()" - } - - // defined to simplify debugging generator problems - def /*cached*/ dispatch String literalIdentifier(ENamedElement it) { - "DOES_NOT_EXIST" - } - - // defined to simplify debugging generator problems - def /*cached*/ dispatch String literalIdentifier(Void it) { - "DOES_NOT_EXIST" - } - - // e.g. EcorePackage.ENAMED_ELEMENT - def /*cached*/ String classifierIdLiteral(EClass it) { - EPackage.qualifiedPackageInterfaceName() + "." + name.format().toUpperCase() - } - - def /*cached*/ dispatch String instanceClassName(Void it) { - "" - } - - def /*cached*/ dispatch String instanceClassName(EClassifier it) { - if (instanceClassName !== null) - return instanceClassName - return name - } - - def /*cached*/ dispatch String instanceClassName(EDataType it) { - if (instanceClassName !== null) - return instanceClassName - return genDataType(it).qualifiedInstanceClassName - } - - def /*cached*/ dispatch String instanceClassName(EClass it) { - if (instanceClassName !== null) - return instanceClassName - return genClass(it).qualifiedInterfaceName - } - - def /*cached*/ GenPackage genPackage(EModelElement it) { - val ePackage = EcoreUtil2.getContainerOfType(it, EPackage) - if (globalScopeProvider !== null && context !== null) { - val scope = globalScopeProvider.getScope(context, GenModelPackage.Literals.GEN_MODEL__GEN_PACKAGES, null) - if (scope !== null && ePackage !== null) { - val desc = scope.getSingleElement(QualifiedName.create(ePackage.nsURI)) - if (desc !== null) { - return EcoreUtil.resolve(desc.EObjectOrProxy, context) as GenPackage - } else { - val resourceDescriptions = resourceDescriptionsProvider.getResourceDescriptions(context) - val descs = resourceDescriptions.getExportedObjects(GenModelPackage.Literals.GEN_PACKAGE, QualifiedName.create(ePackage.nsURI), false).iterator - if (descs.hasNext) { - return EcoreUtil.resolve(descs.next.EObjectOrProxy, context) as GenPackage - } - // In case Xcore is installed GenPackages will be indexed using GenPackage#getQualifiedPackageName() - for (candidate : resourceDescriptions.getExportedObjectsByType(GenModelPackage.Literals.GEN_PACKAGE).filter[name.lastSegment == ePackage.name]) { - val resolvedCanidate = EcoreUtil.resolve(candidate.EObjectOrProxy, context) as GenPackage - if (!resolvedCanidate.eIsProxy && resolvedCanidate.getEcorePackage == ePackage) { - return resolvedCanidate - } - } - } - } - } - val resourceSet = if (context !== null) context.resourceSet else if (it.eResource.resourceSet !== null) it.eResource.resourceSet else new ResourceSetImpl - return if (ePackage !== null) GenModelUtil2.findGenPackage(ePackage, resourceSet) else null - } - - def /*cached*/ GenModel genModel(EModelElement it) { - val genPackage = genPackage(it) - return if (genPackage !== null) genPackage.genModel else null - } - - def /*cached*/ GenClass genClass(EClass it) { - val genPackage = genPackage(it) - return if (genPackage !== null) genPackage.genModel.findGenClassifier(it) as GenClass else null - } - - def /*cached*/ GenDataType genDataType(EDataType it) { - val genPackage = genPackage(it) - return if (genPackage !== null) genPackage.genModel.findGenClassifier(it) as GenDataType else null; - } - - def /*cached*/ String format(String name) { - GenModelUtil2.format(name) - } - -} diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeGenerator.java b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeGenerator.java new file mode 100644 index 0000000000..7eb1121767 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeGenerator.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.scope.generator; + +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorSupport; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeModel; +import com.google.inject.Inject; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.core.resources.IResource; +import org.eclipse.xtext.generator.IFileSystemAccess; +import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.eclipse.xtext.generator.IGenerator2; +import org.eclipse.xtext.generator.IGeneratorContext; +import org.eclipse.xtext.scoping.IScopeProvider; + +/** + * Scope generator generating the {@link IScopeProvider} implementation for a given scope file. + */ +public class ScopeGenerator implements IGenerator2 { + + @Inject + private Naming naming; + + @Inject + private ScopeProviderGenerator scopeProvider; + + @Inject + private ScopeNameProviderGenerator nameProvider; + + @Inject + private GenModelUtilX genModelUtil; + + @Inject + private GeneratorSupport generatorSupport; + + private CompilationContext compilationContext; + + @Override + public void doGenerate(final Resource input, final IFileSystemAccess2 fsa, final IGeneratorContext context) { + if (input == null || input.getContents().isEmpty() || !(input.getContents().get(0) instanceof ScopeModel)) { + return; + } + final ScopeModel model = (ScopeModel) input.getContents().get(0); + genModelUtil.setResource(model.eResource()); + IProject project = null; + if (input.getURI().isPlatformResource()) { + final IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(input.getURI().toPlatformString(true)); + if (res != null) { + project = res.getProject(); + } + } + + generatorSupport.executeWithProjectResourceLoader(project, () -> { + compilationContext = ScopingGeneratorUtil.getCompilationContext(model, genModelUtil); + + generateScopeNameProvider(model, fsa); + generateScopeProvider(model, fsa); + }); + } + + public void generateScopeProvider(final ScopeModel model, final IFileSystemAccess fsa) { + final String fileName = (naming.toJavaPackage(model.getName()) + ".scoping.").replace('.', '/') + naming.toSimpleName(model.getName()) + "ScopeProvider.java"; + fsa.generateFile(fileName, scopeProvider.generate(model, nameProvider, compilationContext, genModelUtil)); + } + + public void generateScopeNameProvider(final ScopeModel model, final IFileSystemAccess fsa) { + final String fileName = (naming.toJavaPackage(model.getName()) + ".scoping.").replace('.', '/') + naming.toSimpleName(model.getName()) + "ScopeNameProvider.java"; + fsa.generateFile(fileName, nameProvider.generate(model, compilationContext, genModelUtil)); + } + + @Override + public void afterGenerate(final Resource input, final IFileSystemAccess2 fsa, final IGeneratorContext context) { + } + + @Override + public void beforeGenerate(final Resource input, final IFileSystemAccess2 fsa, final IGeneratorContext context) { + } + +} diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeGenerator.xtend b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeGenerator.xtend deleted file mode 100644 index 25ebeff4bc..0000000000 --- a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeGenerator.xtend +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.scope.generator - -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorSupport -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeModel -import com.google.inject.Inject -import org.eclipse.core.resources.IProject -import org.eclipse.core.resources.ResourcesPlugin -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.IFileSystemAccess -import org.eclipse.xtext.scoping.IScopeProvider -import org.eclipse.xtext.generator.IGenerator2 -import org.eclipse.xtext.generator.IFileSystemAccess2 -import org.eclipse.xtext.generator.IGeneratorContext - -/** - * Scope generator generating the {@link IScopeProvider} implementation for a given scope file. - */ -class ScopeGenerator implements IGenerator2 { - - @Inject - extension Naming - @Inject - ScopeProviderGenerator scopeProvider - @Inject - ScopeNameProviderGenerator nameProvider - @Inject - GenModelUtilX genModelUtil - @Inject - GeneratorSupport generatorSupport - - CompilationContext compilationContext - - override doGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) { - if (input === null || input.contents.empty || !(input.contents.head instanceof ScopeModel)) { - return - } - val model = input.contents.head as ScopeModel - genModelUtil.resource = model.eResource - var IProject project = null - if (input.URI.isPlatformResource) { - val res = ResourcesPlugin.workspace.root.findMember(input.URI.toPlatformString(true)) - if (res !== null) { - project = res.project - } - } - - generatorSupport.executeWithProjectResourceLoader(project, [ - compilationContext = ScopingGeneratorUtil.getCompilationContext(model, genModelUtil) - - generateScopeNameProvider(model, fsa) - generateScopeProvider(model, fsa) - ]) - } - - def generateScopeProvider(ScopeModel model, IFileSystemAccess fsa) { - val fileName = (model.name.toJavaPackage + ".scoping.").replace('.', '/') + model.name.toSimpleName + "ScopeProvider.java"; - fsa.generateFile(fileName, scopeProvider.generate(model, nameProvider, compilationContext, genModelUtil)) - } - - def generateScopeNameProvider(ScopeModel model, IFileSystemAccess fsa) { - val fileName = (model.name.toJavaPackage + ".scoping.").replace('.', '/') + model.name.toSimpleName + "ScopeNameProvider.java"; - fsa.generateFile(fileName, nameProvider.generate(model, compilationContext, genModelUtil)) - } - - override afterGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {} - - override beforeGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {} - -} diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.java b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.java new file mode 100644 index 0000000000..aeba6f3453 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.java @@ -0,0 +1,200 @@ +package com.avaloq.tools.ddk.xtext.scope.generator; + +import com.avaloq.tools.ddk.xtext.expression.expression.Expression; +import com.avaloq.tools.ddk.xtext.expression.expression.FeatureCall; +import com.avaloq.tools.ddk.xtext.expression.expression.IntegerLiteral; +import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall; +import com.avaloq.tools.ddk.xtext.expression.expression.StringLiteral; +import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.ExpressionExtensionsX; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.avaloq.tools.ddk.xtext.scope.scope.NamingDefinition; +import com.avaloq.tools.ddk.xtext.scope.scope.NamingExpression; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeModel; +import com.google.inject.Inject; +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; + + +public class ScopeNameProviderGenerator { + + @Inject + private CodeGenerationX _codeGenerationX; + + @Inject + private ExpressionExtensionsX _expressionExtensionsX; + + @Inject + private Naming _naming; + + @Inject + private GeneratorUtilX _generatorUtilX; + + @Inject + private ScopeProviderX _scopeProviderX; + + private GenModelUtilX genModelUtil; + + private CompilationContext compilationContext; + + public CharSequence generate(final ScopeModel it, final CompilationContext compilationContext, final GenModelUtilX genModelUtil) { + this.compilationContext = compilationContext; + this.genModelUtil = genModelUtil; + final StringBuilder builder = new StringBuilder(); + builder.append("package ").append(_naming.toJavaPackage(_scopeProviderX.getScopeNameProvider(it))).append(";\n"); + builder.append("\n"); + builder.append("import java.util.Arrays;\n"); + builder.append("\n"); + builder.append("import org.eclipse.emf.ecore.EClass;\n"); + builder.append("\n"); + builder.append("import org.eclipse.xtext.naming.QualifiedName;\n"); + builder.append("\n"); + builder.append("import com.avaloq.tools.ddk.xtext.scoping.AbstractScopeNameProvider;\n"); + builder.append("import com.avaloq.tools.ddk.xtext.scoping.INameFunction;\n"); + builder.append("import com.avaloq.tools.ddk.xtext.scoping.NameFunctions;\n"); + builder.append("\n"); + builder.append("import com.google.common.base.Function;\n"); + builder.append("import com.google.inject.Singleton;\n"); + builder.append("\n"); + builder.append("@SuppressWarnings(\"all\")\n"); + builder.append("@Singleton\n"); + builder.append("public class ").append(_naming.toSimpleName(_scopeProviderX.getScopeNameProvider(it))).append(" extends AbstractScopeNameProvider {\n"); + builder.append("\n"); + builder.append(" @Override\n"); + builder.append(" public Iterable internalGetNameFunctions(final EClass eClass) {\n"); + if (it.getNaming() != null) { + final Set packages = it.getNaming().getNamings().stream() + .map(nd -> nd.getType().getEPackage()) + .collect(Collectors.toSet()); + for (final EPackage p : packages) { + builder.append(" if (").append(genModelUtil.qualifiedPackageInterfaceName(p)).append(".eINSTANCE == eClass.getEPackage()) {\n"); + builder.append(" switch (eClass.getClassifierID()) {\n"); + builder.append("\n"); + for (final NamingDefinition n : it.getNaming().getNamings()) { + if (Objects.equals(n.getType().getEPackage(), p)) { + builder.append(" case ").append(genModelUtil.classifierIdLiteral(n.getType())).append(":\n"); + builder.append(" ").append(_generatorUtilX.javaContributorComment(_generatorUtilX.location(n))).append("\n"); + builder.append(" return ").append(nameFunctions(n.getNaming(), it)).append(";\n"); + } + } + builder.append("\n"); + builder.append(" default:\n"); + builder.append(" return !eClass.getESuperTypes().isEmpty() ? getNameFunctions(eClass.getESuperTypes().get(0)) : null;\n"); + builder.append(" }\n"); + builder.append(" }\n"); + } + } + builder.append(" return !eClass.getESuperTypes().isEmpty() ? getNameFunctions(eClass.getESuperTypes().get(0)) : null;\n"); + builder.append(" }\n"); + builder.append("\n"); + builder.append("}\n"); + return builder; + } + + public CharSequence nameFunctions(final com.avaloq.tools.ddk.xtext.scope.scope.Naming it, final ScopeModel model) { + return nameFunctions(it, model, null, null); + } + + public CharSequence nameFunctions(final com.avaloq.tools.ddk.xtext.scope.scope.Naming it, final ScopeModel model, final String contextName, final EClass contextType) { + final StringBuilder builder = new StringBuilder(); + builder.append("Arrays.asList("); + boolean first = true; + for (final NamingExpression n : it.getNames()) { + if (!first) { + builder.append(", "); + } + first = false; + builder.append(nameFunction(n, model, contextName, contextType)); + } + builder.append(")"); + return builder; + } + + protected String _nameFunction(final NamingExpression it, final ScopeModel model, final String contextName, final EClass contextType) { + if (it.isFactory()) { + if (contextName == null || contextType == null) { + return _codeGenerationX.javaExpression(it.getExpression(), compilationContext.clone("UNEXPECTED_THIS")); + } else { + return _codeGenerationX.javaExpression(it.getExpression(), compilationContext.clone("UNEXPECTED_THIS", null, contextName, contextType)); + } + } else if (it.isExport()) { + return "NameFunctions.exportNameFunction()"; + } else { + return nameFunction(it.getExpression(), model, contextName, contextType); + } + } + + protected String _nameFunction(final Expression it, final ScopeModel model, final String contextName, final EClass contextType) { + return "EXPRESSION_NOT_SUPPORTED(\"" + _expressionExtensionsX.serialize(it) + "\")"; + } + + protected String _nameFunction(final StringLiteral it, final ScopeModel model, final String contextName, final EClass contextType) { + return "NameFunctions.fromConstant(\"" + it.getVal() + "\")"; + } + + protected String _nameFunction(final IntegerLiteral it, final ScopeModel model, final String contextName, final EClass contextType) { + return "NameFunctions.fromConstant(String.valueOf(" + it.getVal() + "))"; + } + + protected String _nameFunction(final FeatureCall it, final ScopeModel model, final String contextName, final EClass contextType) { + final CompilationContext currentContext = (contextName == null) + ? compilationContext.clone("obj", _scopeProviderX.scopeType(it)) + : compilationContext.clone("obj", _scopeProviderX.scopeType(it), "ctx", contextType); + final StringBuilder builder = new StringBuilder(); + if ((it.getTarget() == null || _codeGenerationX.isThisCall(it.getTarget())) && _codeGenerationX.isSimpleFeatureCall(it, currentContext)) { + builder.append("NameFunctions.fromFeature(").append(genModelUtil.literalIdentifier(_scopeProviderX.feature(it))).append(")"); + } else if (_codeGenerationX.isSimpleNavigation(it, currentContext)) { + builder.append("\n"); + builder.append("object -> {\n"); + builder.append(" final ").append(genModelUtil.instanceClassName(_scopeProviderX.scopeType(it))).append(" obj = (").append(genModelUtil.instanceClassName(_scopeProviderX.scopeType(it))).append(") object;\n"); + builder.append(" return toQualifiedName(").append(_codeGenerationX.javaExpression(it, currentContext)).append(");\n"); + builder.append(" }\n"); + } else { + builder.append("EXPRESSION_NOT_SUPPORTED(\"").append(_expressionExtensionsX.serialize(it)).append("\")"); + } + return builder.toString(); + } + + protected String _nameFunction(final OperationCall it, final ScopeModel model, final String contextName, final EClass contextType) { + final CompilationContext currentContext = (contextName == null) + ? compilationContext.clone("obj", _scopeProviderX.scopeType(it)) + : compilationContext.clone("obj", _scopeProviderX.scopeType(it), "ctx", contextType); + final StringBuilder builder = new StringBuilder(); + if (_codeGenerationX.isCompilable(it, currentContext)) { + builder.append("object -> {\n"); + builder.append(" final ").append(genModelUtil.instanceClassName(_scopeProviderX.scopeType(it))).append(" obj = (").append(genModelUtil.instanceClassName(_scopeProviderX.scopeType(it))).append(") object;\n"); + builder.append(" return toQualifiedName(").append(_codeGenerationX.javaExpression(it, currentContext)).append(");\n"); + builder.append(" }\n"); + } else { + builder.append("EXPRESSION_NOT_SUPPORTED(\"").append(_expressionExtensionsX.serialize(it)).append("\")"); + } + return builder.toString(); + } + + public String nameFunction(final EObject it, final ScopeModel model, final String contextName, final EClass contextType) { + if (it instanceof IntegerLiteral integerLiteral) { + return _nameFunction(integerLiteral, model, contextName, contextType); + } else if (it instanceof OperationCall operationCall) { + return _nameFunction(operationCall, model, contextName, contextType); + } else if (it instanceof StringLiteral stringLiteral) { + return _nameFunction(stringLiteral, model, contextName, contextType); + } else if (it instanceof FeatureCall featureCall) { + return _nameFunction(featureCall, model, contextName, contextType); + } else if (it instanceof Expression expression) { + return _nameFunction(expression, model, contextName, contextType); + } else if (it instanceof NamingExpression namingExpression) { + return _nameFunction(namingExpression, model, contextName, contextType); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(it, model, contextName, contextType).toString()); + } + } +} diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.xtend b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.xtend deleted file mode 100644 index cd11358fcf..0000000000 --- a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.xtend +++ /dev/null @@ -1,136 +0,0 @@ -package com.avaloq.tools.ddk.xtext.scope.generator - -import com.avaloq.tools.ddk.xtext.expression.expression.Expression -import com.avaloq.tools.ddk.xtext.expression.expression.FeatureCall -import com.avaloq.tools.ddk.xtext.expression.expression.IntegerLiteral -import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall -import com.avaloq.tools.ddk.xtext.expression.expression.StringLiteral -import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.ExpressionExtensionsX -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX -import com.avaloq.tools.ddk.xtext.scope.scope.Naming -import com.avaloq.tools.ddk.xtext.scope.scope.NamingExpression -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeModel -import com.google.inject.Inject -import org.eclipse.emf.ecore.EClass - -class ScopeNameProviderGenerator { - - @Inject extension CodeGenerationX - @Inject extension ExpressionExtensionsX - @Inject extension com.avaloq.tools.ddk.xtext.expression.generator.Naming - @Inject extension GeneratorUtilX - @Inject extension ScopeProviderX - - extension GenModelUtilX genModelUtil - CompilationContext compilationContext - - def generate(ScopeModel it, CompilationContext compilationContext, GenModelUtilX genModelUtil) { - this.compilationContext = compilationContext - this.genModelUtil = genModelUtil - ''' - package «getScopeNameProvider().toJavaPackage()»; - - import java.util.Arrays; - - import org.eclipse.emf.ecore.EClass; - - import org.eclipse.xtext.naming.QualifiedName; - - import com.avaloq.tools.ddk.xtext.scoping.AbstractScopeNameProvider; - import com.avaloq.tools.ddk.xtext.scoping.INameFunction; - import com.avaloq.tools.ddk.xtext.scoping.NameFunctions; - - import com.google.common.base.Function; - import com.google.inject.Singleton; - - @SuppressWarnings("all") - @Singleton - public class «getScopeNameProvider().toSimpleName()» extends AbstractScopeNameProvider { - - @Override - public Iterable internalGetNameFunctions(final EClass eClass) { - «IF it.naming !== null» - «FOR p : it.naming.namings.map[type.EPackage].toSet()» - if («p.qualifiedPackageInterfaceName()».eINSTANCE == eClass.getEPackage()) { - switch (eClass.getClassifierID()) { - - «FOR n : it.naming.namings.filter(n|n.type.EPackage == p)» - case «n.type.classifierIdLiteral()»: - «javaContributorComment(n.location())» - return «nameFunctions(n.naming, it)»; - «ENDFOR» - - default: - return !eClass.getESuperTypes().isEmpty() ? getNameFunctions(eClass.getESuperTypes().get(0)) : null; - } - } - «ENDFOR» - «ENDIF» - return !eClass.getESuperTypes().isEmpty() ? getNameFunctions(eClass.getESuperTypes().get(0)) : null; - } - - } - ''' - } - - def nameFunctions(Naming it, ScopeModel model) { - nameFunctions(it, model, null, null) - } - - def nameFunctions(Naming it, ScopeModel model, String contextName, EClass contextType) { - '''Arrays.asList(«FOR n : names SEPARATOR ", "»«nameFunction(n, model, contextName, contextType)»«ENDFOR»)''' - } - - def dispatch String nameFunction(NamingExpression it, ScopeModel model, String contextName, EClass contextType) { - if (factory) { - if (contextName === null || contextType === null) { - expression.javaExpression(compilationContext.clone('UNEXPECTED_THIS')) - } else { - expression.javaExpression(compilationContext.clone('UNEXPECTED_THIS', null, contextName, contextType)) - } - } else if (export) { - 'NameFunctions.exportNameFunction()' - } else { - nameFunction(expression, model, contextName, contextType) - } - } - - def dispatch String nameFunction(Expression it, ScopeModel model, String contextName, EClass contextType) { - 'EXPRESSION_NOT_SUPPORTED("' + serialize() + '")' - } - - def dispatch String nameFunction(StringLiteral it, ScopeModel model, String contextName, EClass contextType) { - 'NameFunctions.fromConstant("' + ^val + '")' - } - - def dispatch String nameFunction(IntegerLiteral it, ScopeModel model, String contextName, EClass contextType) { - 'NameFunctions.fromConstant(String.valueOf(' + ^val + '))' - } - - def dispatch String nameFunction(FeatureCall it, ScopeModel model, String contextName, EClass contextType) ''' - «val currentContext = if (contextName === null) compilationContext.clone('obj', scopeType()) else compilationContext.clone('obj', scopeType(), 'ctx', contextType)» - «IF (target === null || target.isThisCall()) && isSimpleFeatureCall(currentContext)»NameFunctions.fromFeature(«literalIdentifier(feature())»)« - ELSEIF isSimpleNavigation(currentContext)» - object -> { - final «scopeType().instanceClassName()» obj = («scopeType().instanceClassName()») object; - return toQualifiedName(«javaExpression(currentContext)»); - } - « - ELSE»EXPRESSION_NOT_SUPPORTED("«serialize()»")«ENDIF - »''' - - def dispatch String nameFunction(OperationCall it, ScopeModel model, String contextName, EClass contextType) ''' - «val currentContext = if (contextName === null) compilationContext.clone('obj', scopeType()) else compilationContext.clone('obj', scopeType(), 'ctx', contextType)» - «IF isCompilable(currentContext)» - object -> { - final «scopeType().instanceClassName()» obj = («scopeType().instanceClassName()») object; - return toQualifiedName(«javaExpression(currentContext)»); - } - « - ELSE»EXPRESSION_NOT_SUPPORTED("«serialize()»")«ENDIF - »''' - -} diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.java b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.java new file mode 100644 index 0000000000..38bbdf9bd2 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.java @@ -0,0 +1,604 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. it program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies it distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.scope.generator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import com.avaloq.tools.ddk.xtext.expression.expression.Expression; +import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall; +import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX; +import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext; +import com.avaloq.tools.ddk.xtext.expression.generator.EClassComparator; +import com.avaloq.tools.ddk.xtext.expression.generator.ExpressionExtensionsX; +import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.avaloq.tools.ddk.xtext.scope.scope.FactoryExpression; +import com.avaloq.tools.ddk.xtext.scope.scope.GlobalScopeExpression; +import com.avaloq.tools.ddk.xtext.scope.scope.LambdaDataExpression; +import com.avaloq.tools.ddk.xtext.scope.scope.MatchDataExpression; +import com.avaloq.tools.ddk.xtext.scope.scope.NamedScopeExpression; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeDefinition; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeDelegation; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeExpression; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeModel; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeRule; +import com.avaloq.tools.ddk.xtext.scope.scope.SimpleScopeExpression; +import com.google.common.collect.Lists; +import com.google.inject.Inject; + +import org.eclipse.emf.ecore.EClass; + +public class ScopeProviderGenerator { + + @Inject + private CodeGenerationX codeGenerationX; + @Inject + private ExpressionExtensionsX expressionExtensionsX; + @Inject + private GeneratorUtilX generatorUtilX; + @Inject + private Naming naming; + @Inject + private ScopeProviderX scopeProviderX; + + private ScopeNameProviderGenerator nameProviderGenerator; + private CompilationContext compilationContext; + private GenModelUtilX genModelUtil; + + public CharSequence generate(final ScopeModel it, final ScopeNameProviderGenerator nameProviderGenerator, final CompilationContext compilationContext, final GenModelUtilX genModelUtil) { + this.nameProviderGenerator = nameProviderGenerator; + this.compilationContext = compilationContext; + this.genModelUtil = genModelUtil; + final StringBuilder builder = new StringBuilder(); + builder.append("package ").append(naming.toJavaPackage(scopeProviderX.getScopeProvider(it))).append(";\n"); + builder.append("\n"); + builder.append("import java.util.Arrays;\n"); + builder.append("\n"); + builder.append("import org.apache.logging.log4j.Logger;\n"); + builder.append("import org.apache.logging.log4j.LogManager;\n"); + builder.append("import org.eclipse.emf.ecore.EClass;\n"); + builder.append("import org.eclipse.emf.ecore.EObject;\n"); + builder.append("import org.eclipse.emf.ecore.EPackage;\n"); + builder.append("import org.eclipse.emf.ecore.EReference;\n"); + builder.append("import org.eclipse.emf.ecore.resource.Resource;\n"); + builder.append("\n"); + builder.append("import org.eclipse.xtext.naming.QualifiedName;\n"); + builder.append("import org.eclipse.xtext.resource.IEObjectDescription;\n"); + builder.append("import org.eclipse.xtext.scoping.IScope;\n"); + builder.append("\n"); + builder.append("import com.avaloq.tools.ddk.xtext.scoping.AbstractNameFunction;\n"); + builder.append("import com.avaloq.tools.ddk.xtext.scoping.AbstractPolymorphicScopeProvider;\n"); + builder.append("import com.avaloq.tools.ddk.xtext.scoping.IContextSupplier;\n"); + builder.append("import com.avaloq.tools.ddk.xtext.scoping.INameFunction;\n"); + builder.append("import com.avaloq.tools.ddk.xtext.scoping.NameFunctions;\n"); + builder.append("import com.avaloq.tools.ddk.xtext.util.EObjectUtil;\n"); + builder.append("\n"); + builder.append("import com.google.common.base.Predicate;\n"); + if (!scopeProviderX.allInjections(it).isEmpty()) { + builder.append("import com.google.inject.Inject;\n"); + } + builder.append("\n"); + builder.append("@SuppressWarnings(\"all\")\n"); + builder.append("public class ").append(naming.toSimpleName(scopeProviderX.getScopeProvider(it))).append(" extends AbstractPolymorphicScopeProvider {\n"); + builder.append("\n"); + builder.append(" /** Class-wide logger. */\n"); + builder.append(" private static final Logger LOGGER = LogManager.getLogger(").append(naming.toSimpleName(scopeProviderX.getScopeProvider(it))).append(".class);\n"); + if (!scopeProviderX.allInjections(it).isEmpty()) { + for (final com.avaloq.tools.ddk.xtext.scope.scope.Injection i : scopeProviderX.allInjections(it)) { + builder.append(" @Inject\n"); + builder.append(" private ").append(i.getType()).append(" ").append(i.getName()).append(";\n"); + } + } + builder.append("\n"); + builder.append(scopeMethods(it, naming.toSimpleName(it.getName()))); + builder.append("\n"); + builder.append("}\n"); + return builder; + } + + public CharSequence scopeMethods(final ScopeModel it, final String baseName) { + final StringBuilder builder = new StringBuilder(); + + // doGetScope with EReference + builder.append(" @Override\n"); + builder.append(" protected IScope doGetScope(final EObject context, final EReference reference, final String scopeName, final Resource originalResource) {\n"); + final List refScopes = scopeProviderX.allScopes(it).stream().filter(s -> s.getReference() != null).toList(); + if (!refScopes.isEmpty()) { + builder.append(" if (scopeName == null) {\n"); + builder.append(" return null;\n"); + builder.append(" }\n"); + builder.append("\n"); + builder.append(" switch (scopeName) {\n"); + final Set refScopeNames = refScopes.stream().map(s -> scopeProviderX.getScopeName(s)).collect(Collectors.toCollection(java.util.LinkedHashSet::new)); + for (final String scopeName : refScopeNames) { + builder.append(" case \"").append(scopeName).append("\":\n"); + for (final ScopeDefinition scope : refScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(scopeName)).toList()) { + builder.append(" if (reference == ").append(genModelUtil.literalIdentifier(scope.getReference())).append(") return ").append(scopeProviderX.scopeMethodName(scope)).append("(context, reference, originalResource);\n"); + } + builder.append(" break;\n"); + } + builder.append(" default: break;\n"); + builder.append(" }\n"); + } + builder.append(" return null;\n"); + builder.append(" }\n"); + builder.append("\n"); + + // doGetScope with EClass + builder.append(" @Override\n"); + builder.append(" protected IScope doGetScope(final EObject context, final EClass type, final String scopeName, final Resource originalResource) {\n"); + final List typeScopes = scopeProviderX.allScopes(it).stream().filter(s -> s.getReference() == null).toList(); + if (!typeScopes.isEmpty()) { + builder.append(" if (scopeName == null) {\n"); + builder.append(" return null;\n"); + builder.append(" }\n"); + builder.append("\n"); + builder.append(" switch (scopeName) {\n"); + final Set typeScopeNames = typeScopes.stream().map(s -> scopeProviderX.getScopeName(s)).collect(Collectors.toCollection(java.util.LinkedHashSet::new)); + for (final String scopeName : typeScopeNames) { + builder.append(" case \"").append(scopeName).append("\":\n"); + for (final ScopeDefinition scope : typeScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(scopeName)).toList()) { + builder.append(" if (type == ").append(genModelUtil.literalIdentifier(scope.getTargetType())).append(") return ").append(scopeProviderX.scopeMethodName(scope)).append("(context, type, originalResource);\n"); + } + builder.append(" break;\n"); + } + builder.append(" default: break;\n"); + builder.append(" }\n"); + } + builder.append(" return null;\n"); + builder.append(" }\n"); + builder.append("\n"); + + // doGlobalCache with EReference + builder.append(" @Override\n"); + builder.append(" protected boolean doGlobalCache(final EObject context, final EReference reference, final String scopeName, final Resource originalResource) {\n"); + final List refGlobalScopes = refScopes.stream().filter(s -> scopeProviderX.allScopeRules(s).stream().anyMatch(r -> r.getContext().isGlobal())).toList(); + if (!refGlobalScopes.isEmpty()) { + builder.append(" if (scopeName != null && context.eContainer() == null) {\n"); + builder.append(" switch (scopeName) {\n"); + final Set refGlobalNames = refGlobalScopes.stream().map(s -> scopeProviderX.getScopeName(s)).collect(Collectors.toCollection(java.util.LinkedHashSet::new)); + for (final String scopeName : refGlobalNames) { + builder.append(" case \"").append(scopeName).append("\":\n"); + for (final ScopeDefinition scope : refScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(scopeName)).toList()) { + final List globalRules = scopeProviderX.allScopeRules(scope).stream().filter(r -> r.getContext().isGlobal()).toList(); + if (!globalRules.isEmpty()) { + builder.append(" if (reference == ").append(genModelUtil.literalIdentifier(scope.getReference())).append(") return true;\n"); + } + } + builder.append(" break;\n"); + } + builder.append(" default: break;\n"); + builder.append(" }\n"); + builder.append(" }\n"); + } + builder.append(" return false;\n"); + builder.append(" }\n"); + builder.append("\n"); + + // doGlobalCache with EClass + builder.append(" @Override\n"); + builder.append(" protected boolean doGlobalCache(final EObject context, final EClass type, final String scopeName, final Resource originalResource) {\n"); + final List typeGlobalScopes = typeScopes.stream().filter(s -> scopeProviderX.allScopeRules(s).stream().anyMatch(r -> r.getContext().isGlobal())).toList(); + if (!typeGlobalScopes.isEmpty()) { + builder.append(" if (context.eContainer() == null) {\n"); + builder.append(" switch (scopeName) {\n"); + final Set typeGlobalNames = typeGlobalScopes.stream().map(s -> scopeProviderX.getScopeName(s)).collect(Collectors.toCollection(java.util.LinkedHashSet::new)); + for (final String scopeName : typeGlobalNames) { + builder.append(" case \"").append(scopeName).append("\":\n"); + for (final ScopeDefinition scope : typeScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(scopeName)).toList()) { + final List globalRules = scopeProviderX.allScopeRules(scope).stream().filter(r -> r.getContext().isGlobal()).toList(); + if (!globalRules.isEmpty()) { + builder.append(" if (type == ").append(genModelUtil.literalIdentifier(scope.getTargetType())).append(") return true;\n"); + } + } + builder.append(" break;\n"); + } + builder.append(" default: break;\n"); + builder.append(" }\n"); + builder.append(" }\n"); + } + builder.append(" return false;\n"); + builder.append(" }\n"); + builder.append("\n"); + + // Per-scope methods + for (final ScopeDefinition scope : scopeProviderX.allScopes(it)) { + builder.append(" protected IScope ").append(scopeProviderX.scopeMethodName(scope)).append("(final EObject context, final "); + if (scope.getReference() != null) { + builder.append("EReference ref"); + } else { + builder.append("EClass type"); + } + builder.append(", final Resource originalResource) {\n"); + final List localRules = scopeProviderX.allScopeRules(scope).stream().filter(r -> !r.getContext().isGlobal()).toList(); + final List globalRules = scopeProviderX.allScopeRules(scope).stream().filter(r -> r.getContext().isGlobal()).toList(); + if (globalRules.size() > 1) { + throw new RuntimeException("only one global rule allowed"); + } + for (final ScopeRule r : scopeProviderX.sortedRules(scopeProviderX.filterUniqueRules(new ArrayList<>(localRules)))) { + builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append("\n"); + if (EClassComparator.isEObjectType(r.getContext().getContextType())) { + builder.append(" if (true) {\n"); + } else { + builder.append(" if (context instanceof ").append(genModelUtil.instanceClassName(r.getContext().getContextType())).append(") {\n"); + } + builder.append(" final ").append(genModelUtil.instanceClassName(r.getContext().getContextType())).append(" ctx = (").append(genModelUtil.instanceClassName(r.getContext().getContextType())).append(") context;\n"); + final List rulesForTypeAndContext = localRules.stream().filter(r2 -> scopeProviderX.hasSameContext(r2, r)).toList(); + builder.append(scopeRuleBlock(rulesForTypeAndContext, it, scopeProviderX.contextRef(r) != null ? "ref" : "type", r.getContext().getContextType(), r.getContext().isGlobal())); + builder.append(" }\n"); + } + if (!localRules.isEmpty() || !globalRules.isEmpty()) { + builder.append("\n"); + builder.append(" final EObject eContainer = context.eContainer();\n"); + builder.append(" if (eContainer != null) {\n"); + builder.append(" return internalGetScope("); + if (!localRules.isEmpty()) { + builder.append("eContainer"); + } else { + builder.append("getRootObject(eContainer)"); + } + builder.append(", "); + if (scope.getReference() != null) { + builder.append("ref"); + } else { + builder.append("type"); + } + builder.append(", \"").append(scopeProviderX.getScopeName(scope)).append("\", originalResource);\n"); + builder.append(" }\n"); + builder.append("\n"); + } + if (!globalRules.isEmpty()) { + final ScopeRule r = globalRules.get(0); + final List rulesForTypeAndContext = List.of(r); + builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append("\n"); + builder.append(" if (context.eResource() != null) {\n"); + builder.append(" final Resource ctx = context.eResource();\n"); + builder.append(scopeRuleBlock(rulesForTypeAndContext, it, scopeProviderX.contextRef(r) != null ? "ref" : "type", r.getContext().getContextType(), r.getContext().isGlobal())); + builder.append(" }\n"); + builder.append("\n"); + } + builder.append(" return null;\n"); + builder.append(" }\n"); + builder.append("\n"); + } + + return builder; + } + + public CharSequence scopeRuleBlock(final List it, final ScopeModel model, final String typeOrRef, final EClass contextType, final Boolean isGlobal) { + final StringBuilder builder = new StringBuilder(); + builder.append(" IScope scope = IScope.NULLSCOPE;\n"); + builder.append(" try {\n"); + if (it.stream().anyMatch(r -> r.getContext().getGuard() != null)) { + boolean first = true; + final List sorted = it.stream() + .sorted(Comparator.comparingInt(r -> r.getContext().getGuard() == null ? it.size() : it.indexOf(r))) + .toList(); + for (final ScopeRule r : sorted) { + if (!first) { + builder.append(" else "); + } else { + builder.append(" "); + first = false; + } + if (r.getContext().getGuard() != null) { + builder.append("if (").append(codeGenerationX.javaExpression(r.getContext().getGuard(), compilationContext.clone("ctx", scopeProviderX.scopeType(r)))).append(") "); + } + builder.append("{\n"); + if (it.size() > 1) { + builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append("\n"); + } + final List reversed = Lists.newArrayList(r.getExprs()); + Collections.reverse(reversed); + for (final ScopeExpression e : reversed) { + builder.append(scopeExpression(e, model, typeOrRef, scopeProviderX.getScope(r), isGlobal)); + } + builder.append(" }"); + } + if (it.stream().noneMatch(r -> r.getContext().getGuard() == null)) { + builder.append(" else {\n"); + builder.append(" throw new UnsupportedOperationException(); // continue matching other definitions\n"); + builder.append(" }"); + } + builder.append("\n"); + } else if (it.size() == 1) { + final List reversed = Lists.newArrayList(it.get(0).getExprs()); + Collections.reverse(reversed); + for (final ScopeExpression e : reversed) { + builder.append(scopeExpression(e, model, typeOrRef, scopeProviderX.getScope(it.get(0)), isGlobal)); + } + } else { + final List locations = new ArrayList<>(); + for (final ScopeRule r : it) { + locations.add(generatorUtilX.location(r)); + } + error("scope context not unique for definitions: " + String.join(", ", locations)); + } + builder.append(" } catch (Exception e) {\n"); + builder.append(" LOGGER.error(\"Error calculating scope for "); + if (isGlobal) { + builder.append("Resource. Context:"); + } else { + builder.append(contextType.getName()); + } + builder.append(" \" + EObjectUtil.getLocationString(context) + \" (").append(scopeProviderX.locatorString(it.get(0))).append(")\", e);\n"); + builder.append(" }\n"); + builder.append(" return scope;\n"); + return builder; + } + + // dispatch scopeExpression + protected CharSequence _scopeExpression(final ScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { + return error("Xtend called the wrong definition." + it.toString() + generatorUtilX.javaContributorComment(generatorUtilX.location(it))); + } + + protected CharSequence _scopeExpression(final FactoryExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { + final StringBuilder b = new StringBuilder(); + final CompilationContext ctx = compilationContext.clone("ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType()); + b.append("scope = ").append(javaCall(it.getExpr(), ctx)).append("(scope, ctx, ").append(typeOrRef).append(", originalResource"); + if (it.getExpr() instanceof OperationCall operationCall) { + for (final Expression param : operationCall.getParams()) { + b.append(", ").append(codeGenerationX.javaExpression(param, ctx)); + } + } + b.append(");\n"); + return b; + } + + // dispatch javaCall + protected String _javaCall(final Expression it, final CompilationContext ctx) { + return error("cannot handle scope factory " + it.toString()); + } + + protected String _javaCall(final OperationCall it, final CompilationContext ctx) { + if (codeGenerationX.isJavaExtensionCall(it, ctx)) { + return codeGenerationX.calledJavaMethod(it, ctx); + } else { + return "/* Error: cannot handle scope factory " + it.toString() + " */"; + } + } + + public String javaCall(final Expression it, final CompilationContext ctx) { + if (it instanceof OperationCall operationCall) { + return _javaCall(operationCall, ctx); + } else if (it != null) { + return _javaCall(it, ctx); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + it); + } + } + + protected CharSequence _scopeExpression(final ScopeDelegation it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { + final StringBuilder builder = new StringBuilder(); + if (it.getDelegate() != null) { + final String delegateString = expressionExtensionsX.serialize(it.getDelegate()); + if ("this.eContainer()".equals(delegateString) || "this.eContainer".equals(delegateString) || "eContainer()".equals(delegateString) || "eContainer".equals(delegateString)) { + builder.append(" scope = newSameScope(\"").append(scopeProviderX.locatorString(it)).append("\", scope, ctx.eContainer()"); + } else if ("this".equals(delegateString)) { + builder.append(" scope = newSameScope(\"").append(scopeProviderX.locatorString(it)).append("\", scope, ctx"); + } else { + builder.append(" scope = newDelegateScope(\"").append(scopeProviderX.locatorString(it)).append("\", scope, "); + if (!isGlobal) { + builder.append("() -> IContextSupplier.makeIterable(").append(scopedElements(it.getDelegate(), model, scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType(), "ctx")).append(")"); + } else { + builder.append(scopedElements(it.getDelegate(), model, scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType(), "ctx")); + } + } + } else { + builder.append(" scope = newExternalDelegateScope(\"").append(scopeProviderX.locatorString(it)).append("\", scope, "); + builder.append(query(it.getExternal(), model, typeOrRef, scope)).append(".execute(originalResource)"); + } + builder.append(", "); + if (it.getScope() != null && scopeProviderX.typeOrRef(it.getScope()) != scopeProviderX.typeOrRef(scopeProviderX.getScope(it))) { + builder.append(genModelUtil.literalIdentifier(scopeProviderX.typeOrRef(it.getScope()))); + } else { + builder.append(typeOrRef); + } + builder.append(", \""); + if (it.getScope() != null && it.getScope().getName() != null) { + builder.append(it.getScope().getName()); + } else { + builder.append("scope"); + } + builder.append("\", originalResource);\n"); + return builder; + } + + protected CharSequence _scopeExpression(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { + final StringBuilder builder = new StringBuilder(); + builder.append(" scope = ").append(scopeExpressionPart(it, model, typeOrRef, scope)); + builder.append(scopeExpressionNaming(it, model, typeOrRef, scope)); + builder.append(scopeExpressionCasing(it, model, typeOrRef, scope)).append(");\n"); + return builder; + } + + protected CharSequence _scopeExpression(final SimpleScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { + final StringBuilder builder = new StringBuilder(); + if (expressionExtensionsX.isEmptyList(it.getExpr())) { + builder.append(" // Empty scope from ").append(generatorUtilX.location(it)).append("\n"); + } else { + builder.append(" scope = ").append(scopeExpressionPart(it, model, typeOrRef, scope)); + builder.append(scopeExpressionNaming(it, model, typeOrRef, scope)); + builder.append(scopeExpressionCasing(it, model, typeOrRef, scope)).append(");\n"); + } + return builder; + } + + public CharSequence scopeExpression(final ScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { + if (it instanceof FactoryExpression factoryExpression) { + return _scopeExpression(factoryExpression, model, typeOrRef, scope, isGlobal); + } else if (it instanceof ScopeDelegation scopeDelegation) { + return _scopeExpression(scopeDelegation, model, typeOrRef, scope, isGlobal); + } else if (it instanceof SimpleScopeExpression simpleScopeExpression) { + return _scopeExpression(simpleScopeExpression, model, typeOrRef, scope, isGlobal); + } else if (it instanceof GlobalScopeExpression) { + // GlobalScopeExpression extends NamedScopeExpression, must be checked first + return _scopeExpression((NamedScopeExpression) it, model, typeOrRef, scope, isGlobal); + } else if (it instanceof NamedScopeExpression namedScopeExpression) { + return _scopeExpression(namedScopeExpression, model, typeOrRef, scope, isGlobal); + } else if (it != null) { + return _scopeExpression(it, model, typeOrRef, scope, isGlobal); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + it); + } + } + + // dispatch scopeExpressionPart + protected String _scopeExpressionPart(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + return error("Xtend called the wrong definition for scopeExpressionPart with this=" + it.toString() + generatorUtilX.javaContributorComment(generatorUtilX.location(it))); + } + + protected String _scopeExpressionPart(final SimpleScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + return "newSimpleScope(\"" + scopeProviderX.locatorString(it) + "\", scope, " + scopedElements(it.getExpr(), model, scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType(), "ctx") + ", "; + } + + protected CharSequence _scopeExpressionPart(final GlobalScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + final StringBuilder builder = new StringBuilder(); + final List matchData = new ArrayList<>(); + for (final Object d : it.getData()) { + if (d instanceof LambdaDataExpression lambdaDataExpression) { + matchData.add(lambdaDataExpression); + } + } + builder.append("\n"); + if (matchData.isEmpty() && it.getPrefix() == null) { + builder.append("newContainerScope("); + } else if (matchData.isEmpty() && it.getPrefix() != null) { + builder.append("newPrefixedContainerScope("); + } else { + builder.append("newDataMatchScope("); + } + builder.append("\"").append(scopeProviderX.locatorString(it)).append("\", scope, ctx, "); + builder.append(query(it, model, typeOrRef, scope)).append(", originalResource"); + if (!matchData.isEmpty()) { + builder.append(", //\n"); + builder.append(" Arrays.asList(\n"); + boolean firstData = true; + for (final LambdaDataExpression d : matchData) { + if (!firstData) { + builder.append(",\n"); + } + firstData = false; + final CompilationContext cc = compilationContext.cloneWithVariable("ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType(), d.getDesc(), "org::eclipse::xtext::resource::IEObjectDescription"); + if (codeGenerationX.isCompilable(d.getValue(), cc.clone("ctx"))) { + builder.append(" ").append(d.getDesc()).append(" -> ").append(codeGenerationX.javaExpression(d.getValue(), cc.clone("ctx"))); + } else { + builder.append(" ").append(d.getDesc()).append(" -> EXPRESSION_NOT_SUPPORTED(\"").append(expressionExtensionsX.serialize(it)).append("\")"); + } + } + builder.append(" )"); + } else if (it.getPrefix() != null) { + builder.append(", ").append(doExpression(it.getPrefix(), model, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType())); + builder.append(", ").append(it.isRecursivePrefix()); + } + return builder; + } + + public CharSequence scopeExpressionPart(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + if (it instanceof GlobalScopeExpression globalScopeExpression) { + return _scopeExpressionPart(globalScopeExpression, model, typeOrRef, scope); + } else if (it instanceof SimpleScopeExpression simpleScopeExpression) { + return _scopeExpressionPart(simpleScopeExpression, model, typeOrRef, scope); + } else if (it != null) { + return _scopeExpressionPart(it, model, typeOrRef, scope); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + it); + } + } + + public CharSequence query(final GlobalScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + final StringBuilder builder = new StringBuilder(); + builder.append("newQuery(").append(genModelUtil.literalIdentifier(it.getType())).append(")"); + final List matchData = new ArrayList<>(); + for (final Object d : it.getData()) { + if (d instanceof MatchDataExpression matchDataExpression) { + matchData.add(matchDataExpression); + } + } + if (it.getName() != null) { + builder.append(".name(").append(doExpression(it.getName(), model, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType())).append(")"); + } + if (!matchData.isEmpty()) { + for (final MatchDataExpression d : matchData) { + builder.append(".data(\"").append(codeGenerationX.javaEncode(d.getKey())).append("\", ").append(doExpression(d.getValue(), model, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType())).append(")"); + } + } + if (!it.getDomains().isEmpty() && !"*".equals(it.getDomains().get(0))) { + builder.append(".domains("); + boolean firstDomain = true; + for (final String d : it.getDomains()) { + if (!firstDomain) { + builder.append(", "); + } + firstDomain = false; + builder.append("\"").append(codeGenerationX.javaEncode(d)).append("\""); + } + builder.append(")"); + } + return builder; + } + + // dispatch scopeExpressionNaming + protected String _scopeExpressionNaming(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + return error("Xtend called the wrong definition for scopeExpressionNaming with this=" + it.toString() + generatorUtilX.javaContributorComment(generatorUtilX.location(it))); + } + + protected String _scopeExpressionNaming(final SimpleScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + return name(it, model, typeOrRef, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType()); + } + + protected String _scopeExpressionNaming(final GlobalScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + return ", " + name(it, model, typeOrRef, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType()); + } + + public String scopeExpressionNaming(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + if (it instanceof GlobalScopeExpression globalScopeExpression) { + return _scopeExpressionNaming(globalScopeExpression, model, typeOrRef, scope); + } else if (it instanceof SimpleScopeExpression simpleScopeExpression) { + return _scopeExpressionNaming(simpleScopeExpression, model, typeOrRef, scope); + } else if (it != null) { + return _scopeExpressionNaming(it, model, typeOrRef, scope); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + it); + } + } + + public String scopeExpressionCasing(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { + return ", " + Boolean.toString(scopeProviderX.isCaseInsensitive(it)); + } + + public String scopedElements(final Expression it, final ScopeModel model, final EClass type, final String object) { + return doExpression(it, model, object, type); + } + + public String doExpression(final Expression it, final ScopeModel model, final String object, final EClass type) { + return codeGenerationX.javaExpression(it, compilationContext.clone(object, type)); + } + + public String name(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final String contextName, final EClass contextType) { + if (it.getNaming() != null) { + return nameProviderGenerator.nameFunctions(it.getNaming(), model, contextName, contextType).toString(); + } else { + return "getNameFunctions(" + typeOrRef + ")"; + } + } + + public String error(final String message) { + throw new RuntimeException(message); + } +} diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.xtend b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.xtend deleted file mode 100644 index cf57184807..0000000000 --- a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.xtend +++ /dev/null @@ -1,386 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. it program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies it distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.scope.generator - -import com.avaloq.tools.ddk.xtext.expression.expression.Expression -import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall -import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX -import com.avaloq.tools.ddk.xtext.expression.generator.CompilationContext -import com.avaloq.tools.ddk.xtext.expression.generator.EClassComparator -import com.avaloq.tools.ddk.xtext.expression.generator.ExpressionExtensionsX -import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.avaloq.tools.ddk.xtext.scope.scope.FactoryExpression -import com.avaloq.tools.ddk.xtext.scope.scope.GlobalScopeExpression -import com.avaloq.tools.ddk.xtext.scope.scope.LambdaDataExpression -import com.avaloq.tools.ddk.xtext.scope.scope.MatchDataExpression -import com.avaloq.tools.ddk.xtext.scope.scope.NamedScopeExpression -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeDefinition -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeDelegation -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeExpression -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeModel -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeRule -import com.avaloq.tools.ddk.xtext.scope.scope.SimpleScopeExpression -import com.google.common.collect.Lists -import com.google.inject.Inject -import java.util.List -import org.eclipse.emf.ecore.EClass - -class ScopeProviderGenerator { - - @Inject extension CodeGenerationX - @Inject extension ExpressionExtensionsX - @Inject extension GeneratorUtilX - @Inject extension Naming - @Inject extension ScopeProviderX - - ScopeNameProviderGenerator nameProviderGenerator - CompilationContext compilationContext - extension GenModelUtilX genModelUtil - - def generate(ScopeModel it, ScopeNameProviderGenerator nameProviderGenerator, CompilationContext compilationContext, GenModelUtilX genModelUtil) { - this.nameProviderGenerator = nameProviderGenerator - this.compilationContext = compilationContext - this.genModelUtil = genModelUtil - ''' - package «getScopeProvider().toJavaPackage()»; - - import java.util.Arrays; - - import org.apache.logging.log4j.Logger; - import org.apache.logging.log4j.LogManager; - import org.eclipse.emf.ecore.EClass; - import org.eclipse.emf.ecore.EObject; - import org.eclipse.emf.ecore.EPackage; - import org.eclipse.emf.ecore.EReference; - import org.eclipse.emf.ecore.resource.Resource; - - import org.eclipse.xtext.naming.QualifiedName; - import org.eclipse.xtext.resource.IEObjectDescription; - import org.eclipse.xtext.scoping.IScope; - - import com.avaloq.tools.ddk.xtext.scoping.AbstractNameFunction; - import com.avaloq.tools.ddk.xtext.scoping.AbstractPolymorphicScopeProvider; - import com.avaloq.tools.ddk.xtext.scoping.IContextSupplier; - import com.avaloq.tools.ddk.xtext.scoping.INameFunction; - import com.avaloq.tools.ddk.xtext.scoping.NameFunctions; - import com.avaloq.tools.ddk.xtext.util.EObjectUtil; - - import com.google.common.base.Predicate; - «IF !allInjections().isEmpty» - import com.google.inject.Inject; - «ENDIF» - - @SuppressWarnings("all") - public class «getScopeProvider().toSimpleName()» extends AbstractPolymorphicScopeProvider { - - /** Class-wide logger. */ - private static final Logger LOGGER = LogManager.getLogger(«getScopeProvider().toSimpleName()».class); - «IF !allInjections().isEmpty» - «FOR i : allInjections()» - @Inject - private «i.type» «i.name»; - «ENDFOR» - «ENDIF» - - «scopeMethods(it, name.toSimpleName())» - - } - ''' - } - - def scopeMethods(ScopeModel it, String baseName) ''' - @Override - protected IScope doGetScope(final EObject context, final EReference reference, final String scopeName, final Resource originalResource) { - «IF !allScopes().filter(s|s.reference !== null).empty» - if (scopeName == null) { - return null; - } - - switch (scopeName) { - «FOR name : allScopes().filter(s|s.reference !== null).map(s|s.getScopeName()).toSet() - »case "«name»": - «FOR scope : allScopes().filter(s|s.reference !== null).filter(s|s.getScopeName()==name)» - if (reference == «scope.reference.literalIdentifier()») return «scope.scopeMethodName()»(context, reference, originalResource); - «ENDFOR» - break; - « - ENDFOR» - default: break; - } - «ENDIF» - return null; - } - - @Override - protected IScope doGetScope(final EObject context, final EClass type, final String scopeName, final Resource originalResource) { - «IF !allScopes().filter(s|s.reference === null).empty» - if (scopeName == null) { - return null; - } - - switch (scopeName) { - «FOR name : allScopes().filter(s|s.reference === null).map(s|s.getScopeName()).toSet() - »case "«name»": - «FOR scope : allScopes().filter(s|s.reference === null).filter(s|s.getScopeName()==name)» - if (type == «scope.targetType.literalIdentifier()») return «scope.scopeMethodName()»(context, type, originalResource); - «ENDFOR» - break; - « - ENDFOR» - default: break; - } - «ENDIF» - return null; - } - - @Override - protected boolean doGlobalCache(final EObject context, final EReference reference, final String scopeName, final Resource originalResource) { - «IF !allScopes().filter(s|s.reference !== null).filter(s|s.allScopeRules().filter(r|r.context.global).size > 0).empty» - if (scopeName != null && context.eContainer() == null) { - switch (scopeName) { - «FOR name : allScopes().filter(s|s.reference !== null).filter(s|s.allScopeRules().filter(r|r.context.global).size > 0).map(s|s.getScopeName()).toSet() - »case "«name»": - «FOR scope : allScopes().filter(s|s.reference !== null).filter(s|s.getScopeName()==name)» - «val globalRules = scope.allScopeRules().filter(r|r.context.global)» - «IF globalRules.size > 0» - if (reference == «scope.reference.literalIdentifier()») return true; - «ENDIF» - «ENDFOR» - break; - « - ENDFOR» - default: break; - } - } - «ENDIF» - return false; - } - - @Override - protected boolean doGlobalCache(final EObject context, final EClass type, final String scopeName, final Resource originalResource) { - «IF !allScopes().filter(s|s.reference === null).filter(s|s.allScopeRules().filter(r|r.context.global).size > 0).empty» - if (context.eContainer() == null) { - switch (scopeName) { - «FOR name : allScopes().filter(s|s.reference === null).filter(s|s.allScopeRules().filter(r|r.context.global).size > 0).map(s|s.getScopeName()).toSet() - »case "«name»": - «FOR scope : allScopes().filter(s|s.reference === null).filter(s|s.getScopeName()==name)» - «val globalRules = scope.allScopeRules().filter(r|r.context.global)» - «IF globalRules.size > 0» - if (type == «scope.targetType.literalIdentifier()») return true; - «ENDIF» - «ENDFOR» - break; - « - ENDFOR» - default: break; - } - } - «ENDIF» - return false; - } - - «FOR scope : allScopes()» - protected IScope «scope.scopeMethodName()»(final EObject context, final «IF scope.reference !== null»EReference ref«ELSE»EClass type«ENDIF», final Resource originalResource) { - «val localRules = scope.allScopeRules().filter(r|!r.context.global).toList» - «val globalRules = scope.allScopeRules().filter(r|r.context.global).toList» - «if (globalRules.size > 1) throw new RuntimeException("only one global rule allowed")» - «FOR r : localRules.filterUniqueRules().sortedRules()» - «javaContributorComment(r.location())» - if («IF EClassComparator.isEObjectType(r.context.contextType)»true«ELSE»context instanceof «r.context.contextType.instanceClassName()»«ENDIF») { - final «r.context.contextType.instanceClassName()» ctx = («r.context.contextType.instanceClassName()») context; - «val rulesForTypeAndContext = localRules.filter(r2|r2.hasSameContext(r)).toList» - «scopeRuleBlock(rulesForTypeAndContext, it, if (r.contextRef() !== null) 'ref' else 'type', r.context.contextType, r.context.global)» - } - «ENDFOR» - «IF !localRules.isEmpty || !globalRules.isEmpty» - - final EObject eContainer = context.eContainer(); - if (eContainer != null) { - return internalGetScope(«IF !localRules.isEmpty»eContainer«ELSE»getRootObject(eContainer)«ENDIF», «IF scope.reference !== null»ref«ELSE»type«ENDIF», "«scope.getScopeName()»", originalResource); - } - - «ENDIF» - «IF !globalRules.isEmpty» - «val r = globalRules.head» - «val rulesForTypeAndContext = #[r]» - «javaContributorComment(r.location())» - if (context.eResource() != null) { - final Resource ctx = context.eResource(); - «scopeRuleBlock(rulesForTypeAndContext, it, if (r.contextRef() !== null) 'ref' else 'type', r.context.contextType, r.context.global)» - } - - «ENDIF» - return null; - } - - «ENDFOR» - ''' - - def scopeRuleBlock(List it, ScopeModel model, String typeOrRef, EClass contextType, Boolean isGlobal) ''' - IScope scope = IScope.NULLSCOPE; - try { - «IF it.exists(r|r.context.guard !== null)» - «FOR r : it.sortBy(r|if (r.context.guard === null) it.size else it.indexOf(r)) SEPARATOR ' else ' - »«IF r.context.guard !== null»if («r.context.guard.javaExpression(compilationContext.clone('ctx', r.scopeType()))») «ENDIF»{ - «IF it.size > 1»«javaContributorComment(r.location())» - «ENDIF - »«FOR e : Lists.newArrayList(r.exprs).reverse()»«scopeExpression(e, model, typeOrRef, r.getScope(), isGlobal)»«ENDFOR» - }«ENDFOR»« - IF !it.exists(r|r.context.guard === null)» else { - throw new UnsupportedOperationException(); // continue matching other definitions - }«ENDIF» - «ELSEIF it.size == 1» - «FOR e : Lists.newArrayList(it.head.exprs).reverse()»«scopeExpression(e, model, typeOrRef, it.head.getScope(), isGlobal)»«ENDFOR» - «ELSE» - «error('scope context not unique for definitions: ' + ', '.join(it.map(r|r.location())))» - «ENDIF» - } catch (Exception e) { - LOGGER.error("Error calculating scope for «if (isGlobal) "Resource. Context:" else contextType.name» " + EObjectUtil.getLocationString(context) + " («it.get(0).locatorString()»)", e); - } - return scope; - ''' - - def dispatch scopeExpression(ScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope, Boolean isGlobal) { - error("Xtend called the wrong definition." + it.toString() + javaContributorComment(it.location())) - } - - def dispatch scopeExpression(FactoryExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope, Boolean isGlobal) { - val b = new StringBuilder - val ctx = compilationContext.clone('ctx', eContainer(ScopeRule).context.contextType) - b.append('scope = ').append(javaCall(it.expr, ctx)).append('(scope, ctx, ').append(typeOrRef).append(', originalResource'); - if (expr instanceof OperationCall) { - for (param : (expr as OperationCall).params) { - b.append(', ').append(javaExpression(param, ctx)) - } - } - b.append(');\n') - return b - } - - def dispatch javaCall(Expression it, CompilationContext ctx) { - error('cannot handle scope factory ' + it.toString()) - } - - def dispatch javaCall(OperationCall it, CompilationContext ctx) { - if (isJavaExtensionCall(ctx)) - calledJavaMethod(ctx) - else - '/* Error: cannot handle scope factory ' + it.toString() + ' */' - } - - def dispatch scopeExpression(ScopeDelegation it, ScopeModel model, String typeOrRef, ScopeDefinition scope, Boolean isGlobal) ''' - «IF delegate !== null » - «val delegateString = delegate.serialize()» - «IF delegateString == "this.eContainer()" || delegateString == "this.eContainer" || delegateString == "eContainer()" || delegateString == "eContainer"» - scope = newSameScope("«it.locatorString()»", scope, ctx.eContainer()« - ELSEIF delegateString == "this"» - scope = newSameScope("«it.locatorString()»", scope, ctx« - ELSE» - scope = newDelegateScope("«it.locatorString()»", scope, « - IF !isGlobal »() -> IContextSupplier.makeIterable(«scopedElements(delegate, model, eContainer(ScopeRule).context.contextType, 'ctx')»)« - ELSE»«scopedElements(delegate, model, eContainer(ScopeRule).context.contextType, 'ctx')»« - ENDIF»« - ENDIF»« - ELSE» - scope = newExternalDelegateScope("«it.locatorString()»", scope, « - query(external, model, typeOrRef, scope)».execute(originalResource)« - ENDIF», « - IF it.scope !== null && it.scope.typeOrRef() != getScope(it).typeOrRef()»«it.scope.typeOrRef().literalIdentifier()»«ELSE»«typeOrRef»«ENDIF», "«if (it.scope !== null && it.scope.name !== null) it.scope.name else "scope"»", originalResource); - ''' - - def dispatch scopeExpression(NamedScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope, Boolean isGlobal) ''' - scope = «scopeExpressionPart (it, model, typeOrRef, scope)»« - scopeExpressionNaming (it, model, typeOrRef, scope)»« - scopeExpressionCasing (it, model, typeOrRef, scope)»); - ''' - - def dispatch scopeExpression(SimpleScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope, Boolean isGlobal) ''' - «IF expr.isEmptyList() » - // Empty scope from «it.location()» - «ELSE» - scope = «scopeExpressionPart (it, model, typeOrRef, scope)»« - scopeExpressionNaming (it, model, typeOrRef, scope)»« - scopeExpressionCasing (it, model, typeOrRef, scope)»); - «ENDIF» - ''' - - def dispatch scopeExpressionPart (NamedScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope) { - error("Xtend called the wrong definition for scopeExpressionPart with this=" + it.toString() + javaContributorComment(it.location())) - } - - def dispatch scopeExpressionPart (SimpleScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope) { - 'newSimpleScope("' + locatorString() + '", scope, ' + scopedElements(expr, model, eContainer(ScopeRule).context.contextType, "ctx") + ', ' - } - - def query (GlobalScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope) ''' - newQuery(«type.literalIdentifier()»)« - val matchData = data.filter(MatchDataExpression)»« - IF name !== null».name(«doExpression (name, model, 'ctx', eContainer(ScopeRule).context.contextType)»)«ENDIF»« - IF !matchData.isEmpty»«FOR d : matchData».data("«javaEncode(d.key)»", «doExpression (d.value, model, 'ctx', eContainer(ScopeRule).context.contextType)»)«ENDFOR»«ENDIF»« - IF !domains.isEmpty && domains.get(0) != "*"».domains(«FOR d : domains SEPARATOR ", "»"«javaEncode(d)»"«ENDFOR»)«ENDIF - »''' - - def dispatch scopeExpressionPart (GlobalScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope) ''' - «val matchData = data.filter(LambdaDataExpression)» - «IF matchData.isEmpty && prefix === null»newContainerScope(«ELSEIF matchData.isEmpty && prefix !== null»newPrefixedContainerScope(«ELSE»newDataMatchScope(«ENDIF»"«it.locatorString()»", scope, ctx, «query (it, model, typeOrRef, scope)», originalResource« - IF !matchData.isEmpty», // - Arrays.asList( - «FOR d : matchData SEPARATOR ","» - «val CompilationContext cc = compilationContext.cloneWithVariable('ctx', eContainer(ScopeRule).context.contextType, d.desc, 'org::eclipse::xtext::resource::IEObjectDescription')» - «IF d.value.isCompilable(cc.clone('ctx'))» - «d.desc» -> «d.value.javaExpression(cc.clone('ctx'))» - «ELSE» - «d.desc» -> EXPRESSION_NOT_SUPPORTED("«serialize()»") - «ENDIF»« - ENDFOR» )« - ELSEIF prefix !== null», «doExpression (prefix, model, 'ctx', eContainer(ScopeRule).context.contextType)», «recursivePrefix»« - ENDIF - »''' - - def dispatch scopeExpressionNaming (NamedScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope) { - error("Xtend called the wrong definition for scopeExpressionNaming with this=" + it.toString() + javaContributorComment(it.location())) - } - - def dispatch scopeExpressionNaming (SimpleScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope) { - name(it, model, typeOrRef, 'ctx', eContainer(ScopeRule).context.contextType) - } - - def dispatch scopeExpressionNaming (GlobalScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope) { - ', ' + name(it, model, typeOrRef, 'ctx', eContainer(ScopeRule).context.contextType) - } - - def scopeExpressionCasing (NamedScopeExpression it, ScopeModel model, String typeOrRef, ScopeDefinition scope) { - ', ' + isCaseInsensitive().toString - } - - def scopedElements(Expression it, ScopeModel model, EClass type, String object) { - doExpression(it, model, object, type) - } - - def doExpression(Expression it, ScopeModel model, String object, EClass type) { - javaExpression (compilationContext.clone(object, type)) - } - - def name(NamedScopeExpression it, ScopeModel model, String typeOrRef, String contextName, EClass contextType) { - if (it.naming !== null) - nameProviderGenerator.nameFunctions(it.naming, model, contextName, contextType) - else - 'getNameFunctions(' + typeOrRef + ')' - } - - def error(String message) { - throw new RuntimeException(message) - } - -} diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.java b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.java new file mode 100644 index 0000000000..7fb20c555b --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.java @@ -0,0 +1,379 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. it program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies it distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.scope.generator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.avaloq.tools.ddk.xtext.expression.expression.Expression; +import com.avaloq.tools.ddk.xtext.expression.expression.FeatureCall; +import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX; +import com.avaloq.tools.ddk.xtext.expression.generator.ExpressionExtensionsX; +import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX; +import com.avaloq.tools.ddk.xtext.expression.generator.Naming; +import com.avaloq.tools.ddk.xtext.scope.ScopeUtil; +import com.avaloq.tools.ddk.xtext.scope.scope.Injection; +import com.avaloq.tools.ddk.xtext.scope.scope.NamedScopeExpression; +import com.avaloq.tools.ddk.xtext.scope.scope.NamingDefinition; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeDefinition; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeModel; +import com.avaloq.tools.ddk.xtext.scope.scope.ScopeRule; +import com.google.inject.Inject; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; + +public class ScopeProviderX { + + @Inject + private Naming naming; + @Inject + private GeneratorUtilX generatorUtilX; + @Inject + private CodeGenerationX codeGenerationX; + @Inject + private ExpressionExtensionsX expressionExtensionsX; + + /* + * CODE GENERATION + */ + public String getScopeProvider(final ScopeModel model) { + return naming.toJavaPackage(model.getName()) + ".scoping." + naming.toSimpleName(model.getName()) + "ScopeProvider"; + } + + public String getScopeNameProvider(final ScopeModel model) { + return naming.toJavaPackage(model.getName()) + ".scoping." + naming.toSimpleName(model.getName()) + "ScopeNameProvider"; + } + + // returns the name of the scope method generated for the given scope definition + public String scopeMethodName(final ScopeDefinition it) { + return getScopeName(it) + "_" + (it.getTargetType() != null ? it.getTargetType().getEPackage().getName() + "_" + it.getTargetType().getName() : it.getContextType().getEPackage().getName() + "_" + it.getContextType().getName() + "_" + it.getReference().getName()); + } + + public String locatorString(final EObject it) { + final String location = generatorUtilX.location(it); + final String[] parts = location.split("/"); + final String last = parts.length > 0 ? parts[parts.length - 1] : null; + return codeGenerationX.javaEncode(last); + } + + public String calledFeature(final FeatureCall it) { + return it.getType().getId().get(0); + } + + public EStructuralFeature feature(final FeatureCall it) { + return scopeType(it).getEStructuralFeature(calledFeature(it)); + } + + /* + * SCOPE RULES + */ + // dispatch allScopeRules + protected List _allScopeRules(final Void it) { + return new ArrayList<>(); + } + + protected List _allScopeRules(final ScopeDefinition it) { + return collectAllScopeRules(getModel(it), it); + } + + public List allScopeRules(final ScopeDefinition it) { + if (it != null) { + return _allScopeRules(it); + } else { + return _allScopeRules((Void) null); + } + } + + public List collectAllScopeRules(final ScopeModel it, final ScopeDefinition def) { + final List myScopeRules = new ArrayList<>(); + for (final ScopeDefinition d : it.getScopes()) { + if (isEqual(d, def)) { + myScopeRules.addAll(d.getRules()); + } + } + final List result; + if (it.getIncludedScopes().isEmpty()) { + result = new ArrayList<>(); + } else { + result = new ArrayList<>(); + for (final ScopeModel included : it.getIncludedScopes()) { + result.addAll(collectAllScopeRules(included, def)); + } + } + result.addAll(myScopeRules); + return result; + } + + public List sortedRules(final Collection it) { + return ScopingGeneratorUtil.sortedRules(it); + } + + public Set filterUniqueRules(final List it) { + return it.stream() + .map(r -> it.stream().filter(r2 -> hasSameContext(r2, r)).findFirst().orElse(null)) + .collect(Collectors.toSet()); + } + + // dispatch isEqual(ScopeRule, ScopeRule) + protected boolean _isEqual(final ScopeRule a, final ScopeRule b) { + return hasSameContext(a, b) + // && ((a.name === null) == (b.name === null)) && (a.name === null || a.name.matches (b.name)) + && Objects.equals(expressionExtensionsX.serialize(a.getContext().getGuard()), expressionExtensionsX.serialize(b.getContext().getGuard())); + } + + public boolean hasSameContext(final ScopeRule a, final ScopeRule b) { + return ruleSignature(a).equals(ruleSignature(b)); + } + + // Hrmph. Use naming here, otherwise we'll get strange (and wrong) results in the GenerateAllAPSLs workflow for netwStruct?! + private /*cached*/ String ruleSignature(final ScopeRule s) { + return ScopeUtil.getSignature(s); + } + + /* + * SCOPE DEFINITIONS + */ + // returns the list of all local and inherited scope definition (skipping any shadowed or extended scope definitions) + // dispatch allScopes + protected List _allScopes(final ScopeModel it) { + final List myScopes = it.getScopes(); + final List result; + if (it.getIncludedScopes().isEmpty()) { + result = new ArrayList<>(); + } else { + result = new ArrayList<>(); + for (final ScopeModel included : it.getIncludedScopes()) { + result.addAll(allScopes(included)); + } + } + result.removeIf(s -> hasScope(myScopes, s)); + result.addAll(myScopes); + return result; + } + + protected List _allScopes(final Void it) { + return new ArrayList<>(); + } + + public List allScopes(final ScopeModel it) { + if (it != null) { + return _allScopes(it); + } else { + return _allScopes((Void) null); + } + } + + public String getScopeName(final ScopeDefinition it) { + if (it.getName() == null) { + return "scope"; + } else { + return it.getName(); + } + } + + public boolean hasScope(final List list, final ScopeDefinition scope) { + if (list.isEmpty()) { + return false; + } else { + return list.stream().anyMatch(s -> isEqual(s, scope)); + } + } + + // dispatch isEqual(ScopeDefinition, ScopeDefinition) + protected boolean _isEqual(final ScopeDefinition a, final ScopeDefinition b) { + return getScopeName(a).equals(getScopeName(b)) && isEqual(a.getTargetType(), b.getTargetType()) && isEqual(a.getReference(), b.getReference()); + } + + /* + * SCOPE TYPE + */ + // dispatch scopeType + protected EClass _scopeType(final ScopeDefinition it) { + if (it.getReference() != null) { + return it.getReference().getEReferenceType(); + } else { + return it.getTargetType(); + } + } + + protected EClass _scopeType(final ScopeRule it) { + return scopeType(getScope(it)); + } + + protected EClass _scopeType(final Expression it) { + if (getScope(it) != null) { + return scopeType(getScope(it)); + } else { + return getNamingDef(it).getType(); + } + } + + public EClass scopeType(final EObject it) { + if (it instanceof ScopeDefinition scopeDefinition) { + return _scopeType(scopeDefinition); + } else if (it instanceof ScopeRule scopeRule) { + return _scopeType(scopeRule); + } else if (it instanceof Expression expression) { + return _scopeType(expression); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + it); + } + } + + public ENamedElement typeOrRef(final ScopeDefinition it) { + if (it.getReference() != null) { + return it.getReference(); + } else { + return it.getTargetType(); + } + } + + public EReference contextRef(final ScopeRule it) { + return getScope(it).getReference(); + } + + /* + * Injections + */ + // returns the list of all local and inherited injections (skipping any shadowed injections) + // dispatch allInjections + protected List _allInjections(final ScopeModel it) { + final List myInjections = it.getInjections(); + final List result; + if (it.getIncludedScopes().isEmpty()) { + result = new ArrayList<>(); + } else { + result = new ArrayList<>(); + for (final ScopeModel included : it.getIncludedScopes()) { + result.addAll(allInjections(included)); + } + } + result.removeIf(i -> hasInjection(myInjections, i)); + result.addAll(myInjections); + return result; + } + + protected List _allInjections(final Void it) { + return new ArrayList<>(); + } + + public List allInjections(final ScopeModel it) { + if (it != null) { + return _allInjections(it); + } else { + return _allInjections((Void) null); + } + } + + public boolean hasInjection(final List list, final Injection injection) { + if (list.isEmpty()) { + return false; + } else { + return list.stream().anyMatch(i -> isEqual(i, injection)); + } + } + + // dispatch isEqual(Injection, Injection) + protected boolean _isEqual(final Injection a, final Injection b) { + return a.getType().equals(b.getType()) && a.getName().equals(b.getName()); + } + + /* + * SCOPE EXPRESSIONS + */ + public boolean isCaseInsensitive(final NamedScopeExpression it) { + return ScopingGeneratorUtil.isCaseInsensitive(it); + } + + /* + * ECONTAINER + */ + public ScopeModel getModel(final EObject it) { + return (ScopeModel) it.eResource().getContents().get(0); + } + + public /*cached*/ ScopeDefinition getScope(final EObject it) { + return eContainer(it, ScopeDefinition.class); + } + + public /*cached*/ NamingDefinition getNamingDef(final EObject it) { + return eContainer(it, NamingDefinition.class); + } + + public T eContainer(final EObject it, final Class type) { + if (it == null) { + return null; + } else if (type.isInstance(it)) { + @SuppressWarnings("unchecked") + final T result = (T) it; + return result; + } else { + return eContainer(it.eContainer(), type); + } + } + + /* + * ECORE + */ + // dispatch isEqual(EClass, EClass) + protected boolean _isEqual(final EClass a, final EClass b) { + return a == b || (a != null && b != null && a.getName().equals(b.getName()) && a.getEPackage().getNsURI().equals(b.getEPackage().getNsURI())); + } + + protected boolean _isEqualVoidVoid(final Void a, final Void b) { + return true; + } + + protected boolean _isEqualObjectVoid(final EObject a, final Void b) { + return false; + } + + protected boolean _isEqualVoidObject(final Void a, final EObject b) { + return false; + } + + // dispatch isEqual(EReference, EReference) + protected boolean _isEqual(final EReference a, final EReference b) { + return a == b || (a != null && b != null && a.getName().equals(b.getName()) && isEqual(a.getEContainingClass(), b.getEContainingClass())); + } + + // Public dispatcher for isEqual - handles all type combinations + public boolean isEqual(final Object a, final Object b) { + if (a instanceof ScopeRule ruleA && b instanceof ScopeRule ruleB) { + return _isEqual(ruleA, ruleB); + } else if (a instanceof ScopeDefinition defA && b instanceof ScopeDefinition defB) { + return _isEqual(defA, defB); + } else if (a instanceof Injection injA && b instanceof Injection injB) { + return _isEqual(injA, injB); + } else if (a instanceof EReference refA && b instanceof EReference refB) { + return _isEqual(refA, refB); + } else if (a instanceof EClass classA && b instanceof EClass classB) { + return _isEqual(classA, classB); + } else if (a == null && b == null) { + return _isEqualVoidVoid(null, null); + } else if (a instanceof EObject && b == null) { + return _isEqualObjectVoid((EObject) a, null); + } else if (a == null && b instanceof EObject) { + return _isEqualVoidObject(null, (EObject) b); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + a + ", " + b); + } + } +} diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.xtend b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.xtend deleted file mode 100644 index 6ad50bec0e..0000000000 --- a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.xtend +++ /dev/null @@ -1,248 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. it program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies it distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.scope.generator - -import com.avaloq.tools.ddk.xtext.expression.expression.Expression -import com.avaloq.tools.ddk.xtext.expression.expression.FeatureCall -import com.avaloq.tools.ddk.xtext.expression.generator.CodeGenerationX -import com.avaloq.tools.ddk.xtext.expression.generator.ExpressionExtensionsX -import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtilX -import com.avaloq.tools.ddk.xtext.expression.generator.Naming -import com.avaloq.tools.ddk.xtext.scope.ScopeUtil -import com.avaloq.tools.ddk.xtext.scope.scope.Injection -import com.avaloq.tools.ddk.xtext.scope.scope.NamedScopeExpression -import com.avaloq.tools.ddk.xtext.scope.scope.NamingDefinition -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeDefinition -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeModel -import com.avaloq.tools.ddk.xtext.scope.scope.ScopeRule -import com.google.inject.Inject -import java.util.Collection -import java.util.List -import java.util.Set -import org.eclipse.emf.ecore.EClass -import org.eclipse.emf.ecore.ENamedElement -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.EReference -import org.eclipse.emf.ecore.EStructuralFeature - -class ScopeProviderX { - - @Inject - extension Naming - @Inject - extension GeneratorUtilX - @Inject - extension CodeGenerationX - @Inject - extension ExpressionExtensionsX - - /* - * CODE GENERATION - */ - def getScopeProvider(ScopeModel model) { - model.name.toJavaPackage() + ".scoping." + model.name.toSimpleName() + "ScopeProvider" - } - - def getScopeNameProvider(ScopeModel model) { - model.name.toJavaPackage() + ".scoping." + model.name.toSimpleName() + "ScopeNameProvider" - } - - // returns the name of the scope method generated for the given scope definition - def String scopeMethodName(ScopeDefinition it) { - getScopeName() + '_' + (if (targetType !== null) targetType.EPackage.name + '_' + targetType.name else contextType.EPackage.name + '_' + contextType.name + '_' + reference.name) - } - - def String locatorString(EObject it) { - location().split('/').lastOrNull().javaEncode() - } - - def String calledFeature(FeatureCall it) { - type.id.head - } - - def EStructuralFeature feature(FeatureCall it) { - scopeType().getEStructuralFeature(calledFeature()) - } - - /* - * SCOPE RULES - */ - def dispatch List allScopeRules(Void it) { - newArrayList() - } - - def dispatch List allScopeRules(ScopeDefinition it) { - getModel().collectAllScopeRules(it) - } - - def List collectAllScopeRules(ScopeModel it, ScopeDefinition ^def) { - val d = scopes.filter(d|d.isEqual(^def)) - val myScopeRules = if (d === null) newArrayList else d.map[rules].flatten - val result = - if (includedScopes.isEmpty) - newArrayList - else - includedScopes.map[collectAllScopeRules(def)].flatten().toList - result.addAll(myScopeRules) - result - } - - def List sortedRules(Collection it) { - ScopingGeneratorUtil.sortedRules(it) - } - - def Set filterUniqueRules(List it) { - map(r|findFirst(r2|r2.hasSameContext(r))).toSet() - } - - def dispatch boolean isEqual(ScopeRule a, ScopeRule b) { - a.hasSameContext(b) - // && ((a.name === null) == (b.name === null)) && (a.name === null || a.name.matches (b.name)) - && a.context.guard.serialize() == b.context.guard.serialize() - } - - def boolean hasSameContext(ScopeRule a, ScopeRule b) { - a.ruleSignature() == b.ruleSignature() - } - - // Hrmph. Use naming here, otherwise we'll get strange (and wrong) results in the GenerateAllAPSLs workflow for netwStruct?! - def private /*cached*/ String ruleSignature(ScopeRule s) { - ScopeUtil.getSignature(s) - } - - /* - * SCOPE DEFINITIONS - */ - // returns the list of all local and inherited scope definition (skipping any shadowed or extended scope definitions) - def dispatch List allScopes(ScopeModel it) { - val myScopes = it.scopes - val result = if (it.includedScopes.isEmpty) newArrayList else it.includedScopes.map[allScopes()].flatten.toList - result.removeIf(s|myScopes.hasScope(s)) - result.addAll(myScopes) - result - } - - def dispatch List allScopes(Void it) { - newArrayList - } - - def String getScopeName(ScopeDefinition it) { - if (it.name === null) 'scope' else it.name - } - - def boolean hasScope(List list, ScopeDefinition scope) { - if (list.isEmpty) false else !(list.filter(s|s.isEqual(scope)).isEmpty) - } - - def dispatch boolean isEqual(ScopeDefinition a, ScopeDefinition b) { - a.getScopeName() == b.getScopeName() && a.targetType.isEqual(b.targetType) && a.reference.isEqual(b.reference) - } - - /* - * SCOPE TYPE - */ - def dispatch EClass scopeType(ScopeDefinition it) { - if (reference !== null) reference.EReferenceType else targetType - } - - def dispatch EClass scopeType(ScopeRule it) { - getScope().scopeType() - } - - def dispatch EClass scopeType(Expression it) { - if (getScope() !== null) getScope().scopeType() else getNamingDef().type - } - - def ENamedElement typeOrRef(ScopeDefinition it) { - if (reference !== null) reference else targetType - } - - def EReference contextRef(ScopeRule it) { - getScope().reference - } - - /* - * Injections - */ - // returns the list of all local and inherited injections (skipping any shadowed injections) - def dispatch List allInjections(ScopeModel it) { - val myInjections = it.injections - val result = if (it.includedScopes.isEmpty) newArrayList else it.includedScopes.map[allInjections()].flatten.toList - result.removeIf(i|myInjections.hasInjection(i)) - result.addAll(myInjections) - result - } - - def dispatch List allInjections(Void it) { - newArrayList - } - - def boolean hasInjection(List list, Injection injection) { - if (list.isEmpty) false else !(list.filter(i|i.isEqual(injection)).isEmpty) - } - - def dispatch boolean isEqual(Injection a, Injection b) { - a.type == b.type && a.name == b.name - } - - /* - * SCOPE EXPRESSIONS - */ - def boolean isCaseInsensitive(NamedScopeExpression it) { - ScopingGeneratorUtil.isCaseInsensitive(it) - } - - /* - * ECONTAINER - */ - def ScopeModel getModel(EObject it) { - it.eResource().contents.head as ScopeModel - } - - def /*cached*/ ScopeDefinition getScope(EObject it) { - eContainer(ScopeDefinition) - } - - def /*cached*/ NamingDefinition getNamingDef(EObject it) { - eContainer(NamingDefinition) - } - - def T eContainer(EObject it, Class type) { - if (it === null) return null - else if (type.isInstance(it)) it as T - else eContainer().eContainer(type) - } - - /* - * ECORE - */ - def dispatch boolean isEqual(EClass a, EClass b) { - a == b || (a !== null && b !== null && a.name == b.name && a.EPackage.nsURI == b.EPackage.nsURI) - } - - def dispatch boolean isEqual(Void a, Void b) { - true - } - - def dispatch boolean isEqual(EObject a, Void b) { - false - } - - def dispatch boolean isEqual(Void a, EObject b) { - false - } - - def dispatch boolean isEqual(EReference a, EReference b) { - a == b || (a !== null && b !== null && a.name == b.name && a.EContainingClass.isEqual(b.EContainingClass)) - } - -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/resource/AbstractResourceDescriptionManagerTest.xtend b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/resource/AbstractResourceDescriptionManagerTest.java similarity index 59% rename from com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/resource/AbstractResourceDescriptionManagerTest.xtend rename to com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/resource/AbstractResourceDescriptionManagerTest.java index f8b03f2670..d67defe3cb 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/resource/AbstractResourceDescriptionManagerTest.xtend +++ b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/resource/AbstractResourceDescriptionManagerTest.java @@ -10,60 +10,69 @@ *******************************************************************************/ package com.avaloq.tools.ddk.xtext.test.resource; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.xtext.resource.IResourceDescription; +import org.eclipse.xtext.resource.IResourceDescription.Delta; +import org.eclipse.xtext.resource.IResourceDescriptions; +import org.junit.Assert; + +import com.avaloq.tools.ddk.xtext.resource.AbstractCachingResourceDescriptionManager; import com.avaloq.tools.ddk.xtext.test.AbstractXtextTest; -import org.eclipse.xtext.resource.IResourceDescription -import com.avaloq.tools.ddk.xtext.resource.AbstractCachingResourceDescriptionManager -import org.eclipse.xtext.resource.IResourceDescriptions -import org.eclipse.emf.common.util.URI -import java.util.Collection -import org.eclipse.xtext.resource.IResourceDescription.Delta -import com.google.common.collect.HashMultiset -import org.junit.Assert -import com.google.common.collect.Sets -import com.avaloq.tools.ddk.xtext.test.TestSource +import com.avaloq.tools.ddk.xtext.test.TestSource; +import com.avaloq.tools.ddk.xtext.test.XtextTestSource; +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Sets; /** * Abstract base class for {@link AbstractCachingResourceDescriptionManager} tests. */ -abstract class AbstractResourceDescriptionManagerTest extends AbstractXtextTest { +public abstract class AbstractResourceDescriptionManagerTest extends AbstractXtextTest { /** * Simple unchanged {@link Delta} implementation with {@link URI}. */ static class UnchangedDelta implements Delta { - val URI uri; + private final URI uri; - new(URI uri) { + UnchangedDelta(final URI uri) { this.uri = uri; } - override getNew() { - null + @Override + public IResourceDescription getNew() { + return null; } - override getOld() { - null + @Override + public IResourceDescription getOld() { + return null; } - override getUri() { - uri + @Override + public URI getUri() { + return uri; } - override haveEObjectDescriptionsChanged() { - false + @Override + public boolean haveEObjectDescriptionsChanged() { + return false; } } - val AbstractCachingResourceDescriptionManager resourceDescriptionManager = testUtil.get(IResourceDescription.Manager) as AbstractCachingResourceDescriptionManager; - val IResourceDescriptions index = testUtil.get(IResourceDescriptions); + private final AbstractCachingResourceDescriptionManager resourceDescriptionManager = (AbstractCachingResourceDescriptionManager) getTestUtil().get(IResourceDescription.Manager.class); + private final IResourceDescriptions index = getTestUtil().get(IResourceDescriptions.class); /** * Returns the {@link AbstractCachingResourceDescriptionManager) to use in the test. * * @return the {@link AbstractCachingResourceDescriptionManager) to use in the test, never {@code null} */ - def AbstractCachingResourceDescriptionManager getResourceDescriptionManager() { + public AbstractCachingResourceDescriptionManager getResourceDescriptionManager() { return resourceDescriptionManager; } @@ -72,7 +81,7 @@ def AbstractCachingResourceDescriptionManager getResourceDescriptionManager() { * * @return the {@link IResourceDescriptions) to use in the test, never {@code null} */ - def IResourceDescriptions getResourceDescriptions() { + public IResourceDescriptions getResourceDescriptions() { return index; } @@ -84,11 +93,12 @@ def IResourceDescriptions getResourceDescriptions() { * * @return the candidates for the affected resource computation, never {@code null} */ - def Collection getCandidates() { - var Collection candidates = testInformation.getTestObject(URI) as Collection; - if (candidates === null) { - candidates = Sets.newHashSet; - testInformation.putTestObject(URI, candidates); + @SuppressWarnings("unchecked") + public Collection getCandidates() { + Collection candidates = (Collection) getTestInformation().getTestObject(URI.class); + if (candidates == null) { + candidates = Sets.newHashSet(); + getTestInformation().putTestObject(URI.class, candidates); } return candidates; } @@ -102,9 +112,10 @@ def Collection getCandidates() { * content of source, must not be {@code null} * @return a new {@link TestSource} with the given parameters, never {@code null} */ - override protected createTestSource(String sourceFileName, String content) { - val testSource = super.createTestSource(sourceFileName, content); - getCandidates().add(testSource.uri); + @Override + protected XtextTestSource createTestSource(final String sourceFileName, final String content) { + final XtextTestSource testSource = super.createTestSource(sourceFileName, content); + getCandidates().add(testSource.getUri()); return testSource; } @@ -118,7 +129,7 @@ override protected createTestSource(String sourceFileName, String content) { * the delta {@link URI}, must not be {@code null} * @return a new {@link Delta}, never {@code null} */ - def Delta createDelta(URI uri) { + public Delta createDelta(final URI uri) { return new UnchangedDelta(uri); } @@ -129,8 +140,8 @@ def Delta createDelta(URI uri) { * file name for the test source, must not be {@code null} * @return the {@link URI} of the {@link TestSource} with the given file name, never {@code null} */ - def URI getUri(String sourceFileName) { - return getTestSource(sourceFileName).uri; + public URI getUri(final String sourceFileName) { + return getTestSource(sourceFileName).getUri(); } /** @@ -144,9 +155,9 @@ def URI getUri(String sourceFileName) { * @param expectedSourceNames * the expected affected source names, must not be {@code null} */ - def assertAffectedResources(String deltaSourceName, String... expectedSourceNames) { - val Collection expectedUris = Sets.newHashSet; - for (sourceName : expectedSourceNames) { + public void assertAffectedResources(final String deltaSourceName, final String... expectedSourceNames) { + final Collection expectedUris = Sets.newHashSet(); + for (final String sourceName : expectedSourceNames) { expectedUris.add(getUri(sourceName)); } assertAffectedResources(Sets.newHashSet(getUri(deltaSourceName)), getCandidates(), expectedUris); @@ -163,7 +174,7 @@ def assertAffectedResources(String deltaSourceName, String... expectedSourceName * @param expectedUris * the expected affected {@link URI}s, must not be {@code null} */ - def assertAffectedResources(Collection deltaUris, Collection expectedUris) { + public void assertAffectedResources(final Collection deltaUris, final Collection expectedUris) { assertAffectedResources(deltaUris, getCandidates(), expectedUris); } @@ -177,8 +188,9 @@ def assertAffectedResources(Collection deltaUris, Collection expectedU * @param expectedUris * the expected affected {@link URI}s, must not be {@code null} */ - def assertAffectedResources(Collection deltaUris, Collection candidates, Collection expectedUris) { - assertDeltaAffectedResources(Sets.newHashSet(deltaUris.map[createDelta(it)]), candidates, expectedUris); + public void assertAffectedResources(final Collection deltaUris, final Collection candidates, final Collection expectedUris) { + final Set deltas = deltaUris.stream().map(uri -> createDelta(uri)).collect(Collectors.toSet()); + assertDeltaAffectedResources(deltas, candidates, expectedUris); } /** @@ -191,8 +203,8 @@ def assertAffectedResources(Collection deltaUris, Collection candidate * @param expectedUris * the expected affected {@link URI}s, must not be {@code null} */ - def assertDeltaAffectedResources(Collection deltas, Collection candidates, Collection expectedUris) { - val result = getResourceDescriptionManager().getAffectedResources(deltas, candidates, getResourceDescriptions()); + public void assertDeltaAffectedResources(final Collection deltas, final Collection candidates, final Collection expectedUris) { + final Collection result = getResourceDescriptionManager().getAffectedResources(deltas, candidates, getResourceDescriptions()); Assert.assertEquals("Affected URIs must be correct.", HashMultiset.create(expectedUris), HashMultiset.create(result)); } } diff --git a/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java b/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java new file mode 100644 index 0000000000..996abe7652 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java @@ -0,0 +1,271 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.ui.templates; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.inject.Guice; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.templates.Template; +import org.eclipse.jface.text.templates.TemplateBuffer; +import org.eclipse.xtext.XtextRuntimeModule; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.ui.editor.templates.XtextTemplateContext; +import org.eclipse.xtext.ui.editor.templates.XtextTemplateContextType; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; + + +@ExtendWith(InjectionExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class TemplateProposalProviderHelperTest { + + private static final String SIMPLE_ENUM_VARIABLE_TYPE = new SimpleEnumTemplateVariableResolver().getType(); + private static final String VARIABLE_NAME = "variableName"; + private static final String RETURNED_PATTERN = "Pattern returned from createSimpleEnumPattern()"; + + private static final String TEMPLATE_NAME = "TemplateName"; + private static final String TEMPLATE_DESCRIPTION = "Template description"; + private static final String CONTEXT_TYPE_ID = "context.type.ID"; + private static final boolean IS_AUTO_INSERTABLE = true; + + private static IDocument mockDocument; + private static Position mockPosition; + private static IRegion mockRegion; + + private static XtextTemplateContext templateContext; + + private static TemplateProposalProviderHelper helper; + + @BeforeAll + public void beforeAll() throws Exception { + mockDocument = mock(IDocument.class); + mockPosition = mock(Position.class); + mockRegion = mock(IRegion.class); + + final XtextTemplateContextType templateContextType = new XtextTemplateContextType(); + templateContextType.addResolver(new SimpleEnumTemplateVariableResolver()); + templateContext = new XtextTemplateContext(templateContextType, mockDocument, mockPosition, null, null); + + helper = Guice.createInjector(new XtextRuntimeModule()).getInstance(TemplateProposalProviderHelper.class); + + when(mockDocument.getLineInformationOfOffset(anyInt())).thenReturn(mockRegion); + when(mockDocument.get(anyInt(), anyInt())).thenReturn(""); + } + + @AfterAll + public void afterAll() { + mockDocument = null; + mockPosition = null; + mockRegion = null; + + templateContext = null; + + helper = null; + } + + @Test + public void testCreateLiteralValuePatternWithNullName() { + assertThrows(NullPointerException.class, () -> helper.createLiteralValuePattern(null, 42)); + } + + @Test + public void testCreateLiteralValuePatternWithNameContainingWhitespace() { + assertThrows(IllegalArgumentException.class, () -> helper.createLiteralValuePattern("Contains whitespace", 42)); + } + + @Test + public void testCreateLiteralValuePatternWithNullDefaultValue() { + testCreateLiteralValuePattern(null, RETURNED_PATTERN, RETURNED_PATTERN); + } + + @Test + public void testCreateLiteralValuePatternWithFalse() { + testCreateLiteralValuePattern(false, RETURNED_PATTERN, RETURNED_PATTERN); + } + + @Test + public void testCreateLiteralValuePatternWithTrue() { + testCreateLiteralValuePattern(true, RETURNED_PATTERN, RETURNED_PATTERN); + } + + @Test + public void testCreateLiteralValuePatternWithNumber() { + testCreateLiteralValuePattern(42, RETURNED_PATTERN, RETURNED_PATTERN); + } + + @Test + public void testCreateLiteralValuePatternWithString() { + testCreateLiteralValuePattern("Supercalifragilisticexpialidocious", RETURNED_PATTERN, "\"" + RETURNED_PATTERN + "\""); + } + + /** + * Test createLiteralValuePattern() using a mock createSimpleEnumPattern(). + * + * @param defaultValue default value to supply to createLiteralValuePattern(), may be {@code null} + * @param pattern pattern to return from createSimpleEnumPattern(), may be {@code null} + * @param expectedResult expected return value from createLiteralValuePattern(), may be {@code null} + */ + public void testCreateLiteralValuePattern(final Object defaultValue, final String pattern, final String expectedResult) { + + // ARRANGE + final TemplateProposalProviderHelper helperSpy = spy(helper); + when(helperSpy.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, defaultValue)). + thenReturn(pattern); + + // ACT + final String actualResult = helperSpy.createLiteralValuePattern(VARIABLE_NAME, defaultValue); + + // ASSERT + verify(helperSpy).createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, defaultValue); + assertEquals(expectedResult, actualResult, "Expected result"); + } + + @Test + public void testCreateTemplateVariablePatternWithNullType() { + assertThrows(NullPointerException.class, () -> helper.createTemplateVariablePattern(null, VARIABLE_NAME)); + } + + @Test + public void testCreateTemplateVariablePatternWithTypeContainingWhitespace() { + assertThrows(IllegalArgumentException.class, () -> helper.createTemplateVariablePattern("Contains whitespace", VARIABLE_NAME)); + } + + @Test + public void testCreateTemplateVariablePatternWithNullName() { + assertThrows(NullPointerException.class, () -> helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, null)); + } + + public void testCreateTemplateVariablePatternWithNameContainingWhitespace() { + assertThrows(IllegalArgumentException.class, () -> helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, "Contains whitespace")); + } + + @Test + public void testCreateTemplateVariablePatternWithNull() { + assertThrows(NullPointerException.class, () -> helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, null)); + } + + @Test + public void testCreateTemplateVariablePatternWithNoValues() { + assertThrows(IllegalArgumentException.class, () -> helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME)); + } + + @Test + public void testCreateTemplateVariablePatternWithFalse() { + testCreateTemplateVariablePattern(new Object[]{false}, "false", new String[]{"false", "true"}); + } + + @Test + public void testCreateTemplateVariablePatternWithTrue() { + testCreateTemplateVariablePattern(new Object[]{true}, "true", new String[]{"true", "false"}); + } + + @Test + public void testCreateTemplateVariablePatternWithMultipleBooleans() { + testCreateTemplateVariablePattern(new Object[]{false, false, true}, "false", new String[]{"false", "false", "true"}); + } + + @Test + public void testCreateTemplateVariablePatternWithNumber() { + testCreateTemplateVariablePattern(new Object[]{42}, "42", new String[]{"42"}); + } + + @Test + public void testCreateTemplateVariablePatternWithMultipleNumbers() { + testCreateTemplateVariablePattern(new Object[]{1297, 1314}, "1297", new String[]{"1297", "1314"}); + } + + @Test + public void testCreateTemplateVariablePatternWithString() { + testCreateTemplateVariablePattern(new Object[]{"Supercalifragilisticexpialidocious"}, "Supercalifragilisticexpialidocious", + new String[]{"Supercalifragilisticexpialidocious"}); + } + + @Test + public void testCreateTemplateVariablePatternWithEmptyString() { + testCreateTemplateVariablePattern(new Object[]{""}, "", new String[]{""}); + } + + @Test + public void testCreateTemplateVariablePatternWithStringContainingWhitespace() { + testCreateTemplateVariablePattern(new Object[]{"Lorem ipsum dolor sit amet"}, "Lorem ipsum dolor sit amet", + new String[]{"Lorem ipsum dolor sit amet"}); + } + + @Test + public void testCreateTemplateVariablePatternWithStringContainingSingleQuotes() { + testCreateTemplateVariablePattern(new Object[]{"Apostrophe's"}, "Apostrophe's", new String[]{"Apostrophe's"}); + } + + @Test + public void testCreateTemplateVariablePatternWithStringContainingDoubleQuotes() { + testCreateTemplateVariablePattern(new Object[]{"CHAIN \"CHUCKIE\""}, "CHAIN \\\"CHUCKIE\\\"", + new String[]{"CHAIN \\\"CHUCKIE\\\""}); + } + + @Test + public void testCreateTemplateVariablePatternWithStringContainingWhitespaceAndSingleAndDoubleQuotes() { + testCreateTemplateVariablePattern( + new Object[]{"\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\" - Dr Johnson"}, + "\\\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\\\" - Dr Johnson", + new String[]{"\\\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\\\" - Dr Johnson"}); + } + + @Test + public void testCreateTemplateVariablePatternWithMultipleStrings() { + testCreateTemplateVariablePattern( + new Object[]{"Twas brillig and the slithy toves", "Did gyre and gimble in the wabe", "All mimsy were the borogroves", + "And the mome raths outgrabe"}, "Twas brillig and the slithy toves", + new String[]{"Twas brillig and the slithy toves", "Did gyre and gimble in the wabe", "All mimsy were the borogroves", + "And the mome raths outgrabe"}); + } + + /** + * Test createTemplateVariablePattern(). + * + * @param values values, may be {@code null} + * @param expectedResult expected result of applying a template containing the pattern, may be {@code null} + * @param expectedValues expected values offered by a template containing the pattern, may be {@code null} + */ + private void testCreateTemplateVariablePattern(final Object[] values, final String expectedResult, final String[] expectedValues) { + try { + // ACT + final String pattern = helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, values); + + // Try using the pattern in a template + final Template template = new Template(TEMPLATE_NAME, TEMPLATE_DESCRIPTION, CONTEXT_TYPE_ID, pattern, IS_AUTO_INSERTABLE); + final TemplateBuffer templateBuffer = templateContext.evaluate(template); + final String actualResult = templateBuffer.getString(); + assertEquals(1, templateBuffer.getVariables().length); + final String[] actualValues = templateBuffer.getVariables()[0].getValues(); + + // ASSERT + assertEquals(expectedResult, actualResult, "Expected result"); + assertArrayEquals(expectedValues, actualValues, "Expected values"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.xtend b/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.xtend deleted file mode 100644 index dd2add1d7c..0000000000 --- a/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.xtend +++ /dev/null @@ -1,265 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.ui.templates - -import com.google.inject.Guice -import org.eclipse.jface.text.IDocument -import org.eclipse.jface.text.IRegion -import org.eclipse.jface.text.Position -import org.eclipse.jface.text.templates.Template -import org.eclipse.xtext.XtextRuntimeModule -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.eclipse.xtext.ui.editor.templates.XtextTemplateContext -import org.eclipse.xtext.ui.editor.templates.XtextTemplateContextType -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.^extension.ExtendWith - -import static org.junit.jupiter.api.Assertions.assertThrows -import static org.junit.jupiter.api.Assertions.assertEquals -import static org.junit.jupiter.api.Assertions.assertArrayEquals -import static org.mockito.ArgumentMatchers.anyInt -import static org.mockito.Mockito.mock -import static org.mockito.Mockito.spy -import static org.mockito.Mockito.verify -import static org.mockito.Mockito.when -import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.AfterAll - -@ExtendWith(InjectionExtension) -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TemplateProposalProviderHelperTest { - - static val SIMPLE_ENUM_VARIABLE_TYPE = new SimpleEnumTemplateVariableResolver().type - static val VARIABLE_NAME = "variableName" - static val RETURNED_PATTERN = "Pattern returned from createSimpleEnumPattern()" - - static val TEMPLATE_NAME = "TemplateName" - static val TEMPLATE_DESCRIPTION = "Template description" - static val CONTEXT_TYPE_ID = "context.type.ID" - static val IS_AUTO_INSERTABLE = true - - static var IDocument mockDocument - static var Position mockPosition - static var IRegion mockRegion - - static var XtextTemplateContext templateContext - - static var TemplateProposalProviderHelper helper - - @BeforeAll - def void beforeAll() { - mockDocument = mock(IDocument) - mockPosition = mock(Position) - mockRegion = mock(IRegion) - - val templateContextType = new XtextTemplateContextType - templateContextType.addResolver(new SimpleEnumTemplateVariableResolver) - templateContext = new XtextTemplateContext(templateContextType, mockDocument, mockPosition, null, null) - - helper = Guice.createInjector(new XtextRuntimeModule).getInstance(TemplateProposalProviderHelper) - - when(mockDocument.getLineInformationOfOffset(anyInt)).thenReturn(mockRegion) - when(mockDocument.get(anyInt, anyInt)).thenReturn("") - } - - @AfterAll - def void afterAll() { - mockDocument = null - mockPosition = null - mockRegion = null - - templateContext = null - - helper = null - } - - @Test - def void testCreateLiteralValuePatternWithNullName() { - assertThrows(NullPointerException, [| helper.createLiteralValuePattern(null, 42)]) - } - - @Test - def void testCreateLiteralValuePatternWithNameContainingWhitespace() { - assertThrows(IllegalArgumentException, [| helper.createLiteralValuePattern("Contains whitespace", 42)]) - } - - @Test - def void testCreateLiteralValuePatternWithNullDefaultValue() { - testCreateLiteralValuePattern(null, RETURNED_PATTERN, RETURNED_PATTERN) - } - - @Test - def void testCreateLiteralValuePatternWithFalse() { - testCreateLiteralValuePattern(false, RETURNED_PATTERN, RETURNED_PATTERN) - } - - @Test - def void testCreateLiteralValuePatternWithTrue() { - testCreateLiteralValuePattern(true, RETURNED_PATTERN, RETURNED_PATTERN) - } - - @Test - def void testCreateLiteralValuePatternWithNumber() { - testCreateLiteralValuePattern(42, RETURNED_PATTERN, RETURNED_PATTERN) - } - - @Test - def void testCreateLiteralValuePatternWithString() { - testCreateLiteralValuePattern("Supercalifragilisticexpialidocious", RETURNED_PATTERN, '''"«RETURNED_PATTERN»"''') - } - - /** - * Test createLiteralValuePattern() using a mock createSimpleEnumPattern(). - * - * @param defaultValue default value to supply to createLiteralValuePattern(), may be {@code null} - * @param pattern pattern to return from createSimpleEnumPattern(), may be {@code null} - * @param expectedResult expected return value from createLiteralValuePattern(), may be {@code null} - */ - def void testCreateLiteralValuePattern(Object defaultValue, String pattern, String expectedResult) { - - // ARRANGE - val helperSpy = spy(helper) - when(helperSpy.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, defaultValue)). - thenReturn(pattern) - - // ACT - val actualResult = helperSpy.createLiteralValuePattern(VARIABLE_NAME, defaultValue) - - // ASSERT - verify(helperSpy).createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, defaultValue) - assertEquals(expectedResult, actualResult, "Expected result") - } - - @Test - def void testCreateTemplateVariablePatternWithNullType() { - assertThrows(NullPointerException, [| helper.createTemplateVariablePattern(null, VARIABLE_NAME)]) - } - - @Test - def void testCreateTemplateVariablePatternWithTypeContainingWhitespace() { - assertThrows(IllegalArgumentException, [|helper.createTemplateVariablePattern("Contains whitespace", VARIABLE_NAME)]) - } - - @Test - def void testCreateTemplateVariablePatternWithNullName() { - assertThrows(NullPointerException, [| helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, null)]) - } - - def void testCreateTemplateVariablePatternWithNameContainingWhitespace() { - assertThrows(IllegalArgumentException, [| helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, "Contains whitespace")]) - } - - @Test - def void testCreateTemplateVariablePatternWithNull() { - assertThrows(NullPointerException, [| helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, null)]) - } - - @Test - def void testCreateTemplateVariablePatternWithNoValues() { - assertThrows(IllegalArgumentException, [| helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME)]) - } - - @Test - def void testCreateTemplateVariablePatternWithFalse() { - testCreateTemplateVariablePattern(#[false], "false", #["false", "true"]) - } - - @Test - def void testCreateTemplateVariablePatternWithTrue() { - testCreateTemplateVariablePattern(#[true], "true", #["true", "false"]) - } - - @Test - def void testCreateTemplateVariablePatternWithMultipleBooleans() { - testCreateTemplateVariablePattern(#[false, false, true], "false", #["false", "false", "true"]) - } - - @Test - def void testCreateTemplateVariablePatternWithNumber() { - testCreateTemplateVariablePattern(#[42], "42", #["42"]) - } - - @Test - def void testCreateTemplateVariablePatternWithMultipleNumbers() { - testCreateTemplateVariablePattern(#[1297, 1314], "1297", #["1297", "1314"]) - } - - @Test - def void testCreateTemplateVariablePatternWithString() { - testCreateTemplateVariablePattern(#["Supercalifragilisticexpialidocious"], "Supercalifragilisticexpialidocious", - #["Supercalifragilisticexpialidocious"]) - } - - @Test - def void testCreateTemplateVariablePatternWithEmptyString() { - testCreateTemplateVariablePattern(#[""], "", #[""]) - } - - @Test - def void testCreateTemplateVariablePatternWithStringContainingWhitespace() { - testCreateTemplateVariablePattern(#["Lorem ipsum dolor sit amet"], "Lorem ipsum dolor sit amet", - #["Lorem ipsum dolor sit amet"]) - } - - @Test - def void testCreateTemplateVariablePatternWithStringContainingSingleQuotes() { - testCreateTemplateVariablePattern(#["Apostrophe's"], "Apostrophe's", #["Apostrophe's"]) - } - - @Test - def void testCreateTemplateVariablePatternWithStringContainingDoubleQuotes() { - testCreateTemplateVariablePattern(#['''CHAIN "CHUCKIE"'''.toString], '''CHAIN \"CHUCKIE\"''', - #['''CHAIN \"CHUCKIE\"''']) - } - - @Test - def void testCreateTemplateVariablePatternWithStringContainingWhitespaceAndSingleAndDoubleQuotes() { - testCreateTemplateVariablePattern( - #['''"Whoever thinks of going to bed before twelve o'clock is a scoundrel" - Dr Johnson'''. - toString], '''\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\" - Dr Johnson''', - #['''\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\" - Dr Johnson''']) - } - - @Test - def void testCreateTemplateVariablePatternWithMultipleStrings() { - testCreateTemplateVariablePattern( - #["Twas brillig and the slithy toves", "Did gyre and gimble in the wabe", "All mimsy were the borogroves", - "And the mome raths outgrabe"], "Twas brillig and the slithy toves", - #["Twas brillig and the slithy toves", "Did gyre and gimble in the wabe", "All mimsy were the borogroves", - "And the mome raths outgrabe"]) - } - - /** - * Test createTemplateVariablePattern(). - * - * @param values values, may be {@code null} - * @param expectedResult expected result of applying a template containing the pattern, may be {@code null} - * @param expectedValues expected values offered by a template containing the pattern, may be {@code null} - */ - private def void testCreateTemplateVariablePattern(Object[] values, String expectedResult, String[] expectedValues) { - // ACT - val pattern = helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, values) - - // Try using the pattern in a template - val template = new Template(TEMPLATE_NAME, TEMPLATE_DESCRIPTION, CONTEXT_TYPE_ID, pattern, IS_AUTO_INSERTABLE) - val templateBuffer = templateContext.evaluate(template) - val actualResult = templateBuffer.string - assertEquals(1, templateBuffer.variables.length) - val actualValues = templateBuffer.variables.get(0).values - - // ASSERT - assertEquals(expectedResult, actualResult, "Expected result") - assertArrayEquals(expectedValues, actualValues, "Expected values") - } - -} diff --git a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.java b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.java new file mode 100644 index 0000000000..b5735d6ca9 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * Contributors: + * Avaloq Group AG - initial API and implementation + */ +package com.avaloq.tools.ddk.xtext.ui.templates; + +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.google.inject.Singleton; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.Validate; +import org.eclipse.jface.text.templates.Template; +import org.eclipse.xtext.ui.editor.contentassist.ITemplateProposalProvider; + +/** + * Helper methods for {@link ITemplateProposalProvider} implementations. + */ +@Singleton +public class TemplateProposalProviderHelper { + + private static final String SIMPLE_ENUM_TYPE = new SimpleEnumTemplateVariableResolver().getType(); + + /** + * Create a literal value pattern, including quotes if necessary, for a {@link Template}. + * + * @param name the name of the variable, may not be {@code null} nor contain whitespace + * @param defaultValue default value, may be {@code null} + * @return pattern, never {@code null} + * @throws {@link NullPointerException} if name is null + * @throws {@link IllegalArgumentException} if name contains whitespace + */ + public String createLiteralValuePattern(final String name, final Object defaultValue) throws NullPointerException, IllegalArgumentException { + final String pattern = createTemplateVariablePattern(SIMPLE_ENUM_TYPE, name, defaultValue); + + if (defaultValue instanceof String) { + // Surround pattern with quotes + return "\"" + pattern + "\""; + } else { + return pattern; + } + } + + /** + * Create a variable pattern for a {@link Template}. + * + * @param type the type of the variable, may not be {@code null} nor contain whitespace + * @param name the name of the variable, may not be {@code null} nor contain whitespace + * @param values the values available at this variable, may not be {@code null} nor empty + * @return pattern, never {@code null} + * @throws {@link NullPointerException} if type, name or values is null + * @throws {@link IllegalArgumentException} if type or name contains whitespace or values is empty + */ + public String createTemplateVariablePattern(final String type, final String name, final Object... values) throws NullPointerException, IllegalArgumentException { + Objects.requireNonNull(type); + Objects.requireNonNull(name); + Objects.requireNonNull(values); + Validate.isTrue(!type.chars().anyMatch(Character::isWhitespace)); + Validate.isTrue(!name.chars().anyMatch(Character::isWhitespace)); + Validate.notEmpty(values); + + final Object[] useValues; + if (values.length == 1 && values[0] instanceof Boolean) { + // Offer both false and true as dropdown options + useValues = new Object[]{values[0], !((Boolean) values[0])}; + } else { + useValues = values; + } + + final String sanitisedValues = Arrays.stream(useValues) + .map(it -> + // Escape double-quotes to comply with string grammar. + // Double-up single-quotes to comply with template pattern grammar. + // Wrap each value in single quotes. + "'" + StringEscapeUtils.escapeJava(String.valueOf(it)).replace("'", "''") + "'") + .collect(Collectors.joining(", ")); + + return "${" + name + ":" + type + "(" + sanitisedValues + ")}"; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.xtend b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.xtend deleted file mode 100644 index 6ea420acf2..0000000000 --- a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.xtend +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * Contributors: - * Avaloq Group AG - initial API and implementation - */ -package com.avaloq.tools.ddk.xtext.ui.templates - -import com.google.inject.Singleton -import java.util.Objects -import org.apache.commons.lang.StringEscapeUtils -import org.apache.commons.lang.Validate -import org.eclipse.jface.text.templates.Template -import org.eclipse.xtext.ui.editor.contentassist.ITemplateProposalProvider - -/** - * Helper methods for {@link ITemplateProposalProvider} implementations. - */ -@Singleton -class TemplateProposalProviderHelper { - - static val SIMPLE_ENUM_TYPE = new SimpleEnumTemplateVariableResolver().type - - /** - * Create a literal value pattern, including quotes if necessary, for a {@link Template}. - * - * @param name the name of the variable, may not be {@code null} nor contain whitespace - * @param defaultValue default value, may be {@code null} - * @return pattern, never {@code null} - * @throws {@link NullPointerException} if name is null - * @throws {@link IllegalArgumentException} if name contains whitespace - */ - def String createLiteralValuePattern(String name, Object defaultValue) throws NullPointerException, IllegalArgumentException { - val pattern = createTemplateVariablePattern(SIMPLE_ENUM_TYPE, name, defaultValue) - - return if (defaultValue instanceof String) { - // Surround pattern with quotes - '''"«pattern»"''' - } else { - pattern - } - } - - /** - * Create a variable pattern for a {@link Template}. - * - * @param type the type of the variable, may not be {@code null} nor contain whitespace - * @param name the name of the variable, may not be {@code null} nor contain whitespace - * @param values the values available at this variable, may not be {@code null} nor empty - * @return pattern, never {@code null} - * @throws {@link NullPointerException} if type, name or values is null - * @throws {@link IllegalArgumentException} if type or name contains whitespace or values is empty - */ - def String createTemplateVariablePattern(String type, String name, Object... values) throws NullPointerException, IllegalArgumentException { - Objects.requireNonNull(type); - Objects.requireNonNull(name); - Objects.requireNonNull(values); - Validate.isTrue(!type.chars().anyMatch[Character.isWhitespace(it)]); - Validate.isTrue(!name.chars().anyMatch[Character.isWhitespace(it)]); - Validate.notEmpty(values); - - val Object[] useValues = if (values.length == 1 && values.get(0) instanceof Boolean) { - // Offer both false and true as dropdown options - #[values.get(0), !(values.get(0) as Boolean)] - } else { - values - } - - val sanitisedValues = useValues.map [ - // Escape double-quotes to comply with string grammar. - // Double-up single-quotes to comply with template pattern grammar. - // Wrap each value in single quotes. - "'" + StringEscapeUtils::escapeJava(String.valueOf(it)).replace("'", "''") + "'" - ] - - return '''${«name»:«type»(«String.join(", ", sanitisedValues)»)}''' - } - -} diff --git a/docs/xtend-migration.md b/docs/xtend-migration.md index bf84e45ed3..49b7b68580 100644 --- a/docs/xtend-migration.md +++ b/docs/xtend-migration.md @@ -12,10 +12,10 @@ | Metric | Value | |--------|-------| | Total Xtend source files | 94 | -| Already migrated (Batch 1–5) | 58 | -| Remaining | 36 | -| Total remaining lines | ~9,377 | -| Modules with remaining Xtend | 13 | +| Already migrated (Batch 1–6) | 68 | +| Remaining | 26 | +| Total remaining lines | ~7,360 | +| Modules with remaining Xtend | 8 | --- @@ -35,7 +35,7 @@ | `xtext.check.generator` | 2 | 113 | **DONE** (Batch 2–3) | | `xtext.export` | 9 | 1,027 | **DONE** (Batch 5) | | `xtext.export.generator` | 1 | 86 | **DONE** (Batch 4) | -| `xtext.expression` | 5 | 679 | 2 done (Batch 2), 3 pending | +| `xtext.expression` | 5 | 679 | **DONE** (Batch 2, 6) | | `xtext.format` | 6 | 1,623 | 1 done (Batch 2), 5 pending | | `xtext.format.generator` | 1 | 239 | Pending | | `xtext.format.ide` | 2 | 31 | **DONE** (Batch 2) | @@ -43,11 +43,11 @@ | `xtext.format.ui` | 1 | 47 | **DONE** (Batch 2) | | `xtext.generator` | 18 | 3,450 | 2 done (Batch 2), 16 pending | | `xtext.generator.test` | 1 | 200 | Pending | -| `xtext.scope` | 4 | 852 | Pending | +| `xtext.scope` | 4 | 852 | **DONE** (Batch 6) | | `xtext.scope.generator` | 1 | 47 | **DONE** (Batch 4) | -| `xtext.test.core` | 2 | 221 | 1 done (Batch 4), 1 pending | -| `xtext.ui` | 1 | 82 | Pending | -| `xtext.ui.test` | 1 | 265 | Pending | +| `xtext.test.core` | 2 | 221 | **DONE** (Batch 4, 6) | +| `xtext.ui` | 1 | 82 | **DONE** (Batch 6) | +| `xtext.ui.test` | 1 | 265 | **DONE** (Batch 6) | All module names are prefixed with `com.avaloq.tools.ddk.` (omitted for brevity). @@ -189,27 +189,27 @@ Code generators with templates and some dispatch methods. --- -## Batch 6 — `xtext.expression` + `xtext.scope` + remaining small files (~12 files) +## Batch 6 — `xtext.expression` + `xtext.scope` + remaining small files (10 files) — DONE ### `xtext.expression` (3 files) -- [ ] `ExpressionExtensionsX.xtend` (87 lines) — Medium — **dispatch**, === -- [ ] `GenModelUtilX.xtend` (160 lines) — Hard — **dispatch**, extension, !==, create -- [ ] `CodeGenerationX.xtend` (373 lines) — Hard — **dispatch**, extension, ===, !==, #[ +- [x] `ExpressionExtensionsX.xtend` (87 lines) — Medium — **dispatch**, === +- [x] `GenModelUtilX.xtend` (160 lines) — Hard — **dispatch**, extension, !==, create +- [x] `CodeGenerationX.xtend` (373 lines) — Hard — **dispatch**, extension, ===, !==, #[ ### `xtext.scope` (4 files) -- [ ] `ScopeGenerator.xtend` (83 lines) — Medium — extension, ===, !==, @Inject, override -- [ ] `ScopeNameProviderGenerator.xtend` (136 lines) — Medium — **dispatch**, templates, extension, switch -- [ ] `ScopeProviderX.xtend` (247 lines) — Hard — **dispatch**, extension, ===, !==, @Inject -- [ ] `ScopeProviderGenerator.xtend` (386 lines) — Hard — **dispatch**, templates, extension, ===, !==, #[, switch +- [x] `ScopeGenerator.xtend` (83 lines) — Medium — extension, ===, !==, @Inject, override +- [x] `ScopeNameProviderGenerator.xtend` (136 lines) — Medium — **dispatch**, templates, extension, switch +- [x] `ScopeProviderX.xtend` (247 lines) — Hard — **dispatch**, extension, ===, !==, @Inject +- [x] `ScopeProviderGenerator.xtend` (386 lines) — Hard — **dispatch**, templates, extension, ===, !==, #[, switch ### `xtext.test.core` (1 file) -- [ ] `AbstractResourceDescriptionManagerTest.xtend` (198 lines) — Medium — ===, override, create +- [x] `AbstractResourceDescriptionManagerTest.xtend` (198 lines) — Medium — ===, override, create ### `xtext.ui` (1 file) -- [ ] `TemplateProposalProviderHelper.xtend` (82 lines) — Medium — templates, #[ +- [x] `TemplateProposalProviderHelper.xtend` (82 lines) — Medium — templates, #[ ### `xtext.ui.test` (1 file) -- [ ] `TemplateProposalProviderHelperTest.xtend` (265 lines) — Medium — templates, #[ +- [x] `TemplateProposalProviderHelperTest.xtend` (265 lines) — Medium — templates, #[ --- From 716c8135e7c741fc1bcdd6e680ac0c6d67f0a93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 28 Feb 2026 21:37:08 +0100 Subject: [PATCH 08/23] feat: migrate Batch 7 Xtend files to Java 21 (6 files) Co-Authored-By: Claude Opus 4.6 --- .../format/generator/FormatFragment2.java | 345 +++++ .../format/generator/FormatFragment2.xtend | 239 --- .../ddk/xtext/format/FormatRuntimeModule.java | 132 ++ .../xtext/format/FormatRuntimeModule.xtend | 115 -- .../format/generator/FormatGenerator.java | 128 ++ .../format/generator/FormatGenerator.xtend | 93 -- .../jvmmodel/FormatJvmModelInferrer.java | 1297 +++++++++++++++++ .../jvmmodel/FormatJvmModelInferrer.xtend | 766 ---------- .../format/scoping/FormatScopeProvider.java | 278 ++++ .../format/scoping/FormatScopeProvider.xtend | 258 ---- .../format/validation/FormatValidator.java | 396 +++++ .../format/validation/FormatValidator.xtend | 376 ----- docs/xtend-migration.md | 30 +- 13 files changed, 2590 insertions(+), 1863 deletions(-) create mode 100644 com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.java delete mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.xtend create mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java delete mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.xtend create mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.java delete mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.xtend create mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.java delete mode 100644 com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.xtend diff --git a/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.java b/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.java new file mode 100644 index 0000000000..63580874de --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.java @@ -0,0 +1,345 @@ +/** + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * Contributors: + * Avaloq Group AG - initial API and implementation + */ +package com.avaloq.tools.ddk.xtext.format.generator; + +import com.avaloq.tools.ddk.xtext.format.FormatStandaloneSetup; +import com.avaloq.tools.ddk.xtext.formatting.AbstractExtendedFormatter; +import com.avaloq.tools.ddk.xtext.formatting.DirectNodeModelStreamer; +import com.avaloq.tools.ddk.xtext.formatting.RegionNodeModelFormatter; +import com.google.inject.Inject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.formatting.IFormatter; +import org.eclipse.xtext.formatting.INodeModelFormatter; +import org.eclipse.xtext.formatting.INodeModelStreamer; +import org.eclipse.xtext.xtext.generator.AbstractStubGeneratingFragment; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; +import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions; +import org.eclipse.xtext.xtext.generator.model.FileAccessFactory; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.JavaFileAccess; +import org.eclipse.xtext.xtext.generator.model.ManifestAccess; +import org.eclipse.xtext.xtext.generator.model.TextFileAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtext.xtext.generator.model.XtendFileAccess; +import org.eclipse.xtext.xtext.generator.util.BooleanGeneratorOption; + +/** + * MWE fragment for the format language. + */ +public class FormatFragment2 extends AbstractStubGeneratingFragment { + + @Inject + private FileAccessFactory fileAccessFactory; + + @Inject + private XtextGeneratorNaming xtextGeneratorNaming; + + @Inject + private GrammarAccessExtensions grammarAccessExtensions; + + private static final String RUNTIME_PLUGIN = "com.avaloq.tools.ddk.xtext"; + + private final BooleanGeneratorOption generateFormatStub = new BooleanGeneratorOption(true); + + public boolean isGenerateFormatStub() { + return generateFormatStub.get(); + } + + public void setGenerateFormatStub(final boolean generateStub) { + generateFormatStub.set(generateStub); + } + + /** + * Class-wide logger. + */ + private static final Logger LOGGER = LogManager.getLogger(FormatFragment2.class); + + /** + * The model for the format resource. + */ + private String baseFormatterClassName = AbstractExtendedFormatter.class.getName(); + + /** + * Set the super type / base class of the formatter. + * @param baseFormatterClass the FQN of the base formatter + */ + public void setBaseFormatterClassName(final String baseFormatterClass) { + baseFormatterClassName = baseFormatterClass; + } + + /** + * Get the super type / base class of the formatter. + * @return the FQN of the base formatter + */ + public String getBaseFormatterClassName() { + return baseFormatterClassName; + } + + protected TypeReference getFormatterStub(final Grammar grammar) { + return new TypeReference(xtextGeneratorNaming.getRuntimeBasePackage(grammar) + ".formatting." + GrammarUtil.getSimpleName(grammar) + "Formatter"); + } + + protected String getFormatStub(final Grammar grammar) { + final String formatter = getFormatterStub(grammar).getPath(); + return formatter.substring(0, formatter.lastIndexOf('/') + 1) + GrammarUtil.getSimpleName(grammar) + ".format"; + } + + @Override + public void generate() { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("executing generate for " + getClass().getName()); + } + + new GuiceModuleAccess.BindingFactory() + .addTypeToType(TypeReference.typeRef(IFormatter.class), new TypeReference(FormatGeneratorUtil.getFormatterName(getGrammar(), ""))) + .addTypeToType(TypeReference.typeRef(INodeModelFormatter.class), TypeReference.typeRef(RegionNodeModelFormatter.class)) + .addTypeToType(TypeReference.typeRef(INodeModelStreamer.class), TypeReference.typeRef(DirectNodeModelStreamer.class)) + .contributeTo(getLanguage().getRuntimeGenModule()); + + ManifestAccess manifest = getProjectConfig().getRuntime().getManifest(); + if (manifest != null) { + manifest.getRequiredBundles().add("org.eclipse.emf.ecore"); + manifest.getRequiredBundles().add(RUNTIME_PLUGIN); + } + ManifestAccess eclipsePluginManifest = getProjectConfig().getEclipsePlugin().getManifest(); + if (eclipsePluginManifest != null) { + eclipsePluginManifest.getRequiredBundles().add(RUNTIME_PLUGIN); + } + ManifestAccess genericIdeManifest = getProjectConfig().getGenericIde().getManifest(); + if (genericIdeManifest != null) { + genericIdeManifest.getRequiredBundles().add(RUNTIME_PLUGIN); + } + + FormatStandaloneSetup.doSetup(); + doGenerateStubFiles(); + } + + protected void doGenerateStubFiles() { + if (!isGenerateStub()) { + return; + } + if (isGenerateXtendStub()) { + final XtendFileAccess xtendFile = doGetXtendStubFile(); + if (xtendFile != null) { + xtendFile.writeTo(getProjectConfig().getRuntime().getSrc()); + } + } else { + final JavaFileAccess javaFile = doGetJavaStubFile(); + if (javaFile != null) { + javaFile.writeTo(getProjectConfig().getRuntime().getSrc()); + } + } + if (isGenerateFormatStub()) { + final TextFileAccess formatFile = doGetFormatStubFile(); + if (formatFile != null) { + formatFile.writeTo(getProjectConfig().getRuntime().getSrc()); + } + } + } + + protected XtendFileAccess doGetXtendStubFile() { + final XtendFileAccess xtendFile = fileAccessFactory.createXtendFile(getFormatterStub(getGrammar())); + xtendFile.setResourceSet(getLanguage().getResourceSet()); + + xtendFile.setContent(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation builder) { + builder.append("import com.avaloq.tools.ddk.xtext.formatting.ExtendedLineEntry"); + builder.newLine(); + builder.append("import java.util.List"); + builder.newLine(); + builder.newLine(); + builder.append("/**"); + builder.newLine(); + builder.append(" * This class contains custom formatting declarations."); + builder.newLine(); + builder.append(" *"); + builder.newLine(); + builder.append(" * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting"); + builder.newLine(); + builder.append(" * on how and when to use it."); + builder.newLine(); + builder.append(" *"); + builder.newLine(); + builder.append(" * Also see {@link org.eclipse.xtext.xtext.XtextFormatter} as an example"); + builder.newLine(); + builder.append(" */"); + builder.newLine(); + builder.append("class "); + builder.append(getFormatterStub(getGrammar()).getSimpleName()); + builder.append(" extends "); + builder.append(FormatGeneratorUtil.getFormatterName(getGrammar(), "Abstract")); + builder.append(" {"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" @"); + builder.append(Inject.class, " "); + builder.append(" extension "); + builder.append(grammarAccessExtensions.getGrammarAccess(getGrammar()), " "); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" override executeCustomPostFormatAction(ExtendedLineEntry lineEntry, List previousEntries) {"); + builder.newLine(); + builder.append(" // TODO Auto-generated method stub"); + builder.newLine(); + builder.append(" return null"); + builder.newLine(); + builder.append(" }"); + builder.newLine(); + builder.newLine(); + builder.append(" override protected getMLCommentRule() {"); + builder.newLine(); + builder.append(" // TODO Auto-generated method stub"); + builder.newLine(); + builder.append(" return ML_COMMENTRule"); + builder.newLine(); + builder.append(" }"); + builder.newLine(); + builder.newLine(); + builder.append(" override protected getSLCommentRule() {"); + builder.newLine(); + builder.append(" // TODO Auto-generated method stub"); + builder.newLine(); + builder.append(" return SL_COMMENTRule"); + builder.newLine(); + builder.append(" }"); + builder.newLine(); + builder.newLine(); + builder.append(" override protected isUnformattedContent(String content) {"); + builder.newLine(); + builder.append(" // TODO Auto-generated method stub"); + builder.newLine(); + builder.append(" return false"); + builder.newLine(); + builder.append(" }"); + builder.newLine(); + builder.newLine(); + builder.append("}"); + builder.newLine(); + } + }); + return xtendFile; + } + + protected JavaFileAccess doGetJavaStubFile() { + final JavaFileAccess javaFile = fileAccessFactory.createJavaFile(getFormatterStub(getGrammar())); + javaFile.setResourceSet(getLanguage().getResourceSet()); + + javaFile.setContent(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation builder) { + builder.append("import com.avaloq.tools.ddk.xtext.formatting.ExtendedLineEntry;"); + builder.newLine(); + builder.append("import java.util.List;"); + builder.newLine(); + builder.newLine(); + builder.append("import org.eclipse.xtext.TerminalRule;"); + builder.newLine(); + builder.newLine(); + builder.append("/**"); + builder.newLine(); + builder.append(" * This class contains custom formatting declarations."); + builder.newLine(); + builder.append(" *"); + builder.newLine(); + builder.append(" * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting"); + builder.newLine(); + builder.append(" * on how and when to use it."); + builder.newLine(); + builder.append(" *"); + builder.newLine(); + builder.append(" * Also see {@link org.eclipse.xtext.xtext.XtextFormatter} as an example"); + builder.newLine(); + builder.append(" */"); + builder.newLine(); + builder.append("public class "); + builder.append(getFormatterStub(getGrammar()).getSimpleName()); + builder.append(" extends "); + builder.append(FormatGeneratorUtil.getFormatterName(getGrammar(), "Abstract")); + builder.append(" {"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" @"); + builder.append(Inject.class, " "); + builder.append(" "); + builder.append(grammarAccessExtensions.getGrammarAccess(getGrammar()), " "); + builder.append(" grammarAccess;"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" @Override"); + builder.newLine(); + builder.append(" protected boolean isUnformattedContent(String content) {"); + builder.newLine(); + builder.append(" // TODO Auto-generated method stub"); + builder.newLine(); + builder.append(" return false;"); + builder.newLine(); + builder.append(" }"); + builder.newLine(); + builder.newLine(); + builder.append(" @Override"); + builder.newLine(); + builder.append(" protected TerminalRule getSLCommentRule() {"); + builder.newLine(); + builder.append(" // TODO Auto-generated method stub"); + builder.newLine(); + builder.append(" return grammarAccess.getSL_COMMENTRule();"); + builder.newLine(); + builder.append(" }"); + builder.newLine(); + builder.newLine(); + builder.append(" @Override"); + builder.newLine(); + builder.append(" protected TerminalRule getMLCommentRule() {"); + builder.newLine(); + builder.append(" // TODO Auto-generated method stub"); + builder.newLine(); + builder.append(" return grammarAccess.getML_COMMENTRule();"); + builder.newLine(); + builder.append(" }"); + builder.newLine(); + builder.newLine(); + builder.append(" @Override"); + builder.newLine(); + builder.append(" public String executeCustomPostFormatAction(ExtendedLineEntry lineEntry, List previousEntries) {"); + builder.newLine(); + builder.append(" // TODO Auto-generated method stub"); + builder.newLine(); + builder.append(" return null;"); + builder.newLine(); + builder.append(" }"); + builder.newLine(); + builder.newLine(); + builder.append("}"); + builder.newLine(); + } + }); + return javaFile; + } + + protected TextFileAccess doGetFormatStubFile() { + final TextFileAccess formatFile = fileAccessFactory.createTextFile(getFormatStub(getGrammar())); + + formatFile.setContent(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation builder) { + builder.append("formatter for "); + builder.append(getGrammar().getName()); + builder.newLineIfNotEmpty(); + builder.newLine(); + } + }); + return formatFile; + } +} diff --git a/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.xtend b/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.xtend deleted file mode 100644 index 957a3d0d9f..0000000000 --- a/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.xtend +++ /dev/null @@ -1,239 +0,0 @@ -/** - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * Contributors: - * Avaloq Group AG - initial API and implementation - */ -package com.avaloq.tools.ddk.xtext.format.generator - -import com.avaloq.tools.ddk.xtext.format.FormatStandaloneSetup -import com.avaloq.tools.ddk.xtext.formatting.AbstractExtendedFormatter -import com.avaloq.tools.ddk.xtext.formatting.DirectNodeModelStreamer -import com.avaloq.tools.ddk.xtext.formatting.RegionNodeModelFormatter -import com.google.inject.Inject -import org.apache.logging.log4j.Logger -import org.apache.logging.log4j.LogManager; -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.formatting.IFormatter -import org.eclipse.xtext.formatting.INodeModelFormatter -import org.eclipse.xtext.formatting.INodeModelStreamer -import org.eclipse.xtext.xtext.generator.AbstractStubGeneratingFragment -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming -import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions -import org.eclipse.xtext.xtext.generator.model.FileAccessFactory -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess -import org.eclipse.xtext.xtext.generator.model.TypeReference -import org.eclipse.xtext.xtext.generator.util.BooleanGeneratorOption - -import static org.eclipse.xtext.GrammarUtil.* - -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* - -/** - * MWE fragment for the format language. - */ -class FormatFragment2 extends AbstractStubGeneratingFragment { - - @Inject FileAccessFactory fileAccessFactory - @Inject extension XtextGeneratorNaming - @Inject extension GrammarAccessExtensions - - static final String RUNTIME_PLUGIN = "com.avaloq.tools.ddk.xtext" - - val generateFormatStub = new BooleanGeneratorOption(true) - - def boolean isGenerateFormatStub() { - generateFormatStub.get - } - - def void setGenerateFormatStub(boolean generateStub) { - this.generateFormatStub.set(generateStub) - } - - /** - * Class-wide logger. - */ - static final Logger LOGGER = LogManager::getLogger(typeof(FormatFragment2)) - - /** - * The model for the format resource. - */ - var baseFormatterClassName = AbstractExtendedFormatter.name - - /** - * Set the super type / base class of the formatter. - * @param baseFormatterClass the FQN of the base formatter - */ - def void setBaseFormatterClassName(String baseFormatterClass) { - baseFormatterClassName = baseFormatterClass - } - - /** - * Get the super type / base class of the formatter. - * @return the FQN of the base formatter - */ - def getBaseFormatterClassName() { - return baseFormatterClassName - } - - protected def TypeReference getFormatterStub(Grammar grammar) { - new TypeReference(grammar.runtimeBasePackage + '.formatting.' + getSimpleName(grammar) + 'Formatter') - } - - protected def String getFormatStub(Grammar grammar) { - val formatter = grammar.formatterStub.path - formatter.substring(0, formatter.lastIndexOf('/') + 1) + getSimpleName(grammar) + '.format' - } - - override void generate() { - if (LOGGER.isInfoEnabled()) { - LOGGER.info('''executing generate for «getClass().getName()»'''.toString) - } - - new GuiceModuleAccess.BindingFactory() - .addTypeToType(IFormatter.typeRef, new TypeReference(FormatGeneratorUtil::getFormatterName(grammar, ""))) - .addTypeToType(INodeModelFormatter.typeRef, RegionNodeModelFormatter.typeRef) - .addTypeToType(INodeModelStreamer.typeRef, DirectNodeModelStreamer.typeRef) - .contributeTo(language.runtimeGenModule) - if (projectConfig.runtime.manifest !== null) { - projectConfig.runtime.manifest.requiredBundles += "org.eclipse.emf.ecore" - projectConfig.runtime.manifest.requiredBundles += RUNTIME_PLUGIN - } - if (projectConfig.eclipsePlugin.manifest !== null) { - projectConfig.eclipsePlugin.manifest.requiredBundles += RUNTIME_PLUGIN - } - - if (projectConfig.genericIde.manifest !== null) { - projectConfig.genericIde.manifest.requiredBundles+= RUNTIME_PLUGIN - } - - FormatStandaloneSetup.doSetup() - doGenerateStubFiles() - } - - protected def doGenerateStubFiles() { - if(!isGenerateStub) { - return - } - if (isGenerateXtendStub) { - val xtendFile = doGetXtendStubFile - xtendFile?.writeTo(projectConfig.runtime.src) - } else { - val javaFile = doGetJavaStubFile - javaFile?.writeTo(projectConfig.runtime.src) - } - if (isGenerateFormatStub) { - val formatFile = doGetFormatStubFile - formatFile?.writeTo(projectConfig.runtime.src) - } - } - - protected def doGetXtendStubFile() { - val xtendFile = fileAccessFactory.createXtendFile(grammar.formatterStub) - xtendFile.resourceSet = language.resourceSet - - xtendFile.content = ''' - import com.avaloq.tools.ddk.xtext.formatting.ExtendedLineEntry - import java.util.List - - /** - * This class contains custom formatting declarations. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting - * on how and when to use it. - * - * Also see {@link org.eclipse.xtext.xtext.XtextFormatter} as an example - */ - class «grammar.formatterStub.simpleName» extends «FormatGeneratorUtil::getFormatterName(grammar, "Abstract")» { - - @«Inject» extension «grammar.grammarAccess» - - override executeCustomPostFormatAction(ExtendedLineEntry lineEntry, List previousEntries) { - // TODO Auto-generated method stub - return null - } - - override protected getMLCommentRule() { - // TODO Auto-generated method stub - return ML_COMMENTRule - } - - override protected getSLCommentRule() { - // TODO Auto-generated method stub - return SL_COMMENTRule - } - - override protected isUnformattedContent(String content) { - // TODO Auto-generated method stub - return false - } - - } - ''' - return xtendFile - } - - protected def doGetJavaStubFile() { - val javaFile = fileAccessFactory.createJavaFile(grammar.formatterStub) - javaFile.resourceSet = language.resourceSet - - javaFile.content = ''' - import com.avaloq.tools.ddk.xtext.formatting.ExtendedLineEntry; - import java.util.List; - - import org.eclipse.xtext.TerminalRule; - - /** - * This class contains custom formatting declarations. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting - * on how and when to use it. - * - * Also see {@link org.eclipse.xtext.xtext.XtextFormatter} as an example - */ - public class «grammar.formatterStub.simpleName» extends «FormatGeneratorUtil::getFormatterName(grammar, "Abstract")» { - - @«Inject» «grammar.grammarAccess» grammarAccess; - - @Override - protected boolean isUnformattedContent(String content) { - // TODO Auto-generated method stub - return false; - } - - @Override - protected TerminalRule getSLCommentRule() { - // TODO Auto-generated method stub - return grammarAccess.getSL_COMMENTRule(); - } - - @Override - protected TerminalRule getMLCommentRule() { - // TODO Auto-generated method stub - return grammarAccess.getML_COMMENTRule(); - } - - @Override - public String executeCustomPostFormatAction(ExtendedLineEntry lineEntry, List previousEntries) { - // TODO Auto-generated method stub - return null; - } - - } - ''' - return javaFile - } - - protected def doGetFormatStubFile() { - val formatFile = fileAccessFactory.createTextFile(grammar.formatStub) - - formatFile.content = ''' - formatter for «grammar.name» - - ''' - return formatFile - } -} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.java new file mode 100644 index 0000000000..13a0345ec6 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.format; + +import com.avaloq.tools.ddk.xtext.format.conversion.FormatValueConverterService; +import com.avaloq.tools.ddk.xtext.format.generator.FormatOutputConfigurationProvider; +import com.avaloq.tools.ddk.xtext.format.naming.FormatQualifiedNameConverter; +import com.avaloq.tools.ddk.xtext.format.naming.FormatQualifiedNameProvider; +import com.avaloq.tools.ddk.xtext.format.resource.FormatResource; +import com.avaloq.tools.ddk.xtext.format.resource.FormatResourceDescriptionStrategy; +import com.avaloq.tools.ddk.xtext.format.scoping.FormatLinkingService; +import com.avaloq.tools.ddk.xtext.format.scoping.FormatScopeProvider; +import com.google.inject.Binder; +import com.google.inject.name.Names; +import org.eclipse.xtext.conversion.IValueConverterService; +import org.eclipse.xtext.generator.IOutputConfigurationProvider; +import org.eclipse.xtext.linking.ILinkingService; +import org.eclipse.xtext.linking.LinkingScopeProviderBinding; +import org.eclipse.xtext.naming.IQualifiedNameConverter; +import org.eclipse.xtext.naming.IQualifiedNameProvider; +import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.resource.containers.IAllContainersState; +import org.eclipse.xtext.resource.containers.ResourceSetBasedAllContainersStateProvider; +import org.eclipse.xtext.scoping.IScopeProvider; +import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; +import org.eclipse.xtext.xbase.scoping.XImportSectionNamespaceScopeProvider; +import org.eclipse.xtext.xtext.generator.model.project.IXtextProjectConfig; +import org.eclipse.xtext.xtext.generator.model.project.XtextProjectConfig; + +/** + * Use this class to register components to be used at runtime / without the Equinox extension registry. + */ +public class FormatRuntimeModule extends AbstractFormatRuntimeModule { + + @Override + public Class bindXtextResource() { + return FormatResource.class; + } + + /** + * Binds a class loader required by the resource manager. + * + * @return bound class loader instance + */ + @Override + public ClassLoader bindClassLoaderToInstance() { + return getClass().getClassLoader(); + } + + @Override + public Class bindIValueConverterService() { + return FormatValueConverterService.class; + } + + /** + * Binds custom qualified name converter. + * + * @return the implementation + */ + @Override + public Class bindIQualifiedNameConverter() { + return FormatQualifiedNameConverter.class; + } + + /** {@inheritDoc} */ + @Override + public Class bindIQualifiedNameProvider() { + return FormatQualifiedNameProvider.class; + } + + /** {@inheritDoc} */ + @Override + public Class bindIScopeProvider() { + return FormatScopeProvider.class; + } + + /** {@inheritDoc} */ + @Override + public void configureLinkingIScopeProvider(final Binder binder) { + binder.bind(IScopeProvider.class).annotatedWith(LinkingScopeProviderBinding.class).to(FormatScopeProvider.class); + } + + /** {@inheritDoc} */ + @Override + // CHECKSTYLE:OFF + public Class bindIAllContainersState$Provider() { + // CHECKSTYLE:ON + return ResourceSetBasedAllContainersStateProvider.class; + } + + /** {@inheritDoc} */ + @Override + public Class bindILinkingService() { + return FormatLinkingService.class; + } + + /** {@inheritDoc} */ + @Override + public Class bindIDefaultResourceDescriptionStrategy() { + return FormatResourceDescriptionStrategy.class; + } + + /** + * Binds a custom output configuration provider. + * + * @return the format output configuration provider + */ + public Class bindIOutputConfigurationProvider() { + return FormatOutputConfigurationProvider.class; + } + + /** {@inheritDoc} */ + @Override + public void configureIScopeProviderDelegate(final Binder binder) { + binder.bind(IScopeProvider.class).annotatedWith(Names.named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE)).to(XImportSectionNamespaceScopeProvider.class); + } + + @Override + public void configure(final Binder binder) { + super.configure(binder); + binder.bind(IXtextProjectConfig.class).to(XtextProjectConfig.class); + } +} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.xtend b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.xtend deleted file mode 100644 index 1d10e8b1de..0000000000 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.xtend +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.format - -import com.avaloq.tools.ddk.xtext.format.conversion.FormatValueConverterService -import com.avaloq.tools.ddk.xtext.format.generator.FormatOutputConfigurationProvider -import com.avaloq.tools.ddk.xtext.format.naming.FormatQualifiedNameConverter -import com.avaloq.tools.ddk.xtext.format.naming.FormatQualifiedNameProvider -import com.avaloq.tools.ddk.xtext.format.resource.FormatResource -import com.avaloq.tools.ddk.xtext.format.resource.FormatResourceDescriptionStrategy -import com.avaloq.tools.ddk.xtext.format.scoping.FormatLinkingService -import com.avaloq.tools.ddk.xtext.format.scoping.FormatScopeProvider -import com.google.inject.Binder -import com.google.inject.name.Names -import org.eclipse.xtext.generator.IOutputConfigurationProvider -import org.eclipse.xtext.linking.LinkingScopeProviderBinding -import org.eclipse.xtext.resource.containers.ResourceSetBasedAllContainersStateProvider -import org.eclipse.xtext.scoping.IScopeProvider -import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider -import org.eclipse.xtext.xbase.scoping.XImportSectionNamespaceScopeProvider -import org.eclipse.xtext.xtext.generator.model.project.IXtextProjectConfig -import org.eclipse.xtext.xtext.generator.model.project.XtextProjectConfig - -/** - * Use this class to register components to be used at runtime / without the Equinox extension registry. - */ -class FormatRuntimeModule extends AbstractFormatRuntimeModule { - - override bindXtextResource() { - return FormatResource - } - - /** - * Binds a class loader required by the resource manager. - * - * @return bound class loader instance - */ - override bindClassLoaderToInstance() { - return getClass().getClassLoader() - } - - override bindIValueConverterService() { - return FormatValueConverterService - } - - /** - * Binds custom qualified name converter. - * - * @return the implementation - */ - override bindIQualifiedNameConverter() { - return FormatQualifiedNameConverter - } - - /** {@inheritDoc} */ - override bindIQualifiedNameProvider() { - return FormatQualifiedNameProvider - } - - /** {@inheritDoc} */ - override bindIScopeProvider() { - return FormatScopeProvider - } - - /** {@inheritDoc} */ - override configureLinkingIScopeProvider(Binder binder) { - binder.bind(IScopeProvider).annotatedWith(LinkingScopeProviderBinding).to(FormatScopeProvider) - } - - /** {@inheritDoc} */ - override - // CHECKSTYLE:OFF - bindIAllContainersState$Provider() { - // CHECKSTYLE:ON - return ResourceSetBasedAllContainersStateProvider - } - - /** {@inheritDoc} */ - override bindILinkingService() { - return FormatLinkingService - } - - /** {@inheritDoc} */ - override bindIDefaultResourceDescriptionStrategy() { - return FormatResourceDescriptionStrategy - } - - /** - * Binds a custom output configuration provider. - * - * @return the format output configuration provider - */ - def Class bindIOutputConfigurationProvider() { - return FormatOutputConfigurationProvider - } - - /** {@inheritDoc} */ - override configureIScopeProviderDelegate(Binder binder) { - binder.bind(IScopeProvider).annotatedWith(Names.named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE)).to(XImportSectionNamespaceScopeProvider) - } - - override configure(Binder binder) { - super.configure(binder); - binder.bind(IXtextProjectConfig).to(XtextProjectConfig); - } -} - diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java new file mode 100644 index 0000000000..11749a647e --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.format.generator; + +import static com.avaloq.tools.ddk.xtext.format.generator.FormatGeneratorUtil.getFormatterName; + +import com.avaloq.tools.ddk.xtext.format.FormatConstants; +import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.common.types.JvmConstructor; +import org.eclipse.xtext.common.types.JvmDeclaredType; +import org.eclipse.xtext.common.types.JvmField; +import org.eclipse.xtext.common.types.JvmMember; +import org.eclipse.xtext.common.types.JvmOperation; +import org.eclipse.xtext.generator.IFileSystemAccess; +import org.eclipse.xtext.util.Strings; +import org.eclipse.xtext.xbase.compiler.DocumentationAdapter; +import org.eclipse.xtext.xbase.compiler.ErrorSafeExtensions; +import org.eclipse.xtext.xbase.compiler.GeneratorConfig; +import org.eclipse.xtext.xbase.compiler.JvmModelGenerator; +import org.eclipse.xtext.xbase.compiler.TreeAppendableUtil; +import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.IteratorExtensions; + +/** + * Generates code from your model files on save. + * + * Currently this generator is not used at all. + * This is a side effect of the usage of the org.eclipse.xtext.generator.generator.GeneratorFragment.GeneratorFragment, + * which generates this file besides necessary contents for org.eclipse.xtext.builder.BuilderParticipant. + * + * see http://www.eclipse.org/Xtext/documentation.html#TutorialCodeGeneration + */ +public class FormatGenerator extends JvmModelGenerator { + + @Inject + private TreeAppendableUtil _treeAppendableUtil; + + @Inject + private ErrorSafeExtensions _errorSafeExtensions; + + public String getSingleCommentDocumentation(final EObject it, final ITreeAppendable appendable, final GeneratorConfig config) { + final DocumentationAdapter adapter = IterableExtensions.head(Iterables.filter(it.eAdapters(), DocumentationAdapter.class)); + String documentation = null; + if (adapter != null) { + documentation = adapter.getDocumentation(); + } + boolean isNullOrEmpty = documentation == null || documentation.isEmpty(); + if (!isNullOrEmpty) { + return adapter.getDocumentation(); + } + return null; + } + + @Override + protected ITreeAppendable _generateMember(final JvmField it, final ITreeAppendable appendable, final GeneratorConfig config) { + appendable.newLine(); + final ITreeAppendable tracedAppendable = appendable.trace(it); + generateAnnotations(it.getAnnotations(), tracedAppendable, true, config); + generateModifier(it, tracedAppendable, config); + _errorSafeExtensions.serializeSafely(it.getType(), "Object", tracedAppendable); + tracedAppendable.append(" "); + _treeAppendableUtil.traceSignificant(tracedAppendable, it).append(it.getSimpleName()); + generateInitialization(it, tracedAppendable, config); + tracedAppendable.append(";"); + String documentation = getSingleCommentDocumentation(it, appendable, config); + if (documentation != null && documentation.endsWith("\r\n")) { + documentation = documentation.substring(0, documentation.length() - 2); + } + if (documentation != null) { + tracedAppendable.append(" // "); + tracedAppendable.append(documentation); + } + return tracedAppendable; + } + + @Override + public void doGenerate(final Resource resource, final IFileSystemAccess fsa) { + super.doGenerate(resource, fsa); // Generate the abstract formatter from inferred Jvm models. + + for (final FormatConfiguration model : Iterables.filter(IteratorExtensions.toIterable(resource.getAllContents()), FormatConfiguration.class)) { + String path = getFormatterName(model, "").replace(".", "/") + ".java"; + fsa.generateFile(path, FormatConstants.FORMATTER, generateSrc(model)); + } + } + + public CharSequence generateSrc(final FormatConfiguration model) { + final StringBuilder builder = new StringBuilder(); + builder.append("package ").append(Strings.skipLastToken(getFormatterName(model, ""), ".")).append(";\n"); + builder.append("\n"); + builder.append("/**\n"); + builder.append(" * The formatting configuration for ").append(Strings.lastToken(model.getTargetGrammar().getName(), ".")).append(".\n"); + builder.append(" */\n"); + builder.append("public class ").append(Strings.lastToken(getFormatterName(model, ""), ".")).append(" extends ").append(Strings.lastToken(getFormatterName(model, "Abstract"), ".")).append(" {\n"); + builder.append(" // TODO: Provide a correct implementation of getSLCommentRule() and getMLCommentRule() in this class\n"); + builder.append("}\n"); + return builder; + } + + @Override + public ITreeAppendable generateMember(final JvmMember it, final ITreeAppendable appendable, final GeneratorConfig config) { + if (it instanceof JvmConstructor) { + return _generateMember((JvmConstructor) it, appendable, config); + } else if (it instanceof JvmOperation) { + return _generateMember((JvmOperation) it, appendable, config); + } else if (it instanceof JvmField jvmField) { + return _generateMember(jvmField, appendable, config); + } else if (it instanceof JvmDeclaredType) { + return _generateMember((JvmDeclaredType) it, appendable, config); + } else if (it != null) { + return _generateMember(it, appendable, config); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + java.util.Arrays.asList(it, appendable, config).toString()); + } + } +} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.xtend b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.xtend deleted file mode 100644 index 0ecfb6910a..0000000000 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.xtend +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.format.generator - -import com.google.inject.Inject -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.common.types.JvmField -import org.eclipse.xtext.generator.IFileSystemAccess -import org.eclipse.xtext.xbase.compiler.DocumentationAdapter -import org.eclipse.xtext.xbase.compiler.ErrorSafeExtensions -import org.eclipse.xtext.xbase.compiler.GeneratorConfig -import org.eclipse.xtext.xbase.compiler.JvmModelGenerator -import org.eclipse.xtext.xbase.compiler.TreeAppendableUtil -import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable - -import static com.avaloq.tools.ddk.xtext.format.generator.FormatGeneratorUtil.* -import static org.eclipse.xtext.xbase.lib.IteratorExtensions.* -import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration -import com.avaloq.tools.ddk.xtext.format.FormatConstants -import org.eclipse.xtext.util.Strings - -/** - * Generates code from your model files on save. - * - * Currently this generator is not used at all. - * This is a side effect of the usage of the org.eclipse.xtext.generator.generator.GeneratorFragment.GeneratorFragment, - * which generates this file besides necessary contents for org.eclipse.xtext.builder.BuilderParticipant. - * - * see http://www.eclipse.org/Xtext/documentation.html#TutorialCodeGeneration - */ -class FormatGenerator extends JvmModelGenerator { - - @Inject extension TreeAppendableUtil - @Inject extension ErrorSafeExtensions - - def getSingleCommentDocumentation(EObject it, ITreeAppendable appendable, GeneratorConfig config) { - val adapter = it.eAdapters.filter(DocumentationAdapter).head - if (!adapter?.documentation.nullOrEmpty) { - return adapter.documentation - } - return null - } - - override dispatch generateMember(JvmField it, ITreeAppendable appendable, GeneratorConfig config) { - appendable.newLine - val tracedAppendable = appendable.trace(it) - annotations.generateAnnotations(tracedAppendable, true, config) - generateModifier(tracedAppendable, config) - type.serializeSafely("Object", tracedAppendable) - tracedAppendable.append(" ") - tracedAppendable.traceSignificant(it).append(simpleName) - generateInitialization(tracedAppendable, config) - tracedAppendable.append(";") - var documentation = getSingleCommentDocumentation(appendable, config) - if (documentation !== null && documentation.endsWith("\r\n")) { - documentation = documentation.substring(0, documentation.length - 2) - } - if (documentation !== null) { - tracedAppendable.append(" // ") - tracedAppendable.append(documentation) - } - } - - override void doGenerate(Resource resource, IFileSystemAccess fsa) { - super.doGenerate(resource, fsa); // Generate the abstract formatter from inferred Jvm models. - - for (model : toIterable(resource.allContents).filter(typeof(FormatConfiguration))) { - fsa.generateFile(getFormatterName(model, "").replace('.', '/') + ".java", FormatConstants.FORMATTER, - model.generateSrc) - } - } - - def generateSrc(FormatConfiguration model) ''' - package «Strings.skipLastToken(getFormatterName(model, ""), ".")»; - - /** - * The formatting configuration for «Strings.lastToken(model.targetGrammar.name,".")». - */ - public class «Strings.lastToken(getFormatterName(model, ""),".")» extends «Strings.lastToken(getFormatterName(model, "Abstract"),".")» { - // TODO: Provide a correct implementation of getSLCommentRule() and getMLCommentRule() in this class - } - ''' - -} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java new file mode 100644 index 0000000000..36e09c4543 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java @@ -0,0 +1,1297 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.format.jvmmodel; + +import static com.avaloq.tools.ddk.xtext.util.EObjectUtil.getFileLocation; +import static org.eclipse.xtext.GrammarUtil.getGrammar; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Pattern; +import org.eclipse.emf.common.util.BasicEList; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.xtext.AbstractElement; +import org.eclipse.xtext.AbstractMetamodelDeclaration; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.EnumRule; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.ParserRule; +import org.eclipse.xtext.TerminalRule; +import org.eclipse.xtext.TypeRef; +import org.eclipse.xtext.common.types.JvmAnnotationReference; +import org.eclipse.xtext.common.types.JvmAnnotationType; +import org.eclipse.xtext.common.types.JvmDeclaredType; +import org.eclipse.xtext.common.types.JvmFormalParameter; +import org.eclipse.xtext.common.types.JvmGenericType; +import org.eclipse.xtext.common.types.JvmMember; +import org.eclipse.xtext.common.types.JvmOperation; +import org.eclipse.xtext.common.types.JvmType; +import org.eclipse.xtext.common.types.JvmTypeReference; +import org.eclipse.xtext.common.types.JvmVisibility; +import org.eclipse.xtext.common.types.TypesFactory; +import org.eclipse.xtext.common.types.util.TypeReferences; +import org.eclipse.xtext.util.Strings; +import org.eclipse.xtext.xbase.XExpression; +import org.eclipse.xtext.xbase.compiler.XbaseCompiler; +import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable; +import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer; +import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor; +import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.Conversions; +import org.eclipse.xtext.xbase.lib.ExclusiveRange; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.ListExtensions; +import org.eclipse.xtext.xbase.lib.Pair; +import org.eclipse.xtext.xbase.lib.StringExtensions; +import org.eclipse.xtext.xtext.RuleNames; +import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions; + +import com.avaloq.tools.ddk.xtext.format.format.ColumnLocator; +import com.avaloq.tools.ddk.xtext.format.format.Constant; +import com.avaloq.tools.ddk.xtext.format.format.ContextFreeDirective; +import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration; +import com.avaloq.tools.ddk.xtext.format.format.GrammarElementLookup; +import com.avaloq.tools.ddk.xtext.format.format.GrammarElementReference; +import com.avaloq.tools.ddk.xtext.format.format.GrammarRule; +import com.avaloq.tools.ddk.xtext.format.format.GrammarRuleDirective; +import com.avaloq.tools.ddk.xtext.format.format.GroupBlock; +import com.avaloq.tools.ddk.xtext.format.format.IndentLocator; +import com.avaloq.tools.ddk.xtext.format.format.IntValue; +import com.avaloq.tools.ddk.xtext.format.format.KeywordPair; +import com.avaloq.tools.ddk.xtext.format.format.LinewrapLocator; +import com.avaloq.tools.ddk.xtext.format.format.Locator; +import com.avaloq.tools.ddk.xtext.format.format.Matcher; +import com.avaloq.tools.ddk.xtext.format.format.MatcherList; +import com.avaloq.tools.ddk.xtext.format.format.MatcherType; +import com.avaloq.tools.ddk.xtext.format.format.NoFormatLocator; +import com.avaloq.tools.ddk.xtext.format.format.OffsetLocator; +import com.avaloq.tools.ddk.xtext.format.format.RightPaddingLocator; +import com.avaloq.tools.ddk.xtext.format.format.Rule; +import com.avaloq.tools.ddk.xtext.format.format.SpaceLocator; +import com.avaloq.tools.ddk.xtext.format.format.SpecificDirective; +import com.avaloq.tools.ddk.xtext.format.format.StringValue; +import com.avaloq.tools.ddk.xtext.format.format.WildcardRule; +import com.avaloq.tools.ddk.xtext.format.format.WildcardRuleDirective; +import com.avaloq.tools.ddk.xtext.format.generator.FormatGeneratorUtil; +import com.avaloq.tools.ddk.xtext.formatting.AbstractExtendedFormatter; +import com.avaloq.tools.ddk.xtext.formatting.ExtendedFormattingConfig; +import com.avaloq.tools.ddk.xtext.formatting.locators.LocatorActivator; +import com.avaloq.tools.ddk.xtext.formatting.locators.LocatorParameterCalculator; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; + +/** + *

Infers a JVM model from the source model.

+ * + *

The JVM model should contain all elements that would appear in the Java code + * which is generated from the source model. Other models link against the JVM model rather than the source model.

+ */ +public class FormatJvmModelInferrer extends AbstractModelInferrer { + + @Inject + private JvmTypesBuilder _jvmTypesBuilder; + + @Inject + private TypeReferences _typeReferences; + + @Inject + private GrammarAccessExtensions grammarAccess; + + @Inject + private TypesFactory typesFactory; + + @Inject + private XbaseCompiler xbaseCompiler; + + private static final String BASE_FORMATTER_CLASS_NAME = AbstractExtendedFormatter.class.getName(); + + private static final String BASE_FORMAT_CONFIG = ExtendedFormattingConfig.class.getName(); + + private static final String METHOD_ACTIVATE = "activate"; + + private static final String METHOD_CALCULATE = "calculateParameter"; + + private static final String PARAMETER_CONFIG = "config"; + + private static final String PARAMETER_ELEMENTS = "elements"; + + private static final String PARAMETER_RULE = "rule"; + + private static final String PARAMETER_GRAMMAR_ACCESS = "grammarAccess"; + + private static final String PARAMETER_CONTEXT = "context"; + + private static final String PARAMETER_COLUMN = "currentColumn"; + + /** + * The dispatch method {@code infer} is called for each instance of the + * given element's type that is contained in a resource. + * + * @param element + * the model to create one or more {@link JvmDeclaredType declared types} from. + * @param acceptor + * each created {@link JvmDeclaredType type} without a container should be passed to the acceptor in order + * get attached to the current resource. The acceptor's {@link IJvmDeclaredTypeAcceptor#accept(JvmDeclaredType, + * org.eclipse.xtext.xbase.lib.Procedures.Procedure1)} method takes the constructed empty type for the + * pre-indexing phase. This one is further initialized in the indexing phase using the passed closure. + * @param isPreIndexingPhase + * whether the method is called in a pre-indexing phase, i.e. when the global index is not yet fully updated. You must not + * rely on linking using the index if isPreIndexingPhase is {@code true}. + */ + protected void _infer(final FormatConfiguration format, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase) { + if (isPreIndexingPhase) { + return; + } + final Grammar context = format.getTargetGrammar(); + if (EcoreUtil.getAdapter(context.eAdapters(), RuleNames.class) == null) { + final List allRules = GrammarUtil.allRules(context); + for (final AbstractRule rule : allRules) { + final Object adpt = EcoreUtil.getAdapter(rule.eAdapters(), RuleNames.class); + if (adpt != null) { + rule.eAdapters().remove(adpt); + } + } + RuleNames.getRuleNames(context, true); + } + acceptor.accept( + _jvmTypesBuilder.toClass(format, Strings.lastToken(FormatGeneratorUtil.getFormatterName(format, "Abstract"), ".")), (JvmGenericType it) -> { + inferClass(format, it); + inferConstants(format, it); + inferGetGrammarAccess(format, it); + inferConfigureAcsFormatting(format, it); + inferInit(format, it); + inferRules(format, it); + inferLocatorActivators(format, it); + }); + } + + public void inferClass(final FormatConfiguration format, final JvmGenericType it) { + Grammar targetGrammar = format.getTargetGrammar(); + String targetGrammarNameRaw = targetGrammar != null ? targetGrammar.getName() : null; + String targetGrammarName = Strings.emptyIfNull(targetGrammarNameRaw); + _jvmTypesBuilder.setDocumentation(it, + "The abstract formatting configuration for " + Strings.skipLastToken(targetGrammarName, ".") + "." + Strings.lastToken(targetGrammarName, ".") + " as declared in " + Strings.lastToken(targetGrammarName, ".") + ".format."); + if (format.getFormatterBaseClass() != null) { + _jvmTypesBuilder.operator_add(it.getSuperTypes(), + _typeReferenceBuilder.typeRef(format.getFormatterBaseClass().getPackageName() + "." + format.getFormatterBaseClass().getSimpleName())); + } else { + _jvmTypesBuilder.operator_add(it.getSuperTypes(), + _typeReferenceBuilder.typeRef(BASE_FORMATTER_CLASS_NAME)); + } + it.setPackageName(Strings.skipLastToken(FormatGeneratorUtil.getFormatterName(format, ""), ".")); + it.setAbstract(true); + } + + public boolean inferConstants(final FormatConfiguration format, final JvmGenericType it) { + if (!FormatGeneratorUtil.getAllConstants(format).isEmpty()) { + return _jvmTypesBuilder.operator_add(it.getMembers(), + ListExtensions.map(FormatGeneratorUtil.getAllConstants(format), (Constant c) -> createConstant(format, c))); + } + return false; + } + + public String getFullyQualifiedName(final Grammar g) { + return GrammarUtil.getNamespace(g) + ".services." + GrammarUtil.getSimpleName(g) + "GrammarAccess"; + } + + public boolean inferGetGrammarAccess(final FormatConfiguration format, final JvmGenericType it) { + JvmOperation method = _jvmTypesBuilder.toMethod(format, "getGrammarAccess", + _typeReferences.getTypeForName(getFullyQualifiedName(format.getTargetGrammar()), format.getTargetGrammar()), (JvmOperation it_1) -> { + it_1.setVisibility(JvmVisibility.PROTECTED); + final JvmAnnotationReference overrideAnnotation = createOverrideAnnotation(format); + if (overrideAnnotation != null) { + _jvmTypesBuilder.operator_add(it_1.getAnnotations(), overrideAnnotation); + } + _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { + StringBuilder sb = new StringBuilder(); + sb.append("return ("); + sb.append(GrammarUtil.getSimpleName(format.getTargetGrammar()) + "GrammarAccess"); + sb.append(") super.getGrammarAccess();"); + it_2.append(sb); + }); + }); + return _jvmTypesBuilder.operator_add(it.getMembers(), method); + } + + public boolean inferConfigureAcsFormatting(final FormatConfiguration format, final JvmGenericType it) { + JvmOperation method = _jvmTypesBuilder.toMethod(format, "configureAcsFormatting", _typeReferenceBuilder.typeRef("void"), (JvmOperation it_1) -> { + it_1.setVisibility(JvmVisibility.PROTECTED); + final JvmAnnotationReference overrideAnnotation = createOverrideAnnotation(format); + if (overrideAnnotation != null) { + _jvmTypesBuilder.operator_add(it_1.getAnnotations(), overrideAnnotation); + } + _jvmTypesBuilder.operator_add(it_1.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); + _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { + it_2.append("init(config, getGrammarAccess());"); + }); + }); + return _jvmTypesBuilder.operator_add(it.getMembers(), method); + } + + public boolean inferInit(final FormatConfiguration format, final JvmGenericType it) { + JvmOperation method = _jvmTypesBuilder.toMethod(format, "init", _typeReferenceBuilder.typeRef("void"), (JvmOperation it_1) -> { + Pair mappedTo = Pair.of(PARAMETER_CONFIG, "the format configuration"); + Pair mappedTo_1 = Pair.of(PARAMETER_GRAMMAR_ACCESS, "the grammar access for the grammar"); + _jvmTypesBuilder.setDocumentation(it_1, generateJavaDoc("Calls all configXyz methods declared in this class.", CollectionLiterals.newLinkedHashMap(mappedTo, mappedTo_1))); + it_1.setVisibility(JvmVisibility.PROTECTED); + _jvmTypesBuilder.operator_add(it_1.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); + _jvmTypesBuilder.operator_add(it_1.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_GRAMMAR_ACCESS, _typeReferenceBuilder.typeRef(getFullyQualifiedName(format.getTargetGrammar())))); + _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { + final ArrayList rules = listConfigRules(format); + int length = ((Object[]) Conversions.unwrapArray(rules, Object.class)).length; + ExclusiveRange range = new ExclusiveRange(0, length, true); + for (final Integer i : range) { + if (i.intValue() != 0) { + it_2.newLine(); + } + it_2.append(rules.get(i.intValue())); + } + }); + }); + return _jvmTypesBuilder.operator_add(it.getMembers(), method); + } + + public boolean inferRules(final FormatConfiguration format, final JvmGenericType it) { + _jvmTypesBuilder.operator_add(it.getMembers(), + Iterables.concat(ListExtensions.>map(FormatGeneratorUtil.getParserRules(format), (GrammarRule c) -> createRule(format, c)))); + _jvmTypesBuilder.operator_add(it.getMembers(), + Iterables.concat(ListExtensions.>map(FormatGeneratorUtil.getEnumRules(format), (GrammarRule c) -> createRule(format, c)))); + _jvmTypesBuilder.operator_add(it.getMembers(), + Iterables.concat(ListExtensions.>map(FormatGeneratorUtil.getTerminalRules(format), (GrammarRule c) -> createRule(format, c)))); + boolean result = false; + if (FormatGeneratorUtil.getWildcardRule(format) != null) { + JvmOperation method = _jvmTypesBuilder.toMethod(format, "configFindElements", _typeReferenceBuilder.typeRef("void"), (JvmOperation it_1) -> { + Pair mappedTo = Pair.of(PARAMETER_CONFIG, "the format configuration"); + Pair mappedTo_1 = Pair.of(PARAMETER_ELEMENTS, "the grammar access for the grammar"); + _jvmTypesBuilder.setDocumentation(it_1, generateJavaDoc("Configuration for IGrammarAccess.findXyz() methods.", CollectionLiterals.newLinkedHashMap(mappedTo, mappedTo_1))); + it_1.setVisibility(JvmVisibility.PROTECTED); + _jvmTypesBuilder.operator_add(it_1.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); + _jvmTypesBuilder.operator_add(it_1.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_ELEMENTS, _typeReferenceBuilder.typeRef(getFullyQualifiedName(getGrammar(format.getTargetGrammar()))))); + _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { + final List directives = ListExtensions.map( + FormatGeneratorUtil.getWildcardRule(format).getDirectives(), + (WildcardRuleDirective d) -> directive(d, getRuleName(FormatGeneratorUtil.getWildcardRule(format))).toString()); + it_2.append(fixLastLine(IterableExtensions.join(directives))); + }); + }); + result = _jvmTypesBuilder.operator_add(it.getMembers(), method); + } + return result; + } + + public void inferLocatorActivators(final FormatConfiguration format, final JvmGenericType it) { + List rules = new LinkedList<>(); + Iterables.addAll(rules, + Iterables.concat( + Iterables.concat(FormatGeneratorUtil.getParserRules(format), FormatGeneratorUtil.getTerminalRules(format)), + FormatGeneratorUtil.getEnumRules(format))); + rules.add(FormatGeneratorUtil.getWildcardRule(format)); + for (final Rule rule : rules) { + List directives = new LinkedList<>(); + if (rule instanceof GrammarRule grammarRule) { + Iterables.addAll(directives, grammarRule.getDirectives()); + } else if (rule instanceof WildcardRule wildcardRule) { + Iterables.addAll(directives, wildcardRule.getDirectives()); + } + for (final EObject directive : IterableExtensions.filterNull(directives)) { + for (final Matcher matcher : collectMatchers(directive)) { + if ((matcher.getLocator() instanceof ColumnLocator) && (((ColumnLocator) matcher.getLocator()).getParameter() != null)) { + _jvmTypesBuilder.operator_add(it.getMembers(), + createParameterCalculatorInnerClass(format, rule, directive, matcher, ((ColumnLocator) matcher.getLocator()).getParameter(), it)); + } + if ((matcher.getLocator() instanceof IndentLocator) && (((IndentLocator) matcher.getLocator()).getParameter() != null)) { + _jvmTypesBuilder.operator_add(it.getMembers(), + createParameterCalculatorInnerClass(format, rule, directive, matcher, ((IndentLocator) matcher.getLocator()).getParameter(), it)); + } + if (matcher.getCondition() != null) { + _jvmTypesBuilder.operator_add(it.getMembers(), + createLocatorActivatorInnerClass(format, rule, directive, matcher, it)); + } + } + } + } + } + + public JvmGenericType createLocatorActivatorInnerClass(final FormatConfiguration format, final Rule rule, final EObject directive, final Matcher matcher, final JvmGenericType type) { + return _jvmTypesBuilder.toClass(format, getLocatorActivatorName(rule, directive, matcher), (JvmGenericType it) -> { + it.setStatic(true); + it.setFinal(true); + it.setVisibility(JvmVisibility.PROTECTED); + _jvmTypesBuilder.operator_add(it.getSuperTypes(), getLocatorActivatorSuperType(format, rule)); + JvmOperation method = _jvmTypesBuilder.toMethod(matcher, METHOD_ACTIVATE, getLocatorActivatorReturnType(format), (JvmOperation it_1) -> { + _jvmTypesBuilder.operator_add(it_1.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_CONTEXT, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), format))); + _jvmTypesBuilder.operator_add(it_1.getParameters(), createCurrenctColumnParameter()); + if (!Objects.equals(format.eResource(), matcher.eResource())) { + _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { + xbaseCompiler.compile(matcher.getCondition(), it_2, getLocatorActivatorReturnType(format), null); + }); + } else { + _jvmTypesBuilder.setBody(it_1, matcher.getCondition()); + } + }); + _jvmTypesBuilder.operator_add(it.getMembers(), method); + }); + } + + public JvmFormalParameter createCurrenctColumnParameter() { + JvmFormalParameter result = typesFactory.createJvmFormalParameter(); + result.setName(PARAMETER_COLUMN); + result.setParameterType(_typeReferenceBuilder.typeRef(Integer.class)); + return result; + } + + public JvmGenericType createParameterCalculatorInnerClass(final FormatConfiguration format, final Rule rule, final EObject directive, final Matcher matcher, final XExpression parameterCalculation, final JvmGenericType type) { + return _jvmTypesBuilder.toClass(format, getParameterCalculatorName(rule, directive, matcher), (JvmGenericType it) -> { + it.setStatic(true); + it.setFinal(true); + it.setVisibility(JvmVisibility.PROTECTED); + _jvmTypesBuilder.operator_add(it.getSuperTypes(), getParameterCalculatorSuperType(format, rule)); + JvmOperation method = _jvmTypesBuilder.toMethod(matcher, METHOD_CALCULATE, getParameterCalculatorReturnType(format), (JvmOperation it_1) -> { + _jvmTypesBuilder.operator_add(it_1.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_CONTEXT, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), format))); + _jvmTypesBuilder.operator_add(it_1.getParameters(), createCurrenctColumnParameter()); + if (!Objects.equals(format.eResource(), matcher.eResource())) { + _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { + xbaseCompiler.compile(parameterCalculation, it_2, getParameterCalculatorReturnType(format), null); + }); + } else { + _jvmTypesBuilder.setBody(it_1, parameterCalculation); + } + }); + _jvmTypesBuilder.operator_add(it.getMembers(), method); + }); + } + + public ArrayList listConfigRules(final FormatConfiguration format) { + final ArrayList configRules = CollectionLiterals.newArrayList(); + if (FormatGeneratorUtil.getWildcardRule(format) != null) { + configRules.add("configFindElements(config, grammarAccess);"); + } + for (final GrammarRule rule : FormatGeneratorUtil.getParserRules(format)) { + configRules.add("config" + rule.getTargetRule().getName() + "(config, grammarAccess." + grammarAccess.gaElementsAccessor(rule.getTargetRule()) + ");"); + } + for (final GrammarRule rule : FormatGeneratorUtil.getEnumRules(format)) { + configRules.add("config" + rule.getTargetRule().getName() + "(config, grammarAccess." + grammarAccess.gaRuleAccessor(rule.getTargetRule()) + ");"); + } + for (final GrammarRule rule : FormatGeneratorUtil.getTerminalRules(format)) { + configRules.add("config" + rule.getTargetRule().getName() + "(config, grammarAccess." + grammarAccess.gaRuleAccessor(rule.getTargetRule()) + ");"); + } + return configRules; + } + + public String generateJavaDoc(final String description, final Map parameters) { + final StringBuilder sb = new StringBuilder(); + sb.append(description).append("\n"); + sb.append("\n"); + for (final Map.Entry parameter : parameters.entrySet()) { + sb.append("@param ").append(parameter.getKey()).append("\n"); + sb.append(" - ").append(parameter.getValue()).append("\n"); + } + return sb.toString(); + } + + public JvmAnnotationReference createOverrideAnnotation(final FormatConfiguration format) { + final JvmTypeReference annotationTypeRef = _typeReferenceBuilder.typeRef(Override.class); + JvmAnnotationReference overrideAnnotation = null; + if (annotationTypeRef != null) { + final JvmType annotationType = annotationTypeRef.getType(); + overrideAnnotation = typesFactory.createJvmAnnotationReference(); + overrideAnnotation.setAnnotation((JvmAnnotationType) annotationType); + } + return overrideAnnotation; + } + + public JvmMember createConstant(final FormatConfiguration configuration, final Constant constant) { + if (constant.getStringValue() != null) { + return _jvmTypesBuilder.toField(constant, constant.getName(), _typeReferences.getTypeForName("String", constant), (it) -> { + _jvmTypesBuilder.setDocumentation(it, locatorString(constant)); + it.setStatic(true); + it.setFinal(true); + it.setVisibility(JvmVisibility.PROTECTED); + _jvmTypesBuilder.setInitializer(it, (ITreeAppendable it_1) -> { + it_1.append("\"" + constant.getStringValue() + "\""); + }); + }); + } else if (constant.getIntValue() != null) { + return _jvmTypesBuilder.toField(constant, constant.getName(), _typeReferences.getTypeForName("int", constant), (it) -> { + _jvmTypesBuilder.setDocumentation(it, locatorString(constant)); + it.setStatic(true); + it.setFinal(true); + it.setVisibility(JvmVisibility.PROTECTED); + _jvmTypesBuilder.setInitializer(it, (ITreeAppendable it_1) -> { + it_1.append(constant.getIntValue().toString()); + }); + }); + } + return null; + } + + public List collectMatchers(final EObject directive) { + List matchers = new LinkedList<>(); + if (directive instanceof GroupBlock groupBlock) { + if (groupBlock.getMatcherList() != null) { + Iterables.addAll(matchers, groupBlock.getMatcherList().getMatchers()); + } + } else if (directive instanceof SpecificDirective specificDirective) { + if (specificDirective.getMatcherList() != null) { + Iterables.addAll(matchers, specificDirective.getMatcherList().getMatchers()); + } + } else if (directive instanceof ContextFreeDirective contextFreeDirective) { + if (contextFreeDirective.getMatcherList() != null) { + Iterables.addAll(matchers, contextFreeDirective.getMatcherList().getMatchers()); + } + } else if (directive instanceof KeywordPair keywordPair) { + if (keywordPair.getLeftMatchers() != null) { + Iterables.addAll(matchers, keywordPair.getLeftMatchers()); + } + if (keywordPair.getRightMatchers() != null) { + Iterables.addAll(matchers, keywordPair.getRightMatchers()); + } + } + return matchers; + } + + public JvmTypeReference getLocatorActivatorReturnType(final FormatConfiguration formatConfiguration) { + return _typeReferenceBuilder.typeRef(boolean.class); + } + + public JvmTypeReference getParameterCalculatorReturnType(final FormatConfiguration formatConfiguration) { + return _typeReferenceBuilder.typeRef(int.class); + } + + // getLocatorActivatorSuperType dispatch + protected JvmTypeReference _getLocatorActivatorSuperType(final FormatConfiguration formatConfiguration, final GrammarRule rule) { + return _typeReferenceBuilder.typeRef(LocatorActivator.class, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); + } + + protected JvmTypeReference _getLocatorActivatorSuperType(final FormatConfiguration formatConfiguration, final WildcardRule rule) { + return _typeReferenceBuilder.typeRef(LocatorActivator.class, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); + } + + public JvmTypeReference getLocatorActivatorSuperType(final FormatConfiguration formatConfiguration, final Rule rule) { + if (rule instanceof GrammarRule grammarRule) { + return _getLocatorActivatorSuperType(formatConfiguration, grammarRule); + } else if (rule instanceof WildcardRule wildcardRule) { + return _getLocatorActivatorSuperType(formatConfiguration, wildcardRule); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(formatConfiguration, rule).toString()); + } + } + + // getParameterCalculatorSuperType dispatch + protected JvmTypeReference _getParameterCalculatorSuperType(final FormatConfiguration formatConfiguration, final GrammarRule rule) { + return _typeReferenceBuilder.typeRef(LocatorParameterCalculator.class, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); + } + + protected JvmTypeReference _getParameterCalculatorSuperType(final FormatConfiguration formatConfiguration, final WildcardRule rule) { + return _typeReferenceBuilder.typeRef(LocatorParameterCalculator.class, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); + } + + public JvmTypeReference getParameterCalculatorSuperType(final FormatConfiguration formatConfiguration, final Rule rule) { + if (rule instanceof GrammarRule grammarRule) { + return _getParameterCalculatorSuperType(formatConfiguration, grammarRule); + } else if (rule instanceof WildcardRule wildcardRule) { + return _getParameterCalculatorSuperType(formatConfiguration, wildcardRule); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(formatConfiguration, rule).toString()); + } + } + + // getGrammarElementNameFromSelf dispatch + protected String _getGrammarElementNameFromSelf(final GrammarRule rule) { + final String originalRuleName = getRuleName(rule); + String actualRuleName = originalRuleName; + if (rule.getTargetRule() == null || rule.getTargetRule().getType() == null || rule.getTargetRule().getType().getClassifier() == null) { + return actualRuleName; + } else { + AbstractRule targetRule = rule.getTargetRule(); + TypeRef type = targetRule != null ? targetRule.getType() : null; + EClassifier classifier = type != null ? type.getClassifier() : null; + String name = classifier != null ? classifier.getName() : null; + if (!Objects.equals(actualRuleName, name)) { + actualRuleName = rule.getTargetRule().getType().getClassifier().getName(); + } + } + AbstractRule targetRule = rule.getTargetRule(); + TypeRef type = targetRule != null ? targetRule.getType() : null; + AbstractMetamodelDeclaration metamodel = type != null ? type.getMetamodel() : null; + if (metamodel == null) { + return actualRuleName; + } else { + if (!Objects.equals(actualRuleName, originalRuleName)) { + boolean anyMatch = metamodel.getEPackage().getEClassifiers().stream().anyMatch( + (EClassifier it) -> (it instanceof EClass) && it.getName().equalsIgnoreCase(originalRuleName)); + if (anyMatch) { + actualRuleName = originalRuleName; + } + } + URI uri = EcoreUtil2.getURI(metamodel.getEPackage()); + String segment = uri != null ? uri.segment(1) : null; + final String metamodelPackage = segment; + if (metamodelPackage == null) { + return actualRuleName; + } + EPackage ePackage = metamodel.getEPackage(); + String ePackageName = ePackage != null ? ePackage.getName() : null; + return metamodelPackage.substring(0, metamodelPackage.lastIndexOf(".core")) + "." + ePackageName + "." + actualRuleName; + } + } + + protected String _getGrammarElementNameFromSelf(final WildcardRule rule) { + return EObject.class.getName(); + } + + public String getGrammarElementNameFromSelf(final Rule rule) { + if (rule instanceof GrammarRule grammarRule) { + return _getGrammarElementNameFromSelf(grammarRule); + } else if (rule instanceof WildcardRule wildcardRule) { + return _getGrammarElementNameFromSelf(wildcardRule); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(rule).toString()); + } + } + + public int getMatcherIndex(final Matcher matcher) { + final MatcherList matcherList = EcoreUtil2.getContainerOfType(matcher, MatcherList.class); + return matcherList.getMatchers().indexOf(matcher); + } + + public String getLocatorActivatorName(final EObject rule, final EObject directive, final Matcher matcher) { + return ("ActivatorFor" + getRuleName(rule) + getMatcherName(matcher, directive)).replace("Impl", ""); + } + + public String getLocatorActivatorName(final String partialName, final Matcher matcher) { + return ("ActivatorFor" + partialName + getMatcherIndex(matcher) + getLocatorName(matcher.getLocator()) + StringExtensions.toFirstUpper(matcher.getType().name().toLowerCase())).replace("Impl", ""); + } + + public String getParameterCalculatorName(final EObject rule, final EObject directive, final Matcher matcher) { + return ("ParameterCalculatorFor" + getRuleName(rule) + getMatcherName(matcher, directive)).replace("Impl", ""); + } + + public String getParameterCalculatorName(final String partialName, final Matcher matcher) { + return ("ParameterCalculatorFor" + partialName + getMatcherIndex(matcher) + getLocatorName(matcher.getLocator()) + StringExtensions.toFirstUpper(matcher.getType().name().toLowerCase())).replace("Impl", ""); + } + + // getRuleName dispatch + protected String _getRuleName(final GrammarRule rule) { + AbstractRule targetRule = rule.getTargetRule(); + return targetRule != null ? targetRule.getName() : null; + } + + protected String _getRuleName(final WildcardRule rule) { + return "Wildcard"; + } + + protected String _getRuleName(final EObject rule) { + return EObject.class.getSimpleName(); + } + + public String getRuleName(final EObject rule) { + if (rule instanceof GrammarRule grammarRule) { + return _getRuleName(grammarRule); + } else if (rule instanceof WildcardRule wildcardRule) { + return _getRuleName(wildcardRule); + } else if (rule != null) { + return _getRuleName(rule); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(rule).toString()); + } + } + + public String getMatcherName(final Matcher matcher, final EObject directive) { + return getDirectiveName(directive) + getMatcherIndex(matcher) + getLocatorName(matcher.getLocator()) + StringExtensions.toFirstUpper(matcher.getType().name().toLowerCase()); + } + + public String getLocatorName(final EObject locator) { + Class clazz = locator != null ? locator.getClass() : null; + String simpleName = clazz != null ? clazz.getSimpleName() : null; + return simpleName != null ? simpleName : ""; + } + + public String convertNonAlphaNumeric(final String str) { + final Pattern pattern = Pattern.compile("[\\W]"); + final java.util.regex.Matcher matcher = pattern.matcher(str); + final StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, String.valueOf(Integer.toHexString(matcher.group().hashCode()))); + } + matcher.appendTail(sb); + return sb.toString(); + } + + // getDirectiveName dispatch + protected String _getDirectiveName(final GroupBlock directive) { + final GrammarRule grammarRule = EcoreUtil2.getContainerOfType(directive, GrammarRule.class); + final ArrayList> directives = CollectionLiterals.>newArrayList(Iterables.filter(grammarRule.getDirectives(), GroupBlock.class)); + return "Group" + String.valueOf(directives.indexOf(directive) + 1); + } + + protected String _getDirectiveName(final SpecificDirective directive) { + String directiveName = ""; + for (final GrammarElementReference grammarElementReference : directive.getGrammarElements()) { + if (grammarElementReference.getAssignment() != null) { + directiveName = directiveName + grammarAccess.gaElementAccessMethodName(grammarElementReference.getAssignment()).replaceFirst("get", "").replaceFirst("(?s)(.*)" + "Assignment", "$1" + ""); + } + if (grammarElementReference.getRuleCall() != null) { + directiveName = directiveName + StringExtensions.toFirstUpper(grammarElementReference.getRuleCall().getRule().getName()); + } + if (grammarElementReference.getRule() != null) { + directiveName = directiveName + StringExtensions.toFirstUpper(grammarElementReference.getRule().getName()); + } + if (grammarElementReference.getKeyword() != null) { + directiveName = directiveName + StringExtensions.toFirstUpper(convertNonAlphaNumeric(grammarElementReference.getKeyword().getValue())); + } + if (grammarElementReference.getSelf() != null) { + directiveName = directiveName + "Self"; + } + } + return directiveName; + } + + protected String _getDirectiveName(final ContextFreeDirective directive) { + String directiveName = ""; + for (final GrammarElementLookup grammarElementLookup : directive.getGrammarElements()) { + if (grammarElementLookup.getRule() != null) { + directiveName = directiveName + StringExtensions.toFirstUpper(grammarElementLookup.getRule().getName()); + } + if (grammarElementLookup.getKeyword() != null) { + directiveName = directiveName + StringExtensions.toFirstUpper(convertNonAlphaNumeric(grammarElementLookup.getKeyword())); + } + } + return directiveName; + } + + protected String _getDirectiveName(final KeywordPair directive) { + return convertNonAlphaNumeric(directive.getLeft()) + convertNonAlphaNumeric(directive.getRight()); + } + + protected String _getDirectiveName(final EObject directive) { + return String.valueOf(directive.hashCode()); + } + + public String getDirectiveName(final EObject directive) { + if (directive instanceof ContextFreeDirective contextFreeDirective) { + return _getDirectiveName(contextFreeDirective); + } else if (directive instanceof KeywordPair keywordPair) { + return _getDirectiveName(keywordPair); + } else if (directive instanceof SpecificDirective specificDirective) { + return _getDirectiveName(specificDirective); + } else if (directive instanceof GroupBlock groupBlock) { + return _getDirectiveName(groupBlock); + } else if (directive != null) { + return _getDirectiveName(directive); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(directive).toString()); + } + } + + public Iterable createRule(final FormatConfiguration format, final GrammarRule rule) { + final List members = CollectionLiterals.newArrayList(); + JvmOperation method = _jvmTypesBuilder.toMethod(format, "config" + rule.getTargetRule().getName(), _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + it.setFinal(false); + it.setVisibility(JvmVisibility.PROTECTED); + _jvmTypesBuilder.operator_add(it.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); + AbstractRule targetRule = rule.getTargetRule(); + if (targetRule instanceof ParserRule) { + final String ruleName = getFullyQualifiedName(getGrammar(rule.getTargetRule())) + "$" + grammarAccess.gaRuleAccessorClassName(rule.getTargetRule()); + _jvmTypesBuilder.operator_add(it.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_ELEMENTS, _typeReferences.getTypeForName(ruleName, rule.getTargetRule()))); + _jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", + CollectionLiterals.newLinkedHashMap( + Pair.of(PARAMETER_CONFIG, "the format configuration"), + Pair.of(PARAMETER_ELEMENTS, "the grammar access for " + rule.getTargetRule().getName() + " elements")))); + } else if (targetRule instanceof EnumRule) { + _jvmTypesBuilder.operator_add(it.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_RULE, _typeReferences.getTypeForName(EnumRule.class.getName(), rule.getTargetRule()))); + _jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", + CollectionLiterals.newLinkedHashMap( + Pair.of(PARAMETER_CONFIG, "the format configuration"), + Pair.of(PARAMETER_RULE, "the enum rule for " + rule.getTargetRule().getName())))); + } else if (targetRule instanceof TerminalRule) { + _jvmTypesBuilder.operator_add(it.getParameters(), + _jvmTypesBuilder.toParameter(format, PARAMETER_RULE, _typeReferences.getTypeForName(TerminalRule.class.getName(), rule.getTargetRule()))); + _jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", + CollectionLiterals.newLinkedHashMap( + Pair.of(PARAMETER_CONFIG, "the format configuration"), + Pair.of(PARAMETER_RULE, "the terminal rule for " + rule.getTargetRule().getName())))); + } + _jvmTypesBuilder.setBody(it, (ITreeAppendable it_1) -> { + final List directives = ListExtensions.map(rule.getDirectives(), (EObject d) -> directive(d, getRuleName(rule)).toString()); + it_1.append(fixLastLine(IterableExtensions.join(directives))); + }); + }); + members.add(method); + return members; + } + + public String fixLastLine(final String content) { + if (content.endsWith("\r\n")) { + return content.substring(0, content.length() - 2); + } else { + return content; + } + } + + // directive dispatch + protected CharSequence _directive(final SpecificDirective dir, final String partialName) { + return matchReference(dir.getMatcherList(), dir.getGrammarElements(), partialName + getDirectiveName(dir)); + } + + protected CharSequence _directive(final ContextFreeDirective dir, final String partialName) { + return matchLookup(dir.getMatcherList(), dir.getGrammarElements(), partialName + getDirectiveName(dir)); + } + + protected CharSequence _directive(final GroupBlock dir, final String partialName) { + if (dir.getMatcherList() != null) { + return matchReference(dir.getMatcherList(), new BasicEList<>(Collections.singletonList(dir.getGrammarElement())), partialName + getDirectiveName(dir)); + } else if (dir.getSubGroup() != null) { + return directive(dir.getSubGroup(), partialName + getDirectiveName(dir)); + } else { + final StringBuilder sb = new StringBuilder(); + for (final GrammarRuleDirective d : dir.getDirectives()) { + sb.append(directive(d, partialName + getDirectiveName(dir))); + } + return sb; + } + } + + protected CharSequence _directive(final KeywordPair dir, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("// ").append(locatorString(dir)).append("\n"); + sb.append("for (final org.eclipse.xtext.util.Pair pair : elements.findKeywordPairs(\"").append(dir.getLeft()).append("\", \"").append(dir.getRight()).append("\")) {\n"); + for (final Matcher matcher : dir.getLeftMatchers()) { + sb.append(matchLookupPartial(matcher.getLocator(), matcher, "pair.getFirst()", partialName + getDirectiveName(dir))); + sb.append("\n"); + } + for (final Matcher matcher : dir.getRightMatchers()) { + sb.append(matchLookupPartial(matcher.getLocator(), matcher, "pair.getSecond()", partialName + getDirectiveName(dir))); + sb.append("\n"); + } + sb.append("}\n"); + return sb; + } + + protected CharSequence _directive(final Object dir, final String partialName) { + throw new UnsupportedOperationException("Unknown directive " + dir.getClass().getName()); + } + + public CharSequence directive(final Object dir, final String partialName) { + if (dir instanceof ContextFreeDirective contextFreeDirective) { + return _directive(contextFreeDirective, partialName); + } else if (dir instanceof KeywordPair keywordPair) { + return _directive(keywordPair, partialName); + } else if (dir instanceof SpecificDirective specificDirective) { + return _directive(specificDirective, partialName); + } else if (dir instanceof GroupBlock groupBlock) { + return _directive(groupBlock, partialName); + } else if (dir != null) { + return _directive(dir, partialName); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(dir, partialName).toString()); + } + } + + public CharSequence matchLookup(final MatcherList matcherList, final EList elements, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (!elements.isEmpty()) { + boolean hasRuleElements = elements.stream().anyMatch((GrammarElementLookup e) -> e.getRule() != null); + if (hasRuleElements) { + sb.append("// ").append(locatorString(matcherList)).append("\n"); + sb.append("for (org.eclipse.xtext.RuleCall ruleCall : elements.findRuleCalls("); + boolean first = true; + for (final GrammarElementLookup element : elements.stream().filter((GrammarElementLookup e) -> e.getRule() != null).toList()) { + if (!first) { + sb.append(", "); + } + first = false; + sb.append("elements.").append(grammarAccess.gaRuleAccessor(element.getRule())); + } + sb.append(")) {\n"); + for (final Matcher matcher : matcherList.getMatchers()) { + sb.append(" ").append(matchLookupPartial(matcher.getLocator(), matcher, "ruleCall", partialName)).append("\n"); + } + sb.append("}\n"); + } + boolean hasKeywordElements = elements.stream().anyMatch((GrammarElementLookup e) -> e.getKeyword() != null); + if (hasKeywordElements) { + sb.append("// ").append(locatorString(matcherList)).append("\n"); + sb.append("for (org.eclipse.xtext.Keyword keyword : elements.findKeywords("); + boolean first2 = true; + for (final GrammarElementLookup element : elements.stream().filter((GrammarElementLookup e) -> e.getKeyword() != null).toList()) { + if (!first2) { + sb.append(", "); + } + first2 = false; + sb.append("\"").append(element.getKeyword()).append("\""); + } + sb.append(")) {\n"); + for (final Matcher matcher : matcherList.getMatchers()) { + sb.append(" ").append(matchLookupPartial(matcher.getLocator(), matcher, "keyword", partialName)).append("\n"); + } + sb.append("}\n"); + } + } + return sb; + } + + // matchLookupPartial dispatch + protected CharSequence _matchLookupPartial(final ColumnLocator columnLocator, final Matcher matcher, final String eobjectTypeName, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (matcher.getType().getLiteral().compareTo("before") == 0) { + sb.append("config.setColumn(").append(getValueOrConstant(columnLocator.getValue())).append(", ").append(columnLocator.isFixed()).append(", ").append(columnLocator.isRelative()).append(", ").append(columnLocator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").before(").append(eobjectTypeName).append("); // ").append(locatorString(columnLocator)).append("\n"); + sb.append("config.setColumn(").append(getValueOrConstant(columnLocator.getValue())).append(", ").append(columnLocator.isFixed()).append(", ").append(columnLocator.isRelative()).append(", ").append(columnLocator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").after(").append(eobjectTypeName).append("); // ").append(locatorString(columnLocator)); + } else { + sb.append("config.setColumn(").append(getValueOrConstant(columnLocator.getValue())); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").").append(matcherType(matcher.getType())).append("(").append(eobjectTypeName).append("); // ").append(locatorString(columnLocator)); + } + return sb; + } + + protected CharSequence _matchLookupPartial(final OffsetLocator offsetLocator, final Matcher matcher, final String eobjectTypeName, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (matcher.getType().getLiteral().compareTo("before") == 0) { + sb.append("config.setColumn(").append(getValueOrConstant(offsetLocator.getValue())).append(", ").append(offsetLocator.isFixed()).append(", true, ").append(offsetLocator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").before(").append(eobjectTypeName).append("); // ").append(locatorString(offsetLocator)).append("\n"); + sb.append("config.setColumn(").append(getValueOrConstant(offsetLocator.getValue())).append(", ").append(offsetLocator.isFixed()).append(", true, ").append(offsetLocator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").after(").append(eobjectTypeName).append("); // ").append(locatorString(offsetLocator)); + } else { + sb.append("config.setOffset(").append(getValueOrConstant(offsetLocator.getValue())); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").").append(matcherType(matcher.getType())).append("(").append(eobjectTypeName).append("); // ").append(locatorString(offsetLocator)); + } + return sb; + } + + protected CharSequence _matchLookupPartial(final EObject locator, final Matcher matcher, final String eobjectTypeName, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("config.").append(locator(matcher, matcher.getLocator(), partialName)).append(".").append(matcherType(matcher.getType())).append("(").append(eobjectTypeName).append(");"); + return sb; + } + + public CharSequence matchLookupPartial(final EObject columnLocator, final Matcher matcher, final String eobjectTypeName, final String partialName) { + if (columnLocator instanceof ColumnLocator cl) { + return _matchLookupPartial(cl, matcher, eobjectTypeName, partialName); + } else if (columnLocator instanceof OffsetLocator ol) { + return _matchLookupPartial(ol, matcher, eobjectTypeName, partialName); + } else if (columnLocator != null) { + return _matchLookupPartial(columnLocator, matcher, eobjectTypeName, partialName); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(columnLocator, matcher, eobjectTypeName, partialName).toString()); + } + } + + public CharSequence matchReference(final MatcherList matcherList, final EList elements, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (!elements.isEmpty()) { + for (final Matcher matcher : matcherList.getMatchers()) { + if (FormatGeneratorUtil.isTwoArgumentMatcherType(matcher.getType()).booleanValue()) { + sb.append(match(matcher, elements.get(0), elements.get(1), matcher.getLocator(), partialName)); + } else { + for (final EObject e : elements) { + sb.append(match(matcher, e, matcher.getLocator(), partialName)); + } + } + } + } + return sb; + } + + public CharSequence match(final Matcher matcher, final EObject element1, final EObject element2, final EObject locator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("config.").append(locator(matcher, matcher.getLocator(), partialName)).append(".").append(matcherType(matcher.getType())).append("(").append(elementAccess(element1)).append(", ").append(elementAccess(element2)).append("); // ").append(locatorString(matcher)).append("\n"); + return sb; + } + + // match dispatch + protected CharSequence _match(final Matcher matcher, final EObject element, final Locator locator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("config.").append(locator(matcher, matcher.getLocator(), partialName)).append(".").append(matcherType(matcher.getType())).append("(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + return sb; + } + + protected CharSequence _match(final Matcher matcher, final EObject element, final NoFormatLocator locator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("config.").append(locator(matcher, matcher.getLocator(), partialName)).append(".").append(matcherType(matcher.getType())).append("(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + return sb; + } + + protected CharSequence _match(final Matcher matcher, final EObject element, final ColumnLocator locator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (matcher.getType().getLiteral().compareTo("before") == 0) { + if (locator.getParameter() != null) { + sb.append("config.setColumn(").append(locator.isFixed()).append(", ").append(locator.isRelative()).append(", ").append(locator.isNobreak()).append(", new ").append(getParameterCalculatorName(partialName, matcher)).append("()"); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").before(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + sb.append("config.setColumn(").append(locator.isFixed()).append(", ").append(locator.isRelative()).append(", ").append(locator.isNobreak()).append(", new ").append(getParameterCalculatorName(partialName, matcher)).append("()"); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").after(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + } else { + sb.append("config.setColumn(").append(getValueOrConstant(locator.getValue())).append(", ").append(locator.isFixed()).append(", ").append(locator.isRelative()).append(", ").append(locator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").before(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + sb.append("config.setColumn(").append(getValueOrConstant(locator.getValue())).append(", ").append(locator.isFixed()).append(", ").append(locator.isRelative()).append(", ").append(locator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").after(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + } + } else { + if (locator.getParameter() != null) { + sb.append("config.setColumn(new ").append(getParameterCalculatorName(partialName, matcher)).append("()"); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").").append(matcherType(matcher.getType())).append("(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + } else { + sb.append("config.setColumn(").append(getValueOrConstant(locator.getValue())); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").").append(matcherType(matcher.getType())).append("(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + } + } + return sb; + } + + protected CharSequence _match(final Matcher matcher, final EObject element, final OffsetLocator locator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (matcher.getType().getLiteral().compareTo("before") == 0) { + sb.append("config.setColumn(").append(getValueOrConstant(locator.getValue())).append(", ").append(locator.isFixed()).append(", true, ").append(locator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").before(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + sb.append("config.setColumn(").append(getValueOrConstant(locator.getValue())).append(", ").append(locator.isFixed()).append(", true, ").append(locator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").after(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + } else { + sb.append("config.setOffset(").append(getValueOrConstant(locator.getValue())); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(").").append(matcherType(matcher.getType())).append("(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + } + return sb; + } + + protected CharSequence _match(final Matcher matcher, final EObject element, final IndentLocator locator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("config.").append(locator(matcher, matcher.getLocator(), partialName)).append(".").append(matcherType(matcher.getType())).append("(").append(elementAccess(element)).append("); // ").append(locatorString(matcher)).append("\n"); + return sb; + } + + public CharSequence match(final Matcher matcher, final EObject element, final Locator locator, final String partialName) { + if (locator instanceof ColumnLocator cl) { + return _match(matcher, element, cl, partialName); + } else if (locator instanceof IndentLocator il) { + return _match(matcher, element, il, partialName); + } else if (locator instanceof NoFormatLocator nfl) { + return _match(matcher, element, nfl, partialName); + } else if (locator instanceof OffsetLocator ol) { + return _match(matcher, element, ol, partialName); + } else if (locator != null) { + return _match(matcher, element, locator, partialName); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(matcher, element, locator, partialName).toString()); + } + } + + public String matcherType(final MatcherType matcherType) { + return matcherType.getLiteral(); + } + + // elementAccess dispatch + protected CharSequence _elementAccess(final GrammarElementLookup grammarElementLookup) { + final StringBuilder sb = new StringBuilder(); + if (grammarElementLookup.getRule() != null) { + sb.append("elements.findRuleCalls(").append(grammarAccess.gaElementsAccessor(grammarElementLookup.getRule())).append(")"); + } else if (grammarElementLookup.getKeyword() != null) { + sb.append("elements.findKeywords(\"").append(grammarElementLookup.getKeyword()).append("\")"); + } + return sb; + } + + protected CharSequence _elementAccess(final GrammarElementReference grammarElementReference) { + if (grammarElementReference.getRuleCall() != null) { + return elementAccess(grammarElementReference.getRuleCall()); + } else if (grammarElementReference.getKeyword() != null) { + return elementAccess(grammarElementReference.getKeyword()); + } else if (grammarElementReference.getAssignment() != null) { + return elementAccess(grammarElementReference.getAssignment()); + } else if (grammarElementReference.getSelf() != null) { + if (FormatGeneratorUtil.containedByParserRule(grammarElementReference).booleanValue()) { + return "elements.getRule()"; + } else { + return "rule"; + } + } else if (grammarElementReference.getRule() != null) { + return elementAccess(grammarElementReference.getRule()); + } + return null; + } + + protected CharSequence _elementAccess(final AbstractRule abstractRule) { + return "getGrammarAccess()." + grammarAccess.gaRuleAccessor(abstractRule); + } + + protected CharSequence _elementAccess(final AbstractElement abstractElement) { + return "elements." + grammarAccess.gaElementAccessor(abstractElement); + } + + protected CharSequence _elementAccess(final Object object) { + throw new UnsupportedOperationException("Unknown Xtext element " + object.getClass().getName()); + } + + public CharSequence elementAccess(final Object grammarElementLookup) { + if (grammarElementLookup instanceof GrammarElementLookup gel) { + return _elementAccess(gel); + } else if (grammarElementLookup instanceof GrammarElementReference ger) { + return _elementAccess(ger); + } else if (grammarElementLookup instanceof AbstractElement ae) { + return _elementAccess(ae); + } else if (grammarElementLookup instanceof AbstractRule ar) { + return _elementAccess(ar); + } else if (grammarElementLookup != null) { + return _elementAccess(grammarElementLookup); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(grammarElementLookup).toString()); + } + } + + // locator dispatch + protected CharSequence _locator(final Matcher matcher, final SpaceLocator spaceLocator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (spaceLocator.isNoSpace()) { + sb.append("setNoSpace("); + if (matcher.getCondition() != null) { + sb.append("new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(")"); + } else { + sb.append("setSpace(").append(getValueOrConstant(spaceLocator.getValue())); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(")"); + } + return sb; + } + + protected CharSequence _locator(final Matcher matcher, final RightPaddingLocator rightPaddingLocator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("setRightPadding(").append(getValueOrConstant(rightPaddingLocator.getValue())); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(")"); + return sb; + } + + protected CharSequence _locator(final Matcher matcher, final LinewrapLocator linewrapLocator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (linewrapLocator.isNoLinewrap()) { + sb.append("setNoLinewrap("); + if (matcher.getCondition() != null) { + sb.append("new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(")"); + } else { + sb.append("setLinewrap("); + if (linewrapLocator.getValue() != null) { + sb.append(getValueOrConstant(linewrapLocator.getValue())); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + } else if (linewrapLocator.getMinimum() != null) { + sb.append(getValueOrConstant(linewrapLocator.getMinimum())).append(", ").append(getValueOrConstant(linewrapLocator.getDefault())).append(", ").append(getValueOrConstant(linewrapLocator.getMaximum())); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + } else { + if (matcher.getCondition() != null) { + sb.append("new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + } + sb.append(")"); + } + return sb; + } + + protected CharSequence _locator(final Matcher matcher, final ColumnLocator columnLocator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("setColumn(").append(getValueOrConstant(columnLocator.getValue())).append(", ").append(columnLocator.isFixed()).append(", ").append(columnLocator.isRelative()).append(", ").append(columnLocator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(")"); + return sb; + } + + protected CharSequence _locator(final Matcher matcher, final OffsetLocator offsetLocator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("setColumn(").append(getValueOrConstant(offsetLocator.getValue())).append(", ").append(offsetLocator.isFixed()).append(", true, ").append(offsetLocator.isNobreak()); + if (matcher.getCondition() != null) { + sb.append(", new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(")"); + return sb; + } + + protected CharSequence _locator(final Matcher matcher, final IndentLocator indentLocator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + if (indentLocator.isIncrement()) { + sb.append("setIndentationIncrement("); + } else { + sb.append("setIndentationDecrement("); + } + if (indentLocator.getValue() != null && (indentLocator.getValue().getReference() != null || indentLocator.getValue().getLiteral().intValue() >= 1)) { + sb.append(getValueOrConstant(indentLocator.getValue())); + } else if (indentLocator.getParameter() != null) { + sb.append("new ").append(getParameterCalculatorName(partialName, matcher)).append("()"); + } + if (matcher.getCondition() != null) { + if (indentLocator.getValue() != null || indentLocator.getParameter() != null) { + sb.append(","); + } + sb.append(" new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(")"); + return sb; + } + + protected CharSequence _locator(final Matcher matcher, final NoFormatLocator noFormatLocator, final String partialName) { + final StringBuilder sb = new StringBuilder(); + sb.append("setNoFormat("); + if (matcher.getCondition() != null) { + sb.append("new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); + } + sb.append(")"); + return sb; + } + + protected CharSequence _locator(final Matcher matcher, final Locator locator, final String partialName) { + throw new UnsupportedOperationException("Unknown locator " + locator.getClass().getName()); + } + + public CharSequence locator(final Matcher matcher, final Locator columnLocator, final String partialName) { + if (columnLocator instanceof ColumnLocator cl) { + return _locator(matcher, cl, partialName); + } else if (columnLocator instanceof IndentLocator il) { + return _locator(matcher, il, partialName); + } else if (columnLocator instanceof LinewrapLocator ll) { + return _locator(matcher, ll, partialName); + } else if (columnLocator instanceof NoFormatLocator nfl) { + return _locator(matcher, nfl, partialName); + } else if (columnLocator instanceof OffsetLocator ol) { + return _locator(matcher, ol, partialName); + } else if (columnLocator instanceof RightPaddingLocator rpl) { + return _locator(matcher, rpl, partialName); + } else if (columnLocator instanceof SpaceLocator sl) { + return _locator(matcher, sl, partialName); + } else if (columnLocator != null) { + return _locator(matcher, columnLocator, partialName); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(matcher, columnLocator, partialName).toString()); + } + } + + // getValueOrConstant dispatch + protected String _getValueOrConstant(final StringValue stringValue) { + if (stringValue.getLiteral() == null) { + return stringValue.getReference().getName(); + } else { + return "\"" + stringValue.getLiteral() + "\""; + } + } + + protected String _getValueOrConstant(final IntValue intValue) { + if (intValue.getLiteral() == null) { + return intValue.getReference().getName(); + } else { + return intValue.getLiteral().toString(); + } + } + + public String getValueOrConstant(final EObject intValue) { + if (intValue instanceof IntValue iv) { + return _getValueOrConstant(iv); + } else if (intValue instanceof StringValue sv) { + return _getValueOrConstant(sv); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(intValue).toString()); + } + } + + public String locatorString(final EObject object) { + return IterableExtensions.lastOrNull((Iterable) Conversions.doWrapArray(getFileLocation(object).split("/"))); + } + + public void infer(final EObject format, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase) { + if (format instanceof FormatConfiguration formatConfiguration) { + _infer(formatConfiguration, acceptor, isPreIndexingPhase); + return; + } else if (format != null) { + _infer(format, acceptor, isPreIndexingPhase); + return; + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(format, acceptor, isPreIndexingPhase).toString()); + } + } +} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.xtend b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.xtend deleted file mode 100644 index 3db5521ec7..0000000000 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.xtend +++ /dev/null @@ -1,766 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.format.jvmmodel - -import com.avaloq.tools.ddk.xtext.format.format.ColumnLocator -import com.avaloq.tools.ddk.xtext.format.format.Constant -import com.avaloq.tools.ddk.xtext.format.format.ContextFreeDirective -import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration -import com.avaloq.tools.ddk.xtext.format.format.GrammarElementLookup -import com.avaloq.tools.ddk.xtext.format.format.GrammarElementReference -import com.avaloq.tools.ddk.xtext.format.format.GrammarRule -import com.avaloq.tools.ddk.xtext.format.format.GroupBlock -import com.avaloq.tools.ddk.xtext.format.format.IndentLocator -import com.avaloq.tools.ddk.xtext.format.format.IntValue -import com.avaloq.tools.ddk.xtext.format.format.KeywordPair -import com.avaloq.tools.ddk.xtext.format.format.LinewrapLocator -import com.avaloq.tools.ddk.xtext.format.format.Locator -import com.avaloq.tools.ddk.xtext.format.format.Matcher -import com.avaloq.tools.ddk.xtext.format.format.MatcherList -import com.avaloq.tools.ddk.xtext.format.format.MatcherType -import com.avaloq.tools.ddk.xtext.format.format.NoFormatLocator -import com.avaloq.tools.ddk.xtext.format.format.OffsetLocator -import com.avaloq.tools.ddk.xtext.format.format.RightPaddingLocator -import com.avaloq.tools.ddk.xtext.format.format.Rule -import com.avaloq.tools.ddk.xtext.format.format.SpaceLocator -import com.avaloq.tools.ddk.xtext.format.format.SpecificDirective -import com.avaloq.tools.ddk.xtext.format.format.StringValue -import com.avaloq.tools.ddk.xtext.format.format.WildcardRule -import com.avaloq.tools.ddk.xtext.formatting.AbstractExtendedFormatter -import com.avaloq.tools.ddk.xtext.formatting.ExtendedFormattingConfig -import com.avaloq.tools.ddk.xtext.formatting.locators.LocatorActivator -import com.avaloq.tools.ddk.xtext.formatting.locators.LocatorParameterCalculator -import com.google.common.collect.Iterables -import com.google.inject.Inject -import java.util.List -import java.util.Map -import org.eclipse.emf.common.util.BasicEList -import org.eclipse.emf.common.util.EList -import org.eclipse.emf.ecore.EObject -import org.eclipse.xtext.AbstractElement -import org.eclipse.xtext.AbstractRule -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.EnumRule -import org.eclipse.xtext.ParserRule -import org.eclipse.xtext.TerminalRule -import org.eclipse.xtext.util.Strings -import org.eclipse.xtext.common.types.JvmAnnotationReference -import org.eclipse.xtext.common.types.JvmAnnotationType -import org.eclipse.xtext.common.types.JvmDeclaredType -import org.eclipse.xtext.common.types.JvmGenericType -import org.eclipse.xtext.common.types.JvmMember -import org.eclipse.xtext.common.types.JvmVisibility -import org.eclipse.xtext.common.types.TypesFactory -import org.eclipse.xtext.common.types.util.TypeReferences -import org.eclipse.xtext.xbase.XExpression -import org.eclipse.xtext.xbase.compiler.XbaseCompiler -import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer -import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor -import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder - -import static com.avaloq.tools.ddk.xtext.util.EObjectUtil.getFileLocation -import static org.eclipse.xtext.GrammarUtil.* - -import static extension com.avaloq.tools.ddk.xtext.format.generator.FormatGeneratorUtil.* -import org.eclipse.emf.ecore.EClass -import java.util.regex.Pattern -import org.eclipse.xtext.xtext.RuleNames -import org.eclipse.emf.ecore.util.EcoreUtil -import org.eclipse.xtext.GrammarUtil -import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions -import org.eclipse.xtext.Grammar - -/** - *

Infers a JVM model from the source model.

- * - *

The JVM model should contain all elements that would appear in the Java code - * which is generated from the source model. Other models link against the JVM model rather than the source model.

- */ -class FormatJvmModelInferrer extends AbstractModelInferrer { - @Inject extension JvmTypesBuilder - @Inject extension TypeReferences - @Inject extension GrammarAccessExtensions grammarAccess - @Inject TypesFactory typesFactory - @Inject XbaseCompiler xbaseCompiler - - static final String BASE_FORMATTER_CLASS_NAME = AbstractExtendedFormatter.name - static final String BASE_FORMAT_CONFIG = ExtendedFormattingConfig.name - - static final String METHOD_ACTIVATE= 'activate' - static final String METHOD_CALCULATE= 'calculateParameter' - - static final String PARAMETER_CONFIG = 'config' - static final String PARAMETER_ELEMENTS = 'elements' - static final String PARAMETER_RULE = 'rule' - static final String PARAMETER_GRAMMAR_ACCESS = 'grammarAccess' - static final String PARAMETER_CONTEXT = 'context' - static final String PARAMETER_COLUMN = 'currentColumn' - - /** - * The dispatch method {@code infer} is called for each instance of the - * given element's type that is contained in a resource. - * - * @param element - * the model to create one or more {@link JvmDeclaredType declared types} from. - * @param acceptor - * each created {@link JvmDeclaredType type} without a container should be passed to the acceptor in order - * get attached to the current resource. The acceptor's {@link IJvmDeclaredTypeAcceptor#accept(JvmDeclaredType, - * org.eclipse.xtext.xbase.lib.Procedures.Procedure1)} method takes the constructed empty type for the - * pre-indexing phase. This one is further initialized in the indexing phase using the passed closure. - * @param isPreIndexingPhase - * whether the method is called in a pre-indexing phase, i.e. when the global index is not yet fully updated. You must not - * rely on linking using the index if isPreIndexingPhase is {@code true}. - */ - def dispatch void infer(FormatConfiguration format, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) { - if (isPreIndexingPhase) return - val context = format.targetGrammar - if (EcoreUtil.getAdapter(context.eAdapters(), typeof(RuleNames)) === null) { - val allRules = GrammarUtil.allRules(context); - for(AbstractRule rule: allRules) { - val adpt =EcoreUtil.getAdapter(rule.eAdapters(), typeof(RuleNames)); - if(adpt!==null) rule.eAdapters().remove(adpt) - } - RuleNames.getRuleNames(context, true); - } - acceptor.accept( - format.toClass(Strings.lastToken(getFormatterName(format, "Abstract"),".")), [ - inferClass(format, it) - inferConstants(format, it) - inferGetGrammarAccess(format, it) - inferConfigureAcsFormatting(format, it) - inferInit(format, it) - inferRules(format, it) - inferLocatorActivators(format, it) - ] - ) - } - - def inferClass(FormatConfiguration format, JvmGenericType it) { - var targetGrammarName = Strings.emptyIfNull(format.targetGrammar?.name) - documentation = '''The abstract formatting configuration for «Strings.skipLastToken(targetGrammarName, ".")».«Strings.lastToken(targetGrammarName,".")» as declared in «Strings.lastToken(targetGrammarName,".")».format.''' - if(format.formatterBaseClass !== null) { - superTypes += typeRef(format.formatterBaseClass.packageName + '.' + format.formatterBaseClass.simpleName) - } else { - superTypes += typeRef(BASE_FORMATTER_CLASS_NAME) - } - packageName = Strings.skipLastToken(getFormatterName(format, ""), ".") - abstract = true - } - - def inferConstants(FormatConfiguration format, JvmGenericType it) { - if(!format.allConstants.isEmpty) { - members += format.allConstants.map(c|createConstant(format, c)); - } - } - - def getFullyQualifiedName(Grammar g) { - GrammarUtil.getNamespace(g) + ".services." + GrammarUtil.getSimpleName(g) + "GrammarAccess"; - } - - def inferGetGrammarAccess(FormatConfiguration format, JvmGenericType it) { - members += format.toMethod('getGrammarAccess', format.targetGrammar.getFullyQualifiedName.getTypeForName(format.targetGrammar)) [ - visibility = JvmVisibility::PROTECTED - val JvmAnnotationReference overrideAnnotation = createOverrideAnnotation(format) - if(overrideAnnotation !== null) { - annotations += overrideAnnotation; - } - body = [append('''return («GrammarUtil.getSimpleName(format.targetGrammar) + "GrammarAccess"») super.getGrammarAccess();''')] - ] - } - - def inferConfigureAcsFormatting(FormatConfiguration format, JvmGenericType it) { - members += format.toMethod('configureAcsFormatting', typeRef('void')) [ - visibility = JvmVisibility::PROTECTED - val JvmAnnotationReference overrideAnnotation = createOverrideAnnotation(format) - if(overrideAnnotation !== null) { - annotations += overrideAnnotation; - } - parameters += format.toParameter(PARAMETER_CONFIG, typeRef(BASE_FORMAT_CONFIG)) - body = [append('''init(config, getGrammarAccess());''')] - ] - } - - def inferInit(FormatConfiguration format, JvmGenericType it) { - members += format.toMethod('init', typeRef('void')) [ - documentation = generateJavaDoc('Calls all configXyz methods declared in this class.', newLinkedHashMap( - PARAMETER_CONFIG -> 'the format configuration', - PARAMETER_GRAMMAR_ACCESS -> 'the grammar access for the grammar' - )) - visibility = JvmVisibility::PROTECTED - parameters += format.toParameter(PARAMETER_CONFIG, typeRef(BASE_FORMAT_CONFIG)) - parameters += format.toParameter(PARAMETER_GRAMMAR_ACCESS, typeRef(format.targetGrammar.getFullyQualifiedName)) - body = [ - val rules = listConfigRules(format) - for (i : 0 ..< rules.length()) { - if(i != 0) newLine - append(rules.get(i)) - } - ] - ] - } - - def inferRules(FormatConfiguration format, JvmGenericType it) { - members += format.parserRules.map(c|createRule(format, c)).flatten; - members += format.enumRules.map(c|createRule(format, c)).flatten; - members += format.terminalRules.map(c|createRule(format, c)).flatten; - if(format.wildcardRule !== null) { - members += format.toMethod('configFindElements', typeRef('void')) [ - documentation = generateJavaDoc('Configuration for IGrammarAccess.findXyz() methods.', newLinkedHashMap( - PARAMETER_CONFIG -> 'the format configuration', - PARAMETER_ELEMENTS -> 'the grammar access for the grammar' - )) - visibility = JvmVisibility::PROTECTED - parameters += format.toParameter(PARAMETER_CONFIG, typeRef(BASE_FORMAT_CONFIG)) - parameters += format.toParameter(PARAMETER_ELEMENTS, typeRef(getGrammar(format.targetGrammar).getFullyQualifiedName)) - body = [ - val directives = format.wildcardRule.directives.map(d|directive(d, format.wildcardRule.getRuleName).toString) - append(fixLastLine(directives.join)) - ] - ] - } - } - - def inferLocatorActivators(FormatConfiguration format, JvmGenericType it) { - var List rules = newLinkedList - rules += format.parserRules + format.terminalRules + format.enumRules - rules += format.wildcardRule - for (rule : rules) { - var List directives = newLinkedList - switch rule { - GrammarRule: directives += rule.directives - WildcardRule: directives += rule.directives - } - for (directive : directives.filterNull) { - for (matcher : collectMatchers(directive)) { - if (matcher.locator instanceof ColumnLocator && (matcher.locator as ColumnLocator).parameter !== null) { - members += createParameterCalculatorInnerClass(format, rule, directive, matcher, (matcher.locator as ColumnLocator).parameter, it) - } - if (matcher.locator instanceof IndentLocator && (matcher.locator as IndentLocator).parameter !== null) { - members += createParameterCalculatorInnerClass(format, rule, directive, matcher, (matcher.locator as IndentLocator).parameter, it) - } - if (matcher.condition !== null) { - members += createLocatorActivatorInnerClass(format, rule, directive, matcher, it) - } - } - } - } - } - - def createLocatorActivatorInnerClass(FormatConfiguration format, Rule rule, EObject directive, Matcher matcher, JvmGenericType type) { - format.toClass(rule.getLocatorActivatorName(directive, matcher)) [ - static = true - final = true - visibility = JvmVisibility::PROTECTED - superTypes += format.getLocatorActivatorSuperType(rule) - members += matcher.toMethod(METHOD_ACTIVATE, format.getLocatorActivatorReturnType) [ - parameters += format.toParameter(PARAMETER_CONTEXT, getGrammarElementNameFromSelf(rule).getTypeForName(format)) - parameters += createCurrenctColumnParameter - if(format.eResource != matcher.eResource) { - body = [xbaseCompiler.compile(matcher.condition, it, format.getLocatorActivatorReturnType, null)] - } else { - body = matcher.condition - } - ] - ] - } - - def createCurrenctColumnParameter(){ - var result = typesFactory.createJvmFormalParameter() - result.setName(PARAMETER_COLUMN) - result.setParameterType(typeRef(typeof(Integer))) - return result - } - - def createParameterCalculatorInnerClass(FormatConfiguration format, Rule rule, EObject directive, Matcher matcher, XExpression parameterCalculation, JvmGenericType type) { - format.toClass(rule.getParameterCalculatorName(directive, matcher)) [ - static = true - final = true - visibility = JvmVisibility::PROTECTED - superTypes += format.getParameterCalculatorSuperType(rule) - members += matcher.toMethod(METHOD_CALCULATE, format.parameterCalculatorReturnType) [ - parameters += format.toParameter(PARAMETER_CONTEXT, getGrammarElementNameFromSelf(rule).getTypeForName(format)) - parameters += createCurrenctColumnParameter - if(format.eResource != matcher.eResource) { - body = [xbaseCompiler.compile(parameterCalculation, it, format.parameterCalculatorReturnType, null)] - } else { - body = parameterCalculation - } - ] - ] - } - - def listConfigRules(FormatConfiguration format) { - val configRules = newArrayList; - if(format.wildcardRule !== null) { - configRules += '''configFindElements(config, grammarAccess);''' - } - for (rule : format.parserRules) { - configRules += '''config«rule.targetRule.name»(config, grammarAccess.«rule.targetRule.gaElementsAccessor»);''' - } - for (rule : format.enumRules) { - configRules += '''config«rule.targetRule.name»(config, grammarAccess.«rule.targetRule.gaRuleAccessor»);''' - } - for (rule : format.terminalRules) { - configRules += '''config«rule.targetRule.name»(config, grammarAccess.«rule.targetRule.gaRuleAccessor»);''' - } - configRules - } - - def generateJavaDoc(String description, Map parameters) { - ''' - «description» - - «FOR parameter : parameters.entrySet()» - @param «parameter.key» - - «parameter.value» - «ENDFOR» - '''.toString - } - - def JvmAnnotationReference createOverrideAnnotation(FormatConfiguration format) { - val annotationTypeRef = typeRef(typeof(Override)); - var JvmAnnotationReference overrideAnnotation = null - if(annotationTypeRef !== null) { - val annotationType = annotationTypeRef.type; - overrideAnnotation = typesFactory.createJvmAnnotationReference(); - overrideAnnotation.annotation = annotationType as JvmAnnotationType; - } - overrideAnnotation - } - - def JvmMember createConstant(FormatConfiguration configuration, Constant constant) { - switch constant { - case constant.stringValue !== null: - constant.toField(constant.name, "String".getTypeForName(constant)) [ - documentation = locatorString(constant) - static = true - final = true - visibility = JvmVisibility::PROTECTED - initializer = [append('"' + constant.stringValue + '"')] - ] - case constant.intValue !== null: - constant.toField(constant.name, "int".getTypeForName(constant)) [ - documentation = locatorString(constant) - static = true - final = true - visibility = JvmVisibility::PROTECTED - initializer = [append(constant.intValue.toString)] - ] - } - } - - def collectMatchers(EObject directive) { - var List matchers = newLinkedList - switch directive { - GroupBlock: if(directive.matcherList !== null) matchers += directive.matcherList.matchers - SpecificDirective: if(directive.matcherList !== null) matchers += directive.matcherList.matchers - ContextFreeDirective: if(directive.matcherList !== null) matchers += directive.matcherList.matchers - KeywordPair: { - if(directive.leftMatchers !== null) matchers += directive.leftMatchers - if(directive.rightMatchers !== null) matchers += directive.rightMatchers - } - } - matchers - } - - def getLocatorActivatorReturnType(FormatConfiguration formatConfiguration) { - typeRef(typeof(boolean)) - } - - def getParameterCalculatorReturnType(FormatConfiguration formatConfiguration) { - typeRef(typeof(int)) - } - - // getLocatorActivatorSuperType dispatch - def dispatch getLocatorActivatorSuperType(FormatConfiguration formatConfiguration, GrammarRule rule) { - typeRef(typeof(LocatorActivator), getGrammarElementNameFromSelf(rule).getTypeForName(formatConfiguration)) - } - def dispatch getLocatorActivatorSuperType(FormatConfiguration formatConfiguration, WildcardRule rule) { - typeRef(typeof(LocatorActivator), getGrammarElementNameFromSelf(rule).getTypeForName(formatConfiguration)) - } - - def dispatch getParameterCalculatorSuperType(FormatConfiguration formatConfiguration, GrammarRule rule) { - typeRef(typeof(LocatorParameterCalculator), getGrammarElementNameFromSelf(rule).getTypeForName(formatConfiguration)) - } - def dispatch getParameterCalculatorSuperType(FormatConfiguration formatConfiguration, WildcardRule rule) { - typeRef(typeof(LocatorParameterCalculator), getGrammarElementNameFromSelf(rule).getTypeForName(formatConfiguration)) - } - - // getGrammarElementNameFromSelf dispatch - def dispatch String getGrammarElementNameFromSelf(GrammarRule rule) { - val originalRuleName = rule.ruleName - var actualRuleName = originalRuleName - if (rule.targetRule === null || rule.targetRule.type === null || rule.targetRule.type.classifier === null) { - return actualRuleName - } else if (actualRuleName != rule.targetRule?.type?.classifier?.name) { - actualRuleName = rule.targetRule.type.classifier.name - } - var metamodel = rule.targetRule?.type?.metamodel - if (metamodel === null) { - return actualRuleName - } else { - if (actualRuleName != originalRuleName) { - if (metamodel.EPackage.EClassifiers.stream.anyMatch[(it instanceof EClass) && (it.name.equalsIgnoreCase(originalRuleName))]){ - actualRuleName = originalRuleName - } - } - val metamodelPackage = EcoreUtil2::getURI(metamodel.EPackage)?.segment(1) - if (metamodelPackage === null) { - return actualRuleName - } - return metamodelPackage.substring(0,metamodelPackage.lastIndexOf('.core')) + '.' + metamodel.EPackage?.name + '.' + actualRuleName - } - } - def dispatch String getGrammarElementNameFromSelf(WildcardRule rule) { - EObject.name - } - - def int getMatcherIndex(Matcher matcher){ - val MatcherList matcherList=EcoreUtil2::getContainerOfType(matcher, typeof(MatcherList)) - return matcherList.matchers.indexOf(matcher); - } - - def String getLocatorActivatorName(EObject rule, EObject directive, Matcher matcher) { - ('ActivatorFor' + rule.getRuleName + matcher.getMatcherName(directive)).replace("Impl", "") - } - - def String getLocatorActivatorName(String partialName, Matcher matcher) { - ('ActivatorFor' + partialName + getMatcherIndex(matcher) + getLocatorName(matcher.locator) + matcher.type.name().toLowerCase.toFirstUpper).replace("Impl", "") - } - - def String getParameterCalculatorName(EObject rule, EObject directive, Matcher matcher) { - ('ParameterCalculatorFor' + rule.getRuleName + matcher.getMatcherName(directive)).replace("Impl", "") - } - - - def String getParameterCalculatorName(String partialName, Matcher matcher) { - ('ParameterCalculatorFor' + partialName + getMatcherIndex(matcher) + getLocatorName(matcher.locator) + matcher.type.name().toLowerCase.toFirstUpper).replace("Impl", "") - } - - // getRuleName dispatch - def dispatch String getRuleName(GrammarRule rule) { rule.targetRule?.name } - def dispatch String getRuleName(WildcardRule rule) { "Wildcard" } - def dispatch String getRuleName(EObject rule) { EObject.simpleName} - - def String getMatcherName(Matcher matcher, EObject directive) { - getDirectiveName(directive) + getMatcherIndex(matcher) + getLocatorName(matcher.locator) + matcher.type.name().toLowerCase.toFirstUpper - } - - def String getLocatorName(EObject locator) { - locator?.class?.simpleName ?: "" - } - - def convertNonAlphaNumeric(String str) { - val pattern = Pattern.compile("[\\W]"); - val matcher = pattern.matcher(str); - val sb = new StringBuffer(); - while(matcher.find) { - matcher.appendReplacement(sb, String.valueOf(Integer.toHexString(matcher.group.hashCode))) - } - matcher.appendTail(sb); - sb.toString; - } - - // getDirectiveName dispatch - def dispatch String getDirectiveName(GroupBlock directive) { - val GrammarRule grammarRule = EcoreUtil2::getContainerOfType(directive, typeof(GrammarRule)) - val directives = newArrayList(Iterables.filter(grammarRule.directives, GroupBlock)); - "Group" + String.valueOf(directives.indexOf(directive) + 1) - } - def dispatch String getDirectiveName(SpecificDirective directive) { - var directiveName = '' - for (grammarElementReference : directive.grammarElements) { - if(grammarElementReference.assignment !== null) { - directiveName = directiveName + grammarElementReference.assignment.gaElementAccessMethodName.replaceFirst("get","").replaceFirst("(?s)(.*)" + "Assignment","$1" + "") - } - if(grammarElementReference.ruleCall !== null) { - directiveName = directiveName + grammarElementReference.ruleCall.rule.name.toFirstUpper - } - if(grammarElementReference.rule !== null) { - directiveName = directiveName + grammarElementReference.rule.name.toFirstUpper - } - if(grammarElementReference.keyword !== null) { - directiveName = directiveName + grammarElementReference.keyword.value.convertNonAlphaNumeric.toFirstUpper - } - if(grammarElementReference.self !== null) { - directiveName = directiveName + "Self" - } - } - directiveName - } - def dispatch String getDirectiveName(ContextFreeDirective directive) { - var directiveName = '' - for (grammarElementLookup : directive.grammarElements) { - if(grammarElementLookup.rule !== null) { - directiveName = directiveName + grammarElementLookup.rule.name.toFirstUpper - } - if(grammarElementLookup.keyword !== null) { - directiveName = directiveName + grammarElementLookup.keyword.convertNonAlphaNumeric.toFirstUpper - } - } - directiveName - } - def dispatch String getDirectiveName(KeywordPair directive) { - directive.left.convertNonAlphaNumeric + directive.right.convertNonAlphaNumeric - } - def dispatch String getDirectiveName(EObject directive) { - String.valueOf(directive.hashCode) - } - - def Iterable createRule(FormatConfiguration format, GrammarRule rule) { - val List members = newArrayList - members += format.toMethod('config' + rule.targetRule.name, typeRef('void')) [ - final = false - visibility = JvmVisibility::PROTECTED - parameters += format.toParameter(PARAMETER_CONFIG, typeRef(BASE_FORMAT_CONFIG)) - switch rule.targetRule { - ParserRule: { - val ruleName = (getGrammar(rule.targetRule).getFullyQualifiedName + "$" + rule.targetRule.gaRuleAccessorClassName) - parameters += format.toParameter(PARAMETER_ELEMENTS, ruleName.getTypeForName(rule.targetRule)) - documentation = generateJavaDoc('''Configuration for «rule.targetRule.name».''', newLinkedHashMap( - PARAMETER_CONFIG -> 'the format configuration', - PARAMETER_ELEMENTS -> '''the grammar access for «rule.targetRule.name» elements''' - )) - } - EnumRule: { - parameters += format.toParameter(PARAMETER_RULE, EnumRule.name.getTypeForName(rule.targetRule)) - documentation = generateJavaDoc('''Configuration for «rule.targetRule.name».''', newLinkedHashMap( - PARAMETER_CONFIG -> 'the format configuration', - PARAMETER_RULE -> '''the enum rule for «rule.targetRule.name»''' - )) - } - TerminalRule: { - parameters += format.toParameter(PARAMETER_RULE, TerminalRule.name.getTypeForName(rule.targetRule)) - documentation = generateJavaDoc('''Configuration for «rule.targetRule.name».''', newLinkedHashMap( - PARAMETER_CONFIG -> 'the format configuration', - PARAMETER_RULE -> '''the terminal rule for «rule.targetRule.name»''' - )) - } - } - body = [ - val directives = rule.directives.map(d|directive(d, rule.getRuleName).toString) - append(fixLastLine(directives.join)) - ] - ] - return members; - } - - def fixLastLine(String content) { - if(content.endsWith("\r\n")) { - return content.substring(0, content.length - 2) - } else { - return content - } - } - - // directive dispatch - def dispatch directive(SpecificDirective dir, String partialName) { matchReference(dir.matcherList, dir.grammarElements, partialName + getDirectiveName(dir)) } - def dispatch directive(ContextFreeDirective dir, String partialName) { matchLookup(dir.matcherList, dir.grammarElements, partialName + getDirectiveName(dir)) } - def dispatch CharSequence directive(GroupBlock dir, String partialName) { - if(dir.matcherList !== null) { - matchReference(dir.matcherList, new BasicEList(#[dir.grammarElement]), partialName + getDirectiveName(dir)) - } else if (dir.subGroup !== null) { - directive(dir.subGroup, partialName+ getDirectiveName(dir)) - } else { - '''«FOR d : dir.directives»«directive(d, partialName + getDirectiveName(dir))»«ENDFOR»''' - } - } - def dispatch directive(KeywordPair dir, String partialName) ''' - // «locatorString(dir)» - for (final org.eclipse.xtext.util.Pair pair : elements.findKeywordPairs("«dir.left»", "«dir.right»")) { - «FOR matcher : dir.leftMatchers» - «matchLookupPartial(matcher.locator, matcher, "pair.getFirst()", partialName + getDirectiveName(dir))» - «ENDFOR» - «FOR matcher : dir.rightMatchers» - «matchLookupPartial(matcher.locator, matcher, "pair.getSecond()", partialName + getDirectiveName(dir))» - «ENDFOR» - } - ''' - def dispatch directive(Object dir, String partialName) { - throw new UnsupportedOperationException("Unknown directive " + dir.class.name) - } - - def matchLookup(MatcherList matcherList, EList elements, String partialName) ''' - «IF !elements.isEmpty» - «IF !elements.filter[e|e.rule !== null].isEmpty» - // «locatorString(matcherList)» - for (org.eclipse.xtext.RuleCall ruleCall : elements.findRuleCalls(«FOR element : elements.filter(e|e.rule !== null) SEPARATOR ', '»elements.«element.rule.gaRuleAccessor»«ENDFOR»)) { - «FOR matcher : matcherList.matchers» - «matchLookupPartial(matcher.locator, matcher, "ruleCall", partialName)» - «ENDFOR» - } - «ENDIF» - «IF !elements.filter(e|e.keyword !== null).isEmpty» - // «locatorString(matcherList)» - for (org.eclipse.xtext.Keyword keyword : elements.findKeywords(«FOR element : elements.filter(e|e.keyword !== null) SEPARATOR ', '»"«element.keyword»"«ENDFOR»)) { - «FOR matcher : matcherList.matchers» - «matchLookupPartial(matcher.locator, matcher, "keyword", partialName)» - «ENDFOR» - } - «ENDIF» - «ENDIF» - ''' - - // matchLookupPartial dispatch - def dispatch matchLookupPartial(ColumnLocator columnLocator, Matcher matcher, String eobjectTypeName, String partialName) ''' - «IF matcher.type.literal.compareTo("before") == 0» - config.setColumn(«columnLocator.value.getValueOrConstant», «columnLocator.fixed», «columnLocator.relative», «columnLocator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).before(«eobjectTypeName»); // «locatorString(columnLocator)» - config.setColumn(«columnLocator.value.getValueOrConstant», «columnLocator.fixed», «columnLocator.relative», «columnLocator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).after(«eobjectTypeName»); // «locatorString(columnLocator)» - «ELSE» - config.setColumn(«columnLocator.value.getValueOrConstant»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).«matcherType(matcher.type)»(«eobjectTypeName»); // «locatorString(columnLocator)» - «ENDIF» - ''' - def dispatch matchLookupPartial(OffsetLocator offsetLocator, Matcher matcher, String eobjectTypeName, String partialName) ''' - «IF matcher.type.literal.compareTo("before") == 0» - config.setColumn(«offsetLocator.value.getValueOrConstant», «offsetLocator.fixed», true, «offsetLocator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).before(«eobjectTypeName»); // «locatorString(offsetLocator)» - config.setColumn(«offsetLocator.value.getValueOrConstant», «offsetLocator.fixed», true, «offsetLocator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).after(«eobjectTypeName»); // «locatorString(offsetLocator)» - «ELSE» - config.setOffset(«offsetLocator.value.getValueOrConstant»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).«matcherType(matcher.type)»(«eobjectTypeName»); // «locatorString(offsetLocator)» - «ENDIF» - ''' - def dispatch matchLookupPartial(EObject locator, Matcher matcher, String eobjectTypeName, String partialName) ''' - config.«locator(matcher, matcher.locator, partialName)».«matcherType(matcher.type)»(«eobjectTypeName»);''' - - def matchReference(MatcherList matcherList, EList elements, String partialName) ''' - «IF !elements.isEmpty» - «FOR matcher : matcherList.matchers» - «IF matcher.type.isTwoArgumentMatcherType» - «match(matcher, elements.get(0), elements.get(1), matcher.locator, partialName)» - «ELSE» - «FOR e : elements»«match(matcher, e, matcher.locator, partialName)»«ENDFOR» - «ENDIF» - «ENDFOR» - «ENDIF» - ''' - - def match(Matcher matcher, EObject element1, EObject element2, EObject locator, String partialName) ''' - config.«locator(matcher, matcher.locator, partialName)».«matcherType(matcher.type)»(«elementAccess(element1)», «elementAccess(element2)»); // «locatorString(matcher)» - ''' - - // match dispatch - def dispatch match(Matcher matcher, EObject element, Locator locator, String partialName) ''' - config.«locator(matcher, matcher.locator, partialName)».«matcherType(matcher.type)»(«elementAccess(element)»); // «locatorString(matcher)» - ''' - def dispatch match(Matcher matcher, EObject element, NoFormatLocator locator, String partialName) ''' - config.«locator(matcher, matcher.locator, partialName)».«matcherType(matcher.type)»(«elementAccess(element)»); // «locatorString(matcher)» - ''' - def dispatch match(Matcher matcher, EObject element, ColumnLocator locator, String partialName) ''' - «IF matcher.type.literal.compareTo("before") == 0» - «IF locator.parameter !== null» - config.setColumn(«locator.fixed», «locator.relative», «locator.nobreak», new «getParameterCalculatorName(partialName, matcher)»()«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).before(«elementAccess(element)»); // «locatorString(matcher)» - config.setColumn(«locator.fixed», «locator.relative», «locator.nobreak», new «getParameterCalculatorName(partialName, matcher)»()«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).after(«elementAccess(element)»); // «locatorString(matcher)» - «ELSE» - config.setColumn(«locator.value.getValueOrConstant», «locator.fixed», «locator.relative», «locator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).before(«elementAccess(element)»); // «locatorString(matcher)» - config.setColumn(«locator.value.getValueOrConstant», «locator.fixed», «locator.relative», «locator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).after(«elementAccess(element)»); // «locatorString(matcher)» - «ENDIF» - «ELSE» - «IF locator.parameter !== null» - config.setColumn(new «getParameterCalculatorName(partialName, matcher)»()«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).«matcherType(matcher.type)»(«elementAccess(element)»); // «locatorString(matcher)» - «ELSE» - config.setColumn(«locator.value.getValueOrConstant»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).«matcherType(matcher.type)»(«elementAccess(element)»); // «locatorString(matcher)» - «ENDIF» - «ENDIF» - ''' - def dispatch match(Matcher matcher, EObject element, OffsetLocator locator, String partialName) ''' - «IF matcher.type.literal.compareTo("before") == 0» - config.setColumn(«locator.value.getValueOrConstant», «locator.fixed», true, «locator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).before(«elementAccess(element)»); // «locatorString(matcher)» - config.setColumn(«locator.value.getValueOrConstant», «locator.fixed», true, «locator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).after(«elementAccess(element)»); // «locatorString(matcher)» - «ELSE» - config.setOffset(«locator.value.getValueOrConstant»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»).«matcherType(matcher.type)»(«elementAccess(element)»); // «locatorString(matcher)» - «ENDIF» - ''' - def dispatch match(Matcher matcher, EObject element, IndentLocator locator, String partialName) ''' - config.«locator(matcher, matcher.locator, partialName)».«matcherType(matcher.type)»(«elementAccess(element)»); // «locatorString(matcher)» - ''' - - def matcherType(MatcherType matcherType) { matcherType.literal } - - // elementAccess dispatch - def dispatch elementAccess(GrammarElementLookup grammarElementLookup) ''' - «IF grammarElementLookup.rule !== null»elements.findRuleCalls(«grammarElementLookup.rule.gaElementsAccessor»)«ELSEIF grammarElementLookup.keyword !== null»elements.findKeywords("«grammarElementLookup.keyword»")«ENDIF»''' - def dispatch CharSequence elementAccess(GrammarElementReference grammarElementReference) { - if(grammarElementReference.ruleCall !== null) { - elementAccess(grammarElementReference.ruleCall) - } - else if(grammarElementReference.keyword !== null) { - elementAccess(grammarElementReference.keyword) - } - else if(grammarElementReference.assignment !== null) { - elementAccess(grammarElementReference.assignment) - } - else if(grammarElementReference.self !== null) { - if(grammarElementReference.containedByParserRule) { - 'elements.getRule()' - } - else { - 'rule' - } - } else if(grammarElementReference.rule !== null) { - elementAccess(grammarElementReference.rule) - } - } - - def dispatch elementAccess(AbstractRule abstractRule) ''' - getGrammarAccess().«abstractRule.gaRuleAccessor»''' - def dispatch elementAccess(AbstractElement abstractElement) ''' - elements.«abstractElement.gaElementAccessor»''' - def dispatch elementAccess(Object object) { - throw new UnsupportedOperationException("Unknown Xtext element " + object.class.name) - } - - // locator dispatch - def dispatch locator(Matcher matcher, SpaceLocator spaceLocator, String partialName) ''' - «IF spaceLocator.noSpace»setNoSpace(«IF matcher.condition !== null»new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»)«ELSE»setSpace(«spaceLocator.value.getValueOrConstant»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»)«ENDIF»''' - def dispatch locator(Matcher matcher, RightPaddingLocator rightPaddingLocator, String partialName) ''' - setRightPadding(«rightPaddingLocator.value.getValueOrConstant»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»)''' - def dispatch locator(Matcher matcher, LinewrapLocator linewrapLocator, String partialName) ''' - «IF linewrapLocator.noLinewrap»setNoLinewrap(«IF matcher.condition !== null»new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»)«ELSE»setLinewrap(«IF linewrapLocator.value !== null»«linewrapLocator.value.getValueOrConstant»«IF matcher.condition !== null», new «getLocatorActivatorName( - partialName, matcher)»()«ENDIF»«ELSEIF linewrapLocator.minimum !== null»«linewrapLocator.minimum.getValueOrConstant», «linewrapLocator.^default.getValueOrConstant», «linewrapLocator.maximum.getValueOrConstant()»«IF matcher.condition!==null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»«ELSE»«IF matcher. - condition !== null»new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»«ENDIF»)«ENDIF»''' - def dispatch locator(Matcher matcher, ColumnLocator columnLocator, String partialName) ''' - setColumn(«columnLocator.value.getValueOrConstant», «columnLocator.fixed», «columnLocator.relative», «columnLocator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»)''' - def dispatch locator(Matcher matcher, OffsetLocator offsetLocator, String partialName) ''' - setColumn(«offsetLocator.value.getValueOrConstant», «offsetLocator.fixed», true, «offsetLocator.nobreak»«IF matcher.condition !== null», new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»)''' - def dispatch locator(Matcher matcher, IndentLocator indentLocator, String partialName) ''' - «IF indentLocator.increment»setIndentationIncrement(«ELSE»setIndentationDecrement(« - ENDIF»« - IF indentLocator.value !== null && (indentLocator.value.reference !== null || indentLocator.value.literal >= 1)»«indentLocator.value.getValueOrConstant»« - ELSEIF indentLocator.parameter !== null»new «getParameterCalculatorName(partialName, matcher)»()« - ENDIF»« - IF matcher.condition !== null»«IF indentLocator.value !== null || indentLocator.parameter !== null»,«ENDIF» new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»)''' - - def dispatch locator(Matcher matcher, NoFormatLocator noFormatLocator, String partialName) ''' - setNoFormat(«IF matcher.condition !== null»new «getLocatorActivatorName(partialName, matcher)»()«ENDIF»)''' - def dispatch locator(Matcher matcher, Locator locator, String partialName) { - throw new UnsupportedOperationException("Unknown locator " + locator.class.name) - } - - // getValueOrConstant dispatch - def dispatch getValueOrConstant(StringValue stringValue) { - if(stringValue.literal === null) { - stringValue.reference.name - } else { - '"' + stringValue.literal + '"' - } - } - def dispatch getValueOrConstant(IntValue intValue) { - if(intValue.literal === null) { - intValue.reference.name - } else { - intValue.literal.toString() - } - } - - def locatorString(EObject object) { - getFileLocation(object).split('/').lastOrNull() - } - -} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.java new file mode 100644 index 0000000000..6950e6ec53 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.java @@ -0,0 +1,278 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.format.scoping; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.CompoundElement; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.EObjectDescription; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.scoping.IScope; +import org.eclipse.xtext.scoping.impl.MapBasedScope; +import org.eclipse.xtext.scoping.impl.SimpleScope; + +import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration; +import com.avaloq.tools.ddk.xtext.format.format.FormatPackage; +import com.avaloq.tools.ddk.xtext.format.format.GrammarElementReference; +import com.avaloq.tools.ddk.xtext.format.format.GrammarRule; +import com.avaloq.tools.ddk.xtext.format.format.GroupBlock; +import com.avaloq.tools.ddk.xtext.format.naming.FormatScopeNameProvider; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.inject.Inject; + +/** + * The scope provider for the Format language. + */ +public class FormatScopeProvider extends AbstractFormatScopeProvider { + + @Inject + private FormatScopeUtil scopeUtil; + + @Inject + private FormatScopeNameProvider nameProvider; + + /** + * Provides a scope for given context and reference. + * If there is no specific scoping method or if there is such a method but it cannot return a scope, the super class method is called. + */ + @Override + public IScope getScope(final EObject context, final EReference reference) { + final IScope result = scope(context, reference); + if (result != null) { + return result; + } + return super.getScope(context, reference); + } + + /** + * For a given grammar returns the grammar on which it is based, and transitively all base grammars for that grammar. + */ + public Iterable getUsedGrammar(final Grammar context) { + final LinkedList grammars = new LinkedList<>(); + grammars.add(context); + final EList usedGrammars = EcoreUtil2.getContainerOfType(context, Grammar.class).getUsedGrammars(); + if (usedGrammars != null && !usedGrammars.isEmpty()) { + Iterables.addAll(grammars, Iterables.concat(Iterables.transform(usedGrammars, (Grammar g) -> getUsedGrammar(g)))); + } + return grammars; + } + + /** + * For a given formatter returns the grammar on which it is based, and transitively all base grammars for that grammar. + */ + public Collection getGrammars(final EObject context) { + final LinkedList grammars = new LinkedList<>(); + final FormatConfiguration format = EcoreUtil2.getContainerOfType(context, FormatConfiguration.class); + if (format != null && format.getTargetGrammar() != null) { + grammars.add(format.getTargetGrammar()); + Iterables.addAll(grammars, getUsedGrammar(format.getTargetGrammar())); + } + return grammars; + } + + /** + * For a given {@link FormatConfiguration} returns transitively all extending format configurations. + * Usage of LinkedList for {@code formats} does not prevent against duplication of grammars, but a HashSet cannot be used here as there won't be possible to recover the overriding order. + */ + public Collection getFormats(final FormatConfiguration context) { + final LinkedList formats = new LinkedList<>(); + final FormatConfiguration format = context; + if (format != null) { + formats.add(format); + if (format.getExtendedFormatConfiguration() != null) { + formats.addAll(getFormats(format.getExtendedFormatConfiguration())); + } + } + return formats; + } + + /** + * In order to ensure the correct path of inheritance/overriding the list of the grammars has to be reversed. + */ + public List getHierarchyOrderedGrammars(final EObject context) { + return Lists.reverse(Lists.newArrayList(getGrammars(context))); + } + + /** + * In order to ensure the correct path of inheritance/overriding the list of the format configurations has to be reversed. + */ + public List getHierarchyOrderedFormats(final EObject context) { + return Lists.reverse(Lists.newArrayList(getFormats(EcoreUtil2.getContainerOfType(context, FormatConfiguration.class)))); + } + + /** + * Creates scopes for a given list of rules for each grammar. Returned scopes are chained (parental relationships). + */ + public IScope createScopeForAbstractRules(final IScope parent, final Iterable> rulesForGrammars) { + if (parent == null) { + return createScopeForAbstractRules( + MapBasedScope.createScope(IScope.NULLSCOPE, createDescriptions(Iterables.getFirst(rulesForGrammars, null))), + Iterables.skip(rulesForGrammars, 1)); + } else { + if (Iterables.isEmpty(rulesForGrammars)) { + return parent; + } else { + return createScopeForAbstractRules( + MapBasedScope.createScope(parent, createDescriptions(Iterables.getFirst(rulesForGrammars, null))), + Iterables.skip(rulesForGrammars, 1)); + } + } + } + + /** + * Creates a scope for a given list of elements. + */ + public IScope createScopeForEObjects(final List elements) { + return MapBasedScope.createScope(IScope.NULLSCOPE, createDescriptions(elements)); + } + + /** + * Creates a simple scope for a given object description. + */ + public SimpleScope createSimpleScope(final IEObjectDescription description) { + return new SimpleScope(IScope.NULLSCOPE, ImmutableList.of(description)); + } + + /** + * Creates a scope for a given list of compound elements. + */ + public IScope createScopeForCompoundElements(final List compoundElements) { + return MapBasedScope.createScope(IScope.NULLSCOPE, createDescriptionsForCompoundElements(compoundElements)); + } + + protected IScope _scope(final GrammarRule context, final EReference reference) { + if (reference == FormatPackage.Literals.GRAMMAR_RULE__TARGET_RULE) { + final List grammars = getHierarchyOrderedGrammars(context); + final Iterable> rulesForGrammars = Iterables.transform(grammars, (Grammar g) -> g.getRules()); + return createScopeForAbstractRules(null, rulesForGrammars); + } else if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__ASSIGNMENT) { + return createScopeForEObjects(scopeUtil.getAssignments(context.getTargetRule())); + } else if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__KEYWORD) { + return createScopeForEObjects(scopeUtil.getKeywords(context.getTargetRule())); + } else if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__RULE_CALL) { + return createScopeForEObjects(scopeUtil.getRuleCalls(context.getTargetRule())); + } else if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__SELF) { + final IEObjectDescription selfDescription = EObjectDescription.create( + nameProvider.getConstantNameFunction("rule").apply(context.getTargetRule()), context.getTargetRule()); + return createSimpleScope(selfDescription); + } + return IScope.NULLSCOPE; + } + + protected IScope _scope(final GroupBlock context, final EReference reference) { + if (reference == FormatPackage.Literals.GROUP_BLOCK__GRAMMAR_ELEMENT) { + final GrammarRule grammarRule = EcoreUtil2.getContainerOfType(context, GrammarRule.class); + final GroupBlock superGroup = EcoreUtil2.getContainerOfType(context.eContainer(), GroupBlock.class); + if (superGroup == null) { + return createScopeForCompoundElements(scopeUtil.getCompoundElements(grammarRule.getTargetRule(), CompoundElement.class)); + } else { + return createScopeForCompoundElements(scopeUtil.getCompoundElements(superGroup.getGrammarElement(), CompoundElement.class)); + } + } + return IScope.NULLSCOPE; + } + + protected IScope _scope(final GrammarElementReference context, final EReference reference) { + final GrammarRule grammarRule = EcoreUtil2.getContainerOfType(context, GrammarRule.class); + final GroupBlock groupBlock = EcoreUtil2.getContainerOfType(context, GroupBlock.class); + if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__KEYWORD) { + if (groupBlock != null) { + return createScopeForEObjects(scopeUtil.getKeywords(groupBlock.getGrammarElement())); + } + return createScopeForEObjects(scopeUtil.getKeywords(grammarRule.getTargetRule())); + } else if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__ASSIGNMENT) { + if (groupBlock != null) { + return createScopeForEObjects(scopeUtil.getAssignments(groupBlock.getGrammarElement())); + } + return createScopeForEObjects(scopeUtil.getAssignments(grammarRule.getTargetRule())); + } else if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__RULE_CALL) { + if (groupBlock != null) { + return createScopeForEObjects(scopeUtil.getRuleCalls(groupBlock.getGrammarElement())); + } + return createScopeForEObjects(scopeUtil.getRuleCalls(grammarRule.getTargetRule())); + } else if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__SELF) { + if (groupBlock != null) { + final IEObjectDescription selfDescription = EObjectDescription.create( + nameProvider.getConstantNameFunction("rule").apply(groupBlock.getGrammarElement()), + groupBlock.getGrammarElement()); + return createSimpleScope(selfDescription); + } else { + final IEObjectDescription selfDescription = EObjectDescription.create( + nameProvider.getConstantNameFunction("rule").apply(grammarRule.getTargetRule()), grammarRule.getTargetRule()); + return createSimpleScope(selfDescription); + } + } else if (reference == FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__RULE) { + final Iterable> rulesForGrammars = Iterables.transform(getHierarchyOrderedGrammars(grammarRule), (Grammar c) -> c.getRules()); + return createScopeForAbstractRules(null, rulesForGrammars); + } + return IScope.NULLSCOPE; + } + + // default implementation will throw an illegal argument exception + protected IScope _scope(final EObject context, final EReference reference) { + return null; + } + + /** + * Dispatch method for scope resolution based on runtime type of context. + */ + public IScope scope(final EObject context, final EReference reference) { + if (context instanceof GrammarRule grammarRule) { + return _scope(grammarRule, reference); + } else if (context instanceof GrammarElementReference grammarElementReference) { + return _scope(grammarElementReference, reference); + } else if (context instanceof GroupBlock groupBlock) { + return _scope(groupBlock, reference); + } else if (context != null) { + return _scope(context, reference); + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(context, reference).toString()); + } + } + + /** + * Creates object descriptions for a given list of {@link FormatConfiguration}. + */ + public Collection createDescriptionsFormats(final List elements) { + return Collections2.transform(elements, (FormatConfiguration e) -> EObjectDescription.create(scopeUtil.findTargetGrammar(e).getName(), e)); + } + + /** + * Creates descriptions for a given list of objects. + */ + public Collection createDescriptions(final List elements) { + final Function namingFunction = nameProvider.getIndexParameterNameFunction(elements); + return Collections2.transform(elements, (EObject e) -> EObjectDescription.create(namingFunction.apply(e), e)); + } + + /** + * Creates object descriptions for a list of CompundElements ({@code group X} items). Groups are referenced using numbers which are used in formatter and at the same time corresponds to indexes in the list. + */ + public Collection createDescriptionsForCompoundElements(final List elements) { + final Function namingFunction = nameProvider.getIndexNameFunction(elements); + return Collections2.transform(elements, (CompoundElement e) -> EObjectDescription.create(namingFunction.apply(e), e)); + } +} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.xtend b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.xtend deleted file mode 100644 index fe5270c5ce..0000000000 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.xtend +++ /dev/null @@ -1,258 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.format.scoping - -import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration -import com.avaloq.tools.ddk.xtext.format.format.FormatPackage -import com.avaloq.tools.ddk.xtext.format.format.GrammarElementReference -import com.avaloq.tools.ddk.xtext.format.format.GrammarRule -import com.avaloq.tools.ddk.xtext.format.format.GroupBlock -import com.avaloq.tools.ddk.xtext.format.naming.FormatScopeNameProvider -import com.google.common.collect.Collections2 -import com.google.common.collect.ImmutableList -import com.google.common.collect.Iterables -import com.google.common.collect.Lists -import com.google.inject.Inject -import java.util.Collection -import java.util.LinkedList -import java.util.List -import org.eclipse.emf.common.util.EList -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.EReference -import org.eclipse.xtext.AbstractRule -import org.eclipse.xtext.CompoundElement -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.resource.EObjectDescription -import org.eclipse.xtext.resource.IEObjectDescription -import org.eclipse.xtext.scoping.IScope -import org.eclipse.xtext.scoping.impl.MapBasedScope -import org.eclipse.xtext.scoping.impl.SimpleScope - -/** - * The scope provider for the Format language. - */ -class FormatScopeProvider extends AbstractFormatScopeProvider { - - @Inject - FormatScopeUtil scopeUtil; - @Inject - FormatScopeNameProvider nameProvider; - - /** - * Provides a scope for given context and reference. - * If there is no specific scoping method or if there is such a method but it cannot return a scope, the super class method is called. - */ - override IScope getScope(EObject context, EReference reference) { - val result = scope(context, reference) - if (result !== null) { - return result - } - return super.getScope(context, reference) - } - - /** - * For a given grammar returns the grammar on which it is based, and transitively all base grammars for that grammar. - * - */ - def Iterable getUsedGrammar(Grammar context){ - val LinkedList grammars = newLinkedList() - grammars.add(context) - val usedGrammars = EcoreUtil2::getContainerOfType(context, typeof(Grammar)).usedGrammars - if (usedGrammars!==null && !usedGrammars.empty){ - grammars.addAll( Iterables::concat( Iterables::transform( usedGrammars, [g|getUsedGrammar(g)] ))) - } - return grammars - } - - /** - * For a given formatter returns the grammar on which it is based, and transitively all base grammars for that grammar. - * - */ - def Collection getGrammars(EObject context) { - val LinkedList grammars = newLinkedList() - val format = EcoreUtil2::getContainerOfType(context, typeof(FormatConfiguration)) - if (format !== null && format.targetGrammar !== null) { - grammars.add(format.targetGrammar); - grammars.addAll(getUsedGrammar(format.targetGrammar)) - } - return grammars - } - - /** - * For a given {@link FormatConfiguration} returns transitively all extending format configurations. - * Usage of LinkedList for {@code formats} does not prevent against duplication of grammars, but a HashSet cannot be used here as there won't be possible to recover the overriding order. - */ - def Collection getFormats(FormatConfiguration context) { - val formats = newLinkedList() - val format = context - if (format !== null) { - formats.add(format); - if (format.extendedFormatConfiguration !== null) { - formats.addAll(getFormats(format.extendedFormatConfiguration)) - } - } - return formats - } - - /** - * In order to ensure the correct path of inheritance/overriding the list of the grammars has to be reversed. - */ - def List getHierarchyOrderedGrammars(EObject context) { - return Lists.newArrayList(getGrammars(context)).reverse() - } - - /** - * In order to ensure the correct path of inheritance/overriding the list of the format configurations has to be reversed. - */ - def List getHierarchyOrderedFormats(EObject context) { - return Lists.newArrayList(getFormats(EcoreUtil2::getContainerOfType(context, typeof(FormatConfiguration)))). - reverse() - } - - /** - * Creates scopes for a given list of rules for each grammar. Returned scopes are chained (parental relationships). - */ - def IScope createScopeForAbstractRules(IScope parent, Iterable> rulesForGrammars) { - if (parent === null) { - return createScopeForAbstractRules( - MapBasedScope::createScope(IScope::NULLSCOPE, createDescriptions(rulesForGrammars.head)), - rulesForGrammars.tail); - } else { - if (rulesForGrammars.empty) { - return parent; - } else { - return createScopeForAbstractRules( - MapBasedScope::createScope(parent, createDescriptions(rulesForGrammars.head)), rulesForGrammars.tail); - } - } - } - - /** - * Creates a scope for a given list of elements. - */ - def IScope createScopeForEObjects(List elements) { - return MapBasedScope::createScope(IScope::NULLSCOPE, createDescriptions(elements)); - } - - /** - * Creates a simple scope for a given object description. - */ - def createSimpleScope(IEObjectDescription description) { - return new SimpleScope(IScope::NULLSCOPE, ImmutableList::of(description)); - } - - /** - * Creates a scope for a given list of compound elements. - */ - def IScope createScopeForCompoundElements(List compoundElements){ - return MapBasedScope::createScope(IScope::NULLSCOPE, createDescriptionsForCompoundElements(compoundElements)) - } - - - def dispatch IScope scope(GrammarRule context, EReference reference) { - if (reference == FormatPackage.Literals::GRAMMAR_RULE__TARGET_RULE) { - val grammars = getHierarchyOrderedGrammars(context) - val rulesForGrammars = Iterables::transform(grammars, [g|g.rules]) - return createScopeForAbstractRules(null, rulesForGrammars); - } else if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__ASSIGNMENT) { - return createScopeForEObjects(scopeUtil.getAssignments(context.targetRule)); - } else if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__KEYWORD) { - return createScopeForEObjects(scopeUtil.getKeywords(context.targetRule)); - } else if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__RULE_CALL) { - return createScopeForEObjects(scopeUtil.getRuleCalls(context.targetRule)); - } else if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__SELF) { - val selfDescription = EObjectDescription::create( - nameProvider.getConstantNameFunction("rule").apply(context.targetRule), context.targetRule); - return createSimpleScope(selfDescription) - } - return IScope::NULLSCOPE; - } - - def dispatch IScope scope(GroupBlock context, EReference reference) { - if (reference == FormatPackage.Literals::GROUP_BLOCK__GRAMMAR_ELEMENT) { - val grammarRule = EcoreUtil2::getContainerOfType(context, typeof(GrammarRule)) - val superGroup = EcoreUtil2::getContainerOfType(context.eContainer(), typeof(GroupBlock)) - if (superGroup === null){ - return createScopeForCompoundElements(scopeUtil.getCompoundElements(grammarRule.targetRule, typeof(CompoundElement))) - } - else{ - return createScopeForCompoundElements(scopeUtil.getCompoundElements(superGroup.grammarElement, typeof(CompoundElement))) - } - } - return IScope::NULLSCOPE; - } - - def dispatch IScope scope(GrammarElementReference context, EReference reference) { - val grammarRule = EcoreUtil2::getContainerOfType(context, typeof(GrammarRule)) - val groupBlock = EcoreUtil2::getContainerOfType(context, typeof(GroupBlock)) - if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__KEYWORD) { - if (groupBlock !== null) { - return createScopeForEObjects(scopeUtil.getKeywords(groupBlock.grammarElement)); - } - return createScopeForEObjects(scopeUtil.getKeywords(grammarRule.targetRule)); - } else if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__ASSIGNMENT) { - if (groupBlock !== null) { - return createScopeForEObjects(scopeUtil.getAssignments(groupBlock.grammarElement)); - } - return createScopeForEObjects(scopeUtil.getAssignments(grammarRule.targetRule)); - } else if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__RULE_CALL) { - if (groupBlock !== null) { - return createScopeForEObjects(scopeUtil.getRuleCalls(groupBlock.grammarElement)); - } - return createScopeForEObjects(scopeUtil.getRuleCalls(grammarRule.targetRule)); - } else if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__SELF) { - if (groupBlock !== null) { - val selfDescription = EObjectDescription::create( - nameProvider.getConstantNameFunction("rule").apply(groupBlock.grammarElement), - groupBlock.grammarElement) - return createSimpleScope(selfDescription) - } else { - val selfDescription = EObjectDescription::create( - nameProvider.getConstantNameFunction("rule").apply(grammarRule.targetRule), grammarRule.targetRule); - return createSimpleScope(selfDescription) - } - } else if (reference == FormatPackage.Literals::GRAMMAR_ELEMENT_REFERENCE__RULE) { - val rulesForGrammars = Iterables::transform(getHierarchyOrderedGrammars(grammarRule), [c|c.rules]) - return createScopeForAbstractRules(null, rulesForGrammars); - } - return IScope::NULLSCOPE; - } - - // default implementation will throw an illegal argument exception - def dispatch IScope scope(EObject context, EReference reference) { - return null - } - - /** - * Creates object descriptions for a given list of {@link FormatConfiguration}. - */ - def Collection createDescriptionsFormats(List elements) { - Collections2::transform(elements, [e|EObjectDescription::create(scopeUtil.findTargetGrammar(e).name, e)]) - } - - /** - * Creates descriptions for a given list of objects. - */ - def Collection createDescriptions(List elements) { - val namingFunction = nameProvider.getIndexParameterNameFunction(elements) - Collections2::transform(elements, [e|EObjectDescription::create(namingFunction.apply(e), e)]) - } - - /** - * Creates object descriptions for a list of CompundElements ({@code group X} items). Groups are referenced using numbers which are used in formatter and at the same time corresponds to indexes in the list. - */ - def Collection createDescriptionsForCompoundElements(List elements) { - val namingFunction = nameProvider.getIndexNameFunction(elements) - Collections2::transform(elements, [e|EObjectDescription::create(namingFunction.apply(e), e)]) - } - -} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.java new file mode 100644 index 0000000000..bf71fd5494 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.java @@ -0,0 +1,396 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.format.validation; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Objects; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.osgi.util.NLS; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.EnumRule; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.ParserRule; +import org.eclipse.xtext.TerminalRule; +import org.eclipse.xtext.validation.Check; + +import com.avaloq.tools.ddk.xtext.format.format.Constant; +import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration; +import com.avaloq.tools.ddk.xtext.format.format.FormatPackage; +import com.avaloq.tools.ddk.xtext.format.format.GrammarElementLookup; +import com.avaloq.tools.ddk.xtext.format.format.GrammarElementReference; +import com.avaloq.tools.ddk.xtext.format.format.GrammarRule; +import com.avaloq.tools.ddk.xtext.format.format.IntValue; +import com.avaloq.tools.ddk.xtext.format.format.KeywordPair; +import com.avaloq.tools.ddk.xtext.format.format.Matcher; +import com.avaloq.tools.ddk.xtext.format.format.MatcherType; +import com.avaloq.tools.ddk.xtext.format.format.Rule; +import com.avaloq.tools.ddk.xtext.format.format.SpecificDirective; +import com.avaloq.tools.ddk.xtext.format.format.StringValue; +import com.avaloq.tools.ddk.xtext.format.format.WildcardRule; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * This class contains custom validation rules. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation + */ +public class FormatValidator extends AbstractFormatValidator { + + /** + * Validation code for illegal format directives for Terminal or Datatype rules. + */ + public static final String ILLEGAL_DIRECTIVE_CODE = "com.avaloq.tools.ddk.xtext.format.validation.IllegalDirective"; + + /** + * Validation code for override missing. + */ + public static final String OVERRIDE_MISSING_CODE = "com.avaloq.tools.ddk.xtext.format.validation.MissingOverride"; + + /** + * Validation code for illegal override. + */ + public static final String OVERRIDE_ILLEGAL_CODE = "com.avaloq.tools.ddk.xtext.format.validation.IllegalOverride"; + + /** + * Validation code for incompatible grammar of extended format. + */ + public static final String EXTENDED_GRAMMAR_INCOMPATIBLE_CODE = "com.avaloq.tools.ddk.xtext.format.validation.ExtendedGrammarIncompatible"; + + /** + * Validation code for required grammar rule missing. + */ + public static final String GRAMMAR_RULE_MISSING_CODE = "com.avaloq.tools.ddk.xtext.format.validation.GrammarRuleMissing"; + + private static final String OVERRIDE_MISSING_MESSAGE = "Override missing"; + + private static final String OVERRIDE_ILLEGAL_MESSAGE = "Override illegal"; + + private static final Predicate IS_OVERRIDE = new Predicate() { + @Override + public boolean apply(final Rule input) { + return input.isOverride(); + } + }; + + private static final Function TARGET_RULE = new Function() { + @Override + public AbstractRule apply(final GrammarRule from) { + return from.getTargetRule(); + } + }; + + /** + * Verify that only rule self directives are used for terminal, enum and data type rules. + * + * @param model + * the GrammarRule + */ + @Check + public void checkDataTypeOrEnumRule(final GrammarRule model) { + if (model.getTargetRule() instanceof TerminalRule || model.getTargetRule() instanceof EnumRule + || (model.getTargetRule() instanceof ParserRule && GrammarUtil.isDatatypeRule((ParserRule) model.getTargetRule()))) { + final Iterator grammarElementAccessors = collectGrammarElementAccessors(model); + final boolean selfAccessOnly = Iterators.all(grammarElementAccessors, new Predicate() { + @Override + public boolean apply(final EObject input) { + return input instanceof GrammarElementReference && ((GrammarElementReference) input).getSelf() != null; + } + }); + if (!selfAccessOnly) { + error(NLS.bind("For data type, enum or terminal rule {0} only ''rule'' directive may be used", model.getTargetRule().getName()), FormatPackage.Literals.GRAMMAR_RULE__DIRECTIVES, ILLEGAL_DIRECTIVE_CODE); + } + } + } + + /** + * Verify that there are exactly two grammar elements if "between" is used. + * + * @param matcher + * the Matcher + */ + @Check + public void checkBetweenArguments(final Matcher matcher) { + checkTwoArgumentMatcherType(matcher, MatcherType.BETWEEN); + } + + /** + * Verify that there are exactly two grammar elements if "range" is used. + * + * @param matcher + * the Matcher + */ + @Check + public void checkRangeArguments(final Matcher matcher) { + checkTwoArgumentMatcherType(matcher, MatcherType.RANGE); + } + + /** + * Verify that references to other grammar rules at most occur once and that "between" or "range" is used. + * + * @param elementReference + * reference to a grammar element + */ + @Check + public void checkRuleReference(final GrammarElementReference elementReference) { + if (elementReference.getRule() == null) { + return; + } + final SpecificDirective directive = EcoreUtil2.getContainerOfType(elementReference, SpecificDirective.class); + if (directive.getMatcherList() != null) { + final boolean twoArgumentMatcherTypesOnly = Iterables.all(directive.getMatcherList().getMatchers(), new Predicate() { + @Override + public boolean apply(final Matcher input) { + return Objects.equals(input.getType(), MatcherType.BETWEEN) || Objects.equals(input.getType(), MatcherType.RANGE); + } + }); + if (!twoArgumentMatcherTypesOnly) { + error(NLS.bind("Grammar rules may only be used with \"{0}\" or \"{1}\"", MatcherType.RANGE.getName(), MatcherType.BETWEEN.getName()), FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__RULE); + } + final Iterable ruleGrammarElements = Iterables.filter(directive.getGrammarElements(), new Predicate() { + @Override + public boolean apply(final GrammarElementReference input) { + return input.getRule() != null; + } + }); + if (Iterables.size(ruleGrammarElements) != 1) { + error(NLS.bind("Only one grammar rule may be referenced with \"{0}\" and \"{1}\"", MatcherType.RANGE.getName(), MatcherType.BETWEEN.getName()), FormatPackage.Literals.GRAMMAR_ELEMENT_REFERENCE__RULE); + } + } + } + + /** + * Checks that rules declare overrides when there is a corresponding inherited rule. + * + * @param model + * the model + */ + @Check + public void checkOverrideMissing(final FormatConfiguration model) { + final FormatConfiguration extendedModel = model.getExtendedFormatConfiguration(); + if (extendedModel == null || extendedModel.eIsProxy()) { + return; + } + final Iterable nonOverrideRules = Iterables.filter(model.getRules(), Predicates.not(IS_OVERRIDE)); + final Iterable overriddenRules = collectRules(extendedModel); + final HashMap localAbstractRuleMap = Maps.newHashMap(); + for (final GrammarRule rule : Iterables.filter(nonOverrideRules, GrammarRule.class)) { + localAbstractRuleMap.put(TARGET_RULE.apply(rule), rule); + } + // Check GrammarRules + for (final GrammarRule overriddenRule : Iterables.filter(overriddenRules, GrammarRule.class)) { + if (localAbstractRuleMap.containsKey(TARGET_RULE.apply(overriddenRule))) { + final GrammarRule localRule = localAbstractRuleMap.get(TARGET_RULE.apply(overriddenRule)); + error(OVERRIDE_MISSING_MESSAGE, localRule, FormatPackage.Literals.GRAMMAR_RULE__TARGET_RULE, OVERRIDE_MISSING_CODE); + } + } + // Check WildcardRule + if (!Iterables.isEmpty(Iterables.filter(nonOverrideRules, WildcardRule.class)) + && !Iterables.isEmpty(Iterables.filter(overriddenRules, WildcardRule.class))) { + error(OVERRIDE_MISSING_MESSAGE, Iterables.filter(nonOverrideRules, WildcardRule.class).iterator().next(), null, OVERRIDE_MISSING_CODE); + } + } + + /** + * Checks that no rule declares override when there is no corresponding inherited rule. + * + * @param model + * the model + */ + @Check + public void checkIllegalOverride(final FormatConfiguration model) { + final Iterable overrideRules = Iterables.filter(model.getRules(), IS_OVERRIDE); + Iterable overrideableRules = Lists.newArrayList(); + final FormatConfiguration extendedModel = model.getExtendedFormatConfiguration(); + if (extendedModel != null && !extendedModel.eIsProxy()) { + overrideableRules = collectRules(extendedModel); + } + final HashMap overrideableAbstractRuleMap = Maps.newHashMap(); + for (final GrammarRule rule : Iterables.filter(overrideableRules, GrammarRule.class)) { + overrideableAbstractRuleMap.put(TARGET_RULE.apply(rule), rule); + } + // Check GrammarRules + for (final GrammarRule overrideRule : Iterables.filter(overrideRules, GrammarRule.class)) { + if (!overrideableAbstractRuleMap.containsKey(TARGET_RULE.apply(overrideRule))) { + error(OVERRIDE_ILLEGAL_MESSAGE, overrideRule, FormatPackage.Literals.GRAMMAR_RULE__TARGET_RULE, OVERRIDE_ILLEGAL_CODE); + } + } + // Check WildcardRule + if (!Iterables.isEmpty(Iterables.filter(overrideRules, WildcardRule.class)) + && Iterables.isEmpty(Iterables.filter(overrideableRules, WildcardRule.class))) { + error(OVERRIDE_ILLEGAL_MESSAGE, Iterables.filter(overrideRules, WildcardRule.class).iterator().next(), null, OVERRIDE_ILLEGAL_CODE); + } + } + + /** + * Check that extended configuration's grammar is compatible. + * + * @param model + * the model + */ + @Check + public void checkExtendedGrammarCompatible(final FormatConfiguration model) { + final FormatConfiguration extendedModel = model.getExtendedFormatConfiguration(); + if (extendedModel == null || extendedModel.eIsProxy()) { + return; + } + if (!extendedModel.getTargetGrammar().eIsProxy()) { + final ArrayList grammars = Lists.newArrayList(model.getTargetGrammar()); + grammars.addAll(model.getTargetGrammar().getUsedGrammars()); + for (final Grammar grammar : grammars) { + if (extendedModel.getTargetGrammar().getName().equals(grammar.getName())) { + return; + } + } + } + error("Extended format configuration has incompatible grammar", FormatPackage.Literals.FORMAT_CONFIGURATION__EXTENDED_FORMAT_CONFIGURATION, EXTENDED_GRAMMAR_INCOMPATIBLE_CODE); + } + + /** + * Check that identically named parent grammar rules are implemented in the model if the parent configuration implements the rule. + * If both grammars have an identically named rule then the extending FormatConfiguration must declare formatting if the parent FormatConfiguration does. + * + * @param model + * the model + */ + @Check + public void checkRequiredRulesImplemented(final FormatConfiguration model) { + final FormatConfiguration extendedModel = model.getExtendedFormatConfiguration(); + if (extendedModel == null || extendedModel.eIsProxy() || Objects.equals(model.getTargetGrammar(), extendedModel.getTargetGrammar())) { // NOPMD + return; + } + final Iterable inheritedRules = Iterables.filter(collectRules(extendedModel), GrammarRule.class); + final HashSet ruleNames = Sets.newHashSet(Iterables.transform(inheritedRules, new Function() { + @Override + public String apply(final GrammarRule from) { + return from.getTargetRule().getName(); + } + })); + for (final GrammarRule rule : Iterables.filter(model.getRules(), GrammarRule.class)) { + if (rule.getTargetRule() != null && !rule.getTargetRule().eIsProxy()) { + ruleNames.remove(rule.getTargetRule().getName()); + } + } + for (final AbstractRule rule : model.getTargetGrammar().getRules()) { + if (ruleNames.contains(rule.getName())) { + error(NLS.bind("Required formatting for rule \"{0}\" missing", rule.getName()), FormatPackage.Literals.FORMAT_CONFIGURATION__TARGET_GRAMMAR, GRAMMAR_RULE_MISSING_CODE, rule.getName()); + } + } + } + + /** + * Check that referenced value is of integer type. + * + * @param value + * the value + */ + @Check + public void checkIntValueConstantReference(final IntValue value) { + if (value.getReference() == null || value.getReference().eIsProxy()) { + return; + } + if (value.getReference().getIntValue() == null) { + error(NLS.bind("Referenced const \"{0}\" is not an integer", value.getReference().getName()), FormatPackage.Literals.INT_VALUE__REFERENCE); + } + } + + /** + * Check that referenced value is of string type. + * + * @param value + * the value + */ + @Check + public void checkStringValueConstantReference(final StringValue value) { + if (value.getReference() == null || value.getReference().eIsProxy()) { + return; + } + if (value.getReference().getIntValue() == null) { + error(NLS.bind("Referenced const \"{0}\" is not a string", value.getReference().getName()), FormatPackage.Literals.STRING_VALUE__REFERENCE); + } + } + + /** + * Check that value is consistent with the (optional) declared type. + * + * @param value + * the value + */ + @Check + public void checkConstantOptionalType(final Constant value) { + if (value.isIntType() && value.getIntValue() == null) { + error("Value is not an integer", FormatPackage.Literals.CONSTANT__NAME); + } else if (value.isStringType() && value.getStringValue() == null) { + error("Value is not a string", FormatPackage.Literals.CONSTANT__NAME); + } + } + + /** + * Collect all rules contained by the given model (including any of its extended configurations). + * + * @param model + * the model + * @return all rules + */ + private Iterable collectRules(final FormatConfiguration model) { + Iterable result = model.getRules(); + final FormatConfiguration extendedModel = model.getExtendedFormatConfiguration(); + if (extendedModel != null && !extendedModel.eIsProxy()) { + result = Iterables.concat(result, collectRules(extendedModel)); + } + return result; + } + + /** + * Verify that there are exactly two grammar elements used in the containing directive if the type of the matcher equals the given MatcherType. + * + * @param matcher + * the Matcher + * @param matcherType + * the MatcherType + */ + private void checkTwoArgumentMatcherType(final Matcher matcher, final MatcherType matcherType) { + if (Objects.equals(matcher.getType(), matcherType)) { + final SpecificDirective directive = EcoreUtil2.getContainerOfType(matcher, SpecificDirective.class); + if (directive == null || directive.getGrammarElements().size() != 2) { + error(NLS.bind("\"{0}\" may only be used with exactly two elements", matcherType.getName()), FormatPackage.Literals.MATCHER__TYPE); + } + } + } + + /** + * Collects all GramarElementReferences, GrammarElementLookups and KeywordPairs contained by a GrammarRule. + * + * @param rule + * the grammar rule + * @return Iterator with all grammar element accessors + */ + private static Iterator collectGrammarElementAccessors(final GrammarRule rule) { + return Iterators.filter(rule.eAllContents(), new Predicate() { + @Override + public boolean apply(final EObject input) { + return input instanceof KeywordPair || input instanceof GrammarElementReference || input instanceof GrammarElementLookup; + } + }); + } +} diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.xtend b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.xtend deleted file mode 100644 index bfe4c0d1ff..0000000000 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.xtend +++ /dev/null @@ -1,376 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.format.validation - -import com.avaloq.tools.ddk.xtext.format.format.Constant -import com.avaloq.tools.ddk.xtext.format.format.FormatConfiguration -import com.avaloq.tools.ddk.xtext.format.format.GrammarElementLookup -import com.avaloq.tools.ddk.xtext.format.format.GrammarElementReference -import com.avaloq.tools.ddk.xtext.format.format.GrammarRule -import com.avaloq.tools.ddk.xtext.format.format.IntValue -import com.avaloq.tools.ddk.xtext.format.format.KeywordPair -import com.avaloq.tools.ddk.xtext.format.format.Matcher -import com.avaloq.tools.ddk.xtext.format.format.MatcherType -import com.avaloq.tools.ddk.xtext.format.format.Rule -import com.avaloq.tools.ddk.xtext.format.format.SpecificDirective -import com.avaloq.tools.ddk.xtext.format.format.StringValue -import com.avaloq.tools.ddk.xtext.format.format.WildcardRule -import com.google.common.collect.Iterables -import com.google.common.collect.Iterators -import com.google.common.collect.Lists -import com.google.common.collect.Maps -import com.google.common.collect.Sets -import java.util.Iterator -import org.eclipse.emf.ecore.EObject -import org.eclipse.osgi.util.NLS -import org.eclipse.xtext.AbstractRule -import org.eclipse.xtext.EcoreUtil2; -import org.eclipse.xtext.EnumRule -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.GrammarUtil -import org.eclipse.xtext.ParserRule -import org.eclipse.xtext.TerminalRule -import org.eclipse.xtext.validation.Check -import com.avaloq.tools.ddk.xtext.format.format.FormatPackage -import com.google.common.base.Predicate -import com.google.common.base.Function -import com.google.common.base.Predicates - -/** - * This class contains custom validation rules. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation - */ -class FormatValidator extends AbstractFormatValidator { - - /** - * Validation code for illegal format directives for Terminal or Datatype rules. - */ - public static val ILLEGAL_DIRECTIVE_CODE = "com.avaloq.tools.ddk.xtext.format.validation.IllegalDirective" - /** - * Validation code for override missing. - */ - public static val OVERRIDE_MISSING_CODE = "com.avaloq.tools.ddk.xtext.format.validation.MissingOverride" - /** - * Validation code for illegal override. - */ - public static val OVERRIDE_ILLEGAL_CODE = "com.avaloq.tools.ddk.xtext.format.validation.IllegalOverride" - /** - * Validation code for incompatible grammar of extended format. - */ - public static val EXTENDED_GRAMMAR_INCOMPATIBLE_CODE = "com.avaloq.tools.ddk.xtext.format.validation.ExtendedGrammarIncompatible" - /** - * Validation code for required grammar rule missing. - */ - public static val GRAMMAR_RULE_MISSING_CODE = "com.avaloq.tools.ddk.xtext.format.validation.GrammarRuleMissing" - static val OVERRIDE_MISSING_MESSAGE = "Override missing" - static val OVERRIDE_ILLEGAL_MESSAGE = "Override illegal" - static val IS_OVERRIDE = new Predicate() { - override apply(Rule input) { - return input.isOverride() - } - - }; - static val TARGET_RULE = new Function() { - override apply(GrammarRule from) { - return from.getTargetRule() - } - }; - - /** - * Verify that only rule self directives are used for terminal, enum and data type rules. - * - * @param model - * the GrammarRule - */ - @Check - def void checkDataTypeOrEnumRule(GrammarRule model) { - if (model.getTargetRule() instanceof TerminalRule || model.getTargetRule() instanceof EnumRule - || (model.getTargetRule() instanceof ParserRule && GrammarUtil.isDatatypeRule(model.getTargetRule() as ParserRule))) { - val grammarElementAccessors = collectGrammarElementAccessors(model) - val selfAccessOnly = Iterators.all(grammarElementAccessors, new Predicate() { - override apply(EObject input) { - return input instanceof GrammarElementReference && (input as GrammarElementReference).getSelf() !== null - } - }); - if (!selfAccessOnly) { - error(NLS.bind("For data type, enum or terminal rule {0} only ''rule'' directive may be used", model.getTargetRule().getName()), FormatPackage::Literals::GRAMMAR_RULE__DIRECTIVES, ILLEGAL_DIRECTIVE_CODE) - } - } - } - - /** - * Verify that there are exactly two grammar elements if "between" is used. - * - * @param matcher - * the Matcher - */ - @Check - def void checkBetweenArguments(Matcher matcher) { - checkTwoArgumentMatcherType(matcher, MatcherType::BETWEEN) - } - - /** - * Verify that there are exactly two grammar elements if "range" is used. - * - * @param matcher - * the Matcher - */ - @Check - def void checkRangeArguments(Matcher matcher) { - checkTwoArgumentMatcherType(matcher, MatcherType::RANGE) - } - - /** - * Verify that references to other grammar rules at most occur once and that "between" or "range" is used. - * - * @param elementReference - * reference to a grammar element - */ - @Check - def void checkRuleReference(GrammarElementReference elementReference) { - if (elementReference.getRule() === null) { - return - } - val directive = EcoreUtil2.getContainerOfType(elementReference, SpecificDirective); - if (directive.getMatcherList() !== null) { - val twoArgumentMatcherTypesOnly = Iterables.all(directive.getMatcherList().getMatchers(), new Predicate() { - override apply(Matcher input) { - return input.getType() == MatcherType::BETWEEN || input.getType() == MatcherType::RANGE - } - }); - if (!twoArgumentMatcherTypesOnly) { - error(NLS.bind("Grammar rules may only be used with \"{0}\" or \"{1}\"", MatcherType::RANGE.getName(), MatcherType::BETWEEN.getName()), FormatPackage::Literals::GRAMMAR_ELEMENT_REFERENCE__RULE) - } - val ruleGrammarElements = Iterables.filter(directive.getGrammarElements(), new Predicate() { - override apply(GrammarElementReference input) { - return input.getRule() !== null - } - }) - if (Iterables.size(ruleGrammarElements) != 1) { - error(NLS.bind("Only one grammar rule may be referenced with \"{0}\" and \"{1}\"", MatcherType::RANGE.getName(), MatcherType::BETWEEN.getName()), FormatPackage::Literals::GRAMMAR_ELEMENT_REFERENCE__RULE) - } - } - } - - /** - * Checks that rules declare overrides when there is a corresponding inherited rule. - * - * @param model - * the model - */ - @Check - def void checkOverrideMissing(FormatConfiguration model) { - val extendedModel = model.getExtendedFormatConfiguration(); - if (extendedModel === null || extendedModel.eIsProxy()) { - return - } - val nonOverrideRules = Iterables.filter(model.getRules(), Predicates.not(IS_OVERRIDE)) - val overriddenRules = collectRules(extendedModel) - val localAbstractRuleMap = Maps.newHashMap() - for (GrammarRule rule : Iterables.filter(nonOverrideRules, GrammarRule)) { - localAbstractRuleMap.put(TARGET_RULE.apply(rule), rule) - } - // Check GrammarRules - for (GrammarRule overriddenRule : Iterables.filter(overriddenRules, GrammarRule)) { - if (localAbstractRuleMap.containsKey(TARGET_RULE.apply(overriddenRule))) { - val localRule = localAbstractRuleMap.get(TARGET_RULE.apply(overriddenRule)) - error(OVERRIDE_MISSING_MESSAGE, localRule, FormatPackage::Literals::GRAMMAR_RULE__TARGET_RULE, OVERRIDE_MISSING_CODE) - } - } - // Check WildcardRule - if (!Iterables.isEmpty(Iterables.filter(nonOverrideRules, WildcardRule)) - && !Iterables.isEmpty(Iterables.filter(overriddenRules, WildcardRule))) { - error(OVERRIDE_MISSING_MESSAGE, Iterables.filter(nonOverrideRules, WildcardRule).iterator().next(), null, OVERRIDE_MISSING_CODE) - } - } - - /** - * Checks that no rule declares override when there is no corresponding inherited rule. - * - * @param model - * the model - */ - @Check - def void checkIllegalOverride(FormatConfiguration model) { - val overrideRules = Iterables.filter(model.getRules(), IS_OVERRIDE) - var Iterable overrideableRules = Lists.newArrayList() - val extendedModel = model.getExtendedFormatConfiguration() - if (extendedModel !== null && !extendedModel.eIsProxy()) { - overrideableRules = collectRules(extendedModel) - } - val overrideableAbstractRuleMap = Maps.newHashMap() - for (GrammarRule rule : Iterables.filter(overrideableRules, GrammarRule)) { - overrideableAbstractRuleMap.put(TARGET_RULE.apply(rule), rule) - } - // Check GrammarRules - for (GrammarRule overrideRule : Iterables.filter(overrideRules, GrammarRule)) { - if (!overrideableAbstractRuleMap.containsKey(TARGET_RULE.apply(overrideRule))) { - error(OVERRIDE_ILLEGAL_MESSAGE, overrideRule, FormatPackage::Literals::GRAMMAR_RULE__TARGET_RULE, OVERRIDE_ILLEGAL_CODE) - } - } - // Check WildcardRule - if (!Iterables.isEmpty(Iterables.filter(overrideRules, WildcardRule)) && Iterables.isEmpty(Iterables.filter(overrideableRules, WildcardRule))) { - error(OVERRIDE_ILLEGAL_MESSAGE, Iterables.filter(overrideRules, WildcardRule).iterator().next(), null, OVERRIDE_ILLEGAL_CODE) - } - } - - /** - * Check that extended configuration's grammar is compatible. - * - * @param model - * the model - */ - @Check - def void checkExtendedGrammarCompatible(FormatConfiguration model) { - val extendedModel = model.getExtendedFormatConfiguration() - if (extendedModel === null || extendedModel.eIsProxy()) { - return - } - if (!extendedModel.getTargetGrammar().eIsProxy()) { - val grammars = Lists.newArrayList(model.getTargetGrammar()) - grammars.addAll(model.getTargetGrammar().getUsedGrammars()) - for (Grammar grammar : grammars) { - if (extendedModel.getTargetGrammar().getName().equals(grammar.getName())) { - return - } - } - } - error("Extended format configuration has incompatible grammar", FormatPackage::Literals::FORMAT_CONFIGURATION__EXTENDED_FORMAT_CONFIGURATION, EXTENDED_GRAMMAR_INCOMPATIBLE_CODE) - } - - /** - * Check that identically named parent grammar rules are implemented in the model if the parent configuration implements the rule. - * If both grammars have an identically named rule then the extending FormatConfiguration must declare formatting if the parent FormatConfiguration does. - * - * @param model - * the model - */ - @Check - def void checkRequiredRulesImplemented(FormatConfiguration model) { - val extendedModel = model.getExtendedFormatConfiguration(); - if (extendedModel === null || extendedModel.eIsProxy() || model.getTargetGrammar() == extendedModel.getTargetGrammar()) {// NOPMD - return - } - val inheritedRules = Iterables.filter(collectRules(extendedModel), GrammarRule); - val ruleNames = Sets.newHashSet(Iterables.transform(inheritedRules, new Function() { - override apply(GrammarRule from) { - return from.getTargetRule().getName() - } - })) - for (GrammarRule rule : Iterables.filter(model.getRules(), GrammarRule)) { - if (rule.getTargetRule() !== null && !rule.getTargetRule().eIsProxy()) { - ruleNames.remove(rule.getTargetRule().getName()) - } - } - for (AbstractRule rule : model.getTargetGrammar().getRules()) { - if (ruleNames.contains(rule.getName())) { - error(NLS.bind("Required formatting for rule \"{0}\" missing", rule.getName()), FormatPackage::Literals::FORMAT_CONFIGURATION__TARGET_GRAMMAR, GRAMMAR_RULE_MISSING_CODE, rule.getName()) - } - } - } - - /** - * Check that referenced value is of integer type. - * - * @param value - * the value - */ - @Check - def void checkIntValueConstantReference(IntValue value) { - if (value.getReference() === null || value.getReference().eIsProxy()) { - return - } - if (value.getReference().getIntValue() === null) { - error(NLS.bind("Referenced const \"{0}\" is not an integer", value.getReference().getName()), FormatPackage::Literals::INT_VALUE__REFERENCE) - } - } - - /** - * Check that referenced value is of string type. - * - * @param value - * the value - */ - @Check - def void checkStringValueConstantReference(StringValue value) { - if (value.getReference() === null || value.getReference().eIsProxy()) { - return - } - if (value.getReference().getIntValue() === null) { - error(NLS.bind("Referenced const \"{0}\" is not a string", value.getReference().getName()), FormatPackage::Literals::STRING_VALUE__REFERENCE) - } - } - - /** - * Check that value is consistent with the (optional) declared type. - * - * @param value - * the value - */ - @Check - def void checkConstantOptionalType(Constant value) { - if (value.isIntType() && value.getIntValue() === null) { - error("Value is not an integer", FormatPackage::Literals::CONSTANT__NAME) - } else if (value.isStringType() && value.getStringValue() === null) { - error("Value is not a string", FormatPackage::Literals::CONSTANT__NAME) - } - } - - /** - * Collect all rules contained by the given model (including any of its extended configurations). - * - * @param model - * the model - * @return all rules - */ - private def Iterable collectRules(FormatConfiguration model) { - var Iterable result = model.getRules() - val extendedModel = model.getExtendedFormatConfiguration() - if (extendedModel !== null && !extendedModel.eIsProxy()) { - result = Iterables.concat(result, collectRules(extendedModel)) - } - return result; - } - - /** - * Verify that there are exactly two grammar elements used in the containing directive if the type of the matcher equals the given MatcherType. - * - * @param matcher - * the Matcher - * @param matcherType - * the MatcherType - */ - private def void checkTwoArgumentMatcherType(Matcher matcher, MatcherType matcherType) { - if (matcher.getType() == matcherType) { - val directive = EcoreUtil2.getContainerOfType(matcher, SpecificDirective) - if (directive === null || directive.getGrammarElements().size() != 2) { - error(NLS.bind("\"{0}\" may only be used with exactly two elements", matcherType.getName()), FormatPackage::Literals::MATCHER__TYPE) - } - } - } - - /** - * Collects all GramarElementReferences, GrammarElementLookups and KeywordPairs contained by a GrammarRule. - * - * @param rule - * the grammar rule - * @return Iterator with all grammar element accessors - */ - private def static Iterator collectGrammarElementAccessors(GrammarRule rule) { - return Iterators.filter(rule.eAllContents(), new Predicate() { - override apply(EObject input) { - return input instanceof KeywordPair || input instanceof GrammarElementReference || input instanceof GrammarElementLookup - } - }) - } - -} diff --git a/docs/xtend-migration.md b/docs/xtend-migration.md index 49b7b68580..a9436887d6 100644 --- a/docs/xtend-migration.md +++ b/docs/xtend-migration.md @@ -12,10 +12,10 @@ | Metric | Value | |--------|-------| | Total Xtend source files | 94 | -| Already migrated (Batch 1–6) | 68 | -| Remaining | 26 | -| Total remaining lines | ~7,360 | -| Modules with remaining Xtend | 8 | +| Already migrated (Batch 1–7) | 74 | +| Remaining | 20 | +| Total remaining lines | ~5,513 | +| Modules with remaining Xtend | 5 | --- @@ -36,8 +36,8 @@ | `xtext.export` | 9 | 1,027 | **DONE** (Batch 5) | | `xtext.export.generator` | 1 | 86 | **DONE** (Batch 4) | | `xtext.expression` | 5 | 679 | **DONE** (Batch 2, 6) | -| `xtext.format` | 6 | 1,623 | 1 done (Batch 2), 5 pending | -| `xtext.format.generator` | 1 | 239 | Pending | +| `xtext.format` | 6 | 1,623 | **DONE** (Batch 2, 7) | +| `xtext.format.generator` | 1 | 239 | **DONE** (Batch 7) | | `xtext.format.ide` | 2 | 31 | **DONE** (Batch 2) | | `xtext.format.test` | 1 | 40 | **DONE** (Batch 3) | | `xtext.format.ui` | 1 | 47 | **DONE** (Batch 2) | @@ -213,21 +213,19 @@ Code generators with templates and some dispatch methods. --- -## Batch 7 — `xtext.format` module (10 files, 1,980 lines) +## Batch 7 — `xtext.format` module (6 files, 1,847 lines) — DONE Includes the largest file in the project. Heavy use of dispatch, templates, create methods. -### `xtext.format` (4 files) -- [ ] `FormatRuntimeModule.xtend` (115 lines) — Medium — extension, override -- [ ] `FormatGenerator.xtend` (93 lines) — Medium — **dispatch**, templates, extension, typeof, @Inject, override -- [ ] `FormatScopeProvider.xtend` (258 lines) — Hard — **dispatch**, typeof, ===, !==, create -- [ ] `FormatValidator.xtend` (376 lines) — Hard — ===, !==, override -- [ ] **`FormatJvmModelInferrer.xtend` (766 lines) — Very Hard** — dispatch, templates, extension, typeof, ===, !==, ?., #[, switch, create +### `xtext.format` (5 files) +- [x] `FormatRuntimeModule.xtend` (115 lines) — Medium — extension, override +- [x] `FormatGenerator.xtend` (93 lines) — Medium — **dispatch**, templates, extension, typeof, @Inject, override +- [x] `FormatScopeProvider.xtend` (258 lines) — Hard — **dispatch**, typeof, ===, !==, create +- [x] `FormatValidator.xtend` (376 lines) — Hard — ===, !==, override +- [x] **`FormatJvmModelInferrer.xtend` (766 lines) — Very Hard** — dispatch, templates, extension, typeof, ===, !==, ?., #[, switch, create ### `xtext.format.generator` (1 file) -- [ ] `FormatFragment2.xtend` (239 lines) — Hard — templates, extension, typeof, !==, ?., @Inject, override - -### Remaining test/ui files (already covered in other batches) +- [x] `FormatFragment2.xtend` (239 lines) — Hard — templates, extension, typeof, !==, ?., @Inject, override --- From 7d6afadeadb1c5bd08441fddcc591c2c926334ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 28 Feb 2026 22:42:34 +0100 Subject: [PATCH 09/23] feat: migrate Batch 8 Xtend files to Java 21 (17 files) Co-Authored-By: Claude Opus 4.6 --- .../test/XbaseGeneratorFragmentTest.java | 211 +++ .../test/XbaseGeneratorFragmentTest.xtend | 200 --- .../DefaultFragmentWithOverride.java | 87 ++ .../DefaultFragmentWithOverride.xtend | 54 - .../builder/BuilderIntegrationFragment2.java | 73 + .../builder/BuilderIntegrationFragment2.xtend | 60 - .../LspBuilderIntegrationFragment2.java | 213 +++ .../LspBuilderIntegrationFragment2.xtend | 174 --- ...StandaloneBuilderIntegrationFragment2.java | 204 +++ ...tandaloneBuilderIntegrationFragment2.xtend | 165 -- .../formatting/FormatterFragment2.java | 217 +++ .../formatting/FormatterFragment2.xtend | 147 -- .../LanguageConstantsFragment2.java | 199 +++ .../LanguageConstantsFragment2.xtend | 144 -- .../ModelInferenceFragment2.java | 48 + .../ModelInferenceFragment2.xtend | 49 - ...tAnnotationAwareAntlrGrammarGenerator.java | 267 ++++ ...AnnotationAwareAntlrGrammarGenerator.xtend | 159 -- ...areAntlrContentAssistGrammarGenerator.java | 1386 +++++++++++++++++ ...reAntlrContentAssistGrammarGenerator.xtend | 489 ------ .../AnnotationAwareAntlrGrammarGenerator.java | 1260 +++++++++++++++ ...AnnotationAwareAntlrGrammarGenerator.xtend | 544 ------- ...tionAwareXtextAntlrGeneratorFragment2.java | 1062 +++++++++++++ ...ionAwareXtextAntlrGeneratorFragment2.xtend | 530 ------- .../parser/common/GrammarRuleAnnotations.java | 767 +++++++++ .../common/GrammarRuleAnnotations.xtend | 406 ----- ...atesNaming.xtend => PredicatesNaming.java} | 23 +- .../ResourceFactoryFragment2.java | 103 ++ .../ResourceFactoryFragment2.xtend | 77 - .../ui/compare/CompareFragment2.java | 99 ++ .../ui/compare/CompareFragment2.xtend | 99 -- ...AnnotationAwareContentAssistFragment2.java | 381 +++++ ...nnotationAwareContentAssistFragment2.xtend | 226 --- docs/xtend-migration.md | 57 +- 34 files changed, 6617 insertions(+), 3563 deletions(-) create mode 100644 com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/modelinference/ModelInferenceFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/modelinference/ModelInferenceFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.xtend rename com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/{PredicatesNaming.xtend => PredicatesNaming.java} (54%) create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.xtend create mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.java delete mode 100644 com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.xtend diff --git a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java new file mode 100644 index 0000000000..a1a62f8cf9 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.xbase.test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.Iterator; + +import com.avaloq.tools.ddk.test.core.jupiter.BugTest; +import com.avaloq.tools.ddk.test.core.jupiter.BugTestAwareRule; +import org.eclipse.emf.common.util.BasicEList; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.xtext.AbstractElement; +import org.eclipse.xtext.AbstractMetamodelDeclaration; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.Assignment; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.Group; +import org.eclipse.xtext.ParserRule; +import org.eclipse.xtext.RuleCall; +import org.eclipse.xtext.TypeRef; +import org.eclipse.xtext.XtextPackage; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.xbase.lib.Pair; +import org.eclipse.xtext.xtext.generator.xbase.XbaseUsageDetector; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; + +/** + * Tests for {@link XbaseUsageDetector}. + */ +@ExtendWith(InjectionExtension.class) +public class XbaseGeneratorFragmentTest { + + @RegisterExtension + public BugTestAwareRule bugTestRule = BugTestAwareRule.getInstance(); + + private final String thisPackageName = "thisPackage"; + private final String xtypePackageName = "xtype"; + private final String xImportSectionRuleName = "XImportSection"; + + private final XbaseUsageDetector detector = new XbaseUsageDetector(); + + /** + * Set expectations prior to calling usesXImportSection.apply(). + * + * @param mockRule Mock Rule, in which to set expectations. + * @param packageName Package name to use. + * @param ruleName Rule name to use. + */ + @SuppressWarnings("unchecked") + private void setExpectationsForApply(final ParserRule mockRule, final String packageName, final String ruleName) { + final TypeRef mockType = mock(TypeRef.class); + final AbstractMetamodelDeclaration mockMetamodel = mock(AbstractMetamodelDeclaration.class); + final EPackage mockEPackage = mock(EPackage.class); + + when(mockRule.getName()).thenReturn(ruleName); + + when(mockRule.getType()).thenReturn(mockType); + when(mockType.getMetamodel()).thenReturn(mockMetamodel); + when(mockMetamodel.getEPackage()).thenReturn(mockEPackage); + when(mockEPackage.getName()).thenReturn(packageName); + } + + /** + * Set expectations prior to calling usesXImportSection(). + * + * @param mockGrammar Mock Grammar, in which to set expectations. + * @param packageAndRuleNamesOfLeafRules Package and rule names to use for leaf rules. + */ + @SafeVarargs + @SuppressWarnings("unchecked") + private void setExpectationsForUsesXImportSection(final Grammar mockGrammar, final Pair... packageAndRuleNamesOfLeafRules) { + final ParserRule mockRootRule = mock(ParserRule.class); + final Group mockAlternatives = mock(Group.class); + final BasicEList mockElements = new BasicEList(); + + final BasicEList mockLeafRules = new BasicEList(); + for (final Pair pair : packageAndRuleNamesOfLeafRules) { + mockLeafRules.add(mock(ParserRule.class)); + } + + final BasicEList mockRules = new BasicEList(); + mockRules.add(mockRootRule); + mockRules.addAll(mockLeafRules); + + // Calls made by UsedRulesFinder.compute() + when(mockGrammar.getRules()).thenReturn(mockRules); + + // Calls made by doSwitch(firstRule) + when(mockRootRule.eClass()).thenReturn(XtextPackage.Literals.PARSER_RULE); + when(mockRootRule.getAlternatives()).thenReturn(mockAlternatives); + + when(mockAlternatives.eClass()).thenReturn(XtextPackage.Literals.GROUP); + when(mockAlternatives.getElements()).thenReturn(mockElements); + + // Calls made per leaf rule by doSwitch(firstRule) + for (final ParserRule mockLeafRule : mockLeafRules) { + final Assignment mockAssignment = mock(Assignment.class); + final RuleCall mockTerminal = mock(RuleCall.class); + mockElements.add(mockAssignment); + + when(mockAssignment.eClass()).thenReturn(XtextPackage.Literals.ASSIGNMENT); + when(mockAssignment.getTerminal()).thenReturn(mockTerminal); + + when(mockTerminal.eClass()).thenReturn(XtextPackage.Literals.RULE_CALL); + when(mockTerminal.getRule()).thenReturn(mockLeafRule); + + when(mockLeafRule.eClass()).thenReturn(XtextPackage.Literals.PARSER_RULE); + when(mockLeafRule.getAlternatives()).thenReturn(null); + when(mockLeafRule.isDefinesHiddenTokens()).thenReturn(false); + } + + // Calls made by doSwitch(grammar) + when(mockGrammar.eClass()).thenReturn(XtextPackage.Literals.GRAMMAR); + when(mockGrammar.isDefinesHiddenTokens()).thenReturn(false); + when(mockGrammar.getUsedGrammars()).thenReturn(new BasicEList()); + + // Calls made per rule by XbaseGeneratorFragmentOverride.usesXImportSection.apply() + setExpectationsForApply(mockRootRule, thisPackageName, "rootRule"); + + Iterator mockLeafRuleIterator = mockLeafRules.iterator(); + Iterator> packageAndRuleNameIterator = Arrays.asList(packageAndRuleNamesOfLeafRules).iterator(); + while (mockLeafRuleIterator.hasNext()) { + final ParserRule mockLeafRule = mockLeafRuleIterator.next(); + final Pair packageandRuleName = packageAndRuleNameIterator.next(); + + final String packageName = packageandRuleName.getKey(); + final String ruleName = packageandRuleName.getValue(); + + setExpectationsForApply(mockLeafRule, packageName, ruleName); + } + } + + /** + * Test usesXImportSection() when passed a null XtextResource + */ + @Test + public void testUsesXImportSectionWithNullGrammar() { + assertThrows(NullPointerException.class, () -> detector.usesXImportSection(null)); + } + + /** + * Test usesXImportSection() when the grammar does not use xtype::XImportSection(). + */ + @Test + @BugTest(value = "DSL-244") + public void testUsesXImportSectionWhenNotUsed() { + // ARRANGE + final Grammar mockGrammar = mock(Grammar.class); + + // Use a selection of rules which do not include xtype::XImportSection + setExpectationsForUsesXImportSection( + mockGrammar, + Pair.of(null, "leafRule1"), + Pair.of(thisPackageName, "leafRule2"), + Pair.of(xtypePackageName, "leafRule3"), + Pair.of(null, xImportSectionRuleName), + Pair.of(thisPackageName, xImportSectionRuleName) + ); + + // ACT + final boolean usesXImportSection = detector.usesXImportSection(mockGrammar); + + // ASSERT + assertFalse(usesXImportSection, "usesXImportSection() should return false when the grammar does not use XImportSection"); + } + + /** + * Test usesXImportSection() when the grammar uses xtype::XImportSection(). + */ + @Test + @BugTest(value = "DSL-244") + public void testUsesXImportSectionWhenUsed() { + // ARRANGE + final Grammar mockGrammar = mock(Grammar.class); + + // Use a selection of rules including xtype::XImportSection + setExpectationsForUsesXImportSection( + mockGrammar, + Pair.of(null, "leafRule1"), + Pair.of(thisPackageName, "leafRule2"), + Pair.of(xtypePackageName, "leafRule3"), + Pair.of(null, xImportSectionRuleName), + Pair.of(thisPackageName, xImportSectionRuleName), + Pair.of(xtypePackageName, xImportSectionRuleName) + ); + + // ACT + final boolean usesXImportSection = detector.usesXImportSection(mockGrammar); + + // ASSERT + assertTrue(usesXImportSection, "usesXImportSection() should return true when the grammar uses XImportSection"); + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.xtend b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.xtend deleted file mode 100644 index 1aed804f45..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.xtend +++ /dev/null @@ -1,200 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.xbase.test - -import com.avaloq.tools.ddk.test.core.jupiter.BugTest -import org.eclipse.emf.common.util.BasicEList -import org.eclipse.emf.ecore.EPackage -import org.eclipse.xtext.AbstractElement -import org.eclipse.xtext.AbstractMetamodelDeclaration -import org.eclipse.xtext.AbstractRule -import org.eclipse.xtext.Assignment -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.Group -import org.eclipse.xtext.ParserRule -import org.eclipse.xtext.RuleCall -import org.eclipse.xtext.TypeRef -import org.eclipse.xtext.XtextPackage - -import static org.mockito.Mockito.mock -import static org.mockito.Mockito.when -import org.eclipse.xtext.xtext.generator.xbase.XbaseUsageDetector -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.assertFalse -import static org.junit.jupiter.api.Assertions.assertThrows -import static org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.^extension.RegisterExtension -import com.avaloq.tools.ddk.test.core.jupiter.BugTestAwareRule - -/** - * Tests for {@link XbaseUsageDetector}. - */ -@ExtendWith(InjectionExtension) -class XbaseGeneratorFragmentTest { - - @RegisterExtension - public BugTestAwareRule bugTestRule = BugTestAwareRule.getInstance(); - - val thisPackageName = "thisPackage" - val xtypePackageName = "xtype" - val xImportSectionRuleName = "XImportSection" - - val detector = new XbaseUsageDetector - - /** - * Set expectations prior to calling usesXImportSection.apply(). - * - * @param mockRule Mock Rule, in which to set expectations. - * @param packageName Package name to use. - * @param ruleName Rule name to use. - */ - private def setExpectationsForApply(ParserRule mockRule, String packageName, String ruleName) { - val mockType = mock(TypeRef) - val mockMetamodel = mock(AbstractMetamodelDeclaration) - val mockEPackage = mock(EPackage) - - when(mockRule.name).thenReturn(ruleName) - - when(mockRule.type).thenReturn(mockType) - when(mockType.metamodel).thenReturn(mockMetamodel) - when(mockMetamodel.EPackage).thenReturn(mockEPackage) - when(mockEPackage.name).thenReturn(packageName) - } - - /** - * Set expectations prior to calling usesXImportSection(). - * - * @param mockGrammar Mock Grammar, in which to set expectations. - * @param packageAndRuleNamesOfLeafRules Package and rule names to use for leaf rules. - */ - private def setExpectationsForUsesXImportSection(Grammar mockGrammar, Pair... packageAndRuleNamesOfLeafRules) { - val mockRootRule = mock(ParserRule) - val mockAlternatives = mock(Group) - val mockElements = new BasicEList - - val mockLeafRules = new BasicEList - packageAndRuleNamesOfLeafRules.forEach[mockLeafRules.add(mock(ParserRule))] - - val mockRules = new BasicEList() - mockRules.add(mockRootRule) - mockRules.addAll(mockLeafRules) - - // Calls made by UsedRulesFinder.compute() - when(mockGrammar.rules).thenReturn(mockRules); - - // Calls made by doSwitch(firstRule) - when(mockRootRule.eClass).thenReturn(XtextPackage.Literals.PARSER_RULE) - when(mockRootRule.alternatives).thenReturn(mockAlternatives) - - when(mockAlternatives.eClass).thenReturn(XtextPackage.Literals.GROUP) - when(mockAlternatives.elements).thenReturn(mockElements) - - // Calls made per leaf rule by doSwitch(firstRule) - mockLeafRules.forEach[mockLeafRule | - val mockAssignment = mock(Assignment) - val mockTerminal = mock(RuleCall) - mockElements.add(mockAssignment) - - when(mockAssignment.eClass).thenReturn(XtextPackage.Literals.ASSIGNMENT) - when(mockAssignment.terminal).thenReturn(mockTerminal) - - when(mockTerminal.eClass).thenReturn(XtextPackage.Literals.RULE_CALL) - when(mockTerminal.rule).thenReturn(mockLeafRule) - - when(mockLeafRule.eClass).thenReturn(XtextPackage.Literals.PARSER_RULE) - when(mockLeafRule.alternatives).thenReturn(null) - when(mockLeafRule.definesHiddenTokens).thenReturn(false) - ] - - // Calls made by doSwitch(grammar) - when(mockGrammar.eClass).thenReturn(XtextPackage.Literals.GRAMMAR) - when(mockGrammar.definesHiddenTokens).thenReturn(false) - when(mockGrammar.usedGrammars).thenReturn(new BasicEList) - - // Calls made per rule by XbaseGeneratorFragmentOverride.usesXImportSection.apply() - mockRootRule.setExpectationsForApply(thisPackageName, "rootRule") - - val mockLeafRuleIterator = mockLeafRules.iterator - val packageAndRuleNameIterator = packageAndRuleNamesOfLeafRules.iterator - while (mockLeafRuleIterator.hasNext) { - val mockLeafRule = mockLeafRuleIterator.next - val packageandRuleName = packageAndRuleNameIterator.next - - val packageName = packageandRuleName.key - val ruleName = packageandRuleName.value - - mockLeafRule.setExpectationsForApply(packageName, ruleName) - } - } - - /** - * Test usesXImportSection() when passed a null XtextResource - */ - @Test - def void testUsesXImportSectionWithNullGrammar() { - assertThrows(NullPointerException, [|detector.usesXImportSection(null)]); - } - - /** - * Test usesXImportSection() when the grammar does not use xtype::XImportSection(). - */ - @Test - @BugTest(value = "DSL-244") - def void testUsesXImportSectionWhenNotUsed() { - // ARRANGE - val mockGrammar = mock(Grammar) - - // Use a selection of rules which do not include xtype::XImportSection - mockGrammar.setExpectationsForUsesXImportSection( - null -> "leafRule1", - thisPackageName -> "leafRule2", - xtypePackageName -> "leafRule3", - null -> xImportSectionRuleName, - thisPackageName -> xImportSectionRuleName - ) - - // ACT - val usesXImportSection = detector.usesXImportSection(mockGrammar) - - // ASSERT - assertFalse(usesXImportSection, "usesXImportSection() should return false when the grammar does not use XImportSection") - } - - /** - * Test usesXImportSection() when the grammar uses xtype::XImportSection(). - */ - @Test - @BugTest(value = "DSL-244") - def void testUsesXImportSectionWhenUsed() { - // ARRANGE - val mockGrammar = mock(Grammar) - - // Use a selection of rules including xtype::XImportSection - mockGrammar.setExpectationsForUsesXImportSection( - null -> "leafRule1", - thisPackageName -> "leafRule2", - xtypePackageName -> "leafRule3", - null -> xImportSectionRuleName, - thisPackageName -> xImportSectionRuleName, - xtypePackageName -> xImportSectionRuleName - ) - - // ACT - val usesXImportSection = detector.usesXImportSection(mockGrammar) - - // ASSERT - assertTrue(usesXImportSection, "usesXImportSection() should return true when the grammar uses XImportSection") - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.java new file mode 100644 index 0000000000..4a83b1a1f9 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator; + +import com.google.inject.Injector; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.IXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.Issues; + +/** + * Allow different fragments to be generated depending on a condition + * + * By default we generate the defaultFragment (or nothing if it is null) + * if useOverride is true, we generate the overrideFragment (or nothing if it is null) + * + */ +public class DefaultFragmentWithOverride extends AbstractXtextGeneratorFragment { + + /** + * Whether to use the override fragment. False by default + */ + private boolean useOverride = false; + + private IXtextGeneratorFragment defaultFragment; + + private IXtextGeneratorFragment overrideFragment; + + public boolean isUseOverride() { + return useOverride; + } + + public void setUseOverride(final boolean useOverride) { + this.useOverride = useOverride; + } + + public IXtextGeneratorFragment getDefaultFragment() { + return defaultFragment; + } + + public void setDefaultFragment(final IXtextGeneratorFragment defaultFragment) { + this.defaultFragment = defaultFragment; + } + + public IXtextGeneratorFragment getOverrideFragment() { + return overrideFragment; + } + + public void setOverrideFragment(final IXtextGeneratorFragment overrideFragment) { + this.overrideFragment = overrideFragment; + } + + @Override + public void generate() { + IXtextGeneratorFragment fragment = useOverride ? overrideFragment : defaultFragment; + if (fragment != null) { + fragment.generate(); + } + } + + @Override + public void initialize(final Injector injector) { + super.initialize(injector); + if (overrideFragment != null) { + overrideFragment.initialize(injector); + } + if (defaultFragment != null) { + defaultFragment.initialize(injector); + } + } + + @Override + public void checkConfiguration(final Issues issues) { + overrideFragment.checkConfiguration(issues); + defaultFragment.checkConfiguration(issues); + } + +} +/* Copyright (c) Avaloq Group AG */ diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.xtend deleted file mode 100644 index 01099bed21..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.xtend +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator - -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtend.lib.annotations.Accessors -import org.eclipse.xtext.xtext.generator.IXtextGeneratorFragment -import com.google.inject.Injector -import org.eclipse.xtext.xtext.generator.Issues - -/** - * Allow different fragments to be generated depending on a condition - * - * By default we generate the defaultFragment (or nothing if it is null) - * if useOverride is true, we generate the overrideFragment (or nothing if it is null) - * - */ -class DefaultFragmentWithOverride extends AbstractXtextGeneratorFragment { - - /** - * Whether to use the override fragment. False by default - */ - @Accessors boolean useOverride = false - - @Accessors IXtextGeneratorFragment defaultFragment - - @Accessors IXtextGeneratorFragment overrideFragment - - override generate() { - (if (useOverride) overrideFragment else defaultFragment)?.generate() - } - - override initialize(Injector injector) { - super.initialize(injector) - overrideFragment?.initialize(injector) - defaultFragment?.initialize(injector) - } - - override checkConfiguration(Issues issues) { - overrideFragment.checkConfiguration(issues) - defaultFragment.checkConfiguration(issues) - } - -} -/* Copyright (c) Avaloq Group AG */ diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.java new file mode 100644 index 0000000000..d2794dc9ed --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.builder; + +import com.avaloq.tools.ddk.xtext.linking.FastLazyURIEncoder; +import com.avaloq.tools.ddk.xtext.linking.LazyLinkingResource2; +import com.google.inject.name.Names; +import org.eclipse.xtext.linking.lazy.LazyLinkingResource; +import org.eclipse.xtext.linking.lazy.LazyURIEncoder; +import org.eclipse.xtext.resource.IContainer; +import org.eclipse.xtext.resource.IResourceDescriptions; +import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtend2.lib.StringConcatenationClient; + +public class BuilderIntegrationFragment2 extends org.eclipse.xtext.xtext.generator.builder.BuilderIntegrationFragment2 { + + private static final String BUILDER_BUNDLE_NAME = "com.avaloq.tools.ddk.xtext.builder"; + + @Override + protected void addRuntimeGuiceBindings() { + super.addRuntimeGuiceBindings(); + new GuiceModuleAccess.BindingFactory() + .addTypeToType(TypeReference.typeRef(IContainer.Manager.class), new TypeReference("com.avaloq.tools.ddk.xtext.builder.CachingStateBasedContainerManager")) + .addTypeToType(TypeReference.typeRef(LazyLinkingResource.class), TypeReference.typeRef(LazyLinkingResource2.class)) + .addTypeToType(TypeReference.typeRef(LazyURIEncoder.class), TypeReference.typeRef(FastLazyURIEncoder.class)) + .contributeTo(getLanguage().getRuntimeGenModule()); + if (getProjectConfig().getRuntime().getManifest() != null) { + getProjectConfig().getRuntime().getManifest().getRequiredBundles().add(BUILDER_BUNDLE_NAME); + } + } + + @Override + protected void addEclipsePluginGuiceBindings() { + super.addEclipsePluginGuiceBindings(); + final StringConcatenationClient statement1 = new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("binder.bind("); + target.append(TypeReference.typeRef(IResourceDescriptions.class)); + target.append(".class"); + target.newLineIfNotEmpty(); + target.append(").annotatedWith("); + target.append(TypeReference.typeRef(Names.class)); + target.append(".named("); + target.append(TypeReference.typeRef(ResourceDescriptionsProvider.class)); + target.append(".NAMED_BUILDER_SCOPE)"); + target.newLineIfNotEmpty(); + target.append(").to("); + target.append(new TypeReference("com.avaloq.tools.ddk.xtext.builder", "CurrentDescriptions2.ResourceSetAware")); + target.append(".class);"); + target.newLineIfNotEmpty(); + } + }; + new GuiceModuleAccess.BindingFactory() + .addConfiguredBinding(IResourceDescriptions.class.getSimpleName() + "BuilderScope", statement1) + .contributeTo(getLanguage().getEclipsePluginGenModule()); + if (getProjectConfig().getEclipsePlugin().getManifest() != null) { + getProjectConfig().getEclipsePlugin().getManifest().getRequiredBundles().add(BUILDER_BUNDLE_NAME); + } + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.xtend deleted file mode 100644 index 1fb9a07b92..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.xtend +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.builder - -import com.google.inject.name.Names -import org.eclipse.xtext.resource.IResourceDescriptions -import com.avaloq.tools.ddk.xtext.linking.FastLazyURIEncoder -import org.eclipse.xtext.linking.lazy.LazyURIEncoder -import org.eclipse.xtext.linking.lazy.LazyLinkingResource -import org.eclipse.xtext.resource.IContainer -import com.avaloq.tools.ddk.xtext.linking.LazyLinkingResource2 -import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess - -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* -import org.eclipse.xtext.xtext.generator.model.TypeReference -import org.eclipse.xtend2.lib.StringConcatenationClient - -class BuilderIntegrationFragment2 extends org.eclipse.xtext.xtext.generator.builder.BuilderIntegrationFragment2 { - - static val BUILDER_BUNDLE_NAME = "com.avaloq.tools.ddk.xtext.builder"; - - override addRuntimeGuiceBindings() { - super.addRuntimeGuiceBindings - new GuiceModuleAccess.BindingFactory() - .addTypeToType(IContainer.Manager.typeRef, new TypeReference("com.avaloq.tools.ddk.xtext.builder.CachingStateBasedContainerManager")) - .addTypeToType(LazyLinkingResource.typeRef, LazyLinkingResource2.typeRef) - .addTypeToType(LazyURIEncoder.typeRef, FastLazyURIEncoder.typeRef) - .contributeTo(language.runtimeGenModule) - if (projectConfig.runtime.manifest !== null) { - projectConfig.runtime.manifest.requiredBundles += BUILDER_BUNDLE_NAME - } - } - - override addEclipsePluginGuiceBindings() { - super.addEclipsePluginGuiceBindings - val StringConcatenationClient statement1 = - ''' - binder.bind(«IResourceDescriptions».class - ).annotatedWith(«Names».named(«ResourceDescriptionsProvider».NAMED_BUILDER_SCOPE) - ).to(«new TypeReference('com.avaloq.tools.ddk.xtext.builder', 'CurrentDescriptions2.ResourceSetAware')».class); - ''' - new GuiceModuleAccess.BindingFactory() - .addConfiguredBinding(IResourceDescriptions.simpleName + 'BuilderScope', statement1) - .contributeTo(language.eclipsePluginGenModule) - if (projectConfig.eclipsePlugin.manifest !== null) { - projectConfig.eclipsePlugin.manifest.requiredBundles += BUILDER_BUNDLE_NAME - } - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java new file mode 100644 index 0000000000..97b04e9700 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.builder; + +import java.util.List; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.osgi.util.NLS; +import org.eclipse.xtext.AbstractMetamodelDeclaration; +import org.eclipse.xtext.GeneratedMetamodel; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; +import org.eclipse.xtext.xtext.generator.model.FileAccessFactory; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtend2.lib.StringConcatenationClient; + +import com.google.inject.Inject; + + +public class LspBuilderIntegrationFragment2 extends AbstractXtextGeneratorFragment { + + private static final Logger LOGGER = LogManager.getLogger(LspBuilderIntegrationFragment2.class); + + @Inject + private FileAccessFactory fileAccessFactory; + + @Inject + private XtextGeneratorNaming packageNaming; + + private TypeReference createSuffixedTypeReference(String suffix) { + return new TypeReference( + packageNaming.getGenericIdeBasePackage(getGrammar()), GrammarUtil.getSimpleName(getGrammar()) + suffix + ); + } + + protected TypeReference getLspBuildSetupGeneratedClass() { + return createSuffixedTypeReference("LspBuildSetupGenerated"); + } + + protected TypeReference getLspBuildSetupServiceClass() { + return createSuffixedTypeReference("LspBuildSetupService"); + } + + @Override + public void generate() { + if (getProjectConfig().getGenericIde().isEnabled()) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(NLS.bind("executing generate for {0}", getClass().getName())); + } + generateServiceRegistration(); + generateBuildService(); + generateBuildSetup(); + } + } + + public void generateServiceRegistration() { + StringBuilder sb = new StringBuilder(); + sb.append(getLspBuildSetupServiceClass().getName()); + sb.append("\n"); + fileAccessFactory.createTextFile("META-INF/services/com.avaloq.tools.ddk.xtext.build.ILspLanguageSetup", + toClient(sb)).writeTo(getProjectConfig().getGenericIde().getSrcGen()); + } + + public void generateBuildService() { + Grammar grammar = getGrammar(); + TypeReference lspBuildSetupServiceClass = getLspBuildSetupServiceClass(); + StringBuilder sb = new StringBuilder(); + sb.append("import java.util.List;\n"); + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.xtext.build.AbstractDynamicSetupService;\n"); + sb.append("import com.avaloq.tools.ddk.xtext.build.ILspLanguageSetup;\n"); + sb.append("import com.google.common.collect.ImmutableList;\n"); + sb.append("import com.google.inject.Injector;\n"); + sb.append("import com.google.inject.Module;\n"); + sb.append("\n"); + sb.append("/**\n"); + sb.append(" * Generated by com.avaloq.tools.ddk.xtext.generator.builder.LspBuilderIntegrationFragment2.\n"); + sb.append(" */\n"); + sb.append("public class ").append(lspBuildSetupServiceClass.getSimpleName()).append(" extends AbstractDynamicSetupService implements ILspLanguageSetup {\n"); + sb.append("\n"); + sb.append(" @SuppressWarnings(\"nls\")\n"); + sb.append(" private static final String GRAMMAR = \"").append(grammar.getName()).append("\";\n"); + sb.append(" @SuppressWarnings(\"nls\")\n"); + sb.append(" private static final List PARENTS = ImmutableList.of(//\n"); + List allUsedGrammars = GrammarUtil.allUsedGrammars(grammar); + for (int i = 0; i < allUsedGrammars.size(); i++) { + Grammar g = allUsedGrammars.get(i); + sb.append(" \"").append(g.getName()).append("\" //"); + if (i < allUsedGrammars.size() - 1) { + sb.append(","); + } + sb.append("\n"); + } + sb.append(" );\n"); + sb.append("\n"); + sb.append(" public Injector doSetup(Module overrideModule, Module... additionalModules) {\n"); + sb.append(" return new ").append(GrammarUtil.getSimpleName(grammar)).append("LspBuildSetupGenerated(SETUP_LOCK, overrideModule, additionalModules).createInjectorAndDoEMFRegistration();\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public List getParentLanguages() {\n"); + sb.append(" return PARENTS;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public String getLanguageName() {\n"); + sb.append(" return GRAMMAR;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append("}\n"); + fileAccessFactory.createJavaFile(lspBuildSetupServiceClass, + toClient(sb)).writeTo(getProjectConfig().getGenericIde().getSrcGen()); + } + + public void generateBuildSetup() { + Grammar grammar = getGrammar(); + TypeReference lspBuildSetupGeneratedClass = getLspBuildSetupGeneratedClass(); + StringBuilder sb = new StringBuilder(); + sb.append("import org.eclipse.xtext.util.Modules2;\n"); + sb.append("\n"); + sb.append("import com.google.common.collect.ImmutableList;\n"); + sb.append("import com.google.inject.Guice;\n"); + sb.append("import com.google.inject.Injector;\n"); + sb.append("import com.google.inject.Module;\n"); + sb.append("import com.google.inject.util.Modules;\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("/**\n"); + sb.append(" * Generated by com.avaloq.tools.ddk.xtext.generator.builder.LspBuilderIntegrationFragment2.\n"); + sb.append(" */\n"); + sb.append("public class ").append(lspBuildSetupGeneratedClass.getSimpleName()).append(" extends ").append(packageNaming.getGenericIdeSetup(grammar)).append(" {\n"); + sb.append("\n"); + sb.append(" private final Module overrideModule;\n"); + sb.append(" private final Module[] additionalModules;\n"); + sb.append(" private final Object lock;\n"); + sb.append("\n"); + sb.append(" public ").append(lspBuildSetupGeneratedClass.getSimpleName()).append("(final Object lock, final Module overrideModule, Module... additionalModules) {\n"); + sb.append(" this.lock = lock;\n"); + sb.append(" this.overrideModule = overrideModule;\n"); + sb.append(" this.additionalModules = additionalModules;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" public ").append(lspBuildSetupGeneratedClass.getSimpleName()).append("(final Module overrideModule, Module... additionalModules) {\n"); + sb.append(" this.lock = null;\n"); + sb.append(" this.overrideModule = overrideModule;\n"); + sb.append(" this.additionalModules = additionalModules;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public Injector createInjectorAndDoEMFRegistration() {\n"); + sb.append(" registerEPackages();\n"); + sb.append(" Injector injector = createInjector();\n"); + sb.append(" if (lock != null) {\n"); + sb.append(" synchronized (lock) {\n"); + sb.append(" register(injector);\n"); + sb.append(" }\n"); + sb.append(" } else {\n"); + sb.append(" register(injector);\n"); + sb.append(" }\n"); + sb.append(" return injector;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public Injector createInjector() {\n"); + sb.append(" return Guice.createInjector(getModules());\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" protected void registerEPackages() {\n"); + for (AbstractMetamodelDeclaration decl : grammar.getMetamodelDeclarations()) { + if (decl instanceof GeneratedMetamodel) { + GeneratedMetamodel mmd = (GeneratedMetamodel) decl; + String ns = GrammarUtil.getNamespace(grammar); + String name = mmd.getName(); + String nameUpper = name.substring(0, 1).toUpperCase() + name.substring(1); + sb.append(" if (").append(ns).append(".").append(name).append(".").append(nameUpper).append("Package.eINSTANCE == null) {\n"); + sb.append(" throw new IllegalStateException(\"EPackage could not be initialized: \" + ").append(ns).append(".").append(name).append(".").append(nameUpper).append("Package.eNS_URI); //$NON-NLS-1$\n"); + sb.append(" }\n"); + } + } + sb.append(" }\n"); + sb.append("\n"); + sb.append(" protected Iterable getModules() {\n"); + sb.append(" return ImmutableList. builder().add(Modules.override(Modules2.mixin(new ").append(grammar.getName()).append("RuntimeModule(), new ").append(packageNaming.getGenericIdeModule(grammar)).append("())).with(overrideModule)).add(additionalModules).build();\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append("}\n"); + fileAccessFactory.createJavaFile(lspBuildSetupGeneratedClass, + toClient(sb)).writeTo(getProjectConfig().getGenericIde().getSrcGen()); + } + + private static StringConcatenationClient toClient(final StringBuilder sb) { + final String content = sb.toString(); + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append(content); + } + }; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.xtend deleted file mode 100644 index f9fc447e36..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.xtend +++ /dev/null @@ -1,174 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.builder - -import com.google.inject.Inject -import org.apache.logging.log4j.LogManager; -import org.eclipse.osgi.util.NLS -import org.eclipse.xtext.GeneratedMetamodel -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming -import org.eclipse.xtext.xtext.generator.model.FileAccessFactory -import org.eclipse.xtext.xtext.generator.model.TypeReference - -import static extension org.eclipse.xtext.EcoreUtil2.* -import static extension org.eclipse.xtext.GrammarUtil.* -import org.eclipse.xtext.GrammarUtil - -class LspBuilderIntegrationFragment2 extends AbstractXtextGeneratorFragment { - - static val LOGGER = LogManager.getLogger(LspBuilderIntegrationFragment2) - - @Inject FileAccessFactory fileAccessFactory - - @Inject XtextGeneratorNaming packageNaming - - def private TypeReference createSuffixedTypeReference(String suffix) { - return new TypeReference( - packageNaming.getGenericIdeBasePackage(grammar), GrammarUtil.getSimpleName(grammar) + suffix - ) - } - - def protected TypeReference getLspBuildSetupGeneratedClass() { - createSuffixedTypeReference("LspBuildSetupGenerated") - } - - def protected TypeReference getLspBuildSetupServiceClass() { - createSuffixedTypeReference("LspBuildSetupService") - } - - override generate() { - if (projectConfig.genericIde.enabled) { - if (LOGGER.isInfoEnabled()) { - LOGGER.info(NLS.bind("executing generate for {0}", getClass().getName())); - } - generateServiceRegistration - generateBuildService - generateBuildSetup - } - } - - def generateServiceRegistration() { - fileAccessFactory.createTextFile("META-INF/services/com.avaloq.tools.ddk.xtext.build.ILspLanguageSetup", ''' - «getLspBuildSetupServiceClass.name» - ''').writeTo(projectConfig.genericIde.srcGen) - } - - def generateBuildService() { - fileAccessFactory.createJavaFile(getLspBuildSetupServiceClass, ''' - import java.util.List; - - import com.avaloq.tools.ddk.xtext.build.AbstractDynamicSetupService; - import com.avaloq.tools.ddk.xtext.build.ILspLanguageSetup; - import com.google.common.collect.ImmutableList; - import com.google.inject.Injector; - import com.google.inject.Module; - - /** - * Generated by com.avaloq.tools.ddk.xtext.generator.builder.LspBuilderIntegrationFragment2. - */ - public class «lspBuildSetupServiceClass.simpleName» extends AbstractDynamicSetupService implements ILspLanguageSetup { - - @SuppressWarnings("nls") - private static final String GRAMMAR = "«grammar.name»"; - @SuppressWarnings("nls") - private static final List PARENTS = ImmutableList.of(// - «FOR g: grammar.allUsedGrammars SEPARATOR ' -,'»"«g.name»" //«ENDFOR» - ); - - public Injector doSetup(Module overrideModule, Module... additionalModules) { - return new «grammar.simpleName»LspBuildSetupGenerated(SETUP_LOCK, overrideModule, additionalModules).createInjectorAndDoEMFRegistration(); - } - - @Override - public List getParentLanguages() { - return PARENTS; - } - - @Override - public String getLanguageName() { - return GRAMMAR; - } - - } - ''').writeTo(projectConfig.genericIde.srcGen) - } - - def generateBuildSetup() { - fileAccessFactory.createJavaFile(getLspBuildSetupGeneratedClass, ''' - import org.eclipse.xtext.util.Modules2; - - import com.google.common.collect.ImmutableList; - import com.google.inject.Guice; - import com.google.inject.Injector; - import com.google.inject.Module; - import com.google.inject.util.Modules; - - - /** - * Generated by com.avaloq.tools.ddk.xtext.generator.builder.LspBuilderIntegrationFragment2. - */ - public class «lspBuildSetupGeneratedClass.simpleName» extends «packageNaming.getGenericIdeSetup(grammar)» { - - private final Module overrideModule; - private final Module[] additionalModules; - private final Object lock; - - public «lspBuildSetupGeneratedClass.simpleName»(final Object lock, final Module overrideModule, Module... additionalModules) { - this.lock = lock; - this.overrideModule = overrideModule; - this.additionalModules = additionalModules; - } - - public «lspBuildSetupGeneratedClass.simpleName»(final Module overrideModule, Module... additionalModules) { - this.lock = null; - this.overrideModule = overrideModule; - this.additionalModules = additionalModules; - } - - @Override - public Injector createInjectorAndDoEMFRegistration() { - registerEPackages(); - Injector injector = createInjector(); - if (lock != null) { - synchronized (lock) { - register(injector); - } - } else { - register(injector); - } - return injector; - } - - @Override - public Injector createInjector() { - return Guice.createInjector(getModules()); - } - - protected void registerEPackages() { - «FOR mmd: grammar.metamodelDeclarations.typeSelect(GeneratedMetamodel)» - if («grammar.namespace».«mmd.name».«mmd.name.toFirstUpper()»Package.eINSTANCE == null) { - throw new IllegalStateException("EPackage could not be initialized: " + «grammar.namespace».«mmd.name».«mmd.name.toFirstUpper()»Package.eNS_URI); //$NON-NLS-1$ - } - «ENDFOR» - } - - protected Iterable getModules() { - return ImmutableList. builder().add(Modules.override(Modules2.mixin(new «grammar.name»RuntimeModule(), new «packageNaming.getGenericIdeModule(grammar)»())).with(overrideModule)).add(additionalModules).build(); - } - - } - ''').writeTo(projectConfig.genericIde.srcGen) - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java new file mode 100644 index 0000000000..606885511d --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.builder; + +import java.util.List; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.osgi.util.NLS; +import org.eclipse.xtext.AbstractMetamodelDeclaration; +import org.eclipse.xtext.GeneratedMetamodel; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.model.FileAccessFactory; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtend2.lib.StringConcatenationClient; + +import com.google.inject.Inject; + + +public class StandaloneBuilderIntegrationFragment2 extends AbstractXtextGeneratorFragment { + + private static final Logger LOGGER = LogManager.getLogger(StandaloneBuilderIntegrationFragment2.class); + + @Inject + private FileAccessFactory fileAccessFactory; + + private TypeReference createSuffixedTypeReference(String suffix) { + return new TypeReference( + getGrammar().getName() + suffix + ); + } + + protected TypeReference getStandaloneBuildSetupGeneratedClass() { + return createSuffixedTypeReference("StandaloneBuildSetupGenerated"); + } + + protected TypeReference getStandaloneBuildSetupServiceClass() { + return createSuffixedTypeReference("StandaloneBuildSetupService"); + } + + @Override + public void generate() { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(NLS.bind("executing generate for {0}", getClass().getName())); + } + generateServiceRegistration(); + generateBuildService(); + generateBuildSetup(); + } + + public void generateServiceRegistration() { + StringBuilder sb = new StringBuilder(); + sb.append(getStandaloneBuildSetupServiceClass().getName()); + sb.append("\n"); + fileAccessFactory.createTextFile("META-INF/services/com.avaloq.tools.ddk.xtext.build.IDynamicSetupService", + toClient(sb)).writeTo(getProjectConfig().getRuntime().getSrcGen()); + } + + public void generateBuildService() { + Grammar grammar = getGrammar(); + TypeReference standaloneBuildSetupServiceClass = getStandaloneBuildSetupServiceClass(); + StringBuilder sb = new StringBuilder(); + sb.append("import java.util.List;\n"); + sb.append("\n"); + sb.append("import com.avaloq.tools.ddk.xtext.build.AbstractDynamicSetupService;\n"); + sb.append("import com.google.common.collect.ImmutableList;\n"); + sb.append("import com.google.inject.Injector;\n"); + sb.append("import com.google.inject.Module;\n"); + sb.append("\n"); + sb.append("/**\n"); + sb.append(" * Generated by com.avaloq.tools.ddk.xtext.generator.builder.StandaloneBuilderIntegrationFragment2.\n"); + sb.append(" */\n"); + sb.append("public class ").append(standaloneBuildSetupServiceClass.getSimpleName()).append(" extends AbstractDynamicSetupService {\n"); + sb.append("\n"); + sb.append(" @SuppressWarnings(\"nls\")\n"); + sb.append(" private static final String GRAMMAR = \"").append(grammar.getName()).append("\";\n"); + sb.append(" @SuppressWarnings(\"nls\")\n"); + sb.append(" private static final List PARENTS = ImmutableList.of(//\n"); + List allUsedGrammars = GrammarUtil.allUsedGrammars(grammar); + for (int i = 0; i < allUsedGrammars.size(); i++) { + Grammar g = allUsedGrammars.get(i); + sb.append(" \"").append(g.getName()).append("\" //"); + if (i < allUsedGrammars.size() - 1) { + sb.append(","); + } + sb.append("\n"); + } + sb.append(" );\n"); + sb.append("\n"); + sb.append(" public Injector doSetup(Module overrideModule, Module... additionalModules) {\n"); + sb.append(" return new ").append(GrammarUtil.getSimpleName(grammar)).append("StandaloneBuildSetupGenerated(SETUP_LOCK, overrideModule, additionalModules).createInjectorAndDoEMFRegistration();\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public List getParentLanguages() {\n"); + sb.append(" return PARENTS;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public String getLanguageName() {\n"); + sb.append(" return GRAMMAR;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append("}\n"); + fileAccessFactory.createJavaFile(standaloneBuildSetupServiceClass, + toClient(sb)).writeTo(getProjectConfig().getRuntime().getSrcGen()); + } + + public void generateBuildSetup() { + Grammar grammar = getGrammar(); + TypeReference standaloneBuildSetupGeneratedClass = getStandaloneBuildSetupGeneratedClass(); + StringBuilder sb = new StringBuilder(); + sb.append("import com.google.common.collect.ImmutableList;\n"); + sb.append("import com.google.inject.Guice;\n"); + sb.append("import com.google.inject.Injector;\n"); + sb.append("import com.google.inject.Module;\n"); + sb.append("import com.google.inject.util.Modules;\n"); + sb.append("\n"); + sb.append("\n"); + sb.append("/**\n"); + sb.append(" * Generated by com.avaloq.tools.ddk.xtext.generator.builder.StandaloneBuilderIntegrationFragment2.\n"); + sb.append(" */\n"); + sb.append("public class ").append(standaloneBuildSetupGeneratedClass.getSimpleName()).append(" extends ").append(GrammarUtil.getSimpleName(grammar)).append("StandaloneSetup {\n"); + sb.append("\n"); + sb.append(" private final Module overrideModule;\n"); + sb.append(" private final Module[] additionalModules;\n"); + sb.append(" private final Object lock;\n"); + sb.append("\n"); + sb.append(" public ").append(standaloneBuildSetupGeneratedClass.getSimpleName()).append("(final Object lock, final Module overrideModule, Module... additionalModules) {\n"); + sb.append(" this.lock = lock;\n"); + sb.append(" this.overrideModule = overrideModule;\n"); + sb.append(" this.additionalModules = additionalModules;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" public ").append(standaloneBuildSetupGeneratedClass.getSimpleName()).append("(final Module overrideModule, Module... additionalModules) {\n"); + sb.append(" this.lock = null;\n"); + sb.append(" this.overrideModule = overrideModule;\n"); + sb.append(" this.additionalModules = additionalModules;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public Injector createInjectorAndDoEMFRegistration() {\n"); + sb.append(" registerEPackages();\n"); + sb.append(" Injector injector = createInjector();\n"); + sb.append(" if (lock != null) {\n"); + sb.append(" synchronized (lock) {\n"); + sb.append(" register(injector);\n"); + sb.append(" }\n"); + sb.append(" } else {\n"); + sb.append(" register(injector);\n"); + sb.append(" }\n"); + sb.append(" return injector;\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" @Override\n"); + sb.append(" public Injector createInjector() {\n"); + sb.append(" return Guice.createInjector(getModules());\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append(" protected void registerEPackages() {\n"); + for (AbstractMetamodelDeclaration decl : grammar.getMetamodelDeclarations()) { + if (decl instanceof GeneratedMetamodel) { + GeneratedMetamodel mmd = (GeneratedMetamodel) decl; + String ns = GrammarUtil.getNamespace(grammar); + String name = mmd.getName(); + String nameUpper = name.substring(0, 1).toUpperCase() + name.substring(1); + sb.append(" if (").append(ns).append(".").append(name).append(".").append(nameUpper).append("Package.eINSTANCE == null) {\n"); + sb.append(" throw new IllegalStateException(\"EPackage could not be initialized: \" + ").append(ns).append(".").append(name).append(".").append(nameUpper).append("Package.eNS_URI); //$NON-NLS-1$\n"); + sb.append(" }\n"); + } + } + sb.append(" }\n"); + sb.append("\n"); + sb.append(" protected Iterable getModules() {\n"); + sb.append(" return ImmutableList. builder().add(Modules.override(new ").append(grammar.getName()).append("RuntimeModule()).with(overrideModule)).add(additionalModules).build();\n"); + sb.append(" }\n"); + sb.append("\n"); + sb.append("}\n"); + fileAccessFactory.createJavaFile(standaloneBuildSetupGeneratedClass, + toClient(sb)).writeTo(getProjectConfig().getRuntime().getSrcGen()); + } + + private static StringConcatenationClient toClient(final StringBuilder sb) { + final String content = sb.toString(); + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append(content); + } + }; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.xtend deleted file mode 100644 index f7813972a1..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.xtend +++ /dev/null @@ -1,165 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.builder - -import org.apache.logging.log4j.LogManager; -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.osgi.util.NLS -import org.eclipse.xtext.xtext.generator.model.FileAccessFactory -import com.google.inject.Inject - -import static extension org.eclipse.xtext.GrammarUtil.* -import static extension org.eclipse.xtext.EcoreUtil2.* -import org.eclipse.xtext.xtext.generator.model.TypeReference -import org.eclipse.xtext.GeneratedMetamodel - -class StandaloneBuilderIntegrationFragment2 extends AbstractXtextGeneratorFragment { - - static val LOGGER = LogManager.getLogger(StandaloneBuilderIntegrationFragment2) - - @Inject FileAccessFactory fileAccessFactory - - def private TypeReference createSuffixedTypeReference(String suffix) { - return new TypeReference( - grammar.name + suffix - ) - } - - def protected TypeReference getStandaloneBuildSetupGeneratedClass() { - createSuffixedTypeReference("StandaloneBuildSetupGenerated") - } - - def protected TypeReference getStandaloneBuildSetupServiceClass() { - createSuffixedTypeReference("StandaloneBuildSetupService") - } - - override generate() { - if (LOGGER.isInfoEnabled()) { - LOGGER.info(NLS.bind("executing generate for {0}", getClass().getName())); - } - generateServiceRegistration - generateBuildService - generateBuildSetup - } - - def generateServiceRegistration() { - fileAccessFactory.createTextFile("META-INF/services/com.avaloq.tools.ddk.xtext.build.IDynamicSetupService", ''' - «getStandaloneBuildSetupServiceClass.name» - ''').writeTo(projectConfig.runtime.srcGen) - } - - def generateBuildService() { - fileAccessFactory.createJavaFile(getStandaloneBuildSetupServiceClass, ''' - import java.util.List; - - import com.avaloq.tools.ddk.xtext.build.AbstractDynamicSetupService; - import com.google.common.collect.ImmutableList; - import com.google.inject.Injector; - import com.google.inject.Module; - - /** - * Generated by com.avaloq.tools.ddk.xtext.generator.builder.StandaloneBuilderIntegrationFragment2. - */ - public class «standaloneBuildSetupServiceClass.simpleName» extends AbstractDynamicSetupService { - - @SuppressWarnings("nls") - private static final String GRAMMAR = "«grammar.name»"; - @SuppressWarnings("nls") - private static final List PARENTS = ImmutableList.of(// - «FOR g: grammar.allUsedGrammars SEPARATOR ' -,'»"«g.name»" //«ENDFOR» - ); - - public Injector doSetup(Module overrideModule, Module... additionalModules) { - return new «grammar.simpleName»StandaloneBuildSetupGenerated(SETUP_LOCK, overrideModule, additionalModules).createInjectorAndDoEMFRegistration(); - } - - @Override - public List getParentLanguages() { - return PARENTS; - } - - @Override - public String getLanguageName() { - return GRAMMAR; - } - - } - ''').writeTo(projectConfig.runtime.srcGen) - } - - def generateBuildSetup() { - fileAccessFactory.createJavaFile(getStandaloneBuildSetupGeneratedClass, ''' - import com.google.common.collect.ImmutableList; - import com.google.inject.Guice; - import com.google.inject.Injector; - import com.google.inject.Module; - import com.google.inject.util.Modules; - - - /** - * Generated by com.avaloq.tools.ddk.xtext.generator.builder.StandaloneBuilderIntegrationFragment2. - */ - public class «standaloneBuildSetupGeneratedClass.simpleName» extends «grammar.simpleName»StandaloneSetup { - - private final Module overrideModule; - private final Module[] additionalModules; - private final Object lock; - - public «standaloneBuildSetupGeneratedClass.simpleName»(final Object lock, final Module overrideModule, Module... additionalModules) { - this.lock = lock; - this.overrideModule = overrideModule; - this.additionalModules = additionalModules; - } - - public «standaloneBuildSetupGeneratedClass.simpleName»(final Module overrideModule, Module... additionalModules) { - this.lock = null; - this.overrideModule = overrideModule; - this.additionalModules = additionalModules; - } - - @Override - public Injector createInjectorAndDoEMFRegistration() { - registerEPackages(); - Injector injector = createInjector(); - if (lock != null) { - synchronized (lock) { - register(injector); - } - } else { - register(injector); - } - return injector; - } - - @Override - public Injector createInjector() { - return Guice.createInjector(getModules()); - } - - protected void registerEPackages() { - «FOR mmd: grammar.metamodelDeclarations.typeSelect(GeneratedMetamodel)» - if («grammar.namespace».«mmd.name».«mmd.name.toFirstUpper()»Package.eINSTANCE == null) { - throw new IllegalStateException("EPackage could not be initialized: " + «grammar.namespace».«mmd.name».«mmd.name.toFirstUpper()»Package.eNS_URI); //$NON-NLS-1$ - } - «ENDFOR» - } - - protected Iterable getModules() { - return ImmutableList. builder().add(Modules.override(new «grammar.name»RuntimeModule()).with(overrideModule)).add(additionalModules).build(); - } - - } - ''').writeTo(projectConfig.runtime.srcGen) - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.java new file mode 100644 index 0000000000..b37c8d2977 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.java @@ -0,0 +1,217 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.formatting; + +import com.avaloq.tools.ddk.xtext.formatting.DirectNodeModelStreamer; +import com.avaloq.tools.ddk.xtext.formatting.RegionNodeModelFormatter; +import com.google.inject.Inject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.osgi.util.NLS; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.formatting.IFormatter; +import org.eclipse.xtext.formatting.INodeModelFormatter; +import org.eclipse.xtext.formatting.INodeModelStreamer; +import org.eclipse.xtext.xtext.generator.AbstractStubGeneratingFragment; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; +import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions; +import org.eclipse.xtext.xtext.generator.model.FileAccessFactory; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.JavaFileAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtext.xtext.generator.model.XtendFileAccess; +import org.eclipse.xtend2.lib.StringConcatenationClient; + +public class FormatterFragment2 extends AbstractStubGeneratingFragment { + + @Inject + private FileAccessFactory fileAccessFactory; + + @Inject + private XtextGeneratorNaming _xtextGeneratorNaming; + + @Inject + private GrammarAccessExtensions _grammarAccessExtensions; + + /** + * Class-wide logger. + */ + private static final Logger LOGGER = LogManager.getLogger(FormatterFragment2.class); + + protected TypeReference getFormatterStub(final Grammar grammar) { + return new TypeReference(_xtextGeneratorNaming.getRuntimeBasePackage(grammar) + ".formatting." + GrammarUtil.getSimpleName(grammar) + "Formatter"); + } + + @Override + public void generate() { + if (!isGenerateStub()) { + return; + } + if (LOGGER.isInfoEnabled()) { + LOGGER.info(NLS.bind("executing generate for {0}", getClass().getName())); + } + + new GuiceModuleAccess.BindingFactory() + .addTypeToType(TypeReference.typeRef(IFormatter.class), getFormatterStub(getLanguage().getGrammar())) + .addTypeToType(TypeReference.typeRef(INodeModelFormatter.class), TypeReference.typeRef(RegionNodeModelFormatter.class)) + .addTypeToType(TypeReference.typeRef(INodeModelStreamer.class), TypeReference.typeRef(DirectNodeModelStreamer.class)) + .contributeTo(getLanguage().getRuntimeGenModule()); + if (getProjectConfig().getRuntime().getManifest() != null) { + getProjectConfig().getRuntime().getManifest().getExportedPackages().add(_xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".formatting"); + } + doGenerateStubFile(); + } + + protected void doGenerateStubFile() { + if (!isGenerateStub()) { + return; + } + if (isGenerateXtendStub()) { + final XtendFileAccess xtendFile = doGetXtendStubFile(); + if (xtendFile != null) { + xtendFile.writeTo(getProjectConfig().getRuntime().getSrc()); + } + } else { + final JavaFileAccess javaFile = doGetJavaStubFile(); + if (javaFile != null) { + javaFile.writeTo(getProjectConfig().getRuntime().getSrc()); + } + } + } + + protected XtendFileAccess doGetXtendStubFile() { + final XtendFileAccess xtendFile = fileAccessFactory.createXtendFile(getFormatterStub(getGrammar())); + xtendFile.setResourceSet(getLanguage().getResourceSet()); + + final String stubSimpleName = getFormatterStub(getGrammar()).getSimpleName(); + final TypeReference grammarAccessRef = _grammarAccessExtensions.getGrammarAccess(getGrammar()); + + xtendFile.setContent(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter"); + target.newLineIfNotEmpty(); + target.append("import org.eclipse.xtext.formatting.impl.FormattingConfig"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append("/**"); + target.newLineIfNotEmpty(); + target.append(" * This class contains custom formatting declarations."); + target.newLineIfNotEmpty(); + target.append(" *"); + target.newLineIfNotEmpty(); + target.append(" * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting"); + target.newLineIfNotEmpty(); + target.append(" * on how and when to use it."); + target.newLineIfNotEmpty(); + target.append(" *"); + target.newLineIfNotEmpty(); + target.append(" * Also see {@link org.eclipse.xtext.xtext.XtextFormatter} as an example"); + target.newLineIfNotEmpty(); + target.append(" */"); + target.newLineIfNotEmpty(); + target.append("class " + stubSimpleName + " extends AbstractDeclarativeFormatter {"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append(" @"); + target.append(TypeReference.typeRef(Inject.class)); + target.append(" extension "); + target.append(grammarAccessRef); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append(" override protected void configureFormatting(FormattingConfig c) {"); + target.newLineIfNotEmpty(); + target.append("// It's usually a good idea to activate the following three statements."); + target.newLineIfNotEmpty(); + target.append("// They will add and preserve newlines around comments"); + target.newLineIfNotEmpty(); + target.append("// c.setLinewrap(0, 1, 2).before(SL_COMMENTRule)"); + target.newLineIfNotEmpty(); + target.append("// c.setLinewrap(0, 1, 2).before(ML_COMMENTRule)"); + target.newLineIfNotEmpty(); + target.append("// c.setLinewrap(0, 1, 1).after(ML_COMMENTRule)"); + target.newLineIfNotEmpty(); + target.append(" }"); + target.newLineIfNotEmpty(); + target.append("}"); + target.newLineIfNotEmpty(); + } + }); + return xtendFile; + } + + protected JavaFileAccess doGetJavaStubFile() { + final JavaFileAccess javaFile = fileAccessFactory.createJavaFile(getFormatterStub(getGrammar())); + javaFile.setResourceSet(getLanguage().getResourceSet()); + + final String stubSimpleName = getFormatterStub(getGrammar()).getSimpleName(); + final TypeReference grammarAccessRef = _grammarAccessExtensions.getGrammarAccess(getGrammar()); + + javaFile.setContent(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter;"); + target.newLineIfNotEmpty(); + target.append("import org.eclipse.xtext.formatting.impl.FormattingConfig;"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append("/**"); + target.newLineIfNotEmpty(); + target.append(" * This class contains custom formatting declarations."); + target.newLineIfNotEmpty(); + target.append(" *"); + target.newLineIfNotEmpty(); + target.append(" * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting"); + target.newLineIfNotEmpty(); + target.append(" * on how and when to use it."); + target.newLineIfNotEmpty(); + target.append(" *"); + target.newLineIfNotEmpty(); + target.append(" * Also see {@link org.eclipse.xtext.xtext.XtextFormatter} as an example"); + target.newLineIfNotEmpty(); + target.append(" */"); + target.newLineIfNotEmpty(); + target.append("class " + stubSimpleName + " extends AbstractDeclarativeFormatter {"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append(" @"); + target.append(TypeReference.typeRef(Inject.class)); + target.append(" "); + target.append(grammarAccessRef); + target.append(" grammarAccess;"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append(" @Override"); + target.newLineIfNotEmpty(); + target.append(" protected void configureFormatting(FormattingConfig c) {"); + target.newLineIfNotEmpty(); + target.append("// It's usually a good idea to activate the following three statements."); + target.newLineIfNotEmpty(); + target.append("// They will add and preserve newlines around comments"); + target.newLineIfNotEmpty(); + target.append("// c.setLinewrap(0, 1, 2).before(grammarAccess.getSL_COMMENTRule());"); + target.newLineIfNotEmpty(); + target.append("// c.setLinewrap(0, 1, 2).before(grammarAccess.getML_COMMENTRule());"); + target.newLineIfNotEmpty(); + target.append("// c.setLinewrap(0, 1, 1).after(grammarAccess.getML_COMMENTRule());"); + target.newLineIfNotEmpty(); + target.append(" }"); + target.newLineIfNotEmpty(); + target.append("}"); + target.newLineIfNotEmpty(); + } + }); + return javaFile; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.xtend deleted file mode 100644 index 5b0738cc93..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.xtend +++ /dev/null @@ -1,147 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.formatting - -import com.avaloq.tools.ddk.xtext.formatting.DirectNodeModelStreamer -import com.avaloq.tools.ddk.xtext.formatting.RegionNodeModelFormatter -import com.google.inject.Inject -import org.apache.logging.log4j.Logger -import org.apache.logging.log4j.LogManager; -import org.eclipse.osgi.util.NLS -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.formatting.IFormatter -import org.eclipse.xtext.formatting.INodeModelFormatter -import org.eclipse.xtext.formatting.INodeModelStreamer -import org.eclipse.xtext.xtext.generator.AbstractStubGeneratingFragment -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming -import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions -import org.eclipse.xtext.xtext.generator.model.FileAccessFactory -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess -import org.eclipse.xtext.xtext.generator.model.TypeReference - -import static org.eclipse.xtext.GrammarUtil.* - -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* - -class FormatterFragment2 extends AbstractStubGeneratingFragment { - - @Inject FileAccessFactory fileAccessFactory - @Inject extension XtextGeneratorNaming - @Inject extension GrammarAccessExtensions - - /** - * Class-wide logger. - */ - static final Logger LOGGER = LogManager::getLogger(typeof(FormatterFragment2)) - - protected def TypeReference getFormatterStub(Grammar grammar) { - new TypeReference(grammar.runtimeBasePackage + '.formatting.' + getSimpleName(grammar) + 'Formatter') - } - - override generate() { - if (!isGenerateStub()) { - return; - } - if (LOGGER.isInfoEnabled()) { - LOGGER.info(NLS.bind("executing generate for {0}", getClass().getName())); - } - - new GuiceModuleAccess.BindingFactory() - .addTypeToType(IFormatter.typeRef, language.grammar.formatterStub) - .addTypeToType(INodeModelFormatter.typeRef, RegionNodeModelFormatter.typeRef) - .addTypeToType(INodeModelStreamer.typeRef, DirectNodeModelStreamer.typeRef) - .contributeTo(language.runtimeGenModule) - if (projectConfig.runtime.manifest !== null) { - projectConfig.runtime.manifest.exportedPackages += grammar.runtimeBasePackage + '.formatting' - } - doGenerateStubFile() - } - - protected def doGenerateStubFile() { - if(!isGenerateStub) { - return - } - if (isGenerateXtendStub) { - val xtendFile = doGetXtendStubFile - xtendFile?.writeTo(projectConfig.runtime.src) - } else { - val javaFile = doGetJavaStubFile - javaFile?.writeTo(projectConfig.runtime.src) - } - } - - protected def doGetXtendStubFile() { - val xtendFile = fileAccessFactory.createXtendFile(grammar.formatterStub) - xtendFile.resourceSet = language.resourceSet - - xtendFile.content = ''' - import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter - import org.eclipse.xtext.formatting.impl.FormattingConfig - - /** - * This class contains custom formatting declarations. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting - * on how and when to use it. - * - * Also see {@link org.eclipse.xtext.xtext.XtextFormatter} as an example - */ - class «grammar.formatterStub.simpleName» extends AbstractDeclarativeFormatter { - - @«Inject» extension «grammar.grammarAccess» - - override protected void configureFormatting(FormattingConfig c) { - // It's usually a good idea to activate the following three statements. - // They will add and preserve newlines around comments - // c.setLinewrap(0, 1, 2).before(SL_COMMENTRule) - // c.setLinewrap(0, 1, 2).before(ML_COMMENTRule) - // c.setLinewrap(0, 1, 1).after(ML_COMMENTRule) - } - } - ''' - return xtendFile - } - - protected def doGetJavaStubFile() { - val javaFile = fileAccessFactory.createJavaFile(grammar.formatterStub) - javaFile.resourceSet = language.resourceSet - - javaFile.content = ''' - import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter; - import org.eclipse.xtext.formatting.impl.FormattingConfig; - - /** - * This class contains custom formatting declarations. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting - * on how and when to use it. - * - * Also see {@link org.eclipse.xtext.xtext.XtextFormatter} as an example - */ - class «grammar.formatterStub.simpleName» extends AbstractDeclarativeFormatter { - - @«Inject» «grammar.grammarAccess» grammarAccess; - - @Override - protected void configureFormatting(FormattingConfig c) { - // It's usually a good idea to activate the following three statements. - // They will add and preserve newlines around comments - // c.setLinewrap(0, 1, 2).before(grammarAccess.getSL_COMMENTRule()); - // c.setLinewrap(0, 1, 2).before(grammarAccess.getML_COMMENTRule()); - // c.setLinewrap(0, 1, 1).after(grammarAccess.getML_COMMENTRule()); - } - } - ''' - return javaFile - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.java new file mode 100644 index 0000000000..21a19e7af0 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.languageconstants; + +import com.google.inject.Inject; +import com.google.inject.Injector; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.osgi.util.NLS; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; +import org.eclipse.xtext.xtext.generator.model.FileAccessFactory; +import org.eclipse.xtext.xtext.generator.model.IXtextGeneratorFileSystemAccess; +import org.eclipse.xtext.xtext.generator.model.JavaFileAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtext.xtext.generator.model.XtextGeneratorFileSystemAccess; +import org.eclipse.xtend2.lib.StringConcatenationClient; + +public class LanguageConstantsFragment2 extends AbstractXtextGeneratorFragment { + + @Inject + private FileAccessFactory fileAccessFactory; + + @Inject + private XtextGeneratorNaming _xtextGeneratorNaming; + + /** Class-wide logger. */ + private static final Logger LOGGER = LogManager.getLogger(LanguageConstantsFragment2.class); + + /** + * An alternative implementation is to use + * com.avaloq.tools.ddk.xtext.generator.util.GeneratorUtil.getFileExtensions(org.eclipse.xtext.Grammar). + * However, we want to use the preferred file extension. + */ + private String preferredFileExtension; + + private String metamodelSrcGenPath; + + private IXtextGeneratorFileSystemAccess metamodelSrcGen; + + public void setPreferredFileExtension(final String preferredFileExtension) { + this.preferredFileExtension = preferredFileExtension; + } + + public String getMetamodelSrcGenPath() { + return metamodelSrcGenPath; + } + + public void setMetamodelSrcGenPath(final String metamodelSrcGenPath) { + this.metamodelSrcGenPath = metamodelSrcGenPath; + } + + protected IXtextGeneratorFileSystemAccess getMetamodelSrcGen() { + return metamodelSrcGen; + } + + /** + * Returns the preferred file extension. If not manually set, the + * first item in {@link fileExtensions} is returned. + * + * @param grammar + * the grammar for which the preferred file extension applies + * @return the preferred file extension + */ + public String getPreferredFileExtension() { + if (preferredFileExtension != null) { + return preferredFileExtension; + } else if (!getLanguage().getFileExtensions().isEmpty()) { + return getLanguage().getFileExtensions().get(0); + } else { + return GrammarUtil.getSimpleName(getGrammar()).toLowerCase(); + } + } + + @Override + public void generate() { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(NLS.bind("executing generate for {0}", getClass().getName())); + } + if (getLanguage().getFileExtensions().size() == 0) { + LOGGER.error(NLS.bind("There must be at least one extension for {0}", getGrammar().getName())); + return; + } + doGenerateFiles(); + } + + public void doGenerateFiles() { + final JavaFileAccess constantsFile = doGetConstantsClassFile(); + if (constantsFile != null) { + constantsFile.writeTo(getMetamodelSrcGen()); + } + } + + public JavaFileAccess doGetConstantsClassFile() { + final TypeReference typeReference = getTypeReference(getGrammar()); + final JavaFileAccess javaFile = fileAccessFactory.createJavaFile(typeReference); + javaFile.setResourceSet(getLanguage().getResourceSet()); + + final String grammarName = getGrammar().getName(); + final String simpleName = typeReference.getSimpleName(); + final String preferredExt = getPreferredFileExtension().replaceAll("%20", " "); + final String allExtensions = String.join(",", getLanguage().getFileExtensions()); + final String grammarSimpleName = GrammarUtil.getSimpleName(getGrammar()); + + javaFile.setContent(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("/**"); + target.newLineIfNotEmpty(); + target.append(" * Provides language specific constants for " + grammarName + "."); + target.newLineIfNotEmpty(); + target.append(" *"); + target.newLineIfNotEmpty(); + target.append(" * Theses constants are used e.g. by the test plug-ins."); + target.newLineIfNotEmpty(); + target.append(" */"); + target.newLineIfNotEmpty(); + target.append("@SuppressWarnings(\"nls\")"); + target.newLineIfNotEmpty(); + target.append("public final class " + simpleName + " {"); + target.newLineIfNotEmpty(); + target.append(" public static final String GRAMMAR = \"" + grammarName + "\";"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append(" /** Preferred file extension (for testing). */"); + target.newLineIfNotEmpty(); + target.append(" public static final String FILE_EXTENSION = \"" + preferredExt + "\";"); + target.newLineIfNotEmpty(); + target.append(" /** All file extensions. */"); + target.newLineIfNotEmpty(); + target.append(" public static final String FILE_EXTENSIONS = \"" + allExtensions + "\";"); + target.newLineIfNotEmpty(); + target.append(" /** Private constant specifying an URI pattern that match all files of the preferred extension. */"); + target.newLineIfNotEmpty(); + target.append(" private static final String ALL_" + grammarSimpleName.toUpperCase() + "_URI = \"*.\"+FILE_EXTENSION;"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append(" private " + simpleName + "() {}"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append(" /**"); + target.newLineIfNotEmpty(); + target.append(" * An URI pattern that matches all files of the preferred file extension."); + target.newLineIfNotEmpty(); + target.append(" *"); + target.newLineIfNotEmpty(); + target.append(" * @return this pattern"); + target.newLineIfNotEmpty(); + target.append(" */"); + target.newLineIfNotEmpty(); + target.append(" public static final String getAll" + grammarSimpleName + "URI() {"); + target.newLineIfNotEmpty(); + target.append(" return ALL_" + grammarSimpleName.toUpperCase() + "_URI;"); + target.newLineIfNotEmpty(); + target.append(" }"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + target.append("}"); + target.newLineIfNotEmpty(); + } + }); + + return javaFile; + } + + /** + * Returns the type reference of the Constants class. + * + * @param grammar + * the grammar + * @return the type reference + */ + public TypeReference getTypeReference(final Grammar grammar) { + return new TypeReference(_xtextGeneratorNaming.getRuntimeBasePackage(grammar) + "." + GrammarUtil.getSimpleName(grammar) + "Constants"); + } + + @Override + public void initialize(final Injector injector) { + super.initialize(injector); + if (metamodelSrcGenPath != null && !metamodelSrcGenPath.isEmpty()) { + metamodelSrcGen = new XtextGeneratorFileSystemAccess(metamodelSrcGenPath, true); + metamodelSrcGen.initialize(injector); + } else { + metamodelSrcGen = getProjectConfig().getRuntime().getSrcGen(); + } + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.xtend deleted file mode 100644 index 8108686691..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.xtend +++ /dev/null @@ -1,144 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.languageconstants - -import com.google.inject.Inject -import org.apache.logging.log4j.Logger -import org.apache.logging.log4j.LogManager; -import org.eclipse.osgi.util.NLS -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.GrammarUtil -import static extension org.eclipse.xtext.GrammarUtil.* -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming -import org.eclipse.xtext.xtext.generator.model.FileAccessFactory -import org.eclipse.xtext.xtext.generator.model.TypeReference -import org.eclipse.xtend.lib.annotations.Accessors -import org.eclipse.xtext.xtext.generator.model.XtextGeneratorFileSystemAccess -import com.google.inject.Injector -import org.eclipse.xtext.xtext.generator.model.IXtextGeneratorFileSystemAccess - -class LanguageConstantsFragment2 extends AbstractXtextGeneratorFragment { - - @Inject FileAccessFactory fileAccessFactory - @Inject extension XtextGeneratorNaming - - /** Class-wide logger. */ - val static Logger LOGGER = LogManager.getLogger(LanguageConstantsFragment2); - - /** - * An alternative implementation is to use - * com.avaloq.tools.ddk.xtext.generator.util.GeneratorUtil.getFileExtensions(org.eclipse.xtext.Grammar). - * However, we want to use the preferred file extension. - */ - @Accessors(PUBLIC_SETTER) String preferredFileExtension - - @Accessors String metamodelSrcGenPath - - @Accessors(PROTECTED_GETTER) IXtextGeneratorFileSystemAccess metamodelSrcGen - - /** - * Returns the preferred file extension. If not manually set, the - * first item in {@link fileExtensions} is returned. - * - * @param grammar - * the grammar for which the preferred file extension applies - * @return the preferred file extension - */ - def String getPreferredFileExtension() { - if (preferredFileExtension !== null) { - return preferredFileExtension - } else if (!language.fileExtensions.empty) { - return language.fileExtensions.get(0); - } else { - return GrammarUtil.getSimpleName(grammar).toLowerCase(); - } - } - - override generate() { - if (LOGGER.isInfoEnabled()) { - LOGGER.info(NLS.bind("executing generate for {0}", class.name)) - } - if (language.fileExtensions.size == 0) { - LOGGER.error(NLS.bind("There must be at least one extension for {0}", grammar.name)) - return - } - doGenerateFiles() - } - - def doGenerateFiles() { - val constantsFile = doGetConstantsClassFile - constantsFile?.writeTo(getMetamodelSrcGen) - } - - def doGetConstantsClassFile() { - val typeReference = grammar.typeReference - val javaFile = fileAccessFactory.createJavaFile(typeReference) - javaFile.resourceSet = language.resourceSet - - javaFile.content = - ''' - /** - * Provides language specific constants for «grammar.name». - * - * Theses constants are used e.g. by the test plug-ins. - */ - @SuppressWarnings("nls") - public final class «typeReference.simpleName» { - public static final String GRAMMAR = "«grammar.name»"; - - /** Preferred file extension (for testing). */ - public static final String FILE_EXTENSION = "«getPreferredFileExtension.replaceAll("%20"," ")»"; - /** All file extensions. */ - public static final String FILE_EXTENSIONS = "«language.fileExtensions.join(",")»"; - /** Private constant specifying an URI pattern that match all files of the preferred extension. */ - private static final String ALL_«grammar.simpleName.toUpperCase()»_URI = "*."+FILE_EXTENSION; - - private «typeReference.simpleName»() {} - - /** - * An URI pattern that matches all files of the preferred file extension. - * - * @return this pattern - */ - public static final String getAll«grammar.simpleName»URI() { - return ALL_«grammar.simpleName.toUpperCase()»_URI; - } - - } - ''' - - return javaFile - } - - /** - * Returns the type reference of the Constants class. - * - * @param grammar - * the grammar - * @return the type reference - */ - def TypeReference getTypeReference(Grammar grammar) { - return new TypeReference(grammar.runtimeBasePackage + "." + GrammarUtil.getSimpleName(grammar) + "Constants") - } - - override initialize(Injector injector) { - super.initialize(injector) - if (!metamodelSrcGenPath.isNullOrEmpty) { - metamodelSrcGen = new XtextGeneratorFileSystemAccess(metamodelSrcGenPath, true) - metamodelSrcGen.initialize(injector) - } else { - metamodelSrcGen = projectConfig.runtime.srcGen - } - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/modelinference/ModelInferenceFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/modelinference/ModelInferenceFragment2.java new file mode 100644 index 0000000000..cf6902da1e --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/modelinference/ModelInferenceFragment2.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.modelinference; + +import com.avaloq.tools.ddk.xtext.modelinference.IInferredModelAssociations; +import com.avaloq.tools.ddk.xtext.modelinference.IInferredModelAssociator; +import com.avaloq.tools.ddk.xtext.modelinference.InferredModelAssociator; +import com.avaloq.tools.ddk.xtext.ui.editor.findrefs.InferredModelReferenceQueryExecutor; +import org.eclipse.xtext.resource.IDerivedStateComputer; +import org.eclipse.xtext.ui.editor.findrefs.ReferenceQueryExecutor; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; + +public class ModelInferenceFragment2 extends AbstractXtextGeneratorFragment { + + @Override + public void generate() { + new GuiceModuleAccess.BindingFactory() + .addTypeToTypeSingleton(TypeReference.typeRef(IInferredModelAssociations.class), TypeReference.typeRef(InferredModelAssociator.class)) + .addTypeToTypeSingleton(TypeReference.typeRef(IInferredModelAssociator.class), TypeReference.typeRef(InferredModelAssociator.class)) + .addTypeToTypeSingleton(TypeReference.typeRef(IDerivedStateComputer.class), TypeReference.typeRef(InferredModelAssociator.class)) + .contributeTo(getLanguage().getRuntimeGenModule()); + new GuiceModuleAccess.BindingFactory() + .addTypeToType(TypeReference.typeRef(ReferenceQueryExecutor.class), TypeReference.typeRef(InferredModelReferenceQueryExecutor.class)) + .contributeTo(getLanguage().getEclipsePluginGenModule()); + + if (getProjectConfig().getRuntime().getManifest() != null) { + getProjectConfig().getRuntime().getManifest().getRequiredBundles().add("com.avaloq.tools.ddk.xtext"); + } + if (getProjectConfig().getEclipsePlugin().getManifest() != null) { + getProjectConfig().getEclipsePlugin().getManifest().getRequiredBundles().add("com.avaloq.tools.ddk.xtext.ui"); + } + if (getProjectConfig().getGenericIde().getManifest() != null) { + getProjectConfig().getGenericIde().getManifest().getRequiredBundles().add("com.avaloq.tools.ddk.xtext.ide"); + } + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/modelinference/ModelInferenceFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/modelinference/ModelInferenceFragment2.xtend deleted file mode 100644 index 628265ca45..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/modelinference/ModelInferenceFragment2.xtend +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.modelinference - -import com.avaloq.tools.ddk.xtext.modelinference.IInferredModelAssociations -import com.avaloq.tools.ddk.xtext.modelinference.IInferredModelAssociator -import com.avaloq.tools.ddk.xtext.modelinference.InferredModelAssociator -import com.avaloq.tools.ddk.xtext.ui.editor.findrefs.InferredModelReferenceQueryExecutor -import org.eclipse.xtext.resource.IDerivedStateComputer -import org.eclipse.xtext.ui.editor.findrefs.ReferenceQueryExecutor -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess - -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* - -class ModelInferenceFragment2 extends AbstractXtextGeneratorFragment { - - override generate() { - new GuiceModuleAccess.BindingFactory() - .addTypeToTypeSingleton(IInferredModelAssociations.typeRef, InferredModelAssociator.typeRef) - .addTypeToTypeSingleton(IInferredModelAssociator.typeRef, InferredModelAssociator.typeRef) - .addTypeToTypeSingleton(IDerivedStateComputer.typeRef, InferredModelAssociator.typeRef) - .contributeTo(language.runtimeGenModule) - new GuiceModuleAccess.BindingFactory() - .addTypeToType(ReferenceQueryExecutor.typeRef, InferredModelReferenceQueryExecutor.typeRef) - .contributeTo(language.eclipsePluginGenModule) - - - if (projectConfig.runtime.manifest !== null) { - projectConfig.runtime.manifest.requiredBundles += "com.avaloq.tools.ddk.xtext" - } - if (projectConfig.eclipsePlugin.manifest !== null) { - projectConfig.eclipsePlugin.manifest.requiredBundles += "com.avaloq.tools.ddk.xtext.ui" - } - if (projectConfig.genericIde.manifest !== null) { - projectConfig.genericIde.manifest.requiredBundles += "com.avaloq.tools.ddk.xtext.ide" - } - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.java new file mode 100644 index 0000000000..2d6ca5d0bd --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.parser.antlr; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.TerminalRule; +import org.eclipse.xtext.xtext.FlattenedGrammarAccess; +import org.eclipse.xtext.xtext.RuleFilter; +import org.eclipse.xtext.xtext.RuleNames; +import org.eclipse.xtext.xtext.generator.CodeConfig; +import org.eclipse.xtext.xtext.generator.model.IXtextGeneratorFileSystemAccess; +import org.eclipse.xtext.xtext.generator.parser.antlr.AbstractAntlrGrammarWithActionsGenerator; +import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrGrammarGenUtil; +import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrOptions; +import org.eclipse.xtext.xtext.generator.parser.antlr.CombinedGrammarMarker; +import org.eclipse.xtext.xtext.generator.parser.antlr.KeywordHelper; + +import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations; +import com.avaloq.tools.ddk.xtext.generator.parser.common.PredicatesNaming; +import com.google.common.collect.Iterators; +import com.google.inject.Inject; + + +public abstract class AbstractAnnotationAwareAntlrGrammarGenerator extends AbstractAntlrGrammarWithActionsGenerator { + + @Inject + protected GrammarRuleAnnotations annotations; + + @Inject + protected PredicatesNaming predicatesNaming; + + @Inject + private CodeConfig codeConfig; + + private Grammar originalGrammar; + + @Override + public void generate(Grammar it, AntlrOptions options, IXtextGeneratorFileSystemAccess fsa) { + this.keywordHelper = KeywordHelper.getHelper(it); + this.originalGrammar = it; + RuleFilter filter = new RuleFilter(); + filter.setDiscardUnreachableRules(true); // options.skipUnusedRules + filter.setDiscardTerminalRules(false); // options.skipUnusedRules + RuleNames ruleNames = RuleNames.getRuleNames(it, true); + Grammar flattened = new FlattenedGrammarAccess(ruleNames, filter).getFlattenedGrammar(); + new CombinedGrammarMarker(isCombinedGrammar()).attachToEmfObject(flattened); + fsa.generateFile(getGrammarNaming().getParserGrammar(it).getGrammarFileName(), compileParser(flattened, options)); + if (!isCombinedGrammar()) { + fsa.generateFile(getGrammarNaming().getLexerGrammar(it).getGrammarFileName(), compileLexer(flattened, options)); + } + } + + @Override + protected boolean isCombinedGrammar() { + return getGrammarNaming().isCombinedGrammar(originalGrammar); + } + + @Override + protected CharSequence compileLexer(Grammar it, AntlrOptions options) { + StringConcatenation sb = new StringConcatenation(); + sb.append(codeConfig.getFileHeader()); + sb.newLineIfNotEmpty(); + sb.append("lexer grammar "); + sb.append(getGrammarNaming().getLexerGrammar(it).getSimpleName()); + sb.append(";"); + sb.newLineIfNotEmpty(); + sb.append(compileLexerOptions(it, options)); + sb.newLineIfNotEmpty(); + sb.append(compileTokens(it, options)); + sb.newLineIfNotEmpty(); + sb.append(compileLexerHeader(it, options)); + sb.newLineIfNotEmpty(); + sb.append(compileLexerMembers(it, options)); + sb.newLineIfNotEmpty(); + sb.append(compileKeywordRules(it, options)); + sb.newLineIfNotEmpty(); + sb.append(compileTerminalRules(it, options)); + sb.newLineIfNotEmpty(); + return sb; + } + + protected CharSequence compileLexerMembers(Grammar it, AntlrOptions options) { + StringConcatenation sb = new StringConcatenation(); + sb.append("@members {"); + sb.newLine(); + sb.append(" "); + sb.append("protected int getSingleLineCommentRule() {"); + sb.newLine(); + sb.append(" "); + sb.append("return RULE_SL_COMMENT;"); + sb.newLine(); + sb.append(" "); + sb.append("}"); + sb.newLine(); + sb.newLine(); + sb.append(" "); + sb.append("protected int getMultiLineCommentRule() {"); + sb.newLine(); + sb.append(" "); + sb.append("return RULE_ML_COMMENT;"); + sb.newLine(); + sb.append(" "); + sb.append("}"); + sb.newLine(); + sb.newLine(); + sb.append(" "); + sb.append("protected int getEndOfFileRule() {"); + sb.newLine(); + sb.append(" "); + sb.append("return EOF;"); + sb.newLine(); + sb.append(" "); + sb.append("}"); + sb.newLine(); + sb.append("}"); + sb.newLine(); + return sb; + } + + @Override + protected String compileParserImports(Grammar it, AntlrOptions options) { + StringConcatenation sb = new StringConcatenation(); + sb.append("import "); + sb.append(predicatesNaming.getSemanticPredicatesFullName(it)); + sb.append(";"); + sb.newLineIfNotEmpty(); + sb.append("import com.avaloq.tools.ddk.xtext.parser.antlr.ParserContext;"); + sb.newLine(); + return sb.toString(); + } + + protected CharSequence compileParserMemberDeclarations(Grammar it, String access) { + StringConcatenation sb = new StringConcatenation(); + sb.append(access); + sb.append(" "); + sb.append(_grammarAccessExtensions.getGrammarAccess(it).getSimpleName()); + sb.append(" grammarAccess;"); + sb.newLineIfNotEmpty(); + sb.append(access); + sb.append(" "); + sb.append(predicatesNaming.getSemanticPredicatesSimpleName(it)); + sb.append(" predicates;"); + sb.newLineIfNotEmpty(); + sb.append(access); + sb.append(" ParserContext parserContext;"); + sb.newLineIfNotEmpty(); + return sb; + } + + protected CharSequence compileParserSetTokenStreamMethod() { + StringConcatenation sb = new StringConcatenation(); + sb.append("/**"); + sb.newLine(); + sb.append(" * Set token stream in parser context."); + sb.newLine(); + sb.append(" * @param input Token stream"); + sb.newLine(); + sb.append(" */"); + sb.newLine(); + sb.append("@Override"); + sb.newLine(); + sb.append("public void setTokenStream(TokenStream input) {"); + sb.newLine(); + sb.append(" "); + sb.append("super.setTokenStream(input);"); + sb.newLine(); + sb.append(" "); + sb.append("if(parserContext != null){"); + sb.newLine(); + sb.append(" "); + sb.append("parserContext.setTokenStream(input);"); + sb.newLine(); + sb.append(" "); + sb.append("}"); + sb.newLine(); + sb.append("}"); + sb.newLine(); + return sb; + } + + @Override + protected CharSequence compileKeywordRules(Grammar it, AntlrOptions options) { + // implementation from xtext, but keywords are from the given grammar only (which has been flattened and filtered correctly) + Set allKeywords = getAllKeywords(it, options); + List allTerminalRules = GrammarUtil.allTerminalRules(it); + + List syntheticKwAlternatives = new ArrayList<>(); + for (String kw : allKeywords) { + String ruleName = keywordHelper.getRuleName(kw); + syntheticKwAlternatives.add("(FRAGMENT_" + ruleName + ")=> FRAGMENT_" + ruleName + " {$type = " + ruleName + "; }"); + } + for (AbstractRule rule : allTerminalRules) { + if (rule instanceof TerminalRule) { + TerminalRule terminalRule = (TerminalRule) rule; + if (!_syntheticTerminalDetector.isSyntheticTerminalRule(terminalRule) && !terminalRule.isFragment()) { + syntheticKwAlternatives.add("(FRAGMENT_" + AntlrGrammarGenUtil.getRuleName(rule) + ")=> FRAGMENT_" + AntlrGrammarGenUtil.getRuleName(rule) + " {$type = " + AntlrGrammarGenUtil.getRuleName(rule) + "; }"); + } + } + } + + StringConcatenation sb = new StringConcatenation(); + if (options.isBacktrackLexer()) { + sb.append("SYNTHETIC_ALL_KEYWORDS :"); + sb.newLine(); + for (int i = 0; i < syntheticKwAlternatives.size(); i++) { + sb.append(" "); + if (i > 0) { + sb.append("| "); + } + sb.append(syntheticKwAlternatives.get(i)); + sb.newLine(); + } + sb.append(";"); + sb.newLine(); + for (String kw : allKeywords) { + sb.append("fragment FRAGMENT_"); + sb.append(keywordHelper.getRuleName(kw)); + sb.append(" : \'"); + sb.append(AntlrGrammarGenUtil.toAntlrString(kw)); + sb.append("\';"); + sb.newLine(); + } + } else { + for (String rule : allKeywords) { + sb.append(compileRule(rule, it, options)); + sb.newLineIfNotEmpty(); + } + } + return sb; + } + + private static Set getAllKeywords(Grammar flattenedGrammar, AntlrOptions options) { + Set result = new TreeSet<>(KeywordHelper.keywordComparator); + List parserRules = GrammarUtil.allParserRules(flattenedGrammar); + List enumRules = GrammarUtil.allEnumRules(flattenedGrammar); + Iterator iter = Iterators.concat(EcoreUtil.getAllContents(parserRules), EcoreUtil.getAllContents(enumRules)); + Iterators.addAll(result, Iterators.transform( + Iterators.filter(iter, Keyword.class), + kw -> options.isIgnoreCase() ? kw.getValue().toLowerCase(Locale.ENGLISH) : kw.getValue() + )); + return Collections.unmodifiableSet(result); + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.xtend deleted file mode 100644 index a6b605450c..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.xtend +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.parser.antlr - -import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations -import com.avaloq.tools.ddk.xtext.generator.parser.common.PredicatesNaming -import com.google.common.collect.Iterators -import com.google.inject.Inject -import java.util.Collections -import java.util.Locale -import java.util.TreeSet -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.util.EcoreUtil -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.GrammarUtil -import org.eclipse.xtext.Keyword -import org.eclipse.xtext.xtext.FlattenedGrammarAccess -import org.eclipse.xtext.xtext.RuleFilter -import org.eclipse.xtext.xtext.RuleNames -import org.eclipse.xtext.xtext.generator.CodeConfig -import org.eclipse.xtext.xtext.generator.model.IXtextGeneratorFileSystemAccess -import org.eclipse.xtext.xtext.generator.parser.antlr.AbstractAntlrGrammarWithActionsGenerator -import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrOptions -import org.eclipse.xtext.xtext.generator.parser.antlr.CombinedGrammarMarker -import org.eclipse.xtext.xtext.generator.parser.antlr.KeywordHelper - -import static extension org.eclipse.xtext.GrammarUtil.* -import static extension org.eclipse.xtext.xtext.generator.parser.antlr.AntlrGrammarGenUtil.* - -abstract class AbstractAnnotationAwareAntlrGrammarGenerator extends AbstractAntlrGrammarWithActionsGenerator { - @Inject protected extension GrammarRuleAnnotations annotations - @Inject protected extension PredicatesNaming predicatesNaming - @Inject CodeConfig codeConfig - - Grammar originalGrammar - - override generate(Grammar it, AntlrOptions options, IXtextGeneratorFileSystemAccess fsa) { - this.keywordHelper = KeywordHelper.getHelper(it) - this.originalGrammar = it - val RuleFilter filter = new RuleFilter(); - filter.discardUnreachableRules = true // options.skipUnusedRules - filter.discardTerminalRules = false // options.skipUnusedRules - val RuleNames ruleNames = RuleNames.getRuleNames(it, true); - val Grammar flattened = new FlattenedGrammarAccess(ruleNames, filter).getFlattenedGrammar(); - new CombinedGrammarMarker(combinedGrammar).attachToEmfObject(flattened) - fsa.generateFile(grammarNaming.getParserGrammar(it).grammarFileName, flattened.compileParser(options)) - if (!isCombinedGrammar) { - fsa.generateFile(grammarNaming.getLexerGrammar(it).grammarFileName, flattened.compileLexer(options)) - } - } - - protected override isCombinedGrammar() { - grammarNaming.isCombinedGrammar(originalGrammar) - } - - protected override compileLexer(Grammar it, AntlrOptions options) ''' - «codeConfig.fileHeader» - lexer grammar «grammarNaming.getLexerGrammar(it).simpleName»; - «compileLexerOptions(options)» - «compileTokens(options)» - «compileLexerHeader(options)» - «compileLexerMembers(options)» - «compileKeywordRules(options)» - «compileTerminalRules(options)» - ''' - - protected def compileLexerMembers(Grammar it, AntlrOptions options) ''' - @members { - protected int getSingleLineCommentRule() { - return RULE_SL_COMMENT; - } - - protected int getMultiLineCommentRule() { - return RULE_ML_COMMENT; - } - - protected int getEndOfFileRule() { - return EOF; - } - } - ''' - - protected override compileParserImports(Grammar it, AntlrOptions options) ''' - import «grammar.semanticPredicatesFullName»; - import com.avaloq.tools.ddk.xtext.parser.antlr.ParserContext; - ''' - - protected def compileParserMemberDeclarations(Grammar it, String access) ''' - «access» «grammarAccess.simpleName» grammarAccess; - «access» «getSemanticPredicatesSimpleName()» predicates; - «access» ParserContext parserContext; - ''' - - protected def compileParserSetTokenStreamMethod() ''' - /** - * Set token stream in parser context. - * @param input Token stream - */ - @Override - public void setTokenStream(TokenStream input) { - super.setTokenStream(input); - if(parserContext != null){ - parserContext.setTokenStream(input); - } - } - ''' - - protected override compileKeywordRules(Grammar it, AntlrOptions options) { - // implementation from xtext, but keywords are from the given grammar only (which has been flattened and filtered correctly) - val allKeywords = getAllKeywords(options) - val allTerminalRules = allTerminalRules - - val synthetic_kw_alternatives = newArrayList - synthetic_kw_alternatives.addAll(allKeywords.indexed.map[ - val ruleName = keywordHelper.getRuleName(value) - return '''(FRAGMENT_«ruleName»)=> FRAGMENT_«ruleName» {$type = «ruleName»; }''' - ]) - synthetic_kw_alternatives.addAll(allTerminalRules.indexed.map[ - if (!isSyntheticTerminalRule(value) && !value.fragment) { - return '''(FRAGMENT_«value.ruleName»)=> FRAGMENT_«value.ruleName» {$type = «value.ruleName»; }''' - } - ].filterNull.toList) - ''' - «IF options.isBacktrackLexer» - SYNTHETIC_ALL_KEYWORDS : - «FOR kw: synthetic_kw_alternatives SEPARATOR ' |'» - «kw» - «ENDFOR» - ; - «FOR kw: allKeywords» - fragment FRAGMENT_«keywordHelper.getRuleName(kw)» : '«kw.toAntlrString()»'; - «ENDFOR» - «ELSE» - «FOR rule:allKeywords» - «rule.compileRule(it, options)» - «ENDFOR» - «ENDIF» - ''' - } - - private static def getAllKeywords(Grammar flattenedGrammar, AntlrOptions options) { - val result = new TreeSet(KeywordHelper.keywordComparator) - val parserRules=GrammarUtil.allParserRules(flattenedGrammar) - val enumRules=GrammarUtil.allEnumRules(flattenedGrammar) - val iter=Iterators.concat(EcoreUtil.getAllContents(parserRules), EcoreUtil.getAllContents(enumRules)) - Iterators.addAll(result, iter.filter(Keyword).map[if (options.ignoreCase) value.toLowerCase(Locale.ENGLISH) else value]) - Collections.unmodifiableSet(result) - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java new file mode 100644 index 0000000000..2d5c88664f --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java @@ -0,0 +1,1386 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.generator.parser.antlr; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtext.AbstractElement; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.Alternatives; +import org.eclipse.xtext.Assignment; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.EnumRule; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.Group; +import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.ParserRule; +import org.eclipse.xtext.RuleCall; +import org.eclipse.xtext.TerminalRule; +import org.eclipse.xtext.UnorderedGroup; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.Pair; +import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrGrammarGenUtil; +import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrOptions; +import org.eclipse.xtext.xtext.generator.parser.antlr.ContentAssistGrammarNaming; +import org.eclipse.xtext.xtext.generator.parser.antlr.GrammarNaming; + +import com.google.common.collect.Iterables; +import com.google.inject.Inject; + +/** + * This implementation is strongly based on AntlrContentAssistGrammarGenerator but with a different base class. + * The following extension is supported: + * + * A datatype grammar rule containing only one ID terminal rule can be annotated + * with @KeywordRule annotation provided a list of words so only these words can + * be accepted by this rule. + * + * Example: + * + * /** + * * @KeywordRule(visible, invisible) + * * / + * VisibleKind returns VisibleKind: + * ID + * ; + * + * The above rule will accept only 'visible' and 'invisible' identifiers. + * This rule in ASMD is called a keyword rule because it is intended to replace + * usages of keywords which shall not be reserved words in the language. + * Reserved words are words that are not allowed to be used in identifiers. + * + * The above example can therefore replace the following enumeration: + * + * enum VisibleKind : + * VISIBLE = "visible" + * | INVISIBLE = "invisible" + * ; + * + * Please note that a corresponding value converter is needed. + * + * Implementation remark: + * - This template will insert validating semantic predicates in the rule + * - If the rule is used from an alternative a gated semantic predicate will + * be used in the alternative + * - Error messages will be adjusted correspondingly + */ +public class AnnotationAwareAntlrContentAssistGrammarGenerator extends AbstractAnnotationAwareAntlrGrammarGenerator { + + @Inject + private ContentAssistGrammarNaming naming; + + @Override + protected GrammarNaming getGrammarNaming() { + return this.naming; + } + + @Override + protected boolean isParserBackTracking(final Grammar it, final AntlrOptions options) { + return super.isParserBackTracking(it, options) || !GrammarUtil.getAllPredicatedElements(it).isEmpty(); + } + + @Override + protected String compileParserImports(final Grammar it, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _isCombinedGrammar = this.isCombinedGrammar(); + boolean _not = (!_isCombinedGrammar); + if (_not) { + _builder.append("import java.util.Map;"); + _builder.newLine(); + _builder.append("import java.util.HashMap;"); + _builder.newLine(); + } + } + _builder.newLine(); + _builder.append("import java.io.InputStream;"); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.*;"); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.parser.*;"); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.parser.impl.*;"); + _builder.newLine(); + _builder.append("import org.eclipse.emf.ecore.util.EcoreUtil;"); + _builder.newLine(); + _builder.append("import org.eclipse.emf.ecore.EObject;"); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream;"); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream.HiddenTokens;"); + _builder.newLine(); + _builder.append("import "); + String _name = this.getGrammarNaming().getInternalParserSuperClass(it).getName(); + _builder.append(_name); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + _builder.append("import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.DFA;"); + _builder.newLine(); + _builder.append("import "); + String _name_1 = this._grammarAccessExtensions.getGrammarAccess(it).getName(); + _builder.append(_name_1); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + String _compileParserImports = super.compileParserImports(it, options); + _builder.append(_compileParserImports); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected String compileParserMembers(final Grammar it, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("@"); + { + boolean _isCombinedGrammar = this.isCombinedGrammar(); + if (_isCombinedGrammar) { + _builder.append("parser::"); + } + } + _builder.append("members {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + CharSequence _compileParserMemberDeclarations = this.compileParserMemberDeclarations(it, "protected"); + _builder.append(_compileParserMemberDeclarations, " "); + _builder.newLineIfNotEmpty(); + { + boolean _isCombinedGrammar_1 = this.isCombinedGrammar(); + boolean _not = (!_isCombinedGrammar_1); + if (_not) { + _builder.append(" "); + _builder.append("private final Map tokenNameToValue = new HashMap();"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + { + List _sortBy = IterableExtensions.sortBy(IterableExtensions.sort(GrammarUtil.getAllKeywords(it)), (String it_1) -> Integer.valueOf(it_1.length())); + for (final String kw : _sortBy) { + _builder.append(" "); + _builder.append(" "); + _builder.append("tokenNameToValue.put(\""); + String _ruleName = this.keywordHelper.getRuleName(kw); + _builder.append(_ruleName, " "); + _builder.append("\", \"\'"); + String _replace = AntlrGrammarGenUtil.toStringInAntlrAction(kw).replace("$", "\\u0024"); + _builder.append(_replace, " "); + _builder.append("\'\");"); + _builder.newLineIfNotEmpty(); + } + } + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + } + } + _builder.newLine(); + _builder.append(" "); + CharSequence _compileParserSetTokenStreamMethod = this.compileParserSetTokenStreamMethod(); + _builder.append(_compileParserSetTokenStreamMethod, " "); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public void setPredicates("); + String _semanticPredicatesSimpleName = this.predicatesNaming.getSemanticPredicatesSimpleName(it); + _builder.append(_semanticPredicatesSimpleName, " "); + _builder.append(" predicates) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("this.predicates = predicates;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public void setGrammarAccess("); + String _simpleName = this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(); + _builder.append(_simpleName, " "); + _builder.append(" grammarAccess) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("this.grammarAccess = grammarAccess;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append("public void setParserContext(ParserContext parserContext) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("this.parserContext = parserContext;"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected Grammar getGrammar() {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("return grammarAccess.getGrammar();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected String getValueForTokenName(String tokenName) {"); + _builder.newLine(); + { + boolean _isCombinedGrammar_2 = this.isCombinedGrammar(); + if (_isCombinedGrammar_2) { + _builder.append(" "); + _builder.append("return tokenName;"); + _builder.newLine(); + } else { + _builder.append(" "); + _builder.append("String result = tokenNameToValue.get(tokenName);"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if (result == null)"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("result = tokenName;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("return result;"); + _builder.newLine(); + } + } + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected CharSequence compileRules(final Grammar g, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + { + List _allParserRules = GrammarUtil.allParserRules(g); + List _allEnumRules = GrammarUtil.allEnumRules(g); + Iterable _plus = Iterables.concat(_allParserRules, _allEnumRules); + Iterable _plus_1 = Iterables.concat(_plus, GrammarUtil.getAllAlternatives(g)); + Iterable _plus_2 = Iterables.concat(_plus_1, GrammarUtil.getAllGroups(g)); + Iterable _plus_3 = Iterables.concat(_plus_2, GrammarUtil.getAllUnorderedGroups(g)); + Iterable _filter = IterableExtensions.filter(Iterables.concat(_plus_3, GrammarUtil.getAllAssignments(g)), + (EObject it) -> Boolean.valueOf(this._grammarAccessExtensions.isCalled(GrammarUtil.containingRule(it), g))); + for (final EObject rule : _filter) { + _builder.newLine(); + CharSequence _compileRule = this.compileRule(rule, g, options); + _builder.append(_compileRule); + _builder.newLineIfNotEmpty(); + } + } + { + boolean _isCombinedGrammar = this.isCombinedGrammar(); + if (_isCombinedGrammar) { + CharSequence _compileTerminalRules = this.compileTerminalRules(g, options); + _builder.append(_compileTerminalRules); + _builder.newLineIfNotEmpty(); + } + } + return _builder; + } + + @Override + protected CharSequence _compileRule(final ParserRule it, final Grammar grammar, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _isValidEntryRule = AntlrGrammarGenUtil.isValidEntryRule(it); + if (_isValidEntryRule) { + _builder.append("// Entry rule "); + String _entryRuleName = this._grammarAccessExtensions.entryRuleName(it); + _builder.append(_entryRuleName); + _builder.newLineIfNotEmpty(); + String _entryRuleName_1 = this._grammarAccessExtensions.entryRuleName(it); + _builder.append(_entryRuleName_1); + _builder.newLineIfNotEmpty(); + { + boolean _isDefinesHiddenTokens = it.isDefinesHiddenTokens(); + if (_isDefinesHiddenTokens) { + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + CharSequence _compileInitHiddenTokens = this.compileInitHiddenTokens(it, options); + _builder.append(_compileInitHiddenTokens, " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + } + } + _builder.append(":"); + _builder.newLine(); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _ruleName = this._grammarAccessExtensions.ruleName(it); + _builder.append(_ruleName, " "); + _builder.newLineIfNotEmpty(); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_1); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("EOF"); + _builder.newLine(); + _builder.append(";"); + _builder.newLine(); + { + boolean _isDefinesHiddenTokens_1 = it.isDefinesHiddenTokens(); + if (_isDefinesHiddenTokens_1) { + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + CharSequence _compileRestoreHiddenTokens = this.compileRestoreHiddenTokens(it, options); + _builder.append(_compileRestoreHiddenTokens, " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + } + } + } + } + _builder.newLine(); + _builder.append("// Rule "); + String _name = AntlrGrammarGenUtil.getOriginalElement(it).getName(); + _builder.append(_name); + _builder.newLineIfNotEmpty(); + String _ruleName_1 = this._grammarAccessExtensions.ruleName(it); + _builder.append(_ruleName_1); + _builder.newLineIfNotEmpty(); + { + boolean _hasNoBacktrackAnnotation = this.annotations.hasNoBacktrackAnnotation(it); + if (_hasNoBacktrackAnnotation) { + _builder.append(" "); + _builder.append("// Enclosing rule was annotated with @NoBacktrack"); + _builder.newLine(); + _builder.append(" "); + _builder.append("options { backtrack=false; }"); + _builder.newLine(); + } + } + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + CharSequence _compileInitHiddenTokens_1 = this.compileInitHiddenTokens(it, options); + _builder.append(_compileInitHiddenTokens_1, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append(":"); + _builder.newLine(); + _builder.append(" "); + { + boolean _hasValidatingPredicate = this.annotations.hasValidatingPredicate(it); + if (_hasValidatingPredicate) { + String _generateValidatingPredicate = this.annotations.generateValidatingPredicate(it); + _builder.append(_generateValidatingPredicate, " "); + } + } + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _ebnf = this.ebnf(it.getAlternatives(), options, false); + _builder.append(_ebnf, " "); + _builder.newLineIfNotEmpty(); + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append(" "); + CharSequence _compileRestoreHiddenTokens_1 = this.compileRestoreHiddenTokens(it, options); + _builder.append(_compileRestoreHiddenTokens_1, " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + return _builder; + } + + @Override + protected CharSequence _compileRule(final EnumRule it, final Grammar grammar, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("// Rule "); + String _name = AntlrGrammarGenUtil.getOriginalElement(it).getName(); + _builder.append(_name); + _builder.newLineIfNotEmpty(); + String _ruleName = this._grammarAccessExtensions.ruleName(it); + _builder.append(_ruleName); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(":"); + _builder.newLine(); + _builder.append(" "); + String _ebnf = this.ebnf(it.getAlternatives(), options, false); + _builder.append(_ebnf, " "); + _builder.newLineIfNotEmpty(); + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder; + } + + protected CharSequence _compileRule(final Alternatives it, final Grammar grammar, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(":"); + _builder.newLine(); + _builder.append(" "); + { + EList _elements = it.getElements(); + boolean _hasElements = false; + for (final AbstractElement element : _elements) { + if (!_hasElements) { + _hasElements = true; + } else { + _builder.appendImmediate("\n|", " "); + } + String _ebnf = this.ebnf(element, options, false); + _builder.append(_ebnf, " "); + } + } + _builder.newLineIfNotEmpty(); + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder; + } + + protected CharSequence _compileRule(final Assignment it, final Grammar grammar, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(":"); + _builder.newLine(); + _builder.append(" "); + String _assignmentEbnf = this.assignmentEbnf(it.getTerminal(), it, options, false); + _builder.append(_assignmentEbnf, " "); + _builder.newLineIfNotEmpty(); + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder; + } + + protected CharSequence _compileRule(final UnorderedGroup it, final Grammar grammar, final AntlrOptions options) { + final boolean hasMandatoryContent = IterableExtensions.exists(it.getElements(), (AbstractElement it_1) -> !GrammarUtil.isOptionalCardinality(it_1)); + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("getUnorderedGroupHelper().enter(grammarAccess."); + String _gaRuleElementAccessor = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaRuleElementAccessor, " "); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(":"); + _builder.newLine(); + _builder.append(" "); + String _contentAssistRuleName_1 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName_1, " "); + _builder.append("__"); + String _gaElementIdentifier_1 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier_1, " "); + _builder.append("__0"); + _builder.newLineIfNotEmpty(); + { + if (hasMandatoryContent) { + _builder.append(" "); + _builder.append("{getUnorderedGroupHelper().canLeave(grammarAccess."); + String _gaRuleElementAccessor_1 = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaRuleElementAccessor_1, " "); + _builder.append(")}?"); + _builder.newLineIfNotEmpty(); + } else { + _builder.append(" "); + _builder.append("?"); + _builder.newLine(); + } + } + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("getUnorderedGroupHelper().leave(grammarAccess."); + String _gaRuleElementAccessor_2 = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaRuleElementAccessor_2, " "); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + CharSequence _ruleImpl = this.ruleImpl(it, grammar, options); + _builder.append(_ruleImpl); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + CharSequence _ruleImpl_1 = this.ruleImpl(it, grammar, options, 0); + _builder.append(_ruleImpl_1); + _builder.newLineIfNotEmpty(); + return _builder; + } + + protected CharSequence _compileRule(final Group it, final Grammar grammar, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + CharSequence _ruleImpl = this.ruleImpl(it, grammar, options, 0); + _builder.append(_ruleImpl); + _builder.newLineIfNotEmpty(); + return _builder; + } + + /** + * Dispatch method for compileRule. + */ + @Override + protected CharSequence compileRule(final Object it, final Grammar grammar, final AntlrOptions options) { + if (it instanceof ParserRule) { + return _compileRule((ParserRule) it, grammar, options); + } else if (it instanceof EnumRule) { + return _compileRule((EnumRule) it, grammar, options); + } else if (it instanceof Alternatives) { + return _compileRule((Alternatives) it, grammar, options); + } else if (it instanceof Assignment) { + return _compileRule((Assignment) it, grammar, options); + } else if (it instanceof UnorderedGroup) { + return _compileRule((UnorderedGroup) it, grammar, options); + } else if (it instanceof Group) { + return _compileRule((Group) it, grammar, options); + } else { + return super.compileRule(it, grammar, options); + } + } + + protected CharSequence ruleImpl(final UnorderedGroup it, final Grammar grammar, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + _builder.append("__Impl"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("boolean selected = false;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(":"); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + { + Iterable> _indexed = IterableExtensions.indexed(it.getElements()); + boolean _hasElements = false; + for (final Pair element : _indexed) { + if (!_hasElements) { + _hasElements = true; + } else { + _builder.appendImmediate("|", " "); + } + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("{getUnorderedGroupHelper().canSelect(grammarAccess."); + String _gaRuleElementAccessor = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaRuleElementAccessor, " "); + _builder.append(", "); + Integer _key = element.getKey(); + _builder.append(_key, " "); + _builder.append(")}?=>("); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("getUnorderedGroupHelper().select(grammarAccess."); + String _gaRuleElementAccessor_1 = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaRuleElementAccessor_1, " "); + _builder.append(", "); + Integer _key_1 = element.getKey(); + _builder.append(_key_1, " "); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("selected = true;"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + { + boolean _isMultipleCardinality = GrammarUtil.isMultipleCardinality(element.getValue()); + if (_isMultipleCardinality) { + _builder.append(" "); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); + _builder.append(_grammarElementAccess, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append(" "); + _builder.append("("); + String _ebnf2 = this.ebnf2(element.getValue(), options, false); + _builder.append(_ebnf2, " "); + _builder.append(")"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); + _builder.append(_grammarElementAccess_1, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess_2 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); + _builder.append(_grammarElementAccess_2, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append(" "); + _builder.append("(("); + String _ebnf2_1 = this.ebnf2(element.getValue(), options, false); + _builder.append(_ebnf2_1, " "); + _builder.append(")=>"); + String _ebnf2_2 = this.ebnf2(element.getValue(), options, false); + _builder.append(_ebnf2_2, " "); + _builder.append(")*"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_3 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); + _builder.append(_grammarElementAccess_3, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + } else { + _builder.append(" "); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess_4 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); + _builder.append(_grammarElementAccess_4, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("("); + String _ebnf2_3 = this.ebnf2(element.getValue(), options, false); + _builder.append(_ebnf2_3, " "); + _builder.append(")"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_5 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); + _builder.append(_grammarElementAccess_5, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + } + } + _builder.append(" "); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + } + } + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if (selected)"); + _builder.newLine(); + _builder.append(" "); + _builder.append("getUnorderedGroupHelper().returnFromSelection(grammarAccess."); + String _gaRuleElementAccessor_2 = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaRuleElementAccessor_2, " "); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder; + } + + protected CharSequence ruleImpl(final UnorderedGroup it, final Grammar grammar, final AntlrOptions options, final int index) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + _builder.append("__"); + _builder.append(index); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(":"); + _builder.newLine(); + _builder.append(" "); + String _contentAssistRuleName_1 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName_1, " "); + _builder.append("__"); + String _gaElementIdentifier_1 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier_1, " "); + _builder.append("__Impl"); + _builder.newLineIfNotEmpty(); + { + int _size = it.getElements().size(); + if (_size > (index + 1)) { + _builder.append(" "); + String _contentAssistRuleName_2 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName_2, " "); + _builder.append("__"); + String _gaElementIdentifier_2 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier_2, " "); + _builder.append("__"); + _builder.append((index + 1), " "); + _builder.append("?"); + _builder.newLineIfNotEmpty(); + } + } + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + { + int _size_1 = it.getElements().size(); + if (_size_1 > (index + 1)) { + CharSequence _ruleImpl = this.ruleImpl(it, grammar, options, (index + 1)); + _builder.append(_ruleImpl); + _builder.newLineIfNotEmpty(); + } + } + return _builder; + } + + protected CharSequence ruleImpl(final Group it, final Grammar grammar, final AntlrOptions options, final int index) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + _builder.append("__"); + _builder.append(index); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(":"); + _builder.newLine(); + _builder.append(" "); + String _contentAssistRuleName_1 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName_1, " "); + _builder.append("__"); + String _gaElementIdentifier_1 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier_1, " "); + _builder.append("__"); + _builder.append(index, " "); + _builder.append("__Impl"); + _builder.newLineIfNotEmpty(); + { + int _size = it.getElements().size(); + if (_size > (index + 1)) { + _builder.append(" "); + String _contentAssistRuleName_2 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName_2, " "); + _builder.append("__"); + String _gaElementIdentifier_2 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier_2, " "); + _builder.append("__"); + _builder.append((index + 1), " "); + _builder.newLineIfNotEmpty(); + } + } + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + String _contentAssistRuleName_3 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName_3); + _builder.append("__"); + String _gaElementIdentifier_3 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier_3); + _builder.append("__"); + _builder.append(index); + _builder.append("__Impl"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("int stackSize = keepStackSize();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(":"); + _builder.newLine(); + String _ebnf = this.ebnf(it.getElements().get(index), options, false); + _builder.append(_ebnf); + _builder.newLineIfNotEmpty(); + _builder.append(";"); + _builder.newLine(); + _builder.append("finally {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("restoreStackSize(stackSize);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + { + int _size_1 = it.getElements().size(); + if (_size_1 > (index + 1)) { + CharSequence _ruleImpl = this.ruleImpl(it, grammar, options, (index + 1)); + _builder.append(_ruleImpl); + _builder.newLineIfNotEmpty(); + } + } + return _builder; + } + + @Override + protected String ebnf(final AbstractElement it, final AntlrOptions options, final boolean supportsActions) { + StringConcatenation _builder = new StringConcatenation(); + { + if ((!GrammarUtil.isOptionalCardinality(it)) && GrammarUtil.isMultipleCardinality(it)) { + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + CharSequence _paramConfig = this.paramConfig(it); + _builder.append(_paramConfig, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("("); + String _ebnf2 = this.ebnf2(it, options, supportsActions); + _builder.append(_ebnf2, " "); + _builder.append(")"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_1, " "); + CharSequence _paramConfig_1 = this.paramConfig(it); + _builder.append(_paramConfig_1, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess_2 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_2, " "); + CharSequence _paramConfig_2 = this.paramConfig(it); + _builder.append(_paramConfig_2, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("("); + String _ebnf2_1 = this.ebnf2(it, options, supportsActions); + _builder.append(_ebnf2_1, " "); + _builder.append(")*"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_3 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_3, " "); + CharSequence _paramConfig_3 = this.paramConfig(it); + _builder.append(_paramConfig_3, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.append(")"); + _builder.newLine(); + } else { + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess_4 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_4, " "); + CharSequence _paramConfig_4 = this.paramConfig(it); + _builder.append(_paramConfig_4, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + { + boolean _mustBeParenthesized = this.mustBeParenthesized(it); + if (_mustBeParenthesized) { + _builder.append("("); + String _ebnf2_2 = this.ebnf2(it, options, supportsActions); + _builder.append(_ebnf2_2, " "); + _builder.append(")"); + } else { + String _ebnf2_3 = this.ebnf2(it, options, supportsActions); + _builder.append(_ebnf2_3, " "); + } + } + String _cardinality = it.getCardinality(); + _builder.append(_cardinality, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_5 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_5, " "); + CharSequence _paramConfig_5 = this.paramConfig(it); + _builder.append(_paramConfig_5, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + _builder.newLine(); + } + } + return _builder.toString(); + } + + protected CharSequence paramConfig(final AbstractElement it) { + StringConcatenation _builder = new StringConcatenation(); + { + if (((GrammarUtil.containingRule(it).getAlternatives() == it) && ParserRule.class.isInstance(GrammarUtil.containingRule(it)) && (!((ParserRule) AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingRule(it))).getParameters().isEmpty()))) { + _builder.append(", "); + AbstractRule _containingRule = GrammarUtil.containingRule(it); + int _parameterConfig = AntlrGrammarGenUtil.getParameterConfig((ParserRule) _containingRule); + _builder.append(_parameterConfig); + _builder.newLineIfNotEmpty(); + } + } + return _builder; + } + + @Override + protected String _assignmentEbnf(final AbstractElement it, final Assignment assignment, final AntlrOptions options, final boolean supportsActions) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _ebnf = this.ebnf(it, options, supportsActions); + _builder.append(_ebnf, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_1, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected String _assignmentEbnf(final CrossReference it, final Assignment assignment, final AntlrOptions options, final boolean supportsActions) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _crossrefEbnf = this.crossrefEbnf(it.getTerminal(), it, supportsActions); + _builder.append(_crossrefEbnf, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_1, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected String _assignmentEbnf(final Alternatives it, final Assignment assignment, final AntlrOptions options, final boolean supportsActions) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("("); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName, " "); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier, " "); + _builder.append(")"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_1, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected String _assignmentEbnf(final RuleCall it, final Assignment assignment, final AntlrOptions options, final boolean supportsActions) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _ruleName = this._grammarAccessExtensions.ruleName(it.getRule()); + _builder.append(_ruleName, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_1, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected String _crossrefEbnf(final RuleCall it, final CrossReference ref, final boolean supportActions) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _crossrefEbnf = this.crossrefEbnf(it.getRule(), it, ref, supportActions); + _builder.append(_crossrefEbnf, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_1, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected String _crossrefEbnf(final Keyword it, final CrossReference ref, final boolean supportActions) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("("); + _builder.newLine(); + _builder.append(" "); + _builder.append("{ before(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _superCrossrefEbnf = super._crossrefEbnf(it, ref, supportActions); + _builder.append(_superCrossrefEbnf, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ after(grammarAccess."); + String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess_1, " "); + _builder.append("); }"); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + _builder.newLine(); + return _builder.toString(); + } + + protected String crossrefEbnf(final TerminalRule it, final RuleCall call, final CrossReference ref, final boolean supportActions) { + return this._grammarAccessExtensions.ruleName(it); + } + + protected String crossrefEbnf(final EnumRule it, final RuleCall call, final CrossReference ref, final boolean supportActions) { + return this._grammarAccessExtensions.ruleName(it); + } + + protected String crossrefEbnf(final AbstractRule it, final RuleCall call, final CrossReference ref, final boolean supportActions) { + if (GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it))) { + return this._grammarAccessExtensions.ruleName(it); + } + throw new IllegalArgumentException(it.getName() + " is not a datatype rule"); + } + + @Override + protected String _ebnf2(final Alternatives it, final AntlrOptions options, final boolean supportActions) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + return _builder.toString(); + } + + @Override + protected String _ebnf2(final Assignment it, final AntlrOptions options, final boolean supportActions) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + return _builder.toString(); + } + + @Override + protected String _ebnf2(final Group it, final AntlrOptions options, final boolean supportActions) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + _builder.append("__0"); + return _builder.toString(); + } + + @Override + protected String _ebnf2(final UnorderedGroup it, final AntlrOptions options, final boolean supportActions) { + StringConcatenation _builder = new StringConcatenation(); + String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + _builder.append(_contentAssistRuleName); + _builder.append("__"); + String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_gaElementIdentifier); + return _builder.toString(); + } + + @Override + protected String _ebnf2(final RuleCall it, final AntlrOptions options, final boolean supportActions) { + return this._grammarAccessExtensions.ruleName(it.getRule()); + } + + @Override + protected boolean shouldBeSkipped(final TerminalRule it, final Grammar grammar) { + return false; + } +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.xtend deleted file mode 100644 index b11cb371df..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.xtend +++ /dev/null @@ -1,489 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.parser.antlr - -import com.google.inject.Inject -import org.eclipse.xtext.AbstractElement -import org.eclipse.xtext.AbstractRule -import org.eclipse.xtext.Alternatives -import org.eclipse.xtext.Assignment -import org.eclipse.xtext.CrossReference -import org.eclipse.xtext.EnumRule -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.Group -import org.eclipse.xtext.Keyword -import org.eclipse.xtext.ParserRule -import org.eclipse.xtext.RuleCall -import org.eclipse.xtext.TerminalRule -import org.eclipse.xtext.UnorderedGroup -import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrOptions -import org.eclipse.xtext.xtext.generator.parser.antlr.ContentAssistGrammarNaming - -import static extension org.eclipse.xtext.GrammarUtil.* -import static extension org.eclipse.xtext.xtext.generator.parser.antlr.AntlrGrammarGenUtil.* - -/** - * This implementation is strongly based on AntlrContentAssistGrammarGenerator but with a different base class. - * The following extension is supported: - * - * A datatype grammar rule containing only one ID terminal rule can be annotated - * with @KeywordRule annotation provided a list of words so only these words can - * be accepted by this rule. - * - * Example: - * - * /** - * * @KeywordRule(visible, invisible) - * * / - * VisibleKind returns VisibleKind: - * ID - * ; - * - * The above rule will accept only 'visible' and 'invisible' identifiers. - * This rule in ASMD is called a keyword rule because it is intended to replace - * usages of keywords which shall not be reserved words in the language. - * Reserved words are words that are not allowed to be used in identifiers. - * - * The above example can therefore replace the following enumeration: - * - * enum VisibleKind : - * VISIBLE = "visible" - * | INVISIBLE = "invisible" - * ; - * - * Please note that a corresponding value converter is needed. - * - * Implementation remark: - * - This template will insert validating semantic predicates in the rule - * - If the rule is used from an alternative a gated semantic predicate will - * be used in the alternative - * - Error messages will be adjusted correspondingly - */ -class AnnotationAwareAntlrContentAssistGrammarGenerator extends AbstractAnnotationAwareAntlrGrammarGenerator { - @Inject - extension ContentAssistGrammarNaming naming - - override protected getGrammarNaming() { - naming - } - - override protected isParserBackTracking(Grammar it, AntlrOptions options) { - super.isParserBackTracking(it, options) || !allPredicatedElements.isEmpty - } - - override protected compileParserImports(Grammar it, AntlrOptions options) ''' - «IF !combinedGrammar» - import java.util.Map; - import java.util.HashMap; - «ENDIF» - - import java.io.InputStream; - import org.eclipse.xtext.*; - import org.eclipse.xtext.parser.*; - import org.eclipse.xtext.parser.impl.*; - import org.eclipse.emf.ecore.util.EcoreUtil; - import org.eclipse.emf.ecore.EObject; - import org.eclipse.xtext.parser.antlr.XtextTokenStream; - import org.eclipse.xtext.parser.antlr.XtextTokenStream.HiddenTokens; - import «grammarNaming.getInternalParserSuperClass(it).name»; - import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.DFA; - import «grammarAccess.name»; - «super.compileParserImports(it, options)» - - ''' - - override protected compileParserMembers(Grammar it, AntlrOptions options) ''' - @«IF combinedGrammar»parser::«ENDIF»members { - «compileParserMemberDeclarations("protected")» - «IF !combinedGrammar» - private final Map tokenNameToValue = new HashMap(); - - { - «FOR kw: allKeywords.sort.sortBy[length]» - tokenNameToValue.put("«keywordHelper.getRuleName(kw)»", "'«kw.toStringInAntlrAction.replace('$', "\\u0024")»'"); - «ENDFOR» - } - «ENDIF» - - «compileParserSetTokenStreamMethod» - - public void setPredicates(«getSemanticPredicatesSimpleName» predicates) { - this.predicates = predicates; - } - - public void setGrammarAccess(«grammarAccess.simpleName» grammarAccess) { - this.grammarAccess = grammarAccess; - } - - public void setParserContext(ParserContext parserContext) { - this.parserContext = parserContext; - } - - @Override - protected Grammar getGrammar() { - return grammarAccess.getGrammar(); - } - - @Override - protected String getValueForTokenName(String tokenName) { - «IF combinedGrammar» - return tokenName; - «ELSE» - String result = tokenNameToValue.get(tokenName); - if (result == null) - result = tokenName; - return result; - «ENDIF» - } - } - ''' - - override protected compileRules(Grammar g, AntlrOptions options) ''' - «FOR rule : (g.allParserRules + g.allEnumRules + g.allAlternatives + g.allGroups + g.allUnorderedGroups + g.allAssignments).filter[containingRule.isCalled(g)]» - - «rule.compileRule(g, options)» - «ENDFOR» - «IF isCombinedGrammar» - «g.compileTerminalRules(options)» - «ENDIF» - ''' - - protected override dispatch compileRule(ParserRule it, Grammar grammar, AntlrOptions options) ''' - «IF isValidEntryRule» - // Entry rule «entryRuleName» - «entryRuleName» - «IF definesHiddenTokens» - @init { - «compileInitHiddenTokens(options)» - } - «ENDIF» - : - { before(grammarAccess.«originalElement.grammarElementAccess»); } - «ruleName» - { after(grammarAccess.«originalElement.grammarElementAccess»); } - EOF - ; - «IF definesHiddenTokens» - finally { - «compileRestoreHiddenTokens(options)» - } - «ENDIF» - «ENDIF» - - // Rule «originalElement.name» - «ruleName» - «IF hasNoBacktrackAnnotation» - // Enclosing rule was annotated with @NoBacktrack - options { backtrack=false; } - «ENDIF» - @init { - «compileInitHiddenTokens(options)» - int stackSize = keepStackSize(); - } - : - «IF hasValidatingPredicate»«generateValidatingPredicate»«ENDIF» - «alternatives.ebnf(options, false)» - ; - finally { - restoreStackSize(stackSize); - «compileRestoreHiddenTokens(options)» - } - ''' - - protected override dispatch compileRule(EnumRule it, Grammar grammar, AntlrOptions options) ''' - // Rule «originalElement.name» - «ruleName()» - @init { - int stackSize = keepStackSize(); - } - : - «alternatives.ebnf(options, false)» - ; - finally { - restoreStackSize(stackSize); - } - ''' - - protected def dispatch compileRule(Alternatives it, Grammar grammar, AntlrOptions options) ''' - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier» - @init { - int stackSize = keepStackSize(); - } - : - «FOR element : elements SEPARATOR '\n|'»«element.ebnf(options, false)»«ENDFOR» - ; - finally { - restoreStackSize(stackSize); - } - ''' - - protected def dispatch compileRule(Assignment it, Grammar grammar, AntlrOptions options) ''' - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier» - @init { - int stackSize = keepStackSize(); - } - : - «terminal.assignmentEbnf(it, options, false)» - ; - finally { - restoreStackSize(stackSize); - } - ''' - - protected def dispatch compileRule(UnorderedGroup it, Grammar grammar, AntlrOptions options) { - val hasMandatoryContent = elements.exists[!isOptionalCardinality] - - ''' - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier()» - @init { - int stackSize = keepStackSize(); - getUnorderedGroupHelper().enter(grammarAccess.«originalElement.gaRuleElementAccessor()»); - } - : - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier()»__0 - «IF hasMandatoryContent» - {getUnorderedGroupHelper().canLeave(grammarAccess.«originalElement.gaRuleElementAccessor()»)}? - «ELSE» - ? - «ENDIF» - ; - finally { - getUnorderedGroupHelper().leave(grammarAccess.«originalElement.gaRuleElementAccessor()»); - restoreStackSize(stackSize); - } - - «ruleImpl(grammar, options)» - - «ruleImpl(grammar, options, 0)» - ''' - } - - protected def dispatch compileRule(Group it, Grammar grammar, AntlrOptions options) ''' - «ruleImpl(grammar, options, 0)» - ''' - - protected def ruleImpl(UnorderedGroup it, Grammar grammar, AntlrOptions options) ''' - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier()»__Impl - @init { - int stackSize = keepStackSize(); - boolean selected = false; - } - : - ( - «FOR element : elements.indexed SEPARATOR '|'» - ( - {getUnorderedGroupHelper().canSelect(grammarAccess.«originalElement.gaRuleElementAccessor()», «element.key»)}?=>( - { - getUnorderedGroupHelper().select(grammarAccess.«originalElement.gaRuleElementAccessor()», «element.key»); - } - { - selected = true; - } - ( - «IF element.value.isMultipleCardinality» - ( - { before(grammarAccess.«element.value.originalElement.grammarElementAccess()»); } - («element.value.ebnf2(options, false)») - { after(grammarAccess.«element.value.originalElement.grammarElementAccess()»); } - ) - ( - { before(grammarAccess.«element.value.originalElement.grammarElementAccess()»); } - ((«element.value.ebnf2(options, false)»)=>«element.value.ebnf2(options, false)»)* - { after(grammarAccess.«element.value.originalElement.grammarElementAccess()»); } - ) - «ELSE» - { before(grammarAccess.«element.value.originalElement.grammarElementAccess()»); } - («element.value.ebnf2(options, false)») - { after(grammarAccess.«element.value.originalElement.grammarElementAccess()»); } - «ENDIF» - ) - ) - ) - «ENDFOR» - ) - ; - finally { - if (selected) - getUnorderedGroupHelper().returnFromSelection(grammarAccess.«originalElement.gaRuleElementAccessor()»); - restoreStackSize(stackSize); - } - ''' - - protected def CharSequence ruleImpl(UnorderedGroup it, Grammar grammar, AntlrOptions options, int index) ''' - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier()»__«index» - @init { - int stackSize = keepStackSize(); - } - : - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier()»__Impl - «IF elements.size > index + 1» - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier()»__«index + 1»? - «ENDIF» - ; - finally { - restoreStackSize(stackSize); - } - - «IF elements.size > index + 1» - «ruleImpl(grammar, options, index + 1)» - «ENDIF» - ''' - - protected def CharSequence ruleImpl(Group it, Grammar grammar, AntlrOptions options, int index) ''' - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier»__«index» - @init { - int stackSize = keepStackSize(); - } - : - «containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier»__«index»__Impl - «IF elements.size > index + 1» - «containingRule().contentAssistRuleName»__«originalElement.gaElementIdentifier»__«index + 1» - «ENDIF» - ; - finally { - restoreStackSize(stackSize); - } - - «containingRule().contentAssistRuleName»__«originalElement.gaElementIdentifier»__«index»__Impl - @init { - int stackSize = keepStackSize(); - } - : - «elements.get(index).ebnf(options, false)» - ; - finally { - restoreStackSize(stackSize); - } - - «IF elements.size > index + 1» - «ruleImpl(grammar, options, index + 1)» - «ENDIF» - ''' - -// TODO - protected override ebnf(AbstractElement it, AntlrOptions options, boolean supportsActions) ''' - «IF !isOptionalCardinality() && isMultipleCardinality()» - ( - ( - { before(grammarAccess.«originalElement.grammarElementAccess»«paramConfig»); } - («ebnf2(options, supportsActions)») - { after(grammarAccess.«originalElement.grammarElementAccess»«paramConfig»); } - ) - ( - { before(grammarAccess.«originalElement.grammarElementAccess»«paramConfig»); } - («ebnf2(options, supportsActions)»)* - { after(grammarAccess.«originalElement.grammarElementAccess»«paramConfig»); } - ) - ) - «ELSE» - ( - { before(grammarAccess.«originalElement.grammarElementAccess»«paramConfig»); } - «IF mustBeParenthesized()»(«ebnf2(options, supportsActions)»)«ELSE»«ebnf2(options, supportsActions)»«ENDIF»«cardinality» - { after(grammarAccess.«originalElement.grammarElementAccess»«paramConfig»); } - ) - «ENDIF» - ''' - - protected def paramConfig(AbstractElement it) ''' - «IF containingRule.alternatives === it && ParserRule.isInstance(containingRule) && !(containingRule.originalElement as ParserRule).parameters.isEmpty» - , «(containingRule as ParserRule).parameterConfig» - «ENDIF» - ''' - - protected override dispatch assignmentEbnf(AbstractElement it, Assignment assignment, AntlrOptions options, boolean supportsActions) ''' - ( - { before(grammarAccess.«originalElement.grammarElementAccess»); } - «ebnf(options, supportsActions)» - { after(grammarAccess.«originalElement.grammarElementAccess»); } - ) - ''' - - protected override dispatch assignmentEbnf(CrossReference it, Assignment assignment, AntlrOptions options, boolean supportsActions) ''' - ( - { before(grammarAccess.«originalElement.grammarElementAccess»); } - «terminal.crossrefEbnf(it, supportsActions)» - { after(grammarAccess.«originalElement.grammarElementAccess»); } - ) - ''' - - protected override dispatch assignmentEbnf(Alternatives it, Assignment assignment, AntlrOptions options, boolean supportsActions) ''' - ( - { before(grammarAccess.«originalElement.grammarElementAccess»); } - («containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier») - { after(grammarAccess.«originalElement.grammarElementAccess»); } - ) - ''' - - protected override dispatch assignmentEbnf(RuleCall it, Assignment assignment, AntlrOptions options, boolean supportsActions) ''' - ( - { before(grammarAccess.«originalElement.grammarElementAccess»); } - «rule.ruleName» - { after(grammarAccess.«originalElement.grammarElementAccess»); } - ) - ''' - - protected dispatch override crossrefEbnf(RuleCall it, CrossReference ref, boolean supportActions) ''' - ( - { before(grammarAccess.«originalElement.grammarElementAccess»); } - «rule.crossrefEbnf(it, ref, supportActions)» - { after(grammarAccess.«originalElement.grammarElementAccess»); } - ) - ''' - - protected dispatch override crossrefEbnf(Keyword it, CrossReference ref, boolean supportActions) ''' - ( - { before(grammarAccess.«originalElement.grammarElementAccess»); } - «super._crossrefEbnf(it, ref, supportActions)» - { after(grammarAccess.«originalElement.grammarElementAccess»); } - ) - ''' - - protected dispatch def crossrefEbnf(TerminalRule it, RuleCall call, CrossReference ref, boolean supportActions) { - ruleName - } - - protected dispatch def crossrefEbnf(EnumRule it, RuleCall call, CrossReference ref, boolean supportActions) { - ruleName - } - - protected def dispatch crossrefEbnf(AbstractRule it, RuleCall call, CrossReference ref, boolean supportActions) { - if (originalElement.isDatatypeRule) { - return ruleName - } - throw new IllegalArgumentException(it.name + " is not a datatype rule") - } - - override protected dispatch ebnf2(Alternatives it, AntlrOptions options, boolean supportActions) { - '''«containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier»''' - } - - override protected dispatch ebnf2(Assignment it, AntlrOptions options, boolean supportActions) { - '''«containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier»''' - } - - override protected dispatch ebnf2(Group it, AntlrOptions options, boolean supportActions) { - '''«containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier»__0''' - } - - override protected dispatch ebnf2(UnorderedGroup it, AntlrOptions options, boolean supportActions) { - '''«containingRule.contentAssistRuleName»__«originalElement.gaElementIdentifier»''' - } - - override protected dispatch ebnf2(RuleCall it, AntlrOptions options, boolean supportActions) { - rule.ruleName - } - - override protected shouldBeSkipped(TerminalRule it, Grammar grammar) { - false - } - -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java new file mode 100644 index 0000000000..d65da02e66 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java @@ -0,0 +1,1260 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.generator.parser.antlr; + +import java.util.List; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtext.AbstractElement; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.Action; +import org.eclipse.xtext.Assignment; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.EnumLiteralDeclaration; +import org.eclipse.xtext.EnumRule; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.ParserRule; +import org.eclipse.xtext.RuleCall; +import org.eclipse.xtext.TerminalRule; +import org.eclipse.xtext.UnorderedGroup; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.ListExtensions; +import org.eclipse.xtext.xbase.lib.StringExtensions; +import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrGrammarGenUtil; +import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrOptions; +import org.eclipse.xtext.xtext.generator.parser.antlr.GrammarNaming; + +import com.google.common.collect.Iterables; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * This implementation is strongly based on AntlrGrammarGenerator but with a different base class. + * The following extension is supported: + * + * A datatype grammar rule containing only one ID terminal rule can be annotated + * with @KeywordRule annotation provided a list of words so only these words can + * be accepted by this rule. + * + * Example: + * + * /** + * * @KeywordRule(visible, invisible) + * * / + * VisibleKind returns VisibleKind: + * ID + * ; + * + * The above rule will accept only 'visible' and 'invisible' identifiers. + * This rule in ASMD is called a keyword rule because it is intended to replace + * usages of keywords which shall not be reserved words in the language. + * Reserved words are words that are not allowed to be used in identifiers. + * + * The above example can therefore replace the following enumeration: + * + * enum VisibleKind : + * VISIBLE = "visible" + * | INVISIBLE = "invisible" + * ; + * + * Please note that a corresponding value converter is needed. + * + * Implementation remark: + * - This template will insert validating semantic predicates in the rule + * - If the rule is used from an alternative a gated semantic predicate will + * be used in the alternative + * - Error messages will be adjusted correspondingly + */ +@Singleton +public class AnnotationAwareAntlrGrammarGenerator extends AbstractAnnotationAwareAntlrGrammarGenerator { + + @Inject + private GrammarNaming naming; + + private String lexerSuperClassName = ""; + + public void setLexerSuperClassName(final String lexerSuperClassName) { + this.lexerSuperClassName = lexerSuperClassName; + } + + @Override + protected GrammarNaming getGrammarNaming() { + return this.naming; + } + + @Override + protected String compileParserImports(final Grammar it, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.*;"); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.parser.*;"); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.parser.impl.*;"); + _builder.newLine(); + _builder.append("import org.eclipse.emf.ecore.util.EcoreUtil;"); + _builder.newLine(); + _builder.append("import org.eclipse.emf.ecore.EObject;"); + _builder.newLine(); + { + boolean _isEmpty = GrammarUtil.allEnumRules(it).isEmpty(); + boolean _not = (!_isEmpty); + if (_not) { + _builder.append("import org.eclipse.emf.common.util.Enumerator;"); + _builder.newLine(); + } + } + _builder.append("import "); + String _name = this.getGrammarNaming().getInternalParserSuperClass(it).getName(); + _builder.append(_name); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + _builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream;"); + _builder.newLine(); + _builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream.HiddenTokens;"); + _builder.newLine(); + { + if ((!IterableExtensions.isEmpty(Iterables.filter(Iterables.concat(ListExtensions.map(GrammarUtil.allParserRules(it), (ParserRule it_1) -> EcoreUtil2.eAllContentsAsList(it_1))), UnorderedGroup.class))) && options.isBacktrack()) { + _builder.append("import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper.UnorderedGroupState;"); + _builder.newLine(); + } + } + _builder.append("import org.eclipse.xtext.parser.antlr.AntlrDatatypeRuleToken;"); + _builder.newLine(); + _builder.append("import "); + String _name_1 = this._grammarAccessExtensions.getGrammarAccess(it).getName(); + _builder.append(_name_1); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + String _compileParserImports = super.compileParserImports(it, options); + _builder.append(_compileParserImports); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected String compileParserMembers(final Grammar it, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + _builder.newLine(); + _builder.append("@"); + { + boolean _isCombinedGrammar = this.isCombinedGrammar(); + if (_isCombinedGrammar) { + _builder.append("parser::"); + } + } + _builder.append("members {"); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + { + boolean _isBacktrack = options.isBacktrack(); + if (_isBacktrack) { + _builder.append("/*"); + _builder.newLine(); + _builder.append(" "); + _builder.append("This grammar contains a lot of empty actions to work around a bug in ANTLR."); + _builder.newLine(); + _builder.append(" "); + _builder.append("Otherwise the ANTLR tool will create synpreds that cannot be compiled in some rare cases."); + _builder.newLine(); + _builder.append("*/"); + _builder.newLine(); + _builder.newLine(); + } + } + _builder.append(" "); + CharSequence _compileParserMemberDeclarations = this.compileParserMemberDeclarations(it, "private"); + _builder.append(_compileParserMemberDeclarations, " "); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public "); + String _simpleName = this.naming.getInternalParserClass(it).getSimpleName(); + _builder.append(_simpleName, " "); + _builder.append("(TokenStream input, "); + String _simpleName_1 = this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(); + _builder.append(_simpleName_1, " "); + _builder.append(" grammarAccess, ParserContext parserContext, "); + String _semanticPredicatesSimpleName = this.predicatesNaming.getSemanticPredicatesSimpleName(it); + _builder.append(_semanticPredicatesSimpleName, " "); + _builder.append(" predicates) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("this(input);"); + _builder.newLine(); + _builder.append(" "); + _builder.append("this.grammarAccess = grammarAccess;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("this.predicates = predicates;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("this.parserContext = parserContext;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("parserContext.setTokenStream(input);"); + _builder.newLine(); + _builder.append(" "); + _builder.append("registerRules(grammarAccess.getGrammar());"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + CharSequence _compileParserSetTokenStreamMethod = this.compileParserSetTokenStreamMethod(); + _builder.append(_compileParserSetTokenStreamMethod, " "); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected String getFirstRuleName() {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("return \""); + String _name2 = AntlrGrammarGenUtil.getOriginalElement(IterableExtensions.head(GrammarUtil.allParserRules(it))).getName(); + _builder.append(_name2, " "); + _builder.append("\";"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected "); + String _simpleName_2 = this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(); + _builder.append(_simpleName_2, " "); + _builder.append(" getGrammarAccess() {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("return grammarAccess;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected String compileRuleCatch(final Grammar it, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + _builder.newLine(); + _builder.append("@rulecatch {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("catch (RecognitionException re) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("recover(input,re);"); + _builder.newLine(); + _builder.append(" "); + _builder.append("appendSkippedTokens();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } + + @Override + protected boolean shouldBeSkipped(final TerminalRule it, final Grammar grammar) { + return false; + } + + @Override + protected CharSequence _compileRule(final ParserRule it, final Grammar grammar, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _isValidEntryRule = AntlrGrammarGenUtil.isValidEntryRule(it); + if (_isValidEntryRule) { + String _compileEntryRule = this.compileEntryRule(it, grammar, options); + _builder.append(_compileEntryRule); + _builder.newLineIfNotEmpty(); + } + } + _builder.newLine(); + String _compileEBNF = this.compileEBNF(it, options); + _builder.append(_compileEBNF); + _builder.newLineIfNotEmpty(); + return _builder; + } + + protected String compileEntryRule(final ParserRule it, final Grammar grammar, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("// Entry rule "); + String _entryRuleName = this._grammarAccessExtensions.entryRuleName(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_entryRuleName); + _builder.newLineIfNotEmpty(); + String _entryRuleName_1 = this._grammarAccessExtensions.entryRuleName(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_entryRuleName_1); + _builder.append(" returns "); + String _compileEntryReturns = this.compileEntryReturns(it, options); + _builder.append(_compileEntryReturns); + CharSequence _compileEntryInit = this.compileEntryInit(it, options); + _builder.append(_compileEntryInit); + _builder.append(":"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ "); + CharSequence _newCompositeNode = this.newCompositeNode(it); + _builder.append(_newCompositeNode, " "); + _builder.append(" }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("iv_"); + String _ruleName = this._grammarAccessExtensions.ruleName(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_ruleName, " "); + _builder.append("="); + String _ruleName_1 = this._grammarAccessExtensions.ruleName(it); + _builder.append(_ruleName_1, " "); + String _defaultArgumentList = AntlrGrammarGenUtil.getDefaultArgumentList(it); + _builder.append(_defaultArgumentList, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("{ $current=$iv_"); + String _ruleName_2 = this._grammarAccessExtensions.ruleName(it); + _builder.append(_ruleName_2, " "); + _builder.append(".current"); + { + boolean _isDatatypeRule = GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it)); + if (_isDatatypeRule) { + _builder.append(".getText()"); + } + } + _builder.append("; }"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("EOF;"); + _builder.newLine(); + CharSequence _compileEntryFinally = this.compileEntryFinally(it, options); + _builder.append(_compileEntryFinally); + _builder.newLineIfNotEmpty(); + return _builder.toString(); + } + + protected String compileEntryReturns(final ParserRule it, final AntlrOptions options) { + boolean _isDatatypeRule = GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it)); + if (_isDatatypeRule) { + return "[String current=null]"; + } else { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("["); + String _currentType = this.getCurrentType(); + _builder.append(_currentType); + _builder.append(" current=null]"); + return _builder.toString(); + } + } + + @Override + protected String compileInit(final AbstractRule it, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + { + if (it instanceof ParserRule) { + boolean _isPassCurrentIntoFragment = this.isPassCurrentIntoFragment(); + boolean _not = (!_isPassCurrentIntoFragment); + String _parameterList = AntlrGrammarGenUtil.getParameterList((ParserRule) it, Boolean.valueOf(_not), this.getCurrentType()); + _builder.append(_parameterList); + } + } + _builder.append(" returns "); + CharSequence _compileReturns = this.compileReturns(it, options); + _builder.append(_compileReturns); + _builder.newLineIfNotEmpty(); + { + boolean _hasNoBacktrackAnnotation = this.annotations.hasNoBacktrackAnnotation(it); + if (_hasNoBacktrackAnnotation) { + _builder.append("// Enclosing rule was annotated with @NoBacktrack"); + _builder.newLine(); + _builder.append("options { backtrack=false; }"); + _builder.newLine(); + } + } + _builder.append("@init {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("enterRule();"); + _builder.newLine(); + _builder.append(" "); + CharSequence _compileInitHiddenTokens = this.compileInitHiddenTokens(it, options); + _builder.append(_compileInitHiddenTokens, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + CharSequence _compileInitUnorderedGroups = this.compileInitUnorderedGroups(it, options); + _builder.append(_compileInitUnorderedGroups, " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + _builder.append("@after {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("leaveRule();"); + _builder.newLine(); + _builder.append("}"); + return _builder.toString(); + } + + protected CharSequence compileReturns(final AbstractRule it, final AntlrOptions options) { + if (it instanceof EnumRule) { + return "[Enumerator current=null]"; + } + if (it instanceof ParserRule) { + if (GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement((ParserRule) it))) { + return "[AntlrDatatypeRuleToken current=new AntlrDatatypeRuleToken()]"; + } + if (GrammarUtil.isEObjectFragmentRule(AntlrGrammarGenUtil.getOriginalElement((ParserRule) it))) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("["); + _builder.append(this.getCurrentType()); + _builder.append(" current=in_current]"); + return _builder; + } + StringConcatenation _builder2 = new StringConcatenation(); + _builder2.append("["); + _builder2.append(this.getCurrentType()); + _builder2.append(" current=null]"); + return _builder2; + } + throw new IllegalStateException("Unexpected rule: " + it); + } + + @Override + protected String _dataTypeEbnf2(final Keyword it, final boolean supportActions) { + if (supportActions) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("kw="); + String __dataTypeEbnf2 = super._dataTypeEbnf2(it, supportActions); + _builder.append(__dataTypeEbnf2); + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("$current.merge(kw);"); + _builder.newLine(); + _builder.append(" "); + CharSequence _newLeafNode = this.newLeafNode(it, "kw"); + _builder.append(_newLeafNode, " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } else { + return super._dataTypeEbnf2(it, supportActions); + } + } + + @Override + protected String _ebnf2(final Action it, final AntlrOptions options, final boolean supportActions) { + if (supportActions) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _isBacktrack = options.isBacktrack(); + if (_isBacktrack) { + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("/* */"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + } + } + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("$current = forceCreateModelElement"); + { + String _feature = it.getFeature(); + if (_feature != null) { + _builder.append("And"); + String _firstUpper = StringExtensions.toFirstUpper(this._grammarAccessExtensions.setOrAdd(it)); + _builder.append(_firstUpper, " "); + } + } + _builder.append("("); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + _builder.append(","); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("$current);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } else { + return super._ebnf2(it, options, supportActions); + } + } + + @Override + protected String _ebnf2(final Keyword it, final AntlrOptions options, final boolean supportActions) { + if (!supportActions) { + return super._ebnf2(it, options, supportActions); + } else if (GrammarUtil.isAssigned(it)) { + StringConcatenation _builder = new StringConcatenation(); + String __ebnf2 = super._ebnf2(it, options, supportActions); + _builder.append(__ebnf2); + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + CharSequence _newLeafNode = this.newLeafNode(it, this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(it), it)); + _builder.append(_newLeafNode, " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } else { + StringConcatenation _builder_1 = new StringConcatenation(); + String _localVar = this._grammarAccessExtensions.localVar(it); + _builder_1.append(_localVar); + _builder_1.append("="); + String __ebnf2_1 = super._ebnf2(it, options, supportActions); + _builder_1.append(__ebnf2_1); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("{"); + _builder_1.newLine(); + _builder_1.append(" "); + CharSequence _newLeafNode_1 = this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)); + _builder_1.append(_newLeafNode_1, " "); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("}"); + _builder_1.newLine(); + return _builder_1.toString(); + } + } + + @Override + protected String _ebnf2(final EnumLiteralDeclaration it, final AntlrOptions options, final boolean supportActions) { + if (!supportActions) { + return super._ebnf2(it, options, supportActions); + } else { + StringConcatenation _builder = new StringConcatenation(); + String _localVar = this._grammarAccessExtensions.localVar(it); + _builder.append(_localVar); + _builder.append("="); + String __ebnf2 = super._ebnf2(it, options, supportActions); + _builder.append(__ebnf2); + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("$current = grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess, " "); + _builder.append(".getEnumLiteral().getInstance();"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + CharSequence _newLeafNode = this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)); + _builder.append(_newLeafNode, " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } + } + + @Override + protected String crossrefEbnf(final AbstractRule it, final RuleCall call, final CrossReference ref, final boolean supportActions) { + if (supportActions) { + if (it instanceof EnumRule || it instanceof ParserRule) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + CharSequence _newCompositeNode = this.newCompositeNode(ref); + _builder.append(_newCompositeNode, " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + String _ruleName = this._grammarAccessExtensions.ruleName(it); + _builder.append(_ruleName); + String _argumentList = AntlrGrammarGenUtil.getArgumentList(call, this.isPassCurrentIntoFragment(), (!supportActions)); + _builder.append(_argumentList); + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("afterParserOrEnumRuleCall();"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } else if (it instanceof TerminalRule) { + StringConcatenation _builder_1 = new StringConcatenation(); + String _localVar = this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(ref)); + _builder_1.append(_localVar); + _builder_1.append("="); + String _ruleName_1 = this._grammarAccessExtensions.ruleName(it); + _builder_1.append(_ruleName_1); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("{"); + _builder_1.newLine(); + _builder_1.append(" "); + CharSequence _newLeafNode = this.newLeafNode(ref, this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(ref))); + _builder_1.append(_newLeafNode, " "); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("}"); + _builder_1.newLine(); + return _builder_1.toString(); + } else { + throw new IllegalStateException("crossrefEbnf is not supported for " + it); + } + } else { + return super.crossrefEbnf(it, call, ref, supportActions); + } + } + + @Override + protected String _assignmentEbnf(final AbstractElement it, final Assignment assignment, final AntlrOptions options, final boolean supportActions) { + if (supportActions) { + StringConcatenation _builder = new StringConcatenation(); + String _localVar = this._grammarAccessExtensions.localVar(assignment, it); + _builder.append(_localVar); + _builder.append("="); + String __assignmentEbnf = super._assignmentEbnf(it, assignment, options, supportActions); + _builder.append(__assignmentEbnf); + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if ($current==null) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("$current = "); + CharSequence _createModelElement = this.createModelElement(assignment); + _builder.append(_createModelElement, " "); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + String _setOrAdd = this._grammarAccessExtensions.setOrAdd(assignment); + _builder.append(_setOrAdd, " "); + _builder.append("WithLastConsumed($current, \""); + String _feature = assignment.getFeature(); + _builder.append(_feature, " "); + _builder.append("\", "); + String _localVar_1 = this._grammarAccessExtensions.localVar(assignment, it); + _builder.append(_localVar_1, " "); + { + boolean _isBooleanAssignment = GrammarUtil.isBooleanAssignment(assignment); + if (_isBooleanAssignment) { + _builder.append(" != null"); + } + } + _builder.append(", "); + CharSequence _stringLiteral = this._grammarAccessExtensions.toStringLiteral(assignment.getTerminal()); + _builder.append(_stringLiteral, " "); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } else { + return super._assignmentEbnf(it, assignment, options, supportActions); + } + } + + @Override + protected boolean isPassCurrentIntoFragment() { + return true; + } + + protected CharSequence createModelElement(final EObject grammarElement) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("createModelElement(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingParserRule(grammarElement))); + _builder.append(_grammarElementAccess); + _builder.append(")"); + return _builder; + } + + protected CharSequence createModelElementForParent(final EObject grammarElement) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("createModelElementForParent(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingParserRule(grammarElement))); + _builder.append(_grammarElementAccess); + _builder.append(")"); + return _builder; + } + + protected CharSequence newCompositeNode(final EObject it) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("newCompositeNode(grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess); + _builder.append(");"); + return _builder; + } + + protected CharSequence newLeafNode(final EObject it, final String token) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("newLeafNode("); + _builder.append(token); + _builder.append(", grammarAccess."); + String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + _builder.append(_grammarElementAccess); + _builder.append(");"); + return _builder; + } + + /** + * Add gated predicate, if necessary, before the action preceding the rule call. + */ + @Override + protected String _dataTypeEbnf2(final RuleCall it, final boolean supportActions) { + if (supportActions) { + AbstractRule _rule = it.getRule(); + if ((_rule instanceof EnumRule && GrammarUtil.isAssigned(it)) || (_rule instanceof ParserRule && GrammarUtil.isAssigned(it))) { + return super._dataTypeEbnf2(it, supportActions); + } else if (_rule instanceof EnumRule || _rule instanceof ParserRule) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _isGatedPredicateRequired = this.annotations.isGatedPredicateRequired(it); + if (_isGatedPredicateRequired) { + _builder.append(this.annotations.generateGatedPredicate(it)); + } + } + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append(this.newCompositeNode(it), " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + _builder.append(this._grammarAccessExtensions.localVar(it)); + _builder.append("="); + _builder.append(super._dataTypeEbnf2(it, supportActions)); + _builder.append(AntlrGrammarGenUtil.getArgumentList(it, this.isPassCurrentIntoFragment(), (!supportActions))); + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("$current.merge("); + _builder.append(this._grammarAccessExtensions.localVar(it), " "); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("afterParserOrEnumRuleCall();"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } else if (_rule instanceof TerminalRule) { + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append(this._grammarAccessExtensions.localVar(it)); + _builder_1.append("="); + _builder_1.append(super._dataTypeEbnf2(it, supportActions)); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("{"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("$current.merge("); + _builder_1.append(this._grammarAccessExtensions.localVar(it), " "); + _builder_1.append(");"); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append("{"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)), " "); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("}"); + _builder_1.newLine(); + return _builder_1.toString(); + } else { + return super._dataTypeEbnf2(it, supportActions); + } + } else { + return super._dataTypeEbnf2(it, supportActions); + } + } + + /** + * Inserts validating predicate only. Gated predicates will be inserted in alternatives if needed. + */ + @Override + protected String compileEBNF(final AbstractRule it, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("// Rule "); + String _name = AntlrGrammarGenUtil.getOriginalElement(it).getName(); + _builder.append(_name); + _builder.newLineIfNotEmpty(); + String _ruleName = this._grammarAccessExtensions.ruleName(it); + _builder.append(_ruleName); + String _compileInit = this.compileInit(it, options); + _builder.append(_compileInit); + _builder.append(":"); + _builder.newLineIfNotEmpty(); + { + if ((it instanceof ParserRule) && GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it))) { + _builder.append(" "); + { + boolean _hasValidatingPredicate = this.annotations.hasValidatingPredicate(it); + if (_hasValidatingPredicate) { + _builder.append(this.annotations.generateValidatingPredicate(it), " "); + } + } + _builder.newLineIfNotEmpty(); + _builder.append(" "); + String _dataTypeEbnf = this.dataTypeEbnf(it.getAlternatives(), true); + _builder.append(_dataTypeEbnf, " "); + _builder.newLineIfNotEmpty(); + } else { + _builder.append(" "); + String _ebnf = this.ebnf(it.getAlternatives(), options, true); + _builder.append(_ebnf, " "); + _builder.newLineIfNotEmpty(); + } + } + _builder.append(";"); + _builder.newLine(); + String _compileFinally = this.compileFinally(it, options); + _builder.append(_compileFinally); + _builder.newLineIfNotEmpty(); + return _builder.toString(); + } + + @Override + protected String dataTypeEbnf(final AbstractElement it, final boolean supportActions) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _mustBeParenthesized = this.mustBeParenthesized(it); + if (_mustBeParenthesized) { + _builder.append("("); + _builder.newLineIfNotEmpty(); + { + boolean _hasNoBacktrackAnnotation = this.annotations.hasNoBacktrackAnnotation(it); + if (_hasNoBacktrackAnnotation) { + _builder.append(" "); + _builder.append("// Enclosing rule was annotated with @NoBacktrack"); + _builder.newLine(); + _builder.append(" "); + _builder.append("options { backtrack=false; }:"); + _builder.newLine(); + } + } + _builder.append(" "); + String _dataTypeEbnfPredicate = this.dataTypeEbnfPredicate(it); + _builder.append(_dataTypeEbnfPredicate, " "); + String _dataTypeEbnf2 = this.dataTypeEbnf2(it, supportActions); + _builder.append(_dataTypeEbnf2, " "); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + } else { + String _dataTypeEbnf2_1 = this.dataTypeEbnf2(it, supportActions); + _builder.append(_dataTypeEbnf2_1); + } + } + String _cardinality = it.getCardinality(); + _builder.append(_cardinality); + _builder.newLineIfNotEmpty(); + return _builder.toString(); + } + + @Override + protected String ebnf(final AbstractElement it, final AntlrOptions options, final boolean supportActions) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _mustBeParenthesized = this.mustBeParenthesized(it); + if (_mustBeParenthesized) { + _builder.append("("); + _builder.newLineIfNotEmpty(); + { + boolean _hasNoBacktrackAnnotation = this.annotations.hasNoBacktrackAnnotation(it); + if (_hasNoBacktrackAnnotation) { + _builder.append(" "); + _builder.append("// Enclosing rule was annotated with @NoBacktrack"); + _builder.newLine(); + _builder.append(" "); + _builder.append("options { backtrack=false; }:"); + _builder.newLine(); + } + } + _builder.append(" "); + String _ebnfPredicate = this.ebnfPredicate(it, options); + _builder.append(_ebnfPredicate, " "); + String _ebnf2 = this.ebnf2(it, options, supportActions); + _builder.append(_ebnf2, " "); + _builder.newLineIfNotEmpty(); + _builder.append(")"); + } else { + String _ebnf2_1 = this.ebnf2(it, options, supportActions); + _builder.append(_ebnf2_1); + } + } + String _cardinality = it.getCardinality(); + _builder.append(_cardinality); + _builder.newLineIfNotEmpty(); + return _builder.toString(); + } + + /** + * Add gated predicate, if necessary, before the action preceding the assignment. + */ + @Override + protected String _assignmentEbnf(final RuleCall it, final Assignment assignment, final AntlrOptions options, final boolean supportActions) { + if (supportActions) { + AbstractRule _rule = it.getRule(); + if (_rule instanceof EnumRule || _rule instanceof ParserRule) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _isGatedPredicateRequired = this.annotations.isGatedPredicateRequired(it); + if (_isGatedPredicateRequired) { + _builder.append(this.annotations.generateGatedPredicate(it)); + } + } + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append(this.newCompositeNode(it), " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + _builder.append(this._grammarAccessExtensions.localVar(assignment, it)); + _builder.append("="); + _builder.append(super._assignmentEbnf(it, assignment, options, supportActions)); + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if ($current==null) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("$current = "); + _builder.append(this.createModelElementForParent(assignment), " "); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append(this._grammarAccessExtensions.setOrAdd(assignment), " "); + _builder.append("("); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("$current,"); + _builder.newLine(); + _builder.append(" "); + _builder.append("\""); + _builder.append(assignment.getFeature(), " "); + _builder.append("\","); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(this._grammarAccessExtensions.localVar(assignment, it), " "); + { + boolean _isBooleanAssignment = GrammarUtil.isBooleanAssignment(assignment); + if (_isBooleanAssignment) { + _builder.append(" != null"); + } + } + _builder.append(","); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(this._grammarAccessExtensions.toStringLiteral(it), " "); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("afterParserOrEnumRuleCall();"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } else if (_rule instanceof TerminalRule) { + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append(this._grammarAccessExtensions.localVar(assignment, it)); + _builder_1.append("="); + _builder_1.append(super._assignmentEbnf(it, assignment, options, supportActions)); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("{"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(assignment, it)), " "); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append("{"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("if ($current==null) {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("$current = "); + _builder_1.append(this.createModelElement(assignment), " "); + _builder_1.append(";"); + _builder_1.newLineIfNotEmpty(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append(this._grammarAccessExtensions.setOrAdd(assignment), " "); + _builder_1.append("WithLastConsumed("); + _builder_1.newLineIfNotEmpty(); + _builder_1.append(" "); + _builder_1.append("$current,"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("\""); + _builder_1.append(assignment.getFeature(), " "); + _builder_1.append("\","); + _builder_1.newLineIfNotEmpty(); + _builder_1.append(" "); + _builder_1.append(this._grammarAccessExtensions.localVar(assignment, it), " "); + { + boolean _isBooleanAssignment2 = GrammarUtil.isBooleanAssignment(assignment); + if (_isBooleanAssignment2) { + _builder_1.append(" != null"); + } + } + _builder_1.append(","); + _builder_1.newLineIfNotEmpty(); + _builder_1.append(" "); + _builder_1.append(this._grammarAccessExtensions.toStringLiteral(it), " "); + _builder_1.append(");"); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("}"); + _builder_1.newLine(); + return _builder_1.toString(); + } else { + throw new IllegalStateException("assignmentEbnf is not supported for " + it); + } + } else { + return super._assignmentEbnf(it, assignment, options, supportActions); + } + } + + /** + * Add gated predicate, if necessary, before the action preceding the cross reference. + */ + @Override + protected String _assignmentEbnf(final CrossReference it, final Assignment assignment, final AntlrOptions options, final boolean supportActions) { + if (supportActions) { + StringConcatenation _builder = new StringConcatenation(); + { + boolean _isGatedPredicateRequired = this.annotations.isGatedPredicateRequired(it); + if (_isGatedPredicateRequired) { + _builder.append(this.annotations.generateGatedPredicate(it)); + } + } + _builder.newLineIfNotEmpty(); + { + boolean _isBacktrack = options.isBacktrack(); + if (_isBacktrack) { + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("/* */"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + } + } + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if ($current==null) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("$current = "); + _builder.append(this.createModelElement(assignment), " "); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.append(super._assignmentEbnf(it, assignment, options, supportActions)); + return _builder.toString(); + } else { + return super._assignmentEbnf(it, assignment, options, supportActions); + } + } + + /** + * Add gated predicate, if necessary, before the action preceding the rule call. + */ + @Override + protected String _ebnf2(final RuleCall it, final AntlrOptions options, final boolean supportActions) { + if (!supportActions) { + return super._ebnf2(it, options, supportActions); + } else { + AbstractRule rule = it.getRule(); + if ((rule instanceof EnumRule && GrammarUtil.isAssigned(it)) || (rule instanceof ParserRule && GrammarUtil.isAssigned(it))) { + return super._ebnf2(it, options, supportActions); + } else if (rule instanceof EnumRule || (rule instanceof ParserRule && GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement((ParserRule) rule)))) { + StringConcatenation _builder = new StringConcatenation(); + { + if (this.annotations.isGatedPredicateRequired(it)) { + _builder.append(this.annotations.generateGatedPredicate(it)); + } + } + _builder.newLineIfNotEmpty(); + { + if (options.isBacktrack()) { + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("/* */"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + } + } + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append(this.newCompositeNode(it), " "); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + _builder.append(super._ebnf2(it, options, supportActions)); + _builder.newLineIfNotEmpty(); + _builder.append("{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("afterParserOrEnumRuleCall();"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + return _builder.toString(); + } else if (rule instanceof ParserRule) { + StringConcatenation _builder_1 = new StringConcatenation(); + { + if (this.annotations.isGatedPredicateRequired(it)) { + _builder_1.append(this.annotations.generateGatedPredicate(it)); + } + } + _builder_1.newLineIfNotEmpty(); + { + if (options.isBacktrack()) { + _builder_1.append("{"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("/* */"); + _builder_1.newLine(); + _builder_1.append("}"); + _builder_1.newLine(); + } + } + _builder_1.append("{"); + _builder_1.newLine(); + { + if (GrammarUtil.isEObjectFragmentRuleCall(it)) { + _builder_1.append(" "); + _builder_1.append("if ($current==null) {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("$current = "); + _builder_1.append(this.createModelElement(it), " "); + _builder_1.append(";"); + _builder_1.newLineIfNotEmpty(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + } + } + _builder_1.append(" "); + _builder_1.append(this.newCompositeNode(it), " "); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("}"); + _builder_1.newLine(); + String _localVar = this._grammarAccessExtensions.localVar(it); + _builder_1.append(_localVar); + _builder_1.append("="); + _builder_1.append(super._ebnf2(it, options, supportActions)); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("{"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("$current = $"); + _builder_1.append(_localVar, " "); + _builder_1.append(".current;"); + _builder_1.newLineIfNotEmpty(); + _builder_1.append(" "); + _builder_1.append("afterParserOrEnumRuleCall();"); + _builder_1.newLine(); + _builder_1.append("}"); + _builder_1.newLine(); + return _builder_1.toString(); + } else if (rule instanceof TerminalRule) { + StringConcatenation _builder_2 = new StringConcatenation(); + String _localVar2 = this._grammarAccessExtensions.localVar(it); + _builder_2.append(_localVar2); + _builder_2.append("="); + _builder_2.append(super._ebnf2(it, options, supportActions)); + _builder_2.newLineIfNotEmpty(); + _builder_2.append("{"); + _builder_2.newLine(); + _builder_2.append(" "); + _builder_2.append(this.newLeafNode(it, _localVar2), " "); + _builder_2.newLineIfNotEmpty(); + _builder_2.append("}"); + _builder_2.newLine(); + return _builder_2.toString(); + } else { + return super._ebnf2(it, options, supportActions); + } + } + } + + @Override + protected String compileLexerImports(final Grammar it, final AntlrOptions options) { + StringConcatenation _builder = new StringConcatenation(); + _builder.newLine(); + _builder.append("// Hack: Use our own Lexer superclass by means of import."); + _builder.newLine(); + _builder.append("// Currently there is no other way to specify the superclass for the lexer."); + _builder.newLine(); + { + if (!this.lexerSuperClassName.isEmpty()) { + _builder.append("import "); + _builder.append(this.lexerSuperClassName); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + } else { + _builder.append("import "); + _builder.append(this.getGrammarNaming().getLexerSuperClass(it)); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + } + } + return _builder.toString(); + } +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.xtend deleted file mode 100644 index ebdfd13ab0..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.xtend +++ /dev/null @@ -1,544 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.parser.antlr - -import com.google.inject.Inject -import com.google.inject.Singleton -import org.eclipse.emf.ecore.EObject -import org.eclipse.xtend.lib.annotations.Accessors -import org.eclipse.xtext.AbstractElement -import org.eclipse.xtext.AbstractRule -import org.eclipse.xtext.Action -import org.eclipse.xtext.Assignment -import org.eclipse.xtext.CrossReference -import org.eclipse.xtext.EnumLiteralDeclaration -import org.eclipse.xtext.EnumRule -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.Keyword -import org.eclipse.xtext.ParserRule -import org.eclipse.xtext.RuleCall -import org.eclipse.xtext.TerminalRule -import org.eclipse.xtext.UnorderedGroup -import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrOptions -import org.eclipse.xtext.xtext.generator.parser.antlr.GrammarNaming - -import static extension org.eclipse.xtext.EcoreUtil2.* -import static extension org.eclipse.xtext.GrammarUtil.* -import static extension org.eclipse.xtext.xtext.generator.parser.antlr.AntlrGrammarGenUtil.* - -/** - * This implementation is strongly based on AntlrGrammarGenerator but with a different base class. - * The following extension is supported: - * - * A datatype grammar rule containing only one ID terminal rule can be annotated - * with @KeywordRule annotation provided a list of words so only these words can - * be accepted by this rule. - * - * Example: - * - * /** - * * @KeywordRule(visible, invisible) - * * / - * VisibleKind returns VisibleKind: - * ID - * ; - * - * The above rule will accept only 'visible' and 'invisible' identifiers. - * This rule in ASMD is called a keyword rule because it is intended to replace - * usages of keywords which shall not be reserved words in the language. - * Reserved words are words that are not allowed to be used in identifiers. - * - * The above example can therefore replace the following enumeration: - * - * enum VisibleKind : - * VISIBLE = "visible" - * | INVISIBLE = "invisible" - * ; - * - * Please note that a corresponding value converter is needed. - * - * Implementation remark: - * - This template will insert validating semantic predicates in the rule - * - If the rule is used from an alternative a gated semantic predicate will - * be used in the alternative - * - Error messages will be adjusted correspondingly - */ -@Singleton -class AnnotationAwareAntlrGrammarGenerator extends AbstractAnnotationAwareAntlrGrammarGenerator { - - @Inject extension GrammarNaming naming - - @Accessors(PUBLIC_SETTER) String lexerSuperClassName = ""; - - protected override getGrammarNaming() { - naming - } - - protected override compileParserImports(Grammar it, AntlrOptions options) ''' - - import org.eclipse.xtext.*; - import org.eclipse.xtext.parser.*; - import org.eclipse.xtext.parser.impl.*; - import org.eclipse.emf.ecore.util.EcoreUtil; - import org.eclipse.emf.ecore.EObject; - «IF !allEnumRules.empty» - import org.eclipse.emf.common.util.Enumerator; - «ENDIF» - import «grammarNaming.getInternalParserSuperClass(it).name»; - import org.eclipse.xtext.parser.antlr.XtextTokenStream; - import org.eclipse.xtext.parser.antlr.XtextTokenStream.HiddenTokens; - «IF !allParserRules.map[eAllContentsAsList].flatten.filter(UnorderedGroup).empty && options.backtrack» - import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper.UnorderedGroupState; - «ENDIF» - import org.eclipse.xtext.parser.antlr.AntlrDatatypeRuleToken; - import «grammarAccess.name»; - «super.compileParserImports(it, options)» - - ''' - - protected override compileParserMembers(Grammar it, AntlrOptions options) ''' - - @«IF combinedGrammar»parser::«ENDIF»members { - - «IF options.backtrack» - /* - This grammar contains a lot of empty actions to work around a bug in ANTLR. - Otherwise the ANTLR tool will create synpreds that cannot be compiled in some rare cases. - */ - - «ENDIF» - «compileParserMemberDeclarations("private")» - - public «internalParserClass.simpleName»(TokenStream input, «grammarAccess.simpleName» grammarAccess, ParserContext parserContext, «getSemanticPredicatesSimpleName()» predicates) { - this(input); - this.grammarAccess = grammarAccess; - this.predicates = predicates; - this.parserContext = parserContext; - parserContext.setTokenStream(input); - registerRules(grammarAccess.getGrammar()); - } - - «compileParserSetTokenStreamMethod» - - @Override - protected String getFirstRuleName() { - return "«allParserRules.head.originalElement.name»"; - } - - @Override - protected «grammarAccess.simpleName» getGrammarAccess() { - return grammarAccess; - } - - } - ''' - - protected override compileRuleCatch(Grammar it, AntlrOptions options) ''' - - @rulecatch { - catch (RecognitionException re) { - recover(input,re); - appendSkippedTokens(); - } - } - ''' - - override protected shouldBeSkipped(TerminalRule it, Grammar grammar) { - false - } - - protected override dispatch compileRule(ParserRule it, Grammar grammar, AntlrOptions options) ''' - «IF isValidEntryRule()» - «compileEntryRule(grammar, options)» - «ENDIF» - - «compileEBNF(options)» - ''' - - protected def String compileEntryRule(ParserRule it, Grammar grammar, AntlrOptions options) ''' - // Entry rule «originalElement.entryRuleName» - «originalElement.entryRuleName» returns «compileEntryReturns(options)»«compileEntryInit(options)»: - { «newCompositeNode» } - iv_«originalElement.ruleName»=«ruleName»«defaultArgumentList» - { $current=$iv_«ruleName».current«IF originalElement.datatypeRule».getText()«ENDIF»; } - EOF; - «compileEntryFinally(options)» - ''' - - protected def compileEntryReturns(ParserRule it, AntlrOptions options) { - if (originalElement.datatypeRule) - return '[String current=null]' - else - return '''[«currentType» current=null]''' - } - - - protected override compileInit(AbstractRule it, AntlrOptions options) ''' - «IF it instanceof ParserRule»«getParameterList(!isPassCurrentIntoFragment, currentType)»«ENDIF» returns «compileReturns(options)» - «IF hasNoBacktrackAnnotation» - // Enclosing rule was annotated with @NoBacktrack - options { backtrack=false; } - «ENDIF» - @init { - enterRule(); - «compileInitHiddenTokens(options)» - «compileInitUnorderedGroups(options)» - } - @after { - leaveRule(); - }''' - - protected def compileReturns(AbstractRule it, AntlrOptions options) { - switch it { - EnumRule: - '[Enumerator current=null]' - ParserRule case originalElement.datatypeRule: - '[AntlrDatatypeRuleToken current=new AntlrDatatypeRuleToken()]' - ParserRule case originalElement.isEObjectFragmentRule: - '''[«currentType» current=in_current]''' - ParserRule: - '''[«currentType» current=null]''' - default: - throw new IllegalStateException("Unexpected rule: " + it) - } - } - - protected override String _dataTypeEbnf2(Keyword it, boolean supportActions) { - if (supportActions) ''' - kw=«super._dataTypeEbnf2(it, supportActions)» - { - $current.merge(kw); - «newLeafNode("kw")» - } - ''' - else - super._dataTypeEbnf2(it, supportActions) - } - - protected override String _ebnf2(Action it, AntlrOptions options, boolean supportActions) { - if (supportActions) ''' - «IF options.backtrack» - { - /* */ - } - «ENDIF» - { - $current = forceCreateModelElement«IF feature !== null»And«setOrAdd.toFirstUpper»«ENDIF»( - grammarAccess.«originalElement.grammarElementAccess», - $current); - } - ''' - else - super._ebnf2(it, options, supportActions) - } - - protected override String _ebnf2(Keyword it, AntlrOptions options, boolean supportActions) { - if (!supportActions) - super._ebnf2(it, options, supportActions) - else if (assigned) ''' - «super._ebnf2(it, options, supportActions)» - { - «newLeafNode(containingAssignment.localVar(it))» - } - ''' - else ''' - «localVar»=«super._ebnf2(it, options, supportActions)» - { - «newLeafNode(localVar)» - } - ''' - } - - override protected _ebnf2(EnumLiteralDeclaration it, AntlrOptions options, boolean supportActions) { - if (!supportActions) - super._ebnf2(it, options, supportActions) - else ''' - «localVar»=«super._ebnf2(it, options, supportActions)» - { - $current = grammarAccess.«grammarElementAccess(originalElement)».getEnumLiteral().getInstance(); - «newLeafNode(localVar)» - } - ''' - } - - protected override String crossrefEbnf(AbstractRule it, RuleCall call, CrossReference ref, boolean supportActions) { - if (supportActions) - switch it { - EnumRule, - ParserRule: ''' - { - «ref.newCompositeNode» - } - «ruleName»«call.getArgumentList(isPassCurrentIntoFragment, !supportActions)» - { - afterParserOrEnumRuleCall(); - } - ''' - TerminalRule: ''' - «ref.containingAssignment.localVar»=«ruleName» - { - «ref.newLeafNode(ref.containingAssignment.localVar)» - } - ''' - default: - throw new IllegalStateException("crossrefEbnf is not supported for " + it) - } - else - super.crossrefEbnf(it, call, ref, supportActions) - } - - override protected _assignmentEbnf(AbstractElement it, Assignment assignment, AntlrOptions options, boolean supportActions) { - if (supportActions) ''' - «assignment.localVar(it)»=«super._assignmentEbnf(it, assignment, options, supportActions)» - { - if ($current==null) { - $current = «assignment.createModelElement»; - } - «assignment.setOrAdd»WithLastConsumed($current, "«assignment.feature»", « - assignment.localVar(it)»«IF assignment.isBooleanAssignment» != null«ENDIF - », «assignment.terminal.toStringLiteral»); - } - ''' - else - super._assignmentEbnf(it, assignment, options, supportActions) - } - - override protected isPassCurrentIntoFragment() { - return true - } - - protected def createModelElement(EObject grammarElement) ''' - createModelElement(grammarAccess.«grammarElement.containingParserRule.originalElement.grammarElementAccess»)''' - - protected def createModelElementForParent(EObject grammarElement) ''' - createModelElementForParent(grammarAccess.«grammarElement.containingParserRule.originalElement.grammarElementAccess»)''' - - protected def newCompositeNode(EObject it) '''newCompositeNode(grammarAccess.«originalElement.grammarElementAccess»);''' - - protected def newLeafNode(EObject it, String token) '''newLeafNode(«token», grammarAccess.«originalElement.grammarElementAccess»);''' - - /** - * Add gated predicate, if necessary, before the action preceding the rule call. - */ - protected override String _dataTypeEbnf2(RuleCall it, boolean supportActions) { - if (supportActions) - switch rule { - EnumRule case assigned, - ParserRule case assigned: - super._dataTypeEbnf2(it, supportActions) - EnumRule, - ParserRule: ''' - «IF isGatedPredicateRequired»«generateGatedPredicate»«ENDIF» - { - «newCompositeNode» - } - «localVar»=«super._dataTypeEbnf2(it, supportActions)»«getArgumentList(isPassCurrentIntoFragment, !supportActions)» - { - $current.merge(«localVar»); - } - { - afterParserOrEnumRuleCall(); - } - ''' - TerminalRule: ''' - «localVar»=«super._dataTypeEbnf2(it, supportActions)» - { - $current.merge(«localVar»); - } - { - «newLeafNode(localVar)» - } - ''' - default: - super._dataTypeEbnf2(it, supportActions) - } - else - super._dataTypeEbnf2(it, supportActions) - } - - /** - * Inserts validating predicate only. Gated predicates will be inserted in alternatives if needed. - */ - protected override String compileEBNF(AbstractRule it, AntlrOptions options) ''' - // Rule «originalElement.name» - «ruleName»«compileInit(options)»: - «IF it instanceof ParserRule && originalElement.datatypeRule» - «IF hasValidatingPredicate»«generateValidatingPredicate»«ENDIF» - «dataTypeEbnf(alternatives, true)» - «ELSE» - «ebnf(alternatives, options, true)» - «ENDIF» - ; - «compileFinally(options)» - ''' - - protected override String dataTypeEbnf(AbstractElement it, boolean supportActions) ''' - «IF mustBeParenthesized»( - «IF hasNoBacktrackAnnotation» - // Enclosing rule was annotated with @NoBacktrack - options { backtrack=false; }: - «ENDIF» - «dataTypeEbnfPredicate»«dataTypeEbnf2(supportActions)» - )«ELSE»«dataTypeEbnf2(supportActions)»«ENDIF»«cardinality» - ''' - - protected override String ebnf(AbstractElement it, AntlrOptions options, boolean supportActions) ''' - «IF mustBeParenthesized»( - «IF hasNoBacktrackAnnotation» - // Enclosing rule was annotated with @NoBacktrack - options { backtrack=false; }: - «ENDIF» - «ebnfPredicate(options)»«ebnf2(options, supportActions)» - )«ELSE»«ebnf2(options, supportActions)»«ENDIF»«cardinality» - ''' - - - - /** - * Add gated predicate, if necessary, before the action preceding the assignment. - */ - protected override String _assignmentEbnf(RuleCall it, Assignment assignment, AntlrOptions options, boolean supportActions) { - if (supportActions) - switch rule { - EnumRule, - ParserRule: ''' - «IF isGatedPredicateRequired»«generateGatedPredicate»«ENDIF» - { - «newCompositeNode» - } - «assignment.localVar(it)»=«super._assignmentEbnf(it, assignment, options, supportActions)» - { - if ($current==null) { - $current = «assignment.createModelElementForParent»; - } - «assignment.setOrAdd»( - $current, - "«assignment.feature»", - «assignment.localVar(it)»«IF assignment.isBooleanAssignment» != null«ENDIF», - «toStringLiteral»); - afterParserOrEnumRuleCall(); - } - ''' - TerminalRule: ''' - «assignment.localVar(it)»=«super._assignmentEbnf(it, assignment, options, supportActions)» - { - «newLeafNode(assignment.localVar(it))» - } - { - if ($current==null) { - $current = «assignment.createModelElement»; - } - «assignment.setOrAdd»WithLastConsumed( - $current, - "«assignment.feature»", - «assignment.localVar(it)»«IF assignment.isBooleanAssignment» != null«ENDIF», - «toStringLiteral»); - } - ''' - default: - throw new IllegalStateException("assignmentEbnf is not supported for " + it) - } - else - super._assignmentEbnf(it, assignment, options, supportActions) - } - - /** - * Add gated predicate, if necessary, before the action preceding the cross reference. - */ - protected override _assignmentEbnf(CrossReference it, Assignment assignment, AntlrOptions options, boolean supportActions) { - if (supportActions) ''' - «IF isGatedPredicateRequired»«generateGatedPredicate»«ENDIF» - «IF options.backtrack» - { - /* */ - } - «ENDIF» - { - if ($current==null) { - $current = «assignment.createModelElement»; - } - } - «super._assignmentEbnf(it, assignment, options, supportActions)»''' - else - super._assignmentEbnf(it, assignment, options, supportActions) - } - - /** - * Add gated predicate, if necessary, before the action preceding the rule call. - */ - protected override String _ebnf2(RuleCall it, AntlrOptions options, boolean supportActions) { - if (!supportActions) - super._ebnf2(it, options, supportActions) - else - switch rule : rule { - EnumRule case assigned, - ParserRule case assigned: - super._ebnf2(it, options, supportActions) - EnumRule, - ParserRule case rule.originalElement.datatypeRule: ''' - «IF isGatedPredicateRequired»«generateGatedPredicate»«ENDIF» - «IF options.backtrack» - { - /* */ - } - «ENDIF» - { - «newCompositeNode» - } - «super._ebnf2(it, options, supportActions)» - { - afterParserOrEnumRuleCall(); - } - ''' - ParserRule: ''' - «IF isGatedPredicateRequired»«generateGatedPredicate»«ENDIF» - «IF options.backtrack» - { - /* */ - } - «ENDIF» - { - «IF isEObjectFragmentRuleCall» - if ($current==null) { - $current = «it.createModelElement»; - } - «ENDIF» - «newCompositeNode» - } - «localVar»=«super._ebnf2(it, options, supportActions)» - { - $current = $«localVar».current; - afterParserOrEnumRuleCall(); - } - ''' - TerminalRule: ''' - «localVar»=«super._ebnf2(it, options, supportActions)» - { - «newLeafNode(localVar)» - } - ''' - default: - super._ebnf2(it, options, supportActions) - } - } - - protected override compileLexerImports(Grammar it, AntlrOptions options) ''' - - // Hack: Use our own Lexer superclass by means of import. - // Currently there is no other way to specify the superclass for the lexer. - «IF !lexerSuperClassName.empty» - import «lexerSuperClassName»; - «ELSE» - import «grammarNaming.getLexerSuperClass(it)»; - «ENDIF» - ''' -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.java new file mode 100644 index 0000000000..98e13fe4c8 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.java @@ -0,0 +1,1062 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.generator.parser.antlr; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.antlr.runtime.CharStream; +import org.antlr.runtime.Token; +import org.antlr.runtime.TokenSource; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.AbstractElement; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.ParserRule; +import org.eclipse.xtext.parser.antlr.AntlrTokenDefProvider; +import org.eclipse.xtext.parser.antlr.ITokenDefProvider; +import org.eclipse.xtext.parser.antlr.Lexer; +import org.eclipse.xtext.parser.antlr.LexerProvider; +import org.eclipse.xtext.parser.antlr.XtextTokenStream; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xtext.FlattenedGrammarAccess; +import org.eclipse.xtext.xtext.RuleFilter; +import org.eclipse.xtext.xtext.RuleNames; +import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions; +import org.eclipse.xtext.xtext.generator.model.FileAccessFactory; +import org.eclipse.xtext.xtext.generator.model.GeneratedJavaFileAccess; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.IXtextGeneratorFileSystemAccess; +import org.eclipse.xtext.xtext.generator.model.JavaFileAccess; +import org.eclipse.xtext.xtext.generator.model.ManifestAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtext.xtext.generator.parser.antlr.AntlrGrammarGenUtil; +import org.eclipse.xtext.xtext.generator.parser.antlr.ContentAssistGrammarNaming; +import org.eclipse.xtext.xtext.generator.parser.antlr.GrammarNaming; +import org.eclipse.xtext.xtext.generator.parser.antlr.XtextAntlrGeneratorFragment2; + +import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations; +import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations.SemanticPredicate; +import com.avaloq.tools.ddk.xtext.generator.parser.common.PredicatesNaming; +import com.avaloq.tools.ddk.xtext.parser.ISemanticPredicates; +import com.avaloq.tools.ddk.xtext.parser.antlr.AbstractContextualAntlrParser; +import com.avaloq.tools.ddk.xtext.parser.antlr.ParserContext; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Names; + + +public class AnnotationAwareXtextAntlrGeneratorFragment2 extends XtextAntlrGeneratorFragment2 { + + private static final String ADDITIONAL_CA_REQUIRED_BUNDLE = "com.avaloq.tools.ddk.xtext"; + + @Inject + private AnnotationAwareAntlrGrammarGenerator productionGenerator; + + @Inject + private AnnotationAwareAntlrContentAssistGrammarGenerator contentAssistGenerator; + + @Inject + private GrammarNaming productionNaming; + + @Inject + private FileAccessFactory fileFactory; + + @Inject + private ContentAssistGrammarNaming contentAssistNaming; + + @Inject + private PredicatesNaming predicatesNaming; + + @Inject + private GrammarAccessExtensions grammarUtil; + + @Inject + private GrammarRuleAnnotations annotations; + + private boolean generateContentAssistIfIdeMissing; + + private boolean removeBacktrackingGuards; + + private int lookaheadThreshold; + + private boolean partialParsing; + + private Set reservedWords = ImmutableSet.of(); + + private Set keywords = ImmutableSet.of(); + + private Set identifierRules = ImmutableSet.of(); + + private String lexerSuperClassName = ""; + + /** + * Suffix used in the naming convention for the classes responsible for semantic predicates. + */ + private static final String CLASS_SUFFIX = "SemanticPredicates"; + + @Override + public void setRemoveBacktrackingGuards(final boolean removeBacktrackingGuards) { + this.removeBacktrackingGuards = removeBacktrackingGuards; + super.setRemoveBacktrackingGuards(removeBacktrackingGuards); + } + + @Override + public void setLookaheadThreshold(final String lookaheadThreshold) { + this.lookaheadThreshold = Integer.parseInt(lookaheadThreshold); + super.setLookaheadThreshold(lookaheadThreshold); + } + + @Override + public void setPartialParsing(final boolean partialParsing) { + this.partialParsing = partialParsing; + super.setPartialParsing(partialParsing); + } + + public void setReservedWords(final String words) { + this.reservedWords = toSet(words); + } + + public void setIdentifierRules(final String rules) { + this.identifierRules = toSet(rules); + } + + public void setKeywords(final String words) { + this.keywords = toSet(words); + } + + public void setLexerSuperClassName(final String className) { + this.lexerSuperClassName = className; + } + + private Set toSet(final String words) { + return Arrays.stream(words.split(",")).map(String::trim).filter(str -> !str.isEmpty()).collect(Collectors.toSet()); + } + + public boolean isGenerateContentAssistIfIdeMissing() { + return this.generateContentAssistIfIdeMissing; + } + + public void setGenerateContentAssistIfIdeMissing(final boolean generateContentAssistIfIdeMissing) { + this.generateContentAssistIfIdeMissing = generateContentAssistIfIdeMissing; + } + + @Override + protected void checkGrammar() { + super.checkGrammar(); + this.annotations.annotateGrammar(getGrammar()); + } + + @Override + protected void doGenerate() { + super.doGenerate(); + // if there is no ide plugin, write the content assist parser to the ui plugin. + if (this.generateContentAssistIfIdeMissing && getProjectConfig().getGenericIde().getSrcGen() == null) { + generateUiContentAssistGrammar(); + generateContentAssistParser().writeTo(getProjectConfig().getEclipsePlugin().getSrcGen()); + if (hasSyntheticTerminalRule()) { + generateContentAssistTokenSource().writeTo(getProjectConfig().getEclipsePlugin().getSrc()); + } + addIdeUiBindingsAndImports(); + } + generateAbstractSemanticPredicate().writeTo(getProjectConfig().getRuntime().getSrcGen()); + } + + @Override + protected void addRuntimeBindingsAndImports() { + super.addRuntimeBindingsAndImports(); + ManifestAccess manifest = getProjectConfig().getRuntime().getManifest(); + if (manifest != null) { + Set exportedPackages = manifest.getExportedPackages(); + String semanticPredicatesPackageName = this.predicatesNaming.getSemanticPredicatesPackageName(getGrammar()); + exportedPackages.add(semanticPredicatesPackageName); + } + } + + @Override + protected void generateContentAssistGrammar() { + generateContentAssistGrammar(getProjectConfig().getGenericIde().getSrcGen()); + } + + protected void generateContentAssistGrammar(final IXtextGeneratorFileSystemAccess fsa) { + final ContentAssistGrammarNaming naming = this.contentAssistNaming; + this.contentAssistGenerator.generate(getGrammar(), getOptions(), fsa); + runAntlr(naming.getParserGrammar(getGrammar()), naming.getLexerGrammar(getGrammar()), fsa); + simplifyUnorderedGroupPredicatesIfRequired(getGrammar(), fsa, naming.getInternalParserClass(getGrammar())); + splitParserAndLexerIfEnabled(fsa, naming.getInternalParserClass(getGrammar()), naming.getLexerClass(getGrammar())); + normalizeTokens(fsa, naming.getLexerGrammar(getGrammar()).getTokensFileName()); + suppressWarnings(fsa, naming.getInternalParserClass(getGrammar()), naming.getLexerClass(getGrammar())); + normalizeLineDelimiters(fsa, naming.getLexerClass(getGrammar()), naming.getInternalParserClass(getGrammar())); + if (this.removeBacktrackingGuards) { + removeBackTrackingGuards(fsa, naming.getInternalParserClass(getGrammar()), this.lookaheadThreshold); + } + } + + @Override + protected void addIdeBindingsAndImports() { + super.addIdeBindingsAndImports(); + ManifestAccess manifest = getProjectConfig().getGenericIde().getManifest(); + if (manifest != null) { + Set requiredBundles = manifest.getRequiredBundles(); + requiredBundles.add(ADDITIONAL_CA_REQUIRED_BUNDLE); + } + } + + protected void generateUiContentAssistGrammar() { + generateContentAssistGrammar(getProjectConfig().getEclipsePlugin().getSrcGen()); + } + + protected void addIdeUiBindingsAndImports() { + final ContentAssistGrammarNaming naming = this.contentAssistNaming; + ManifestAccess manifest = getProjectConfig().getEclipsePlugin().getManifest(); + if (manifest != null) { + Set exportedPackages = manifest.getExportedPackages(); + Iterables.addAll(exportedPackages, List.of( + naming.getLexerClass(getGrammar()).getPackageName(), + naming.getParserClass(getGrammar()).getPackageName(), + naming.getInternalParserClass(getGrammar()).getPackageName())); + Set requiredBundles = manifest.getRequiredBundles(); + Iterables.addAll(requiredBundles, List.of( + "org.antlr.runtime;bundle-version=\"[3.2.0,3.2.1)\"", + ADDITIONAL_CA_REQUIRED_BUNDLE)); + } + GuiceModuleAccess.BindingFactory ideBindings = new GuiceModuleAccess.BindingFactory() + .addConfiguredBinding("ContentAssistLexer", new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("binder.bind("); + TypeReference _lexerSuperClass = naming.getLexerSuperClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_lexerSuperClass); + _builder.append(".class)"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(".annotatedWith("); + _builder.append(Names.class, " "); + _builder.append(".named("); + TypeReference _typeRef = TypeReference.typeRef("org.eclipse.xtext.ide.LexerIdeBindings"); + _builder.append(_typeRef, " "); + _builder.append(".CONTENT_ASSIST))"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(".to("); + TypeReference _lexerClass = naming.getLexerClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_lexerClass, " "); + _builder.append(".class);"); + _builder.newLineIfNotEmpty(); + } + }) + .addTypeToType(TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.antlr.IContentAssistParser"), naming.getParserClass(getGrammar())) + .addConfiguredBinding("IProposalConflictHelper", new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("binder.bind(org.eclipse.xtext.ide.editor.contentassist.IProposalConflictHelper.class)"); + _builder.newLine(); + _builder.append(" "); + _builder.append(".to(org.eclipse.xtext.ide.editor.contentassist.antlr.AntlrProposalConflictHelper.class);"); + _builder.newLine(); + } + }); + if (this.partialParsing) { + ideBindings.addTypeToType( + TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.antlr.ContentAssistContextFactory"), + TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.antlr.PartialContentAssistContextFactory")); + } + if (hasSyntheticTerminalRule()) { + ideBindings.addTypeToType( + TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.CompletionPrefixProvider"), + TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.IndentationAwareCompletionPrefixProvider")); + } + ideBindings.contributeTo(getLanguage().getEclipsePluginGenModule()); + } + + @Override + public JavaFileAccess generateContentAssistParser() { + final ContentAssistGrammarNaming naming = this.contentAssistNaming; + final GeneratedJavaFileAccess file = this.fileFactory.createGeneratedJavaFile(naming.getParserClass(getGrammar())); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("public class "); + String _simpleName = naming.getParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()).getSimpleName(); + _builder.append(_simpleName); + _builder.append(" extends "); + TypeReference _parserSuperClass = naming.getParserSuperClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar(), AnnotationAwareXtextAntlrGeneratorFragment2.this.partialParsing); + _builder.append(_parserSuperClass); + _builder.append(" {"); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + StringConcatenationClient _initNameMappings = AnnotationAwareXtextAntlrGeneratorFragment2.this.initNameMappings(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_initNameMappings, " "); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@"); + _builder.append(Inject.class, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("private "); + TypeReference _grammarAccess = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_grammarAccess, " "); + _builder.append(" grammarAccess;"); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@"); + _builder.append(Inject.class, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("private "); + TypeReference _typeRef = TypeReference.typeRef(ISemanticPredicates.class); + _builder.append(_typeRef, " "); + _builder.append(" predicates;"); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* Creates compilation context."); + _builder.newLine(); + _builder.append(" "); + _builder.append("*"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* @param Input"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* Stream"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* @return Compilation context"); + _builder.newLine(); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected "); + TypeReference _typeRef_1 = TypeReference.typeRef(ParserContext.class); + _builder.append(_typeRef_1, " "); + _builder.append(" createParserContext() {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("return new ParserContext();"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected "); + TypeReference _internalParserClass = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_internalParserClass, " "); + _builder.append(" createParser() {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + TypeReference _internalParserClass_1 = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_internalParserClass_1, " "); + _builder.append(" result = new "); + TypeReference _internalParserClass_2 = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_internalParserClass_2, " "); + _builder.append("(null);"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("result.setGrammarAccess(grammarAccess);"); + _builder.newLine(); + _builder.append(" "); + _builder.append("result.setParserContext(createParserContext());"); + _builder.newLine(); + _builder.append(" "); + _builder.append("result.setPredicates(("); + TypeReference _typeRef_2 = TypeReference.typeRef(AnnotationAwareXtextAntlrGeneratorFragment2.this.predicatesNaming.getSemanticPredicatesFullName(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar())); + _builder.append(_typeRef_2, " "); + _builder.append(")predicates);"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("return result;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + { + boolean _hasSyntheticTerminalRule = AnnotationAwareXtextAntlrGeneratorFragment2.this.hasSyntheticTerminalRule(); + if (_hasSyntheticTerminalRule) { + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected "); + _builder.append(TokenSource.class, " "); + _builder.append(" createLexer("); + _builder.append(CharStream.class, " "); + _builder.append(" stream) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("return new "); + TypeReference _tokenSourceClass = naming.getTokenSourceClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_tokenSourceClass, " "); + _builder.append("(super.createLexer(stream));"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + } + } + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected String getRuleName("); + _builder.append(AbstractElement.class, " "); + _builder.append(" element) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("return nameMappings.getRuleName(element);"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected String[] getInitialHiddenTokens() {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("return new String[] { "); + { + List _initialHiddenTokens = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.initialHiddenTokens(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + boolean _hasElements = false; + for (final String hidden : _initialHiddenTokens) { + if (!_hasElements) { + _hasElements = true; + } else { + _builder.appendImmediate(", ", " "); + } + _builder.append("\""); + _builder.append(hidden, " "); + _builder.append("\""); + } + } + _builder.append(" };"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public "); + TypeReference _grammarAccess_1 = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_grammarAccess_1, " "); + _builder.append(" getGrammarAccess() {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("return this.grammarAccess;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public void setGrammarAccess("); + TypeReference _grammarAccess_2 = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_grammarAccess_2, " "); + _builder.append(" grammarAccess) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("this.grammarAccess = grammarAccess;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public NameMappings getNameMappings() {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("return nameMappings;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public void setNameMappings(NameMappings nameMappings) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("this.nameMappings = nameMappings;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + } + }; + file.setContent(_client); + return file; + } + + @Override + protected void generateProductionGrammar() { + final GrammarNaming naming = this.productionNaming; + final IXtextGeneratorFileSystemAccess fsa = getProjectConfig().getRuntime().getSrcGen(); + this.productionGenerator.setLexerSuperClassName(this.lexerSuperClassName); + this.productionGenerator.generate(getGrammar(), getOptions(), fsa); + runAntlr(naming.getParserGrammar(getGrammar()), naming.getLexerGrammar(getGrammar()), fsa); + simplifyUnorderedGroupPredicatesIfRequired(getGrammar(), fsa, naming.getInternalParserClass(getGrammar())); + splitParserAndLexerIfEnabled(fsa, naming.getInternalParserClass(getGrammar()), naming.getLexerClass(getGrammar())); + normalizeTokens(fsa, naming.getLexerGrammar(getGrammar()).getTokensFileName()); + suppressWarnings(fsa, naming.getInternalParserClass(getGrammar()), naming.getLexerClass(getGrammar())); + normalizeLineDelimiters(fsa, naming.getInternalParserClass(getGrammar()), naming.getLexerClass(getGrammar())); + + /* filter and ruleNames for flattened grammar */ + final RuleFilter filter = new RuleFilter(); + filter.setDiscardUnreachableRules(true); + filter.setDiscardTerminalRules(false); + final RuleNames ruleNames = RuleNames.getRuleNames(getGrammar(), true); + + String grammarFileName = this.productionGenerator.getGrammarNaming().getParserGrammar(getGrammar()).getGrammarFileName(); + Grammar flattenedGrammar = new FlattenedGrammarAccess(ruleNames, filter).getFlattenedGrammar(); + final KeywordAnalysisHelper keywordAnalysisHelper = new KeywordAnalysisHelper(grammarFileName, flattenedGrammar, this.identifierRules, this.reservedWords, this.keywords, this.grammarUtil); + keywordAnalysisHelper.printReport(fsa.getPath()); + keywordAnalysisHelper.printViolations(fsa.getPath()); + } + + public JavaFileAccess generateAbstractSemanticPredicate() { + final GeneratedJavaFileAccess file = this.fileFactory.createGeneratedJavaFile(TypeReference.typeRef(this.predicatesNaming.getSemanticPredicatesFullName(getGrammar()))); + file.importType(TypeReference.typeRef(this.predicatesNaming.getSemanticPredicatesFullName(getGrammar()))); + file.importType(TypeReference.typeRef(ISemanticPredicates.AbstractSemanticPredicates.class)); + if (!this.annotations.predicates(getGrammar()).isEmpty()) { + file.importType(TypeReference.typeRef(ParserContext.class)); + file.importType(TypeReference.typeRef(Token.class)); + for (final Grammar inheritedGrammar : this.annotations.allInheritedGrammars(getGrammar())) { + file.importType(TypeReference.typeRef(GrammarUtil.getNamespace(inheritedGrammar) + ".grammar." + GrammarUtil.getSimpleName(inheritedGrammar) + CLASS_SUFFIX)); + } + } + file.importType(TypeReference.typeRef(Singleton.class)); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* Provides semantic predicates as specified in the grammar. Language may need to override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* this class in order to provide concrete implementations for predicates."); + _builder.newLine(); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.append("@Singleton"); + _builder.newLine(); + _builder.append("public class "); + String _semanticPredicatesSimpleName = AnnotationAwareXtextAntlrGeneratorFragment2.this.predicatesNaming.getSemanticPredicatesSimpleName(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_semanticPredicatesSimpleName); + _builder.append(" extends AbstractSemanticPredicates {"); + _builder.newLineIfNotEmpty(); + { + List _predicates = AnnotationAwareXtextAntlrGeneratorFragment2.this.annotations.predicates(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + for (final GrammarRuleAnnotations.SemanticPredicate element : _predicates) { + _builder.newLine(); + _builder.append(" "); + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* Predicate for grammar rule "); + String _name = element.getName(); + _builder.append(_name, " "); + _builder.append("."); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("*"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* @param input"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* Input from Lexer"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* @return {@code true} if the grammar rule is enabled, {@code false} otherwise"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.append(" "); + _builder.append("public boolean "); + String _name_1 = element.getName(); + _builder.append(_name_1, " "); + _builder.append("(ParserContext parserContext) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + String _rulePredicateCondition = AnnotationAwareXtextAntlrGeneratorFragment2.this.getRulePredicateCondition(element); + _builder.append(_rulePredicateCondition, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + } + } + _builder.newLine(); + { + List _predicates_1 = AnnotationAwareXtextAntlrGeneratorFragment2.this.annotations.predicates(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + for (final GrammarRuleAnnotations.SemanticPredicate element_1 : _predicates_1) { + _builder.newLine(); + _builder.append(" "); + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* Message for "); + String _name_2 = element_1.getName(); + _builder.append(_name_2, " "); + _builder.append(" predicate."); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("*"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* @param input"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* Input from Lexer"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* @return {@code true} if the grammar rule is enabled, {@code false} otherwise"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("public String "); + String _message = element_1.getMessage(); + _builder.append(_message, " "); + _builder.append("(Token token) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + String _rulePredicateMessage = AnnotationAwareXtextAntlrGeneratorFragment2.this.getRulePredicateMessage(element_1); + _builder.append(_rulePredicateMessage, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + } + } + _builder.append("}"); + _builder.newLine(); + } + }; + file.setContent(_client); + return file; + } + + /** + * Returns name for the predicate message method. + * + * @param predicate + * Semantic predicate, must not be {@code null} + * @return Content for the predicate message method + */ + public String getRulePredicateMessage(final SemanticPredicate predicate) { + if (predicate.getKeywords() != null) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("return \"Unexpected: \" + token.getText() + \". Expected: \'"); + String _join = Joiner.on("\', \'").join(predicate.getKeywords()); + _builder.append(_join); + _builder.append("\'\";"); + _builder.newLineIfNotEmpty(); + return _builder.toString(); + } else { + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("/* Default message. Intended to be overridden. */"); + _builder_1.newLine(); + _builder_1.append("return \"Condition "); + String _name = predicate.getName(); + _builder_1.append(_name); + _builder_1.append(" is not fullfilled \";"); + _builder_1.newLineIfNotEmpty(); + return _builder_1.toString(); + } + } + + /** + * Returns predicate condition (default condition). + * + * @param predicate + * Semantic predicate, must not be {@code null} + * @return A string containing the condition for the semantic predicate or {@code null} + */ + public String getRulePredicateCondition(final SemanticPredicate predicate) { + if (predicate.getKeywords() != null) { + final String condition = predicate.getKeywords().stream().map(s -> { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("\""); + _builder.append(s); + _builder.append("\".equalsIgnoreCase(text)"); + return _builder.toString(); + }).collect(Collectors.joining(" || ")); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("String text = parserContext.getInput().LT(1).getText();"); + _builder.newLine(); + _builder.append("return "); + _builder.append(condition); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + return _builder.toString(); + } else { + return "return " + predicate.getGrammar() + CLASS_SUFFIX + "." + predicate.getName() + "(parserContext);\n"; + } + } + + @Override + public JavaFileAccess generateProductionParser() { + final GrammarNaming naming = this.productionNaming; + final GeneratedJavaFileAccess file = this.fileFactory.createGeneratedJavaFile(naming.getParserClass(getGrammar())); + file.importType(TypeReference.typeRef(this.predicatesNaming.getSemanticPredicatesFullName(getGrammar()))); + file.importType(TypeReference.typeRef(ISemanticPredicates.class)); + StringConcatenationClient _client = new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("public class "); + String _simpleName = naming.getParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()).getSimpleName(); + _builder.append(_simpleName); + _builder.append(" extends "); + _builder.append(AbstractContextualAntlrParser.class); + _builder.append(" {"); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@"); + _builder.append(Inject.class, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("private "); + TypeReference _grammarAccess = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_grammarAccess, " "); + _builder.append(" grammarAccess;"); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@"); + _builder.append(Inject.class, " "); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("private ISemanticPredicates predicates;"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected void setInitialHiddenTokens("); + _builder.append(XtextTokenStream.class, " "); + _builder.append(" tokenStream) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("tokenStream.setInitialHiddenTokens("); + { + List _initialHiddenTokens = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.initialHiddenTokens(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + boolean _hasElements = false; + for (final String hidden : _initialHiddenTokens) { + if (!_hasElements) { + _hasElements = true; + } else { + _builder.appendImmediate(", ", " "); + } + _builder.append("\""); + _builder.append(hidden, " "); + _builder.append("\""); + } + } + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + { + boolean _hasSyntheticTerminalRule = AnnotationAwareXtextAntlrGeneratorFragment2.this.hasSyntheticTerminalRule(); + if (_hasSyntheticTerminalRule) { + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected "); + _builder.append(TokenSource.class, " "); + _builder.append(" createLexer("); + _builder.append(CharStream.class, " "); + _builder.append(" stream) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(" "); + _builder.append("return new "); + TypeReference _tokenSourceClass = naming.getTokenSourceClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_tokenSourceClass, " "); + _builder.append("(super.createLexer(stream));"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* Indentation aware languages do not support partial parsing since the lexer is inherently stateful."); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("* Override and return {@code true} if your terminal splitting is stateless."); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected boolean isReparseSupported() {"); + _builder.newLine(); + _builder.append(" "); + _builder.append(" "); + _builder.append("return false;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + } + } + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected "); + TypeReference _internalParserClass = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_internalParserClass, " "); + _builder.append(" createParser("); + _builder.append(XtextTokenStream.class, " "); + _builder.append(" stream) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("return new "); + TypeReference _internalParserClass_1 = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_internalParserClass_1, " "); + _builder.append("(stream, getGrammarAccess(), createParserContext(), ("); + String _semanticPredicatesSimpleName = AnnotationAwareXtextAntlrGeneratorFragment2.this.predicatesNaming.getSemanticPredicatesSimpleName(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_semanticPredicatesSimpleName, " "); + _builder.append(") predicates);"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@Override"); + _builder.newLine(); + _builder.append(" "); + _builder.append("protected String getDefaultRuleName() {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("return \""); + String _name = AntlrGrammarGenUtil.getOriginalElement(IterableExtensions.head(GrammarUtil.allParserRules(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()))).getName(); + _builder.append(_name, " "); + _builder.append("\";"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public "); + TypeReference _grammarAccess_1 = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_grammarAccess_1, " "); + _builder.append(" getGrammarAccess() {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("return this.grammarAccess;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("public void setGrammarAccess("); + TypeReference _grammarAccess_2 = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_grammarAccess_2, " "); + _builder.append(" grammarAccess) {"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append("this.grammarAccess = grammarAccess;"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + } + }; + file.setContent(_client); + return file; + } + + @Override + protected void addUiBindingsAndImports() { + /* Overridden to remove the binding for IContentAssistParser, which we bind at a different place. + * If we would register it here, we would have conflicting bindings for IContentAssistParser. + */ + final ContentAssistGrammarNaming naming = this.contentAssistNaming; + final TypeReference caLexerClass = naming.getLexerClass(getGrammar()); + + ManifestAccess manifest = getProjectConfig().getGenericIde().getManifest(); + if (manifest != null) { + Set exportedPackages = manifest.getExportedPackages(); + Iterables.addAll(exportedPackages, List.of( + caLexerClass.getPackageName(), + naming.getParserClass(getGrammar()).getPackageName(), + naming.getInternalParserClass(getGrammar()).getPackageName())); + } + GuiceModuleAccess.BindingFactory uiBindings = new GuiceModuleAccess.BindingFactory() + .addTypeToType( + TypeReference.typeRef("org.eclipse.xtext.ui.editor.contentassist.IProposalConflictHelper"), + TypeReference.typeRef("org.eclipse.xtext.ui.editor.contentassist.antlr.AntlrProposalConflictHelper")) + .addConfiguredBinding("ContentAssistLexer", new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("binder.bind("); + TypeReference _lexerSuperClass = naming.getLexerSuperClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_lexerSuperClass); + _builder.append(".class)"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(".annotatedWith("); + _builder.append(Names.class, " "); + _builder.append(".named("); + TypeReference _typeRef = TypeReference.typeRef("org.eclipse.xtext.ide.LexerIdeBindings"); + _builder.append(_typeRef, " "); + _builder.append(".CONTENT_ASSIST))"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(".to("); + _builder.append(caLexerClass, " "); + _builder.append(".class);"); + _builder.newLineIfNotEmpty(); + } + }) + // registration of the 'ContentAssistLexer' is put in front of the 'HighlightingLexer' + // in order to let 'caLexerClass' get added to the imports, since it is referenced + // several times and the lexer classes' simple names are usually identical + .addConfiguredBinding("HighlightingLexer", new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("binder.bind("); + _builder.append(Lexer.class); + _builder.append(".class)"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(".annotatedWith("); + _builder.append(Names.class, " "); + _builder.append(".named("); + TypeReference _typeRef = TypeReference.typeRef("org.eclipse.xtext.ide.LexerIdeBindings"); + _builder.append(_typeRef, " "); + _builder.append(".HIGHLIGHTING))"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(".to("); + TypeReference _lexerClass = AnnotationAwareXtextAntlrGeneratorFragment2.this.productionNaming.getLexerClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); + _builder.append(_lexerClass, " "); + _builder.append(".class);"); + _builder.newLineIfNotEmpty(); + } + }) + .addConfiguredBinding("HighlightingTokenDefProvider", new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("binder.bind("); + _builder.append(ITokenDefProvider.class); + _builder.append(".class)"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(".annotatedWith("); + _builder.append(Names.class, " "); + _builder.append(".named("); + TypeReference _typeRef = TypeReference.typeRef("org.eclipse.xtext.ide.LexerIdeBindings"); + _builder.append(_typeRef, " "); + _builder.append(".HIGHLIGHTING))"); + _builder.newLineIfNotEmpty(); + _builder.append(" "); + _builder.append(".to("); + _builder.append(AntlrTokenDefProvider.class, " "); + _builder.append(".class);"); + _builder.newLineIfNotEmpty(); + } + }) + .addTypeToType( + new TypeReference("org.eclipse.xtext.ui.editor.contentassist", "ContentAssistContext.Factory"), + TypeReference.typeRef("org.eclipse.xtext.ui.editor.contentassist.antlr.DelegatingContentAssistContextFactory")) + .addConfiguredBinding("ContentAssistLexerProvider", new StringConcatenationClient() { + @Override + protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { + _builder.append("binder.bind("); + _builder.append(caLexerClass); + _builder.append(".class).toProvider("); + _builder.append(LexerProvider.class); + _builder.append(".create("); + _builder.append(caLexerClass); + _builder.append(".class));"); + _builder.newLineIfNotEmpty(); + } + }); + + if (getProjectConfig().getGenericIde().getSrcGen() != null) { + uiBindings.addTypeToType(TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.antlr.IContentAssistParser"), naming.getParserClass(getGrammar())); + } + + if (hasSyntheticTerminalRule()) { + uiBindings.addTypeToType( + TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.CompletionPrefixProvider"), + TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.IndentationAwareCompletionPrefixProvider")); + } + uiBindings.contributeTo(getLanguage().getEclipsePluginGenModule()); + } +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.xtend deleted file mode 100644 index f295d4cbf7..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.xtend +++ /dev/null @@ -1,530 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.parser.antlr - -import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations -import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations.SemanticPredicate -import com.avaloq.tools.ddk.xtext.generator.parser.common.PredicatesNaming -import com.avaloq.tools.ddk.xtext.parser.ISemanticPredicates -import com.avaloq.tools.ddk.xtext.parser.antlr.AbstractContextualAntlrParser -import com.avaloq.tools.ddk.xtext.parser.antlr.ParserContext -import com.google.common.base.Joiner -import com.google.common.collect.ImmutableSet -import com.google.inject.Inject -import com.google.inject.Singleton -import com.google.inject.name.Names -import java.util.Arrays -import java.util.Set -import java.util.stream.Collectors -import org.antlr.runtime.CharStream -import org.antlr.runtime.Token -import org.antlr.runtime.TokenSource -import org.eclipse.xtext.AbstractElement -import org.eclipse.xtext.GrammarUtil -import org.eclipse.xtext.parser.antlr.AntlrTokenDefProvider -import org.eclipse.xtext.parser.antlr.ITokenDefProvider -import org.eclipse.xtext.parser.antlr.Lexer -import org.eclipse.xtext.parser.antlr.LexerProvider -import org.eclipse.xtext.parser.antlr.XtextTokenStream -import org.eclipse.xtext.xtext.FlattenedGrammarAccess -import org.eclipse.xtext.xtext.RuleFilter -import org.eclipse.xtext.xtext.RuleNames -import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions -import org.eclipse.xtext.xtext.generator.model.FileAccessFactory -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess -import org.eclipse.xtext.xtext.generator.model.IXtextGeneratorFileSystemAccess -import org.eclipse.xtext.xtext.generator.model.JavaFileAccess -import org.eclipse.xtext.xtext.generator.model.TypeReference -import org.eclipse.xtext.xtext.generator.parser.antlr.ContentAssistGrammarNaming -import org.eclipse.xtext.xtext.generator.parser.antlr.GrammarNaming -import org.eclipse.xtext.xtext.generator.parser.antlr.XtextAntlrGeneratorFragment2 - -import static extension org.eclipse.xtext.GrammarUtil.* -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* -import static extension org.eclipse.xtext.xtext.generator.parser.antlr.AntlrGrammarGenUtil.* -import org.eclipse.xtend.lib.annotations.Accessors - -class AnnotationAwareXtextAntlrGeneratorFragment2 extends XtextAntlrGeneratorFragment2 { - - static val ADDITIONAL_CA_REQUIRED_BUNDLE = "com.avaloq.tools.ddk.xtext" - - @Inject AnnotationAwareAntlrGrammarGenerator productionGenerator - @Inject AnnotationAwareAntlrContentAssistGrammarGenerator contentAssistGenerator - @Inject GrammarNaming productionNaming - @Inject FileAccessFactory fileFactory - @Inject ContentAssistGrammarNaming contentAssistNaming - - @Inject extension PredicatesNaming predicatesNaming - @Inject extension GrammarAccessExtensions grammarUtil - @Inject extension GrammarRuleAnnotations annotations - - @Accessors boolean generateContentAssistIfIdeMissing - - boolean removeBacktrackingGuards - int lookaheadThreshold - boolean partialParsing - - Set reservedWords = ImmutableSet.of(); - Set keywords = ImmutableSet.of(); - Set identifierRules = ImmutableSet.of(); - String lexerSuperClassName = ""; - - /** - * Suffix used in the naming convention for the classes responsible for semantic predicates. - */ - static val CLASS_SUFFIX = "SemanticPredicates"; - - override setRemoveBacktrackingGuards(boolean removeBacktrackingGuards) { - this.removeBacktrackingGuards = removeBacktrackingGuards - super.setRemoveBacktrackingGuards(removeBacktrackingGuards) - } - - override setLookaheadThreshold(String lookaheadThreshold) { - this.lookaheadThreshold = Integer.parseInt(lookaheadThreshold) - super.setLookaheadThreshold(lookaheadThreshold) - } - - override setPartialParsing(boolean partialParsing) { - this.partialParsing = partialParsing - super.setPartialParsing(partialParsing) - } - - def setReservedWords(String words) { - reservedWords = toSet(words); - } - - def setIdentifierRules(String rules) { - identifierRules = toSet(rules); - } - - def setKeywords(String words) { - keywords = toSet(words); - } - - def setLexerSuperClassName (String className) { - lexerSuperClassName = className - } - - def private Set toSet(String words) { - Arrays.stream(words.split(",")).map(str | str.trim()).filter(str | !str.isEmpty()).collect(Collectors.toSet()); - } - - protected override void checkGrammar() { - super.checkGrammar(); - getGrammar().annotateGrammar - } - - protected override doGenerate() { - super.doGenerate() - // if there is no ide plugin, write the content assist parser to the ui plugin. - if (generateContentAssistIfIdeMissing && projectConfig.genericIde.srcGen === null) { - generateUiContentAssistGrammar() - generateContentAssistParser().writeTo(projectConfig.eclipsePlugin.srcGen) - if (hasSyntheticTerminalRule()) { - generateContentAssistTokenSource().writeTo(projectConfig.eclipsePlugin.src) - } - addIdeUiBindingsAndImports() - } - - generateAbstractSemanticPredicate().writeTo(projectConfig.runtime.srcGen) - } - - override protected addRuntimeBindingsAndImports() { - super.addRuntimeBindingsAndImports - if (projectConfig.runtime.manifest !== null) { - projectConfig.runtime.manifest=>[ - exportedPackages += #[ - grammar.semanticPredicatesPackageName - ] - ] - } - } - - protected override generateContentAssistGrammar() { - generateContentAssistGrammar(projectConfig.genericIde.srcGen) - } - - protected def generateContentAssistGrammar(IXtextGeneratorFileSystemAccess fsa) { - val extension naming = contentAssistNaming - - contentAssistGenerator.generate(grammar, options, fsa) - - runAntlr(grammar.parserGrammar, grammar.lexerGrammar, fsa) - - simplifyUnorderedGroupPredicatesIfRequired(grammar, fsa, grammar.internalParserClass) - splitParserAndLexerIfEnabled(fsa, grammar.internalParserClass, grammar.lexerClass) - normalizeTokens(fsa, grammar.lexerGrammar.tokensFileName) - suppressWarnings(fsa, grammar.internalParserClass, grammar.lexerClass) - normalizeLineDelimiters(fsa, grammar.lexerClass, grammar.internalParserClass) - if (removeBacktrackingGuards) { - removeBackTrackingGuards(fsa, grammar.internalParserClass, lookaheadThreshold) - } - } - - override protected void addIdeBindingsAndImports() { - super.addIdeBindingsAndImports - if (projectConfig.genericIde.manifest !== null) { - projectConfig.genericIde.manifest=>[ - requiredBundles += ADDITIONAL_CA_REQUIRED_BUNDLE - ] - } - } - - protected def generateUiContentAssistGrammar() { - generateContentAssistGrammar(projectConfig.eclipsePlugin.srcGen) - } - - def protected void addIdeUiBindingsAndImports() { - val extension naming = contentAssistNaming - if (projectConfig.eclipsePlugin.manifest !== null) { - projectConfig.eclipsePlugin.manifest=>[ - exportedPackages += #[ - grammar.lexerClass.packageName, - grammar.parserClass.packageName, - grammar.internalParserClass.packageName - ] - requiredBundles += #[ - "org.antlr.runtime;bundle-version=\"[3.2.0,3.2.1)\"", - ADDITIONAL_CA_REQUIRED_BUNDLE - ] - ] - } - val ideBindings = new GuiceModuleAccess.BindingFactory() - .addConfiguredBinding("ContentAssistLexer", ''' - binder.bind(«grammar.lexerSuperClass».class) - .annotatedWith(«Names».named(«"org.eclipse.xtext.ide.LexerIdeBindings".typeRef».CONTENT_ASSIST)) - .to(«grammar.lexerClass».class); - ''') - .addTypeToType('org.eclipse.xtext.ide.editor.contentassist.antlr.IContentAssistParser'.typeRef, grammar.parserClass) - .addConfiguredBinding("IProposalConflictHelper", ''' - binder.bind(org.eclipse.xtext.ide.editor.contentassist.IProposalConflictHelper.class) - .to(org.eclipse.xtext.ide.editor.contentassist.antlr.AntlrProposalConflictHelper.class); - ''') - if (partialParsing) { - ideBindings.addTypeToType( - "org.eclipse.xtext.ide.editor.contentassist.antlr.ContentAssistContextFactory".typeRef, - "org.eclipse.xtext.ide.editor.contentassist.antlr.PartialContentAssistContextFactory".typeRef - ) - } - if (hasSyntheticTerminalRule) { - ideBindings.addTypeToType( - "org.eclipse.xtext.ide.editor.contentassist.CompletionPrefixProvider".typeRef, - "org.eclipse.xtext.ide.editor.contentassist.IndentationAwareCompletionPrefixProvider".typeRef - ) - } - ideBindings.contributeTo(language.eclipsePluginGenModule) - } - - override JavaFileAccess generateContentAssistParser() { - val extension naming = contentAssistNaming - val file = fileFactory.createGeneratedJavaFile(grammar.parserClass) - file.content = ''' - public class «grammar.parserClass.simpleName» extends «grammar.getParserSuperClass(partialParsing)» { - - «grammar.initNameMappings()» - - @«Inject» - private «grammar.grammarAccess» grammarAccess; - - @«Inject» - private «ISemanticPredicates.typeRef» predicates; - - /** - * Creates compilation context. - * - * @param Input - * Stream - * @return Compilation context - */ - protected «ParserContext.typeRef» createParserContext() { - return new ParserContext(); - } - - @Override - protected «grammar.internalParserClass» createParser() { - «grammar.internalParserClass» result = new «grammar.internalParserClass»(null); - result.setGrammarAccess(grammarAccess); - result.setParserContext(createParserContext()); - result.setPredicates((«grammar.semanticPredicatesFullName.typeRef»)predicates); - return result; - } - - «IF hasSyntheticTerminalRule» - @Override - protected «TokenSource» createLexer(«CharStream» stream) { - return new «grammar.tokenSourceClass»(super.createLexer(stream)); - } - - «ENDIF» - @Override - protected String getRuleName(«AbstractElement» element) { - return nameMappings.getRuleName(element); - } - - @Override - protected String[] getInitialHiddenTokens() { - return new String[] { «FOR hidden : grammar.initialHiddenTokens SEPARATOR ", "»"«hidden»"«ENDFOR» }; - } - - public «grammar.grammarAccess» getGrammarAccess() { - return this.grammarAccess; - } - - public void setGrammarAccess(«grammar.grammarAccess» grammarAccess) { - this.grammarAccess = grammarAccess; - } - - public NameMappings getNameMappings() { - return nameMappings; - } - - public void setNameMappings(NameMappings nameMappings) { - this.nameMappings = nameMappings; - } - } - ''' - return file - } - - protected override generateProductionGrammar() { - val extension naming = productionNaming - val fsa = projectConfig.runtime.srcGen - productionGenerator.lexerSuperClassName = lexerSuperClassName; - productionGenerator.generate(grammar, options, fsa) - - runAntlr(grammar.parserGrammar, grammar.lexerGrammar, fsa) - - simplifyUnorderedGroupPredicatesIfRequired(grammar, fsa, grammar.internalParserClass) - splitParserAndLexerIfEnabled(fsa, grammar.internalParserClass, grammar.lexerClass) - normalizeTokens(fsa, grammar.lexerGrammar.tokensFileName) - suppressWarnings(fsa, grammar.internalParserClass, grammar.lexerClass) - normalizeLineDelimiters(fsa, grammar.internalParserClass, grammar.lexerClass) - - /* filter and ruleNames for flattened grammar */ - val RuleFilter filter = new RuleFilter(); - filter.discardUnreachableRules = true - filter.discardTerminalRules = false - val RuleNames ruleNames = RuleNames.getRuleNames(grammar, true); - - val keywordAnalysisHelper = new KeywordAnalysisHelper(productionGenerator.grammarNaming.getParserGrammar(grammar).grammarFileName, new FlattenedGrammarAccess(ruleNames, filter).getFlattenedGrammar(), identifierRules, reservedWords, keywords, grammarUtil) - keywordAnalysisHelper.printReport(fsa.path); - keywordAnalysisHelper.printViolations(fsa.path); - } - - def JavaFileAccess generateAbstractSemanticPredicate() { - val file = fileFactory.createGeneratedJavaFile(TypeReference.typeRef(grammar.getSemanticPredicatesFullName)) - file.importType(TypeReference.typeRef(grammar.semanticPredicatesFullName)) - file.importType(TypeReference.typeRef(ISemanticPredicates.AbstractSemanticPredicates)) - if(!getGrammar().predicates.isEmpty){ - file.importType(TypeReference.typeRef(ParserContext)) - file.importType(TypeReference.typeRef(Token)) - for (inheritedGrammar : annotations.allInheritedGrammars(getGrammar())) { - file.importType(TypeReference.typeRef(GrammarUtil.getNamespace(inheritedGrammar) + ".grammar." + GrammarUtil.getSimpleName(inheritedGrammar) + CLASS_SUFFIX)) - } - } - file.importType(TypeReference.typeRef(Singleton)) - file.content = ''' - /** - * Provides semantic predicates as specified in the grammar. Language may need to override - * this class in order to provide concrete implementations for predicates. - */ - @Singleton - public class «grammar.getSemanticPredicatesSimpleName()» extends AbstractSemanticPredicates { - «FOR element : getGrammar().predicates» - - /** - * Predicate for grammar rule «element.name». - * - * @param input - * Input from Lexer - * @return {@code true} if the grammar rule is enabled, {@code false} otherwise - */ - public boolean «element.name»(ParserContext parserContext) { - «element.getRulePredicateCondition» - } - «ENDFOR» - - «FOR element : getGrammar().predicates» - - /** - * Message for «element.name» predicate. - * - * @param input - * Input from Lexer - * @return {@code true} if the grammar rule is enabled, {@code false} otherwise - */ - public String «element.message»(Token token) { - «element.getRulePredicateMessage» - } - «ENDFOR» - } - ''' - file - } - - /** - * Returns name for the predicate message method. - * - * @param predicate - * Semantic predicate, must not be {@code null} - * @return Content for the predicate message method - */ - def String getRulePredicateMessage(SemanticPredicate predicate){ - if(predicate.keywords!==null) - ''' - return "Unexpected: " + token.getText() + ". Expected: '«Joiner.on("', '").join(predicate.keywords)»'"; - ''' - else - ''' - /* Default message. Intended to be overridden. */ - return "Condition «predicate.name» is not fullfilled "; - ''' - } - - /** - * Returns predicate condition (default condition). - * - * @param predicate - * Semantic predicate, must not be {@code null} - * @return A string containing the condition for the semantic predicate or {@code null} - */ - def String getRulePredicateCondition(SemanticPredicate predicate) { - if (predicate.keywords !== null) { - val condition = predicate.keywords.stream(). - map([s | '''"«s»".equalsIgnoreCase(text)''']).collect(Collectors.joining(" || ")) - ''' - String text = parserContext.getInput().LT(1).getText(); - return «condition»; - ''' - } else { - return "return " + predicate.grammar + CLASS_SUFFIX + "." + predicate.name + "(parserContext);\n" - } - } - - override JavaFileAccess generateProductionParser() { - val extension naming = productionNaming - val file = fileFactory.createGeneratedJavaFile(grammar.parserClass) - file.importType(TypeReference.typeRef(grammar.semanticPredicatesFullName)) - file.importType(TypeReference.typeRef(ISemanticPredicates)) - - file.content = ''' - public class «grammar.parserClass.simpleName» extends «AbstractContextualAntlrParser» { - - @«Inject» - private «grammar.grammarAccess» grammarAccess; - - @«Inject» - private ISemanticPredicates predicates; - - @Override - protected void setInitialHiddenTokens(«XtextTokenStream» tokenStream) { - tokenStream.setInitialHiddenTokens(«FOR hidden : grammar.initialHiddenTokens SEPARATOR ", "»"«hidden»"«ENDFOR»); - } - - «IF hasSyntheticTerminalRule» - @Override - protected «TokenSource» createLexer(«CharStream» stream) { - return new «grammar.tokenSourceClass»(super.createLexer(stream)); - } - - /** - * Indentation aware languages do not support partial parsing since the lexer is inherently stateful. - * Override and return {@code true} if your terminal splitting is stateless. - */ - @Override - protected boolean isReparseSupported() { - return false; - } - «ENDIF» - - @Override - protected «grammar.internalParserClass» createParser(«XtextTokenStream» stream) { - return new «grammar.internalParserClass»(stream, getGrammarAccess(), createParserContext(), («grammar.semanticPredicatesSimpleName») predicates); - } - - @Override - protected String getDefaultRuleName() { - return "«grammar.allParserRules.head.originalElement.name»"; - } - - public «grammar.grammarAccess» getGrammarAccess() { - return this.grammarAccess; - } - - public void setGrammarAccess(«grammar.grammarAccess» grammarAccess) { - this.grammarAccess = grammarAccess; - } - } - ''' - file - } - - override protected addUiBindingsAndImports() { - /* Overridden to remove the binding for IContentAssistParser, which we bind at a different place. - * If we would register it here, we would have conflicting bindings for IContentAssistParser. - */ - val extension naming = contentAssistNaming - val caLexerClass = grammar.lexerClass - - if (projectConfig.genericIde.manifest !== null) { - projectConfig.genericIde.manifest=>[ - exportedPackages += #[ - caLexerClass.packageName, - grammar.parserClass.packageName, - grammar.internalParserClass.packageName - ] - ] - } - val uiBindings = new GuiceModuleAccess.BindingFactory() - .addTypeToType( - "org.eclipse.xtext.ui.editor.contentassist.IProposalConflictHelper".typeRef, - "org.eclipse.xtext.ui.editor.contentassist.antlr.AntlrProposalConflictHelper".typeRef - ) - .addConfiguredBinding("ContentAssistLexer", ''' - binder.bind(«grammar.lexerSuperClass».class) - .annotatedWith(«Names».named(«"org.eclipse.xtext.ide.LexerIdeBindings".typeRef».CONTENT_ASSIST)) - .to(«caLexerClass».class); - ''') - // registration of the 'ContentAssistLexer' is put in front of the 'HighlightingLexer' - // in order to let 'caLexerClass' get added to the imports, since it is referenced - // several times and the lexer classes' simple names are usually identical - .addConfiguredBinding("HighlightingLexer", ''' - binder.bind(«Lexer».class) - .annotatedWith(«Names».named(«"org.eclipse.xtext.ide.LexerIdeBindings".typeRef».HIGHLIGHTING)) - .to(«productionNaming.getLexerClass(grammar)».class); - ''') - .addConfiguredBinding("HighlightingTokenDefProvider", ''' - binder.bind(«ITokenDefProvider».class) - .annotatedWith(«Names».named(«"org.eclipse.xtext.ide.LexerIdeBindings".typeRef».HIGHLIGHTING)) - .to(«AntlrTokenDefProvider».class); - ''') - .addTypeToType( - new TypeReference("org.eclipse.xtext.ui.editor.contentassist", "ContentAssistContext.Factory"), - "org.eclipse.xtext.ui.editor.contentassist.antlr.DelegatingContentAssistContextFactory".typeRef - ) - .addConfiguredBinding("ContentAssistLexerProvider", ''' - binder.bind(«caLexerClass».class).toProvider(«LexerProvider».create(«caLexerClass».class)); - ''') - - if (projectConfig.genericIde.srcGen !== null) { - uiBindings.addTypeToType("org.eclipse.xtext.ide.editor.contentassist.antlr.IContentAssistParser".typeRef, grammar.parserClass) - } - - if (hasSyntheticTerminalRule) { - uiBindings.addTypeToType( - "org.eclipse.xtext.ide.editor.contentassist.CompletionPrefixProvider".typeRef, - "org.eclipse.xtext.ide.editor.contentassist.IndentationAwareCompletionPrefixProvider".typeRef - ) - } - uiBindings.contributeTo(language.eclipsePluginGenModule) - } -} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java new file mode 100644 index 0000000000..d13bda02da --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java @@ -0,0 +1,767 @@ +/** + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * Contributors: + * Avaloq Group AG - initial API and implementation + */ +package com.avaloq.tools.ddk.xtext.generator.parser.common; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.common.notify.Notifier; +import org.eclipse.emf.common.notify.impl.AdapterImpl; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.AbstractElement; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.Action; +import org.eclipse.xtext.Alternatives; +import org.eclipse.xtext.Assignment; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.Group; +import org.eclipse.xtext.ParserRule; +import org.eclipse.xtext.RuleCall; +import org.eclipse.xtext.nodemodel.ICompositeNode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.util.internal.EmfAdaptable; +import org.eclipse.xtext.xbase.lib.Pure; +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; +import org.eclipse.xtext.xtext.RuleWithParameterValues; +import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions; + +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.inject.Inject; + +public class GrammarRuleAnnotations { + + @EmfAdaptable + public static class NoBacktrack { + public static class NoBacktrackAdapter extends AdapterImpl { + private GrammarRuleAnnotations.NoBacktrack element; + + public NoBacktrackAdapter(final GrammarRuleAnnotations.NoBacktrack element) { + this.element = element; + } + + public GrammarRuleAnnotations.NoBacktrack get() { + return this.element; + } + + @Override + public boolean isAdapterForType(final Object object) { + return object == GrammarRuleAnnotations.NoBacktrack.class; + } + } + + public static GrammarRuleAnnotations.NoBacktrack findInEmfObject(final Notifier emfObject) { + for (Adapter adapter : emfObject.eAdapters()) { + if (adapter instanceof GrammarRuleAnnotations.NoBacktrack.NoBacktrackAdapter) { + return ((GrammarRuleAnnotations.NoBacktrack.NoBacktrackAdapter) adapter).get(); + } + } + return null; + } + + public static GrammarRuleAnnotations.NoBacktrack removeFromEmfObject(final Notifier emfObject) { + List adapters = emfObject.eAdapters(); + for (int i = 0, max = adapters.size(); i < max; i++) { + Adapter adapter = adapters.get(i); + if (adapter instanceof GrammarRuleAnnotations.NoBacktrack.NoBacktrackAdapter) { + emfObject.eAdapters().remove(i); + return ((GrammarRuleAnnotations.NoBacktrack.NoBacktrackAdapter) adapter).get(); + } + } + return null; + } + + public void attachToEmfObject(final Notifier emfObject) { + NoBacktrack result = findInEmfObject(emfObject); + if (result != null) { + throw new IllegalStateException("The given EMF object already contains an adapter for NoBacktrack"); + } + GrammarRuleAnnotations.NoBacktrack.NoBacktrackAdapter adapter = new GrammarRuleAnnotations.NoBacktrack.NoBacktrackAdapter(this); + emfObject.eAdapters().add(adapter); + } + + @Override + @Pure + public int hashCode() { + return 1; + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + return true; + } + + @Override + @Pure + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + return b.toString(); + } + } + + /** + * Gated predicate: {condition}?=> + * Validating predicate: {condition message}? + */ + @EmfAdaptable + public static class SemanticPredicate { + public static class SemanticPredicateAdapter extends AdapterImpl { + private GrammarRuleAnnotations.SemanticPredicate element; + + public SemanticPredicateAdapter(final GrammarRuleAnnotations.SemanticPredicate element) { + this.element = element; + } + + public GrammarRuleAnnotations.SemanticPredicate get() { + return this.element; + } + + @Override + public boolean isAdapterForType(final Object object) { + return object == GrammarRuleAnnotations.SemanticPredicate.class; + } + } + + private final String name; + + private final String message; + + private final String grammar; + + private final List keywords; + + public static GrammarRuleAnnotations.SemanticPredicate findInEmfObject(final Notifier emfObject) { + for (Adapter adapter : emfObject.eAdapters()) { + if (adapter instanceof GrammarRuleAnnotations.SemanticPredicate.SemanticPredicateAdapter) { + return ((GrammarRuleAnnotations.SemanticPredicate.SemanticPredicateAdapter) adapter).get(); + } + } + return null; + } + + public static GrammarRuleAnnotations.SemanticPredicate removeFromEmfObject(final Notifier emfObject) { + List adapters = emfObject.eAdapters(); + for (int i = 0, max = adapters.size(); i < max; i++) { + Adapter adapter = adapters.get(i); + if (adapter instanceof GrammarRuleAnnotations.SemanticPredicate.SemanticPredicateAdapter) { + emfObject.eAdapters().remove(i); + return ((GrammarRuleAnnotations.SemanticPredicate.SemanticPredicateAdapter) adapter).get(); + } + } + return null; + } + + public void attachToEmfObject(final Notifier emfObject) { + SemanticPredicate result = findInEmfObject(emfObject); + if (result != null) { + throw new IllegalStateException("The given EMF object already contains an adapter for SemanticPredicate"); + } + GrammarRuleAnnotations.SemanticPredicate.SemanticPredicateAdapter adapter = new GrammarRuleAnnotations.SemanticPredicate.SemanticPredicateAdapter(this); + emfObject.eAdapters().add(adapter); + } + + public SemanticPredicate(final String name, final String message, final String grammar, final List keywords) { + super(); + this.name = name; + this.message = message; + this.grammar = grammar; + this.keywords = keywords; + } + + @Override + @Pure + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); + result = prime * result + ((this.message == null) ? 0 : this.message.hashCode()); + result = prime * result + ((this.grammar == null) ? 0 : this.grammar.hashCode()); + return prime * result + ((this.keywords == null) ? 0 : this.keywords.hashCode()); + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GrammarRuleAnnotations.SemanticPredicate other = (GrammarRuleAnnotations.SemanticPredicate) obj; + if (this.name == null) { + if (other.name != null) { + return false; + } + } else if (!this.name.equals(other.name)) { + return false; + } + if (this.message == null) { + if (other.message != null) { + return false; + } + } else if (!this.message.equals(other.message)) { + return false; + } + if (this.grammar == null) { + if (other.grammar != null) { + return false; + } + } else if (!this.grammar.equals(other.grammar)) { + return false; + } + if (this.keywords == null) { + if (other.keywords != null) { + return false; + } + } else if (!this.keywords.equals(other.keywords)) { + return false; + } + return true; + } + + @Override + @Pure + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("name", this.name); + b.add("message", this.message); + b.add("grammar", this.grammar); + b.add("keywords", this.keywords); + return b.toString(); + } + + @Pure + public String getName() { + return this.name; + } + + @Pure + public String getMessage() { + return this.message; + } + + @Pure + public String getGrammar() { + return this.grammar; + } + + @Pure + public List getKeywords() { + return this.keywords; + } + } + + @EmfAdaptable + public static class GrammarAnnotations { + public static class GrammarAnnotationsAdapter extends AdapterImpl { + private GrammarRuleAnnotations.GrammarAnnotations element; + + public GrammarAnnotationsAdapter(final GrammarRuleAnnotations.GrammarAnnotations element) { + this.element = element; + } + + public GrammarRuleAnnotations.GrammarAnnotations get() { + return this.element; + } + + @Override + public boolean isAdapterForType(final Object object) { + return object == GrammarRuleAnnotations.GrammarAnnotations.class; + } + } + + private final List predicates; + + public static GrammarRuleAnnotations.GrammarAnnotations findInEmfObject(final Notifier emfObject) { + for (Adapter adapter : emfObject.eAdapters()) { + if (adapter instanceof GrammarRuleAnnotations.GrammarAnnotations.GrammarAnnotationsAdapter) { + return ((GrammarRuleAnnotations.GrammarAnnotations.GrammarAnnotationsAdapter) adapter).get(); + } + } + return null; + } + + public static GrammarRuleAnnotations.GrammarAnnotations removeFromEmfObject(final Notifier emfObject) { + List adapters = emfObject.eAdapters(); + for (int i = 0, max = adapters.size(); i < max; i++) { + Adapter adapter = adapters.get(i); + if (adapter instanceof GrammarRuleAnnotations.GrammarAnnotations.GrammarAnnotationsAdapter) { + emfObject.eAdapters().remove(i); + return ((GrammarRuleAnnotations.GrammarAnnotations.GrammarAnnotationsAdapter) adapter).get(); + } + } + return null; + } + + public void attachToEmfObject(final Notifier emfObject) { + GrammarAnnotations result = findInEmfObject(emfObject); + if (result != null) { + throw new IllegalStateException("The given EMF object already contains an adapter for GrammarAnnotations"); + } + GrammarRuleAnnotations.GrammarAnnotations.GrammarAnnotationsAdapter adapter = new GrammarRuleAnnotations.GrammarAnnotations.GrammarAnnotationsAdapter(this); + emfObject.eAdapters().add(adapter); + } + + public GrammarAnnotations(final List predicates) { + super(); + this.predicates = predicates; + } + + @Override + @Pure + public int hashCode() { + return 31 * 1 + ((this.predicates == null) ? 0 : this.predicates.hashCode()); + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GrammarRuleAnnotations.GrammarAnnotations other = (GrammarRuleAnnotations.GrammarAnnotations) obj; + if (this.predicates == null) { + if (other.predicates != null) { + return false; + } + } else if (!this.predicates.equals(other.predicates)) { + return false; + } + return true; + } + + @Override + @Pure + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("predicates", this.predicates); + return b.toString(); + } + + @Pure + public List getPredicates() { + return this.predicates; + } + } + + /** + * Pattern to deactivate backtracking for single rule. + */ + private static final Pattern NO_BACKTRACK_ANNOTATION_PATTERN = Pattern.compile("@NoBacktrack", Pattern.MULTILINE); // $NON-NLS-1$ + + /** + * Pattern to search for keyword rule annotations and extracting list of comma-separated keywords. + */ + private static final Pattern KEYWORD_RULE_ANNOTATION_PATTERN = Pattern.compile("@KeywordRule\\(([\\w\\s,]+)\\)", + Pattern.MULTILINE); // $NON-NLS-1$ + + /** + * Pattern to search for semantic predicate rule annotation that enables the given rule. + */ + private static final Pattern SEMANTIC_PREDICATE_PATTERN = Pattern.compile("@SemanticPredicate\\(([\\s]*[\\w]+)[\\s]*\\)", + Pattern.MULTILINE); // $NON-NLS-1$ + + /** + * Splits comma separated list of keywords. + */ + private static final Splitter KEYWORDS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings(); + + @Inject + private GrammarAccessExtensions grammarExtensions; + + public boolean hasNoBacktrackAnnotation(final AbstractRule rule) { + return getNoBacktrackAnnotation(rule) != null; + } + + /** + * Checks if the given element is contained in a rule with a NoBacktrack annotation. + * + * @param element + * Grammar element + * @return {@code true} if there is an annotation on the enclosing rule, {@code false} otherwise + */ + public boolean hasNoBacktrackAnnotation(final AbstractElement element) { + return hasNoBacktrackAnnotation(GrammarUtil.containingRule(element)); + } + + public boolean hasSemanticPredicate(final AbstractElement element) { + return findPredicate(element) != null; + } + + public boolean hasValidatingPredicate(final AbstractRule rule) { + return getSemanticPredicateAnnotation(rule) != null; + } + + /** + * Returns disambiguating/validating semantic predicate. + * + * @param element + * Xtext grammar element + * @return A string containing the semantic predicate or an empty string + */ + public String generateValidatingPredicate(final AbstractRule rule) { + final SemanticPredicate predicate = getSemanticPredicateAnnotation(rule); + if (predicate != null) { + return generateValidatingPredicate(predicate); + } + return ""; + } + + public boolean isGatedPredicateRequired(final AbstractElement element) { + return isStartingWithPredicatedRule(element) && isAlternativeAvailable(element); + } + + /** + * Returns gated semantic predicate. + * + * @param element + * Xtext grammar element + * @return A string containing the semantic predicate or an empty string + */ + public String generateGatedPredicate(final AbstractElement element) { + final SemanticPredicate predicate = findPredicate(element); + if (predicate != null) { + return generateGatedPredicate(predicate); + } + return ""; + } + + public GrammarAnnotations annotateGrammar(final Grammar grammar) { + GrammarAnnotations annotations = GrammarAnnotations.findInEmfObject(grammar); + if (annotations == null) { + List collected = grammar.getRules().stream() + .map(r -> annotateRule(r)) + .filter(a -> a != null) + .collect(Collectors.toList()); + annotations = new GrammarAnnotations(collected); + annotations.attachToEmfObject(grammar); + + Set inheritedGrammars = allInheritedGrammars(grammar); + for (Grammar inheritedGrammar : inheritedGrammars) { + GrammarAnnotations inheritedAnnotations = GrammarAnnotations.findInEmfObject(inheritedGrammar); + if (inheritedAnnotations == null) { + List inheritedCollected = inheritedGrammar.getRules().stream() + .map(r -> annotateRule(r)) + .filter(a -> a != null) + .collect(Collectors.toList()); + inheritedAnnotations = new GrammarAnnotations(inheritedCollected); + inheritedAnnotations.attachToEmfObject(inheritedGrammar); + } + annotations.predicates.addAll(inheritedAnnotations.predicates); + } + } + return annotations; + } + + public Set allInheritedGrammars(final Grammar grammar) { + HashSet result = Sets.newHashSet(); + List allParserRules = GrammarUtil.allParserRules(grammar); + for (AbstractRule rule : allParserRules) { + Grammar ruleGrammar = GrammarUtil.getGrammar(rule); + if (!ruleGrammar.equals(grammar) && this.isSemanticPredicate(rule)) { + result.add(ruleGrammar); + } + } + return new HashSet<>(result); + } + + public List predicates(final Grammar grammar) { + return annotateGrammar(grammar).predicates; + } + + /** + * Checks whether this abstract element leads directly to a keyword rule. + * + * @param element + * Element call + * @return {@code true} if the rule leads to a keyword rule + */ + public boolean isStartingWithPredicatedRule(final AbstractElement element) { + if (element instanceof CrossReference) { + return findPredicate(((CrossReference) element).getTerminal()) != null; + } + return findPredicate(element) != null; + } + + /** + * Finds the predicated rule the given element leads to. + * + * @param element + * Current element + * @return Keyword rule or {@code null} if the given element does not lead to a keyword rule + */ + public SemanticPredicate findPredicate(final AbstractElement element) { + if (element instanceof RuleCall) { + final SemanticPredicate predicate = getSemanticPredicateAnnotation(((RuleCall) element).getRule()); + if (predicate != null) { + return predicate; + } + return findPredicate(((RuleCall) element).getRule().getAlternatives()); + } + if (GrammarUtil.isOptionalCardinality(element)) { + return null; + } + if (element instanceof CrossReference) { + return findPredicate(((CrossReference) element).getTerminal()); + } + if (element instanceof Group) { + final AbstractElement firstNonActionElement = getFirstNonActionElement((Group) element); + if (firstNonActionElement != null) { + return findPredicate(firstNonActionElement); + } + } + if (element instanceof Assignment) { + return findPredicate(((Assignment) element).getTerminal()); + } + return null; + } + + public boolean isRuleWithPredicate(final AbstractRule rule) { + return getSemanticPredicateAnnotation(rule) != null; + } + + public AbstractElement getFirstNonActionElement(final Group group) { + for (AbstractElement groupElement : group.getElements()) { + if (!(groupElement instanceof Action)) { + return groupElement; + } + } + return null; + } + + /** + * Checks whether there is a viable alternative (i.e. not potentially gated by another gated semantic predicate) for the current element. + * If there is no alternative we should not insert gated semantic predicates, but validating semantic predicates, so we get a better error recovery and + * a correct message. We should not also propagate validating predicates in the callers. If we do so this will damage error recovery in the callers. + * + * @param element + * Grammar element + * @return {@code true} if there is an alternative available and the gated semantic predicate can be inserted + */ + public boolean isAlternativeAvailable(final AbstractElement element) { + if (GrammarUtil.isOptionalCardinality(element)) { + return true; + } + final EObject container = element.eContainer(); + if (container instanceof Assignment) { + return isAlternativeAvailable((AbstractElement) container); + } else if (container instanceof CrossReference) { + return isAlternativeAvailable((AbstractElement) container); + } else if (container instanceof Group) { + if (isFirstNonActionElement((Group) container, element)) { + return isAlternativeAvailable((AbstractElement) container); + } + } else if (container instanceof Alternatives) { + for (AbstractElement alternative : ((Alternatives) container).getElements()) { + if (!Objects.equals(alternative, element)) { + return true; + } + } + } + return false; + } + + /** + * Checks if the given grammar element is the first non action element in the given group. + * + * @param group + * where the position is checked, must not be {@code null} + * @param element + * to check, must not be {@code null} + * @return {@code true}, if is first non action element is the given element, {@code false} otherwise + */ + public boolean isFirstNonActionElement(final Group group, final AbstractElement element) { + return Objects.equals(element, getFirstNonActionElement(group)); + } + + public String generateGatedPredicate(final SemanticPredicate predicate) { + StringBuilder sb = new StringBuilder(); + sb.append("{predicates."); + sb.append(predicate.name); + sb.append("(parserContext)}?=>"); + return sb.toString(); + } + + public String generateValidatingPredicate(final SemanticPredicate predicate) { + StringBuilder sb = new StringBuilder(); + sb.append("{predicates."); + sb.append(predicate.name); + sb.append("(parserContext) /* @ErrorMessage("); + sb.append(predicate.message); + sb.append(") */}?"); + return sb.toString(); + } + + /** + * Translate annotations in comments into predicate annotations. + * + *

+ * Gated vs. Disambiguating predicates On the first look a disambiguating semantic predicate + * would be a right choice. However inserting them would be much more difficult. The reason is that we need + * not only insert them in the beginning of the current rule, but also propagate before actions into alternatives + * that call this rule. We have to do the same for gated predicated, however there is one important difference. + * If we have an alternative like {@code rule: (Keyword1 | Keyword2) Keyword3 ;} then we need to insert the predicate + * only before the first alternative (Keyword1). If we insert disambiguating semantic predicate before both + * the exception the predicate may throw can destroy recovery for the entire rule i.e. will not try going to Keyword3. + * We, however, need validating predicate in the beginning of each rule Keyword2, Keyword3. This requires an + * extra analysis which might be a next step. Gated predicates we can safely insert before Keyword1 and Keyword2. + * This will have no negative impact. We still need validating predicates in Keyword rules themselves. + *

+ */ + public SemanticPredicate annotateRule(final AbstractRule rule) { + final String text = getText(rule); + SemanticPredicate predicate = null; + if (text != null) { + final String ruleGrammarName = GrammarUtil.getSimpleName(GrammarUtil.getGrammar(rule)); + predicate = getKeywordRulePredicate(text, rule.getName(), ruleGrammarName); + if (predicate != null) { + predicate.attachToEmfObject(rule); + } + final SemanticPredicate semanticPredicate = getSemanticPredicate(text, ruleGrammarName); + if (semanticPredicate != null) { + if (predicate != null) { + throw new IllegalArgumentException("You may not combine keyword annotations with semantic predicate annotations on one rule: " + rule.getName()); + } + semanticPredicate.attachToEmfObject(rule); + predicate = semanticPredicate; + } + final NoBacktrack noBacktrack = getNoBacktrack(text); + if (noBacktrack != null) { + noBacktrack.attachToEmfObject(rule); + } + } + return predicate; + } + + public SemanticPredicate getSemanticPredicateAnnotation(final AbstractRule rule) { + if (rule != null) { + RuleWithParameterValues ruleWithParams = RuleWithParameterValues.findInEmfObject(rule); + AbstractRule original = null; + if (ruleWithParams != null) { + original = ruleWithParams.getOriginal(); + } + if (original == null) { + original = rule; + } + return SemanticPredicate.findInEmfObject(original); + } + return null; + } + + public NoBacktrack getNoBacktrackAnnotation(final AbstractRule rule) { + if (rule != null) { + AbstractRule original = RuleWithParameterValues.findInEmfObject(rule).getOriginal(); + if (original == null) { + original = rule; + } + return NoBacktrack.findInEmfObject(original); + } + return null; + } + + /** + * Checks if the given rule contains {@code @KeywordRule(kw1,kw2)} annotation. + */ + public SemanticPredicate getKeywordRulePredicate(final String text, final String ruleName, final String grammar) { + final Matcher matcher = KEYWORD_RULE_ANNOTATION_PATTERN.matcher(text); + if (matcher.find()) { + ArrayList keywordsList = Lists.newArrayList(KEYWORDS_SPLITTER.split(matcher.group(1))); + return new SemanticPredicate( + "is" + ruleName + "Enabled", + "get" + ruleName + "EnabledMessage", + grammar, + keywordsList); + } + return null; + } + + /** + * Checks if the given rule contains {@code @SemanticPredicate(condition)} annotation. + */ + public SemanticPredicate getSemanticPredicate(final String text, final String grammar) { + final Matcher matcher = SEMANTIC_PREDICATE_PATTERN.matcher(text); + if (matcher.find()) { + return new SemanticPredicate( + matcher.group(1), + "get" + matcher.group(1) + "Message", + grammar, + null); + } + return null; + } + + /** + * Checks if the given rule contains a NoBacktrack annotation. + */ + public NoBacktrack getNoBacktrack(final String text) { + final Matcher matcher = NO_BACKTRACK_ANNOTATION_PATTERN.matcher(text); + if (matcher.find()) { + return new NoBacktrack(); + } + return null; + } + + public String getText(final AbstractRule rule) { + final ICompositeNode node = NodeModelUtils.getNode(rule); + if (node != null) { + return node.getText(); + } else { + return grammarExtensions.grammarFragmentToString(rule, ""); + } + } + + /** + * Checks if the given rule contains a keyword rule annotation. + * + * @param rule + * Grammar rule + * @return {@code true} if there is an annotation, {@code false} otherwise + */ + public boolean isSemanticPredicate(final AbstractRule rule) { + String text = getText(rule); + if (text != null) { + final Matcher matcher = SEMANTIC_PREDICATE_PATTERN.matcher(text); + if (matcher.find()) { + return true; + } + } + return false; + } +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.xtend deleted file mode 100644 index 13097b749b..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.xtend +++ /dev/null @@ -1,406 +0,0 @@ -/** - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * Contributors: - * Avaloq Group AG - initial API and implementation - */ - -package com.avaloq.tools.ddk.xtext.generator.parser.common - -import com.google.common.base.Splitter -import com.google.common.collect.Lists -import java.util.List -import java.util.regex.Pattern -import org.eclipse.xtend.lib.annotations.Data -import org.eclipse.xtext.AbstractElement -import org.eclipse.xtext.AbstractRule -import org.eclipse.xtext.Action -import org.eclipse.xtext.Alternatives -import org.eclipse.xtext.Assignment -import org.eclipse.xtext.CrossReference -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.GrammarUtil -import org.eclipse.xtext.Group -import org.eclipse.xtext.RuleCall -import org.eclipse.xtext.nodemodel.util.NodeModelUtils -import org.eclipse.xtext.util.internal.EmfAdaptable -import org.eclipse.xtext.xtext.RuleWithParameterValues -import java.util.stream.Collectors -import java.util.Set -import com.google.common.collect.Sets -import org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions -import com.google.inject.Inject - -class GrammarRuleAnnotations { - - /** - * Pattern to deactivate backtracking for single rule. - */ - static final Pattern NO_BACKTRACK_ANNOTATION_PATTERN = Pattern.compile("@NoBacktrack", Pattern.MULTILINE); // $NON-NLS-1$ - /** - * Pattern to search for keyword rule annotations and extracting list of comma-separated keywords. - */ - static final Pattern KEYWORD_RULE_ANNOTATION_PATTERN = Pattern.compile("@KeywordRule\\(([\\w\\s,]+)\\)", - Pattern.MULTILINE); // $NON-NLS-1$ - /** - * Pattern to search for semantic predicate rule annotation that enables the given rule. - */ - static final Pattern SEMANTIC_PREDICATE_PATTERN = Pattern.compile("@SemanticPredicate\\(([\\s]*[\\w]+)[\\s]*\\)", - Pattern.MULTILINE); // $NON-NLS-1$ - /** - * Splits comma separated list of keywords. - */ - static final Splitter KEYWORDS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings(); - - @Inject - GrammarAccessExtensions grammarExtensions; - - @EmfAdaptable - @Data - static class NoBacktrack { - } - -/** - * Gated predicate: {condition}?=> - * Validating predicate: {condition message}? - */ - @EmfAdaptable - @Data - static class SemanticPredicate { - val String name - val String message - val String grammar - val List keywords - } - - @EmfAdaptable - @Data - static class GrammarAnnotations { - val List predicates - } - - def boolean hasNoBacktrackAnnotation(AbstractRule rule){ - return getNoBacktrackAnnotation(rule) !== null - } - - /** - * Checks if the given element is contained in a rule with a NoBacktrack annotation. - * - * @param element - * Grammar element - * @return {@code true} if there is an annotation on the enclosing rule, {@code false} otherwise - */ - def boolean hasNoBacktrackAnnotation(AbstractElement element){ - return hasNoBacktrackAnnotation(GrammarUtil.containingRule(element)) - } - - def boolean hasSemanticPredicate(AbstractElement element){ - return findPredicate(element) !== null - } - - def boolean hasValidatingPredicate(AbstractRule rule){ - return getSemanticPredicateAnnotation(rule) !== null - } - - /** - * Returns disambiguating/validating semantic predicate. - * - * @param element - * Xtext grammar element - * @return A string containing the semantic predicate or an empty string - */ - def String generateValidatingPredicate(AbstractRule rule){ - val predicate = getSemanticPredicateAnnotation(rule) - if(predicate !== null) return generateValidatingPredicate(predicate) - return ""; - } - - def boolean isGatedPredicateRequired(AbstractElement element){ - return isStartingWithPredicatedRule(element) && isAlternativeAvailable(element); - } - - /** - * Returns gated semantic predicate. - * - * @param element - * Xtext grammar element - * @return A string containing the semantic predicate or an empty string - */ - def String generateGatedPredicate(AbstractElement element){ - val predicate = findPredicate(element) - if(predicate !== null) return generateGatedPredicate(predicate) - return ""; - } - - def GrammarAnnotations annotateGrammar(Grammar grammar){ - var annotations = GrammarAnnotations.findInEmfObject(grammar) - if (annotations === null) { - annotations = new GrammarAnnotations(grammar.rules.stream().map[r | annotateRule(r)].filter([a | a !== null]).collect(Collectors.toList)) - annotations.attachToEmfObject(grammar) - - var inheritedGrammars = allInheritedGrammars(grammar) - for (inheritedGrammar : inheritedGrammars) { - var inheritedAnnotations = GrammarAnnotations.findInEmfObject(inheritedGrammar) - if (inheritedAnnotations === null) { - inheritedAnnotations = new GrammarAnnotations(inheritedGrammar.rules.stream().map[r | annotateRule(r)].filter([a | a !== null]).collect(Collectors.toList)) - inheritedAnnotations.attachToEmfObject(inheritedGrammar) - } - annotations.predicates.addAll(inheritedAnnotations.predicates) - } - } - - return annotations - } - - def Set allInheritedGrammars(Grammar grammar) { - var result = Sets.newHashSet(); - for (AbstractRule rule : GrammarUtil.allParserRules(grammar)) { - var ruleGrammar = GrammarUtil.getGrammar(rule); - if (!ruleGrammar.equals(grammar) && this.isSemanticPredicate(rule)) { - result.addAll(ruleGrammar) - } - } - return result.toSet; - } - - def List predicates(Grammar grammar){ - return grammar.annotateGrammar.predicates - } - - /** - * Checks whether this abstract element leads directly to a keyword rule. - * - * @param element - * Element call - * @return {@code true} if the rule leads to a keyword rule - */ - def boolean isStartingWithPredicatedRule(AbstractElement element) { - if (element instanceof CrossReference) { - return findPredicate(element.getTerminal()) !== null; - } - return findPredicate(element) !== null; - } - - /** - * Finds the predicated rule the given element leads to. - * - * @param element - * Current element - * @return Keyword rule or {@code null} if the given element does not lead to a keyword rule - */ - def SemanticPredicate findPredicate(AbstractElement element) { - if (element instanceof RuleCall) { - val predicate = getSemanticPredicateAnnotation(element.getRule()) - if (predicate !== null) { - return predicate; - } - return findPredicate(element.getRule().getAlternatives()); - } - if (GrammarUtil.isOptionalCardinality(element)) { - return null; - } - if (element instanceof CrossReference) { - return findPredicate(element.getTerminal()); - } - if (element instanceof Group) { - val firstNonActionElement = getFirstNonActionElement(element); - if (firstNonActionElement !== null) { - return findPredicate(firstNonActionElement); - } - } - if (element instanceof Assignment) { - return findPredicate((element).getTerminal()); - } - return null; - } - - def boolean isRuleWithPredicate(AbstractRule rule){ - return getSemanticPredicateAnnotation(rule) !== null - } - - def AbstractElement getFirstNonActionElement(Group group){ - for (AbstractElement groupElement : group.getElements()) { - if (!(groupElement instanceof Action)) { - return groupElement; - } - } - return null; - } - - /** - * Checks whether there is a viable alternative (i.e. not potentially gated by another gated semantic predicate) for the current element. - * If there is no alternative we should not insert gated semantic predicates, but validating semantic predicates, so we get a better error recovery and - * a correct message. We should not also propagate validating predicates in the callers. If we do so this will damage error recovery in the callers. - * - * @param element - * Grammar element - * @return {@code true} if there is an alternative available and the gated semantic predicate can be inserted - */ - def boolean isAlternativeAvailable(AbstractElement element) { - if (GrammarUtil.isOptionalCardinality(element)) { - return true; - } - val container = element.eContainer(); - if (container instanceof Assignment) { - return isAlternativeAvailable(container); - } else if (container instanceof CrossReference) { - return isAlternativeAvailable(container); - } else if (container instanceof Group) { - if (isFirstNonActionElement(container, element)) { - return isAlternativeAvailable(container); - } - } else if (container instanceof Alternatives) { - for (AbstractElement alternative : container.getElements()) { - if (alternative != element /*&& !isGated(alternative)*/) { - return true; - } - } - } - return false; - } - - /** - * Checks if the given grammar element is the first non action element in the given group. - * - * @param group - * where the position is checked, must not be {@code null} - * @param element - * to check, must not be {@code null} - * @return {@code true}, if is first non action element is the given element, {@code false} otherwise - */ - def boolean isFirstNonActionElement(Group group, AbstractElement element) { - return element == getFirstNonActionElement(group); - } - - - def String generateGatedPredicate(SemanticPredicate predicate) - '''{predicates.«predicate.name»(parserContext)}?=>''' - - def String generateValidatingPredicate(SemanticPredicate predicate) - '''{predicates.«predicate.name»(parserContext) /* @ErrorMessage(«predicate.message») */}?''' - - - /** - * Translate annotations in comments into predicate annotations. - * - *

- * Gated vs. Disambiguating predicates On the first look a disambiguating semantic predicate - * would be a right choice. However inserting them would be much more difficult. The reason is that we need - * not only insert them in the beginning of the current rule, but also propagate before actions into alternatives - * that call this rule. We have to do the same for gated predicated, however there is one important difference. - * If we have an alternative like {@code rule: (Keyword1 | Keyword2) Keyword3 ;} then we need to insert the predicate - * only before the first alternative (Keyword1). If we insert disambiguating semantic predicate before both - * the exception the predicate may throw can destroy recovery for the entire rule i.e. will not try going to Keyword3. - * We, however, need validating predicate in the beginning of each rule Keyword2, Keyword3. This requires an - * extra analysis which might be a next step. Gated predicates we can safely insert before Keyword1 and Keyword2. - * This will have no negative impact. We still need validating predicates in Keyword rules themselves. - *

- */ - def SemanticPredicate annotateRule(AbstractRule rule) { - val text = getText(rule) - var SemanticPredicate predicate = null - if (text !== null) { - val ruleGrammarName = GrammarUtil.getSimpleName(GrammarUtil.getGrammar(rule)) - predicate = getKeywordRulePredicate(text, rule.getName(), ruleGrammarName) - if(predicate !== null){ - predicate.attachToEmfObject(rule) - } - val semanticPredicate = getSemanticPredicate(text, ruleGrammarName) - if(semanticPredicate !== null){ - if(predicate !== null) - throw new IllegalArgumentException("You may not combine keyword annotations with semantic predicate annotations on one rule: " + rule.name) - semanticPredicate.attachToEmfObject(rule) - predicate = semanticPredicate - } - val noBacktrack = getNoBacktrack(text) - noBacktrack?.attachToEmfObject(rule) - } - return predicate - } - - def SemanticPredicate getSemanticPredicateAnnotation(AbstractRule rule) { - if (rule !== null) { - var original = RuleWithParameterValues.findInEmfObject(rule)?.getOriginal() - if (original === null) { - original = rule - } - return SemanticPredicate.findInEmfObject(original) - } - } - - def NoBacktrack getNoBacktrackAnnotation(AbstractRule rule) { - if (rule !== null) { - var original = RuleWithParameterValues.findInEmfObject(rule).getOriginal() - if (original === null) { - original = rule - } - return NoBacktrack.findInEmfObject(original) - } - } - - /** - * Checks if the given rule contains {@code @KeywordRule(kw1,kw2)} annotation. - */ - def SemanticPredicate getKeywordRulePredicate(String text, String ruleName, String grammar){ - val matcher = KEYWORD_RULE_ANNOTATION_PATTERN.matcher(text); - if (matcher.find()) { - return new SemanticPredicate( - "is" + ruleName + "Enabled", - "get" + ruleName + "EnabledMessage", - grammar, - Lists.newArrayList(KEYWORDS_SPLITTER.split(matcher.group(1))) - ) - } - } - - /** - * Checks if the given rule contains {@code @SemanticPredicate(condition)} annotation. - */ - def SemanticPredicate getSemanticPredicate(String text, String grammar){ - val matcher = SEMANTIC_PREDICATE_PATTERN.matcher(text); - if (matcher.find()) { - return new SemanticPredicate( - matcher.group(1), - "get" + matcher.group(1) + "Message", - grammar, - null - ) - } - } - - /** - * Checks if the given rule contains a NoBacktrack annotation. - */ - def NoBacktrack getNoBacktrack(String text){ - val matcher = NO_BACKTRACK_ANNOTATION_PATTERN.matcher(text); - if (matcher.find()) { - return new NoBacktrack - } - } - - def String getText(AbstractRule rule) { - val node = NodeModelUtils.getNode(rule); - return if(node !== null) node.getText() else grammarExtensions.grammarFragmentToString(rule,""); - } - - /** - * Checks if the given rule contains a keyword rule annotation. - * - * @param rule - * Grammar rule - * @return {@code true} if there is an annotation, {@code false} otherwise - */ - def boolean isSemanticPredicate(AbstractRule rule) { - var text = getText(rule); - if (text !== null) { - val matcher = SEMANTIC_PREDICATE_PATTERN.matcher(text); - if (matcher.find()) { - return true; - } - } - return false; - } -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/PredicatesNaming.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/PredicatesNaming.java similarity index 54% rename from com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/PredicatesNaming.xtend rename to com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/PredicatesNaming.java index b52d998ec6..ff51d0e392 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/PredicatesNaming.xtend +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/PredicatesNaming.java @@ -9,26 +9,27 @@ * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.generator.parser.common +package com.avaloq.tools.ddk.xtext.generator.parser.common; -import com.google.inject.Inject -import org.eclipse.xtext.Grammar -import org.eclipse.xtext.GrammarUtil -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming +import com.google.inject.Inject; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; -class PredicatesNaming { +public class PredicatesNaming { - @Inject extension XtextGeneratorNaming naming + @Inject + private XtextGeneratorNaming naming; - def String getSemanticPredicatesFullName(Grammar grammar) { + public String getSemanticPredicatesFullName(final Grammar grammar) { return getSemanticPredicatesPackageName(grammar) + "." + getSemanticPredicatesSimpleName(grammar); } - def String getSemanticPredicatesPackageName(Grammar grammar) { - return naming.getRuntimeBasePackage(grammar) + ".grammar" + public String getSemanticPredicatesPackageName(final Grammar grammar) { + return naming.getRuntimeBasePackage(grammar) + ".grammar"; } - def String getSemanticPredicatesSimpleName(Grammar grammar) { + public String getSemanticPredicatesSimpleName(final Grammar grammar) { return "Abstract" + GrammarUtil.getSimpleName(grammar) + "SemanticPredicates"; } diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.java new file mode 100644 index 0000000000..b9b8dc1f82 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) Avaloq Group AG + * Schwerzistrasse 6, 8807 Freienbach, Switzerland, http://www.avaloq.com + * All Rights Reserved. + * + * This software is the confidential and proprietary information of Avaloq Group AG. + * You shall not disclose whole or parts of it and shall use it only in accordance with the terms of the + * licence agreement you entered into with Avaloq Group AG. + */ + +package com.avaloq.tools.ddk.xtext.generator.resourceFactory; + +import java.util.Arrays; +import java.util.List; + +import com.google.inject.Inject; +import org.eclipse.xtext.resource.IResourceFactory; +import org.eclipse.xtext.resource.IResourceServiceProvider; +import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtend2.lib.StringConcatenationClient; + +/** + * Implementation that allows the fileExtensions for the fragment to be distinct from language.fileExtensions + */ +public class ResourceFactoryFragment2 extends AbstractXtextGeneratorFragment { + + private List fileExtensions; + + @Inject + private XtextGeneratorNaming _xtextGeneratorNaming; + + protected List getFileExtensions() { + return fileExtensions; + } + + /** + * Either a single file extension or a comma-separated list of extensions for which the language + * shall be registered. + */ + public void setFileExtensions(final String fileExtensions) { + this.fileExtensions = Arrays.asList(fileExtensions.trim().split("\\s*,\\s*")); + } + + // This is ResourceFactoryFragment2#generate with language.fileExtensions replaced by getFileExtensions + @Override + public void generate() { + + getLanguage().getRuntimeGenSetup().getRegistrations().add(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append(TypeReference.typeRef(IResourceFactory.class)); + target.append(" resourceFactory = injector.getInstance("); + target.append(TypeReference.typeRef(IResourceFactory.class)); + target.append(".class);"); + target.newLineIfNotEmpty(); + target.append(TypeReference.typeRef(IResourceServiceProvider.class)); + target.append(" serviceProvider = injector.getInstance("); + target.append(TypeReference.typeRef(IResourceServiceProvider.class)); + target.append(".class);"); + target.newLineIfNotEmpty(); + target.newLineIfNotEmpty(); + for (final String fileExtension : getFileExtensions()) { + target.append(TypeReference.typeRef(org.eclipse.emf.ecore.resource.Resource.class)); + target.append(".Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(\""); + target.append(fileExtension); + target.append("\", resourceFactory);"); + target.newLineIfNotEmpty(); + target.append(TypeReference.typeRef(IResourceServiceProvider.class)); + target.append(".Registry.INSTANCE.getExtensionToFactoryMap().put(\""); + target.append(fileExtension); + target.append("\", serviceProvider);"); + target.newLineIfNotEmpty(); + } + } + }); + + if (getProjectConfig().getEclipsePlugin() != null && getProjectConfig().getEclipsePlugin().getPluginXml() != null) { + final StringBuilder builder = new StringBuilder(); + builder.append("\n"); + for (final String fileExtension : getFileExtensions()) { + builder.append("\n"); + builder.append(" \n"); + builder.append(" \n"); + builder.append("\n"); + builder.append("\n"); + builder.append(" \n"); + builder.append(" \n"); + builder.append("\n"); + } + getProjectConfig().getEclipsePlugin().getPluginXml().getEntries().add(builder.toString()); + } + } + +} + +/* Copyright (c) Avaloq Group AG */ diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.xtend deleted file mode 100644 index 8b7306a7b0..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.xtend +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) Avaloq Group AG - * Schwerzistrasse 6, 8807 Freienbach, Switzerland, http://www.avaloq.com - * All Rights Reserved. - * - * This software is the confidential and proprietary information of Avaloq Group AG. - * You shall not disclose whole or parts of it and shall use it only in accordance with the terms of the - * licence agreement you entered into with Avaloq Group AG. - */ - -package com.avaloq.tools.ddk.xtext.generator.resourceFactory - -import com.google.inject.Inject -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming -import org.eclipse.xtext.resource.IResourceFactory -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.resource.IResourceServiceProvider -import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment -import org.eclipse.xtend.lib.annotations.Accessors -import java.util.List - -/** - * Implementation that allows the fileExtensions for the fragment to be distinct from language.fileExtensions - */ -class ResourceFactoryFragment2 extends AbstractXtextGeneratorFragment { - - @Accessors(PROTECTED_GETTER) List fileExtensions - - @Inject - extension XtextGeneratorNaming - - /** - * Either a single file extension or a comma-separated list of extensions for which the language - * shall be registered. - */ - def void setFileExtensions(String fileExtensions) { - this.fileExtensions = fileExtensions.trim.split('\\s*,\\s*').toList - } - - // This is ResourceFactoryFragment2#generate with language.fileExtensions replaced by getFileExtensions - override generate() { - - language.runtimeGenSetup.registrations.add(''' - «IResourceFactory» resourceFactory = injector.getInstance(«IResourceFactory».class); - «IResourceServiceProvider» serviceProvider = injector.getInstance(«IResourceServiceProvider».class); - - «FOR fileExtension : getFileExtensions» - «Resource».Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("«fileExtension»", resourceFactory); - «IResourceServiceProvider».Registry.INSTANCE.getExtensionToFactoryMap().put("«fileExtension»", serviceProvider); - «ENDFOR» - ''') - - if (projectConfig.eclipsePlugin?.pluginXml !== null) { - projectConfig.eclipsePlugin.pluginXml.entries += ''' - - «FOR fileExtension : getFileExtensions» - - - - - - - - - «ENDFOR» - ''' - } - } - -} - -/* Copyright (c) Avaloq Group AG */ \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java new file mode 100644 index 0000000000..74971c5d72 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.ui.compare; + +import com.google.inject.Inject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.compare.IViewerCreator; +import org.eclipse.emf.mwe2.runtime.Mandatory; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming; +import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtext.xtext.generator.resourceFactory.ResourceFactoryFragment2; + +public class CompareFragment2 extends ResourceFactoryFragment2 { + + @Inject + private XtextGeneratorNaming _xtextGeneratorNaming; + + private static final Logger LOGGER = LogManager.getLogger(CompareFragment2.class); + + private String viewCreator; + private String bundleName; + + /** + * Sets the view creator. + * + * @param viewCreator + * the new view creator + */ + @Mandatory + public void setViewCreator(final String viewCreator) { + this.viewCreator = viewCreator; + } + + /** + * Sets bundle where the view creator is located. + * + * @param bundleName + * the new bundle name + */ + @Mandatory + public void setBundleName(final String bundleName) { + this.bundleName = bundleName; + } + + @Override + public void generate() { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("generating Compare Framework infrastructure"); + } + + new GuiceModuleAccess.BindingFactory() + .addTypeToType(TypeReference.typeRef(IViewerCreator.class), new TypeReference(viewCreator)) + .contributeTo(getLanguage().getEclipsePluginGenModule()); + if (getProjectConfig().getEclipsePlugin().getManifest() != null) { + getProjectConfig().getEclipsePlugin().getManifest().getRequiredBundles().add(bundleName); + } + if (getProjectConfig().getEclipsePlugin().getPluginXml().getEntries() != null) { + getProjectConfig().getEclipsePlugin().getPluginXml().getEntries().add(eclipsePluginXmlContribution()); + } + } + + public CharSequence eclipsePluginXmlContribution() { + final TypeReference executableExtensionFactory = _xtextGeneratorNaming.getEclipsePluginExecutableExtensionFactory(getGrammar()); + final String fileExtensions = String.join(",", getLanguage().getFileExtensions()); + final StringBuilder builder = new StringBuilder(); + builder.append("\n"); + builder.append("\n"); + builder.append(" \n"); + builder.append(" \n"); + builder.append("\n"); + builder.append("\n"); + builder.append(" \n"); + builder.append(" \n"); + builder.append("\n"); + builder.append("\n"); + builder.append(" \n"); + builder.append(" \n"); + builder.append("\n"); + return builder; + } +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.xtend deleted file mode 100644 index 69797104a4..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.xtend +++ /dev/null @@ -1,99 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.ui.compare - -import com.google.inject.Inject -import org.apache.logging.log4j.Logger -import org.apache.logging.log4j.LogManager; -import org.eclipse.compare.IViewerCreator -import org.eclipse.emf.mwe2.runtime.Mandatory -import org.eclipse.xtext.xtext.generator.XtextGeneratorNaming -import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess -import org.eclipse.xtext.xtext.generator.model.TypeReference -import org.eclipse.xtext.xtext.generator.resourceFactory.ResourceFactoryFragment2 - -import static extension org.eclipse.xtext.GrammarUtil.* -import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.* - -class CompareFragment2 extends ResourceFactoryFragment2 { - - @Inject - extension XtextGeneratorNaming - - val static Logger LOGGER = LogManager.getLogger(CompareFragment2); - - var String viewCreator; - var String bundleName; - - /** - * Sets the view creator. - * - * @param viewCreator - * the new view creator - */ - @Mandatory - def void setViewCreator(String viewCreator) { - this.viewCreator = viewCreator; - } - - /** - * Sets bundle where the view creator is located. - * - * @param bundleName - * the new bundle name - */ - @Mandatory - def void setBundleName(String bundleName) { - this.bundleName = bundleName; - } - - override void generate() { - if (LOGGER.isInfoEnabled()) { - LOGGER.info("generating Compare Framework infrastructure"); - } - - new GuiceModuleAccess.BindingFactory() - .addTypeToType(IViewerCreator.typeRef, new TypeReference(viewCreator)) - .contributeTo(language.eclipsePluginGenModule) - if (projectConfig.eclipsePlugin.manifest !== null) { - projectConfig.eclipsePlugin.manifest.requiredBundles += bundleName - } - if (projectConfig.eclipsePlugin.pluginXml.entries !== null) { - projectConfig.eclipsePlugin.pluginXml.entries += eclipsePluginXmlContribution() - } - } - - def eclipsePluginXmlContribution() { - val executableExtensionFactory = grammar.eclipsePluginExecutableExtensionFactory - ''' - - - - - - - - - - - - - - ''' - } -} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.java new file mode 100644 index 0000000000..0e2e33cce4 --- /dev/null +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.java @@ -0,0 +1,381 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.generator.ui.contentAssist; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtend2.lib.StringConcatenationClient; +import org.eclipse.xtext.AbstractElement; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.Alternatives; +import org.eclipse.xtext.Assignment; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.Grammar; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.RuleCall; +import org.eclipse.xtext.xtext.generator.model.FileAccessFactory; +import org.eclipse.xtext.xtext.generator.model.GeneratedJavaFileAccess; +import org.eclipse.xtext.xtext.generator.model.TypeReference; +import org.eclipse.xtext.xtext.generator.ui.contentAssist.ContentAssistFragment2; + +import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations; +import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations.SemanticPredicate; +import com.google.inject.Inject; + + +public class AnnotationAwareContentAssistFragment2 extends ContentAssistFragment2 { + + /** + * Whether the Proposal Provider extensions should be generated - default is true. + */ + private boolean generateProposalProvider = true; + + @Inject + private FileAccessFactory fileAccessFactory; + + @Inject + private GrammarRuleAnnotations annotations; + + public boolean isGenerateProposalProvider() { + return generateProposalProvider; + } + + public void setGenerateProposalProvider(boolean generateProposalProvider) { + this.generateProposalProvider = generateProposalProvider; + } + + @Override + public void generate() { + if (generateProposalProvider) { + super.generate(); + } + } + + // generation of the 'Abstract...ProposalProvider' + + @Override + protected void generateGenJavaProposalProvider() { + Grammar grammar = getGrammar(); + // excluded features are those that stem from inherited grammars, + // they are handled by the super grammars' proposal provider + final Set excludedFqnFeatureNames = getFQFeatureNamesToExclude(grammar); + final Set processedNames = new HashSet<>(); + annotations.annotateGrammar(grammar); + // determine all assignments within the grammar that are not excluded and not handled yet + final List assignments = new ArrayList<>(); + for (Assignment assignment : GrammarUtil.containedAssignments(grammar)) { + String fqFeatureName = getFQFeatureName(assignment); + if (!processedNames.contains(fqFeatureName) && !excludedFqnFeatureNames.contains(fqFeatureName)) { + processedNames.add(fqFeatureName); + assignments.add(assignment); + } + } + + // determine keyword rules + final List keywordRules = new ArrayList<>(); + for (AbstractRule rule : grammar.getRules()) { + String fqFeatureName = getFQFeatureName(rule); + SemanticPredicate predAnnotation = annotations.getSemanticPredicateAnnotation(rule); + if (!processedNames.contains(fqFeatureName) && !excludedFqnFeatureNames.contains(fqFeatureName) + && predAnnotation != null && predAnnotation.getKeywords() != null + ) { + processedNames.add(fqFeatureName); + keywordRules.add(rule); + } + } + + // determine the (remaining) rules that are not excluded and not handled yet + final List remainingRules = new ArrayList<>(); + for (AbstractRule rule : grammar.getRules()) { + String fqnFeatureName = getFQFeatureName(rule); + if (!processedNames.contains(fqnFeatureName) && !excludedFqnFeatureNames.contains(fqnFeatureName)) { + processedNames.add(fqnFeatureName); + remainingRules.add(rule); + } + } + + // take the non-abstract class signature for the src-gen class in case of !generateStub + // as proposalProviders of sub languages refer to 'grammar.proposalProviderClass', + // see 'getGenProposalProviderSuperClass(...)' + final TypeReference genClass = + isGenerateStub() ? getGenProposalProviderClass(grammar) : getProposalProviderClass(grammar); + + GeneratedJavaFileAccess javaFile = fileAccessFactory.createGeneratedJavaFile(genClass); + final TypeReference superClass = getGenProposalProviderSuperClass(grammar); + + javaFile.setTypeComment(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("/**"); target.newLine(); + target.append(" * Represents a generated, default implementation of superclass {@link "); + target.append(superClass); + target.append("}."); target.newLine(); + target.append(" * Methods are dynamically dispatched on the first parameter, i.e., you can override them"); target.newLine(); + target.append(" * with a more concrete subtype."); target.newLine(); + target.append(" */"); target.newLine(); + } + }); + + javaFile.setContent(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("public "); + if (isGenerateStub()) { + target.append("abstract "); + } + target.append("class "); + target.append(genClass.getSimpleName()); + target.append(" extends "); + target.append(superClass); + target.append(" {"); target.newLineIfNotEmpty(); target.newLine(); + + if (!assignments.isEmpty()) { + for (Assignment assignment : assignments) { + target.append(handleAssignment(assignment)); + } + target.newLine(); + } + if (!keywordRules.isEmpty()) { + for (AbstractRule rule : keywordRules) { + target.append(" public void complete"); + target.append(getFQFeatureName(rule)); + target.append("("); + target.append(EObject.class); + target.append(" model, "); + target.append(RuleCall.class); + target.append(" ruleCall, "); + target.append(getContentAssistContextClass()); + target.append(" context, "); + target.append(getICompletionProposalAcceptorClass()); + target.append(" acceptor) {"); target.newLineIfNotEmpty(); + target.append(handleKeywordRule(rule)); + target.append(" }"); target.newLineIfNotEmpty(); + } + target.newLine(); + } + for (AbstractRule rule : remainingRules) { + target.append(" public void complete"); + target.append(getFQFeatureName(rule)); + target.append("("); + target.append(EObject.class); + target.append(" model, "); + target.append(RuleCall.class); + target.append(" ruleCall, "); + target.append(getContentAssistContextClass()); + target.append(" context, "); + target.append(getICompletionProposalAcceptorClass()); + target.append(" acceptor) {"); target.newLineIfNotEmpty(); + target.append(" // subclasses may override"); target.newLineIfNotEmpty(); + target.append(" }"); target.newLineIfNotEmpty(); + } + target.append("}"); target.newLineIfNotEmpty(); + } + }); + javaFile.writeTo(getProjectConfig().getEclipsePlugin().getSrcGen()); + } + + private StringConcatenationClient handleKeywordRule(AbstractRule rule) { + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + SemanticPredicate predAnnotation = annotations.getSemanticPredicateAnnotation(rule); + if (predAnnotation != null && predAnnotation.getKeywords() != null) { + for (String keyword : predAnnotation.getKeywords()) { + target.append(" acceptor.accept(createCompletionProposal(\""); + target.append(keyword); + target.append("\", context));"); target.newLineIfNotEmpty(); + } + } + } + }; + } + + private StringConcatenationClient handleAssignment(Assignment assignment) { + // determine all assignments within 'assignment's containing parser rule + // assigning the same feature, obtain their expected terminals, ... + final List terminals = new ArrayList<>(); + for (Assignment a : GrammarUtil.containedAssignments(GrammarUtil.containingParserRule(assignment))) { + if (a.getFeature().equals(assignment.getFeature())) { + terminals.add(a.getTerminal()); + } + } + + // ... and determine the types of those terminals + final Set terminalTypes = new HashSet<>(); + for (AbstractElement terminal : terminals) { + terminalTypes.add(terminal.eClass()); + } + + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append(" public void complete"); + target.append(getFQFeatureName(assignment)); + target.append("("); + target.append(EObject.class); + target.append(" model, "); + target.append(Assignment.class); + target.append(" assignment, "); + target.append(getContentAssistContextClass()); + target.append(" context, "); + target.append(getICompletionProposalAcceptorClass()); + target.append(" acceptor) {"); target.newLineIfNotEmpty(); + if (terminalTypes.size() > 1) { + target.append(handleAssignmentOptions(terminals)); + } else { + target.append(" "); + target.append(assignmentTerminal(assignment.getTerminal(), new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("assignment.getTerminal()"); + } + })); + } + target.append(" }"); target.newLineIfNotEmpty(); + } + }; + } + + private StringConcatenationClient handleAssignmentOptions(Iterable terminals) { + final Set processedTerminals = new HashSet<>(); + + // for each type of terminal occurring in 'terminals' ... + final List candidates = new ArrayList<>(); + for (AbstractElement terminal : terminals) { + if (!processedTerminals.contains(terminal.eClass())) { + processedTerminals.add(terminal.eClass()); + candidates.add(terminal); + } + } + + // ... generate an 'instanceof' clause + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + for (AbstractElement terminal : candidates) { + target.append(" if (assignment.getTerminal() instanceof "); + target.append(terminal.eClass().getInstanceClass()); + target.append(") {"); target.newLineIfNotEmpty(); + target.append(" "); + target.append(assignmentTerminal(terminal, new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("assignment.getTerminal()"); + } + })); + target.append(" }"); target.newLineIfNotEmpty(); + } + } + }; + } + + // dispatch methods for assignmentTerminal + + private StringConcatenationClient assignmentTerminal(AbstractElement element, StringConcatenationClient accessor) { + if (element instanceof Alternatives) { + return _assignmentTerminal((Alternatives) element, accessor); + } else if (element instanceof CrossReference) { + return _assignmentTerminal((CrossReference) element, accessor); + } else if (element instanceof RuleCall) { + return _assignmentTerminal((RuleCall) element, accessor); + } else { + return _assignmentTerminal(element, accessor); + } + } + + private StringConcatenationClient _assignmentTerminal(AbstractElement element, StringConcatenationClient accessor) { + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("// subclasses may override"); target.newLineIfNotEmpty(); + } + }; + } + + private StringConcatenationClient _assignmentTerminal(CrossReference element, StringConcatenationClient accessor) { + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("lookupCrossReference((("); + target.append(CrossReference.class); + target.append(")"); + target.append(accessor); + target.append("), context, acceptor);"); target.newLineIfNotEmpty(); + } + }; + } + + private StringConcatenationClient _assignmentTerminal(RuleCall element, StringConcatenationClient accessor) { + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("completeRuleCall((("); + target.append(RuleCall.class); + target.append(")"); + target.append(accessor); + target.append("), context, acceptor);"); target.newLineIfNotEmpty(); + } + }; + } + + private StringConcatenationClient _assignmentTerminal(Alternatives alternatives, StringConcatenationClient accessor) { + return new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + List elements = alternatives.getElements(); + for (int i = 0; i < elements.size(); i++) { + final int index = i; + target.append(assignmentTerminal(elements.get(i), new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append("(("); + target.append(Alternatives.class); + target.append(")"); + target.append(accessor); + target.append(").getElements().get("); + target.append(Integer.toString(index)); + target.append(")"); + } + })); + } + } + }; + } + + // helper methods + + private TypeReference getContentAssistContextClass() { + return new TypeReference("org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext"); + } + + private TypeReference getICompletionProposalAcceptorClass() { + return new TypeReference("org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor"); + } + + private String getFQFeatureName(AbstractRule r) { + return "_" + r.getName(); + } + + private String getFQFeatureName(Assignment a) { + String ruleName = GrammarUtil.containingParserRule(a).getName(); + String firstUpper = ruleName.substring(0, 1).toUpperCase() + ruleName.substring(1); + String featureName = a.getFeature(); + String featureFirstUpper = featureName.substring(0, 1).toUpperCase() + featureName.substring(1); + return firstUpper + "_" + featureFirstUpper; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.xtend b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.xtend deleted file mode 100644 index 815c3ea14e..0000000000 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.xtend +++ /dev/null @@ -1,226 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.generator.ui.contentAssist - -import com.google.inject.Inject -import org.eclipse.emf.ecore.EObject -import org.eclipse.xtend2.lib.StringConcatenationClient -import org.eclipse.xtext.AbstractElement -import org.eclipse.xtext.AbstractRule -import org.eclipse.xtext.Alternatives -import org.eclipse.xtext.Assignment -import org.eclipse.xtext.CrossReference -import org.eclipse.xtext.RuleCall -import org.eclipse.xtext.xtext.generator.model.FileAccessFactory -import org.eclipse.xtext.xtext.generator.model.TypeReference -import org.eclipse.xtext.xtext.generator.ui.contentAssist.ContentAssistFragment2 - -import static extension org.eclipse.xtext.GrammarUtil.* -import com.avaloq.tools.ddk.xtext.generator.parser.common.GrammarRuleAnnotations -import org.eclipse.xtend.lib.annotations.Accessors - -class AnnotationAwareContentAssistFragment2 extends ContentAssistFragment2 { - - /** - * Whether the Proposal Provider extensions should be generated - default is true. - */ - @Accessors boolean generateProposalProvider = true; - - @Inject - FileAccessFactory fileAccessFactory - - @Inject - extension GrammarRuleAnnotations annotations - - override generate() { - if (generateProposalProvider) - super.generate - } - - // generation of the 'Abstract...ProposalProvider' - - protected override generateGenJavaProposalProvider() { - // excluded features are those that stem from inherited grammars, - // they are handled by the super grammars' proposal provider - val excludedFqnFeatureNames = grammar.getFQFeatureNamesToExclude - val processedNames = newHashSet() - grammar.annotateGrammar - // determine all assignments within the grammar that are not excluded and not handled yet - val assignments = grammar.containedAssignments().fold(newArrayList()) [ candidates, assignment | - val fqFeatureName = assignment.FQFeatureName - if (!processedNames.contains(fqFeatureName) && !excludedFqnFeatureNames.contains(fqFeatureName)) { - processedNames += fqFeatureName; - candidates += assignment; - } - candidates - ] - - // determine keyword rules - val keywordRules = grammar.rules.fold(newArrayList()) [ candidates, rule | - val fqFeatureName = rule.FQFeatureName - if (!processedNames.contains(fqFeatureName) && !excludedFqnFeatureNames.contains(fqFeatureName) - && rule.semanticPredicateAnnotation?.keywords !== null - ) { - processedNames += fqFeatureName; - candidates += rule; - } - candidates - ] - - // determine the (remaining) rules that are not excluded and not handled yet - val remainingRules = grammar.rules.fold(newArrayList()) [candidates, rule | - val fqnFeatureName = rule.FQFeatureName - if (!processedNames.contains(fqnFeatureName) && !excludedFqnFeatureNames.contains(fqnFeatureName)) { - processedNames += fqnFeatureName - candidates += rule - } - candidates - ] - - // take the non-abstract class signature for the src-gen class in case of !generateStub - // as proposalProviders of sub languages refer to 'grammar.proposalProviderClass', - // see 'getGenProposalProviderSuperClass(...)' - val genClass = - if (isGenerateStub) grammar.genProposalProviderClass else grammar.proposalProviderClass; - - fileAccessFactory.createGeneratedJavaFile(genClass) => [ - val superClass = grammar.genProposalProviderSuperClass - - typeComment = ''' - /** - * Represents a generated, default implementation of superclass {@link «superClass»}. - * Methods are dynamically dispatched on the first parameter, i.e., you can override them - * with a more concrete subtype. - */ - ''' - - content = ''' - public «IF isGenerateStub»abstract «ENDIF»class «genClass.simpleName» extends «superClass» { - - «IF !assignments.empty» - «FOR assignment : assignments» - «assignment.handleAssignment» - «ENDFOR» - - «ENDIF» - «IF !keywordRules.empty» - «FOR rule : keywordRules» - public void complete«rule.FQFeatureName»(«EObject» model, «RuleCall» ruleCall, « - contentAssistContextClass» context, «ICompletionProposalAcceptorClass» acceptor) { - «rule.handleKeywordRule» - } - «ENDFOR» - - «ENDIF» - «FOR rule : remainingRules» - public void complete«rule.FQFeatureName»(«EObject» model, «RuleCall» ruleCall, « - contentAssistContextClass» context, «ICompletionProposalAcceptorClass» acceptor) { - // subclasses may override - } - «ENDFOR» - } - ''' - writeTo(projectConfig.eclipsePlugin.srcGen) - ] - } - - private def StringConcatenationClient handleKeywordRule(AbstractRule rule) { - ''' - «FOR keyword : rule.semanticPredicateAnnotation.keywords» - acceptor.accept(createCompletionProposal("«keyword»", context)); - «ENDFOR» - ''' - } - - private def StringConcatenationClient handleAssignment(Assignment assignment) { - // determine all assignment within 'assignment's containing parser rule - // assigning the same feature, obtain their expected terminals, ... - val terminals = assignment.containingParserRule.containedAssignments().filter[ - it.feature == assignment.feature - ].map[ - terminal - ].toList - - // ... and determine the types of those terminals - val terminalTypes = terminals.map[ eClass ].toSet; - - ''' - public void complete«assignment.FQFeatureName»(«EObject» model, «Assignment» assignment, « - contentAssistContextClass» context, «ICompletionProposalAcceptorClass» acceptor) { - «IF terminalTypes.size > 1» - «terminals.handleAssignmentOptions» - «ELSE» - «assignment.terminal.assignmentTerminal('''assignment.getTerminal()''')» - «ENDIF» - } - ''' - } - - private def StringConcatenationClient handleAssignmentOptions(Iterable terminals) { - val processedTerminals = newHashSet(); - - // for each type of terminal occurring in 'terminals' ... - val candidates = terminals.fold(newArrayList()) [ candidates, terminal | - if (!processedTerminals.contains(terminal.eClass)) { - processedTerminals += terminal.eClass - candidates += terminal - } - candidates - ] - - // ... generate an 'instanceof' clause - ''' - «FOR terminal : candidates» - if (assignment.getTerminal() instanceof «terminal.eClass.instanceClass») { - «terminal.assignmentTerminal('''assignment.getTerminal()''')» - } - «ENDFOR» - ''' - } - - private def dispatch StringConcatenationClient assignmentTerminal(AbstractElement element, StringConcatenationClient accessor) ''' - // subclasses may override - ''' - - private def dispatch StringConcatenationClient assignmentTerminal(CrossReference element, StringConcatenationClient accessor) ''' - lookupCrossReference(((«CrossReference»)«accessor»), context, acceptor); - ''' - - private def dispatch StringConcatenationClient assignmentTerminal(RuleCall element, StringConcatenationClient accessor) ''' - completeRuleCall(((«RuleCall»)«accessor»), context, acceptor); - ''' - - private def dispatch StringConcatenationClient assignmentTerminal(Alternatives alternatives, StringConcatenationClient accessor) ''' - «FOR pair : alternatives.elements.indexed» - «pair.value.assignmentTerminal('''((«Alternatives»)«accessor»).getElements().get(«pair.key»)''')» - «ENDFOR» - ''' - - // helper methods - - private def getContentAssistContextClass() { - new TypeReference("org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext") - } - - private def getICompletionProposalAcceptorClass() { - new TypeReference("org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor") - } - - def private getFQFeatureName(AbstractRule r) { - "_" + r.name; - } - - def private getFQFeatureName(Assignment a) { - a.containingParserRule().name.toFirstUpper() + "_" + a.feature.toFirstUpper(); - } - -} diff --git a/docs/xtend-migration.md b/docs/xtend-migration.md index a9436887d6..ddd229aec5 100644 --- a/docs/xtend-migration.md +++ b/docs/xtend-migration.md @@ -12,10 +12,10 @@ | Metric | Value | |--------|-------| | Total Xtend source files | 94 | -| Already migrated (Batch 1–7) | 74 | -| Remaining | 20 | -| Total remaining lines | ~5,513 | -| Modules with remaining Xtend | 5 | +| Already migrated (Batch 1–8) | 89 | +| Remaining | 5 | +| Total remaining lines | ~1,295 | +| Modules with remaining Xtend | 2 | --- @@ -24,7 +24,7 @@ | Module | Files | Lines | Status | |--------|-------|-------|--------| | `check.core` | 8 | ~1,848 | **DONE** (Batch 1) | -| `check.core.test` | 8 | 1,508 | 7 done (Batch 2–4), 1 pending | +| `check.core.test` | 11 | ~1,760 | 7 done (Batch 2–4), 4 pending | | `check.test.runtime` | 1 | 22 | **DONE** (Batch 2) | | `check.test.runtime.tests` | 3 | 202 | **DONE** (Batch 3–4) | | `check.ui` | 2 | 113 | **DONE** (Batch 3) | @@ -41,8 +41,8 @@ | `xtext.format.ide` | 2 | 31 | **DONE** (Batch 2) | | `xtext.format.test` | 1 | 40 | **DONE** (Batch 3) | | `xtext.format.ui` | 1 | 47 | **DONE** (Batch 2) | -| `xtext.generator` | 18 | 3,450 | 2 done (Batch 2), 16 pending | -| `xtext.generator.test` | 1 | 200 | Pending | +| `xtext.generator` | 18 | 3,450 | **DONE** (Batch 2, 8) | +| `xtext.generator.test` | 1 | 200 | **DONE** (Batch 8) | | `xtext.scope` | 4 | 852 | **DONE** (Batch 6) | | `xtext.scope.generator` | 1 | 47 | **DONE** (Batch 4) | | `xtext.test.core` | 2 | 221 | **DONE** (Batch 4, 6) | @@ -229,46 +229,45 @@ Includes the largest file in the project. Heavy use of dispatch, templates, crea --- -## Batch 8 — `xtext.generator` module (18 files, 3,450 lines) +## Batch 8 — `xtext.generator` module (17 files, 3,555 lines) — DONE The largest module. Includes ANTLR grammar generators — the hardest files in the project. ### Simple (4 files) -- [ ] `PredicatesNaming.xtend` (35 lines) — Trivial — extension, @Inject -- [ ] `ModelInferenceFragment2.xtend` (49 lines) — Trivial — extension, !==, override -- [ ] `DefaultFragmentWithOverride.xtend` (54 lines) — Easy — ?., override, @Accessors -- [ ] `BuilderIntegrationFragment2.xtend` (60 lines) — Easy — templates, extension, !==, override +- [x] `PredicatesNaming.xtend` (35 lines) — Trivial — extension, @Inject +- [x] `ModelInferenceFragment2.xtend` (49 lines) — Trivial — extension, !==, override +- [x] `DefaultFragmentWithOverride.xtend` (54 lines) — Easy — ?., override, @Accessors +- [x] `BuilderIntegrationFragment2.xtend` (60 lines) — Easy — templates, extension, !==, override ### Medium (5 files) -- [ ] `ResourceFactoryFragment2.xtend` (76 lines) — Medium — templates, extension, !==, ?., @Accessors -- [ ] `CompareFragment2.xtend` (99 lines) — Medium — templates, extension, !==, @Inject -- [ ] `LanguageConstantsFragment2.xtend` (144 lines) — Medium — templates, extension, !==, ?., @Accessors -- [ ] `FormatterFragment2.xtend` (147 lines) — Medium — templates, extension, typeof, !==, ?., @Inject -- [ ] `XbaseGeneratorFragmentTest.xtend` (200 lines) — Medium — extension +- [x] `ResourceFactoryFragment2.xtend` (76 lines) — Medium — templates, extension, !==, ?., @Accessors +- [x] `CompareFragment2.xtend` (99 lines) — Medium — templates, extension, !==, @Inject +- [x] `LanguageConstantsFragment2.xtend` (144 lines) — Medium — templates, extension, !==, ?., @Accessors +- [x] `FormatterFragment2.xtend` (147 lines) — Medium — templates, extension, typeof, !==, ?., @Inject +- [x] `XbaseGeneratorFragmentTest.xtend` (200 lines) — Medium — extension ### Hard - Builder fragments (2 files) -- [ ] `StandaloneBuilderIntegrationFragment2.xtend` (165 lines) — Hard — templates, extension, @Inject -- [ ] `LspBuilderIntegrationFragment2.xtend` (174 lines) — Hard — templates, extension, @Inject +- [x] `StandaloneBuilderIntegrationFragment2.xtend` (165 lines) — Hard — templates, extension, @Inject +- [x] `LspBuilderIntegrationFragment2.xtend` (174 lines) — Hard — templates, extension, @Inject ### Hard - Content assist (1 file) -- [ ] `AnnotationAwareContentAssistFragment2.xtend` (226 lines) — Hard — **dispatch**, templates, extension, !==, ?., @Accessors +- [x] `AnnotationAwareContentAssistFragment2.xtend` (226 lines) — Hard — **dispatch**, templates, extension, !==, ?., @Accessors ### Very Hard - ANTLR generators (4 files) -- [ ] `AbstractAnnotationAwareAntlrGrammarGenerator.xtend` (159 lines) — Hard — templates, extension, @Inject -- [ ] `GrammarRuleAnnotations.xtend` (406 lines) — Very Hard — templates, ===, !==, ?., @Data -- [ ] `AnnotationAwareAntlrContentAssistGrammarGenerator.xtend` (489 lines) — Very Hard — **dispatch**, templates, extension, === -- [ ] `AnnotationAwareAntlrGrammarGenerator.xtend` (543 lines) — Very Hard — **dispatch**, templates, extension, !==, @Accessors, switch, create -- [ ] `AnnotationAwareXtextAntlrGeneratorFragment2.xtend` (529 lines) — Very Hard — templates, extension, ===, !==, #[, @Accessors, create +- [x] `AbstractAnnotationAwareAntlrGrammarGenerator.xtend` (159 lines) — Hard — templates, extension, @Inject +- [x] `GrammarRuleAnnotations.xtend` (406 lines) — Very Hard — templates, ===, !==, ?., @Data +- [x] `AnnotationAwareAntlrContentAssistGrammarGenerator.xtend` (489 lines) — Very Hard — **dispatch**, templates, extension, === +- [x] `AnnotationAwareAntlrGrammarGenerator.xtend` (543 lines) — Very Hard — **dispatch**, templates, extension, !==, @Accessors, switch, create +- [x] `AnnotationAwareXtextAntlrGeneratorFragment2.xtend` (529 lines) — Very Hard — templates, extension, ===, !==, #[, @Accessors, create --- -## Batch 9 — Remaining test files (~4 files) +## Batch 9 — Remaining test files (5 files) -### `check.core.test` (2 files) +### `check.core.test` (4 files) +- [ ] `CheckModelUtil.xtend` — Utility class - [ ] `IssueCodeToLabelMapGenerationTest.xtend` (130 lines) — Medium — templates, #[, switch - [ ] `CheckValidationTest.xtend` (342 lines) — Hard — extension, typeof, create - -### `check.core.test` (1 file) - [ ] `CheckFormattingTest.xtend` (554 lines) — Very Hard — templates, extension, typeof, !==, ?. ### `check.ui.test` (1 file) From b6f36bb917bcb8dd684f83b5f4009bbd9a27e7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 08:56:58 +0100 Subject: [PATCH 10/23] =?UTF-8?q?feat:=20migrate=20Batch=209=20Xtend=20fil?= =?UTF-8?q?es=20to=20Java=2021=20(5=20files)=20=E2=80=94=20migration=20com?= =?UTF-8?q?plete!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All 94 Xtend source files have been migrated to Java 21. Zero .xtend files remain in src/ directories. Co-Authored-By: Claude Opus 4.6 --- .../IssueCodeToLabelMapGenerationTest.java | 151 +++ .../IssueCodeToLabelMapGenerationTest.xtend | 130 -- .../check/core/test/util/CheckModelUtil.java | 173 +++ .../check/core/test/util/CheckModelUtil.xtend | 113 -- .../check/formatting/CheckFormattingTest.java | 1095 +++++++++++++++++ .../formatting/CheckFormattingTest.xtend | 554 --------- .../check/validation/CheckValidationTest.java | 333 +++++ .../validation/CheckValidationTest.xtend | 342 ----- .../ui/test/quickfix/CheckQuickfixTest.java | 240 ++++ .../ui/test/quickfix/CheckQuickfixTest.xtend | 200 --- docs/xtend-migration.md | 24 +- 11 files changed, 2004 insertions(+), 1351 deletions(-) create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.xtend create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.xtend create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.xtend create mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.java delete mode 100644 com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.xtend create mode 100644 com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java delete mode 100644 com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.xtend diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java new file mode 100644 index 0000000000..6b8ef8b9d7 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.check.core.test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.util.List; + +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.xbase.testing.JavaSource; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import com.avaloq.tools.ddk.check.CheckInjectorProvider; + + +/** + * Unit test for auto generation of check issue code to label map. + */ +@InjectWith(CheckInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +@SuppressWarnings("nls") +public class IssueCodeToLabelMapGenerationTest extends AbstractCheckGenerationTestCase { + + private static final String PACKAGE_NAME = "mypackage"; + + private static final String CATALOG_NAME = "MyCatalog"; + + /** + * Test the map generated from a catalog with no checks. + */ + @Test + public void testMapGenerationWithNoChecks() { + // ARRANGE + StringBuilder builder = new StringBuilder(); + builder.append("package "); + builder.append(PACKAGE_NAME); + builder.append("\n"); + builder.append("\n"); + builder.append("catalog "); + builder.append(CATALOG_NAME); + builder.append("\n"); + builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); + builder.append("\n"); + builder.append("}\n"); + final String source = builder.toString(); + + // check for the construction of an empty map + final List expectedCatalog = List.of("ImmutableMap.builderWithExpectedSize(0).build()"); + + // ACT AND ASSERT + testMapGeneration(source, expectedCatalog); + } + + /** + * Test the map generated from a catalog with checks. + */ + @Test + public void testMapGeneration() { + // ARRANGE + // @Format-Off + StringBuilder builder = new StringBuilder(); + builder.append("package "); + builder.append(PACKAGE_NAME); + builder.append("\n"); + builder.append("\n"); + builder.append("import com.avaloq.tools.ddk.check.check.Check\n"); + builder.append("import com.avaloq.tools.ddk.check.check.Context\n"); + builder.append("import com.avaloq.tools.ddk.check.check.Documented\n"); + builder.append("\n"); + builder.append("catalog "); + builder.append(CATALOG_NAME); + builder.append("\n"); + builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); + builder.append("\n"); + builder.append(" live error ID1 \"Label 1\"\n"); + builder.append(" message \"Message 1\" {\n"); + builder.append(" for Documented elem {\n"); + builder.append(" switch elem {\n"); + builder.append(" Context : issue on elem\n"); + builder.append(" Check : issue on elem\n"); + builder.append(" }\n"); + builder.append(" }\n"); + builder.append(" }\n"); + builder.append("\n"); + builder.append(" live error ID2 \"Label 2\"\n"); + builder.append(" message \"Message 2\" {\n"); + builder.append(" for Documented elem {\n"); + builder.append(" switch elem {\n"); + builder.append(" Context : issue on elem\n"); + builder.append(" Check : issue on elem\n"); + builder.append(" }\n"); + builder.append(" }\n"); + builder.append(" }\n"); + builder.append("}\n"); + final String source = builder.toString(); + // @Format-On + + final List expectedCatalog = List.of("put(MyCatalogIssueCodes.ID_1,\"Label1\")", "put(MyCatalogIssueCodes.ID_2,\"Label2\")"); + + // ACT AND ASSERT + testMapGeneration(source, expectedCatalog); + } + + /** + * Test the map generated from a catalog. + * + * @param source + * the catalog, must not be {@code null} + * @param expectedCatalog + * the expected map, may be {@code null} + */ + public void testMapGeneration(final String source, final List expectedCatalog) { + // ACT + List compiledClassesList; + final ByteArrayInputStream sourceStream = new ByteArrayInputStream(source.getBytes()); + try { + compiledClassesList = generateAndCompile(sourceStream); + } finally { + try { + sourceStream.close(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // ASSERT + final String catalogClassName = CATALOG_NAME + CATALOG_NAME_SUFFIX; + + final String catalogClass = compiledClassesList.stream() + .filter(s -> s.getFileName().equals(catalogClassName)) + .findFirst() + .orElseThrow() + .getCode(); + + for (final String code : expectedCatalog) { + assertTrue(catalogClass.replaceAll("\\s+", "").contains(code), catalogClassName + " was generated correctly"); + } + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.xtend deleted file mode 100644 index 064a7b8ceb..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.xtend +++ /dev/null @@ -1,130 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.check.core.test - -import com.avaloq.tools.ddk.check.CheckInjectorProvider -import java.io.ByteArrayInputStream -import java.util.List -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.eclipse.xtext.xbase.testing.JavaSource -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.^extension.ExtendWith - -import static org.junit.jupiter.api.Assertions.* - -/** - * Unit test for auto generation of check issue code to label map. - */ -@InjectWith(CheckInjectorProvider) -@ExtendWith(InjectionExtension) -class IssueCodeToLabelMapGenerationTest extends AbstractCheckGenerationTestCase { - - static final String PACKAGE_NAME = "mypackage" - static final String CATALOG_NAME = "MyCatalog" - - /** - * Test the map generated from a catalog with no checks. - */ - @Test - def void testMapGenerationWithNoChecks() { - // ARRANGE - val source = ''' - package «PACKAGE_NAME» - - catalog «CATALOG_NAME» - for grammar com.avaloq.tools.ddk.check.Check { - - } - '''; - - // check for the construction of an empty map - val expectedCatalog = #['ImmutableMap.builderWithExpectedSize(0).build()'] - - // ACT AND ASSERT - testMapGeneration(source, expectedCatalog) - } - - /** - * Test the map generated from a catalog with checks. - */ - @Test - def void testMapGeneration() { - // ARRANGE - // @Format-Off - val source = ''' - package «PACKAGE_NAME» - - import com.avaloq.tools.ddk.check.check.Check - import com.avaloq.tools.ddk.check.check.Context - import com.avaloq.tools.ddk.check.check.Documented - - catalog «CATALOG_NAME» - for grammar com.avaloq.tools.ddk.check.Check { - - live error ID1 "Label 1" - message "Message 1" { - for Documented elem { - switch elem { - Context : issue on elem - Check : issue on elem - } - } - } - - live error ID2 "Label 2" - message "Message 2" { - for Documented elem { - switch elem { - Context : issue on elem - Check : issue on elem - } - } - } - } - '''; - // @Format-On - - val expectedCatalog = #['put(MyCatalogIssueCodes.ID_1,"Label1")','put(MyCatalogIssueCodes.ID_2,"Label2")'] - - // ACT AND ASSERT - testMapGeneration(source, expectedCatalog) - } - - /** - * Test the map generated from a catalog. - * @param source - * the catalog, must not be {@code null} - * @param expectedMap - * the expected map, may be {@code null} - */ - def void testMapGeneration(String source, List expectedCatalog) { - // ACT - var List compiledClassesList - val sourceStream = new ByteArrayInputStream(source.getBytes()); - try { - compiledClassesList = generateAndCompile(sourceStream); - } finally { - sourceStream.close - } - - // ASSERT - val catalogClassName = '''«CATALOG_NAME»«CATALOG_NAME_SUFFIX»''' - - val catalogClass = compiledClassesList.findFirst[s | s.fileName.equals(catalogClassName)].code; - - for (code: expectedCatalog) { - assertTrue( catalogClass.replaceAll("\\s+","").contains(code), '''«catalogClassName» was generated correctly''') - } - } - -} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java new file mode 100644 index 0000000000..3ab30f53e3 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.core.test.util; + +import java.util.List; + + +/** + * Provides utility operations for Check model stubs. Only partial models + * are returned as strings. + */ +public class CheckModelUtil { + + /** + * Returns a base model stub with package (com.test), catalog (c) and grammar (g). + */ + public String modelWithGrammar() { + StringBuilder builder = new StringBuilder(); + builder.append("package com.test"); + builder.append("\n"); + builder.append("catalog c for grammar g {"); + return builder.toString(); + } + + /** + * Returns a base model stub with a default category. + */ + public String modelWithCategory() { + String modelWithGrammar = this.modelWithGrammar(); + StringBuilder builder = new StringBuilder(); + builder.append("category \"Default Category\" {"); + return modelWithGrammar + builder.toString(); + } + + /** + * Returns a dummy category with given ID. + */ + public String emptyCategory(final String id, final String label) { + StringBuilder builder = new StringBuilder(); + builder.append("category "); + builder.append(id); + builder.append(" \""); + builder.append(label); + builder.append("\" {\n"); + builder.append("}"); + return builder.toString(); + } + + /** + * Returns a base model stub with a severity range. + */ + public String modelWithSeverityRange(final String min, final String max, final String severity) { + String modelWithCategory = this.modelWithCategory(); + StringBuilder builder = new StringBuilder(); + builder.append("@SeverityRange("); + builder.append(min); + builder.append(" .. "); + builder.append(max); + builder.append(")\n"); + builder.append(" "); + builder.append(severity); + builder.append(" ID \"My Check\" ()\n"); + builder.append(" "); + builder.append("message \"My Message\""); + return modelWithCategory + builder.toString(); + } + + /** + * Returns a base model stub with a severity range and a default check. + */ + public String modelWithSeverityRange(final String min, final String max) { + String modelWithCategory = this.modelWithCategory(); + StringBuilder builder = new StringBuilder(); + builder.append("@SeverityRange("); + builder.append(min); + builder.append(" .. "); + builder.append(max); + builder.append(")\n"); + return modelWithCategory + builder.toString() + modelWithCheck(); + } + + /** + * Returns a base model stub with a check of given ID. + */ + public String modelWithCheck(final String id) { + String modelWithCategory = this.modelWithCategory(); + StringBuilder builder = new StringBuilder(); + builder.append("error "); + builder.append(id); + builder.append(" \"Some Error\" ()\n"); + builder.append("message \"My Message\" {"); + return modelWithCategory + builder.toString(); + } + + /** + * Returns a base model stub with a check (SomeError) with severity 'error' + * and message (MyMessage). + */ + public String modelWithCheck() { + return this.modelWithCheck("ID"); + } + + /** + * Returns a dummy check with given ID. + */ + public String emptyCheck(final String id) { + StringBuilder builder = new StringBuilder(); + builder.append("error "); + builder.append(id); + builder.append(" \"Some Error\" ()\n"); + builder.append("message \"My message\" {\n"); + builder.append("}"); + return builder.toString(); + } + + /** + * Returns a base model stub with a context using context type ContextType + * 'ctx'. + */ + public String modelWithContext() { + String modelWithCheck = this.modelWithCheck(); + StringBuilder builder = new StringBuilder(); + builder.append("for ContextType ctx {"); + return modelWithCheck + builder.toString(); + } + + /** + * Returns a base model stub with a give collection of contexts. + */ + public String modelWithContexts(final List contexts) { + String modelWithCheck = this.modelWithCheck(); + StringBuilder builder = new StringBuilder(); + for (final String c : contexts) { + builder.append(c.toString()); + builder.append("\n"); + builder.append(" "); + } + return modelWithCheck + builder.toString(); + } + + /** + * Returns a complete Check model with multiple SL_ and ML_COMMENTS. + */ + public String modelWithComments() { + StringBuilder builder = new StringBuilder(); + builder.append("package com.test // SL1\n"); + builder.append("/* ML1 */\n"); + builder.append("catalog c /* ML2 */ for grammar g {\n"); + builder.append(" // SL2\n"); + builder.append(" category \"My cat\" {\n"); + builder.append(" /* ML3 */\n"); + builder.append(" // SL3\n"); + builder.append(" error MYerr \"My Err\" (int Abc = 23) message \"A\" {\n"); + builder.append(" for Atype thisName {\n"); + builder.append(" val x = 3 // SL4\n"); + builder.append(" // SL5\n"); + builder.append(" /* ML5 */ issue /* ML4 */\n"); + builder.append(" // SL6\n"); + builder.append(" }\n"); + builder.append(" }\n"); + builder.append(" } // SL7\n"); + builder.append("}"); + return builder.toString(); + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.xtend deleted file mode 100644 index a6a60b60bc..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.xtend +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.core.test.util - -import java.util.List - -/* - * Provides utility operations for Check model stubs. Only partial models - * are returned as strings. - */ -class CheckModelUtil { - - /* Returns a base model stub with package (com.test), catalog (c) and grammar (g). */ - def String modelWithGrammar () {''' - package com.test - catalog c for grammar g {'''.toString - } - - /* Returns a base model stub with a default category. */ - def String modelWithCategory () { - modelWithGrammar+ ''' - category "Default Category" {'''.toString - } - - /* Returns a dummy category with given ID. */ - def String emptyCategory (String id, String label) { ''' - category «id» "«label»" { - }'''.toString - } - - /* Returns a base model stub with a severity range. */ - def String modelWithSeverityRange (String min, String max, String severity) { - modelWithCategory + '''@SeverityRange(«min» .. «max») - «severity» ID "My Check" () - message "My Message"'''.toString - } - - /* Returns a base model stub with a severity range and a default check. */ - def String modelWithSeverityRange (String min, String max) { - modelWithCategory + '''@SeverityRange(«min» .. «max») - '''.toString + modelWithCheck - } - - /* Returns a base model stub with a check of given ID. */ - def String modelWithCheck (String id) { - modelWithCategory + ''' - error «id» "Some Error" () - message "My Message" {'''.toString - } - - /* - * Returns a base model stub with a check (SomeError) with severity 'error' - * and message (MyMessage). - */ - def String modelWithCheck () { - modelWithCheck("ID") - } - - /* Returns a dummy check with given ID. */ - def String emptyCheck(String id) { ''' - error «id» "Some Error" () - message "My message" { - }'''.toString - } - - /* - * Returns a base model stub with a context using context type ContextType - * 'ctx'. - */ - def String modelWithContext() { - modelWithCheck + ''' - for ContextType ctx {'''.toString - } - - /* Returns a base model stub with a give collection of contexts. */ - def String modelWithContexts(List contexts) { - modelWithCheck + ''' - «FOR c:contexts» - «c.toString» - «ENDFOR»'''.toString - } - - /* Returns a complete Check model with multiple SL_ and ML_COMMENTS */ - def String modelWithComments() {''' - package com.test // SL1 - /* ML1 */ - catalog c /* ML2 */ for grammar g { - // SL2 - category "My cat" { - /* ML3 */ - // SL3 - error MYerr "My Err" (int Abc = 23) message "A" { - for Atype thisName { - val x = 3 // SL4 - // SL5 - /* ML5 */ issue /* ML4 */ - // SL6 - } - } - } // SL7 - }'''.toString() - - } - -} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.java new file mode 100644 index 0000000000..d80cf6b812 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.java @@ -0,0 +1,1095 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.check.formatting; + +import com.avaloq.tools.ddk.check.CheckUiInjectorProvider; +import com.google.inject.Inject; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtext.formatting2.FormatterPreferenceKeys; +import org.eclipse.xtext.preferences.MapBasedPreferenceValues; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.formatter.FormatterTestHelper; +import org.eclipse.xtext.testing.formatter.FormatterTestRequest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@InjectWith(CheckUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +public class CheckFormattingTest { + + @Inject + private FormatterTestHelper _formatterTestHelper; + + /** + * Test that correctly formatted Check sources are not modified. + */ + @Test + public void testFormattedSource() { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("package com.avaloq.tools.ddk.check.formatting"); + _builder.newLine(); + _builder.newLine(); + _builder.append("import com.avaloq.tools.ddk.check.check.*"); + _builder.newLine(); + _builder.newLine(); + _builder.append("catalog CheckFormattingTest"); + _builder.newLine(); + _builder.append("for grammar com.avaloq.tools.ddk.check.Check {"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("category \"Label\" {"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + _builder.newLine(); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.append(" "); + _builder.append("live error UniqueID \"Label\""); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"message\" {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("live error anotherid \"Label\""); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"message {0}, {1}\" {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("def Name"); + _builder.newLine(); + _builder.append(" "); + _builder.append("for Category list {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("issue anotherid on list bind (3, 2) data (\"\")"); + _builder.newLine(); + _builder.append(" "); + _builder.append("val size ="); + _builder.newLine(); + _builder.append(" "); + _builder.append("if (list.checks !== null) list.checks.size else 0"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if (list.checks?.size > 1) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("// SL: string value of list"); + _builder.newLine(); + _builder.append(" "); + _builder.append("String::valueOf(list)"); + _builder.newLine(); + _builder.append(" "); + _builder.append("issue UniqueID on list#checks[0]"); + _builder.newLine(); + _builder.append(" "); + _builder.append("} else {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("/* ML: string value of size */"); + _builder.newLine(); + _builder.append(" "); + _builder.append("String::valueOf(size)"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@SeverityRange(warning .. error)"); + _builder.newLine(); + _builder.append(" "); + _builder.append("onSave error lastID \"Label\""); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"message\" {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("// single line comment"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* This check is javadoc-like commented."); + _builder.newLine(); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.append(" "); + _builder.append("warning CategoryNamedW \"Category named W\" (boolean foo = false, boolean bar = true)"); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"Category named \'w\'\" {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("for Category c {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("issue"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + final String input = _builder.toString(); + + _formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { + // these preferences are usually picked up from the resource, but we are not using a resource here. + MapBasedPreferenceValues prefs = new MapBasedPreferenceValues(); + prefs.put(FormatterPreferenceKeys.indentation, " "); + it.getRequest().setPreferences(prefs); + it.setToBeFormatted(input); + it.setExpectation(input); + }); + } + + /** + * Test that spaces and new lines are added where expected. + */ + @Test + public void testWSAdded() { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("package com.avaloq.tools.ddk.check.formatting import com.avaloq.tools.ddk.check.check.* catalog CheckFormattingTest"); + _builder.newLine(); + _builder.append("for grammar com.avaloq.tools.ddk.check.Check{category \"Label\"{/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + _builder.newLine(); + _builder.append(" "); + _builder.append("*/live error UniqueID \"Label\""); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"message\"{}live error anotherid \"Label\""); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"message {0}, {1}\" {}}"); + _builder.newLine(); + _builder.append(" "); + _builder.append("def Name for Category list{issue anotherid on list bind(3,2)data(\"\")"); + _builder.newLine(); + _builder.append(" "); + _builder.append("val size=if(list.checks !== null)list.checks.size else 0"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if(list.checks?.size>1){"); + _builder.newLine(); + _builder.append(" "); + _builder.append("// SL: string value of list"); + _builder.newLine(); + _builder.append(" "); + _builder.append("String::valueOf(list)issue UniqueID on list#checks[0]}else{/* ML: string value of size */String::valueOf(size)}}"); + _builder.newLine(); + _builder.append(" "); + _builder.append("@SeverityRange(warning..error)onSave error lastID\"Label\"message \"message\" {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("// single line comment"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* This check is javadoc-like commented."); + _builder.newLine(); + _builder.append(" "); + _builder.append("*/warning CategoryNamedW \"Category named W\"(boolean foo=false,boolean bar=true)message \"Category named \'w\'\"{"); + _builder.newLine(); + _builder.append(" "); + _builder.append("for Category c {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("if(\'w\'.equalsIgnoreCase(c.name)){issue}"); + _builder.newLine(); + _builder.append("}}}"); + _builder.newLine(); + final String input = _builder.toString(); + + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("package com.avaloq.tools.ddk.check.formatting"); + _builder_1.newLine(); + _builder_1.append("import com.avaloq.tools.ddk.check.check.*"); + _builder_1.newLine(); + _builder_1.append("catalog CheckFormattingTest"); + _builder_1.newLine(); + _builder_1.append("for grammar com.avaloq.tools.ddk.check.Check {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("category \"Label\" {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("/**"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("*/"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("live error UniqueID \"Label\""); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("message \"message\" {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("live error anotherid \"Label\""); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("message \"message {0}, {1}\" {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("def Name"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("for Category list {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("issue anotherid on list bind (3, 2) data (\"\")"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("val size ="); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("if (list.checks !== null) list.checks.size else 0"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("if (list.checks?.size > 1) {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("// SL: string value of list"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("String::valueOf(list)"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("issue UniqueID on list#checks[0]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("} else { /* ML: string value of size */"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("String::valueOf(size)"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("@SeverityRange(warning .. error)"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("onSave error lastID \"Label\""); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("message \"message\" {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("// single line comment"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("/**"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("* This check is javadoc-like commented."); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("*/"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("warning CategoryNamedW \"Category named W\" (boolean foo = false, boolean bar = true)"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("message \"Category named \'w\'\" {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("for Category c {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("issue"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append("}"); + _builder_1.newLine(); + final String expected = _builder_1.toString(); + + _formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { + // these preferences are usually picked up from the resource, but we are not using a resource here. + MapBasedPreferenceValues prefs = new MapBasedPreferenceValues(); + prefs.put(FormatterPreferenceKeys.indentation, " "); + it.getRequest().setPreferences(prefs); + it.setToBeFormatted(input); + it.setExpectation(expected); + }); + } + + /** + * Test that additional spaces and new lines are removed + */ + @Test + public void testWSRemoved() { + StringConcatenation _builder = new StringConcatenation(); + _builder.append(" "); + _builder.append("package"); + _builder.newLine(); + _builder.append(" "); + _builder.append("com.avaloq.tools.ddk.check.formatting"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append("import"); + _builder.newLine(); + _builder.append(" "); + _builder.append("com.avaloq.tools.ddk.check.check.*"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append("catalog"); + _builder.newLine(); + _builder.append(" "); + _builder.append("CheckFormattingTest"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append("for"); + _builder.newLine(); + _builder.append(" "); + _builder.append("grammar"); + _builder.newLine(); + _builder.append(" "); + _builder.append("com.avaloq.tools.ddk.check.Check"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("category"); + _builder.newLine(); + _builder.append(" "); + _builder.append("\"Label\""); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + _builder.newLine(); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("live"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("error"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("UniqueID"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("\"Label\""); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("message"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("\"message\""); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("live error anotherid \"Label\""); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"message {0}, {1}\" {"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("def"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("Name"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("for"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("Category"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("list"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("issue"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("anotherid"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("on"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("list"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("bind"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("3"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(","); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("2"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("data"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("\"\""); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("val"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("size"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("="); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("if"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("list"); + _builder.newLine(); + _builder.append(" "); + _builder.append("."); + _builder.newLine(); + _builder.append(" "); + _builder.append("checks"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("!=="); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("null"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("list . checks . size"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("else"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("0"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("if"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("list.checks ?. size"); + _builder.newLine(); + _builder.append(" "); + _builder.append("> 1)"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("// SL: string value of list"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("String"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("::"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("valueOf"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("list"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("issue UniqueID on list # checks"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("["); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("0"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("]"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("else"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("{"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("/* ML: string value of size */"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("String :: valueOf ( size )"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("@"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("SeverityRange"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("warning"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(".."); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("error"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("onSave error lastID \"Label\""); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"message\" {"); + _builder.newLine(); + _builder.append(" "); + _builder.append("// single line comment"); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("/**"); + _builder.newLine(); + _builder.append(" "); + _builder.append("* This check is javadoc-like commented."); + _builder.newLine(); + _builder.append(" "); + _builder.append("*/"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("warning CategoryNamedW \"Category named W\""); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("("); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("boolean"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("foo"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("="); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("false"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(","); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("boolean"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("bar"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("="); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("true"); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append(")"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("message \"Category named \'w\'\" {"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("for Category c {"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("issue"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append(" "); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _builder.newLine(); + final String input = _builder.toString(); + + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("package com.avaloq.tools.ddk.check.formatting"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append("import com.avaloq.tools.ddk.check.check.*"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append("catalog CheckFormattingTest"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append("for grammar com.avaloq.tools.ddk.check.Check {"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("category \"Label\" {"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("/**"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("*/"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("live error UniqueID \"Label\""); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("message \"message\" {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("live error anotherid \"Label\""); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("message \"message {0}, {1}\" {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("def Name"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("for Category list {"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("issue anotherid on list bind (3, 2) data (\"\")"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("val size ="); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("if (list.checks !== null) list.checks.size else 0"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("if (list.checks?.size > 1) {"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("// SL: string value of list"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("String::valueOf("); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("list"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append(")"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("issue UniqueID on list#checks[0]"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("} else {"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("/* ML: string value of size */"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("String::valueOf(size)"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("@SeverityRange(warning .. error)"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("onSave error lastID \"Label\""); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("message \"message\" {"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("// single line comment"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("/**"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("* This check is javadoc-like commented."); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("*/"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("warning CategoryNamedW \"Category named W\" (boolean foo = false,"); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("boolean bar = true)"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("message \"Category named \'w\'\" {"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("for Category c {"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("issue"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.newLine(); + _builder_1.append(" "); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.append("}"); + _builder_1.newLine(); + final String expected = _builder_1.toString(); + + _formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { + // these preferences are usually picked up from the resource, but we are not using a resource here. + MapBasedPreferenceValues prefs = new MapBasedPreferenceValues(); + prefs.put(FormatterPreferenceKeys.indentation, " "); + it.getRequest().setPreferences(prefs); + it.setToBeFormatted(input); + it.setExpectation(expected); + }); + } +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.xtend deleted file mode 100644 index 027a376929..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.xtend +++ /dev/null @@ -1,554 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.check.formatting - -import com.avaloq.tools.ddk.check.CheckUiInjectorProvider -import com.google.inject.Inject -import org.eclipse.xtext.formatting2.FormatterPreferenceKeys -import org.eclipse.xtext.preferences.MapBasedPreferenceValues -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.formatter.FormatterTestHelper -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test - -@InjectWith(typeof(CheckUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class CheckFormattingTest { - - @Inject - extension FormatterTestHelper - - /** - * Test that correctly formatted Check sources are not modified. - */ - @Test - def void testFormattedSource() { - val input = ''' - package com.avaloq.tools.ddk.check.formatting - - import com.avaloq.tools.ddk.check.check.* - - catalog CheckFormattingTest - for grammar com.avaloq.tools.ddk.check.Check { - - category "Label" { - - /** - * @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 - */ - live error UniqueID "Label" - message "message" { - } - - live error anotherid "Label" - message "message {0}, {1}" { - } - } - - def Name - for Category list { - issue anotherid on list bind (3, 2) data ("") - val size = - if (list.checks !== null) list.checks.size else 0 - if (list.checks?.size > 1) { - // SL: string value of list - String::valueOf(list) - issue UniqueID on list#checks[0] - } else { - /* ML: string value of size */ - String::valueOf(size) - } - } - - @SeverityRange(warning .. error) - onSave error lastID "Label" - message "message" { - // single line comment - } - - /** - * This check is javadoc-like commented. - */ - warning CategoryNamedW "Category named W" (boolean foo = false, boolean bar = true) - message "Category named 'w'" { - for Category c { - if ('w'.equalsIgnoreCase(c.name)) { - issue - } - } - } - } - ''' - - assertFormatted[ - // these preferences are usually picked up from the resource, but we are not using a resource here. - request.preferences = new MapBasedPreferenceValues() => [put(FormatterPreferenceKeys.indentation, ' ')] - - toBeFormatted = input - expectation = input - ]; - } - - /** - * Test that spaces and new lines are added where expected. - */ - @Test - def void testWSAdded() { - val input = ''' - package com.avaloq.tools.ddk.check.formatting import com.avaloq.tools.ddk.check.check.* catalog CheckFormattingTest - for grammar com.avaloq.tools.ddk.check.Check{category "Label"{/** - * @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 - */live error UniqueID "Label" - message "message"{}live error anotherid "Label" - message "message {0}, {1}" {}} - def Name for Category list{issue anotherid on list bind(3,2)data("") - val size=if(list.checks !== null)list.checks.size else 0 - if(list.checks?.size>1){ - // SL: string value of list - String::valueOf(list)issue UniqueID on list#checks[0]}else{/* ML: string value of size */String::valueOf(size)}} - @SeverityRange(warning..error)onSave error lastID"Label"message "message" { - // single line comment - }/** - * This check is javadoc-like commented. - */warning CategoryNamedW "Category named W"(boolean foo=false,boolean bar=true)message "Category named 'w'"{ - for Category c { - if('w'.equalsIgnoreCase(c.name)){issue} - }}} - ''' - - val expected = ''' - package com.avaloq.tools.ddk.check.formatting - import com.avaloq.tools.ddk.check.check.* - catalog CheckFormattingTest - for grammar com.avaloq.tools.ddk.check.Check { - category "Label" { - /** - * @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 - */ - live error UniqueID "Label" - message "message" { - } - live error anotherid "Label" - message "message {0}, {1}" { - } - } - def Name - for Category list { - issue anotherid on list bind (3, 2) data ("") - val size = - if (list.checks !== null) list.checks.size else 0 - if (list.checks?.size > 1) { - // SL: string value of list - String::valueOf(list) - issue UniqueID on list#checks[0] - } else { /* ML: string value of size */ - String::valueOf(size) - } - } - @SeverityRange(warning .. error) - onSave error lastID "Label" - message "message" { - // single line comment - } - /** - * This check is javadoc-like commented. - */ - warning CategoryNamedW "Category named W" (boolean foo = false, boolean bar = true) - message "Category named 'w'" { - for Category c { - if ('w'.equalsIgnoreCase(c.name)) { - issue - } - } - } - } - ''' - - assertFormatted[ - // these preferences are usually picked up from the resource, but we are not using a resource here. - request.preferences = new MapBasedPreferenceValues() => [put(FormatterPreferenceKeys.indentation, ' ')] - toBeFormatted = input - expectation = expected - ]; - } - - /** - * Test that additional spaces and new lines are removed - */ - @Test - def void testWSRemoved() { - val input = ''' - package - com.avaloq.tools.ddk.check.formatting - - - - import - com.avaloq.tools.ddk.check.check.* - - - - catalog - CheckFormattingTest - - - for - grammar - com.avaloq.tools.ddk.check.Check - - - { - - - - category - "Label" - - { - - - /** - * @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 - */ - - - - live - - error - - UniqueID - - "Label" - - - message - - - "message" - - { - - - } - - live error anotherid "Label" - message "message {0}, {1}" { - - - } - - - } - - - - def - - Name - - - for - - Category - - list - - { - - - issue - - - anotherid - - - on - - - list - - - bind - - - ( - - 3 - - , - - 2 - - ) - - data - - ( - - "" - - ) - - - val - - size - - = - - - if - - ( - - list - . - checks - - !== - - null - - ) - - list . checks . size - - - else - - 0 - - if - - ( - - list.checks ?. size - > 1) - - - { - - - - // SL: string value of list - - - String - - :: - - valueOf - - ( - - list - - ) - - issue UniqueID on list # checks - - [ - - 0 - - ] - } - - - else - - - { - - - - /* ML: string value of size */ - - - String :: valueOf ( size ) - - - } - - - } - - - - @ - - SeverityRange - - ( - - warning - - .. - - error - - ) - - - onSave error lastID "Label" - message "message" { - // single line comment - } - - - - /** - * This check is javadoc-like commented. - */ - - - warning CategoryNamedW "Category named W" - - - ( - - boolean - - foo - - = - - false - - , - - boolean - - bar - - = - - true - - ) - - - message "Category named 'w'" { - - - for Category c { - - - if ('w'.equalsIgnoreCase(c.name)) { - - - issue - - - } - - - } - - - } - - - } - - - ''' - - val expected = ''' - package com.avaloq.tools.ddk.check.formatting - - import com.avaloq.tools.ddk.check.check.* - - catalog CheckFormattingTest - - for grammar com.avaloq.tools.ddk.check.Check { - - category "Label" { - - /** - * @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 - */ - live error UniqueID "Label" - - message "message" { - } - - live error anotherid "Label" - message "message {0}, {1}" { - } - } - - def Name - - for Category list { - - issue anotherid on list bind (3, 2) data ("") - - val size = - - if (list.checks !== null) list.checks.size else 0 - - if (list.checks?.size > 1) { - - // SL: string value of list - String::valueOf( - list - ) - - issue UniqueID on list#checks[0] - } else { - - /* ML: string value of size */ - String::valueOf(size) - - } - - } - - @SeverityRange(warning .. error) - onSave error lastID "Label" - message "message" { - // single line comment - } - - /** - * This check is javadoc-like commented. - */ - warning CategoryNamedW "Category named W" (boolean foo = false, - boolean bar = true) - - message "Category named 'w'" { - - for Category c { - - if ('w'.equalsIgnoreCase(c.name)) { - - issue - - } - - } - - } - } - ''' - - assertFormatted[ - // these preferences are usually picked up from the resource, but we are not using a resource here. - request.preferences = new MapBasedPreferenceValues() => [put(FormatterPreferenceKeys.indentation, ' ')] - toBeFormatted = input - expectation = expected - ]; - } -} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.java new file mode 100644 index 0000000000..d0b3caef93 --- /dev/null +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.java @@ -0,0 +1,333 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.validation; + +import com.avaloq.tools.ddk.check.CheckUiInjectorProvider; +import com.avaloq.tools.ddk.check.check.CheckCatalog; +import com.avaloq.tools.ddk.check.check.CheckPackage; +import com.avaloq.tools.ddk.check.core.test.util.CheckModelUtil; +import com.google.common.collect.Lists; +import com.google.inject.Inject; + +import java.util.ArrayList; + +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.eclipse.xtext.xbase.XbasePackage; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +/* + * Tests for various check validations as implemented in the validation classes + *
    + *
  • com.avaloq.tools.ddk.check.validation.CheckJavaValidator + *
  • com.avaloq.tools.ddk.check.validation.ClasspathBasedChecks + *
+ */ +@InjectWith(CheckUiInjectorProvider.class) +@ExtendWith(InjectionExtension.class) +@SuppressWarnings("nls") +public class CheckValidationTest { + + @Inject + private ValidationTestHelper helper; + + @Inject + private ParseHelper parser; + + @Inject + private CheckModelUtil modelUtil; + + /* Tests checkReturnExpressions(XReturnExpression) */ + @Test + public void testReturnExpressions() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithGrammar() + "def SomeDef for X { return null;"); + helper.assertError(model, XbasePackage.Literals.XRETURN_EXPRESSION, IssueCodes.RETURN_IN_IMPL); + } + + /* Tests checkIssuedCheck(XIssueExpression) */ + @Test + public void testIssuedCheck() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithGrammar() + "def SomeDef for X { issue on"); + helper.assertError(model, CheckPackage.Literals.XISSUE_EXPRESSION, IssueCodes.ISSUED_CHECK); + } + + /* Tests checkImplicitIssuedCheck(XIssueExpression) */ + @Test + public void testImplicitIssuedCheck() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithCheck("A") + "for X { issue A"); + helper.assertWarning(model, CheckPackage.Literals.XISSUE_EXPRESSION, IssueCodes.IMPLICIT_ISSUED_CHECK); + final CheckCatalog model2 = parser.parse(modelUtil.modelWithCheck("A") + "for X { issue A"); + helper.assertWarning(model2, CheckPackage.Literals.XISSUE_EXPRESSION, IssueCodes.IMPLICIT_ISSUED_CHECK); + } + + // TODO check included catalogs + + /* Tests checkFileNamingConventions(CheckCatalog) */ + @Test + public void testFileNamingConventions() throws Exception { + final CheckCatalog model = parser.parse("package p catalog c "); + helper.assertError(model, CheckPackage.Literals.CHECK_CATALOG, IssueCodes.WRONG_FILE); + helper.assertError(model, CheckPackage.Literals.CHECK_CATALOG, IssueCodes.WRONG_PACKAGE); + } + + /* Tests checkPackageName(CheckCatalog). All given package names are valid. */ + @Test + public void testPackageNameIsValid() throws Exception { + helper.assertNoError(parser.parse("package p "), IssueCodes.INVALID_PACKAGE_NAME); + helper.assertNoError(parser.parse("package p.q.r "), IssueCodes.INVALID_PACKAGE_NAME); + } + + /* Tests checkPackageName(CheckCatalog). All given package names are invalid. */ + @Test + public void testPackageNameIsInvalid() throws Exception { + // Cannot check package names such as '.p' or 'p..q' because they will cause a parsing error preventing the Java + // check from being executed + helper.assertError(parser.parse("package P.p.P. "), CheckPackage.Literals.CHECK_CATALOG, IssueCodes.INVALID_PACKAGE_NAME); + helper.assertError(parser.parse("package P.package.P. "), CheckPackage.Literals.CHECK_CATALOG, IssueCodes.INVALID_PACKAGE_NAME); + } + + /* Tests checkContextTypeIsUnique(Check) */ + @Test + @Disabled("Tests do not work because of scoping issues at run-time") + public void testContextTypeIsUnique() throws Exception { + // should fail + ArrayList contexts = Lists.newArrayList("for C c {issue}", "for C d {issue}"); + CheckCatalog model = parser.parse(modelUtil.modelWithContexts(contexts)); + helper.assertError(model, CheckPackage.Literals.CONTEXT, IssueCodes.CONTEXT_TYPES_NOT_UNIQUE); + + // should fail + contexts = Lists.newArrayList("for C c {issue}", "for D d {issue}", "for C e {issue}"); + model = parser.parse(modelUtil.modelWithContexts(contexts)); + helper.assertError(model, CheckPackage.Literals.CONTEXT, IssueCodes.CONTEXT_TYPES_NOT_UNIQUE); + + // should not fail + contexts = Lists.newArrayList("for org.eclipse.emf.ecore.EObject e {issue}", "for E e {issue}"); + model = parser.parse(modelUtil.modelWithContexts(contexts)); + helper.assertNoError(model, IssueCodes.CONTEXT_TYPES_NOT_UNIQUE); + } + + /* Tests checkGuardsFirstInBlockExpression(Context) */ + @Test + public void testGuardsPrecedeIssues() throws Exception { + // basic case: should not fail + CheckCatalog model = parser.parse(modelUtil.modelWithContext() + "guard(false) issue"); + helper.assertNoError(model, IssueCodes.GUARDS_COME_FIRST); + + // multiple guards: should not fail + model = parser.parse(modelUtil.modelWithContext() + "guard(false) guard(true) if(false) {null} issue"); + helper.assertNoError(model, IssueCodes.GUARDS_COME_FIRST); + + // should not fail + model = parser.parse(modelUtil.modelWithContext() + "guard(false) val x = 1 var y = 2 issue"); + helper.assertNoError(model, IssueCodes.GUARDS_COME_FIRST); + + // guard not first: should fail + model = parser.parse(modelUtil.modelWithContext() + "issue guard(false)"); + helper.assertError(model, CheckPackage.Literals.XGUARD_EXPRESSION, IssueCodes.GUARDS_COME_FIRST); + + // should fail + model = parser.parse(modelUtil.modelWithContext() + "guard(true) issue guard(false)"); + helper.assertError(model, CheckPackage.Literals.XGUARD_EXPRESSION, IssueCodes.GUARDS_COME_FIRST); + + // should fail + model = parser.parse(modelUtil.modelWithContext() + "guard(true) if(true){issue} guard(true)"); + helper.assertError(model, CheckPackage.Literals.XGUARD_EXPRESSION, IssueCodes.GUARDS_COME_FIRST); + } + + /* Tests org.eclipse.xtext.xbase.validation.EarlyExitValidator.checkDeadCode(XBlockExpression) */ + @Test + public void testDeadCode() throws Exception { + // should not fail + CheckCatalog model = parser.parse(modelUtil.modelWithContext() + "issue"); + helper.assertNoError(model, IssueCodes.DEAD_CODE); + + // should fail + model = parser.parse(modelUtil.modelWithContext() + "if(false) {return} else {return} issue"); + helper.assertError(model, XbasePackage.Literals.XEXPRESSION, org.eclipse.xtext.xbase.validation.IssueCodes.UNREACHABLE_CODE); + } + + /* Tests checkIssueExpressionExists(Context) */ + @Test + public void testIssueExpressionExists() throws Exception { + CheckCatalog model = parser.parse(modelUtil.modelWithContext() + "guard(false)"); + helper.assertError(model, CheckPackage.Literals.CONTEXT, IssueCodes.MISSING_ISSUE_EXPRESSION); + + // should not fail + model = parser.parse(modelUtil.modelWithContext() + "if (false) { null } else { issue"); + helper.assertNoError(model, IssueCodes.MISSING_ISSUE_EXPRESSION); + + // should fail + model = parser.parse(modelUtil.modelWithContext() + "if (false) { null } else { null } "); + helper.assertError(model, CheckPackage.Literals.CONTEXT, IssueCodes.MISSING_ISSUE_EXPRESSION); + + // should not fail + model = parser.parse(modelUtil.modelWithContext() + "if (false) { null } else { null } issue"); + helper.assertNoError(model, IssueCodes.MISSING_ISSUE_EXPRESSION); + + // should not fail + model = parser.parse(modelUtil.modelWithContext() + "if (false) { issue "); + helper.assertNoError(model, IssueCodes.MISSING_ISSUE_EXPRESSION); + } + + /* Test checkCheckName(Check). ID is missing. */ + @Test + public void testCheckIDIsMissing() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithCheck("")); + helper.assertError(model, CheckPackage.Literals.CHECK, IssueCodes.MISSING_ID_ON_CHECK); + helper.assertNoErrors(model, CheckPackage.Literals.CHECK, IssueCodes.INVALID_CHECK_NAME); + helper.assertNoWarnings(model, CheckPackage.Literals.CHECK, IssueCodes.INVALID_CHECK_NAME); + } + + /* Test checkCheckName(Check). ID is valid. */ + @Test + public void testCheckIDIsValid() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithCheck("ID")); + helper.assertNoErrors(model, CheckPackage.Literals.CHECK, IssueCodes.MISSING_ID_ON_CHECK); + helper.assertNoErrors(model, CheckPackage.Literals.CHECK, IssueCodes.INVALID_CHECK_NAME); + helper.assertNoWarnings(model, CheckPackage.Literals.CHECK, IssueCodes.INVALID_CHECK_NAME); + } + + // Cannot test with an invalid ID because that would cause a syntax error. + // But CheckJavaValidatorUtilTest.checkNameIsInvalid() tests the relevant logic in CheckJavaValidatorUtil.checkCheckName(String). + + /* Test checkCheckName(Check). ID is discouraged. */ + @Test + public void testCheckIDIsDiscouraged() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithCheck("iD")); + helper.assertNoErrors(model, CheckPackage.Literals.CHECK, IssueCodes.MISSING_ID_ON_CHECK); + helper.assertNoErrors(model, CheckPackage.Literals.CHECK, IssueCodes.INVALID_CHECK_NAME); + helper.assertWarning(model, CheckPackage.Literals.CHECK, IssueCodes.INVALID_CHECK_NAME); + } + + /* Test checkCheckNamesAreUnique(CheckCatalog). IDs are unique. */ + @Test + public void testCheckIDsAreUnique() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithCategory() + modelUtil.emptyCheck("ID1") + modelUtil.emptyCheck("ID2")); + helper.assertNoErrors(model, CheckPackage.Literals.CHECK, IssueCodes.DUPLICATE_CHECK); + } + + /* Test checkCheckNamesAreUnique(CheckCatalog). IDs are not unique. */ + @Test + public void testCheckIDsAreNotUnique() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithCategory() + modelUtil.emptyCheck("ID1") + modelUtil.emptyCheck("ID1")); + helper.assertError(model, CheckPackage.Literals.CHECK, IssueCodes.DUPLICATE_CHECK); + } + + /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are unique. */ + @Test + public void testCategoryIDsAreUnique() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithGrammar() + modelUtil.emptyCategory("ID1", "Label") + modelUtil.emptyCategory("ID2", "Label")); + helper.assertNoErrors(model, CheckPackage.Literals.CATEGORY, IssueCodes.DUPLICATE_CATEGORY); + } + + /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are not unique. */ + @Test + public void testCategoryIDsAreNotUnique() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithCategory() + modelUtil.emptyCategory("ID1", "Label") + modelUtil.emptyCategory("ID1", "Label")); + helper.assertError(model, CheckPackage.Literals.CATEGORY, IssueCodes.DUPLICATE_CATEGORY); + } + + /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are not present; labels are unique. */ + @Test + public void testCategoryLabelsAreUnique() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithGrammar() + modelUtil.emptyCategory("", "Label1") + modelUtil.emptyCategory("", "Label2")); + helper.assertNoErrors(model, CheckPackage.Literals.CATEGORY, IssueCodes.DUPLICATE_CATEGORY); + } + + /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are not present; labels are not unique. */ + @Test + public void testCategoryLabelsAreNotUnique() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithGrammar() + modelUtil.emptyCategory("", "Label1") + modelUtil.emptyCategory("", "Label1")); + helper.assertError(model, CheckPackage.Literals.CATEGORY, IssueCodes.DUPLICATE_CATEGORY); + } + + /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are not present; labels are unique but create non-unique names. */ + @Test + public void testCategoryLabelsAreNotUniqueOnceConverted() throws Exception { + final CheckCatalog model = parser.parse(modelUtil.modelWithGrammar() + modelUtil.emptyCategory("", "LabelOne") + modelUtil.emptyCategory("", "Label one")); + helper.assertError(model, CheckPackage.Literals.CATEGORY, IssueCodes.DUPLICATE_CATEGORY); + } + + /* Tests checkSeverityRangeOrder(Check) */ + @Test + public void testSeverityRangeOrder_1() throws Exception { + helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange("warning", "error")), + IssueCodes.ILLEGAL_SEVERITY_RANGE_ORDER); + } + + /* Tests checkSeverityRangeOrder(Check) */ + @Test + public void testSeverityRangeOrder_2() throws Exception { + helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange("ignore", "warning")), + IssueCodes.ILLEGAL_SEVERITY_RANGE_ORDER); + } + + /* Tests checkSeverityRangeOrder(Check) */ + @Test + public void testSeverityRangeOrder_3() throws Exception { + helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange("info", "info")), + IssueCodes.ILLEGAL_SEVERITY_RANGE_ORDER); + } + + /* Tests checkSeverityRangeOrder(Check) */ + @Test + public void testSeverityRangeOrder_4() throws Exception { + helper.assertError(parser.parse(modelUtil.modelWithSeverityRange("info", "ignore")), + CheckPackage.Literals.SEVERITY_RANGE, IssueCodes.ILLEGAL_SEVERITY_RANGE_ORDER); + } + + /* Tests checkSeverityRangeOrder(Check) */ + @Test + public void testSeverityRangeOrder_5() throws Exception { + helper.assertError(parser.parse(modelUtil.modelWithSeverityRange("error", "info")), + CheckPackage.Literals.SEVERITY_RANGE, IssueCodes.ILLEGAL_SEVERITY_RANGE_ORDER); + } + + /* Tests checkDefaultSeverityInRange(Check) */ + @Test + public void testDefaultSeverityInRange_1() throws Exception { + helper.assertError(parser.parse(modelUtil.modelWithSeverityRange("warning", "error", "info")), + CheckPackage.Literals.CHECK, IssueCodes.DEFAULT_SEVERITY_NOT_IN_RANGE); + } + + /* Tests checkDefaultSeverityInRange(Check) */ + @Test + public void testDefaultSeverityInRange_2() throws Exception { + helper.assertError(parser.parse(modelUtil.modelWithSeverityRange("error", "info", "ignore")), + CheckPackage.Literals.CHECK, IssueCodes.DEFAULT_SEVERITY_NOT_IN_RANGE); + } + + /* Tests checkDefaultSeverityInRange(Check) */ + @Test + public void testDefaultSeverityInRange_3() throws Exception { + helper.assertError(parser.parse(modelUtil.modelWithSeverityRange("error", "error", "ignore")), + CheckPackage.Literals.CHECK, IssueCodes.DEFAULT_SEVERITY_NOT_IN_RANGE); + } + + /* Tests checkDefaultSeverityInRange(Check) */ + @Test + public void testDefaultSeverityInRange_4() throws Exception { + helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange("error", "error", "error")), + IssueCodes.DEFAULT_SEVERITY_NOT_IN_RANGE); + } + + /* Tests checkDefaultSeverityInRange(Check) */ + @Test + public void testDefaultSeverityInRange_5() throws Exception { + helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange("info", "error", "warning")), + IssueCodes.DEFAULT_SEVERITY_NOT_IN_RANGE); + } + +} diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.xtend b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.xtend deleted file mode 100644 index 42420211ec..0000000000 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.xtend +++ /dev/null @@ -1,342 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.validation - -import com.avaloq.tools.ddk.check.CheckUiInjectorProvider -import com.avaloq.tools.ddk.check.check.CheckCatalog -import com.avaloq.tools.ddk.check.core.test.util.CheckModelUtil -import com.google.common.collect.Lists -import com.google.inject.Inject -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.util.ParseHelper -import org.eclipse.xtext.testing.validation.ValidationTestHelper -import org.eclipse.xtext.xbase.XbasePackage$Literals -import com.avaloq.tools.ddk.check.validation.IssueCodes -import com.avaloq.tools.ddk.check.check.CheckPackage -import org.junit.jupiter.api.^extension.ExtendWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.Disabled - -/* - * Tests for various check validations as implemented in the validation classes - *
    - *
  • com.avaloq.tools.ddk.check.validation.CheckJavaValidator - *
  • com.avaloq.tools.ddk.check.validation.ClasspathBasedChecks - *
- */ -@InjectWith(typeof(CheckUiInjectorProvider)) -@ExtendWith(typeof(InjectionExtension)) -class CheckValidationTest { - - @Inject - ValidationTestHelper helper - - @Inject - ParseHelper parser - - @Inject - CheckModelUtil modelUtil - - /* Tests checkReturnExpressions(XReturnExpression) */ - @Test - def void testReturnExpressions() { - val model = parser.parse(modelUtil.modelWithGrammar + "def SomeDef for X { return null;") - helper.assertError(model, XbasePackage$Literals::XRETURN_EXPRESSION, IssueCodes::RETURN_IN_IMPL) - } - - /* Tests checkIssuedCheck(XIssueExpression) */ - @Test - def void testIssuedCheck() { - val model = parser.parse(modelUtil.modelWithGrammar + "def SomeDef for X { issue on") - helper.assertError(model, CheckPackage$Literals::XISSUE_EXPRESSION, IssueCodes::ISSUED_CHECK) - } - - /* Tests checkImplicitIssuedCheck(XIssueExpression) */ - @Test - def void testImplicitIssuedCheck() { - val model = parser.parse(modelUtil.modelWithCheck("A") + "for X { issue A") - helper.assertWarning(model, CheckPackage$Literals::XISSUE_EXPRESSION, IssueCodes::IMPLICIT_ISSUED_CHECK) - val model2 = parser.parse(modelUtil.modelWithCheck("A") + "for X { issue A") - helper.assertWarning(model2, CheckPackage$Literals::XISSUE_EXPRESSION, IssueCodes::IMPLICIT_ISSUED_CHECK) - } - -//TODO check included catalogs - - /* Tests checkFileNamingConventions(CheckCatalog) */ - @Test - def void testFileNamingConventions() { - val model = parser.parse("package p catalog c ") - helper.assertError(model, CheckPackage$Literals::CHECK_CATALOG, IssueCodes::WRONG_FILE) - helper.assertError(model, CheckPackage$Literals::CHECK_CATALOG, IssueCodes::WRONG_PACKAGE) - } - - /* Tests checkPackageName(CheckCatalog). All given package names are valid. */ - @Test - def void testPackageNameIsValid() { - helper.assertNoError(parser.parse("package p "), IssueCodes::INVALID_PACKAGE_NAME) - helper.assertNoError(parser.parse("package p.q.r "), IssueCodes::INVALID_PACKAGE_NAME) - } - - /* Tests checkPackageName(CheckCatalog). All given package names are invalid. */ - @Test - def void testPackageNameIsInvalid() { - // Cannot check package names such as '.p' or 'p..q' because they will cause a parsing error preventing the Java - // check from being executed - helper.assertError(parser.parse("package P.p.P. "), CheckPackage$Literals::CHECK_CATALOG, IssueCodes::INVALID_PACKAGE_NAME) - helper.assertError(parser.parse("package P.package.P. "), CheckPackage$Literals::CHECK_CATALOG, IssueCodes::INVALID_PACKAGE_NAME) - } - - /* Tests checkContextTypeIsUnique(Check) */ - @Test - @Disabled("Tests do not work because of scoping issues at run-time") - def void testContextTypeIsUnique() { - // should fail - var contexts = Lists::newArrayList("for C c {issue}", "for C d {issue}") - var model = parser.parse(modelUtil.modelWithContexts(contexts)) - helper.assertError(model, CheckPackage$Literals::CONTEXT, IssueCodes::CONTEXT_TYPES_NOT_UNIQUE) - - // should fail - contexts = Lists::newArrayList("for C c {issue}", "for D d {issue}", "for C e {issue}") - model = parser.parse(modelUtil.modelWithContexts(contexts)) - helper.assertError(model, CheckPackage$Literals::CONTEXT, IssueCodes::CONTEXT_TYPES_NOT_UNIQUE) - - // should not fail - contexts = Lists::newArrayList("for org.eclipse.emf.ecore.EObject e {issue}", "for E e {issue}") - model = parser.parse(modelUtil.modelWithContexts(contexts)) - helper.assertNoError(model, IssueCodes::CONTEXT_TYPES_NOT_UNIQUE) - } - - /* Tests checkGuardsFirstInBlockExpression(Context) */ - @Test - def void testGuardsPrecedeIssues() { - // basic case: should not fail - var model = parser.parse(modelUtil.modelWithContext + "guard(false) issue") - helper.assertNoError(model, IssueCodes::GUARDS_COME_FIRST) - - // multiple guards: should not fail - model = parser.parse(modelUtil.modelWithContext + "guard(false) guard(true) if(false) {null} issue") - helper.assertNoError(model, IssueCodes::GUARDS_COME_FIRST) - - // should not fail - model = parser.parse(modelUtil.modelWithContext + "guard(false) val x = 1 var y = 2 issue") - helper.assertNoError(model, IssueCodes::GUARDS_COME_FIRST) - - // guard not first: should fail - model = parser.parse(modelUtil.modelWithContext + "issue guard(false)") - helper.assertError(model, CheckPackage$Literals::XGUARD_EXPRESSION, IssueCodes::GUARDS_COME_FIRST) - - // should fail - model = parser.parse(modelUtil.modelWithContext + "guard(true) issue guard(false)") - helper.assertError(model, CheckPackage$Literals::XGUARD_EXPRESSION, IssueCodes::GUARDS_COME_FIRST) - - // should fail - model = parser.parse(modelUtil.modelWithContext + "guard(true) if(true){issue} guard(true)") - helper.assertError(model, CheckPackage$Literals::XGUARD_EXPRESSION, IssueCodes::GUARDS_COME_FIRST) - } - - /* Tests org.eclipse.xtext.xbase.validation.EarlyExitValidator.checkDeadCode(XBlockExpression) */ - @Test - def void testDeadCode() { - // should not fail - var model = parser.parse(modelUtil.modelWithContext + "issue") - helper.assertNoError(model, IssueCodes::DEAD_CODE) - - // should fail - model = parser.parse(modelUtil.modelWithContext + "if(false) {return} else {return} issue") - helper.assertError(model, XbasePackage$Literals::XEXPRESSION, org::eclipse::xtext::xbase::validation::IssueCodes::UNREACHABLE_CODE) - } - - - - /* Tests checkIssueExpressionExists(Context) */ - @Test - def void testIssueExpressionExists() { - var model = parser.parse(modelUtil.modelWithContext + "guard(false)") - helper.assertError(model, CheckPackage$Literals::CONTEXT, IssueCodes::MISSING_ISSUE_EXPRESSION) - - // should not fail - model = parser.parse(modelUtil.modelWithContext + "if (false) { null } else { issue") - helper.assertNoError(model, IssueCodes::MISSING_ISSUE_EXPRESSION) - - // should fail - model = parser.parse(modelUtil.modelWithContext + "if (false) { null } else { null } ") - helper.assertError(model, CheckPackage$Literals::CONTEXT, IssueCodes::MISSING_ISSUE_EXPRESSION) - - // should not fail - model = parser.parse(modelUtil.modelWithContext + "if (false) { null } else { null } issue") - helper.assertNoError(model, IssueCodes::MISSING_ISSUE_EXPRESSION) - - // should not fail - model = parser.parse(modelUtil.modelWithContext + "if (false) { issue ") - helper.assertNoError(model, IssueCodes::MISSING_ISSUE_EXPRESSION) - } - - /* Test checkCheckName(Check). ID is missing. */ - @Test - def void testCheckIDIsMissing() { - val model = parser.parse(modelUtil.modelWithCheck("")) - helper.assertError(model, CheckPackage$Literals::CHECK, IssueCodes::MISSING_ID_ON_CHECK) - helper.assertNoErrors(model, CheckPackage$Literals::CHECK, IssueCodes::INVALID_CHECK_NAME) - helper.assertNoWarnings(model, CheckPackage$Literals::CHECK, IssueCodes::INVALID_CHECK_NAME) - } - - /* Test checkCheckName(Check). ID is valid. */ - @Test - def void testCheckIDIsValid() { - val model = parser.parse(modelUtil.modelWithCheck("ID")) - helper.assertNoErrors(model, CheckPackage$Literals::CHECK, IssueCodes::MISSING_ID_ON_CHECK) - helper.assertNoErrors(model, CheckPackage$Literals::CHECK, IssueCodes::INVALID_CHECK_NAME) - helper.assertNoWarnings(model, CheckPackage$Literals::CHECK, IssueCodes::INVALID_CHECK_NAME) - } - - // Cannot test with an invalid ID because that would cause a syntax error. - // But CheckJavaValidatorUtilTest.checkNameIsInvalid() tests the relevant logic in CheckJavaValidatorUtil.checkCheckName(String). - - /* Test checkCheckName(Check). ID is discouraged. */ - @Test - def void testCheckIDIsDiscouraged() { - val model = parser.parse(modelUtil.modelWithCheck("iD")) - helper.assertNoErrors(model, CheckPackage$Literals::CHECK, IssueCodes::MISSING_ID_ON_CHECK) - helper.assertNoErrors(model, CheckPackage$Literals::CHECK, IssueCodes::INVALID_CHECK_NAME) - helper.assertWarning(model, CheckPackage$Literals::CHECK, IssueCodes::INVALID_CHECK_NAME) - } - - /* Test checkCheckNamesAreUnique(CheckCatalog). IDs are unique. */ - @Test - def void testCheckIDsAreUnique() { - val model = parser.parse(modelUtil.modelWithCategory + modelUtil.emptyCheck("ID1") + modelUtil.emptyCheck("ID2")) - helper.assertNoErrors(model, CheckPackage$Literals::CHECK, IssueCodes::DUPLICATE_CHECK) - } - - /* Test checkCheckNamesAreUnique(CheckCatalog). IDs are not unique. */ - @Test - def void testCheckIDsAreNotUnique() { - val model = parser.parse(modelUtil.modelWithCategory + modelUtil.emptyCheck("ID1") + modelUtil.emptyCheck("ID1")) - helper.assertError(model, CheckPackage$Literals::CHECK, IssueCodes::DUPLICATE_CHECK) - } - - /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are unique. */ - @Test - def void testCategoryIDsAreUnique() { - val model = parser.parse(modelUtil.modelWithGrammar + modelUtil.emptyCategory("ID1", "Label") + modelUtil.emptyCategory("ID2", "Label")) - helper.assertNoErrors(model, CheckPackage$Literals::CATEGORY, IssueCodes::DUPLICATE_CATEGORY) - } - - /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are not unique. */ - @Test - def void testCategoryIDsAreNotUnique() { - val model = parser.parse(modelUtil.modelWithCategory + modelUtil.emptyCategory("ID1", "Label") + modelUtil.emptyCategory("ID1", "Label")) - helper.assertError(model, CheckPackage$Literals::CATEGORY, IssueCodes::DUPLICATE_CATEGORY) - } - - /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are not present; labels are unique. */ - @Test - def void testCategoryLabelsAreUnique() { - val model = parser.parse(modelUtil.modelWithGrammar + modelUtil.emptyCategory("", "Label1") + modelUtil.emptyCategory("", "Label2")) - helper.assertNoErrors(model, CheckPackage$Literals::CATEGORY, IssueCodes::DUPLICATE_CATEGORY) - } - - /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are not present; labels are not unique. */ - @Test - def void testCategoryLabelsAreNotUnique() { - val model = parser.parse(modelUtil.modelWithGrammar + modelUtil.emptyCategory("", "Label1") + modelUtil.emptyCategory("", "Label1")) - helper.assertError(model, CheckPackage$Literals::CATEGORY, IssueCodes::DUPLICATE_CATEGORY) - } - - /* Test checkCategoryNamesAreUnique(CheckCatalog). IDs are not present; labels are unique but create non-unique names. */ - @Test - def void testCategoryLabelsAreNotUniqueOnceConverted() { - val model = parser.parse(modelUtil.modelWithGrammar + modelUtil.emptyCategory("", "LabelOne") + modelUtil.emptyCategory("", "Label one")) - helper.assertError(model, CheckPackage$Literals::CATEGORY, IssueCodes::DUPLICATE_CATEGORY) - } - - /* Tests checkSeverityRangeOrder(Check) */ - @Test - def void testSeverityRangeOrder_1() { - helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange('warning', 'error')), - IssueCodes::ILLEGAL_SEVERITY_RANGE_ORDER - ) - } - - /* Tests checkSeverityRangeOrder(Check) */ - @Test - def void testSeverityRangeOrder_2() { - helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange('ignore', 'warning')), - IssueCodes::ILLEGAL_SEVERITY_RANGE_ORDER - ) - } - - /* Tests checkSeverityRangeOrder(Check) */ - @Test - def void testSeverityRangeOrder_3() { - helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange('info', 'info')), - IssueCodes::ILLEGAL_SEVERITY_RANGE_ORDER - ) - } - - /* Tests checkSeverityRangeOrder(Check) */ - @Test - def void testSeverityRangeOrder_4() { - helper.assertError(parser.parse(modelUtil.modelWithSeverityRange('info', 'ignore')), - CheckPackage$Literals::SEVERITY_RANGE, IssueCodes::ILLEGAL_SEVERITY_RANGE_ORDER - ) - } - - /* Tests checkSeverityRangeOrder(Check) */ - @Test - def void testSeverityRangeOrder_5() { - helper.assertError(parser.parse(modelUtil.modelWithSeverityRange('error', 'info')), - CheckPackage$Literals::SEVERITY_RANGE, IssueCodes::ILLEGAL_SEVERITY_RANGE_ORDER - ) - } - - /* Tests checkDefaultSeverityInRange(Check) */ - @Test - def void testDefaultSeverityInRange_1() { - helper.assertError(parser.parse(modelUtil.modelWithSeverityRange('warning', 'error', 'info')), - CheckPackage$Literals::CHECK, IssueCodes::DEFAULT_SEVERITY_NOT_IN_RANGE - ) - } - - /* Tests checkDefaultSeverityInRange(Check) */ - @Test - def void testDefaultSeverityInRange_2() { - helper.assertError(parser.parse(modelUtil.modelWithSeverityRange('error', 'info', 'ignore')), - CheckPackage$Literals::CHECK, IssueCodes::DEFAULT_SEVERITY_NOT_IN_RANGE - ) - } - - /* Tests checkDefaultSeverityInRange(Check) */ - @Test - def void testDefaultSeverityInRange_3() { - helper.assertError(parser.parse(modelUtil.modelWithSeverityRange('error', 'error', 'ignore')), - CheckPackage$Literals::CHECK, IssueCodes::DEFAULT_SEVERITY_NOT_IN_RANGE - ) - } - - /* Tests checkDefaultSeverityInRange(Check) */ - @Test - def void testDefaultSeverityInRange_4() { - helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange('error', 'error', 'error')), - IssueCodes::DEFAULT_SEVERITY_NOT_IN_RANGE - ) - } - - /* Tests checkDefaultSeverityInRange(Check) */ - @Test - def void testDefaultSeverityInRange_5() { - helper.assertNoError(parser.parse(modelUtil.modelWithSeverityRange('info', 'error', 'warning')), - IssueCodes::DEFAULT_SEVERITY_NOT_IN_RANGE - ) - } - -} diff --git a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java new file mode 100644 index 0000000000..d0c9fbf31c --- /dev/null +++ b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java @@ -0,0 +1,240 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.ui.test.quickfix; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Collection; +import java.util.List; + +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; +import org.eclipse.swtbot.swt.finder.widgets.TimeoutException; +import org.eclipse.xtext.diagnostics.Diagnostic; +import org.eclipse.xtext.validation.Issue; +import org.junit.jupiter.api.Test; + +import com.avaloq.tools.ddk.check.ui.quickfix.Messages; +import com.avaloq.tools.ddk.check.validation.IssueCodes; +import com.avaloq.tools.ddk.test.core.Retry; +import com.avaloq.tools.ddk.test.core.jupiter.BugTest; +import com.avaloq.tools.ddk.test.ui.swtbot.SwtWorkbenchBot; +import com.avaloq.tools.ddk.test.ui.swtbot.condition.WaitForEquals; +import com.avaloq.tools.ddk.test.ui.swtbot.util.ProblemsViewTestUtil; +import com.avaloq.tools.ddk.xtext.test.TestSource; +import com.avaloq.tools.ddk.xtext.test.XtextTestSource; + + +/** + * Test quickfixes for Check files. + */ +@SuppressWarnings("nls") +public class CheckQuickfixTest extends AbstractCheckQuickfixTest { + + private static final String PACKAGE_NAME = "com.avaloq.test"; + + private final SwtWorkbenchBot bot = new SwtWorkbenchBot(); + private boolean oldAutoBuildState; + + public String getTestSourceFileName(final String catalogName) { + StringBuilder builder = new StringBuilder(); + builder.append(PACKAGE_NAME.replace(".", "/")); + builder.append("/"); + builder.append(catalogName); + builder.append("."); + builder.append(getXtextTestUtil().getFileExtension()); + return builder.toString(); + } + + @Override + protected String getTestSourceFileName() { + return getTestSourceFileName(getTestSourceModelName()); + } + + @Override + protected void registerRequiredSources() { + } + + @Override + protected XtextTestSource getTestSource() { + return null; + } + + @Override + protected void beforeEachTest() { + super.beforeEachTest(); + oldAutoBuildState = getTestProjectManager().setAutobuild(true); + cleanUp(); + } + + @Override + protected void afterEachTest() { + getTestProjectManager().setAutobuild(oldAutoBuildState); + cleanUp(); + super.afterEachTest(); + } + + /** + * Close all shells and editors and remove all sources. + */ + private void cleanUp() { + bot.closeAllShells(); + bot.closeAllEditors(); + Collection testSources = getTestProjectManager().getTestSources(); + for (final TestSource testSource : testSources) { + getTestProjectManager().removeTestSource(testSource); + } + } + + @Test + @BugTest(value = "DSL-244") + public void testImportFix() { + StringBuilder builder = new StringBuilder(); + builder.append("package "); + builder.append(PACKAGE_NAME); + builder.append("\n"); + builder.append("\n"); + builder.append("catalog "); + builder.append(getTestSourceModelName()); + builder.append(" for grammar org.eclipse.xtext.Xtext\n"); + builder.append("{\n"); + builder.append(" /** Missing import test */\n"); + builder.append(" warning TestWarning \"Test Warning\"\n"); + builder.append(" message \"This is a Test Warning\" {\n"); + builder.append(" for AbstractRule c {\n"); + builder.append(" issue\n"); + builder.append(" }\n"); + builder.append(" }\n"); + builder.append("}\n"); + createTestSource(getTestSourceFileName(), builder.toString()); + openEditor(getTestSourceFileName()); + final String quickfixLabel = "Import 'AbstractRule' (org.eclipse.xtext)"; + final List beforeIssues = getXtextTestUtil().getIssues(getDocument()); + assertHasQuickFix(Diagnostic.LINKING_DIAGNOSTIC, quickfixLabel); + assertQuickFixSuccessful(Diagnostic.LINKING_DIAGNOSTIC, quickfixLabel); + final List afterIssues = getXtextTestUtil().getIssues(getDocument()); + assertTrue(afterIssues.size() < beforeIssues.size()); + } + + /** + * Test the Add ID quickfix. + */ + @Test + public void testAddID() { + // ARRANGE + StringBuilder builder = new StringBuilder(); + builder.append("package "); + builder.append(PACKAGE_NAME); + builder.append("\n"); + builder.append("\n"); + builder.append("catalog "); + builder.append(getTestSourceModelName()); + builder.append("\n"); + builder.append("for grammar org.eclipse.xtext.Xtext {\n"); + builder.append("\n"); + builder.append(" warning \"Test Warning\"\n"); + builder.append(" message \"This is a Test Warning\" {\n"); + builder.append(" }\n"); + builder.append("}\n"); + final String sourceContent = builder.toString(); + + StringBuilder builder2 = new StringBuilder(); + builder2.append("package "); + builder2.append(PACKAGE_NAME); + builder2.append("\n"); + builder2.append("\n"); + builder2.append("catalog "); + builder2.append(getTestSourceModelName()); + builder2.append("\n"); + builder2.append("for grammar org.eclipse.xtext.Xtext {\n"); + builder2.append("\n"); + builder2.append(" warning TestWarning \"Test Warning\"\n"); + builder2.append(" message \"This is a Test Warning\" {\n"); + builder2.append(" }\n"); + builder2.append("}\n"); + final String expectedContent = builder2.toString(); + + // ACT and ASSERT + assertQuickFixExistsAndSuccessfulInCustomerSource(IssueCodes.MISSING_ID_ON_CHECK, + Messages.CheckQuickfixProvider_ADD_ID_LABEL, getTestSourceFileName(), sourceContent, expectedContent); + } + + /** + * Test bulk-applying a quickfix. + * Tolerate up to ten timeouts, because occasionally new markers don't appear or not all markers are fixed; + * the problems appears to be in Eclipse. + */ + @Test + @Retry(10) + public void testBulkApplyingQuickfix() { + // ARRANGE + final List catalogNames = List.of(getTestSourceModelName(), getTestSourceModelName() + "2"); + final List checkLabels = List.of("Check with no explicit ID", "Another check with no explicit ID"); + final int expectedMarkers = catalogNames.size() * checkLabels.size(); + + // Show all error markers + ProblemsViewTestUtil.showProblemsView(bot); + ProblemsViewTestUtil.showAllErrors(bot); + ProblemsViewTestUtil.groupByNone(bot); + + // Add catalogs containing multiple instances of the same quickfixable marker + for (final String catalogName : catalogNames) { + StringBuilder builder = new StringBuilder(); + builder.append("package "); + builder.append(PACKAGE_NAME); + builder.append("\n"); + builder.append("\n"); + builder.append("catalog "); + builder.append(catalogName); + builder.append("\n"); + builder.append("for grammar org.eclipse.xtext.Xtext {\n"); + for (final String checkLabel : checkLabels) { + builder.append("\n"); + builder.append(" live error \""); + builder.append(checkLabel); + builder.append("\"\n"); + builder.append(" message \""); + builder.append(checkLabel); + builder.append("\" {\n"); + builder.append(" }\n"); + } + builder.append("}\n"); + createTestSource(getTestSourceFileName(catalogName), builder.toString()); + } + + // Build the catalogs, and wait for the expected markers to appear + getTestProjectManager().build(); + final SWTBotTree markersTreeBot = ProblemsViewTestUtil.getMarkersTree(bot); + bot.waitUntil(new WaitForEquals<>("Not all expected markers appeared.", () -> expectedMarkers, () -> markersTreeBot.getAllItems().length)); + + // ACT + // Disable autobuilding, to avoid losing focus while selecting markers + getTestProjectManager().setAutobuild(false); + getTestProjectManager().build(); + + // Bulk-apply quickfixes on all markers, ensuring that all markers remain selected + ProblemsViewTestUtil.bulkApplyQuickfix(bot, Messages.CheckQuickfixProvider_ADD_ID_LABEL, markersTreeBot.getAllItems()); + bot.waitUntil(new WaitForEquals<>("Not all markers are still selected.", () -> expectedMarkers, () -> markersTreeBot.selectionCount())); + + // Save all modified files and build the catalogs + bot.editors().forEach(editor -> editor.save()); + getTestProjectManager().setAutobuild(true); + getTestProjectManager().build(); + + // ASSERT + // Check that all markers are fixed + try { + bot.waitUntil(new WaitForEquals<>("Some markers were not quickfixed.", () -> 0, () -> markersTreeBot.getAllItems().length)); + } catch (TimeoutException exception) { + fail(exception.getMessage()); + } + } +} diff --git a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.xtend b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.xtend deleted file mode 100644 index af5a67e390..0000000000 --- a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.xtend +++ /dev/null @@ -1,200 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.check.ui.test.quickfix - -import com.avaloq.tools.ddk.check.ui.quickfix.Messages -import com.avaloq.tools.ddk.check.validation.IssueCodes -import com.avaloq.tools.ddk.test.core.jupiter.BugTest -import com.avaloq.tools.ddk.test.core.Retry -import com.avaloq.tools.ddk.test.ui.swtbot.SwtWorkbenchBot -import com.avaloq.tools.ddk.test.ui.swtbot.condition.WaitForEquals -import com.avaloq.tools.ddk.test.ui.swtbot.util.ProblemsViewTestUtil -import org.eclipse.swtbot.swt.finder.widgets.TimeoutException -import org.eclipse.xtext.diagnostics.Diagnostic -import org.junit.jupiter.api.Test -import static org.junit.jupiter.api.Assertions.assertTrue -import static org.junit.jupiter.api.Assertions.fail - -/** - * Test quickfixes for Check files. - */ -class CheckQuickfixTest extends AbstractCheckQuickfixTest { - - static val PACKAGE_NAME = "com.avaloq.test" - - val SwtWorkbenchBot bot = new SwtWorkbenchBot - var boolean oldAutoBuildState - - def String getTestSourceFileName(String catalogName) { - return '''«PACKAGE_NAME.replace(".", "/")»/«catalogName».«xtextTestUtil.getFileExtension»''' - } - - override protected getTestSourceFileName() { - return getTestSourceFileName(testSourceModelName) - } - - override protected registerRequiredSources() { - } - - override protected getTestSource() { - return null - } - - override protected beforeEachTest() { - super.beforeEachTest - oldAutoBuildState = testProjectManager.setAutobuild(true) - cleanUp - } - - override protected afterEachTest() { - testProjectManager.autobuild = oldAutoBuildState - cleanUp - super.afterEachTest - } - - /** - * Close all shells and editors and remove all sources. - */ - def private void cleanUp() { - bot.closeAllShells - bot.closeAllEditors - for (testSource : testProjectManager.testSources) { - testProjectManager.removeTestSource(testSource) - } - } - - @Test - @BugTest(value="DSL-244") - def testImportFix() { - createTestSource(testSourceFileName, ''' - package «PACKAGE_NAME» - - catalog «testSourceModelName» for grammar org.eclipse.xtext.Xtext - { - /** Missing import test */ - warning TestWarning "Test Warning" - message "This is a Test Warning" { - for AbstractRule c { - issue - } - } - } - ''') - openEditor(testSourceFileName) - val quickfixLabel = "Import 'AbstractRule' (org.eclipse.xtext)" - val beforeIssues = getXtextTestUtil().getIssues(getDocument()); - assertHasQuickFix(Diagnostic::LINKING_DIAGNOSTIC, quickfixLabel); - assertQuickFixSuccessful(Diagnostic::LINKING_DIAGNOSTIC, quickfixLabel); - val afterIssues = getXtextTestUtil().getIssues(getDocument()); - assertTrue(afterIssues.size < beforeIssues.size); - } - - /** - * Test the Add ID quickfix. - */ - @Test - def testAddID() { - - // ARRANGE - val sourceContent = ''' - package «PACKAGE_NAME» - - catalog «testSourceModelName» - for grammar org.eclipse.xtext.Xtext { - - warning "Test Warning" - message "This is a Test Warning" { - } - } - ''' - val expectedContent = ''' - package «PACKAGE_NAME» - - catalog «testSourceModelName» - for grammar org.eclipse.xtext.Xtext { - - warning TestWarning "Test Warning" - message "This is a Test Warning" { - } - } - ''' - - // ACT and ASSERT - assertQuickFixExistsAndSuccessfulInCustomerSource(IssueCodes::MISSING_ID_ON_CHECK, - Messages.CheckQuickfixProvider_ADD_ID_LABEL, testSourceFileName, sourceContent, expectedContent) - } - - /** - * Test bulk-applying a quickfix. - * Tolerate up to ten timeouts, because occasionally new markers don't appear or not all markers are fixed; - * the problems appears to be in Eclipse. - */ - @Test - @Retry(10) - def void testBulkApplyingQuickfix() { - - // ARRANGE - val catalogNames = #[testSourceModelName, testSourceModelName + "2"] - val checkLabels = #["Check with no explicit ID", "Another check with no explicit ID"] - val expectedMarkers = catalogNames.length * checkLabels.length - - // Show all error markers - ProblemsViewTestUtil.showProblemsView(bot) - ProblemsViewTestUtil.showAllErrors(bot) - ProblemsViewTestUtil.groupByNone(bot) - - // Add catalogs containing multiple instances of the same quickfixable marker - for (catalogName : catalogNames) { - createTestSource(getTestSourceFileName(catalogName), ''' - package «PACKAGE_NAME» - - catalog «catalogName» - for grammar org.eclipse.xtext.Xtext { - «FOR checkLabel : checkLabels» - - live error "«checkLabel»" - message "«checkLabel»" { - } - «ENDFOR» - } - ''') - } - - // Build the catalogs, and wait for the expected markers to appear - testProjectManager.build - val markersTreeBot = ProblemsViewTestUtil.getMarkersTree(bot) - bot.waitUntil(new WaitForEquals("Not all expected markers appeared.", [expectedMarkers], [markersTreeBot.allItems.length])) - - // ACT - // Disable autobuilding, to avoid losing focus while selecting markers - testProjectManager.autobuild = false - testProjectManager.build - - // Bulk-apply quickfixes on all markers, ensuring that all markers remain selected - ProblemsViewTestUtil.bulkApplyQuickfix(bot, Messages.CheckQuickfixProvider_ADD_ID_LABEL, markersTreeBot.allItems) - bot.waitUntil(new WaitForEquals("Not all markers are still selected.", [expectedMarkers], [markersTreeBot.selectionCount])) - - // Save all modified files and build the catalogs - bot.editors.forEach[save] - testProjectManager.autobuild = true - testProjectManager.build - - // ASSERT - // Check that all markers are fixed - try { - bot.waitUntil(new WaitForEquals("Some markers were not quickfixed.", [0], [markersTreeBot.allItems.length])) - } catch (TimeoutException exception) { - fail(exception.message) - } - } - -} - diff --git a/docs/xtend-migration.md b/docs/xtend-migration.md index ddd229aec5..1b1af28f89 100644 --- a/docs/xtend-migration.md +++ b/docs/xtend-migration.md @@ -12,10 +12,10 @@ | Metric | Value | |--------|-------| | Total Xtend source files | 94 | -| Already migrated (Batch 1–8) | 89 | -| Remaining | 5 | -| Total remaining lines | ~1,295 | -| Modules with remaining Xtend | 2 | +| Already migrated (Batch 1–9) | 94 | +| Remaining | 0 | +| Total remaining lines | 0 | +| Modules with remaining Xtend | 0 | --- @@ -24,11 +24,11 @@ | Module | Files | Lines | Status | |--------|-------|-------|--------| | `check.core` | 8 | ~1,848 | **DONE** (Batch 1) | -| `check.core.test` | 11 | ~1,760 | 7 done (Batch 2–4), 4 pending | +| `check.core.test` | 11 | ~1,760 | **DONE** (Batch 2–4, 9) | | `check.test.runtime` | 1 | 22 | **DONE** (Batch 2) | | `check.test.runtime.tests` | 3 | 202 | **DONE** (Batch 3–4) | | `check.ui` | 2 | 113 | **DONE** (Batch 3) | -| `check.ui.test` | 1 | 200 | Pending | +| `check.ui.test` | 1 | 200 | **DONE** (Batch 9) | | `checkcfg.core` | 4 | 303 | **DONE** (Batch 2–4) | | `checkcfg.core.test` | 7 | 460 | **DONE** (Batch 2–4) | | `sample.helloworld.ui.test` | 3 | 203 | **DONE** (Batch 3–4) | @@ -262,16 +262,16 @@ The largest module. Includes ANTLR grammar generators — the hardest files in t --- -## Batch 9 — Remaining test files (5 files) +## Batch 9 — Remaining test files (5 files) — DONE ### `check.core.test` (4 files) -- [ ] `CheckModelUtil.xtend` — Utility class -- [ ] `IssueCodeToLabelMapGenerationTest.xtend` (130 lines) — Medium — templates, #[, switch -- [ ] `CheckValidationTest.xtend` (342 lines) — Hard — extension, typeof, create -- [ ] `CheckFormattingTest.xtend` (554 lines) — Very Hard — templates, extension, typeof, !==, ?. +- [x] `CheckModelUtil.xtend` (113 lines) — Medium — templates +- [x] `IssueCodeToLabelMapGenerationTest.xtend` (130 lines) — Medium — templates, #[, switch +- [x] `CheckValidationTest.xtend` (342 lines) — Hard — extension, typeof, create +- [x] `CheckFormattingTest.xtend` (554 lines) — Very Hard — templates, extension, typeof, !==, ?. ### `check.ui.test` (1 file) -- [ ] `CheckQuickfixTest.xtend` (200 lines) — Medium — templates, #[, override +- [x] `CheckQuickfixTest.xtend` (200 lines) — Medium — templates, #[, override --- From b37717673a14e4253d483ad35266fe1cd6791fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 09:11:16 +0100 Subject: [PATCH 11/23] chore: remove Xtend build infrastructure after migration Remove all xtend-gen references from .classpath, build.properties, pom.xml (xtend-maven-plugin, xtend.version property, PMD exclude, clean plugin fileset), PMD ruleset, Checkstyle config, and .gitignore. Remove org.eclipse.xtend.lib from MANIFEST.MF where no longer needed (kept in xtext.generator, check.core.test, sample.helloworld.ui, and xtext.test.core which still use xtend2.lib runtime classes or xtend.lib annotations). Remove migration section from AGENTS.md. Co-Authored-By: Claude Opus 4.6 --- .gitignore | 3 -- AGENTS.md | 54 ++----------------- .../.classpath | 5 -- .../build.properties | 1 - com.avaloq.tools.ddk.check.core/.classpath | 5 -- .../build.properties | 3 +- com.avaloq.tools.ddk.check.ide/.classpath | 5 -- .../build.properties | 3 +- .../.classpath | 5 -- .../META-INF/MANIFEST.MF | 1 - .../build.properties | 1 - .../.classpath | 5 -- .../build.properties | 3 +- com.avaloq.tools.ddk.check.ui.test/.classpath | 5 -- .../build.properties | 1 - com.avaloq.tools.ddk.check.ui/.classpath | 5 -- .../build.properties | 3 +- .../.classpath | 5 -- .../META-INF/MANIFEST.MF | 1 - .../build.properties | 3 +- com.avaloq.tools.ddk.checkcfg.core/.classpath | 5 -- .../build.properties | 3 +- com.avaloq.tools.ddk.checkcfg.ide/.classpath | 5 -- .../build.properties | 3 +- .../META-INF/MANIFEST.MF | 1 - .../.classpath | 1 - .../build.properties | 1 - .../META-INF/MANIFEST.MF | 4 +- .../META-INF/MANIFEST.MF | 1 - .../.classpath | 1 - .../build.properties | 1 - .../.classpath | 1 - .../build.properties | 1 - .../.classpath | 5 -- .../build.properties | 3 +- com.avaloq.tools.ddk.xtext.export/.classpath | 5 -- .../build.properties | 3 +- .../.classpath | 5 -- .../build.properties | 3 +- .../.classpath | 5 -- .../build.properties | 3 +- .../.classpath | 1 - .../build.properties | 3 +- .../.classpath | 1 - .../build.properties | 3 +- .../.classpath | 1 - .../build.properties | 3 +- .../.classpath | 1 - .../META-INF/MANIFEST.MF | 3 +- .../build.properties | 3 +- com.avaloq.tools.ddk.xtext.format/.classpath | 5 -- .../META-INF/MANIFEST.MF | 1 - .../build.properties | 3 +- .../.classpath | 1 - .../build.properties | 1 - .../.classpath | 5 -- .../build.properties | 1 - .../.classpath | 1 - .../build.properties | 1 - .../.classpath | 5 -- .../build.properties | 3 +- com.avaloq.tools.ddk.xtext.scope/.classpath | 5 -- .../build.properties | 3 +- .../.classpath | 5 -- .../META-INF/MANIFEST.MF | 4 +- .../build.properties | 3 +- com.avaloq.tools.ddk.xtext.ui.test/.classpath | 1 - .../build.properties | 1 - com.avaloq.tools.ddk.xtext.ui/.classpath | 1 - .../build.properties | 3 +- .../.classpath | 5 -- .../build.properties | 3 +- ddk-configuration/.checkstyle | 1 - ddk-configuration/pmd/ruleset.xml | 1 - ddk-parent/pom.xml | 29 ---------- 75 files changed, 29 insertions(+), 259 deletions(-) diff --git a/.gitignore b/.gitignore index c561386df8..27d089948c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,3 @@ *.java._trace *.smap *.checkbin -*.xtendbin -/*/xtend-gen/* -!/*/xtend-gen/.gitignore diff --git a/AGENTS.md b/AGENTS.md index 86a8aded36..155faed195 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,7 @@ This document helps AI coding agents work effectively with the DSL DevKit codeba - **Java**: 21+ - **Maven**: 3.9+ - **Tycho** -- **Xtext/Xtend** +- **Xtext** ## Key Directories @@ -50,7 +50,7 @@ export WORKSPACE=$(pwd) ### PMD - **Ruleset**: `ddk-configuration/pmd/ruleset.xml` -- Excludes: `src-gen/`, `src-model/`, `xtend-gen/` +- Excludes: `src-gen/`, `src-model/` ### Checkstyle - **Config**: `ddk-configuration/checkstyle/avaloq.xml` @@ -79,10 +79,6 @@ Tests are disabled by default and activated only in test bundles. These directories contain generated code - do not edit manually: - `src-gen/` - Xtext generated sources - `src-model/` - EMF model generated sources -- `xtend-gen/` - Xtend transpiled Java sources - -### Xtend -- `.xtend` files in `src/` compile to Java in `xtend-gen/` ## Common Tasks @@ -95,7 +91,7 @@ These directories contain generated code - do not edit manually: ### Fixing PMD Violations 1. Check ruleset at `ddk-configuration/pmd/ruleset.xml` -2. Violations in generated code (`src-gen/`, `xtend-gen/`) are excluded +2. Violations in generated code (`src-gen/`) are excluded 3. Run `mvn pmd:check -f ./ddk-parent/pom.xml` to verify fixes ### Fixing Checkstyle Violations @@ -117,47 +113,3 @@ xvfb-run mvn verify -f ./ddk-parent/pom.xml -pl :com.avaloq.tools.ddk.xtext.test - **Workflow**: `.github/workflows/verify.yml` - Triggers on: push to master, pull requests ---- - -## Xtend-to-Java Migration (feature/xtend-to-java-migration branch) - -> **TEMPORARY SECTION** — Remove this section and `docs/xtend-to-java-conversion-prompt.md` after the migration branch is merged to master. Check on every push. - -### Overview - -We are migrating all ~94 Xtend source files to idiomatic Java 21. Batch 1 (8 files in `check.core`) is complete. The remaining 86 files are tracked in [`docs/xtend-migration.md`](docs/xtend-migration.md). - -### Key References - -| Document | Purpose | -|----------|---------| -| [`docs/xtend-migration.md`](docs/xtend-migration.md) | Master checklist — per-file status, batch order, build cleanup tasks | -| [`docs/xtend-to-java-conversion-prompt.md`](docs/xtend-to-java-conversion-prompt.md) | Full conversion prompt with 18 sections of rules, checklist, and worked example | - -### Migration Conventions - -- **Java 21** target — use pattern matching, switch expressions where appropriate -- **`StringBuilder`** for Xtend template expressions (no Xtend runtime dependency) -- **No `var` keyword** — always use explicit types (`final ExplicitType`, not `final var`) -- **2-space indentation** to match project convention -- Preserve all comments, copyright headers, and method ordering - -### Per-File Conversion Workflow - -1. Read the `.xtend` source file -2. Read the corresponding `xtend-gen/*.java` file as reference -3. Apply the conversion prompt rules from `docs/xtend-to-java-conversion-prompt.md` -4. Write the `.java` file to `src/` (same package path as the `.xtend` file) -5. Delete the `.xtend` file -6. Delete the `xtend-gen/*.java` file -7. Update the checklist in `docs/xtend-migration.md` - -### Verification After Each Batch - -```bash -# Must pass -mvn clean compile -f ./ddk-parent/pom.xml --batch-mode - -# Must pass (except known macOS UI test) -mvn clean verify -f ./ddk-parent/pom.xml --batch-mode --fail-at-end -``` diff --git a/com.avaloq.tools.ddk.check.core.test/.classpath b/com.avaloq.tools.ddk.check.core.test/.classpath index 3450ddaac1..325c9ddddf 100644 --- a/com.avaloq.tools.ddk.check.core.test/.classpath +++ b/com.avaloq.tools.ddk.check.core.test/.classpath @@ -15,11 +15,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.check.core.test/build.properties b/com.avaloq.tools.ddk.check.core.test/build.properties index dacebd4595..6013dbdcc5 100644 --- a/com.avaloq.tools.ddk.check.core.test/build.properties +++ b/com.avaloq.tools.ddk.check.core.test/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ src-gen/,\ - xtend-gen/,\ resource/ output.. = bin/ bin.includes = META-INF/,\ diff --git a/com.avaloq.tools.ddk.check.core/.classpath b/com.avaloq.tools.ddk.check.core/.classpath index 0c82b24373..e7a6322800 100644 --- a/com.avaloq.tools.ddk.check.core/.classpath +++ b/com.avaloq.tools.ddk.check.core/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.check.core/build.properties b/com.avaloq.tools.ddk.check.core/build.properties index 5839f7a848..b533d62244 100644 --- a/com.avaloq.tools.ddk.check.core/build.properties +++ b/com.avaloq.tools.ddk.check.core/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ .,\ plugin.xml,\ diff --git a/com.avaloq.tools.ddk.check.ide/.classpath b/com.avaloq.tools.ddk.check.ide/.classpath index 5a4d66ff35..f7054419e4 100644 --- a/com.avaloq.tools.ddk.check.ide/.classpath +++ b/com.avaloq.tools.ddk.check.ide/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.check.ide/build.properties b/com.avaloq.tools.ddk.check.ide/build.properties index 3f5513de7b..2d6ac57da2 100644 --- a/com.avaloq.tools.ddk.check.ide/build.properties +++ b/com.avaloq.tools.ddk.check.ide/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/.classpath b/com.avaloq.tools.ddk.check.test.runtime.tests/.classpath index 1b454394ec..405761e5aa 100644 --- a/com.avaloq.tools.ddk.check.test.runtime.tests/.classpath +++ b/com.avaloq.tools.ddk.check.test.runtime.tests/.classpath @@ -1,11 +1,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.check.test.runtime.tests/META-INF/MANIFEST.MF index 9e7400160b..948c5612e3 100644 --- a/com.avaloq.tools.ddk.check.test.runtime.tests/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.check.test.runtime.tests/META-INF/MANIFEST.MF @@ -15,7 +15,6 @@ Require-Bundle: com.avaloq.tools.ddk.check.runtime.core, org.eclipse.xtext.testing, org.eclipse.xtext.ui.testing, org.eclipse.ui.workbench;resolution:=optional, - org.eclipse.xtend.lib, org.eclipse.xtext.xbase.lib, junit-jupiter-api, junit-jupiter-engine, diff --git a/com.avaloq.tools.ddk.check.test.runtime.tests/build.properties b/com.avaloq.tools.ddk.check.test.runtime.tests/build.properties index 57a52eb790..2ae3772a83 100644 --- a/com.avaloq.tools.ddk.check.test.runtime.tests/build.properties +++ b/com.avaloq.tools.ddk.check.test.runtime.tests/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - xtend-gen/,\ resource/ output.. = bin/ bin.includes = META-INF/,\ diff --git a/com.avaloq.tools.ddk.check.test.runtime/.classpath b/com.avaloq.tools.ddk.check.test.runtime/.classpath index fc183f78b3..2de44c4bb9 100644 --- a/com.avaloq.tools.ddk.check.test.runtime/.classpath +++ b/com.avaloq.tools.ddk.check.test.runtime/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.check.test.runtime/build.properties b/com.avaloq.tools.ddk.check.test.runtime/build.properties index 31255ed05b..e10dcceb6a 100644 --- a/com.avaloq.tools.ddk.check.test.runtime/build.properties +++ b/com.avaloq.tools.ddk.check.test.runtime/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ .,\ plugin.xml \ No newline at end of file diff --git a/com.avaloq.tools.ddk.check.ui.test/.classpath b/com.avaloq.tools.ddk.check.ui.test/.classpath index aa502e196b..1ad2437b6e 100644 --- a/com.avaloq.tools.ddk.check.ui.test/.classpath +++ b/com.avaloq.tools.ddk.check.ui.test/.classpath @@ -1,11 +1,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.check.ui.test/build.properties b/com.avaloq.tools.ddk.check.ui.test/build.properties index d6c49e5cf1..6b7927735f 100644 --- a/com.avaloq.tools.ddk.check.ui.test/build.properties +++ b/com.avaloq.tools.ddk.check.ui.test/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - xtend-gen/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.check.ui/.classpath b/com.avaloq.tools.ddk.check.ui/.classpath index 5a4d66ff35..f7054419e4 100644 --- a/com.avaloq.tools.ddk.check.ui/.classpath +++ b/com.avaloq.tools.ddk.check.ui/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.check.ui/build.properties b/com.avaloq.tools.ddk.check.ui/build.properties index 45000ac928..08ea14410f 100644 --- a/com.avaloq.tools.ddk.check.ui/build.properties +++ b/com.avaloq.tools.ddk.check.ui/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ icons/,\ .,\ diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/.classpath b/com.avaloq.tools.ddk.checkcfg.core.test/.classpath index fa768afab7..5540ec29d4 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/.classpath +++ b/com.avaloq.tools.ddk.checkcfg.core.test/.classpath @@ -1,11 +1,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.checkcfg.core.test/META-INF/MANIFEST.MF index 4ecadbacf3..dca624e42d 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.checkcfg.core.test/META-INF/MANIFEST.MF @@ -16,7 +16,6 @@ Require-Bundle: com.avaloq.tools.ddk.test.core, org.eclipse.ui, org.eclipse.ui.ide, org.eclipse.core.runtime, - org.eclipse.xtend.lib, org.eclipse.xtext.ui.testing, org.eclipse.xtext.xbase.lib, org.eclipse.ui.workbench;resolution:=optional, diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/build.properties b/com.avaloq.tools.ddk.checkcfg.core.test/build.properties index d8e2f0e92e..34d2e4d2da 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/build.properties +++ b/com.avaloq.tools.ddk.checkcfg.core.test/build.properties @@ -1,5 +1,4 @@ -source.. = src/,\ - xtend-gen/ +source.. = src/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.checkcfg.core/.classpath b/com.avaloq.tools.ddk.checkcfg.core/.classpath index 5a4d66ff35..f7054419e4 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/.classpath +++ b/com.avaloq.tools.ddk.checkcfg.core/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.checkcfg.core/build.properties b/com.avaloq.tools.ddk.checkcfg.core/build.properties index 7838757824..d69df83aa0 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/build.properties +++ b/com.avaloq.tools.ddk.checkcfg.core/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ .,\ plugin.xml,\ diff --git a/com.avaloq.tools.ddk.checkcfg.ide/.classpath b/com.avaloq.tools.ddk.checkcfg.ide/.classpath index 5a4d66ff35..f7054419e4 100644 --- a/com.avaloq.tools.ddk.checkcfg.ide/.classpath +++ b/com.avaloq.tools.ddk.checkcfg.ide/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.checkcfg.ide/build.properties b/com.avaloq.tools.ddk.checkcfg.ide/build.properties index 3f5513de7b..2d6ac57da2 100644 --- a/com.avaloq.tools.ddk.checkcfg.ide/build.properties +++ b/com.avaloq.tools.ddk.checkcfg.ide/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.sample.helloworld.ide/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.sample.helloworld.ide/META-INF/MANIFEST.MF index 8aff8f3e7b..a85b00c70b 100644 --- a/com.avaloq.tools.ddk.sample.helloworld.ide/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.sample.helloworld.ide/META-INF/MANIFEST.MF @@ -10,7 +10,6 @@ Require-Bundle: com.avaloq.tools.ddk.sample.helloworld, org.eclipse.compare, org.eclipse.xtext.builder, org.eclipse.xtext.xbase.lib, - org.eclipse.xtend.lib;resolution:=optional, org.antlr.runtime, com.avaloq.tools.ddk.check.runtime.core, com.google.inject, diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui.test/.classpath b/com.avaloq.tools.ddk.sample.helloworld.ui.test/.classpath index 7b1ace8da9..8a7d45dab6 100644 --- a/com.avaloq.tools.ddk.sample.helloworld.ui.test/.classpath +++ b/com.avaloq.tools.ddk.sample.helloworld.ui.test/.classpath @@ -2,7 +2,6 @@ - diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui.test/build.properties b/com.avaloq.tools.ddk.sample.helloworld.ui.test/build.properties index 877df0f1d3..9d45ce6c63 100644 --- a/com.avaloq.tools.ddk.sample.helloworld.ui.test/build.properties +++ b/com.avaloq.tools.ddk.sample.helloworld.ui.test/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ src-gen/,\ - xtend-gen/,\ resource/ bin.includes = .,\ META-INF/ diff --git a/com.avaloq.tools.ddk.sample.helloworld.ui/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.sample.helloworld.ui/META-INF/MANIFEST.MF index 3cae5086d0..ad0143052f 100644 --- a/com.avaloq.tools.ddk.sample.helloworld.ui/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.sample.helloworld.ui/META-INF/MANIFEST.MF @@ -16,12 +16,12 @@ Require-Bundle: com.avaloq.tools.ddk.sample.helloworld, org.eclipse.compare, org.eclipse.xtext.builder, org.eclipse.xtext.xbase.lib, - org.eclipse.xtend.lib;resolution:=optional, org.antlr.runtime, com.avaloq.tools.ddk.check.runtime.core, com.avaloq.tools.ddk.xtext.ui, com.avaloq.tools.ddk.sample.helloworld.ide, - com.avaloq.tools.ddk.xtext.ide + com.avaloq.tools.ddk.xtext.ide, + org.eclipse.xtend.lib Import-Package: org.apache.log4j Bundle-RequiredExecutionEnvironment: JavaSE-21 Export-Package: com.avaloq.tools.ddk.sample.helloworld.ui.quickfix, diff --git a/com.avaloq.tools.ddk.sample.helloworld/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.sample.helloworld/META-INF/MANIFEST.MF index 6e18a7cb62..fe6b985736 100644 --- a/com.avaloq.tools.ddk.sample.helloworld/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.sample.helloworld/META-INF/MANIFEST.MF @@ -15,7 +15,6 @@ Require-Bundle: org.eclipse.xtext, org.eclipse.xtext.util, org.eclipse.xtext.ide, org.eclipse.emf.common, - org.eclipse.xtend.lib, com.avaloq.tools.ddk.xtext, org.eclipse.emf.mwe2.launch;resolution:=optional, org.eclipse.core.runtime, diff --git a/com.avaloq.tools.ddk.xtext.check.generator/.classpath b/com.avaloq.tools.ddk.xtext.check.generator/.classpath index 26f051475d..a17f989fe8 100644 --- a/com.avaloq.tools.ddk.xtext.check.generator/.classpath +++ b/com.avaloq.tools.ddk.xtext.check.generator/.classpath @@ -1,7 +1,6 @@ - diff --git a/com.avaloq.tools.ddk.xtext.check.generator/build.properties b/com.avaloq.tools.ddk.xtext.check.generator/build.properties index 3820ac88f3..6b7927735f 100644 --- a/com.avaloq.tools.ddk.xtext.check.generator/build.properties +++ b/com.avaloq.tools.ddk.xtext.check.generator/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - xtend-gen/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.export.generator/.classpath b/com.avaloq.tools.ddk.xtext.export.generator/.classpath index 8d8d754076..eb603c114d 100644 --- a/com.avaloq.tools.ddk.xtext.export.generator/.classpath +++ b/com.avaloq.tools.ddk.xtext.export.generator/.classpath @@ -7,6 +7,5 @@ - diff --git a/com.avaloq.tools.ddk.xtext.export.generator/build.properties b/com.avaloq.tools.ddk.xtext.export.generator/build.properties index 3820ac88f3..6b7927735f 100644 --- a/com.avaloq.tools.ddk.xtext.export.generator/build.properties +++ b/com.avaloq.tools.ddk.xtext.export.generator/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - xtend-gen/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.export.ide/.classpath b/com.avaloq.tools.ddk.xtext.export.ide/.classpath index fc183f78b3..2de44c4bb9 100644 --- a/com.avaloq.tools.ddk.xtext.export.ide/.classpath +++ b/com.avaloq.tools.ddk.xtext.export.ide/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.export.ide/build.properties b/com.avaloq.tools.ddk.xtext.export.ide/build.properties index 3f5513de7b..2d6ac57da2 100644 --- a/com.avaloq.tools.ddk.xtext.export.ide/build.properties +++ b/com.avaloq.tools.ddk.xtext.export.ide/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.export/.classpath b/com.avaloq.tools.ddk.xtext.export/.classpath index fc183f78b3..2de44c4bb9 100644 --- a/com.avaloq.tools.ddk.xtext.export/.classpath +++ b/com.avaloq.tools.ddk.xtext.export/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.export/build.properties b/com.avaloq.tools.ddk.xtext.export/build.properties index 5839f7a848..b533d62244 100644 --- a/com.avaloq.tools.ddk.xtext.export/build.properties +++ b/com.avaloq.tools.ddk.xtext.export/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ .,\ plugin.xml,\ diff --git a/com.avaloq.tools.ddk.xtext.expression.ide/.classpath b/com.avaloq.tools.ddk.xtext.expression.ide/.classpath index fc183f78b3..2de44c4bb9 100644 --- a/com.avaloq.tools.ddk.xtext.expression.ide/.classpath +++ b/com.avaloq.tools.ddk.xtext.expression.ide/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.expression.ide/build.properties b/com.avaloq.tools.ddk.xtext.expression.ide/build.properties index 3f5513de7b..2d6ac57da2 100644 --- a/com.avaloq.tools.ddk.xtext.expression.ide/build.properties +++ b/com.avaloq.tools.ddk.xtext.expression.ide/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.expression/.classpath b/com.avaloq.tools.ddk.xtext.expression/.classpath index fc183f78b3..2de44c4bb9 100644 --- a/com.avaloq.tools.ddk.xtext.expression/.classpath +++ b/com.avaloq.tools.ddk.xtext.expression/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.expression/build.properties b/com.avaloq.tools.ddk.xtext.expression/build.properties index 5839f7a848..b533d62244 100644 --- a/com.avaloq.tools.ddk.xtext.expression/build.properties +++ b/com.avaloq.tools.ddk.xtext.expression/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ .,\ plugin.xml,\ diff --git a/com.avaloq.tools.ddk.xtext.format.generator/.classpath b/com.avaloq.tools.ddk.xtext.format.generator/.classpath index 8d8d754076..eb603c114d 100644 --- a/com.avaloq.tools.ddk.xtext.format.generator/.classpath +++ b/com.avaloq.tools.ddk.xtext.format.generator/.classpath @@ -7,6 +7,5 @@ - diff --git a/com.avaloq.tools.ddk.xtext.format.generator/build.properties b/com.avaloq.tools.ddk.xtext.format.generator/build.properties index 672bdf9170..b2adb6124f 100644 --- a/com.avaloq.tools.ddk.xtext.format.generator/build.properties +++ b/com.avaloq.tools.ddk.xtext.format.generator/build.properties @@ -1,5 +1,4 @@ -source.. = src/,\ - xtend-gen/ +source.. = src/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.format.ide/.classpath b/com.avaloq.tools.ddk.xtext.format.ide/.classpath index 66b4755301..dee17f20f7 100644 --- a/com.avaloq.tools.ddk.xtext.format.ide/.classpath +++ b/com.avaloq.tools.ddk.xtext.format.ide/.classpath @@ -7,7 +7,6 @@ - diff --git a/com.avaloq.tools.ddk.xtext.format.ide/build.properties b/com.avaloq.tools.ddk.xtext.format.ide/build.properties index bef28d3d93..ec65859a4c 100644 --- a/com.avaloq.tools.ddk.xtext.format.ide/build.properties +++ b/com.avaloq.tools.ddk.xtext.format.ide/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.format.test/.classpath b/com.avaloq.tools.ddk.xtext.format.test/.classpath index bc8caf1683..9209effae2 100644 --- a/com.avaloq.tools.ddk.xtext.format.test/.classpath +++ b/com.avaloq.tools.ddk.xtext.format.test/.classpath @@ -3,7 +3,6 @@ - diff --git a/com.avaloq.tools.ddk.xtext.format.test/build.properties b/com.avaloq.tools.ddk.xtext.format.test/build.properties index 39b83bd4a8..4404a080c8 100644 --- a/com.avaloq.tools.ddk.xtext.format.test/build.properties +++ b/com.avaloq.tools.ddk.xtext.format.test/build.properties @@ -1,7 +1,6 @@ source.. = src/,\ src-gen/,\ - resource/,\ - xtend-gen/ + resource/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.format.ui/.classpath b/com.avaloq.tools.ddk.xtext.format.ui/.classpath index 9e1b018817..72be310083 100644 --- a/com.avaloq.tools.ddk.xtext.format.ui/.classpath +++ b/com.avaloq.tools.ddk.xtext.format.ui/.classpath @@ -8,7 +8,6 @@ - diff --git a/com.avaloq.tools.ddk.xtext.format.ui/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.xtext.format.ui/META-INF/MANIFEST.MF index 8f2d6cf2c8..f849f3cb30 100644 --- a/com.avaloq.tools.ddk.xtext.format.ui/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.xtext.format.ui/META-INF/MANIFEST.MF @@ -25,8 +25,7 @@ Require-Bundle: com.avaloq.tools.ddk.xtext.format;visibility:=reexport, org.eclipse.xtext.xbase.ui, org.eclipse.jdt.debug.ui, org.eclipse.xtext.xbase.lib, - org.eclipse.xtext.ui.codetemplates.ui, - org.eclipse.xtend.lib;resolution:=optional + org.eclipse.xtext.ui.codetemplates.ui Import-Package: org.apache.log4j Bundle-RequiredExecutionEnvironment: JavaSE-21 Export-Package: com.avaloq.tools.ddk.xtext.format.ui.builder, diff --git a/com.avaloq.tools.ddk.xtext.format.ui/build.properties b/com.avaloq.tools.ddk.xtext.format.ui/build.properties index 31255ed05b..e10dcceb6a 100644 --- a/com.avaloq.tools.ddk.xtext.format.ui/build.properties +++ b/com.avaloq.tools.ddk.xtext.format.ui/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ .,\ plugin.xml \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.format/.classpath b/com.avaloq.tools.ddk.xtext.format/.classpath index 7e674d9ee4..0ddb998ae0 100644 --- a/com.avaloq.tools.ddk.xtext.format/.classpath +++ b/com.avaloq.tools.ddk.xtext.format/.classpath @@ -13,10 +13,5 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.format/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.xtext.format/META-INF/MANIFEST.MF index 1a5bee37bd..831018aa82 100644 --- a/com.avaloq.tools.ddk.xtext.format/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.xtext.format/META-INF/MANIFEST.MF @@ -21,7 +21,6 @@ Require-Bundle: org.eclipse.xtext, org.eclipse.osgi, org.eclipse.core.runtime, org.eclipse.core.resources, - org.eclipse.xtend.lib, org.eclipse.xtext.common.types, org.eclipse.xtext.xbase;visibility:=reexport, org.eclipse.xtext.xbase.lib, diff --git a/com.avaloq.tools.ddk.xtext.format/build.properties b/com.avaloq.tools.ddk.xtext.format/build.properties index 93152c92f5..04a0b862e0 100644 --- a/com.avaloq.tools.ddk.xtext.format/build.properties +++ b/com.avaloq.tools.ddk.xtext.format/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = model/generated/,\ META-INF/,\ .,\ diff --git a/com.avaloq.tools.ddk.xtext.generator.test/.classpath b/com.avaloq.tools.ddk.xtext.generator.test/.classpath index ed47baa3cf..526bfab37b 100644 --- a/com.avaloq.tools.ddk.xtext.generator.test/.classpath +++ b/com.avaloq.tools.ddk.xtext.generator.test/.classpath @@ -1,6 +1,5 @@ - diff --git a/com.avaloq.tools.ddk.xtext.generator.test/build.properties b/com.avaloq.tools.ddk.xtext.generator.test/build.properties index d6c49e5cf1..6b7927735f 100644 --- a/com.avaloq.tools.ddk.xtext.generator.test/build.properties +++ b/com.avaloq.tools.ddk.xtext.generator.test/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - xtend-gen/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.generator/.classpath b/com.avaloq.tools.ddk.xtext.generator/.classpath index aba0d9bb22..69e01f9099 100644 --- a/com.avaloq.tools.ddk.xtext.generator/.classpath +++ b/com.avaloq.tools.ddk.xtext.generator/.classpath @@ -1,11 +1,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.generator/build.properties b/com.avaloq.tools.ddk.xtext.generator/build.properties index d6c49e5cf1..6b7927735f 100644 --- a/com.avaloq.tools.ddk.xtext.generator/build.properties +++ b/com.avaloq.tools.ddk.xtext.generator/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - xtend-gen/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.scope.generator/.classpath b/com.avaloq.tools.ddk.xtext.scope.generator/.classpath index f70b2088b4..f46b5bd15d 100644 --- a/com.avaloq.tools.ddk.xtext.scope.generator/.classpath +++ b/com.avaloq.tools.ddk.xtext.scope.generator/.classpath @@ -1,7 +1,6 @@ - diff --git a/com.avaloq.tools.ddk.xtext.scope.generator/build.properties b/com.avaloq.tools.ddk.xtext.scope.generator/build.properties index 7edf8a4ebf..6b7927735f 100644 --- a/com.avaloq.tools.ddk.xtext.scope.generator/build.properties +++ b/com.avaloq.tools.ddk.xtext.scope.generator/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - xtend-gen/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.scope.ide/.classpath b/com.avaloq.tools.ddk.xtext.scope.ide/.classpath index fc183f78b3..2de44c4bb9 100644 --- a/com.avaloq.tools.ddk.xtext.scope.ide/.classpath +++ b/com.avaloq.tools.ddk.xtext.scope.ide/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.scope.ide/build.properties b/com.avaloq.tools.ddk.xtext.scope.ide/build.properties index 3f5513de7b..2d6ac57da2 100644 --- a/com.avaloq.tools.ddk.xtext.scope.ide/build.properties +++ b/com.avaloq.tools.ddk.xtext.scope.ide/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.scope/.classpath b/com.avaloq.tools.ddk.xtext.scope/.classpath index fc183f78b3..2de44c4bb9 100644 --- a/com.avaloq.tools.ddk.xtext.scope/.classpath +++ b/com.avaloq.tools.ddk.xtext.scope/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.scope/build.properties b/com.avaloq.tools.ddk.xtext.scope/build.properties index 5839f7a848..b533d62244 100644 --- a/com.avaloq.tools.ddk.xtext.scope/build.properties +++ b/com.avaloq.tools.ddk.xtext.scope/build.properties @@ -1,6 +1,5 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ .,\ plugin.xml,\ diff --git a/com.avaloq.tools.ddk.xtext.test.core/.classpath b/com.avaloq.tools.ddk.xtext.test.core/.classpath index d651646e41..4e3ebccc78 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/.classpath +++ b/com.avaloq.tools.ddk.xtext.test.core/.classpath @@ -1,11 +1,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF index 30f314e304..6a4e56093e 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF @@ -15,7 +15,6 @@ Require-Bundle: com.avaloq.tools.ddk.xtext, org.eclipse.jdt.core, org.eclipse.pde.core, org.eclipse.ui.ide, - org.eclipse.xtend.lib, org.eclipse.xtext.testing;visibility:=reexport, org.eclipse.xtext.ui.testing;visibility:=reexport, org.eclipse.xtext.ui, @@ -27,7 +26,8 @@ Require-Bundle: com.avaloq.tools.ddk.xtext, com.avaloq.tools.ddk.check.runtime.core, org.eclipse.emf.common, com.avaloq.tools.ddk, - junit-jupiter-api + junit-jupiter-api, + org.eclipse.xtend.lib Import-Package: org.slf4j, org.apache.logging.log4j,org.apache.log4j Export-Package: com.avaloq.tools.ddk.xtext.test, com.avaloq.tools.ddk.xtext.test.contentassist, diff --git a/com.avaloq.tools.ddk.xtext.test.core/build.properties b/com.avaloq.tools.ddk.xtext.test.core/build.properties index eeeed051e3..a12d47e566 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/build.properties +++ b/com.avaloq.tools.ddk.xtext.test.core/build.properties @@ -1,4 +1,3 @@ -source.. = src/,\ - xtend-gen/ +source.. = src/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.ui.test/.classpath b/com.avaloq.tools.ddk.xtext.ui.test/.classpath index 338476cab8..5540ec29d4 100644 --- a/com.avaloq.tools.ddk.xtext.ui.test/.classpath +++ b/com.avaloq.tools.ddk.xtext.ui.test/.classpath @@ -1,7 +1,6 @@ - diff --git a/com.avaloq.tools.ddk.xtext.ui.test/build.properties b/com.avaloq.tools.ddk.xtext.ui.test/build.properties index d6c49e5cf1..6b7927735f 100644 --- a/com.avaloq.tools.ddk.xtext.ui.test/build.properties +++ b/com.avaloq.tools.ddk.xtext.ui.test/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - xtend-gen/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/com.avaloq.tools.ddk.xtext.ui/.classpath b/com.avaloq.tools.ddk.xtext.ui/.classpath index 7b0f1225c1..58a21f1484 100644 --- a/com.avaloq.tools.ddk.xtext.ui/.classpath +++ b/com.avaloq.tools.ddk.xtext.ui/.classpath @@ -1,7 +1,6 @@ - diff --git a/com.avaloq.tools.ddk.xtext.ui/build.properties b/com.avaloq.tools.ddk.xtext.ui/build.properties index 6d2b56e648..3466223bf3 100644 --- a/com.avaloq.tools.ddk.xtext.ui/build.properties +++ b/com.avaloq.tools.ddk.xtext.ui/build.properties @@ -1,5 +1,4 @@ -source.. = src/,\ - xtend-gen/ +source.. = src/ bin.includes = META-INF/,\ icons/,\ schema/,\ diff --git a/com.avaloq.tools.ddk.xtext.valid.ide/.classpath b/com.avaloq.tools.ddk.xtext.valid.ide/.classpath index fc183f78b3..2de44c4bb9 100644 --- a/com.avaloq.tools.ddk.xtext.valid.ide/.classpath +++ b/com.avaloq.tools.ddk.xtext.valid.ide/.classpath @@ -6,11 +6,6 @@ - - - - - diff --git a/com.avaloq.tools.ddk.xtext.valid.ide/build.properties b/com.avaloq.tools.ddk.xtext.valid.ide/build.properties index 3f5513de7b..2d6ac57da2 100644 --- a/com.avaloq.tools.ddk.xtext.valid.ide/build.properties +++ b/com.avaloq.tools.ddk.xtext.valid.ide/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ - src-gen/,\ - xtend-gen/ + src-gen/ bin.includes = META-INF/,\ . diff --git a/ddk-configuration/.checkstyle b/ddk-configuration/.checkstyle index 8248743687..ab5c6246d0 100644 --- a/ddk-configuration/.checkstyle +++ b/ddk-configuration/.checkstyle @@ -10,7 +10,6 @@ - diff --git a/ddk-configuration/pmd/ruleset.xml b/ddk-configuration/pmd/ruleset.xml index cca425c723..25448c28f3 100644 --- a/ddk-configuration/pmd/ruleset.xml +++ b/ddk-configuration/pmd/ruleset.xml @@ -9,7 +9,6 @@ .*/src-gen/.* .*/src-model/.* - .*/xtend-gen/.* .*/ddk/xtext/test/ui/quickfix/AbstractQuickFixTest.* diff --git a/ddk-parent/pom.xml b/ddk-parent/pom.xml index e7ccfe6d23..a28279e6b0 100644 --- a/ddk-parent/pom.xml +++ b/ddk-parent/pom.xml @@ -55,7 +55,6 @@ 3.28.0 7.22.0 5.0.2 - 2.42.0 @@ -224,25 +223,6 @@ - - org.eclipse.xtext - xtend-maven-plugin - ${xtend.version} - - - xtend-generate - generate-sources - - compile - testCompile - - - ${basedir}/xtend-gen/ - ${basedir}/xtend-gen/ - - - - org.eclipse.tycho tycho-surefire-plugin @@ -313,7 +293,6 @@ ${basedir}/src-gen ${basedir}/src-model - ${basedir}/xtend-gen @@ -368,14 +347,6 @@ maven-clean-plugin ${clean.version} - - - xtend-gen - - ** - - - From 13cdb52a1945688b11223accd652b8edcf484722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 13:03:29 +0100 Subject: [PATCH 12/23] style: resolve all PMD and checkstyle warnings in migrated code Fix ~396 violations across 12 files in 5 modules (xtext.expression, xtext.format, xtext.ui, xtext.ui.test, xtext.check.generator): - Suppress dispatch method naming and unused params at class level - Rename underscore-prefixed fields and lambda parameters - Use char literals in StringBuilder.append for single characters - Add StringBuilder capacity, extract string constants, fix Javadoc - Simplify boolean returns, fix loose coupling, remove unnecessary boxing - Extract long lambdas into private methods, fix varargs array creation Co-Authored-By: Claude Opus 4.6 --- .../CheckQuickfixProviderFragment2.java | 4 + .../expression/generator/CodeGenerationX.java | 29 +- .../generator/ExpressionExtensionsX.java | 5 + .../expression/generator/GenModelUtilX.java | 9 +- .../xtext/expression/generator/Naming.java | 2 + .../ddk/xtext/format/FormatRuntimeModule.java | 1 + .../format/generator/FormatGenerator.java | 13 +- .../jvmmodel/FormatJvmModelInferrer.java | 469 +++++++++--------- .../format/scoping/FormatScopeProvider.java | 72 ++- .../format/validation/FormatValidator.java | 11 +- .../TemplateProposalProviderHelperTest.java | 47 +- .../TemplateProposalProviderHelper.java | 8 +- 12 files changed, 385 insertions(+), 285 deletions(-) diff --git a/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.java b/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.java index ff64e4e9cc..8d4a2dbf5a 100644 --- a/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.java +++ b/com.avaloq.tools.ddk.xtext.check.generator/src/com/avaloq/tools/ddk/xtext/check/generator/quickfix/CheckQuickfixProviderFragment2.java @@ -53,6 +53,7 @@ public void generate() { } protected void generateQuickfixProvider() { + // CHECKSTYLE:CONSTANTS-OFF StringConcatenationClient content = new StringConcatenationClient() { @Override protected void appendTo(final TargetStringConcatenation builder) { @@ -86,11 +87,13 @@ protected void appendTo(final TargetStringConcatenation builder) { builder.newLine(); } }; + // CHECKSTYLE:CONSTANTS-ON fileAccessFactory.createJavaFile(getQuickfixProviderClass(getGrammar()), content).writeTo(getProjectConfig().getEclipsePlugin().getSrc()); } protected void addRegistrationToPluginXml() { final TypeReference executableExtensionFactory = xtextGeneratorNaming.getEclipsePluginExecutableExtensionFactory(getGrammar()); + // CHECKSTYLE:CONSTANTS-OFF StringConcatenation builder = new StringConcatenation(); builder.append(""); builder.newLine(); @@ -112,6 +115,7 @@ protected void addRegistrationToPluginXml() { builder.newLine(); builder.append(""); builder.newLine(); + // CHECKSTYLE:CONSTANTS-ON getProjectConfig().getEclipsePlugin().getPluginXml().getEntries().add(builder.toString()); } } diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java index 9d1b49e452..f98c104e0f 100644 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java @@ -32,9 +32,10 @@ import com.avaloq.tools.ddk.xtext.expression.expression.SyntaxElement; import com.avaloq.tools.ddk.xtext.expression.expression.TypeSelectExpression; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class CodeGenerationX { - private ExpressionExtensionsX expressionExtensionsX = new ExpressionExtensionsX(); + private final ExpressionExtensionsX expressionExtensionsX = new ExpressionExtensionsX(); ////////////////////////////////////////////////// // ENTRY POINTS @@ -219,9 +220,11 @@ public boolean isSimpleFeatureCall(final Expression it, final CompilationContext return false; } + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity public boolean isSimpleFeatureCall(final FeatureCall it, final CompilationContext ctx) { return it.eClass().getName().contains("FeatureCall") && it.getName() == null && isFeature(it.getType()) && (it.getTarget() == null || isVariable(it.getTarget(), ctx) || isThisCall(it.getTarget())); } + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity // dispatch isSimpleNavigation protected boolean _isSimpleNavigation(final Expression it, final CompilationContext ctx) { @@ -232,19 +235,19 @@ protected boolean _isSimpleNavigation(final TypeSelectExpression it, final Compi return true; } + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity protected boolean _isSimpleNavigation(final FeatureCall it, final CompilationContext ctx) { return it.getName() == null && isFeature(it.getType()) && (it.getTarget() == null || isVariable(it.getTarget(), ctx) || isThisCall(it.getTarget()) || isSimpleNavigation(it.getTarget(), ctx)); } + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity public boolean isSimpleNavigation(final Expression it, final CompilationContext ctx) { if (it instanceof TypeSelectExpression typeSelectExpression) { return _isSimpleNavigation(typeSelectExpression, ctx); } else if (it instanceof FeatureCall featureCall) { return _isSimpleNavigation(featureCall, ctx); - } else if (it != null) { - return _isSimpleNavigation(it, ctx); } else { - return false; + return it != null && _isSimpleNavigation(it, ctx); } } @@ -401,9 +404,11 @@ public String autoBracket(final Expression it, final String javaCode, final Comp } // dispatch requiresBracketing (1 param: Expression, ctx) + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity protected boolean _requiresBracketing(final Expression it, final CompilationContext ctx) { return (expressionExtensionsX.isPrefixExpression(it, ctx) || expressionExtensionsX.isInfixExpression(it, ctx)) && it.eContainer() != null && requiresBracketing(it, it.eContainer(), ctx); } + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity protected boolean _requiresBracketing(final Literal it, final CompilationContext ctx) { return false; @@ -412,10 +417,8 @@ protected boolean _requiresBracketing(final Literal it, final CompilationContext public boolean requiresBracketing(final Expression it, final CompilationContext ctx) { if (it instanceof Literal literal) { return _requiresBracketing(literal, ctx); - } else if (it != null) { - return _requiresBracketing(it, ctx); } else { - return false; + return it != null && _requiresBracketing(it, ctx); } } @@ -424,15 +427,19 @@ protected boolean _requiresBracketingWithObject(final Expression it, final Objec return false; } + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity protected boolean _requiresBracketingWithExpression(final Expression it, final Expression parent, final CompilationContext ctx) { return expressionExtensionsX.isPrefixExpression(it, ctx) && expressionExtensionsX.isPrefixExpression(parent, ctx) || (expressionExtensionsX.isInfixExpression(it, ctx) && (expressionExtensionsX.isPrefixExpression(parent, ctx) || expressionExtensionsX.isInfixExpression(parent, ctx))); } + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity protected boolean _requiresBracketing(final OperationCall it, final OperationCall parent, final CompilationContext ctx) { return expressionExtensionsX.isPrefixExpression(it, ctx) && expressionExtensionsX.isPrefixExpression(parent, ctx) || (expressionExtensionsX.isInfixExpression(it, ctx) && (expressionExtensionsX.isPrefixExpression(parent, ctx) || (expressionExtensionsX.isInfixExpression(parent, ctx) && !it.getName().equals(parent.getName())))); } + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity protected boolean _requiresBracketing(final BooleanOperation it, final BooleanOperation parent, final CompilationContext ctx) { return !it.getOperator().equals(parent.getOperator()); @@ -465,10 +472,8 @@ protected boolean _isThisCall(final FeatureCall it) { public boolean isThisCall(final Expression it) { if (it instanceof FeatureCall featureCall) { return _isThisCall(featureCall); - } else if (it != null) { - return _isThisCall(it); } else { - return false; + return it != null && _isThisCall(it); } } @@ -488,10 +493,8 @@ protected boolean _isThis(final Identifier it) { public boolean isThis(final SyntaxElement it) { if (it instanceof Identifier identifier) { return _isThis(identifier); - } else if (it instanceof Expression expression) { - return _isThis(expression); } else { - return false; + return it instanceof Expression expression && _isThis(expression); } } diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.java index 14e9d6619d..b80616713a 100644 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.java +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/ExpressionExtensionsX.java @@ -19,6 +19,7 @@ import com.avaloq.tools.ddk.xtext.expression.expression.OperationCall; import org.eclipse.emf.ecore.EObject; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class ExpressionExtensionsX { protected String _serialize(final EObject it) { @@ -63,11 +64,13 @@ public boolean isNumber(final Expression it, final CompilationContext ctx) { return ctx.findType("Real").isAssignableFrom(ctx.analyze(it)); } + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity protected boolean _isArithmeticOperatorCall(final OperationCall it, final CompilationContext ctx) { return it.getType() == null && it.getTarget() == null && it.getParams().size() > 1 && ("+".equals(it.getName()) || "-".equals(it.getName()) || "*".equals(it.getName()) || "/".equals(it.getName())) && it.getParams().stream().allMatch(p -> isNumber(p, ctx)); } + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity protected boolean _isArithmeticOperatorCall(final Expression it, final CompilationContext ctx) { return false; @@ -85,10 +88,12 @@ protected boolean _isPrefixExpression(final Expression it, final CompilationCont return false; } + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity protected boolean _isPrefixExpression(final OperationCall it, final CompilationContext ctx) { return it.getType() == null && it.getTarget() == null && it.getParams().size() == 1 && ("-".equals(it.getName()) || "!".equals(it.getName())); } + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity public boolean isPrefixExpression(final Expression it, final CompilationContext ctx) { if (it instanceof OperationCall operationCall) { diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.java index 6c50e2416f..ad50b70c22 100644 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.java +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/GenModelUtilX.java @@ -30,10 +30,11 @@ import org.eclipse.xtext.xbase.lib.StringExtensions; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class GenModelUtilX { @Inject - private Naming _naming; + private Naming naming; @Inject private IGlobalScopeProvider globalScopeProvider; @@ -43,9 +44,11 @@ public class GenModelUtilX { private Resource context; + // CHECKSTYLE:CHECK-OFF HiddenField public void setResource(final Resource context) { this.context = context; } + // CHECKSTYLE:CHECK-ON HiddenField public /* cached */ String qualifiedPackageInterfaceName(final EPackage it) { final GenPackage genPackage = genPackage(it); @@ -57,12 +60,13 @@ public void setResource(final Resource context) { return null; } + // CHECKSTYLE:CONSTANTS-OFF public String qualifiedSwitchClassName(final EPackage it) { final GenPackage genPackage = genPackage(it); if (genPackage != null && genPackage.isLiteralsInterface()) { return genPackage.getUtilitiesPackageName() + "." + genPackage.getSwitchClassName(); } else { - return _naming.toJavaPackage(qualifiedPackageInterfaceName(it)) + ".util." + StringExtensions.toFirstUpper(it.getName()) + "Switch"; // heuristic + return naming.toJavaPackage(qualifiedPackageInterfaceName(it)) + ".util." + StringExtensions.toFirstUpper(it.getName()) + "Switch"; // heuristic } } @@ -100,6 +104,7 @@ public String qualifiedSwitchClassName(final EPackage it) { public /* cached */ String classifierIdLiteral(final EClass it) { return qualifiedPackageInterfaceName(it.getEPackage()) + "." + format(it.getName()).toUpperCase(); } + // CHECKSTYLE:CONSTANTS-ON protected /* cached */ String _instanceClassName(final Void it) { return ""; diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.java index 831c45a721..bdcc573db6 100644 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.java +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/Naming.java @@ -14,6 +14,7 @@ public class Naming { + // CHECKSTYLE:CONSTANTS-OFF public String toFileName(final String qualifiedName) { return toJavaPackage(qualifiedName).replace('.', '/') + '/' + toSimpleName(qualifiedName) + ".java"; } @@ -25,4 +26,5 @@ public String toJavaPackage(final String qualifiedName) { public String toSimpleName(final String qualifiedName) { return Strings.lastToken(qualifiedName, "."); } + // CHECKSTYLE:CONSTANTS-ON } diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.java index 13a0345ec6..89602f2d1a 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.java +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/FormatRuntimeModule.java @@ -91,6 +91,7 @@ public void configureLinkingIScopeProvider(final Binder binder) { /** {@inheritDoc} */ @Override + @SuppressWarnings("PMD.AvoidDollarSigns") // CHECKSTYLE:OFF public Class bindIAllContainersState$Provider() { // CHECKSTYLE:ON diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java index 11749a647e..741c218efb 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java @@ -43,13 +43,14 @@ * * see http://www.eclipse.org/Xtext/documentation.html#TutorialCodeGeneration */ +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class FormatGenerator extends JvmModelGenerator { @Inject - private TreeAppendableUtil _treeAppendableUtil; + private TreeAppendableUtil treeAppendableUtil; @Inject - private ErrorSafeExtensions _errorSafeExtensions; + private ErrorSafeExtensions errorSafeExtensions; public String getSingleCommentDocumentation(final EObject it, final ITreeAppendable appendable, final GeneratorConfig config) { final DocumentationAdapter adapter = IterableExtensions.head(Iterables.filter(it.eAdapters(), DocumentationAdapter.class)); @@ -70,9 +71,9 @@ protected ITreeAppendable _generateMember(final JvmField it, final ITreeAppendab final ITreeAppendable tracedAppendable = appendable.trace(it); generateAnnotations(it.getAnnotations(), tracedAppendable, true, config); generateModifier(it, tracedAppendable, config); - _errorSafeExtensions.serializeSafely(it.getType(), "Object", tracedAppendable); + errorSafeExtensions.serializeSafely(it.getType(), "Object", tracedAppendable); tracedAppendable.append(" "); - _treeAppendableUtil.traceSignificant(tracedAppendable, it).append(it.getSimpleName()); + treeAppendableUtil.traceSignificant(tracedAppendable, it).append(it.getSimpleName()); generateInitialization(it, tracedAppendable, config); tracedAppendable.append(";"); String documentation = getSingleCommentDocumentation(it, appendable, config); @@ -97,9 +98,9 @@ public void doGenerate(final Resource resource, final IFileSystemAccess fsa) { } public CharSequence generateSrc(final FormatConfiguration model) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(256); builder.append("package ").append(Strings.skipLastToken(getFormatterName(model, ""), ".")).append(";\n"); - builder.append("\n"); + builder.append('\n'); builder.append("/**\n"); builder.append(" * The formatting configuration for ").append(Strings.lastToken(model.getTargetGrammar().getName(), ".")).append(".\n"); builder.append(" */\n"); diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java index 36e09c4543..21cf44a349 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java @@ -13,7 +13,6 @@ import static com.avaloq.tools.ddk.xtext.util.EObjectUtil.getFileLocation; import static org.eclipse.xtext.GrammarUtil.getGrammar; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; @@ -28,7 +27,6 @@ import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.xtext.AbstractElement; import org.eclipse.xtext.AbstractMetamodelDeclaration; @@ -109,13 +107,14 @@ *

The JVM model should contain all elements that would appear in the Java code * which is generated from the source model. Other models link against the JVM model rather than the source model.

*/ +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class FormatJvmModelInferrer extends AbstractModelInferrer { @Inject - private JvmTypesBuilder _jvmTypesBuilder; + private JvmTypesBuilder jvmTypesBuilder; @Inject - private TypeReferences _typeReferences; + private TypeReferences typeReferences; @Inject private GrammarAccessExtensions grammarAccess; @@ -146,11 +145,19 @@ public class FormatJvmModelInferrer extends AbstractModelInferrer { private static final String PARAMETER_COLUMN = "currentColumn"; + private static final int DEFAULT_BUFFER_CAPACITY = 256; + + private static final String DOT = "."; + + private static final String IMPL_SUFFIX = "Impl"; + + private static final String THE_FORMAT_CONFIGURATION = "the format configuration"; + /** * The dispatch method {@code infer} is called for each instance of the * given element's type that is contained in a resource. * - * @param element + * @param format * the model to create one or more {@link JvmDeclaredType declared types} from. * @param acceptor * each created {@link JvmDeclaredType type} without a container should be passed to the acceptor in order @@ -177,7 +184,7 @@ protected void _infer(final FormatConfiguration format, final IJvmDeclaredTypeAc RuleNames.getRuleNames(context, true); } acceptor.accept( - _jvmTypesBuilder.toClass(format, Strings.lastToken(FormatGeneratorUtil.getFormatterName(format, "Abstract"), ".")), (JvmGenericType it) -> { + jvmTypesBuilder.toClass(format, Strings.lastToken(FormatGeneratorUtil.getFormatterName(format, "Abstract"), DOT)), (JvmGenericType it) -> { inferClass(format, it); inferConstants(format, it); inferGetGrammarAccess(format, it); @@ -192,22 +199,22 @@ public void inferClass(final FormatConfiguration format, final JvmGenericType it Grammar targetGrammar = format.getTargetGrammar(); String targetGrammarNameRaw = targetGrammar != null ? targetGrammar.getName() : null; String targetGrammarName = Strings.emptyIfNull(targetGrammarNameRaw); - _jvmTypesBuilder.setDocumentation(it, - "The abstract formatting configuration for " + Strings.skipLastToken(targetGrammarName, ".") + "." + Strings.lastToken(targetGrammarName, ".") + " as declared in " + Strings.lastToken(targetGrammarName, ".") + ".format."); + jvmTypesBuilder.setDocumentation(it, + "The abstract formatting configuration for " + Strings.skipLastToken(targetGrammarName, DOT) + DOT + Strings.lastToken(targetGrammarName, DOT) + " as declared in " + Strings.lastToken(targetGrammarName, DOT) + ".format."); if (format.getFormatterBaseClass() != null) { - _jvmTypesBuilder.operator_add(it.getSuperTypes(), - _typeReferenceBuilder.typeRef(format.getFormatterBaseClass().getPackageName() + "." + format.getFormatterBaseClass().getSimpleName())); + jvmTypesBuilder.operator_add(it.getSuperTypes(), + _typeReferenceBuilder.typeRef(format.getFormatterBaseClass().getPackageName() + DOT + format.getFormatterBaseClass().getSimpleName())); } else { - _jvmTypesBuilder.operator_add(it.getSuperTypes(), + jvmTypesBuilder.operator_add(it.getSuperTypes(), _typeReferenceBuilder.typeRef(BASE_FORMATTER_CLASS_NAME)); } - it.setPackageName(Strings.skipLastToken(FormatGeneratorUtil.getFormatterName(format, ""), ".")); + it.setPackageName(Strings.skipLastToken(FormatGeneratorUtil.getFormatterName(format, ""), DOT)); it.setAbstract(true); } public boolean inferConstants(final FormatConfiguration format, final JvmGenericType it) { if (!FormatGeneratorUtil.getAllConstants(format).isEmpty()) { - return _jvmTypesBuilder.operator_add(it.getMembers(), + return jvmTypesBuilder.operator_add(it.getMembers(), ListExtensions.map(FormatGeneratorUtil.getAllConstants(format), (Constant c) -> createConstant(format, c))); } return false; @@ -218,91 +225,94 @@ public String getFullyQualifiedName(final Grammar g) { } public boolean inferGetGrammarAccess(final FormatConfiguration format, final JvmGenericType it) { - JvmOperation method = _jvmTypesBuilder.toMethod(format, "getGrammarAccess", - _typeReferences.getTypeForName(getFullyQualifiedName(format.getTargetGrammar()), format.getTargetGrammar()), (JvmOperation it_1) -> { - it_1.setVisibility(JvmVisibility.PROTECTED); + JvmOperation method = jvmTypesBuilder.toMethod(format, "getGrammarAccess", + typeReferences.getTypeForName(getFullyQualifiedName(format.getTargetGrammar()), format.getTargetGrammar()), (JvmOperation op) -> { + op.setVisibility(JvmVisibility.PROTECTED); final JvmAnnotationReference overrideAnnotation = createOverrideAnnotation(format); if (overrideAnnotation != null) { - _jvmTypesBuilder.operator_add(it_1.getAnnotations(), overrideAnnotation); + jvmTypesBuilder.operator_add(op.getAnnotations(), overrideAnnotation); } - _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { - StringBuilder sb = new StringBuilder(); + jvmTypesBuilder.setBody(op, (ITreeAppendable body) -> { + StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_CAPACITY); sb.append("return ("); - sb.append(GrammarUtil.getSimpleName(format.getTargetGrammar()) + "GrammarAccess"); + sb.append(GrammarUtil.getSimpleName(format.getTargetGrammar())).append("GrammarAccess"); sb.append(") super.getGrammarAccess();"); - it_2.append(sb); + body.append(sb); }); }); - return _jvmTypesBuilder.operator_add(it.getMembers(), method); + return jvmTypesBuilder.operator_add(it.getMembers(), method); } public boolean inferConfigureAcsFormatting(final FormatConfiguration format, final JvmGenericType it) { - JvmOperation method = _jvmTypesBuilder.toMethod(format, "configureAcsFormatting", _typeReferenceBuilder.typeRef("void"), (JvmOperation it_1) -> { - it_1.setVisibility(JvmVisibility.PROTECTED); + JvmOperation method = jvmTypesBuilder.toMethod(format, "configureAcsFormatting", _typeReferenceBuilder.typeRef("void"), (JvmOperation op) -> { + op.setVisibility(JvmVisibility.PROTECTED); final JvmAnnotationReference overrideAnnotation = createOverrideAnnotation(format); if (overrideAnnotation != null) { - _jvmTypesBuilder.operator_add(it_1.getAnnotations(), overrideAnnotation); + jvmTypesBuilder.operator_add(op.getAnnotations(), overrideAnnotation); } - _jvmTypesBuilder.operator_add(it_1.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); - _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { - it_2.append("init(config, getGrammarAccess());"); + jvmTypesBuilder.operator_add(op.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); + jvmTypesBuilder.setBody(op, (ITreeAppendable body) -> { + body.append("init(config, getGrammarAccess());"); }); }); - return _jvmTypesBuilder.operator_add(it.getMembers(), method); + return jvmTypesBuilder.operator_add(it.getMembers(), method); } public boolean inferInit(final FormatConfiguration format, final JvmGenericType it) { - JvmOperation method = _jvmTypesBuilder.toMethod(format, "init", _typeReferenceBuilder.typeRef("void"), (JvmOperation it_1) -> { - Pair mappedTo = Pair.of(PARAMETER_CONFIG, "the format configuration"); - Pair mappedTo_1 = Pair.of(PARAMETER_GRAMMAR_ACCESS, "the grammar access for the grammar"); - _jvmTypesBuilder.setDocumentation(it_1, generateJavaDoc("Calls all configXyz methods declared in this class.", CollectionLiterals.newLinkedHashMap(mappedTo, mappedTo_1))); - it_1.setVisibility(JvmVisibility.PROTECTED); - _jvmTypesBuilder.operator_add(it_1.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); - _jvmTypesBuilder.operator_add(it_1.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_GRAMMAR_ACCESS, _typeReferenceBuilder.typeRef(getFullyQualifiedName(format.getTargetGrammar())))); - _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { - final ArrayList rules = listConfigRules(format); - int length = ((Object[]) Conversions.unwrapArray(rules, Object.class)).length; - ExclusiveRange range = new ExclusiveRange(0, length, true); - for (final Integer i : range) { - if (i.intValue() != 0) { - it_2.newLine(); - } - it_2.append(rules.get(i.intValue())); + JvmOperation method = jvmTypesBuilder.toMethod(format, "init", _typeReferenceBuilder.typeRef("void"), + (JvmOperation op) -> initializeInitMethod(format, op)); + return jvmTypesBuilder.operator_add(it.getMembers(), method); + } + + private void initializeInitMethod(final FormatConfiguration format, final JvmOperation op) { + Pair mappedTo = Pair.of(PARAMETER_CONFIG, THE_FORMAT_CONFIGURATION); + Pair mapped = Pair.of(PARAMETER_GRAMMAR_ACCESS, "the grammar access for the grammar"); + jvmTypesBuilder.setDocumentation(op, generateJavaDoc("Calls all configXyz methods declared in this class.", CollectionLiterals.newLinkedHashMap(mappedTo, mapped))); + op.setVisibility(JvmVisibility.PROTECTED); + jvmTypesBuilder.operator_add(op.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); + jvmTypesBuilder.operator_add(op.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_GRAMMAR_ACCESS, _typeReferenceBuilder.typeRef(getFullyQualifiedName(format.getTargetGrammar())))); + jvmTypesBuilder.setBody(op, (ITreeAppendable body) -> { + final List rules = listConfigRules(format); + int length = ((Object[]) Conversions.unwrapArray(rules, Object.class)).length; + ExclusiveRange range = new ExclusiveRange(0, length, true); + for (final Integer i : range) { + if (i != 0) { + body.newLine(); } - }); + body.append(rules.get(i)); + } }); - return _jvmTypesBuilder.operator_add(it.getMembers(), method); } public boolean inferRules(final FormatConfiguration format, final JvmGenericType it) { - _jvmTypesBuilder.operator_add(it.getMembers(), + jvmTypesBuilder.operator_add(it.getMembers(), Iterables.concat(ListExtensions.>map(FormatGeneratorUtil.getParserRules(format), (GrammarRule c) -> createRule(format, c)))); - _jvmTypesBuilder.operator_add(it.getMembers(), + jvmTypesBuilder.operator_add(it.getMembers(), Iterables.concat(ListExtensions.>map(FormatGeneratorUtil.getEnumRules(format), (GrammarRule c) -> createRule(format, c)))); - _jvmTypesBuilder.operator_add(it.getMembers(), + jvmTypesBuilder.operator_add(it.getMembers(), Iterables.concat(ListExtensions.>map(FormatGeneratorUtil.getTerminalRules(format), (GrammarRule c) -> createRule(format, c)))); boolean result = false; if (FormatGeneratorUtil.getWildcardRule(format) != null) { - JvmOperation method = _jvmTypesBuilder.toMethod(format, "configFindElements", _typeReferenceBuilder.typeRef("void"), (JvmOperation it_1) -> { - Pair mappedTo = Pair.of(PARAMETER_CONFIG, "the format configuration"); - Pair mappedTo_1 = Pair.of(PARAMETER_ELEMENTS, "the grammar access for the grammar"); - _jvmTypesBuilder.setDocumentation(it_1, generateJavaDoc("Configuration for IGrammarAccess.findXyz() methods.", CollectionLiterals.newLinkedHashMap(mappedTo, mappedTo_1))); - it_1.setVisibility(JvmVisibility.PROTECTED); - _jvmTypesBuilder.operator_add(it_1.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); - _jvmTypesBuilder.operator_add(it_1.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_ELEMENTS, _typeReferenceBuilder.typeRef(getFullyQualifiedName(getGrammar(format.getTargetGrammar()))))); - _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { + JvmOperation method = jvmTypesBuilder.toMethod(format, "configFindElements", _typeReferenceBuilder.typeRef("void"), (JvmOperation op) -> { + Pair mappedTo = Pair.of(PARAMETER_CONFIG, THE_FORMAT_CONFIGURATION); + Pair mapped = Pair.of(PARAMETER_ELEMENTS, "the grammar access for the grammar"); + jvmTypesBuilder.setDocumentation(op, generateJavaDoc("Configuration for IGrammarAccess.findXyz() methods.", CollectionLiterals.newLinkedHashMap(mappedTo, mapped))); + op.setVisibility(JvmVisibility.PROTECTED); + jvmTypesBuilder.operator_add(op.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); + jvmTypesBuilder.operator_add(op.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_ELEMENTS, _typeReferenceBuilder.typeRef(getFullyQualifiedName(getGrammar(format.getTargetGrammar()))))); + jvmTypesBuilder.setBody(op, (ITreeAppendable body) -> { final List directives = ListExtensions.map( FormatGeneratorUtil.getWildcardRule(format).getDirectives(), (WildcardRuleDirective d) -> directive(d, getRuleName(FormatGeneratorUtil.getWildcardRule(format))).toString()); - it_2.append(fixLastLine(IterableExtensions.join(directives))); + body.append(fixLastLine(IterableExtensions.join(directives))); }); }); - result = _jvmTypesBuilder.operator_add(it.getMembers(), method); + result = jvmTypesBuilder.operator_add(it.getMembers(), method); } return result; } @@ -324,15 +334,15 @@ public void inferLocatorActivators(final FormatConfiguration format, final JvmGe for (final EObject directive : IterableExtensions.filterNull(directives)) { for (final Matcher matcher : collectMatchers(directive)) { if ((matcher.getLocator() instanceof ColumnLocator) && (((ColumnLocator) matcher.getLocator()).getParameter() != null)) { - _jvmTypesBuilder.operator_add(it.getMembers(), + jvmTypesBuilder.operator_add(it.getMembers(), createParameterCalculatorInnerClass(format, rule, directive, matcher, ((ColumnLocator) matcher.getLocator()).getParameter(), it)); } if ((matcher.getLocator() instanceof IndentLocator) && (((IndentLocator) matcher.getLocator()).getParameter() != null)) { - _jvmTypesBuilder.operator_add(it.getMembers(), + jvmTypesBuilder.operator_add(it.getMembers(), createParameterCalculatorInnerClass(format, rule, directive, matcher, ((IndentLocator) matcher.getLocator()).getParameter(), it)); } if (matcher.getCondition() != null) { - _jvmTypesBuilder.operator_add(it.getMembers(), + jvmTypesBuilder.operator_add(it.getMembers(), createLocatorActivatorInnerClass(format, rule, directive, matcher, it)); } } @@ -341,24 +351,24 @@ public void inferLocatorActivators(final FormatConfiguration format, final JvmGe } public JvmGenericType createLocatorActivatorInnerClass(final FormatConfiguration format, final Rule rule, final EObject directive, final Matcher matcher, final JvmGenericType type) { - return _jvmTypesBuilder.toClass(format, getLocatorActivatorName(rule, directive, matcher), (JvmGenericType it) -> { + return jvmTypesBuilder.toClass(format, getLocatorActivatorName(rule, directive, matcher), (JvmGenericType it) -> { it.setStatic(true); it.setFinal(true); it.setVisibility(JvmVisibility.PROTECTED); - _jvmTypesBuilder.operator_add(it.getSuperTypes(), getLocatorActivatorSuperType(format, rule)); - JvmOperation method = _jvmTypesBuilder.toMethod(matcher, METHOD_ACTIVATE, getLocatorActivatorReturnType(format), (JvmOperation it_1) -> { - _jvmTypesBuilder.operator_add(it_1.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_CONTEXT, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), format))); - _jvmTypesBuilder.operator_add(it_1.getParameters(), createCurrenctColumnParameter()); + jvmTypesBuilder.operator_add(it.getSuperTypes(), getLocatorActivatorSuperType(format, rule)); + JvmOperation method = jvmTypesBuilder.toMethod(matcher, METHOD_ACTIVATE, getLocatorActivatorReturnType(format), (JvmOperation op) -> { + jvmTypesBuilder.operator_add(op.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_CONTEXT, typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), format))); + jvmTypesBuilder.operator_add(op.getParameters(), createCurrenctColumnParameter()); if (!Objects.equals(format.eResource(), matcher.eResource())) { - _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { - xbaseCompiler.compile(matcher.getCondition(), it_2, getLocatorActivatorReturnType(format), null); + jvmTypesBuilder.setBody(op, (ITreeAppendable body) -> { + xbaseCompiler.compile(matcher.getCondition(), body, getLocatorActivatorReturnType(format), null); }); } else { - _jvmTypesBuilder.setBody(it_1, matcher.getCondition()); + jvmTypesBuilder.setBody(op, matcher.getCondition()); } }); - _jvmTypesBuilder.operator_add(it.getMembers(), method); + jvmTypesBuilder.operator_add(it.getMembers(), method); }); } @@ -370,29 +380,29 @@ public JvmFormalParameter createCurrenctColumnParameter() { } public JvmGenericType createParameterCalculatorInnerClass(final FormatConfiguration format, final Rule rule, final EObject directive, final Matcher matcher, final XExpression parameterCalculation, final JvmGenericType type) { - return _jvmTypesBuilder.toClass(format, getParameterCalculatorName(rule, directive, matcher), (JvmGenericType it) -> { + return jvmTypesBuilder.toClass(format, getParameterCalculatorName(rule, directive, matcher), (JvmGenericType it) -> { it.setStatic(true); it.setFinal(true); it.setVisibility(JvmVisibility.PROTECTED); - _jvmTypesBuilder.operator_add(it.getSuperTypes(), getParameterCalculatorSuperType(format, rule)); - JvmOperation method = _jvmTypesBuilder.toMethod(matcher, METHOD_CALCULATE, getParameterCalculatorReturnType(format), (JvmOperation it_1) -> { - _jvmTypesBuilder.operator_add(it_1.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_CONTEXT, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), format))); - _jvmTypesBuilder.operator_add(it_1.getParameters(), createCurrenctColumnParameter()); + jvmTypesBuilder.operator_add(it.getSuperTypes(), getParameterCalculatorSuperType(format, rule)); + JvmOperation method = jvmTypesBuilder.toMethod(matcher, METHOD_CALCULATE, getParameterCalculatorReturnType(format), (JvmOperation op) -> { + jvmTypesBuilder.operator_add(op.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_CONTEXT, typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), format))); + jvmTypesBuilder.operator_add(op.getParameters(), createCurrenctColumnParameter()); if (!Objects.equals(format.eResource(), matcher.eResource())) { - _jvmTypesBuilder.setBody(it_1, (ITreeAppendable it_2) -> { - xbaseCompiler.compile(parameterCalculation, it_2, getParameterCalculatorReturnType(format), null); + jvmTypesBuilder.setBody(op, (ITreeAppendable body) -> { + xbaseCompiler.compile(parameterCalculation, body, getParameterCalculatorReturnType(format), null); }); } else { - _jvmTypesBuilder.setBody(it_1, parameterCalculation); + jvmTypesBuilder.setBody(op, parameterCalculation); } }); - _jvmTypesBuilder.operator_add(it.getMembers(), method); + jvmTypesBuilder.operator_add(it.getMembers(), method); }); } - public ArrayList listConfigRules(final FormatConfiguration format) { - final ArrayList configRules = CollectionLiterals.newArrayList(); + public List listConfigRules(final FormatConfiguration format) { + final List configRules = CollectionLiterals.newArrayList(); if (FormatGeneratorUtil.getWildcardRule(format) != null) { configRules.add("configFindElements(config, grammarAccess);"); } @@ -409,12 +419,12 @@ public ArrayList listConfigRules(final FormatConfiguration format) { } public String generateJavaDoc(final String description, final Map parameters) { - final StringBuilder sb = new StringBuilder(); - sb.append(description).append("\n"); - sb.append("\n"); + final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_CAPACITY); + sb.append(description).append('\n'); + sb.append('\n'); for (final Map.Entry parameter : parameters.entrySet()) { - sb.append("@param ").append(parameter.getKey()).append("\n"); - sb.append(" - ").append(parameter.getValue()).append("\n"); + sb.append("@param ").append(parameter.getKey()).append('\n'); + sb.append(" - ").append(parameter.getValue()).append('\n'); } return sb.toString(); } @@ -432,23 +442,23 @@ public JvmAnnotationReference createOverrideAnnotation(final FormatConfiguration public JvmMember createConstant(final FormatConfiguration configuration, final Constant constant) { if (constant.getStringValue() != null) { - return _jvmTypesBuilder.toField(constant, constant.getName(), _typeReferences.getTypeForName("String", constant), (it) -> { - _jvmTypesBuilder.setDocumentation(it, locatorString(constant)); + return jvmTypesBuilder.toField(constant, constant.getName(), typeReferences.getTypeForName("String", constant), (it) -> { + jvmTypesBuilder.setDocumentation(it, locatorString(constant)); it.setStatic(true); it.setFinal(true); it.setVisibility(JvmVisibility.PROTECTED); - _jvmTypesBuilder.setInitializer(it, (ITreeAppendable it_1) -> { - it_1.append("\"" + constant.getStringValue() + "\""); + jvmTypesBuilder.setInitializer(it, (ITreeAppendable op) -> { + op.append("\"" + constant.getStringValue() + "\""); }); }); } else if (constant.getIntValue() != null) { - return _jvmTypesBuilder.toField(constant, constant.getName(), _typeReferences.getTypeForName("int", constant), (it) -> { - _jvmTypesBuilder.setDocumentation(it, locatorString(constant)); + return jvmTypesBuilder.toField(constant, constant.getName(), typeReferences.getTypeForName("int", constant), (it) -> { + jvmTypesBuilder.setDocumentation(it, locatorString(constant)); it.setStatic(true); it.setFinal(true); it.setVisibility(JvmVisibility.PROTECTED); - _jvmTypesBuilder.setInitializer(it, (ITreeAppendable it_1) -> { - it_1.append(constant.getIntValue().toString()); + jvmTypesBuilder.setInitializer(it, (ITreeAppendable op) -> { + op.append(constant.getIntValue().toString()); }); }); } @@ -490,11 +500,11 @@ public JvmTypeReference getParameterCalculatorReturnType(final FormatConfigurati // getLocatorActivatorSuperType dispatch protected JvmTypeReference _getLocatorActivatorSuperType(final FormatConfiguration formatConfiguration, final GrammarRule rule) { - return _typeReferenceBuilder.typeRef(LocatorActivator.class, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); + return _typeReferenceBuilder.typeRef(LocatorActivator.class, typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); } protected JvmTypeReference _getLocatorActivatorSuperType(final FormatConfiguration formatConfiguration, final WildcardRule rule) { - return _typeReferenceBuilder.typeRef(LocatorActivator.class, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); + return _typeReferenceBuilder.typeRef(LocatorActivator.class, typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); } public JvmTypeReference getLocatorActivatorSuperType(final FormatConfiguration formatConfiguration, final Rule rule) { @@ -509,11 +519,11 @@ public JvmTypeReference getLocatorActivatorSuperType(final FormatConfiguration f // getParameterCalculatorSuperType dispatch protected JvmTypeReference _getParameterCalculatorSuperType(final FormatConfiguration formatConfiguration, final GrammarRule rule) { - return _typeReferenceBuilder.typeRef(LocatorParameterCalculator.class, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); + return _typeReferenceBuilder.typeRef(LocatorParameterCalculator.class, typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); } protected JvmTypeReference _getParameterCalculatorSuperType(final FormatConfiguration formatConfiguration, final WildcardRule rule) { - return _typeReferenceBuilder.typeRef(LocatorParameterCalculator.class, _typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); + return _typeReferenceBuilder.typeRef(LocatorParameterCalculator.class, typeReferences.getTypeForName(getGrammarElementNameFromSelf(rule), formatConfiguration)); } public JvmTypeReference getParameterCalculatorSuperType(final FormatConfiguration formatConfiguration, final Rule rule) { @@ -562,7 +572,7 @@ protected String _getGrammarElementNameFromSelf(final GrammarRule rule) { } EPackage ePackage = metamodel.getEPackage(); String ePackageName = ePackage != null ? ePackage.getName() : null; - return metamodelPackage.substring(0, metamodelPackage.lastIndexOf(".core")) + "." + ePackageName + "." + actualRuleName; + return metamodelPackage.substring(0, metamodelPackage.lastIndexOf(".core")) + DOT + ePackageName + DOT + actualRuleName; } } @@ -586,19 +596,19 @@ public int getMatcherIndex(final Matcher matcher) { } public String getLocatorActivatorName(final EObject rule, final EObject directive, final Matcher matcher) { - return ("ActivatorFor" + getRuleName(rule) + getMatcherName(matcher, directive)).replace("Impl", ""); + return ("ActivatorFor" + getRuleName(rule) + getMatcherName(matcher, directive)).replace(IMPL_SUFFIX, ""); } public String getLocatorActivatorName(final String partialName, final Matcher matcher) { - return ("ActivatorFor" + partialName + getMatcherIndex(matcher) + getLocatorName(matcher.getLocator()) + StringExtensions.toFirstUpper(matcher.getType().name().toLowerCase())).replace("Impl", ""); + return ("ActivatorFor" + partialName + getMatcherIndex(matcher) + getLocatorName(matcher.getLocator()) + StringExtensions.toFirstUpper(matcher.getType().name().toLowerCase())).replace(IMPL_SUFFIX, ""); } public String getParameterCalculatorName(final EObject rule, final EObject directive, final Matcher matcher) { - return ("ParameterCalculatorFor" + getRuleName(rule) + getMatcherName(matcher, directive)).replace("Impl", ""); + return ("ParameterCalculatorFor" + getRuleName(rule) + getMatcherName(matcher, directive)).replace(IMPL_SUFFIX, ""); } public String getParameterCalculatorName(final String partialName, final Matcher matcher) { - return ("ParameterCalculatorFor" + partialName + getMatcherIndex(matcher) + getLocatorName(matcher.getLocator()) + StringExtensions.toFirstUpper(matcher.getType().name().toLowerCase())).replace("Impl", ""); + return ("ParameterCalculatorFor" + partialName + getMatcherIndex(matcher) + getLocatorName(matcher.getLocator()) + StringExtensions.toFirstUpper(matcher.getType().name().toLowerCase())).replace(IMPL_SUFFIX, ""); } // getRuleName dispatch @@ -642,52 +652,53 @@ public String convertNonAlphaNumeric(final String str) { final java.util.regex.Matcher matcher = pattern.matcher(str); final StringBuffer sb = new StringBuffer(); while (matcher.find()) { - matcher.appendReplacement(sb, String.valueOf(Integer.toHexString(matcher.group().hashCode()))); + matcher.appendReplacement(sb, Integer.toHexString(matcher.group().hashCode())); } matcher.appendTail(sb); return sb.toString(); } // getDirectiveName dispatch + @SuppressWarnings("PMD.CollectionTypeMismatch") protected String _getDirectiveName(final GroupBlock directive) { final GrammarRule grammarRule = EcoreUtil2.getContainerOfType(directive, GrammarRule.class); - final ArrayList> directives = CollectionLiterals.>newArrayList(Iterables.filter(grammarRule.getDirectives(), GroupBlock.class)); - return "Group" + String.valueOf(directives.indexOf(directive) + 1); + final List> directives = CollectionLiterals.>newArrayList(Iterables.filter(grammarRule.getDirectives(), GroupBlock.class)); + return "Group" + (directives.indexOf(directive) + 1); } protected String _getDirectiveName(final SpecificDirective directive) { - String directiveName = ""; + StringBuilder directiveName = new StringBuilder(DEFAULT_BUFFER_CAPACITY); for (final GrammarElementReference grammarElementReference : directive.getGrammarElements()) { if (grammarElementReference.getAssignment() != null) { - directiveName = directiveName + grammarAccess.gaElementAccessMethodName(grammarElementReference.getAssignment()).replaceFirst("get", "").replaceFirst("(?s)(.*)" + "Assignment", "$1" + ""); + directiveName.append(grammarAccess.gaElementAccessMethodName(grammarElementReference.getAssignment()).replaceFirst("get", "").replaceFirst("(?s)(.*)Assignment", "$1")); } if (grammarElementReference.getRuleCall() != null) { - directiveName = directiveName + StringExtensions.toFirstUpper(grammarElementReference.getRuleCall().getRule().getName()); + directiveName.append(StringExtensions.toFirstUpper(grammarElementReference.getRuleCall().getRule().getName())); } if (grammarElementReference.getRule() != null) { - directiveName = directiveName + StringExtensions.toFirstUpper(grammarElementReference.getRule().getName()); + directiveName.append(StringExtensions.toFirstUpper(grammarElementReference.getRule().getName())); } if (grammarElementReference.getKeyword() != null) { - directiveName = directiveName + StringExtensions.toFirstUpper(convertNonAlphaNumeric(grammarElementReference.getKeyword().getValue())); + directiveName.append(StringExtensions.toFirstUpper(convertNonAlphaNumeric(grammarElementReference.getKeyword().getValue()))); } if (grammarElementReference.getSelf() != null) { - directiveName = directiveName + "Self"; + directiveName.append("Self"); } } - return directiveName; + return directiveName.toString(); } protected String _getDirectiveName(final ContextFreeDirective directive) { - String directiveName = ""; + StringBuilder directiveName = new StringBuilder(DEFAULT_BUFFER_CAPACITY); for (final GrammarElementLookup grammarElementLookup : directive.getGrammarElements()) { if (grammarElementLookup.getRule() != null) { - directiveName = directiveName + StringExtensions.toFirstUpper(grammarElementLookup.getRule().getName()); + directiveName.append(StringExtensions.toFirstUpper(grammarElementLookup.getRule().getName())); } if (grammarElementLookup.getKeyword() != null) { - directiveName = directiveName + StringExtensions.toFirstUpper(convertNonAlphaNumeric(grammarElementLookup.getKeyword())); + directiveName.append(StringExtensions.toFirstUpper(convertNonAlphaNumeric(grammarElementLookup.getKeyword()))); } } - return directiveName; + return directiveName.toString(); } protected String _getDirectiveName(final KeywordPair directive) { @@ -716,44 +727,47 @@ public String getDirectiveName(final EObject directive) { public Iterable createRule(final FormatConfiguration format, final GrammarRule rule) { final List members = CollectionLiterals.newArrayList(); - JvmOperation method = _jvmTypesBuilder.toMethod(format, "config" + rule.getTargetRule().getName(), _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { - it.setFinal(false); - it.setVisibility(JvmVisibility.PROTECTED); - _jvmTypesBuilder.operator_add(it.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); - AbstractRule targetRule = rule.getTargetRule(); - if (targetRule instanceof ParserRule) { - final String ruleName = getFullyQualifiedName(getGrammar(rule.getTargetRule())) + "$" + grammarAccess.gaRuleAccessorClassName(rule.getTargetRule()); - _jvmTypesBuilder.operator_add(it.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_ELEMENTS, _typeReferences.getTypeForName(ruleName, rule.getTargetRule()))); - _jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", - CollectionLiterals.newLinkedHashMap( - Pair.of(PARAMETER_CONFIG, "the format configuration"), - Pair.of(PARAMETER_ELEMENTS, "the grammar access for " + rule.getTargetRule().getName() + " elements")))); - } else if (targetRule instanceof EnumRule) { - _jvmTypesBuilder.operator_add(it.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_RULE, _typeReferences.getTypeForName(EnumRule.class.getName(), rule.getTargetRule()))); - _jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", - CollectionLiterals.newLinkedHashMap( - Pair.of(PARAMETER_CONFIG, "the format configuration"), - Pair.of(PARAMETER_RULE, "the enum rule for " + rule.getTargetRule().getName())))); - } else if (targetRule instanceof TerminalRule) { - _jvmTypesBuilder.operator_add(it.getParameters(), - _jvmTypesBuilder.toParameter(format, PARAMETER_RULE, _typeReferences.getTypeForName(TerminalRule.class.getName(), rule.getTargetRule()))); - _jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", - CollectionLiterals.newLinkedHashMap( - Pair.of(PARAMETER_CONFIG, "the format configuration"), - Pair.of(PARAMETER_RULE, "the terminal rule for " + rule.getTargetRule().getName())))); - } - _jvmTypesBuilder.setBody(it, (ITreeAppendable it_1) -> { - final List directives = ListExtensions.map(rule.getDirectives(), (EObject d) -> directive(d, getRuleName(rule)).toString()); - it_1.append(fixLastLine(IterableExtensions.join(directives))); - }); - }); + JvmOperation method = jvmTypesBuilder.toMethod(format, "config" + rule.getTargetRule().getName(), _typeReferenceBuilder.typeRef("void"), + (JvmOperation it) -> initializeRuleMethod(format, rule, it)); members.add(method); return members; } + private void initializeRuleMethod(final FormatConfiguration format, final GrammarRule rule, final JvmOperation it) { + it.setFinal(false); + it.setVisibility(JvmVisibility.PROTECTED); + jvmTypesBuilder.operator_add(it.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_CONFIG, _typeReferenceBuilder.typeRef(BASE_FORMAT_CONFIG))); + AbstractRule targetRule = rule.getTargetRule(); + if (targetRule instanceof ParserRule) { + final String ruleName = getFullyQualifiedName(getGrammar(rule.getTargetRule())) + "$" + grammarAccess.gaRuleAccessorClassName(rule.getTargetRule()); + jvmTypesBuilder.operator_add(it.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_ELEMENTS, typeReferences.getTypeForName(ruleName, rule.getTargetRule()))); + jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", + CollectionLiterals.newLinkedHashMap( + Pair.of(PARAMETER_CONFIG, THE_FORMAT_CONFIGURATION), + Pair.of(PARAMETER_ELEMENTS, "the grammar access for " + rule.getTargetRule().getName() + " elements")))); + } else if (targetRule instanceof EnumRule) { + jvmTypesBuilder.operator_add(it.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_RULE, typeReferences.getTypeForName(EnumRule.class.getName(), rule.getTargetRule()))); + jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", + CollectionLiterals.newLinkedHashMap( + Pair.of(PARAMETER_CONFIG, THE_FORMAT_CONFIGURATION), + Pair.of(PARAMETER_RULE, "the enum rule for " + rule.getTargetRule().getName())))); + } else if (targetRule instanceof TerminalRule) { + jvmTypesBuilder.operator_add(it.getParameters(), + jvmTypesBuilder.toParameter(format, PARAMETER_RULE, typeReferences.getTypeForName(TerminalRule.class.getName(), rule.getTargetRule()))); + jvmTypesBuilder.setDocumentation(it, generateJavaDoc("Configuration for " + rule.getTargetRule().getName() + ".", + CollectionLiterals.newLinkedHashMap( + Pair.of(PARAMETER_CONFIG, THE_FORMAT_CONFIGURATION), + Pair.of(PARAMETER_RULE, "the terminal rule for " + rule.getTargetRule().getName())))); + } + jvmTypesBuilder.setBody(it, (ITreeAppendable op) -> { + final List directives = ListExtensions.map(rule.getDirectives(), (EObject d) -> directive(d, getRuleName(rule)).toString()); + op.append(fixLastLine(IterableExtensions.join(directives))); + }); + } + public String fixLastLine(final String content) { if (content.endsWith("\r\n")) { return content.substring(0, content.length() - 2); @@ -762,6 +776,7 @@ public String fixLastLine(final String content) { } } + // CHECKSTYLE:CONSTANTS-OFF // directive dispatch protected CharSequence _directive(final SpecificDirective dir, final String partialName) { return matchReference(dir.getMatcherList(), dir.getGrammarElements(), partialName + getDirectiveName(dir)); @@ -777,7 +792,7 @@ protected CharSequence _directive(final GroupBlock dir, final String partialName } else if (dir.getSubGroup() != null) { return directive(dir.getSubGroup(), partialName + getDirectiveName(dir)); } else { - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_CAPACITY); for (final GrammarRuleDirective d : dir.getDirectives()) { sb.append(directive(d, partialName + getDirectiveName(dir))); } @@ -786,16 +801,16 @@ protected CharSequence _directive(final GroupBlock dir, final String partialName } protected CharSequence _directive(final KeywordPair dir, final String partialName) { - final StringBuilder sb = new StringBuilder(); - sb.append("// ").append(locatorString(dir)).append("\n"); + final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_CAPACITY); + sb.append("// ").append(locatorString(dir)).append('\n'); sb.append("for (final org.eclipse.xtext.util.Pair pair : elements.findKeywordPairs(\"").append(dir.getLeft()).append("\", \"").append(dir.getRight()).append("\")) {\n"); for (final Matcher matcher : dir.getLeftMatchers()) { sb.append(matchLookupPartial(matcher.getLocator(), matcher, "pair.getFirst()", partialName + getDirectiveName(dir))); - sb.append("\n"); + sb.append('\n'); } for (final Matcher matcher : dir.getRightMatchers()) { sb.append(matchLookupPartial(matcher.getLocator(), matcher, "pair.getSecond()", partialName + getDirectiveName(dir))); - sb.append("\n"); + sb.append('\n'); } sb.append("}\n"); return sb; @@ -822,11 +837,11 @@ public CharSequence directive(final Object dir, final String partialName) { } public CharSequence matchLookup(final MatcherList matcherList, final EList elements, final String partialName) { - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_CAPACITY); if (!elements.isEmpty()) { boolean hasRuleElements = elements.stream().anyMatch((GrammarElementLookup e) -> e.getRule() != null); if (hasRuleElements) { - sb.append("// ").append(locatorString(matcherList)).append("\n"); + sb.append("// ").append(locatorString(matcherList)).append('\n'); sb.append("for (org.eclipse.xtext.RuleCall ruleCall : elements.findRuleCalls("); boolean first = true; for (final GrammarElementLookup element : elements.stream().filter((GrammarElementLookup e) -> e.getRule() != null).toList()) { @@ -838,13 +853,13 @@ public CharSequence matchLookup(final MatcherList matcherList, final EList e.getKeyword() != null); if (hasKeywordElements) { - sb.append("// ").append(locatorString(matcherList)).append("\n"); + sb.append("// ").append(locatorString(matcherList)).append('\n'); sb.append("for (org.eclipse.xtext.Keyword keyword : elements.findKeywords("); boolean first2 = true; for (final GrammarElementLookup element : elements.stream().filter((GrammarElementLookup e) -> e.getKeyword() != null).toList()) { @@ -852,11 +867,11 @@ public CharSequence matchLookup(final MatcherList matcherList, final EList elements, final String partialName) { - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_CAPACITY); if (!elements.isEmpty()) { for (final Matcher matcher : matcherList.getMatchers()) { - if (FormatGeneratorUtil.isTwoArgumentMatcherType(matcher.getType()).booleanValue()) { + if (FormatGeneratorUtil.isTwoArgumentMatcherType(matcher.getType())) { sb.append(match(matcher, elements.get(0), elements.get(1), matcher.getLocator(), partialName)); } else { for (final EObject e : elements) { @@ -946,49 +961,49 @@ public CharSequence matchReference(final MatcherList matcherList, final EList= 1)) { + if (indentLocator.getValue() != null && (indentLocator.getValue().getReference() != null || indentLocator.getValue().getLiteral() >= 1)) { sb.append(getValueOrConstant(indentLocator.getValue())); } else if (indentLocator.getParameter() != null) { sb.append("new ").append(getParameterCalculatorName(partialName, matcher)).append("()"); } if (matcher.getCondition() != null) { if (indentLocator.getValue() != null || indentLocator.getParameter() != null) { - sb.append(","); + sb.append(','); } sb.append(" new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); } - sb.append(")"); + sb.append(')'); return sb; } protected CharSequence _locator(final Matcher matcher, final NoFormatLocator noFormatLocator, final String partialName) { - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_CAPACITY); sb.append("setNoFormat("); if (matcher.getCondition() != null) { sb.append("new ").append(getLocatorActivatorName(partialName, matcher)).append("()"); } - sb.append(")"); + sb.append(')'); return sb; } @@ -1252,6 +1267,8 @@ public CharSequence locator(final Matcher matcher, final Locator columnLocator, } } + // CHECKSTYLE:CONSTANTS-ON + // getValueOrConstant dispatch protected String _getValueOrConstant(final StringValue stringValue) { if (stringValue.getLiteral() == null) { @@ -1286,10 +1303,8 @@ public String locatorString(final EObject object) { public void infer(final EObject format, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase) { if (format instanceof FormatConfiguration formatConfiguration) { _infer(formatConfiguration, acceptor, isPreIndexingPhase); - return; } else if (format != null) { _infer(format, acceptor, isPreIndexingPhase); - return; } else { throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(format, acceptor, isPreIndexingPhase).toString()); } diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.java index 6950e6ec53..ef753ff133 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.java +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/scoping/FormatScopeProvider.java @@ -45,6 +45,7 @@ /** * The scope provider for the Format language. */ +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class FormatScopeProvider extends AbstractFormatScopeProvider { @Inject @@ -56,6 +57,12 @@ public class FormatScopeProvider extends AbstractFormatScopeProvider { /** * Provides a scope for given context and reference. * If there is no specific scoping method or if there is such a method but it cannot return a scope, the super class method is called. + * + * @param context + * the context object + * @param reference + * the reference + * @return the scope for the given context and reference */ @Override public IScope getScope(final EObject context, final EReference reference) { @@ -68,9 +75,13 @@ public IScope getScope(final EObject context, final EReference reference) { /** * For a given grammar returns the grammar on which it is based, and transitively all base grammars for that grammar. + * + * @param context + * the grammar + * @return all used grammars including the given one */ public Iterable getUsedGrammar(final Grammar context) { - final LinkedList grammars = new LinkedList<>(); + final List grammars = new LinkedList<>(); grammars.add(context); final EList usedGrammars = EcoreUtil2.getContainerOfType(context, Grammar.class).getUsedGrammars(); if (usedGrammars != null && !usedGrammars.isEmpty()) { @@ -81,9 +92,13 @@ public Iterable getUsedGrammar(final Grammar context) { /** * For a given formatter returns the grammar on which it is based, and transitively all base grammars for that grammar. + * + * @param context + * the context object + * @return the collection of grammars */ public Collection getGrammars(final EObject context) { - final LinkedList grammars = new LinkedList<>(); + final List grammars = new LinkedList<>(); final FormatConfiguration format = EcoreUtil2.getContainerOfType(context, FormatConfiguration.class); if (format != null && format.getTargetGrammar() != null) { grammars.add(format.getTargetGrammar()); @@ -95,9 +110,13 @@ public Collection getGrammars(final EObject context) { /** * For a given {@link FormatConfiguration} returns transitively all extending format configurations. * Usage of LinkedList for {@code formats} does not prevent against duplication of grammars, but a HashSet cannot be used here as there won't be possible to recover the overriding order. + * + * @param context + * the format configuration + * @return all format configurations including the given one and its extensions */ public Collection getFormats(final FormatConfiguration context) { - final LinkedList formats = new LinkedList<>(); + final List formats = new LinkedList<>(); final FormatConfiguration format = context; if (format != null) { formats.add(format); @@ -110,6 +129,10 @@ public Collection getFormats(final FormatConfiguration cont /** * In order to ensure the correct path of inheritance/overriding the list of the grammars has to be reversed. + * + * @param context + * the context object + * @return the list of grammars in hierarchy order */ public List getHierarchyOrderedGrammars(final EObject context) { return Lists.reverse(Lists.newArrayList(getGrammars(context))); @@ -117,6 +140,10 @@ public List getHierarchyOrderedGrammars(final EObject context) { /** * In order to ensure the correct path of inheritance/overriding the list of the format configurations has to be reversed. + * + * @param context + * the context object + * @return the list of format configurations in hierarchy order */ public List getHierarchyOrderedFormats(final EObject context) { return Lists.reverse(Lists.newArrayList(getFormats(EcoreUtil2.getContainerOfType(context, FormatConfiguration.class)))); @@ -124,6 +151,12 @@ public List getHierarchyOrderedFormats(final EObject contex /** * Creates scopes for a given list of rules for each grammar. Returned scopes are chained (parental relationships). + * + * @param parent + * the parent scope, may be {@code null} + * @param rulesForGrammars + * the rules for each grammar + * @return the chained scope */ public IScope createScopeForAbstractRules(final IScope parent, final Iterable> rulesForGrammars) { if (parent == null) { @@ -143,6 +176,12 @@ public IScope createScopeForAbstractRules(final IScope parent, final Iterable + * the element type + * @param elements + * the list of elements + * @return the scope */ public IScope createScopeForEObjects(final List elements) { return MapBasedScope.createScope(IScope.NULLSCOPE, createDescriptions(elements)); @@ -150,6 +189,10 @@ public IScope createScopeForEObjects(final List elements) /** * Creates a simple scope for a given object description. + * + * @param description + * the object description + * @return the simple scope */ public SimpleScope createSimpleScope(final IEObjectDescription description) { return new SimpleScope(IScope.NULLSCOPE, ImmutableList.of(description)); @@ -157,6 +200,10 @@ public SimpleScope createSimpleScope(final IEObjectDescription description) { /** * Creates a scope for a given list of compound elements. + * + * @param compoundElements + * the list of compound elements + * @return the scope */ public IScope createScopeForCompoundElements(final List compoundElements) { return MapBasedScope.createScope(IScope.NULLSCOPE, createDescriptionsForCompoundElements(compoundElements)); @@ -237,6 +284,13 @@ protected IScope _scope(final EObject context, final EReference reference) { /** * Dispatch method for scope resolution based on runtime type of context. + * + * @param context + * the context object + * @param reference + * the reference + * @return the scope, or {@code null} if no specific scope applies + * @throws IllegalArgumentException if the context type is not handled */ public IScope scope(final EObject context, final EReference reference) { if (context instanceof GrammarRule grammarRule) { @@ -255,6 +309,10 @@ public IScope scope(final EObject context, final EReference reference) { /** * Creates object descriptions for a given list of {@link FormatConfiguration}. + * + * @param elements + * the list of format configurations + * @return the collection of object descriptions */ public Collection createDescriptionsFormats(final List elements) { return Collections2.transform(elements, (FormatConfiguration e) -> EObjectDescription.create(scopeUtil.findTargetGrammar(e).getName(), e)); @@ -262,6 +320,10 @@ public Collection createDescriptionsFormats(final List
createDescriptions(final List elements) { final Function namingFunction = nameProvider.getIndexParameterNameFunction(elements); @@ -270,6 +332,10 @@ public Collection createDescriptions(final List createDescriptionsForCompoundElements(final List elements) { final Function namingFunction = nameProvider.getIndexNameFunction(elements); diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.java index bf71fd5494..7777e02b82 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.java +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/validation/FormatValidator.java @@ -14,7 +14,10 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Set; import org.eclipse.emf.ecore.EObject; import org.eclipse.osgi.util.NLS; @@ -193,7 +196,7 @@ public void checkOverrideMissing(final FormatConfiguration model) { } final Iterable nonOverrideRules = Iterables.filter(model.getRules(), Predicates.not(IS_OVERRIDE)); final Iterable overriddenRules = collectRules(extendedModel); - final HashMap localAbstractRuleMap = Maps.newHashMap(); + final Map localAbstractRuleMap = Maps.newHashMap(); for (final GrammarRule rule : Iterables.filter(nonOverrideRules, GrammarRule.class)) { localAbstractRuleMap.put(TARGET_RULE.apply(rule), rule); } @@ -225,7 +228,7 @@ public void checkIllegalOverride(final FormatConfiguration model) { if (extendedModel != null && !extendedModel.eIsProxy()) { overrideableRules = collectRules(extendedModel); } - final HashMap overrideableAbstractRuleMap = Maps.newHashMap(); + final Map overrideableAbstractRuleMap = Maps.newHashMap(); for (final GrammarRule rule : Iterables.filter(overrideableRules, GrammarRule.class)) { overrideableAbstractRuleMap.put(TARGET_RULE.apply(rule), rule); } @@ -255,7 +258,7 @@ public void checkExtendedGrammarCompatible(final FormatConfiguration model) { return; } if (!extendedModel.getTargetGrammar().eIsProxy()) { - final ArrayList grammars = Lists.newArrayList(model.getTargetGrammar()); + final List grammars = Lists.newArrayList(model.getTargetGrammar()); grammars.addAll(model.getTargetGrammar().getUsedGrammars()); for (final Grammar grammar : grammars) { if (extendedModel.getTargetGrammar().getName().equals(grammar.getName())) { @@ -280,7 +283,7 @@ public void checkRequiredRulesImplemented(final FormatConfiguration model) { return; } final Iterable inheritedRules = Iterables.filter(collectRules(extendedModel), GrammarRule.class); - final HashSet ruleNames = Sets.newHashSet(Iterables.transform(inheritedRules, new Function() { + final Set ruleNames = Sets.newHashSet(Iterables.transform(inheritedRules, new Function() { @Override public String apply(final GrammarRule from) { return from.getTargetRule().getName(); diff --git a/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java b/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java index 996abe7652..829c2197ee 100644 --- a/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java +++ b/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java @@ -50,19 +50,16 @@ public class TemplateProposalProviderHelperTest { private static final String CONTEXT_TYPE_ID = "context.type.ID"; private static final boolean IS_AUTO_INSERTABLE = true; - private static IDocument mockDocument; - private static Position mockPosition; - private static IRegion mockRegion; - private static XtextTemplateContext templateContext; private static TemplateProposalProviderHelper helper; @BeforeAll + @SuppressWarnings("PMD.SignatureDeclareThrowsException") public void beforeAll() throws Exception { - mockDocument = mock(IDocument.class); - mockPosition = mock(Position.class); - mockRegion = mock(IRegion.class); + final IDocument mockDocument = mock(IDocument.class); + final Position mockPosition = mock(Position.class); + final IRegion mockRegion = mock(IRegion.class); final XtextTemplateContextType templateContextType = new XtextTemplateContextType(); templateContextType.addResolver(new SimpleEnumTemplateVariableResolver()); @@ -76,15 +73,12 @@ public void beforeAll() throws Exception { @AfterAll public void afterAll() { - mockDocument = null; - mockPosition = null; - mockRegion = null; - templateContext = null; helper = null; } + // CHECKSTYLE:CONSTANTS-OFF @Test public void testCreateLiteralValuePatternWithNullName() { assertThrows(NullPointerException.class, () -> helper.createLiteralValuePattern(null, 42)); @@ -173,55 +167,55 @@ public void testCreateTemplateVariablePatternWithNoValues() { @Test public void testCreateTemplateVariablePatternWithFalse() { - testCreateTemplateVariablePattern(new Object[]{false}, "false", new String[]{"false", "true"}); + testCreateTemplateVariablePattern(new Object[]{false}, "false", "false", "true"); } @Test public void testCreateTemplateVariablePatternWithTrue() { - testCreateTemplateVariablePattern(new Object[]{true}, "true", new String[]{"true", "false"}); + testCreateTemplateVariablePattern(new Object[]{true}, "true", "true", "false"); } @Test public void testCreateTemplateVariablePatternWithMultipleBooleans() { - testCreateTemplateVariablePattern(new Object[]{false, false, true}, "false", new String[]{"false", "false", "true"}); + testCreateTemplateVariablePattern(new Object[]{false, false, true}, "false", "false", "false", "true"); } @Test public void testCreateTemplateVariablePatternWithNumber() { - testCreateTemplateVariablePattern(new Object[]{42}, "42", new String[]{"42"}); + testCreateTemplateVariablePattern(new Object[]{42}, "42", "42"); } @Test public void testCreateTemplateVariablePatternWithMultipleNumbers() { - testCreateTemplateVariablePattern(new Object[]{1297, 1314}, "1297", new String[]{"1297", "1314"}); + testCreateTemplateVariablePattern(new Object[]{1297, 1314}, "1297", "1297", "1314"); } @Test public void testCreateTemplateVariablePatternWithString() { testCreateTemplateVariablePattern(new Object[]{"Supercalifragilisticexpialidocious"}, "Supercalifragilisticexpialidocious", - new String[]{"Supercalifragilisticexpialidocious"}); + "Supercalifragilisticexpialidocious"); } @Test public void testCreateTemplateVariablePatternWithEmptyString() { - testCreateTemplateVariablePattern(new Object[]{""}, "", new String[]{""}); + testCreateTemplateVariablePattern(new Object[]{""}, "", ""); } @Test public void testCreateTemplateVariablePatternWithStringContainingWhitespace() { testCreateTemplateVariablePattern(new Object[]{"Lorem ipsum dolor sit amet"}, "Lorem ipsum dolor sit amet", - new String[]{"Lorem ipsum dolor sit amet"}); + "Lorem ipsum dolor sit amet"); } @Test public void testCreateTemplateVariablePatternWithStringContainingSingleQuotes() { - testCreateTemplateVariablePattern(new Object[]{"Apostrophe's"}, "Apostrophe's", new String[]{"Apostrophe's"}); + testCreateTemplateVariablePattern(new Object[]{"Apostrophe's"}, "Apostrophe's", "Apostrophe's"); } @Test public void testCreateTemplateVariablePatternWithStringContainingDoubleQuotes() { testCreateTemplateVariablePattern(new Object[]{"CHAIN \"CHUCKIE\""}, "CHAIN \\\"CHUCKIE\\\"", - new String[]{"CHAIN \\\"CHUCKIE\\\""}); + "CHAIN \\\"CHUCKIE\\\""); } @Test @@ -229,7 +223,7 @@ public void testCreateTemplateVariablePatternWithStringContainingWhitespaceAndSi testCreateTemplateVariablePattern( new Object[]{"\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\" - Dr Johnson"}, "\\\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\\\" - Dr Johnson", - new String[]{"\\\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\\\" - Dr Johnson"}); + "\\\"Whoever thinks of going to bed before twelve o'clock is a scoundrel\\\" - Dr Johnson"); } @Test @@ -237,8 +231,8 @@ public void testCreateTemplateVariablePatternWithMultipleStrings() { testCreateTemplateVariablePattern( new Object[]{"Twas brillig and the slithy toves", "Did gyre and gimble in the wabe", "All mimsy were the borogroves", "And the mome raths outgrabe"}, "Twas brillig and the slithy toves", - new String[]{"Twas brillig and the slithy toves", "Did gyre and gimble in the wabe", "All mimsy were the borogroves", - "And the mome raths outgrabe"}); + "Twas brillig and the slithy toves", "Did gyre and gimble in the wabe", "All mimsy were the borogroves", + "And the mome raths outgrabe"); } /** @@ -248,7 +242,7 @@ public void testCreateTemplateVariablePatternWithMultipleStrings() { * @param expectedResult expected result of applying a template containing the pattern, may be {@code null} * @param expectedValues expected values offered by a template containing the pattern, may be {@code null} */ - private void testCreateTemplateVariablePattern(final Object[] values, final String expectedResult, final String[] expectedValues) { + private void testCreateTemplateVariablePattern(final Object[] values, final String expectedResult, final String... expectedValues) { try { // ACT final String pattern = helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, values); @@ -264,8 +258,9 @@ private void testCreateTemplateVariablePattern(final Object[] values, final Stri assertEquals(expectedResult, actualResult, "Expected result"); assertArrayEquals(expectedValues, actualValues, "Expected values"); } catch (Exception e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } } + // CHECKSTYLE:CONSTANTS-ON } diff --git a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.java b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.java index b5735d6ca9..0f1ae51d3a 100644 --- a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.java +++ b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelper.java @@ -33,8 +33,8 @@ public class TemplateProposalProviderHelper { * @param name the name of the variable, may not be {@code null} nor contain whitespace * @param defaultValue default value, may be {@code null} * @return pattern, never {@code null} - * @throws {@link NullPointerException} if name is null - * @throws {@link IllegalArgumentException} if name contains whitespace + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name contains whitespace */ public String createLiteralValuePattern(final String name, final Object defaultValue) throws NullPointerException, IllegalArgumentException { final String pattern = createTemplateVariablePattern(SIMPLE_ENUM_TYPE, name, defaultValue); @@ -54,8 +54,8 @@ public String createLiteralValuePattern(final String name, final Object defaultV * @param name the name of the variable, may not be {@code null} nor contain whitespace * @param values the values available at this variable, may not be {@code null} nor empty * @return pattern, never {@code null} - * @throws {@link NullPointerException} if type, name or values is null - * @throws {@link IllegalArgumentException} if type or name contains whitespace or values is empty + * @throws NullPointerException if type, name or values is null + * @throws IllegalArgumentException if type or name contains whitespace or values is empty */ public String createTemplateVariablePattern(final String type, final String name, final Object... values) throws NullPointerException, IllegalArgumentException { Objects.requireNonNull(type); From cfbd1f4bdfbd5b65fbaf3b8933855ffba0da8fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 14:39:08 +0100 Subject: [PATCH 13/23] style: fix remaining CI violations (SpotBugs, PMD) - Remove superfluous instanceof check in CodeGenerationX - Simplify inferConstants boolean return in FormatJvmModelInferrer - Add @Override on infer() dispatch method - Cast null to Object[] to clarify varargs intent in test Co-Authored-By: Claude Opus 4.6 --- .../ddk/xtext/expression/generator/CodeGenerationX.java | 2 +- .../xtext/format/jvmmodel/FormatJvmModelInferrer.java | 9 ++++----- .../ui/templates/TemplateProposalProviderHelperTest.java | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java index f98c104e0f..5f4dda5c11 100644 --- a/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java +++ b/com.avaloq.tools.ddk.xtext.expression/src/com/avaloq/tools/ddk/xtext/expression/generator/CodeGenerationX.java @@ -450,7 +450,7 @@ public boolean requiresBracketing(final Expression it, final Object parent, fina return _requiresBracketing(operationCall, parentOp, ctx); } else if (it instanceof BooleanOperation boolOp && parent instanceof BooleanOperation parentBool) { return _requiresBracketing(boolOp, parentBool, ctx); - } else if (it instanceof Expression && parent instanceof Expression parentExpr) { + } else if (parent instanceof Expression parentExpr) { return _requiresBracketingWithExpression(it, parentExpr, ctx); } else { return _requiresBracketingWithObject(it, parent, ctx); diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java index 21cf44a349..356cd007d7 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java @@ -213,11 +213,9 @@ public void inferClass(final FormatConfiguration format, final JvmGenericType it } public boolean inferConstants(final FormatConfiguration format, final JvmGenericType it) { - if (!FormatGeneratorUtil.getAllConstants(format).isEmpty()) { - return jvmTypesBuilder.operator_add(it.getMembers(), - ListExtensions.map(FormatGeneratorUtil.getAllConstants(format), (Constant c) -> createConstant(format, c))); - } - return false; + return !FormatGeneratorUtil.getAllConstants(format).isEmpty() + && jvmTypesBuilder.operator_add(it.getMembers(), + ListExtensions.map(FormatGeneratorUtil.getAllConstants(format), (Constant c) -> createConstant(format, c))); } public String getFullyQualifiedName(final Grammar g) { @@ -1300,6 +1298,7 @@ public String locatorString(final EObject object) { return IterableExtensions.lastOrNull((Iterable) Conversions.doWrapArray(getFileLocation(object).split("/"))); } + @Override public void infer(final EObject format, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase) { if (format instanceof FormatConfiguration formatConfiguration) { _infer(formatConfiguration, acceptor, isPreIndexingPhase); diff --git a/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java b/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java index 829c2197ee..b0f3549ce6 100644 --- a/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java +++ b/com.avaloq.tools.ddk.xtext.ui.test/src/com/avaloq/tools/ddk/xtext/ui/templates/TemplateProposalProviderHelperTest.java @@ -157,7 +157,7 @@ public void testCreateTemplateVariablePatternWithNameContainingWhitespace() { @Test public void testCreateTemplateVariablePatternWithNull() { - assertThrows(NullPointerException.class, () -> helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, null)); + assertThrows(NullPointerException.class, () -> helper.createTemplateVariablePattern(SIMPLE_ENUM_VARIABLE_TYPE, VARIABLE_NAME, (Object[]) null)); } @Test From 3d34c1bdf7cac0a7789e28f016f3d8294601ae60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 16:47:34 +0100 Subject: [PATCH 14/23] style: resolve all PMD and checkstyle warnings in generator, scope, and export modules Co-Authored-By: Claude Opus 4.6 --- .../ExportFeatureExtensionGenerator.java | 31 +- .../export/generator/ExportGenerator.java | 12 +- .../export/generator/ExportGeneratorX.java | 107 +- .../ExportedNamesProviderGenerator.java | 30 +- .../FingerprintComputerGenerator.java | 65 +- .../generator/FragmentProviderGenerator.java | 35 +- ...ResourceDescriptionConstantsGenerator.java | 11 +- .../ResourceDescriptionManagerGenerator.java | 19 +- .../ResourceDescriptionStrategyGenerator.java | 60 +- .../BundleVersionStripperFragment.java | 1 - .../DefaultFragmentWithOverride.java | 9 +- .../builder/BuilderIntegrationFragment2.java | 2 +- .../LspBuilderIntegrationFragment2.java | 68 +- ...StandaloneBuilderIntegrationFragment2.java | 66 +- .../formatting/FormatterFragment2.java | 22 +- .../LanguageConstantsFragment2.java | 14 +- ...tAnnotationAwareAntlrGrammarGenerator.java | 74 +- ...areAntlrContentAssistGrammarGenerator.java | 2097 ++++++++--------- .../AnnotationAwareAntlrGrammarGenerator.java | 1729 +++++++------- ...tionAwareXtextAntlrGeneratorFragment2.java | 1155 ++++----- .../parser/common/GrammarRuleAnnotations.java | 33 +- .../ResourceFactoryFragment2.java | 20 +- .../ui/compare/CompareFragment2.java | 8 +- ...AnnotationAwareContentAssistFragment2.java | 112 +- .../generator/util/AcfKeywordHelper.java | 4 +- .../util/CustomClassAwareEcoreGenerator.java | 4 +- .../xtext/generator/util/StandaloneSetup.java | 2 +- .../generator/ScopeNameProviderGenerator.java | 149 +- .../generator/ScopeProviderGenerator.java | 295 ++- .../xtext/scope/generator/ScopeProviderX.java | 242 +- 30 files changed, 3357 insertions(+), 3119 deletions(-) diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.java index b5e4de83a1..ca118a2da5 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFeatureExtensionGenerator.java @@ -17,6 +17,7 @@ import com.google.inject.Inject; +@SuppressWarnings("PMD.UnusedFormalParameter") public class ExportFeatureExtensionGenerator { @Inject @@ -26,68 +27,70 @@ public class ExportFeatureExtensionGenerator { private ExportGeneratorX exportGeneratorX; public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { - final StringBuilder sb = new StringBuilder(); + // CHECKSTYLE:CONSTANTS-OFF + final StringBuilder sb = new StringBuilder(2048); sb.append("package "); sb.append(naming.toJavaPackage(exportGeneratorX.getExportFeatureExtension(it))); sb.append(";\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import org.eclipse.xtext.naming.IQualifiedNameProvider;\n"); sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractExportFeatureExtension;\n"); sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractResourceDescriptionStrategy;\n"); sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractSelectorFragmentProvider;\n"); sb.append("import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer;\n"); sb.append("import com.google.inject.Inject;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import "); sb.append(exportGeneratorX.getExportedNamesProvider(it)); sb.append(";\n"); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("public class "); sb.append(naming.toSimpleName(exportGeneratorX.getExportFeatureExtension(it))); sb.append(" extends AbstractExportFeatureExtension {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Inject\n"); sb.append(" private "); sb.append(naming.toSimpleName(exportGeneratorX.getExportedNamesProvider(it))); sb.append(" namesProvider;\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Inject\n"); sb.append(" private "); sb.append(naming.toSimpleName(exportGeneratorX.getFingerprintComputer(it))); sb.append(" fingerprintComputer;\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Inject\n"); sb.append(" private "); sb.append(naming.toSimpleName(exportGeneratorX.getFragmentProvider(it))); sb.append(" fragmentProvider;\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Inject\n"); sb.append(" private "); sb.append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionStrategy(it))); sb.append(" resourceDescriptionStrategy;\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" protected IQualifiedNameProvider getNamesProvider() {\n"); sb.append(" return namesProvider;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" protected IFingerprintComputer getFingerprintComputer() {\n"); sb.append(" return fingerprintComputer;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" protected AbstractSelectorFragmentProvider getFragmentProvider() {\n"); sb.append(" return fragmentProvider;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" protected AbstractResourceDescriptionStrategy getResourceDescriptionStrategy() {\n"); sb.append(" return resourceDescriptionStrategy;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append("}\n"); + // CHECKSTYLE:CONSTANTS-ON return sb; } diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java index c035776298..460b277f79 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java @@ -112,15 +112,17 @@ public void generateFragmentProvider(final ExportModel model, final IFileSystemA if (model.getExports().stream().anyMatch(e -> e.isFingerprint() && e.getFragmentAttribute() != null) || model.isExtension()) { fsa.generateFile(fileName, fragmentProviderGenerator.generate(model, compilationContext, genModelUtil)); } else if (!model.getExports().isEmpty()) { - final StringBuilder sb = new StringBuilder(); + // CHECKSTYLE:CONSTANTS-OFF + final StringBuilder sb = new StringBuilder(512); sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getFragmentProvider(model))).append(";\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.xtext.linking.ShortFragmentProvider;\n"); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getFragmentProvider(model))).append(" extends ShortFragmentProvider {\n"); - sb.append("\n"); + sb.append('\n'); sb.append("}\n"); + // CHECKSTYLE:CONSTANTS-ON fsa.generateFile(fileName, sb); } } diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.java index d459f56c44..cb19aec7c6 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGeneratorX.java @@ -33,17 +33,20 @@ import com.google.inject.Inject; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class ExportGeneratorX { + private static final int URI_PACKAGE_START_INDEX = 3; + @Inject private Naming naming; - public String getName(ExportModel model) { + public String getName(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); return uri.trimFileExtension().lastSegment(); } - public Grammar getGrammar(ExportModel model) { + public Grammar getGrammar(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); // Grammar should be set correctly for export extensions, not yet for normal export sources if (model.getTargetGrammar() != null) { @@ -56,56 +59,60 @@ public Grammar getGrammar(ExportModel model) { : null; } - public String getExportedNamesProvider(ExportModel model) { + public String getExportedNamesProvider(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".naming." + getName(model) + "ExportedNamesProvider"; + return String.join(".", uri.segmentsList().subList(URI_PACKAGE_START_INDEX, uri.segmentCount() - 1)) + ".naming." + getName(model) + "ExportedNamesProvider"; } - public String getResourceDescriptionManager(ExportModel model) { + public String getResourceDescriptionManager(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionManager"; + return String.join(".", uri.segmentsList().subList(URI_PACKAGE_START_INDEX, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionManager"; } - public String getResourceDescriptionManager(Grammar grammar) { + public String getResourceDescriptionManager(final Grammar grammar) { return naming.toJavaPackage(grammar.getName()) + ".resource." + naming.toSimpleName(grammar.getName()) + "ResourceDescriptionManager"; } - public String getResourceDescriptionStrategy(ExportModel model) { + public String getResourceDescriptionStrategy(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionStrategy"; + return String.join(".", uri.segmentsList().subList(URI_PACKAGE_START_INDEX, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionStrategy"; } - public String getResourceDescriptionConstants(ExportModel model) { + public String getResourceDescriptionConstants(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionConstants"; + return String.join(".", uri.segmentsList().subList(URI_PACKAGE_START_INDEX, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionConstants"; } - public String getFingerprintComputer(ExportModel model) { + public String getFingerprintComputer(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FingerprintComputer"; + return String.join(".", uri.segmentsList().subList(URI_PACKAGE_START_INDEX, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FingerprintComputer"; } - public String getFragmentProvider(ExportModel model) { + public String getFragmentProvider(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); // TODO this is a hack; to support modularization we should probably add name to export models (as with scope models) - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FragmentProvider"; + return String.join(".", uri.segmentsList().subList(URI_PACKAGE_START_INDEX, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FragmentProvider"; } - public String getExportFeatureExtension(ExportModel model) { + public String getExportFeatureExtension(final ExportModel model) { final org.eclipse.emf.common.util.URI uri = model.eResource().getURI(); // TODO we still need to add a package to the models. Extension models already have a name in contrast to cases above - return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + model.getName() + "ExportFeatureExtension"; + return String.join(".", uri.segmentsList().subList(URI_PACKAGE_START_INDEX, uri.segmentCount() - 1)) + ".resource." + model.getName() + "ExportFeatureExtension"; } /** * Return the export specification for a type's supertype, if any, or null otherwise. + * + * @param it + * the export specification + * @return the export specification for the supertype, or {@code null} */ - public Export superType(Export it) { + public Export superType(final Export it) { if (it.getType().getESuperTypes().isEmpty()) { return null; } else { @@ -115,8 +122,14 @@ public Export superType(Export it) { /** * Return the export specification for a given type. + * + * @param it + * the export model + * @param type + * the type to look for + * @return the matching export, or {@code null} */ - public Export exportForType(ExportModel it, EClassifier type) { + public Export exportForType(final ExportModel it, final EClassifier type) { return it.getExports().stream() .filter(c -> c.getType().getName().equals(type.getName()) && c.getType().getEPackage().getNsURI().equals(type.getEPackage().getNsURI())) .findFirst() @@ -127,8 +140,14 @@ public Export exportForType(ExportModel it, EClassifier type) { * Return a combined list of all user data specifications; including those on supertypes. * *

Public dispatcher for the dispatch methods.

+ * + * @param it + * the export or {@code null} + * @return combined list of user data + * @throws IllegalArgumentException + * if the parameter type is not handled */ - public List allUserData(Object it) { + public List allUserData(final Object it) { if (it instanceof Export e) { return _allUserData(e); } else if (it == null) { @@ -140,8 +159,12 @@ public List allUserData(Object it) { /** * Return a combined list of all user data specifications; including those on supertypes. + * + * @param it + * the export + * @return combined list of user data */ - protected List _allUserData(Export it) { + protected List _allUserData(final Export it) { final List result = allUserData(superType(it)); result.addAll(it.getUserData()); return result; @@ -149,15 +172,25 @@ protected List _allUserData(Export it) { /** * Sentinel for the above. + * + * @param it + * unused sentinel parameter + * @return empty list */ - protected List _allUserData(Void it) { + protected List _allUserData(final Void it) { return new ArrayList<>(); } /** * Return all the interface specification for the supertypes of a type. + * + * @param it + * the interface specification + * @param type + * the EClass type + * @return list of super interfaces */ - public List getSuperInterfaces(Interface it, EClass type) { + public List getSuperInterfaces(final Interface it, final EClass type) { if (type.getESuperTypes().isEmpty()) { return new ArrayList<>(); } else { @@ -167,8 +200,14 @@ public List getSuperInterfaces(Interface it, EClass type) { /** * Return all interface specifications that apply to a certain type; including those that are defined for supertypes. + * + * @param it + * the export model + * @param type + * the EClass type + * @return list of matching interfaces */ - public List getInterfacesForType(ExportModel it, EClass type) { + public List getInterfacesForType(final ExportModel it, final EClass type) { final List filtered = it.getInterfaces().stream() .filter(f -> f.getType() == type) .collect(java.util.stream.Collectors.toList()); @@ -181,15 +220,27 @@ public List getInterfacesForType(ExportModel it, EClass type) { /** * Returns a constant name for an Attribute field. + * + * @param attribute + * the attribute + * @param exportType + * the export type + * @return the constant name */ - public String constantName(EAttribute attribute, EClass exportType) { + public String constantName(final EAttribute attribute, final EClass exportType) { return (GenModelUtil2.format(exportType.getName()) + "__" + GenModelUtil2.format(attribute.getName())).toUpperCase(); } /** * Returns a constant name for a UserData field. + * + * @param data + * the user data + * @param exportType + * the export type + * @return the constant name */ - public String constantName(UserData data, EClass exportType) { + public String constantName(final UserData data, final EClass exportType) { return (GenModelUtil2.format(exportType.getName()) + "__" + GenModelUtil2.format(data.getName())).toUpperCase(); } @@ -200,7 +251,7 @@ public String constantName(UserData data, EClass exportType) { * exports to sort * @return sorted map of all exports */ - public ListMultimap sortedExportsByEPackage(Collection exports) { + public ListMultimap sortedExportsByEPackage(final Collection exports) { return EClassComparator.sortedEPackageGroups(exports, e -> e.getType()); } @@ -213,7 +264,7 @@ public ListMultimap sortedExportsByEPackage(Collection * Xtext grammar * @return mappings */ - public Map typeMap(Collection exports, Grammar grammar) { + public Map typeMap(final Collection exports, final Grammar grammar) { return GeneratorUtil.typeMap(exports, grammar, e -> e.getType()); } } diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.java index 4ec9f4e776..e585f7caa3 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportedNamesProviderGenerator.java @@ -44,17 +44,18 @@ public class ExportedNamesProviderGenerator { public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { final Grammar grammar = exportGeneratorX.getGrammar(it); - final StringBuilder sb = new StringBuilder(); + // CHECKSTYLE:CONSTANTS-OFF + final StringBuilder sb = new StringBuilder(2048); sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getExportedNamesProvider(it))).append(";\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import org.eclipse.emf.ecore.EClass;\n"); sb.append("import org.eclipse.emf.ecore.EObject;\n"); sb.append("import org.eclipse.emf.ecore.EPackage;\n"); sb.append("import org.eclipse.xtext.naming.QualifiedName;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.xtext.naming.AbstractExportedNameProvider;\n"); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("/**\n"); sb.append(" * Qualified name provider for grammar "); String grammarName = grammar != null ? grammar.getName() : null; @@ -62,7 +63,7 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, sb.append(" providing the qualified names for exported objects.\n"); sb.append(" */\n"); sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getExportedNamesProvider(it))).append(" extends AbstractExportedNameProvider {\n"); - sb.append("\n"); + sb.append('\n'); if (!it.getExports().isEmpty()) { final List types = it.getExports(); sb.append(" @Override\n"); @@ -79,12 +80,10 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, sb.append(" int classifierID = eClass.getClassifierID();\n"); sb.append(" switch (classifierID) {\n"); for (EClassifier classifier : p.getEClassifiers()) { - if (classifier instanceof EClass c) { - if (exportedEClasses.stream().anyMatch(e -> e.isSuperTypeOf(c))) { - sb.append(" case ").append(genModelUtil.classifierIdLiteral(c)).append(": {\n"); - sb.append(" return qualifiedName((").append(genModelUtil.instanceClassName(c)).append(") object);\n"); - sb.append(" }\n"); - } + if (classifier instanceof EClass c && exportedEClasses.stream().anyMatch(e -> e.isSuperTypeOf(c))) { + sb.append(" case ").append(genModelUtil.classifierIdLiteral(c)).append(": {\n"); + sb.append(" return qualifiedName((").append(genModelUtil.instanceClassName(c)).append(") object);\n"); + sb.append(" }\n"); } } sb.append(" default:\n"); @@ -94,7 +93,7 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, } sb.append(" return null;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); for (Export c : types) { sb.append(" /**\n"); sb.append(" * Return the qualified name under which a ").append(c.getType().getName()).append(" object is exported, or null if the object should not be exported.\n"); @@ -104,7 +103,7 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, sb.append(" * @return The object's qualified name, or null if the object is not to be exported\n"); sb.append(" */\n"); sb.append(" protected QualifiedName qualifiedName(final ").append(genModelUtil.instanceClassName(c.getType())).append(" obj) {\n"); - sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c))).append("\n"); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c))).append('\n'); if (c.getNaming() != null) { sb.append(" final Object name = ").append(codeGenerationX.javaExpression(c.getNaming(), ctx.clone("obj", c.getType()))).append(";\n"); sb.append(" return name != null ? "); @@ -124,10 +123,11 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, sb.append("; // \"name\" attribute by default\n"); } sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); } } sb.append("}\n"); + // CHECKSTYLE:CONSTANTS-ON return sb; } } diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.java index b466720964..0afc973a09 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FingerprintComputerGenerator.java @@ -31,6 +31,7 @@ import com.google.inject.Inject; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class FingerprintComputerGenerator { @Inject @@ -42,33 +43,34 @@ public class FingerprintComputerGenerator { @Inject private ExportGeneratorX exportGeneratorX; - public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUtilX genModelUtil) { - final StringBuilder sb = new StringBuilder(); + public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { + // CHECKSTYLE:CONSTANTS-OFF + final StringBuilder sb = new StringBuilder(2048); sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getFingerprintComputer(it))).append(";\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import org.eclipse.emf.ecore.EObject;\n"); if (!it.getInterfaces().isEmpty()) { sb.append("import org.eclipse.emf.ecore.EPackage;\n"); sb.append("import org.eclipse.emf.ecore.util.Switch;\n"); } - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractStreamingFingerprintComputer;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.google.common.hash.Hasher;\n"); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getFingerprintComputer(it))).append(" extends AbstractStreamingFingerprintComputer {\n"); - sb.append("\n"); + sb.append('\n'); if (it.getInterfaces().isEmpty()) { sb.append(" // no fingerprint defined\n"); sb.append(" @Override\n"); sb.append(" public String computeFingerprint(final org.eclipse.emf.ecore.resource.Resource resource) {\n"); sb.append(" return null;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); } - sb.append(" private ThreadLocal hasherAccess = new ThreadLocal();\n"); - sb.append("\n"); + sb.append(" private final ThreadLocal hasherAccess = new ThreadLocal();\n"); + sb.append('\n'); final Set packages = it.getInterfaces().stream() .map(f -> f.getType().getEPackage()) @@ -83,8 +85,8 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti .filter(f -> f.getType().getEPackage() == p) .collect(Collectors.toList()); for (Interface f : interfacesForPackage) { - sb.append("\n"); - sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(f))).append("\n"); + sb.append('\n'); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(f))).append('\n'); sb.append(" @Override\n"); sb.append(" public Hasher case").append(f.getType().getName()).append("(final ").append(genModelUtil.instanceClassName(f.getType())).append(" obj) {\n"); sb.append(" final Hasher hasher = hasherAccess.get();\n"); @@ -107,11 +109,11 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti sb.append(" }\n"); } sb.append(" };\n"); - sb.append("\n"); + sb.append('\n'); } sb.append(" @Override\n"); - sb.append(" protected void fingerprint(final EObject object, Hasher hasher) {\n"); + sb.append(" protected void fingerprint(final EObject object, final Hasher hasher) {\n"); sb.append(" hasherAccess.set(hasher);\n"); if (!it.getInterfaces().isEmpty()) { sb.append(" final EPackage ePackage = object.eClass().getEPackage();\n"); @@ -124,13 +126,24 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti sb.append(" hasherAccess.set(null);\n"); sb.append(" }\n"); sb.append("}\n"); + // CHECKSTYLE:CONSTANTS-ON return sb; } /** * Public dispatcher for doProfile. + * + * @param it + * the interface item + * @param ctx + * the compilation context + * @param genModelUtil + * the gen model utility + * @param type + * the EClass type + * @return the generated profile code */ - public CharSequence doProfile(InterfaceItem it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { + public CharSequence doProfile(final InterfaceItem it, final CompilationContext ctx, final GenModelUtilX genModelUtil, final EClass type) { if (it instanceof InterfaceExpression interfaceExpression) { return _doProfile(interfaceExpression, ctx, genModelUtil, type); } else if (it instanceof InterfaceField interfaceField) { @@ -142,13 +155,14 @@ public CharSequence doProfile(InterfaceItem it, CompilationContext ctx, GenModel } } - protected CharSequence _doProfileDefault(InterfaceItem it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { + protected CharSequence _doProfileDefault(final InterfaceItem it, final CompilationContext ctx, final GenModelUtilX genModelUtil, final EClass type) { return "ERROR" + it.toString() + " " + generatorUtilX.javaContributorComment(generatorUtilX.location(it)); } - protected CharSequence _doProfile(InterfaceField it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { - final StringBuilder sb = new StringBuilder(); - if (it.getField().isMany() && (it.isUnordered() == true)) { + // CHECKSTYLE:CONSTANTS-OFF + protected CharSequence _doProfile(final InterfaceField it, final CompilationContext ctx, final GenModelUtilX genModelUtil, final EClass type) { + final StringBuilder sb = new StringBuilder(128); + if (it.getField().isMany() && it.isUnordered()) { sb.append("fingerprintFeature(obj, ").append(genModelUtil.literalIdentifier(it.getField())).append(", FingerprintOrder.UNORDERED, hasher);\n"); } else { sb.append("fingerprintFeature(obj, ").append(genModelUtil.literalIdentifier(it.getField())).append(", hasher);\n"); @@ -157,9 +171,9 @@ protected CharSequence _doProfile(InterfaceField it, CompilationContext ctx, Gen return sb; } - protected CharSequence _doProfile(InterfaceNavigation it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { - final StringBuilder sb = new StringBuilder(); - if (it.getRef().isMany() && (it.isUnordered() == true)) { + protected CharSequence _doProfile(final InterfaceNavigation it, final CompilationContext ctx, final GenModelUtilX genModelUtil, final EClass type) { + final StringBuilder sb = new StringBuilder(128); + if (it.getRef().isMany() && it.isUnordered()) { sb.append("fingerprintRef(obj, ").append(genModelUtil.literalIdentifier(it.getRef())).append(", FingerprintOrder.UNORDERED, hasher);\n"); } else { sb.append("fingerprintRef(obj, ").append(genModelUtil.literalIdentifier(it.getRef())).append(", hasher);\n"); @@ -168,8 +182,8 @@ protected CharSequence _doProfile(InterfaceNavigation it, CompilationContext ctx return sb; } - protected CharSequence _doProfile(InterfaceExpression it, CompilationContext ctx, GenModelUtilX genModelUtil, EClass type) { - final StringBuilder sb = new StringBuilder(); + protected CharSequence _doProfile(final InterfaceExpression it, final CompilationContext ctx, final GenModelUtilX genModelUtil, final EClass type) { + final StringBuilder sb = new StringBuilder(128); sb.append("fingerprintExpr(").append(codeGenerationX.javaExpression(it.getExpr(), ctx.clone("obj", type))) .append(", obj, FingerprintOrder.").append(it.isUnordered() ? "UNORDERED" : "ORDERED") .append(", FingerprintIndirection.").append(it.isRef() ? "INDIRECT" : "DIRECT") @@ -177,4 +191,5 @@ protected CharSequence _doProfile(InterfaceExpression it, CompilationContext ctx sb.append("hasher.putChar(ITEM_SEP);\n"); return sb; } + // CHECKSTYLE:CONSTANTS-ON } diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.java index ac623994a1..c726347978 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/FragmentProviderGenerator.java @@ -30,6 +30,7 @@ import com.google.inject.Inject; +@SuppressWarnings("PMD.UnusedFormalParameter") public class FragmentProviderGenerator { @Inject @@ -44,9 +45,10 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, final List fingerprintedExports = it.getExports().stream() .filter(e -> e.isFingerprint() && e.getFragmentAttribute() != null) .collect(Collectors.toList()); - final StringBuilder sb = new StringBuilder(); + // CHECKSTYLE:CONSTANTS-OFF + final StringBuilder sb = new StringBuilder(2048); sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getFragmentProvider(it))).append(";\n"); - sb.append("\n"); + sb.append('\n'); if (!fingerprintedExports.isEmpty()) { sb.append("import org.eclipse.emf.ecore.EClass;\n"); } @@ -56,12 +58,12 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, if (!fingerprintedExports.isEmpty()) { sb.append("import org.eclipse.emf.ecore.EPackage;\n"); } - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractSelectorFragmentProvider;\n"); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getFragmentProvider(it))).append(" extends AbstractSelectorFragmentProvider {\n"); - sb.append("\n"); + sb.append('\n'); if (!fingerprintedExports.isEmpty()) { sb.append(" @Override\n"); sb.append(" public boolean appendFragmentSegment(final EObject object, StringBuilder builder) {\n"); @@ -74,14 +76,12 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, sb.append(" int classifierID = eClass.getClassifierID();\n"); sb.append(" switch (classifierID) {\n"); for (EClassifier classifier : p.getEClassifiers()) { - if (classifier instanceof EClass c) { - if (fingerprintedExports.stream().map(Export::getType).anyMatch(e -> e.isSuperTypeOf(c))) { - final Export e = typeMap.get(c); - sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(e))).append("\n"); - sb.append(" case ").append(genModelUtil.classifierIdLiteral(c)).append(": {\n"); - sb.append(" return appendFragmentSegment((").append(genModelUtil.instanceClassName(c)).append(") object, builder);\n"); - sb.append(" }\n"); - } + if (classifier instanceof EClass c && fingerprintedExports.stream().map(Export::getType).anyMatch(e -> e.isSuperTypeOf(c))) { + final Export e = typeMap.get(c); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(e))).append('\n'); + sb.append(" case ").append(genModelUtil.classifierIdLiteral(c)).append(": {\n"); + sb.append(" return appendFragmentSegment((").append(genModelUtil.instanceClassName(c)).append(") object, builder);\n"); + sb.append(" }\n"); } } sb.append(" default:\n"); @@ -92,22 +92,23 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, sb.append(" return super.appendFragmentSegment(object, builder);\n"); sb.append(" }\n"); } - sb.append("\n"); + sb.append('\n'); if (it.isExtension()) { sb.append(" @Override\n"); sb.append(" protected boolean appendFragmentSegmentFallback(final EObject object, StringBuilder builder) {\n"); sb.append(" // For export extension we must return false, so the logic will try other extensions\n"); sb.append(" return false;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); } for (Export e : fingerprintedExports) { sb.append(" protected boolean appendFragmentSegment(final ").append(genModelUtil.instanceClassName(e.getType())).append(" obj, StringBuilder builder) {\n"); sb.append(" return computeSelectorFragmentSegment(obj, ").append(genModelUtil.literalIdentifier(e.getFragmentAttribute())).append(", ").append(e.isFragmentUnique()).append(", builder);\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); } sb.append("}\n"); + // CHECKSTYLE:CONSTANTS-ON return sb; } } diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.java index ba2b72d312..753b612107 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionConstantsGenerator.java @@ -25,6 +25,7 @@ import com.google.inject.Inject; +@SuppressWarnings("PMD.UnusedFormalParameter") public class ResourceDescriptionConstantsGenerator { @Inject @@ -37,11 +38,12 @@ public class ResourceDescriptionConstantsGenerator { private ExportGeneratorX exportGeneratorX; public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { - final StringBuilder sb = new StringBuilder(); + // CHECKSTYLE:CONSTANTS-OFF + final StringBuilder sb = new StringBuilder(512); sb.append("package "); sb.append(naming.toJavaPackage(exportGeneratorX.getResourceDescriptionConstants(it))); sb.append(";\n"); - sb.append("\n"); + sb.append('\n'); sb.append("public interface "); sb.append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionConstants(it))); sb.append(" {\n"); @@ -53,7 +55,7 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, if (!a.isEmpty() || !d.isEmpty()) { sb.append(" // Export "); sb.append(c.getType().getName()); - sb.append("\n"); + sb.append('\n'); if (!a.isEmpty()) { for (final EAttribute attr : a) { sb.append(" public static final String "); @@ -72,11 +74,12 @@ public CharSequence generate(final ExportModel it, final CompilationContext ctx, sb.append("\"; //$NON-NLS-1$\n"); } } - sb.append("\n"); + sb.append('\n'); } } } sb.append("}\n"); + // CHECKSTYLE:CONSTANTS-ON return sb; } diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.java index 6d3b7e0493..51caf0baad 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionManagerGenerator.java @@ -22,6 +22,7 @@ import com.google.inject.Inject; +@SuppressWarnings("PMD.UnusedFormalParameter") public class ResourceDescriptionManagerGenerator { @Inject @@ -34,13 +35,14 @@ public CharSequence generate(final ExportModel model, final CompilationContext c final Grammar grammar = exportGeneratorX.getGrammar(model); final List usedGrammars = grammar != null ? grammar.getUsedGrammars() : new ArrayList<>(); final Grammar extendedGrammar = (usedGrammars.isEmpty() || usedGrammars.get(0).getName().endsWith(".Terminals")) ? null : usedGrammars.get(0); - final StringBuilder sb = new StringBuilder(); + // CHECKSTYLE:CONSTANTS-OFF + final StringBuilder sb = new StringBuilder(2048); sb.append("package "); sb.append(naming.toJavaPackage(exportGeneratorX.getResourceDescriptionManager(model))); sb.append(";\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import java.util.Set;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractCachingResourceDescriptionManager;\n"); if (extendedGrammar != null) { sb.append("import "); @@ -50,8 +52,8 @@ public CharSequence generate(final ExportModel model, final CompilationContext c sb.append("import com.google.common.collect.Sets;\n"); } sb.append("import com.google.inject.Singleton;\n"); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("/**\n"); sb.append(" * Resource description manager for "); sb.append(exportGeneratorX.getName(model)); @@ -61,7 +63,7 @@ public CharSequence generate(final ExportModel model, final CompilationContext c sb.append("public class "); sb.append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionManager(model))); sb.append(" extends AbstractCachingResourceDescriptionManager {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" public static final Set INTERESTING_EXTS = "); if (extendedGrammar != null) { sb.append("ImmutableSet.copyOf(Sets.union("); @@ -70,13 +72,14 @@ public CharSequence generate(final ExportModel model, final CompilationContext c } else { sb.append("all();\n"); } - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" protected Set getInterestingExtensions() {\n"); sb.append(" return INTERESTING_EXTS;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append("}\n"); + // CHECKSTYLE:CONSTANTS-ON return sb; } diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.java index 931fb078a0..ad87a385d9 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ResourceDescriptionStrategyGenerator.java @@ -43,13 +43,14 @@ public class ResourceDescriptionStrategyGenerator { @Inject private ExportGeneratorX exportGeneratorX; - public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUtilX genModelUtil) { - final StringBuilder sb = new StringBuilder(); + public CharSequence generate(final ExportModel it, final CompilationContext ctx, final GenModelUtilX genModelUtil) { + // CHECKSTYLE:CONSTANTS-OFF + final StringBuilder sb = new StringBuilder(2048); sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getResourceDescriptionStrategy(it))).append(";\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import java.util.Map;\n"); sb.append("import java.util.Set;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import org.eclipse.emf.ecore.EClass;\n"); sb.append("import org.eclipse.emf.ecore.EObject;\n"); sb.append("import org.eclipse.emf.ecore.EPackage;\n"); @@ -57,7 +58,7 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti sb.append("import org.eclipse.emf.ecore.util.Switch;\n"); sb.append("import org.eclipse.xtext.resource.IEObjectDescription;\n"); sb.append("import org.eclipse.xtext.util.IAcceptor;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.xtext.resource.AbstractResourceDescriptionStrategy;\n"); if (it.getExports().stream().anyMatch(e -> e.isFingerprint() || e.isResourceFingerprint())) { sb.append("import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer;\n"); @@ -70,10 +71,10 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti sb.append("import com.google.common.collect.ImmutableSet;\n"); final Collection types = it.getExports(); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionStrategy(it))).append(" extends AbstractResourceDescriptionStrategy {\n"); - sb.append("\n"); + sb.append('\n'); // EXPORTED_ECLASSES sb.append(" private static final Set EXPORTED_ECLASSES = ImmutableSet.copyOf(new EClass[] {\n"); @@ -84,21 +85,21 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti for (int i = 0; i < sortedKeys.size(); i++) { sb.append(" ").append(genModelUtil.literalIdentifier(sortedKeys.get(i))); if (i < sortedKeys.size() - 1) { - sb.append(","); + sb.append(','); } - sb.append("\n"); + sb.append('\n'); } sb.append(" });\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public Set getExportedEClasses(final Resource resource) {\n"); sb.append(" return EXPORTED_ECLASSES;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); if (!types.isEmpty()) { sb.append(" private final ThreadLocal> acceptor = new ThreadLocal>();\n"); - sb.append("\n"); + sb.append('\n'); final Set packageSet = types.stream() .filter(c -> !c.getType().isAbstract()) @@ -110,7 +111,7 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti for (EPackage p : sortedPackages) { sb.append(" private final Switch ").append(p.getName()).append("ExportSwitch = new ").append(genModelUtil.qualifiedSwitchClassName(p)).append("() {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public Boolean defaultCase(final EObject obj) {\n"); sb.append(" return true;\n"); @@ -121,20 +122,20 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti .collect(Collectors.toList()); for (Export c : exportsForPackage) { - sb.append("\n"); - sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c))).append("\n"); + sb.append('\n'); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c))).append('\n'); sb.append(" @Override\n"); sb.append(" public Boolean case").append(c.getType().getName()).append("(final ").append(genModelUtil.instanceClassName(c.getType())).append(" obj) {\n"); final String guard = codeGenerationX.javaExpression(c.getGuard(), ctx.clone("obj", c.getType())); if (c.getGuard() == null) { sb.append(generateCaseBody(it, c, ctx, genModelUtil)); - } else if (!guard.equalsIgnoreCase("false")) { - sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c.getGuard()))).append("\n"); + } else if (!"false".equalsIgnoreCase(guard)) { + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c.getGuard()))).append('\n'); sb.append(" if (").append(guard).append(") {\n"); sb.append(generateCaseBody(it, c, ctx, genModelUtil)); sb.append(" }\n"); } - sb.append("\n"); + sb.append('\n'); // can Type contain any nested types ? final Set nonAbstractTypeNames = types.stream() @@ -151,7 +152,7 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti sb.append(" }\n"); } sb.append(" };\n"); - sb.append("\n"); + sb.append('\n'); } sb.append(" @Override\n"); @@ -175,20 +176,24 @@ public CharSequence generate(ExportModel it, CompilationContext ctx, GenModelUti sb.append(" this.acceptor.set(null);\n"); sb.append(" }\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); } sb.append("}\n"); + // CHECKSTYLE:CONSTANTS-ON return sb; } - public CharSequence generateCaseBody(ExportModel it, Export c, CompilationContext ctx, GenModelUtilX genModelUtil) { + // CHECKSTYLE:CONSTANTS-OFF + public CharSequence generateCaseBody(final ExportModel it, final Export c, final CompilationContext ctx, final GenModelUtilX genModelUtil) { final List a = c.getAllEAttributes(); final List d = exportGeneratorX.allUserData(c); - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(512); + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity if (!a.isEmpty() || !d.isEmpty() || c.isFingerprint() || c.isResourceFingerprint() || c.isLookup()) { + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity sb.append(" // Use a forwarding map to delay calculation as much as possible; otherwise we may get recursive EObject resolution attempts\n"); sb.append(" Map data = new AbstractForwardingResourceDescriptionStrategyMap() {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" protected void fill(final ImmutableMap.Builder builder) {\n"); sb.append(" Object value = null;\n"); @@ -208,7 +213,7 @@ public CharSequence generateCaseBody(ExportModel it, Export c, CompilationContex if (c.isLookup()) { sb.append(" // Allow lookups\n"); if (c.getLookupPredicate() != null) { - sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c.getLookupPredicate()))).append("\n"); + sb.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(c.getLookupPredicate()))).append('\n'); sb.append(" if (").append(codeGenerationX.javaExpression(c.getLookupPredicate(), ctx.clone("obj", c.getType()))).append(") {\n"); sb.append(" builder.put(DetachableEObjectDescription.ALLOW_LOOKUP, Boolean.TRUE.toString());\n"); sb.append(" }\n"); @@ -221,7 +226,7 @@ public CharSequence generateCaseBody(ExportModel it, Export c, CompilationContex for (EAttribute attr : a) { sb.append(" value = obj.eGet(").append(genModelUtil.literalIdentifier(attr)).append(", false);\n"); sb.append(" if (value != null) {\n"); - sb.append(" builder.put(").append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionConstants(it))).append(".").append(exportGeneratorX.constantName(attr, c.getType())).append(", value.toString());\n"); + sb.append(" builder.put(").append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionConstants(it))).append('.').append(exportGeneratorX.constantName(attr, c.getType())).append(", value.toString());\n"); sb.append(" }\n"); } } @@ -230,7 +235,7 @@ public CharSequence generateCaseBody(ExportModel it, Export c, CompilationContex for (UserData data : d) { sb.append(" value = ").append(codeGenerationX.javaExpression(data.getExpr(), ctx.clone("obj", c.getType()))).append(";\n"); sb.append(" if (value != null) {\n"); - sb.append(" builder.put(").append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionConstants(it))).append(".").append(exportGeneratorX.constantName(data, c.getType())).append(", value.toString());\n"); + sb.append(" builder.put(").append(naming.toSimpleName(exportGeneratorX.getResourceDescriptionConstants(it))).append('.').append(exportGeneratorX.constantName(data, c.getType())).append(", value.toString());\n"); sb.append(" }\n"); } } @@ -242,4 +247,5 @@ public CharSequence generateCaseBody(ExportModel it, Export c, CompilationContex } return sb; } + // CHECKSTYLE:CONSTANTS-ON } diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.java index e3288834bf..2bd2a7e8e3 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/BundleVersionStripperFragment.java @@ -13,7 +13,6 @@ import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment; import org.eclipse.xtext.xtext.generator.model.ManifestAccess; import org.eclipse.xtext.xtext.generator.model.project.IBundleProjectConfig; diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.java index 4a83b1a1f9..c0df730444 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/DefaultFragmentWithOverride.java @@ -17,18 +17,17 @@ import org.eclipse.xtext.xtext.generator.Issues; /** - * Allow different fragments to be generated depending on a condition - * - * By default we generate the defaultFragment (or nothing if it is null) - * if useOverride is true, we generate the overrideFragment (or nothing if it is null) + * Allow different fragments to be generated depending on a condition. * + *

By default we generate the defaultFragment (or nothing if it is null). + * If useOverride is true, we generate the overrideFragment (or nothing if it is null). */ public class DefaultFragmentWithOverride extends AbstractXtextGeneratorFragment { /** * Whether to use the override fragment. False by default */ - private boolean useOverride = false; + private boolean useOverride; private IXtextGeneratorFragment defaultFragment; diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.java index d2794dc9ed..11e9c511b9 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/BuilderIntegrationFragment2.java @@ -45,7 +45,7 @@ protected void addEclipsePluginGuiceBindings() { super.addEclipsePluginGuiceBindings(); final StringConcatenationClient statement1 = new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append("binder.bind("); target.append(TypeReference.typeRef(IResourceDescriptions.class)); target.append(".class"); diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java index 97b04e9700..70eb62efc7 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java @@ -39,7 +39,9 @@ public class LspBuilderIntegrationFragment2 extends AbstractXtextGeneratorFragme @Inject private XtextGeneratorNaming packageNaming; - private TypeReference createSuffixedTypeReference(String suffix) { + private static final int INITIAL_BUFFER_CAPACITY = 128; + + private TypeReference createSuffixedTypeReference(final String suffix) { return new TypeReference( packageNaming.getGenericIdeBasePackage(getGrammar()), GrammarUtil.getSimpleName(getGrammar()) + suffix ); @@ -66,30 +68,31 @@ public void generate() { } public void generateServiceRegistration() { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(INITIAL_BUFFER_CAPACITY); sb.append(getLspBuildSetupServiceClass().getName()); - sb.append("\n"); + sb.append('\n'); fileAccessFactory.createTextFile("META-INF/services/com.avaloq.tools.ddk.xtext.build.ILspLanguageSetup", toClient(sb)).writeTo(getProjectConfig().getGenericIde().getSrcGen()); } + // CHECKSTYLE:CONSTANTS-OFF public void generateBuildService() { - Grammar grammar = getGrammar(); - TypeReference lspBuildSetupServiceClass = getLspBuildSetupServiceClass(); - StringBuilder sb = new StringBuilder(); + final Grammar grammar = getGrammar(); + final TypeReference lspBuildSetupServiceClass = getLspBuildSetupServiceClass(); + StringBuilder sb = new StringBuilder(1024); sb.append("import java.util.List;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.xtext.build.AbstractDynamicSetupService;\n"); sb.append("import com.avaloq.tools.ddk.xtext.build.ILspLanguageSetup;\n"); sb.append("import com.google.common.collect.ImmutableList;\n"); sb.append("import com.google.inject.Injector;\n"); sb.append("import com.google.inject.Module;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("/**\n"); sb.append(" * Generated by com.avaloq.tools.ddk.xtext.generator.builder.LspBuilderIntegrationFragment2.\n"); sb.append(" */\n"); sb.append("public class ").append(lspBuildSetupServiceClass.getSimpleName()).append(" extends AbstractDynamicSetupService implements ILspLanguageSetup {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @SuppressWarnings(\"nls\")\n"); sb.append(" private static final String GRAMMAR = \"").append(grammar.getName()).append("\";\n"); sb.append(" @SuppressWarnings(\"nls\")\n"); @@ -99,65 +102,65 @@ public void generateBuildService() { Grammar g = allUsedGrammars.get(i); sb.append(" \"").append(g.getName()).append("\" //"); if (i < allUsedGrammars.size() - 1) { - sb.append(","); + sb.append(','); } - sb.append("\n"); + sb.append('\n'); } sb.append(" );\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" public Injector doSetup(Module overrideModule, Module... additionalModules) {\n"); sb.append(" return new ").append(GrammarUtil.getSimpleName(grammar)).append("LspBuildSetupGenerated(SETUP_LOCK, overrideModule, additionalModules).createInjectorAndDoEMFRegistration();\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public List getParentLanguages() {\n"); sb.append(" return PARENTS;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public String getLanguageName() {\n"); sb.append(" return GRAMMAR;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append("}\n"); fileAccessFactory.createJavaFile(lspBuildSetupServiceClass, toClient(sb)).writeTo(getProjectConfig().getGenericIde().getSrcGen()); } public void generateBuildSetup() { - Grammar grammar = getGrammar(); - TypeReference lspBuildSetupGeneratedClass = getLspBuildSetupGeneratedClass(); - StringBuilder sb = new StringBuilder(); + final Grammar grammar = getGrammar(); + final TypeReference lspBuildSetupGeneratedClass = getLspBuildSetupGeneratedClass(); + StringBuilder sb = new StringBuilder(2048); sb.append("import org.eclipse.xtext.util.Modules2;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.google.common.collect.ImmutableList;\n"); sb.append("import com.google.inject.Guice;\n"); sb.append("import com.google.inject.Injector;\n"); sb.append("import com.google.inject.Module;\n"); sb.append("import com.google.inject.util.Modules;\n"); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("/**\n"); sb.append(" * Generated by com.avaloq.tools.ddk.xtext.generator.builder.LspBuilderIntegrationFragment2.\n"); sb.append(" */\n"); sb.append("public class ").append(lspBuildSetupGeneratedClass.getSimpleName()).append(" extends ").append(packageNaming.getGenericIdeSetup(grammar)).append(" {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" private final Module overrideModule;\n"); sb.append(" private final Module[] additionalModules;\n"); sb.append(" private final Object lock;\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" public ").append(lspBuildSetupGeneratedClass.getSimpleName()).append("(final Object lock, final Module overrideModule, Module... additionalModules) {\n"); sb.append(" this.lock = lock;\n"); sb.append(" this.overrideModule = overrideModule;\n"); sb.append(" this.additionalModules = additionalModules;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" public ").append(lspBuildSetupGeneratedClass.getSimpleName()).append("(final Module overrideModule, Module... additionalModules) {\n"); sb.append(" this.lock = null;\n"); sb.append(" this.overrideModule = overrideModule;\n"); sb.append(" this.additionalModules = additionalModules;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public Injector createInjectorAndDoEMFRegistration() {\n"); sb.append(" registerEPackages();\n"); @@ -171,12 +174,12 @@ public void generateBuildSetup() { sb.append(" }\n"); sb.append(" return injector;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public Injector createInjector() {\n"); sb.append(" return Guice.createInjector(getModules());\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" protected void registerEPackages() {\n"); for (AbstractMetamodelDeclaration decl : grammar.getMetamodelDeclarations()) { if (decl instanceof GeneratedMetamodel) { @@ -184,27 +187,28 @@ public void generateBuildSetup() { String ns = GrammarUtil.getNamespace(grammar); String name = mmd.getName(); String nameUpper = name.substring(0, 1).toUpperCase() + name.substring(1); - sb.append(" if (").append(ns).append(".").append(name).append(".").append(nameUpper).append("Package.eINSTANCE == null) {\n"); - sb.append(" throw new IllegalStateException(\"EPackage could not be initialized: \" + ").append(ns).append(".").append(name).append(".").append(nameUpper).append("Package.eNS_URI); //$NON-NLS-1$\n"); + sb.append(" if (").append(ns).append('.').append(name).append('.').append(nameUpper).append("Package.eINSTANCE == null) {\n"); + sb.append(" throw new IllegalStateException(\"EPackage could not be initialized: \" + ").append(ns).append('.').append(name).append('.').append(nameUpper).append("Package.eNS_URI); //$NON-NLS-1$\n"); sb.append(" }\n"); } } sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" protected Iterable getModules() {\n"); sb.append(" return ImmutableList. builder().add(Modules.override(Modules2.mixin(new ").append(grammar.getName()).append("RuntimeModule(), new ").append(packageNaming.getGenericIdeModule(grammar)).append("())).with(overrideModule)).add(additionalModules).build();\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append("}\n"); fileAccessFactory.createJavaFile(lspBuildSetupGeneratedClass, toClient(sb)).writeTo(getProjectConfig().getGenericIde().getSrcGen()); } + // CHECKSTYLE:CONSTANTS-ON private static StringConcatenationClient toClient(final StringBuilder sb) { final String content = sb.toString(); return new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append(content); } }; diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java index 606885511d..633a102e64 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java @@ -35,7 +35,7 @@ public class StandaloneBuilderIntegrationFragment2 extends AbstractXtextGenerato @Inject private FileAccessFactory fileAccessFactory; - private TypeReference createSuffixedTypeReference(String suffix) { + private TypeReference createSuffixedTypeReference(final String suffix) { return new TypeReference( getGrammar().getName() + suffix ); @@ -59,30 +59,33 @@ public void generate() { generateBuildSetup(); } + private static final int INITIAL_BUFFER_CAPACITY = 128; + public void generateServiceRegistration() { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(INITIAL_BUFFER_CAPACITY); sb.append(getStandaloneBuildSetupServiceClass().getName()); - sb.append("\n"); + sb.append('\n'); fileAccessFactory.createTextFile("META-INF/services/com.avaloq.tools.ddk.xtext.build.IDynamicSetupService", toClient(sb)).writeTo(getProjectConfig().getRuntime().getSrcGen()); } + // CHECKSTYLE:CONSTANTS-OFF public void generateBuildService() { - Grammar grammar = getGrammar(); - TypeReference standaloneBuildSetupServiceClass = getStandaloneBuildSetupServiceClass(); - StringBuilder sb = new StringBuilder(); + final Grammar grammar = getGrammar(); + final TypeReference standaloneBuildSetupServiceClass = getStandaloneBuildSetupServiceClass(); + StringBuilder sb = new StringBuilder(2048); sb.append("import java.util.List;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.xtext.build.AbstractDynamicSetupService;\n"); sb.append("import com.google.common.collect.ImmutableList;\n"); sb.append("import com.google.inject.Injector;\n"); sb.append("import com.google.inject.Module;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("/**\n"); sb.append(" * Generated by com.avaloq.tools.ddk.xtext.generator.builder.StandaloneBuilderIntegrationFragment2.\n"); sb.append(" */\n"); sb.append("public class ").append(standaloneBuildSetupServiceClass.getSimpleName()).append(" extends AbstractDynamicSetupService {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @SuppressWarnings(\"nls\")\n"); sb.append(" private static final String GRAMMAR = \"").append(grammar.getName()).append("\";\n"); sb.append(" @SuppressWarnings(\"nls\")\n"); @@ -92,63 +95,63 @@ public void generateBuildService() { Grammar g = allUsedGrammars.get(i); sb.append(" \"").append(g.getName()).append("\" //"); if (i < allUsedGrammars.size() - 1) { - sb.append(","); + sb.append(','); } - sb.append("\n"); + sb.append('\n'); } sb.append(" );\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" public Injector doSetup(Module overrideModule, Module... additionalModules) {\n"); sb.append(" return new ").append(GrammarUtil.getSimpleName(grammar)).append("StandaloneBuildSetupGenerated(SETUP_LOCK, overrideModule, additionalModules).createInjectorAndDoEMFRegistration();\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public List getParentLanguages() {\n"); sb.append(" return PARENTS;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public String getLanguageName() {\n"); sb.append(" return GRAMMAR;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append("}\n"); fileAccessFactory.createJavaFile(standaloneBuildSetupServiceClass, toClient(sb)).writeTo(getProjectConfig().getRuntime().getSrcGen()); } public void generateBuildSetup() { - Grammar grammar = getGrammar(); - TypeReference standaloneBuildSetupGeneratedClass = getStandaloneBuildSetupGeneratedClass(); - StringBuilder sb = new StringBuilder(); + final Grammar grammar = getGrammar(); + final TypeReference standaloneBuildSetupGeneratedClass = getStandaloneBuildSetupGeneratedClass(); + StringBuilder sb = new StringBuilder(2048); sb.append("import com.google.common.collect.ImmutableList;\n"); sb.append("import com.google.inject.Guice;\n"); sb.append("import com.google.inject.Injector;\n"); sb.append("import com.google.inject.Module;\n"); sb.append("import com.google.inject.util.Modules;\n"); - sb.append("\n"); - sb.append("\n"); + sb.append('\n'); + sb.append('\n'); sb.append("/**\n"); sb.append(" * Generated by com.avaloq.tools.ddk.xtext.generator.builder.StandaloneBuilderIntegrationFragment2.\n"); sb.append(" */\n"); sb.append("public class ").append(standaloneBuildSetupGeneratedClass.getSimpleName()).append(" extends ").append(GrammarUtil.getSimpleName(grammar)).append("StandaloneSetup {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" private final Module overrideModule;\n"); sb.append(" private final Module[] additionalModules;\n"); sb.append(" private final Object lock;\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" public ").append(standaloneBuildSetupGeneratedClass.getSimpleName()).append("(final Object lock, final Module overrideModule, Module... additionalModules) {\n"); sb.append(" this.lock = lock;\n"); sb.append(" this.overrideModule = overrideModule;\n"); sb.append(" this.additionalModules = additionalModules;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" public ").append(standaloneBuildSetupGeneratedClass.getSimpleName()).append("(final Module overrideModule, Module... additionalModules) {\n"); sb.append(" this.lock = null;\n"); sb.append(" this.overrideModule = overrideModule;\n"); sb.append(" this.additionalModules = additionalModules;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public Injector createInjectorAndDoEMFRegistration() {\n"); sb.append(" registerEPackages();\n"); @@ -162,12 +165,12 @@ public void generateBuildSetup() { sb.append(" }\n"); sb.append(" return injector;\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public Injector createInjector() {\n"); sb.append(" return Guice.createInjector(getModules());\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" protected void registerEPackages() {\n"); for (AbstractMetamodelDeclaration decl : grammar.getMetamodelDeclarations()) { if (decl instanceof GeneratedMetamodel) { @@ -175,27 +178,28 @@ public void generateBuildSetup() { String ns = GrammarUtil.getNamespace(grammar); String name = mmd.getName(); String nameUpper = name.substring(0, 1).toUpperCase() + name.substring(1); - sb.append(" if (").append(ns).append(".").append(name).append(".").append(nameUpper).append("Package.eINSTANCE == null) {\n"); - sb.append(" throw new IllegalStateException(\"EPackage could not be initialized: \" + ").append(ns).append(".").append(name).append(".").append(nameUpper).append("Package.eNS_URI); //$NON-NLS-1$\n"); + sb.append(" if (").append(ns).append('.').append(name).append('.').append(nameUpper).append("Package.eINSTANCE == null) {\n"); + sb.append(" throw new IllegalStateException(\"EPackage could not be initialized: \" + ").append(ns).append('.').append(name).append('.').append(nameUpper).append("Package.eNS_URI); //$NON-NLS-1$\n"); sb.append(" }\n"); } } sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" protected Iterable getModules() {\n"); sb.append(" return ImmutableList. builder().add(Modules.override(new ").append(grammar.getName()).append("RuntimeModule()).with(overrideModule)).add(additionalModules).build();\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append("}\n"); fileAccessFactory.createJavaFile(standaloneBuildSetupGeneratedClass, toClient(sb)).writeTo(getProjectConfig().getRuntime().getSrcGen()); } + // CHECKSTYLE:CONSTANTS-ON private static StringConcatenationClient toClient(final StringBuilder sb) { final String content = sb.toString(); return new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append(content); } }; diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.java index b37c8d2977..62a28031c9 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/formatting/FormatterFragment2.java @@ -38,19 +38,21 @@ public class FormatterFragment2 extends AbstractStubGeneratingFragment { private FileAccessFactory fileAccessFactory; @Inject - private XtextGeneratorNaming _xtextGeneratorNaming; + private XtextGeneratorNaming xtextGeneratorNaming; @Inject - private GrammarAccessExtensions _grammarAccessExtensions; + private GrammarAccessExtensions grammarAccessExtensions; /** * Class-wide logger. */ private static final Logger LOGGER = LogManager.getLogger(FormatterFragment2.class); + // CHECKSTYLE:CONSTANTS-OFF protected TypeReference getFormatterStub(final Grammar grammar) { - return new TypeReference(_xtextGeneratorNaming.getRuntimeBasePackage(grammar) + ".formatting." + GrammarUtil.getSimpleName(grammar) + "Formatter"); + return new TypeReference(xtextGeneratorNaming.getRuntimeBasePackage(grammar) + ".formatting." + GrammarUtil.getSimpleName(grammar) + "Formatter"); } + // CHECKSTYLE:CONSTANTS-ON @Override public void generate() { @@ -67,7 +69,7 @@ public void generate() { .addTypeToType(TypeReference.typeRef(INodeModelStreamer.class), TypeReference.typeRef(DirectNodeModelStreamer.class)) .contributeTo(getLanguage().getRuntimeGenModule()); if (getProjectConfig().getRuntime().getManifest() != null) { - getProjectConfig().getRuntime().getManifest().getExportedPackages().add(_xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".formatting"); + getProjectConfig().getRuntime().getManifest().getExportedPackages().add(xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".formatting"); } doGenerateStubFile(); } @@ -94,11 +96,12 @@ protected XtendFileAccess doGetXtendStubFile() { xtendFile.setResourceSet(getLanguage().getResourceSet()); final String stubSimpleName = getFormatterStub(getGrammar()).getSimpleName(); - final TypeReference grammarAccessRef = _grammarAccessExtensions.getGrammarAccess(getGrammar()); + final TypeReference grammarAccessRef = grammarAccessExtensions.getGrammarAccess(getGrammar()); + // CHECKSTYLE:CONSTANTS-OFF xtendFile.setContent(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append("import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter"); target.newLineIfNotEmpty(); target.append("import org.eclipse.xtext.formatting.impl.FormattingConfig"); @@ -147,6 +150,7 @@ protected void appendTo(TargetStringConcatenation target) { target.newLineIfNotEmpty(); } }); + // CHECKSTYLE:CONSTANTS-ON return xtendFile; } @@ -155,11 +159,12 @@ protected JavaFileAccess doGetJavaStubFile() { javaFile.setResourceSet(getLanguage().getResourceSet()); final String stubSimpleName = getFormatterStub(getGrammar()).getSimpleName(); - final TypeReference grammarAccessRef = _grammarAccessExtensions.getGrammarAccess(getGrammar()); + final TypeReference grammarAccessRef = grammarAccessExtensions.getGrammarAccess(getGrammar()); + // CHECKSTYLE:CONSTANTS-OFF javaFile.setContent(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append("import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter;"); target.newLineIfNotEmpty(); target.append("import org.eclipse.xtext.formatting.impl.FormattingConfig;"); @@ -211,6 +216,7 @@ protected void appendTo(TargetStringConcatenation target) { target.newLineIfNotEmpty(); } }); + // CHECKSTYLE:CONSTANTS-ON return javaFile; } diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.java index 21a19e7af0..fefdeabac7 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/languageconstants/LanguageConstantsFragment2.java @@ -33,7 +33,7 @@ public class LanguageConstantsFragment2 extends AbstractXtextGeneratorFragment { private FileAccessFactory fileAccessFactory; @Inject - private XtextGeneratorNaming _xtextGeneratorNaming; + private XtextGeneratorNaming xtextGeneratorNaming; /** Class-wide logger. */ private static final Logger LOGGER = LogManager.getLogger(LanguageConstantsFragment2.class); @@ -67,10 +67,8 @@ protected IXtextGeneratorFileSystemAccess getMetamodelSrcGen() { /** * Returns the preferred file extension. If not manually set, the - * first item in {@link fileExtensions} is returned. + * first item in {@link #getFileExtensions() fileExtensions} is returned. * - * @param grammar - * the grammar for which the preferred file extension applies * @return the preferred file extension */ public String getPreferredFileExtension() { @@ -88,7 +86,7 @@ public void generate() { if (LOGGER.isInfoEnabled()) { LOGGER.info(NLS.bind("executing generate for {0}", getClass().getName())); } - if (getLanguage().getFileExtensions().size() == 0) { + if (getLanguage().getFileExtensions().isEmpty()) { LOGGER.error(NLS.bind("There must be at least one extension for {0}", getGrammar().getName())); return; } @@ -102,6 +100,7 @@ public void doGenerateFiles() { } } + // CHECKSTYLE:CONSTANTS-OFF public JavaFileAccess doGetConstantsClassFile() { final TypeReference typeReference = getTypeReference(getGrammar()); final JavaFileAccess javaFile = fileAccessFactory.createJavaFile(typeReference); @@ -115,7 +114,7 @@ public JavaFileAccess doGetConstantsClassFile() { javaFile.setContent(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append("/**"); target.newLineIfNotEmpty(); target.append(" * Provides language specific constants for " + grammarName + "."); @@ -173,6 +172,7 @@ protected void appendTo(TargetStringConcatenation target) { return javaFile; } + // CHECKSTYLE:CONSTANTS-ON /** * Returns the type reference of the Constants class. @@ -182,7 +182,7 @@ protected void appendTo(TargetStringConcatenation target) { * @return the type reference */ public TypeReference getTypeReference(final Grammar grammar) { - return new TypeReference(_xtextGeneratorNaming.getRuntimeBasePackage(grammar) + "." + GrammarUtil.getSimpleName(grammar) + "Constants"); + return new TypeReference(xtextGeneratorNaming.getRuntimeBasePackage(grammar) + "." + GrammarUtil.getSimpleName(grammar) + "Constants"); } @Override diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.java index 2d6ca5d0bd..97b8a490ac 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AbstractAnnotationAwareAntlrGrammarGenerator.java @@ -11,7 +11,6 @@ package com.avaloq.tools.ddk.xtext.generator.parser.antlr; -import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -43,14 +42,18 @@ import com.google.common.collect.Iterators; import com.google.inject.Inject; +// CHECKSTYLE:CONSTANTS-OFF +@SuppressWarnings("PMD.UnusedFormalParameter") public abstract class AbstractAnnotationAwareAntlrGrammarGenerator extends AbstractAntlrGrammarWithActionsGenerator { + // CHECKSTYLE:CHECK-OFF VisibilityModifier @Inject protected GrammarRuleAnnotations annotations; @Inject protected PredicatesNaming predicatesNaming; + // CHECKSTYLE:CHECK-ON VisibilityModifier @Inject private CodeConfig codeConfig; @@ -58,14 +61,14 @@ public abstract class AbstractAnnotationAwareAntlrGrammarGenerator extends Abstr private Grammar originalGrammar; @Override - public void generate(Grammar it, AntlrOptions options, IXtextGeneratorFileSystemAccess fsa) { + public void generate(final Grammar it, final AntlrOptions options, final IXtextGeneratorFileSystemAccess fsa) { this.keywordHelper = KeywordHelper.getHelper(it); this.originalGrammar = it; - RuleFilter filter = new RuleFilter(); + final RuleFilter filter = new RuleFilter(); filter.setDiscardUnreachableRules(true); // options.skipUnusedRules filter.setDiscardTerminalRules(false); // options.skipUnusedRules - RuleNames ruleNames = RuleNames.getRuleNames(it, true); - Grammar flattened = new FlattenedGrammarAccess(ruleNames, filter).getFlattenedGrammar(); + final RuleNames ruleNames = RuleNames.getRuleNames(it, true); + final Grammar flattened = new FlattenedGrammarAccess(ruleNames, filter).getFlattenedGrammar(); new CombinedGrammarMarker(isCombinedGrammar()).attachToEmfObject(flattened); fsa.generateFile(getGrammarNaming().getParserGrammar(it).getGrammarFileName(), compileParser(flattened, options)); if (!isCombinedGrammar()) { @@ -79,13 +82,13 @@ protected boolean isCombinedGrammar() { } @Override - protected CharSequence compileLexer(Grammar it, AntlrOptions options) { - StringConcatenation sb = new StringConcatenation(); + protected CharSequence compileLexer(final Grammar it, final AntlrOptions options) { + final StringConcatenation sb = new StringConcatenation(); sb.append(codeConfig.getFileHeader()); sb.newLineIfNotEmpty(); sb.append("lexer grammar "); sb.append(getGrammarNaming().getLexerGrammar(it).getSimpleName()); - sb.append(";"); + sb.append(';'); sb.newLineIfNotEmpty(); sb.append(compileLexerOptions(it, options)); sb.newLineIfNotEmpty(); @@ -102,8 +105,8 @@ protected CharSequence compileLexer(Grammar it, AntlrOptions options) { return sb; } - protected CharSequence compileLexerMembers(Grammar it, AntlrOptions options) { - StringConcatenation sb = new StringConcatenation(); + protected CharSequence compileLexerMembers(final Grammar it, final AntlrOptions options) { + final StringConcatenation sb = new StringConcatenation(); sb.append("@members {"); sb.newLine(); sb.append(" "); @@ -141,26 +144,26 @@ protected CharSequence compileLexerMembers(Grammar it, AntlrOptions options) { } @Override - protected String compileParserImports(Grammar it, AntlrOptions options) { - StringConcatenation sb = new StringConcatenation(); + protected String compileParserImports(final Grammar it, final AntlrOptions options) { + final StringConcatenation sb = new StringConcatenation(); sb.append("import "); sb.append(predicatesNaming.getSemanticPredicatesFullName(it)); - sb.append(";"); + sb.append(';'); sb.newLineIfNotEmpty(); sb.append("import com.avaloq.tools.ddk.xtext.parser.antlr.ParserContext;"); sb.newLine(); return sb.toString(); } - protected CharSequence compileParserMemberDeclarations(Grammar it, String access) { - StringConcatenation sb = new StringConcatenation(); + protected CharSequence compileParserMemberDeclarations(final Grammar it, final String access) { + final StringConcatenation sb = new StringConcatenation(); sb.append(access); - sb.append(" "); + sb.append(' '); sb.append(_grammarAccessExtensions.getGrammarAccess(it).getSimpleName()); sb.append(" grammarAccess;"); sb.newLineIfNotEmpty(); sb.append(access); - sb.append(" "); + sb.append(' '); sb.append(predicatesNaming.getSemanticPredicatesSimpleName(it)); sb.append(" predicates;"); sb.newLineIfNotEmpty(); @@ -171,7 +174,7 @@ protected CharSequence compileParserMemberDeclarations(Grammar it, String access } protected CharSequence compileParserSetTokenStreamMethod() { - StringConcatenation sb = new StringConcatenation(); + final StringConcatenation sb = new StringConcatenation(); sb.append("/**"); sb.newLine(); sb.append(" * Set token stream in parser context."); @@ -202,26 +205,26 @@ protected CharSequence compileParserSetTokenStreamMethod() { } @Override - protected CharSequence compileKeywordRules(Grammar it, AntlrOptions options) { + protected CharSequence compileKeywordRules(final Grammar it, final AntlrOptions options) { // implementation from xtext, but keywords are from the given grammar only (which has been flattened and filtered correctly) - Set allKeywords = getAllKeywords(it, options); - List allTerminalRules = GrammarUtil.allTerminalRules(it); + final Set allKeywords = getAllKeywords(it, options); + final List allTerminalRules = GrammarUtil.allTerminalRules(it); - List syntheticKwAlternatives = new ArrayList<>(); - for (String kw : allKeywords) { - String ruleName = keywordHelper.getRuleName(kw); + final List syntheticKwAlternatives = new java.util.ArrayList<>(); + for (final String kw : allKeywords) { + final String ruleName = keywordHelper.getRuleName(kw); syntheticKwAlternatives.add("(FRAGMENT_" + ruleName + ")=> FRAGMENT_" + ruleName + " {$type = " + ruleName + "; }"); } - for (AbstractRule rule : allTerminalRules) { + for (final AbstractRule rule : allTerminalRules) { if (rule instanceof TerminalRule) { - TerminalRule terminalRule = (TerminalRule) rule; + final TerminalRule terminalRule = (TerminalRule) rule; if (!_syntheticTerminalDetector.isSyntheticTerminalRule(terminalRule) && !terminalRule.isFragment()) { syntheticKwAlternatives.add("(FRAGMENT_" + AntlrGrammarGenUtil.getRuleName(rule) + ")=> FRAGMENT_" + AntlrGrammarGenUtil.getRuleName(rule) + " {$type = " + AntlrGrammarGenUtil.getRuleName(rule) + "; }"); } } } - StringConcatenation sb = new StringConcatenation(); + final StringConcatenation sb = new StringConcatenation(); if (options.isBacktrackLexer()) { sb.append("SYNTHETIC_ALL_KEYWORDS :"); sb.newLine(); @@ -233,9 +236,9 @@ protected CharSequence compileKeywordRules(Grammar it, AntlrOptions options) { sb.append(syntheticKwAlternatives.get(i)); sb.newLine(); } - sb.append(";"); + sb.append(';'); sb.newLine(); - for (String kw : allKeywords) { + for (final String kw : allKeywords) { sb.append("fragment FRAGMENT_"); sb.append(keywordHelper.getRuleName(kw)); sb.append(" : \'"); @@ -244,7 +247,7 @@ protected CharSequence compileKeywordRules(Grammar it, AntlrOptions options) { sb.newLine(); } } else { - for (String rule : allKeywords) { + for (final String rule : allKeywords) { sb.append(compileRule(rule, it, options)); sb.newLineIfNotEmpty(); } @@ -252,11 +255,11 @@ protected CharSequence compileKeywordRules(Grammar it, AntlrOptions options) { return sb; } - private static Set getAllKeywords(Grammar flattenedGrammar, AntlrOptions options) { - Set result = new TreeSet<>(KeywordHelper.keywordComparator); - List parserRules = GrammarUtil.allParserRules(flattenedGrammar); - List enumRules = GrammarUtil.allEnumRules(flattenedGrammar); - Iterator iter = Iterators.concat(EcoreUtil.getAllContents(parserRules), EcoreUtil.getAllContents(enumRules)); + private static Set getAllKeywords(final Grammar flattenedGrammar, final AntlrOptions options) { + final Set result = new TreeSet<>(KeywordHelper.keywordComparator); + final List parserRules = GrammarUtil.allParserRules(flattenedGrammar); + final List enumRules = GrammarUtil.allEnumRules(flattenedGrammar); + final Iterator iter = Iterators.concat(EcoreUtil.getAllContents(parserRules), EcoreUtil.getAllContents(enumRules)); Iterators.addAll(result, Iterators.transform( Iterators.filter(iter, Keyword.class), kw -> options.isIgnoreCase() ? kw.getValue().toLowerCase(Locale.ENGLISH) : kw.getValue() @@ -265,3 +268,4 @@ private static Set getAllKeywords(Grammar flattenedGrammar, AntlrOptions } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java index 2d5c88664f..d45de6b2c3 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java @@ -40,6 +40,8 @@ import com.google.common.collect.Iterables; import com.google.inject.Inject; +// CHECKSTYLE:CONSTANTS-OFF + /** * This implementation is strongly based on AntlrContentAssistGrammarGenerator but with a different base class. * The following extension is supported: @@ -77,6 +79,7 @@ * be used in the alternative * - Error messages will be adjusted correspondingly */ +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class AnnotationAwareAntlrContentAssistGrammarGenerator extends AbstractAnnotationAwareAntlrGrammarGenerator { @Inject @@ -94,543 +97,461 @@ protected boolean isParserBackTracking(final Grammar it, final AntlrOptions opti @Override protected String compileParserImports(final Grammar it, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _isCombinedGrammar = this.isCombinedGrammar(); - boolean _not = (!_isCombinedGrammar); - if (_not) { - _builder.append("import java.util.Map;"); - _builder.newLine(); - _builder.append("import java.util.HashMap;"); - _builder.newLine(); - } + final StringConcatenation builder = new StringConcatenation(); + if (!this.isCombinedGrammar()) { + builder.append("import java.util.Map;"); + builder.newLine(); + builder.append("import java.util.HashMap;"); + builder.newLine(); } - _builder.newLine(); - _builder.append("import java.io.InputStream;"); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.*;"); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.parser.*;"); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.parser.impl.*;"); - _builder.newLine(); - _builder.append("import org.eclipse.emf.ecore.util.EcoreUtil;"); - _builder.newLine(); - _builder.append("import org.eclipse.emf.ecore.EObject;"); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream;"); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream.HiddenTokens;"); - _builder.newLine(); - _builder.append("import "); - String _name = this.getGrammarNaming().getInternalParserSuperClass(it).getName(); - _builder.append(_name); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - _builder.append("import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.DFA;"); - _builder.newLine(); - _builder.append("import "); - String _name_1 = this._grammarAccessExtensions.getGrammarAccess(it).getName(); - _builder.append(_name_1); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - String _compileParserImports = super.compileParserImports(it, options); - _builder.append(_compileParserImports); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - return _builder.toString(); + builder.newLine(); + builder.append("import java.io.InputStream;"); + builder.newLine(); + builder.append("import org.eclipse.xtext.*;"); + builder.newLine(); + builder.append("import org.eclipse.xtext.parser.*;"); + builder.newLine(); + builder.append("import org.eclipse.xtext.parser.impl.*;"); + builder.newLine(); + builder.append("import org.eclipse.emf.ecore.util.EcoreUtil;"); + builder.newLine(); + builder.append("import org.eclipse.emf.ecore.EObject;"); + builder.newLine(); + builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream;"); + builder.newLine(); + builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream.HiddenTokens;"); + builder.newLine(); + builder.append("import "); + builder.append(this.getGrammarNaming().getInternalParserSuperClass(it).getName()); + builder.append(';'); + builder.newLineIfNotEmpty(); + builder.append("import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.DFA;"); + builder.newLine(); + builder.append("import "); + builder.append(this._grammarAccessExtensions.getGrammarAccess(it).getName()); + builder.append(';'); + builder.newLineIfNotEmpty(); + builder.append(super.compileParserImports(it, options)); + builder.newLineIfNotEmpty(); + builder.newLine(); + return builder.toString(); } @Override protected String compileParserMembers(final Grammar it, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("@"); - { - boolean _isCombinedGrammar = this.isCombinedGrammar(); - if (_isCombinedGrammar) { - _builder.append("parser::"); - } + final StringConcatenation builder = new StringConcatenation(); + builder.append('@'); + if (this.isCombinedGrammar()) { + builder.append("parser::"); } - _builder.append("members {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - CharSequence _compileParserMemberDeclarations = this.compileParserMemberDeclarations(it, "protected"); - _builder.append(_compileParserMemberDeclarations, " "); - _builder.newLineIfNotEmpty(); - { - boolean _isCombinedGrammar_1 = this.isCombinedGrammar(); - boolean _not = (!_isCombinedGrammar_1); - if (_not) { - _builder.append(" "); - _builder.append("private final Map tokenNameToValue = new HashMap();"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - { - List _sortBy = IterableExtensions.sortBy(IterableExtensions.sort(GrammarUtil.getAllKeywords(it)), (String it_1) -> Integer.valueOf(it_1.length())); - for (final String kw : _sortBy) { - _builder.append(" "); - _builder.append(" "); - _builder.append("tokenNameToValue.put(\""); - String _ruleName = this.keywordHelper.getRuleName(kw); - _builder.append(_ruleName, " "); - _builder.append("\", \"\'"); - String _replace = AntlrGrammarGenUtil.toStringInAntlrAction(kw).replace("$", "\\u0024"); - _builder.append(_replace, " "); - _builder.append("\'\");"); - _builder.newLineIfNotEmpty(); - } - } - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); + builder.append("members {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this.compileParserMemberDeclarations(it, "protected"), " "); + builder.newLineIfNotEmpty(); + if (!this.isCombinedGrammar()) { + builder.append(" "); + builder.append("private final Map tokenNameToValue = new HashMap();"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append('{'); + builder.newLine(); + for (final String kw : IterableExtensions.sortBy(IterableExtensions.sort(GrammarUtil.getAllKeywords(it)), (String it1) -> Integer.valueOf(it1.length()))) { + builder.append(" "); + builder.append(" "); + builder.append("tokenNameToValue.put(\""); + builder.append(this.keywordHelper.getRuleName(kw), " "); + builder.append("\", \"\'"); + builder.append(AntlrGrammarGenUtil.toStringInAntlrAction(kw).replace("$", "\\u0024"), " "); + builder.append("\'\");"); + builder.newLineIfNotEmpty(); } + builder.append(" "); + builder.append('}'); + builder.newLine(); } - _builder.newLine(); - _builder.append(" "); - CharSequence _compileParserSetTokenStreamMethod = this.compileParserSetTokenStreamMethod(); - _builder.append(_compileParserSetTokenStreamMethod, " "); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public void setPredicates("); - String _semanticPredicatesSimpleName = this.predicatesNaming.getSemanticPredicatesSimpleName(it); - _builder.append(_semanticPredicatesSimpleName, " "); - _builder.append(" predicates) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("this.predicates = predicates;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public void setGrammarAccess("); - String _simpleName = this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(); - _builder.append(_simpleName, " "); - _builder.append(" grammarAccess) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("this.grammarAccess = grammarAccess;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append("public void setParserContext(ParserContext parserContext) {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("this.parserContext = parserContext;"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected Grammar getGrammar() {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("return grammarAccess.getGrammar();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected String getValueForTokenName(String tokenName) {"); - _builder.newLine(); - { - boolean _isCombinedGrammar_2 = this.isCombinedGrammar(); - if (_isCombinedGrammar_2) { - _builder.append(" "); - _builder.append("return tokenName;"); - _builder.newLine(); - } else { - _builder.append(" "); - _builder.append("String result = tokenNameToValue.get(tokenName);"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if (result == null)"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("result = tokenName;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("return result;"); - _builder.newLine(); - } + builder.newLine(); + builder.append(" "); + builder.append(this.compileParserSetTokenStreamMethod(), " "); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); + builder.append("public void setPredicates("); + builder.append(this.predicatesNaming.getSemanticPredicatesSimpleName(it), " "); + builder.append(" predicates) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("this.predicates = predicates;"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("public void setGrammarAccess("); + builder.append(this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(), " "); + builder.append(" grammarAccess) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("this.grammarAccess = grammarAccess;"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append("public void setParserContext(ParserContext parserContext) {"); + builder.newLine(); + builder.append(" "); + builder.append("this.parserContext = parserContext;"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected Grammar getGrammar() {"); + builder.newLine(); + builder.append(" "); + builder.append("return grammarAccess.getGrammar();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected String getValueForTokenName(String tokenName) {"); + builder.newLine(); + if (this.isCombinedGrammar()) { + builder.append(" "); + builder.append("return tokenName;"); + builder.newLine(); + } else { + builder.append(" "); + builder.append("String result = tokenNameToValue.get(tokenName);"); + builder.newLine(); + builder.append(" "); + builder.append("if (result == null)"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("result = tokenName;"); + builder.newLine(); + builder.append(" "); + builder.append("return result;"); + builder.newLine(); } - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } @Override protected CharSequence compileRules(final Grammar g, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - { - List _allParserRules = GrammarUtil.allParserRules(g); - List _allEnumRules = GrammarUtil.allEnumRules(g); - Iterable _plus = Iterables.concat(_allParserRules, _allEnumRules); - Iterable _plus_1 = Iterables.concat(_plus, GrammarUtil.getAllAlternatives(g)); - Iterable _plus_2 = Iterables.concat(_plus_1, GrammarUtil.getAllGroups(g)); - Iterable _plus_3 = Iterables.concat(_plus_2, GrammarUtil.getAllUnorderedGroups(g)); - Iterable _filter = IterableExtensions.filter(Iterables.concat(_plus_3, GrammarUtil.getAllAssignments(g)), - (EObject it) -> Boolean.valueOf(this._grammarAccessExtensions.isCalled(GrammarUtil.containingRule(it), g))); - for (final EObject rule : _filter) { - _builder.newLine(); - CharSequence _compileRule = this.compileRule(rule, g, options); - _builder.append(_compileRule); - _builder.newLineIfNotEmpty(); - } + final StringConcatenation builder = new StringConcatenation(); + final Iterable allRulesAndElements = IterableExtensions.filter( + Iterables.concat( + Iterables.concat( + Iterables.concat( + Iterables.concat( + Iterables.concat(GrammarUtil.allParserRules(g), GrammarUtil.allEnumRules(g)), + GrammarUtil.getAllAlternatives(g)), + GrammarUtil.getAllGroups(g)), + GrammarUtil.getAllUnorderedGroups(g)), + GrammarUtil.getAllAssignments(g)), + (EObject it) -> Boolean.valueOf(this._grammarAccessExtensions.isCalled(GrammarUtil.containingRule(it), g))); + for (final EObject rule : allRulesAndElements) { + builder.newLine(); + builder.append(this.compileRule(rule, g, options)); + builder.newLineIfNotEmpty(); } - { - boolean _isCombinedGrammar = this.isCombinedGrammar(); - if (_isCombinedGrammar) { - CharSequence _compileTerminalRules = this.compileTerminalRules(g, options); - _builder.append(_compileTerminalRules); - _builder.newLineIfNotEmpty(); - } + if (this.isCombinedGrammar()) { + builder.append(this.compileTerminalRules(g, options)); + builder.newLineIfNotEmpty(); } - return _builder; + return builder; } @Override protected CharSequence _compileRule(final ParserRule it, final Grammar grammar, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _isValidEntryRule = AntlrGrammarGenUtil.isValidEntryRule(it); - if (_isValidEntryRule) { - _builder.append("// Entry rule "); - String _entryRuleName = this._grammarAccessExtensions.entryRuleName(it); - _builder.append(_entryRuleName); - _builder.newLineIfNotEmpty(); - String _entryRuleName_1 = this._grammarAccessExtensions.entryRuleName(it); - _builder.append(_entryRuleName_1); - _builder.newLineIfNotEmpty(); - { - boolean _isDefinesHiddenTokens = it.isDefinesHiddenTokens(); - if (_isDefinesHiddenTokens) { - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - CharSequence _compileInitHiddenTokens = this.compileInitHiddenTokens(it, options); - _builder.append(_compileInitHiddenTokens, " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - } - } - _builder.append(":"); - _builder.newLine(); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - String _ruleName = this._grammarAccessExtensions.ruleName(it); - _builder.append(_ruleName, " "); - _builder.newLineIfNotEmpty(); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_1); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("EOF"); - _builder.newLine(); - _builder.append(";"); - _builder.newLine(); - { - boolean _isDefinesHiddenTokens_1 = it.isDefinesHiddenTokens(); - if (_isDefinesHiddenTokens_1) { - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - CharSequence _compileRestoreHiddenTokens = this.compileRestoreHiddenTokens(it, options); - _builder.append(_compileRestoreHiddenTokens, " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - } - } + final StringConcatenation builder = new StringConcatenation(); + if (AntlrGrammarGenUtil.isValidEntryRule(it)) { + builder.append("// Entry rule "); + builder.append(this._grammarAccessExtensions.entryRuleName(it)); + builder.newLineIfNotEmpty(); + builder.append(this._grammarAccessExtensions.entryRuleName(it)); + builder.newLineIfNotEmpty(); + if (it.isDefinesHiddenTokens()) { + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append(this.compileInitHiddenTokens(it, options), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); } - } - _builder.newLine(); - _builder.append("// Rule "); - String _name = AntlrGrammarGenUtil.getOriginalElement(it).getName(); - _builder.append(_name); - _builder.newLineIfNotEmpty(); - String _ruleName_1 = this._grammarAccessExtensions.ruleName(it); - _builder.append(_ruleName_1); - _builder.newLineIfNotEmpty(); - { - boolean _hasNoBacktrackAnnotation = this.annotations.hasNoBacktrackAnnotation(it); - if (_hasNoBacktrackAnnotation) { - _builder.append(" "); - _builder.append("// Enclosing rule was annotated with @NoBacktrack"); - _builder.newLine(); - _builder.append(" "); - _builder.append("options { backtrack=false; }"); - _builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append("{ before(grammarAccess."); + builder.append(this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this._grammarAccessExtensions.ruleName(it), " "); + builder.newLineIfNotEmpty(); + builder.append("{ after(grammarAccess."); + builder.append(this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("EOF"); + builder.newLine(); + builder.append(';'); + builder.newLine(); + if (it.isDefinesHiddenTokens()) { + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append(this.compileRestoreHiddenTokens(it, options), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); } } - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - CharSequence _compileInitHiddenTokens_1 = this.compileInitHiddenTokens(it, options); - _builder.append(_compileInitHiddenTokens_1, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - _builder.append(":"); - _builder.newLine(); - _builder.append(" "); - { - boolean _hasValidatingPredicate = this.annotations.hasValidatingPredicate(it); - if (_hasValidatingPredicate) { - String _generateValidatingPredicate = this.annotations.generateValidatingPredicate(it); - _builder.append(_generateValidatingPredicate, " "); - } + builder.newLine(); + builder.append("// Rule "); + builder.append(AntlrGrammarGenUtil.getOriginalElement(it).getName()); + builder.newLineIfNotEmpty(); + builder.append(this._grammarAccessExtensions.ruleName(it)); + builder.newLineIfNotEmpty(); + if (this.annotations.hasNoBacktrackAnnotation(it)) { + builder.append(" "); + builder.append("// Enclosing rule was annotated with @NoBacktrack"); + builder.newLine(); + builder.append(" "); + builder.append("options { backtrack=false; }"); + builder.newLine(); + } + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append(this.compileInitHiddenTokens(it, options), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(" "); + builder.append(':'); + builder.newLine(); + builder.append(" "); + if (this.annotations.hasValidatingPredicate(it)) { + builder.append(this.annotations.generateValidatingPredicate(it), " "); } - _builder.newLineIfNotEmpty(); - _builder.append(" "); - String _ebnf = this.ebnf(it.getAlternatives(), options, false); - _builder.append(_ebnf, " "); - _builder.newLineIfNotEmpty(); - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append(" "); - CharSequence _compileRestoreHiddenTokens_1 = this.compileRestoreHiddenTokens(it, options); - _builder.append(_compileRestoreHiddenTokens_1, " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - return _builder; + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this.ebnf(it.getAlternatives(), options, false), " "); + builder.newLineIfNotEmpty(); + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append(" "); + builder.append(this.compileRestoreHiddenTokens(it, options), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + return builder; } @Override protected CharSequence _compileRule(final EnumRule it, final Grammar grammar, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("// Rule "); - String _name = AntlrGrammarGenUtil.getOriginalElement(it).getName(); - _builder.append(_name); - _builder.newLineIfNotEmpty(); - String _ruleName = this._grammarAccessExtensions.ruleName(it); - _builder.append(_ruleName); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(":"); - _builder.newLine(); - _builder.append(" "); - String _ebnf = this.ebnf(it.getAlternatives(), options, false); - _builder.append(_ebnf, " "); - _builder.newLineIfNotEmpty(); - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder; + final StringConcatenation builder = new StringConcatenation(); + builder.append("// Rule "); + builder.append(AntlrGrammarGenUtil.getOriginalElement(it).getName()); + builder.newLineIfNotEmpty(); + builder.append(this._grammarAccessExtensions.ruleName(it)); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append(" "); + builder.append(this.ebnf(it.getAlternatives(), options, false), " "); + builder.newLineIfNotEmpty(); + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder; } protected CharSequence _compileRule(final Alternatives it, final Grammar grammar, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(":"); - _builder.newLine(); - _builder.append(" "); - { - EList _elements = it.getElements(); - boolean _hasElements = false; - for (final AbstractElement element : _elements) { - if (!_hasElements) { - _hasElements = true; - } else { - _builder.appendImmediate("\n|", " "); - } - String _ebnf = this.ebnf(element, options, false); - _builder.append(_ebnf, " "); + final StringConcatenation builder = new StringConcatenation(); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it))); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append(" "); + boolean hasElements = false; + for (final AbstractElement element : it.getElements()) { + if (!hasElements) { + hasElements = true; + } else { + builder.appendImmediate("\n|", " "); } + builder.append(this.ebnf(element, options, false), " "); } - _builder.newLineIfNotEmpty(); - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder; + builder.newLineIfNotEmpty(); + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder; } protected CharSequence _compileRule(final Assignment it, final Grammar grammar, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(":"); - _builder.newLine(); - _builder.append(" "); - String _assignmentEbnf = this.assignmentEbnf(it.getTerminal(), it, options, false); - _builder.append(_assignmentEbnf, " "); - _builder.newLineIfNotEmpty(); - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder; + final StringConcatenation builder = new StringConcatenation(); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it))); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append(" "); + builder.append(this.assignmentEbnf(it.getTerminal(), it, options, false), " "); + builder.newLineIfNotEmpty(); + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder; } protected CharSequence _compileRule(final UnorderedGroup it, final Grammar grammar, final AntlrOptions options) { - final boolean hasMandatoryContent = IterableExtensions.exists(it.getElements(), (AbstractElement it_1) -> !GrammarUtil.isOptionalCardinality(it_1)); - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("getUnorderedGroupHelper().enter(grammarAccess."); - String _gaRuleElementAccessor = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaRuleElementAccessor, " "); - _builder.append(");"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(":"); - _builder.newLine(); - _builder.append(" "); - String _contentAssistRuleName_1 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName_1, " "); - _builder.append("__"); - String _gaElementIdentifier_1 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier_1, " "); - _builder.append("__0"); - _builder.newLineIfNotEmpty(); - { - if (hasMandatoryContent) { - _builder.append(" "); - _builder.append("{getUnorderedGroupHelper().canLeave(grammarAccess."); - String _gaRuleElementAccessor_1 = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaRuleElementAccessor_1, " "); - _builder.append(")}?"); - _builder.newLineIfNotEmpty(); - } else { - _builder.append(" "); - _builder.append("?"); - _builder.newLine(); - } + final boolean hasMandatoryContent = IterableExtensions.exists(it.getElements(), (AbstractElement it1) -> !GrammarUtil.isOptionalCardinality(it1)); + final StringConcatenation builder = new StringConcatenation(); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it))); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append("getUnorderedGroupHelper().enter(grammarAccess."); + builder.append(this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append(");"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append(" "); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)), " "); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append("__0"); + builder.newLineIfNotEmpty(); + if (hasMandatoryContent) { + builder.append(" "); + builder.append("{getUnorderedGroupHelper().canLeave(grammarAccess."); + builder.append(this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append(")}?"); + builder.newLineIfNotEmpty(); + } else { + builder.append(" "); + builder.append('?'); + builder.newLine(); } - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("getUnorderedGroupHelper().leave(grammarAccess."); - String _gaRuleElementAccessor_2 = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaRuleElementAccessor_2, " "); - _builder.append(");"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - CharSequence _ruleImpl = this.ruleImpl(it, grammar, options); - _builder.append(_ruleImpl); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - CharSequence _ruleImpl_1 = this.ruleImpl(it, grammar, options, 0); - _builder.append(_ruleImpl_1); - _builder.newLineIfNotEmpty(); - return _builder; + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("getUnorderedGroupHelper().leave(grammarAccess."); + builder.append(this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append(");"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append(this.ruleImpl(it, grammar, options)); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(this.ruleImpl(it, grammar, options, 0)); + builder.newLineIfNotEmpty(); + return builder; } protected CharSequence _compileRule(final Group it, final Grammar grammar, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - CharSequence _ruleImpl = this.ruleImpl(it, grammar, options, 0); - _builder.append(_ruleImpl); - _builder.newLineIfNotEmpty(); - return _builder; + final StringConcatenation builder = new StringConcatenation(); + builder.append(this.ruleImpl(it, grammar, options, 0)); + builder.newLineIfNotEmpty(); + return builder; } /** @@ -656,662 +577,579 @@ protected CharSequence compileRule(final Object it, final Grammar grammar, final } protected CharSequence ruleImpl(final UnorderedGroup it, final Grammar grammar, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - _builder.append("__Impl"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("boolean selected = false;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(":"); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - { - Iterable> _indexed = IterableExtensions.indexed(it.getElements()); - boolean _hasElements = false; - for (final Pair element : _indexed) { - if (!_hasElements) { - _hasElements = true; - } else { - _builder.appendImmediate("|", " "); - } - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("{getUnorderedGroupHelper().canSelect(grammarAccess."); - String _gaRuleElementAccessor = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaRuleElementAccessor, " "); - _builder.append(", "); - Integer _key = element.getKey(); - _builder.append(_key, " "); - _builder.append(")}?=>("); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("getUnorderedGroupHelper().select(grammarAccess."); - String _gaRuleElementAccessor_1 = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaRuleElementAccessor_1, " "); - _builder.append(", "); - Integer _key_1 = element.getKey(); - _builder.append(_key_1, " "); - _builder.append(");"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("selected = true;"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - { - boolean _isMultipleCardinality = GrammarUtil.isMultipleCardinality(element.getValue()); - if (_isMultipleCardinality) { - _builder.append(" "); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); - _builder.append(_grammarElementAccess, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append(" "); - _builder.append("("); - String _ebnf2 = this.ebnf2(element.getValue(), options, false); - _builder.append(_ebnf2, " "); - _builder.append(")"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); - _builder.append(_grammarElementAccess_1, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess_2 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); - _builder.append(_grammarElementAccess_2, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append(" "); - _builder.append("(("); - String _ebnf2_1 = this.ebnf2(element.getValue(), options, false); - _builder.append(_ebnf2_1, " "); - _builder.append(")=>"); - String _ebnf2_2 = this.ebnf2(element.getValue(), options, false); - _builder.append(_ebnf2_2, " "); - _builder.append(")*"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_3 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); - _builder.append(_grammarElementAccess_3, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - } else { - _builder.append(" "); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess_4 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); - _builder.append(_grammarElementAccess_4, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("("); - String _ebnf2_3 = this.ebnf2(element.getValue(), options, false); - _builder.append(_ebnf2_3, " "); - _builder.append(")"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_5 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); - _builder.append(_grammarElementAccess_5, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - } - } - _builder.append(" "); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); + final StringConcatenation builder = new StringConcatenation(); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it))); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.append("__Impl"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append("boolean selected = false;"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append(" "); + builder.append('('); + builder.newLine(); + boolean hasElements = false; + for (final Pair element : IterableExtensions.indexed(it.getElements())) { + if (!hasElements) { + hasElements = true; + } else { + builder.appendImmediate("|", " "); + } + final String originalAccessor = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); + final String originalElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(element.getValue())); + builder.append(" "); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("{getUnorderedGroupHelper().canSelect(grammarAccess."); + builder.append(originalAccessor, " "); + builder.append(", "); + builder.append(element.getKey(), " "); + builder.append(")}?=>("); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("getUnorderedGroupHelper().select(grammarAccess."); + builder.append(originalAccessor, " "); + builder.append(", "); + builder.append(element.getKey(), " "); + builder.append(");"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("selected = true;"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append('('); + builder.newLine(); + if (GrammarUtil.isMultipleCardinality(element.getValue())) { + builder.append(" "); + builder.append(" "); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(originalElementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append(" "); + builder.append('('); + builder.append(this.ebnf2(element.getValue(), options, false), " "); + builder.append(')'); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(originalElementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append(')'); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(originalElementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append(" "); + builder.append("(("); + builder.append(this.ebnf2(element.getValue(), options, false), " "); + builder.append(")=>"); + builder.append(this.ebnf2(element.getValue(), options, false), " "); + builder.append(")*"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(originalElementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append(')'); + builder.newLine(); + } else { + builder.append(" "); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(originalElementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append('('); + builder.append(this.ebnf2(element.getValue(), options, false), " "); + builder.append(')'); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(originalElementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); } + builder.append(" "); + builder.append(" "); + builder.append(')'); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append(')'); + builder.newLine(); + builder.append(" "); + builder.append(')'); + builder.newLine(); } - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if (selected)"); - _builder.newLine(); - _builder.append(" "); - _builder.append("getUnorderedGroupHelper().returnFromSelection(grammarAccess."); - String _gaRuleElementAccessor_2 = this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaRuleElementAccessor_2, " "); - _builder.append(");"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder; + builder.append(" "); + builder.append(')'); + builder.newLine(); + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("if (selected)"); + builder.newLine(); + builder.append(" "); + builder.append("getUnorderedGroupHelper().returnFromSelection(grammarAccess."); + builder.append(this._grammarAccessExtensions.gaRuleElementAccessor(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append(");"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder; } protected CharSequence ruleImpl(final UnorderedGroup it, final Grammar grammar, final AntlrOptions options, final int index) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - _builder.append("__"); - _builder.append(index); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(":"); - _builder.newLine(); - _builder.append(" "); - String _contentAssistRuleName_1 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName_1, " "); - _builder.append("__"); - String _gaElementIdentifier_1 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier_1, " "); - _builder.append("__Impl"); - _builder.newLineIfNotEmpty(); - { - int _size = it.getElements().size(); - if (_size > (index + 1)) { - _builder.append(" "); - String _contentAssistRuleName_2 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName_2, " "); - _builder.append("__"); - String _gaElementIdentifier_2 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier_2, " "); - _builder.append("__"); - _builder.append((index + 1), " "); - _builder.append("?"); - _builder.newLineIfNotEmpty(); - } + final StringConcatenation builder = new StringConcatenation(); + final String ruleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + final String elementId = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + builder.append(ruleName); + builder.append("__"); + builder.append(elementId); + builder.append("__"); + builder.append(index); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append(" "); + builder.append(ruleName, " "); + builder.append("__"); + builder.append(elementId, " "); + builder.append("__Impl"); + builder.newLineIfNotEmpty(); + if (it.getElements().size() > (index + 1)) { + builder.append(" "); + builder.append(ruleName, " "); + builder.append("__"); + builder.append(elementId, " "); + builder.append("__"); + builder.append((index + 1), " "); + builder.append('?'); + builder.newLineIfNotEmpty(); } - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - { - int _size_1 = it.getElements().size(); - if (_size_1 > (index + 1)) { - CharSequence _ruleImpl = this.ruleImpl(it, grammar, options, (index + 1)); - _builder.append(_ruleImpl); - _builder.newLineIfNotEmpty(); - } + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + builder.newLine(); + if (it.getElements().size() > (index + 1)) { + builder.append(this.ruleImpl(it, grammar, options, (index + 1))); + builder.newLineIfNotEmpty(); } - return _builder; + return builder; } protected CharSequence ruleImpl(final Group it, final Grammar grammar, final AntlrOptions options, final int index) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - _builder.append("__"); - _builder.append(index); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(":"); - _builder.newLine(); - _builder.append(" "); - String _contentAssistRuleName_1 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName_1, " "); - _builder.append("__"); - String _gaElementIdentifier_1 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier_1, " "); - _builder.append("__"); - _builder.append(index, " "); - _builder.append("__Impl"); - _builder.newLineIfNotEmpty(); - { - int _size = it.getElements().size(); - if (_size > (index + 1)) { - _builder.append(" "); - String _contentAssistRuleName_2 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName_2, " "); - _builder.append("__"); - String _gaElementIdentifier_2 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier_2, " "); - _builder.append("__"); - _builder.append((index + 1), " "); - _builder.newLineIfNotEmpty(); - } + final StringConcatenation builder = new StringConcatenation(); + final String ruleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); + final String elementId = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); + builder.append(ruleName); + builder.append("__"); + builder.append(elementId); + builder.append("__"); + builder.append(index); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append(" "); + builder.append(ruleName, " "); + builder.append("__"); + builder.append(elementId, " "); + builder.append("__"); + builder.append(index, " "); + builder.append("__Impl"); + builder.newLineIfNotEmpty(); + if (it.getElements().size() > (index + 1)) { + builder.append(" "); + builder.append(ruleName, " "); + builder.append("__"); + builder.append(elementId, " "); + builder.append("__"); + builder.append((index + 1), " "); + builder.newLineIfNotEmpty(); } - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - String _contentAssistRuleName_3 = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName_3); - _builder.append("__"); - String _gaElementIdentifier_3 = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier_3); - _builder.append("__"); - _builder.append(index); - _builder.append("__Impl"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("int stackSize = keepStackSize();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(":"); - _builder.newLine(); - String _ebnf = this.ebnf(it.getElements().get(index), options, false); - _builder.append(_ebnf); - _builder.newLineIfNotEmpty(); - _builder.append(";"); - _builder.newLine(); - _builder.append("finally {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("restoreStackSize(stackSize);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - { - int _size_1 = it.getElements().size(); - if (_size_1 > (index + 1)) { - CharSequence _ruleImpl = this.ruleImpl(it, grammar, options, (index + 1)); - _builder.append(_ruleImpl); - _builder.newLineIfNotEmpty(); - } + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append(ruleName); + builder.append("__"); + builder.append(elementId); + builder.append("__"); + builder.append(index); + builder.append("__Impl"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("int stackSize = keepStackSize();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(':'); + builder.newLine(); + builder.append(this.ebnf(it.getElements().get(index), options, false)); + builder.newLineIfNotEmpty(); + builder.append(';'); + builder.newLine(); + builder.append("finally {"); + builder.newLine(); + builder.append(" "); + builder.append("restoreStackSize(stackSize);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + builder.newLine(); + if (it.getElements().size() > (index + 1)) { + builder.append(this.ruleImpl(it, grammar, options, (index + 1))); + builder.newLineIfNotEmpty(); } - return _builder; + return builder; } @Override protected String ebnf(final AbstractElement it, final AntlrOptions options, final boolean supportsActions) { - StringConcatenation _builder = new StringConcatenation(); - { - if ((!GrammarUtil.isOptionalCardinality(it)) && GrammarUtil.isMultipleCardinality(it)) { - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - CharSequence _paramConfig = this.paramConfig(it); - _builder.append(_paramConfig, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("("); - String _ebnf2 = this.ebnf2(it, options, supportsActions); - _builder.append(_ebnf2, " "); - _builder.append(")"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_1, " "); - CharSequence _paramConfig_1 = this.paramConfig(it); - _builder.append(_paramConfig_1, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess_2 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_2, " "); - CharSequence _paramConfig_2 = this.paramConfig(it); - _builder.append(_paramConfig_2, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("("); - String _ebnf2_1 = this.ebnf2(it, options, supportsActions); - _builder.append(_ebnf2_1, " "); - _builder.append(")*"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_3 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_3, " "); - CharSequence _paramConfig_3 = this.paramConfig(it); - _builder.append(_paramConfig_3, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.append(")"); - _builder.newLine(); + final StringConcatenation builder = new StringConcatenation(); + final String elementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + final CharSequence paramCfg = this.paramConfig(it); + if ((!GrammarUtil.isOptionalCardinality(it)) && GrammarUtil.isMultipleCardinality(it)) { + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append(paramCfg, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append('('); + builder.append(this.ebnf2(it, options, supportsActions), " "); + builder.append(')'); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append(paramCfg, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(')'); + builder.newLine(); + builder.append(" "); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append(paramCfg, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append('('); + builder.append(this.ebnf2(it, options, supportsActions), " "); + builder.append(")*"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append(paramCfg, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(')'); + builder.newLine(); + builder.append(')'); + builder.newLine(); + } else { + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append(paramCfg, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + if (this.mustBeParenthesized(it)) { + builder.append('('); + builder.append(this.ebnf2(it, options, supportsActions), " "); + builder.append(')'); } else { - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess_4 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_4, " "); - CharSequence _paramConfig_4 = this.paramConfig(it); - _builder.append(_paramConfig_4, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - { - boolean _mustBeParenthesized = this.mustBeParenthesized(it); - if (_mustBeParenthesized) { - _builder.append("("); - String _ebnf2_2 = this.ebnf2(it, options, supportsActions); - _builder.append(_ebnf2_2, " "); - _builder.append(")"); - } else { - String _ebnf2_3 = this.ebnf2(it, options, supportsActions); - _builder.append(_ebnf2_3, " "); - } - } - String _cardinality = it.getCardinality(); - _builder.append(_cardinality, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_5 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_5, " "); - CharSequence _paramConfig_5 = this.paramConfig(it); - _builder.append(_paramConfig_5, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - _builder.newLine(); + builder.append(this.ebnf2(it, options, supportsActions), " "); } + builder.append(it.getCardinality(), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append(paramCfg, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(')'); + builder.newLine(); } - return _builder.toString(); + return builder.toString(); } protected CharSequence paramConfig(final AbstractElement it) { - StringConcatenation _builder = new StringConcatenation(); - { - if (((GrammarUtil.containingRule(it).getAlternatives() == it) && ParserRule.class.isInstance(GrammarUtil.containingRule(it)) && (!((ParserRule) AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingRule(it))).getParameters().isEmpty()))) { - _builder.append(", "); - AbstractRule _containingRule = GrammarUtil.containingRule(it); - int _parameterConfig = AntlrGrammarGenUtil.getParameterConfig((ParserRule) _containingRule); - _builder.append(_parameterConfig); - _builder.newLineIfNotEmpty(); - } + final StringConcatenation builder = new StringConcatenation(); + if (((GrammarUtil.containingRule(it).getAlternatives() == it) && ParserRule.class.isInstance(GrammarUtil.containingRule(it)) && (!((ParserRule) AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingRule(it))).getParameters().isEmpty()))) { + builder.append(", "); + builder.append(AntlrGrammarGenUtil.getParameterConfig((ParserRule) GrammarUtil.containingRule(it))); + builder.newLineIfNotEmpty(); } - return _builder; + return builder; } @Override protected String _assignmentEbnf(final AbstractElement it, final Assignment assignment, final AntlrOptions options, final boolean supportsActions) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - String _ebnf = this.ebnf(it, options, supportsActions); - _builder.append(_ebnf, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_1, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + final String elementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this.ebnf(it, options, supportsActions), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(')'); + builder.newLine(); + return builder.toString(); } @Override protected String _assignmentEbnf(final CrossReference it, final Assignment assignment, final AntlrOptions options, final boolean supportsActions) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - String _crossrefEbnf = this.crossrefEbnf(it.getTerminal(), it, supportsActions); - _builder.append(_crossrefEbnf, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_1, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + final String elementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this.crossrefEbnf(it.getTerminal(), it, supportsActions), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(')'); + builder.newLine(); + return builder.toString(); } @Override protected String _assignmentEbnf(final Alternatives it, final Assignment assignment, final AntlrOptions options, final boolean supportsActions) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("("); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName, " "); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier, " "); - _builder.append(")"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_1, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + final String elementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append('('); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)), " "); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append(')'); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(')'); + builder.newLine(); + return builder.toString(); } @Override protected String _assignmentEbnf(final RuleCall it, final Assignment assignment, final AntlrOptions options, final boolean supportsActions) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - String _ruleName = this._grammarAccessExtensions.ruleName(it.getRule()); - _builder.append(_ruleName, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_1, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + final String elementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this._grammarAccessExtensions.ruleName(it.getRule()), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(')'); + builder.newLine(); + return builder.toString(); } @Override protected String _crossrefEbnf(final RuleCall it, final CrossReference ref, final boolean supportActions) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - String _crossrefEbnf = this.crossrefEbnf(it.getRule(), it, ref, supportActions); - _builder.append(_crossrefEbnf, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_1, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + final String elementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this.crossrefEbnf(it.getRule(), it, ref, supportActions), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(')'); + builder.newLine(); + return builder.toString(); } @Override protected String _crossrefEbnf(final Keyword it, final CrossReference ref, final boolean supportActions) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("("); - _builder.newLine(); - _builder.append(" "); - _builder.append("{ before(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - String _superCrossrefEbnf = super._crossrefEbnf(it, ref, supportActions); - _builder.append(_superCrossrefEbnf, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ after(grammarAccess."); - String _grammarElementAccess_1 = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess_1, " "); - _builder.append("); }"); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + final String elementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); + builder.append('('); + builder.newLine(); + builder.append(" "); + builder.append("{ before(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(super._crossrefEbnf(it, ref, supportActions), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ after(grammarAccess."); + builder.append(elementAccess, " "); + builder.append("); }"); + builder.newLineIfNotEmpty(); + builder.append(')'); + builder.newLine(); + return builder.toString(); } protected String crossrefEbnf(final TerminalRule it, final RuleCall call, final CrossReference ref, final boolean supportActions) { @@ -1331,47 +1169,39 @@ protected String crossrefEbnf(final AbstractRule it, final RuleCall call, final @Override protected String _ebnf2(final Alternatives it, final AntlrOptions options, final boolean supportActions) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it))); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it))); + return builder.toString(); } @Override protected String _ebnf2(final Assignment it, final AntlrOptions options, final boolean supportActions) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it))); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it))); + return builder.toString(); } @Override protected String _ebnf2(final Group it, final AntlrOptions options, final boolean supportActions) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - _builder.append("__0"); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it))); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.append("__0"); + return builder.toString(); } @Override protected String _ebnf2(final UnorderedGroup it, final AntlrOptions options, final boolean supportActions) { - StringConcatenation _builder = new StringConcatenation(); - String _contentAssistRuleName = AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it)); - _builder.append(_contentAssistRuleName); - _builder.append("__"); - String _gaElementIdentifier = this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_gaElementIdentifier); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append(AntlrGrammarGenUtil.getContentAssistRuleName(GrammarUtil.containingRule(it))); + builder.append("__"); + builder.append(this._grammarAccessExtensions.gaElementIdentifier(AntlrGrammarGenUtil.getOriginalElement(it))); + return builder.toString(); } @Override @@ -1384,3 +1214,4 @@ protected boolean shouldBeSkipped(final TerminalRule it, final Grammar grammar) return false; } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java index d65da02e66..ed5fb293eb 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java @@ -10,8 +10,6 @@ *******************************************************************************/ package com.avaloq.tools.ddk.xtext.generator.parser.antlr; -import java.util.List; - import org.eclipse.emf.ecore.EObject; import org.eclipse.xtend2.lib.StringConcatenation; import org.eclipse.xtext.AbstractElement; @@ -40,6 +38,8 @@ import com.google.inject.Inject; import com.google.inject.Singleton; +// CHECKSTYLE:CONSTANTS-OFF + /** * This implementation is strongly based on AntlrGrammarGenerator but with a different base class. * The following extension is supported: @@ -78,6 +78,7 @@ * - Error messages will be adjusted correspondingly */ @Singleton +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class AnnotationAwareAntlrGrammarGenerator extends AbstractAnnotationAwareAntlrGrammarGenerator { @Inject @@ -96,187 +97,165 @@ protected GrammarNaming getGrammarNaming() { @Override protected String compileParserImports(final Grammar it, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.*;"); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.parser.*;"); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.parser.impl.*;"); - _builder.newLine(); - _builder.append("import org.eclipse.emf.ecore.util.EcoreUtil;"); - _builder.newLine(); - _builder.append("import org.eclipse.emf.ecore.EObject;"); - _builder.newLine(); - { - boolean _isEmpty = GrammarUtil.allEnumRules(it).isEmpty(); - boolean _not = (!_isEmpty); - if (_not) { - _builder.append("import org.eclipse.emf.common.util.Enumerator;"); - _builder.newLine(); - } + final StringConcatenation builder = new StringConcatenation(); + builder.newLine(); + builder.append("import org.eclipse.xtext.*;"); + builder.newLine(); + builder.append("import org.eclipse.xtext.parser.*;"); + builder.newLine(); + builder.append("import org.eclipse.xtext.parser.impl.*;"); + builder.newLine(); + builder.append("import org.eclipse.emf.ecore.util.EcoreUtil;"); + builder.newLine(); + builder.append("import org.eclipse.emf.ecore.EObject;"); + builder.newLine(); + if (!GrammarUtil.allEnumRules(it).isEmpty()) { + builder.append("import org.eclipse.emf.common.util.Enumerator;"); + builder.newLine(); } - _builder.append("import "); - String _name = this.getGrammarNaming().getInternalParserSuperClass(it).getName(); - _builder.append(_name); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - _builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream;"); - _builder.newLine(); - _builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream.HiddenTokens;"); - _builder.newLine(); - { - if ((!IterableExtensions.isEmpty(Iterables.filter(Iterables.concat(ListExtensions.map(GrammarUtil.allParserRules(it), (ParserRule it_1) -> EcoreUtil2.eAllContentsAsList(it_1))), UnorderedGroup.class))) && options.isBacktrack()) { - _builder.append("import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper.UnorderedGroupState;"); - _builder.newLine(); - } + builder.append("import "); + builder.append(this.getGrammarNaming().getInternalParserSuperClass(it).getName()); + builder.append(';'); + builder.newLineIfNotEmpty(); + builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream;"); + builder.newLine(); + builder.append("import org.eclipse.xtext.parser.antlr.XtextTokenStream.HiddenTokens;"); + builder.newLine(); + if ((!IterableExtensions.isEmpty(Iterables.filter(Iterables.concat(ListExtensions.map(GrammarUtil.allParserRules(it), (ParserRule it1) -> EcoreUtil2.eAllContentsAsList(it1))), UnorderedGroup.class))) && options.isBacktrack()) { + builder.append("import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper.UnorderedGroupState;"); + builder.newLine(); } - _builder.append("import org.eclipse.xtext.parser.antlr.AntlrDatatypeRuleToken;"); - _builder.newLine(); - _builder.append("import "); - String _name_1 = this._grammarAccessExtensions.getGrammarAccess(it).getName(); - _builder.append(_name_1); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - String _compileParserImports = super.compileParserImports(it, options); - _builder.append(_compileParserImports); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - return _builder.toString(); + builder.append("import org.eclipse.xtext.parser.antlr.AntlrDatatypeRuleToken;"); + builder.newLine(); + builder.append("import "); + builder.append(this._grammarAccessExtensions.getGrammarAccess(it).getName()); + builder.append(';'); + builder.newLineIfNotEmpty(); + builder.append(super.compileParserImports(it, options)); + builder.newLineIfNotEmpty(); + builder.newLine(); + return builder.toString(); } @Override protected String compileParserMembers(final Grammar it, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - _builder.newLine(); - _builder.append("@"); - { - boolean _isCombinedGrammar = this.isCombinedGrammar(); - if (_isCombinedGrammar) { - _builder.append("parser::"); - } + final StringConcatenation builder = new StringConcatenation(); + builder.newLine(); + builder.append('@'); + if (this.isCombinedGrammar()) { + builder.append("parser::"); } - _builder.append("members {"); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - { - boolean _isBacktrack = options.isBacktrack(); - if (_isBacktrack) { - _builder.append("/*"); - _builder.newLine(); - _builder.append(" "); - _builder.append("This grammar contains a lot of empty actions to work around a bug in ANTLR."); - _builder.newLine(); - _builder.append(" "); - _builder.append("Otherwise the ANTLR tool will create synpreds that cannot be compiled in some rare cases."); - _builder.newLine(); - _builder.append("*/"); - _builder.newLine(); - _builder.newLine(); - } + builder.append("members {"); + builder.newLineIfNotEmpty(); + builder.newLine(); + if (options.isBacktrack()) { + builder.append("/*"); + builder.newLine(); + builder.append(" "); + builder.append("This grammar contains a lot of empty actions to work around a bug in ANTLR."); + builder.newLine(); + builder.append(" "); + builder.append("Otherwise the ANTLR tool will create synpreds that cannot be compiled in some rare cases."); + builder.newLine(); + builder.append("*/"); + builder.newLine(); + builder.newLine(); } - _builder.append(" "); - CharSequence _compileParserMemberDeclarations = this.compileParserMemberDeclarations(it, "private"); - _builder.append(_compileParserMemberDeclarations, " "); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public "); - String _simpleName = this.naming.getInternalParserClass(it).getSimpleName(); - _builder.append(_simpleName, " "); - _builder.append("(TokenStream input, "); - String _simpleName_1 = this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(); - _builder.append(_simpleName_1, " "); - _builder.append(" grammarAccess, ParserContext parserContext, "); - String _semanticPredicatesSimpleName = this.predicatesNaming.getSemanticPredicatesSimpleName(it); - _builder.append(_semanticPredicatesSimpleName, " "); - _builder.append(" predicates) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("this(input);"); - _builder.newLine(); - _builder.append(" "); - _builder.append("this.grammarAccess = grammarAccess;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("this.predicates = predicates;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("this.parserContext = parserContext;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("parserContext.setTokenStream(input);"); - _builder.newLine(); - _builder.append(" "); - _builder.append("registerRules(grammarAccess.getGrammar());"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - CharSequence _compileParserSetTokenStreamMethod = this.compileParserSetTokenStreamMethod(); - _builder.append(_compileParserSetTokenStreamMethod, " "); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected String getFirstRuleName() {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("return \""); - String _name2 = AntlrGrammarGenUtil.getOriginalElement(IterableExtensions.head(GrammarUtil.allParserRules(it))).getName(); - _builder.append(_name2, " "); - _builder.append("\";"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected "); - String _simpleName_2 = this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(); - _builder.append(_simpleName_2, " "); - _builder.append(" getGrammarAccess() {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("return grammarAccess;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + builder.append(" "); + builder.append(this.compileParserMemberDeclarations(it, "private"), " "); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); + builder.append("public "); + builder.append(this.naming.getInternalParserClass(it).getSimpleName(), " "); + builder.append("(TokenStream input, "); + builder.append(this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(), " "); + builder.append(" grammarAccess, ParserContext parserContext, "); + builder.append(this.predicatesNaming.getSemanticPredicatesSimpleName(it), " "); + builder.append(" predicates) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("this(input);"); + builder.newLine(); + builder.append(" "); + builder.append("this.grammarAccess = grammarAccess;"); + builder.newLine(); + builder.append(" "); + builder.append("this.predicates = predicates;"); + builder.newLine(); + builder.append(" "); + builder.append("this.parserContext = parserContext;"); + builder.newLine(); + builder.append(" "); + builder.append("parserContext.setTokenStream(input);"); + builder.newLine(); + builder.append(" "); + builder.append("registerRules(grammarAccess.getGrammar());"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(this.compileParserSetTokenStreamMethod(), " "); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected String getFirstRuleName() {"); + builder.newLine(); + builder.append(" "); + builder.append("return \""); + builder.append(AntlrGrammarGenUtil.getOriginalElement(IterableExtensions.head(GrammarUtil.allParserRules(it))).getName(), " "); + builder.append("\";"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected "); + builder.append(this._grammarAccessExtensions.getGrammarAccess(it).getSimpleName(), " "); + builder.append(" getGrammarAccess() {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("return grammarAccess;"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } @Override protected String compileRuleCatch(final Grammar it, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - _builder.newLine(); - _builder.append("@rulecatch {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("catch (RecognitionException re) {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("recover(input,re);"); - _builder.newLine(); - _builder.append(" "); - _builder.append("appendSkippedTokens();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.newLine(); + builder.append("@rulecatch {"); + builder.newLine(); + builder.append(" "); + builder.append("catch (RecognitionException re) {"); + builder.newLine(); + builder.append(" "); + builder.append("recover(input,re);"); + builder.newLine(); + builder.append(" "); + builder.append("appendSkippedTokens();"); + builder.newLine(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } @Override @@ -286,135 +265,104 @@ protected boolean shouldBeSkipped(final TerminalRule it, final Grammar grammar) @Override protected CharSequence _compileRule(final ParserRule it, final Grammar grammar, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _isValidEntryRule = AntlrGrammarGenUtil.isValidEntryRule(it); - if (_isValidEntryRule) { - String _compileEntryRule = this.compileEntryRule(it, grammar, options); - _builder.append(_compileEntryRule); - _builder.newLineIfNotEmpty(); - } + final StringConcatenation builder = new StringConcatenation(); + if (AntlrGrammarGenUtil.isValidEntryRule(it)) { + builder.append(this.compileEntryRule(it, grammar, options)); + builder.newLineIfNotEmpty(); } - _builder.newLine(); - String _compileEBNF = this.compileEBNF(it, options); - _builder.append(_compileEBNF); - _builder.newLineIfNotEmpty(); - return _builder; + builder.newLine(); + builder.append(this.compileEBNF(it, options)); + builder.newLineIfNotEmpty(); + return builder; } protected String compileEntryRule(final ParserRule it, final Grammar grammar, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("// Entry rule "); - String _entryRuleName = this._grammarAccessExtensions.entryRuleName(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_entryRuleName); - _builder.newLineIfNotEmpty(); - String _entryRuleName_1 = this._grammarAccessExtensions.entryRuleName(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_entryRuleName_1); - _builder.append(" returns "); - String _compileEntryReturns = this.compileEntryReturns(it, options); - _builder.append(_compileEntryReturns); - CharSequence _compileEntryInit = this.compileEntryInit(it, options); - _builder.append(_compileEntryInit); - _builder.append(":"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ "); - CharSequence _newCompositeNode = this.newCompositeNode(it); - _builder.append(_newCompositeNode, " "); - _builder.append(" }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("iv_"); - String _ruleName = this._grammarAccessExtensions.ruleName(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_ruleName, " "); - _builder.append("="); - String _ruleName_1 = this._grammarAccessExtensions.ruleName(it); - _builder.append(_ruleName_1, " "); - String _defaultArgumentList = AntlrGrammarGenUtil.getDefaultArgumentList(it); - _builder.append(_defaultArgumentList, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("{ $current=$iv_"); - String _ruleName_2 = this._grammarAccessExtensions.ruleName(it); - _builder.append(_ruleName_2, " "); - _builder.append(".current"); - { - boolean _isDatatypeRule = GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it)); - if (_isDatatypeRule) { - _builder.append(".getText()"); - } + final StringConcatenation builder = new StringConcatenation(); + builder.append("// Entry rule "); + builder.append(this._grammarAccessExtensions.entryRuleName(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.newLineIfNotEmpty(); + builder.append(this._grammarAccessExtensions.entryRuleName(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.append(" returns "); + builder.append(this.compileEntryReturns(it, options)); + builder.append(this.compileEntryInit(it, options)); + builder.append(':'); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ "); + builder.append(this.newCompositeNode(it), " "); + builder.append(" }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("iv_"); + builder.append(this._grammarAccessExtensions.ruleName(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append('='); + builder.append(this._grammarAccessExtensions.ruleName(it), " "); + builder.append(AntlrGrammarGenUtil.getDefaultArgumentList(it), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("{ $current=$iv_"); + builder.append(this._grammarAccessExtensions.ruleName(it), " "); + builder.append(".current"); + if (GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it))) { + builder.append(".getText()"); } - _builder.append("; }"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("EOF;"); - _builder.newLine(); - CharSequence _compileEntryFinally = this.compileEntryFinally(it, options); - _builder.append(_compileEntryFinally); - _builder.newLineIfNotEmpty(); - return _builder.toString(); + builder.append("; }"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("EOF;"); + builder.newLine(); + builder.append(this.compileEntryFinally(it, options)); + builder.newLineIfNotEmpty(); + return builder.toString(); } protected String compileEntryReturns(final ParserRule it, final AntlrOptions options) { - boolean _isDatatypeRule = GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it)); - if (_isDatatypeRule) { + if (GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it))) { return "[String current=null]"; } else { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("["); - String _currentType = this.getCurrentType(); - _builder.append(_currentType); - _builder.append(" current=null]"); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append('['); + builder.append(this.getCurrentType()); + builder.append(" current=null]"); + return builder.toString(); } } @Override protected String compileInit(final AbstractRule it, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - { - if (it instanceof ParserRule) { - boolean _isPassCurrentIntoFragment = this.isPassCurrentIntoFragment(); - boolean _not = (!_isPassCurrentIntoFragment); - String _parameterList = AntlrGrammarGenUtil.getParameterList((ParserRule) it, Boolean.valueOf(_not), this.getCurrentType()); - _builder.append(_parameterList); - } + final StringConcatenation builder = new StringConcatenation(); + if (it instanceof ParserRule) { + builder.append(AntlrGrammarGenUtil.getParameterList((ParserRule) it, Boolean.valueOf(!this.isPassCurrentIntoFragment()), this.getCurrentType())); } - _builder.append(" returns "); - CharSequence _compileReturns = this.compileReturns(it, options); - _builder.append(_compileReturns); - _builder.newLineIfNotEmpty(); - { - boolean _hasNoBacktrackAnnotation = this.annotations.hasNoBacktrackAnnotation(it); - if (_hasNoBacktrackAnnotation) { - _builder.append("// Enclosing rule was annotated with @NoBacktrack"); - _builder.newLine(); - _builder.append("options { backtrack=false; }"); - _builder.newLine(); - } + builder.append(" returns "); + builder.append(this.compileReturns(it, options)); + builder.newLineIfNotEmpty(); + if (this.annotations.hasNoBacktrackAnnotation(it)) { + builder.append("// Enclosing rule was annotated with @NoBacktrack"); + builder.newLine(); + builder.append("options { backtrack=false; }"); + builder.newLine(); } - _builder.append("@init {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("enterRule();"); - _builder.newLine(); - _builder.append(" "); - CharSequence _compileInitHiddenTokens = this.compileInitHiddenTokens(it, options); - _builder.append(_compileInitHiddenTokens, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - CharSequence _compileInitUnorderedGroups = this.compileInitUnorderedGroups(it, options); - _builder.append(_compileInitUnorderedGroups, " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - _builder.append("@after {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("leaveRule();"); - _builder.newLine(); - _builder.append("}"); - return _builder.toString(); + builder.append("@init {"); + builder.newLine(); + builder.append(" "); + builder.append("enterRule();"); + builder.newLine(); + builder.append(" "); + builder.append(this.compileInitHiddenTokens(it, options), " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this.compileInitUnorderedGroups(it, options), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + builder.append("@after {"); + builder.newLine(); + builder.append(" "); + builder.append("leaveRule();"); + builder.newLine(); + builder.append('}'); + return builder.toString(); } protected CharSequence compileReturns(final AbstractRule it, final AntlrOptions options) { @@ -426,17 +374,17 @@ protected CharSequence compileReturns(final AbstractRule it, final AntlrOptions return "[AntlrDatatypeRuleToken current=new AntlrDatatypeRuleToken()]"; } if (GrammarUtil.isEObjectFragmentRule(AntlrGrammarGenUtil.getOriginalElement((ParserRule) it))) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("["); - _builder.append(this.getCurrentType()); - _builder.append(" current=in_current]"); - return _builder; + final StringConcatenation builder = new StringConcatenation(); + builder.append('['); + builder.append(this.getCurrentType()); + builder.append(" current=in_current]"); + return builder; } - StringConcatenation _builder2 = new StringConcatenation(); - _builder2.append("["); - _builder2.append(this.getCurrentType()); - _builder2.append(" current=null]"); - return _builder2; + final StringConcatenation builder1 = new StringConcatenation(); + builder1.append('['); + builder1.append(this.getCurrentType()); + builder1.append(" current=null]"); + return builder1; } throw new IllegalStateException("Unexpected rule: " + it); } @@ -444,23 +392,21 @@ protected CharSequence compileReturns(final AbstractRule it, final AntlrOptions @Override protected String _dataTypeEbnf2(final Keyword it, final boolean supportActions) { if (supportActions) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("kw="); - String __dataTypeEbnf2 = super._dataTypeEbnf2(it, supportActions); - _builder.append(__dataTypeEbnf2); - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("$current.merge(kw);"); - _builder.newLine(); - _builder.append(" "); - CharSequence _newLeafNode = this.newLeafNode(it, "kw"); - _builder.append(_newLeafNode, " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append("kw="); + builder.append(super._dataTypeEbnf2(it, supportActions)); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("$current.merge(kw);"); + builder.newLine(); + builder.append(" "); + builder.append(this.newLeafNode(it, "kw"), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } else { return super._dataTypeEbnf2(it, supportActions); } @@ -469,45 +415,37 @@ protected String _dataTypeEbnf2(final Keyword it, final boolean supportActions) @Override protected String _ebnf2(final Action it, final AntlrOptions options, final boolean supportActions) { if (supportActions) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _isBacktrack = options.isBacktrack(); - if (_isBacktrack) { - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("/* */"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - } + final StringConcatenation builder = new StringConcatenation(); + if (options.isBacktrack()) { + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("/* */"); + builder.newLine(); + builder.append('}'); + builder.newLine(); } - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("$current = forceCreateModelElement"); - { - String _feature = it.getFeature(); - if (_feature != null) { - _builder.append("And"); - String _firstUpper = StringExtensions.toFirstUpper(this._grammarAccessExtensions.setOrAdd(it)); - _builder.append(_firstUpper, " "); - } + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("$current = forceCreateModelElement"); + if (it.getFeature() != null) { + builder.append("And"); + builder.append(StringExtensions.toFirstUpper(this._grammarAccessExtensions.setOrAdd(it)), " "); } - _builder.append("("); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - _builder.append(","); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("$current);"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + builder.append('('); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("grammarAccess."); + builder.append(this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append(','); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("$current);"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } else { return super._ebnf2(it, options, supportActions); } @@ -518,36 +456,31 @@ protected String _ebnf2(final Keyword it, final AntlrOptions options, final bool if (!supportActions) { return super._ebnf2(it, options, supportActions); } else if (GrammarUtil.isAssigned(it)) { - StringConcatenation _builder = new StringConcatenation(); - String __ebnf2 = super._ebnf2(it, options, supportActions); - _builder.append(__ebnf2); - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - CharSequence _newLeafNode = this.newLeafNode(it, this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(it), it)); - _builder.append(_newLeafNode, " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append(super._ebnf2(it, options, supportActions)); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(it), it)), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } else { - StringConcatenation _builder_1 = new StringConcatenation(); - String _localVar = this._grammarAccessExtensions.localVar(it); - _builder_1.append(_localVar); - _builder_1.append("="); - String __ebnf2_1 = super._ebnf2(it, options, supportActions); - _builder_1.append(__ebnf2_1); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("{"); - _builder_1.newLine(); - _builder_1.append(" "); - CharSequence _newLeafNode_1 = this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)); - _builder_1.append(_newLeafNode_1, " "); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("}"); - _builder_1.newLine(); - return _builder_1.toString(); + final StringConcatenation builder1 = new StringConcatenation(); + builder1.append(this._grammarAccessExtensions.localVar(it)); + builder1.append('='); + builder1.append(super._ebnf2(it, options, supportActions)); + builder1.newLineIfNotEmpty(); + builder1.append('{'); + builder1.newLine(); + builder1.append(" "); + builder1.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)), " "); + builder1.newLineIfNotEmpty(); + builder1.append('}'); + builder1.newLine(); + return builder1.toString(); } } @@ -556,28 +489,24 @@ protected String _ebnf2(final EnumLiteralDeclaration it, final AntlrOptions opti if (!supportActions) { return super._ebnf2(it, options, supportActions); } else { - StringConcatenation _builder = new StringConcatenation(); - String _localVar = this._grammarAccessExtensions.localVar(it); - _builder.append(_localVar); - _builder.append("="); - String __ebnf2 = super._ebnf2(it, options, supportActions); - _builder.append(__ebnf2); - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("$current = grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess, " "); - _builder.append(".getEnumLiteral().getInstance();"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - CharSequence _newLeafNode = this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)); - _builder.append(_newLeafNode, " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append(this._grammarAccessExtensions.localVar(it)); + builder.append('='); + builder.append(super._ebnf2(it, options, supportActions)); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("$current = grammarAccess."); + builder.append(this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)), " "); + builder.append(".getEnumLiteral().getInstance();"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } } @@ -585,45 +514,39 @@ protected String _ebnf2(final EnumLiteralDeclaration it, final AntlrOptions opti protected String crossrefEbnf(final AbstractRule it, final RuleCall call, final CrossReference ref, final boolean supportActions) { if (supportActions) { if (it instanceof EnumRule || it instanceof ParserRule) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - CharSequence _newCompositeNode = this.newCompositeNode(ref); - _builder.append(_newCompositeNode, " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - String _ruleName = this._grammarAccessExtensions.ruleName(it); - _builder.append(_ruleName); - String _argumentList = AntlrGrammarGenUtil.getArgumentList(call, this.isPassCurrentIntoFragment(), (!supportActions)); - _builder.append(_argumentList); - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("afterParserOrEnumRuleCall();"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + final StringConcatenation builder = new StringConcatenation(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append(this.newCompositeNode(ref), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + builder.append(this._grammarAccessExtensions.ruleName(it)); + builder.append(AntlrGrammarGenUtil.getArgumentList(call, this.isPassCurrentIntoFragment(), (!supportActions))); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("afterParserOrEnumRuleCall();"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } else if (it instanceof TerminalRule) { - StringConcatenation _builder_1 = new StringConcatenation(); - String _localVar = this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(ref)); - _builder_1.append(_localVar); - _builder_1.append("="); - String _ruleName_1 = this._grammarAccessExtensions.ruleName(it); - _builder_1.append(_ruleName_1); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("{"); - _builder_1.newLine(); - _builder_1.append(" "); - CharSequence _newLeafNode = this.newLeafNode(ref, this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(ref))); - _builder_1.append(_newLeafNode, " "); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("}"); - _builder_1.newLine(); - return _builder_1.toString(); + final StringConcatenation builder1 = new StringConcatenation(); + builder1.append(this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(ref))); + builder1.append('='); + builder1.append(this._grammarAccessExtensions.ruleName(it)); + builder1.newLineIfNotEmpty(); + builder1.append('{'); + builder1.newLine(); + builder1.append(" "); + builder1.append(this.newLeafNode(ref, this._grammarAccessExtensions.localVar(GrammarUtil.containingAssignment(ref))), " "); + builder1.newLineIfNotEmpty(); + builder1.append('}'); + builder1.newLine(); + return builder1.toString(); } else { throw new IllegalStateException("crossrefEbnf is not supported for " + it); } @@ -635,50 +558,40 @@ protected String crossrefEbnf(final AbstractRule it, final RuleCall call, final @Override protected String _assignmentEbnf(final AbstractElement it, final Assignment assignment, final AntlrOptions options, final boolean supportActions) { if (supportActions) { - StringConcatenation _builder = new StringConcatenation(); - String _localVar = this._grammarAccessExtensions.localVar(assignment, it); - _builder.append(_localVar); - _builder.append("="); - String __assignmentEbnf = super._assignmentEbnf(it, assignment, options, supportActions); - _builder.append(__assignmentEbnf); - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if ($current==null) {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("$current = "); - CharSequence _createModelElement = this.createModelElement(assignment); - _builder.append(_createModelElement, " "); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - String _setOrAdd = this._grammarAccessExtensions.setOrAdd(assignment); - _builder.append(_setOrAdd, " "); - _builder.append("WithLastConsumed($current, \""); - String _feature = assignment.getFeature(); - _builder.append(_feature, " "); - _builder.append("\", "); - String _localVar_1 = this._grammarAccessExtensions.localVar(assignment, it); - _builder.append(_localVar_1, " "); - { - boolean _isBooleanAssignment = GrammarUtil.isBooleanAssignment(assignment); - if (_isBooleanAssignment) { - _builder.append(" != null"); - } + final StringConcatenation builder = new StringConcatenation(); + builder.append(this._grammarAccessExtensions.localVar(assignment, it)); + builder.append('='); + builder.append(super._assignmentEbnf(it, assignment, options, supportActions)); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("if ($current==null) {"); + builder.newLine(); + builder.append(" "); + builder.append("$current = "); + builder.append(this.createModelElement(assignment), " "); + builder.append(';'); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(" "); + builder.append(this._grammarAccessExtensions.setOrAdd(assignment), " "); + builder.append("WithLastConsumed($current, \""); + builder.append(assignment.getFeature(), " "); + builder.append("\", "); + builder.append(this._grammarAccessExtensions.localVar(assignment, it), " "); + if (GrammarUtil.isBooleanAssignment(assignment)) { + builder.append(" != null"); } - _builder.append(", "); - CharSequence _stringLiteral = this._grammarAccessExtensions.toStringLiteral(assignment.getTerminal()); - _builder.append(_stringLiteral, " "); - _builder.append(");"); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + builder.append(", "); + builder.append(this._grammarAccessExtensions.toStringLiteral(assignment.getTerminal()), " "); + builder.append(");"); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } else { return super._assignmentEbnf(it, assignment, options, supportActions); } @@ -690,41 +603,37 @@ protected boolean isPassCurrentIntoFragment() { } protected CharSequence createModelElement(final EObject grammarElement) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("createModelElement(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingParserRule(grammarElement))); - _builder.append(_grammarElementAccess); - _builder.append(")"); - return _builder; + final StringConcatenation builder = new StringConcatenation(); + builder.append("createModelElement(grammarAccess."); + builder.append(this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingParserRule(grammarElement)))); + builder.append(')'); + return builder; } protected CharSequence createModelElementForParent(final EObject grammarElement) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("createModelElementForParent(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingParserRule(grammarElement))); - _builder.append(_grammarElementAccess); - _builder.append(")"); - return _builder; + final StringConcatenation builder = new StringConcatenation(); + builder.append("createModelElementForParent(grammarAccess."); + builder.append(this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(GrammarUtil.containingParserRule(grammarElement)))); + builder.append(')'); + return builder; } protected CharSequence newCompositeNode(final EObject it) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("newCompositeNode(grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess); - _builder.append(");"); - return _builder; + final StringConcatenation builder = new StringConcatenation(); + builder.append("newCompositeNode(grammarAccess."); + builder.append(this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.append(");"); + return builder; } protected CharSequence newLeafNode(final EObject it, final String token) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("newLeafNode("); - _builder.append(token); - _builder.append(", grammarAccess."); - String _grammarElementAccess = this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it)); - _builder.append(_grammarElementAccess); - _builder.append(");"); - return _builder; + final StringConcatenation builder = new StringConcatenation(); + builder.append("newLeafNode("); + builder.append(token); + builder.append(", grammarAccess."); + builder.append(this._grammarAccessExtensions.grammarElementAccess(AntlrGrammarGenUtil.getOriginalElement(it))); + builder.append(");"); + return builder; } /** @@ -733,70 +642,67 @@ protected CharSequence newLeafNode(final EObject it, final String token) { @Override protected String _dataTypeEbnf2(final RuleCall it, final boolean supportActions) { if (supportActions) { - AbstractRule _rule = it.getRule(); - if ((_rule instanceof EnumRule && GrammarUtil.isAssigned(it)) || (_rule instanceof ParserRule && GrammarUtil.isAssigned(it))) { + final AbstractRule rule = it.getRule(); + if ((rule instanceof EnumRule && GrammarUtil.isAssigned(it)) || (rule instanceof ParserRule && GrammarUtil.isAssigned(it))) { return super._dataTypeEbnf2(it, supportActions); - } else if (_rule instanceof EnumRule || _rule instanceof ParserRule) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _isGatedPredicateRequired = this.annotations.isGatedPredicateRequired(it); - if (_isGatedPredicateRequired) { - _builder.append(this.annotations.generateGatedPredicate(it)); - } + } else if (rule instanceof EnumRule || rule instanceof ParserRule) { + final StringConcatenation builder = new StringConcatenation(); + if (this.annotations.isGatedPredicateRequired(it)) { + builder.append(this.annotations.generateGatedPredicate(it)); } - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append(this.newCompositeNode(it), " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - _builder.append(this._grammarAccessExtensions.localVar(it)); - _builder.append("="); - _builder.append(super._dataTypeEbnf2(it, supportActions)); - _builder.append(AntlrGrammarGenUtil.getArgumentList(it, this.isPassCurrentIntoFragment(), (!supportActions))); - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("$current.merge("); - _builder.append(this._grammarAccessExtensions.localVar(it), " "); - _builder.append(");"); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("afterParserOrEnumRuleCall();"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); - } else if (_rule instanceof TerminalRule) { - StringConcatenation _builder_1 = new StringConcatenation(); - _builder_1.append(this._grammarAccessExtensions.localVar(it)); - _builder_1.append("="); - _builder_1.append(super._dataTypeEbnf2(it, supportActions)); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("{"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("$current.merge("); - _builder_1.append(this._grammarAccessExtensions.localVar(it), " "); - _builder_1.append(");"); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append("{"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)), " "); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("}"); - _builder_1.newLine(); - return _builder_1.toString(); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append(this.newCompositeNode(it), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + builder.append(this._grammarAccessExtensions.localVar(it)); + builder.append('='); + builder.append(super._dataTypeEbnf2(it, supportActions)); + builder.append(AntlrGrammarGenUtil.getArgumentList(it, this.isPassCurrentIntoFragment(), (!supportActions))); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("$current.merge("); + builder.append(this._grammarAccessExtensions.localVar(it), " "); + builder.append(");"); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("afterParserOrEnumRuleCall();"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder.toString(); + } else if (rule instanceof TerminalRule) { + final StringConcatenation builder1 = new StringConcatenation(); + builder1.append(this._grammarAccessExtensions.localVar(it)); + builder1.append('='); + builder1.append(super._dataTypeEbnf2(it, supportActions)); + builder1.newLineIfNotEmpty(); + builder1.append('{'); + builder1.newLine(); + builder1.append(" "); + builder1.append("$current.merge("); + builder1.append(this._grammarAccessExtensions.localVar(it), " "); + builder1.append(");"); + builder1.newLineIfNotEmpty(); + builder1.append('}'); + builder1.newLine(); + builder1.append('{'); + builder1.newLine(); + builder1.append(" "); + builder1.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(it)), " "); + builder1.newLineIfNotEmpty(); + builder1.append('}'); + builder1.newLine(); + return builder1.toString(); } else { return super._dataTypeEbnf2(it, supportActions); } @@ -810,118 +716,87 @@ protected String _dataTypeEbnf2(final RuleCall it, final boolean supportActions) */ @Override protected String compileEBNF(final AbstractRule it, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("// Rule "); - String _name = AntlrGrammarGenUtil.getOriginalElement(it).getName(); - _builder.append(_name); - _builder.newLineIfNotEmpty(); - String _ruleName = this._grammarAccessExtensions.ruleName(it); - _builder.append(_ruleName); - String _compileInit = this.compileInit(it, options); - _builder.append(_compileInit); - _builder.append(":"); - _builder.newLineIfNotEmpty(); - { - if ((it instanceof ParserRule) && GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it))) { - _builder.append(" "); - { - boolean _hasValidatingPredicate = this.annotations.hasValidatingPredicate(it); - if (_hasValidatingPredicate) { - _builder.append(this.annotations.generateValidatingPredicate(it), " "); - } - } - _builder.newLineIfNotEmpty(); - _builder.append(" "); - String _dataTypeEbnf = this.dataTypeEbnf(it.getAlternatives(), true); - _builder.append(_dataTypeEbnf, " "); - _builder.newLineIfNotEmpty(); - } else { - _builder.append(" "); - String _ebnf = this.ebnf(it.getAlternatives(), options, true); - _builder.append(_ebnf, " "); - _builder.newLineIfNotEmpty(); + final StringConcatenation builder = new StringConcatenation(); + builder.append("// Rule "); + builder.append(AntlrGrammarGenUtil.getOriginalElement(it).getName()); + builder.newLineIfNotEmpty(); + builder.append(this._grammarAccessExtensions.ruleName(it)); + builder.append(this.compileInit(it, options)); + builder.append(':'); + builder.newLineIfNotEmpty(); + if ((it instanceof ParserRule) && GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it))) { + builder.append(" "); + if (this.annotations.hasValidatingPredicate(it)) { + builder.append(this.annotations.generateValidatingPredicate(it), " "); } + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this.dataTypeEbnf(it.getAlternatives(), true), " "); + builder.newLineIfNotEmpty(); + } else { + builder.append(" "); + builder.append(this.ebnf(it.getAlternatives(), options, true), " "); + builder.newLineIfNotEmpty(); } - _builder.append(";"); - _builder.newLine(); - String _compileFinally = this.compileFinally(it, options); - _builder.append(_compileFinally); - _builder.newLineIfNotEmpty(); - return _builder.toString(); + builder.append(';'); + builder.newLine(); + builder.append(this.compileFinally(it, options)); + builder.newLineIfNotEmpty(); + return builder.toString(); } @Override protected String dataTypeEbnf(final AbstractElement it, final boolean supportActions) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _mustBeParenthesized = this.mustBeParenthesized(it); - if (_mustBeParenthesized) { - _builder.append("("); - _builder.newLineIfNotEmpty(); - { - boolean _hasNoBacktrackAnnotation = this.annotations.hasNoBacktrackAnnotation(it); - if (_hasNoBacktrackAnnotation) { - _builder.append(" "); - _builder.append("// Enclosing rule was annotated with @NoBacktrack"); - _builder.newLine(); - _builder.append(" "); - _builder.append("options { backtrack=false; }:"); - _builder.newLine(); - } - } - _builder.append(" "); - String _dataTypeEbnfPredicate = this.dataTypeEbnfPredicate(it); - _builder.append(_dataTypeEbnfPredicate, " "); - String _dataTypeEbnf2 = this.dataTypeEbnf2(it, supportActions); - _builder.append(_dataTypeEbnf2, " "); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - } else { - String _dataTypeEbnf2_1 = this.dataTypeEbnf2(it, supportActions); - _builder.append(_dataTypeEbnf2_1); + final StringConcatenation builder = new StringConcatenation(); + if (this.mustBeParenthesized(it)) { + builder.append('('); + builder.newLineIfNotEmpty(); + if (this.annotations.hasNoBacktrackAnnotation(it)) { + builder.append(" "); + builder.append("// Enclosing rule was annotated with @NoBacktrack"); + builder.newLine(); + builder.append(" "); + builder.append("options { backtrack=false; }:"); + builder.newLine(); } + builder.append(" "); + builder.append(this.dataTypeEbnfPredicate(it), " "); + builder.append(this.dataTypeEbnf2(it, supportActions), " "); + builder.newLineIfNotEmpty(); + builder.append(')'); + } else { + builder.append(this.dataTypeEbnf2(it, supportActions)); } - String _cardinality = it.getCardinality(); - _builder.append(_cardinality); - _builder.newLineIfNotEmpty(); - return _builder.toString(); + builder.append(it.getCardinality()); + builder.newLineIfNotEmpty(); + return builder.toString(); } @Override protected String ebnf(final AbstractElement it, final AntlrOptions options, final boolean supportActions) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _mustBeParenthesized = this.mustBeParenthesized(it); - if (_mustBeParenthesized) { - _builder.append("("); - _builder.newLineIfNotEmpty(); - { - boolean _hasNoBacktrackAnnotation = this.annotations.hasNoBacktrackAnnotation(it); - if (_hasNoBacktrackAnnotation) { - _builder.append(" "); - _builder.append("// Enclosing rule was annotated with @NoBacktrack"); - _builder.newLine(); - _builder.append(" "); - _builder.append("options { backtrack=false; }:"); - _builder.newLine(); - } - } - _builder.append(" "); - String _ebnfPredicate = this.ebnfPredicate(it, options); - _builder.append(_ebnfPredicate, " "); - String _ebnf2 = this.ebnf2(it, options, supportActions); - _builder.append(_ebnf2, " "); - _builder.newLineIfNotEmpty(); - _builder.append(")"); - } else { - String _ebnf2_1 = this.ebnf2(it, options, supportActions); - _builder.append(_ebnf2_1); + final StringConcatenation builder = new StringConcatenation(); + if (this.mustBeParenthesized(it)) { + builder.append('('); + builder.newLineIfNotEmpty(); + if (this.annotations.hasNoBacktrackAnnotation(it)) { + builder.append(" "); + builder.append("// Enclosing rule was annotated with @NoBacktrack"); + builder.newLine(); + builder.append(" "); + builder.append("options { backtrack=false; }:"); + builder.newLine(); } + builder.append(" "); + builder.append(this.ebnfPredicate(it, options), " "); + builder.append(this.ebnf2(it, options, supportActions), " "); + builder.newLineIfNotEmpty(); + builder.append(')'); + } else { + builder.append(this.ebnf2(it, options, supportActions)); } - String _cardinality = it.getCardinality(); - _builder.append(_cardinality); - _builder.newLineIfNotEmpty(); - return _builder.toString(); + builder.append(it.getCardinality()); + builder.newLineIfNotEmpty(); + return builder.toString(); } /** @@ -930,127 +805,118 @@ protected String ebnf(final AbstractElement it, final AntlrOptions options, fina @Override protected String _assignmentEbnf(final RuleCall it, final Assignment assignment, final AntlrOptions options, final boolean supportActions) { if (supportActions) { - AbstractRule _rule = it.getRule(); - if (_rule instanceof EnumRule || _rule instanceof ParserRule) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _isGatedPredicateRequired = this.annotations.isGatedPredicateRequired(it); - if (_isGatedPredicateRequired) { - _builder.append(this.annotations.generateGatedPredicate(it)); - } + final AbstractRule rule = it.getRule(); + if (rule instanceof EnumRule || rule instanceof ParserRule) { + final StringConcatenation builder = new StringConcatenation(); + if (this.annotations.isGatedPredicateRequired(it)) { + builder.append(this.annotations.generateGatedPredicate(it)); } - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append(this.newCompositeNode(it), " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - _builder.append(this._grammarAccessExtensions.localVar(assignment, it)); - _builder.append("="); - _builder.append(super._assignmentEbnf(it, assignment, options, supportActions)); - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if ($current==null) {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("$current = "); - _builder.append(this.createModelElementForParent(assignment), " "); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - _builder.append(this._grammarAccessExtensions.setOrAdd(assignment), " "); - _builder.append("("); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("$current,"); - _builder.newLine(); - _builder.append(" "); - _builder.append("\""); - _builder.append(assignment.getFeature(), " "); - _builder.append("\","); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(this._grammarAccessExtensions.localVar(assignment, it), " "); - { - boolean _isBooleanAssignment = GrammarUtil.isBooleanAssignment(assignment); - if (_isBooleanAssignment) { - _builder.append(" != null"); - } + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append(this.newCompositeNode(it), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + builder.append(this._grammarAccessExtensions.localVar(assignment, it)); + builder.append('='); + builder.append(super._assignmentEbnf(it, assignment, options, supportActions)); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("if ($current==null) {"); + builder.newLine(); + builder.append(" "); + builder.append("$current = "); + builder.append(this.createModelElementForParent(assignment), " "); + builder.append(';'); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append(" "); + builder.append(this._grammarAccessExtensions.setOrAdd(assignment), " "); + builder.append('('); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("$current,"); + builder.newLine(); + builder.append(" "); + builder.append("\""); + builder.append(assignment.getFeature(), " "); + builder.append("\","); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this._grammarAccessExtensions.localVar(assignment, it), " "); + if (GrammarUtil.isBooleanAssignment(assignment)) { + builder.append(" != null"); } - _builder.append(","); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(this._grammarAccessExtensions.toStringLiteral(it), " "); - _builder.append(");"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("afterParserOrEnumRuleCall();"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); - } else if (_rule instanceof TerminalRule) { - StringConcatenation _builder_1 = new StringConcatenation(); - _builder_1.append(this._grammarAccessExtensions.localVar(assignment, it)); - _builder_1.append("="); - _builder_1.append(super._assignmentEbnf(it, assignment, options, supportActions)); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("{"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(assignment, it)), " "); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append("{"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("if ($current==null) {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("$current = "); - _builder_1.append(this.createModelElement(assignment), " "); - _builder_1.append(";"); - _builder_1.newLineIfNotEmpty(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append(this._grammarAccessExtensions.setOrAdd(assignment), " "); - _builder_1.append("WithLastConsumed("); - _builder_1.newLineIfNotEmpty(); - _builder_1.append(" "); - _builder_1.append("$current,"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("\""); - _builder_1.append(assignment.getFeature(), " "); - _builder_1.append("\","); - _builder_1.newLineIfNotEmpty(); - _builder_1.append(" "); - _builder_1.append(this._grammarAccessExtensions.localVar(assignment, it), " "); - { - boolean _isBooleanAssignment2 = GrammarUtil.isBooleanAssignment(assignment); - if (_isBooleanAssignment2) { - _builder_1.append(" != null"); - } + builder.append(','); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(this._grammarAccessExtensions.toStringLiteral(it), " "); + builder.append(");"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("afterParserOrEnumRuleCall();"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder.toString(); + } else if (rule instanceof TerminalRule) { + final StringConcatenation builder1 = new StringConcatenation(); + builder1.append(this._grammarAccessExtensions.localVar(assignment, it)); + builder1.append('='); + builder1.append(super._assignmentEbnf(it, assignment, options, supportActions)); + builder1.newLineIfNotEmpty(); + builder1.append('{'); + builder1.newLine(); + builder1.append(" "); + builder1.append(this.newLeafNode(it, this._grammarAccessExtensions.localVar(assignment, it)), " "); + builder1.newLineIfNotEmpty(); + builder1.append('}'); + builder1.newLine(); + builder1.append('{'); + builder1.newLine(); + builder1.append(" "); + builder1.append("if ($current==null) {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("$current = "); + builder1.append(this.createModelElement(assignment), " "); + builder1.append(';'); + builder1.newLineIfNotEmpty(); + builder1.append(" "); + builder1.append('}'); + builder1.newLine(); + builder1.append(" "); + builder1.append(this._grammarAccessExtensions.setOrAdd(assignment), " "); + builder1.append("WithLastConsumed("); + builder1.newLineIfNotEmpty(); + builder1.append(" "); + builder1.append("$current,"); + builder1.newLine(); + builder1.append(" "); + builder1.append("\""); + builder1.append(assignment.getFeature(), " "); + builder1.append("\","); + builder1.newLineIfNotEmpty(); + builder1.append(" "); + builder1.append(this._grammarAccessExtensions.localVar(assignment, it), " "); + if (GrammarUtil.isBooleanAssignment(assignment)) { + builder1.append(" != null"); } - _builder_1.append(","); - _builder_1.newLineIfNotEmpty(); - _builder_1.append(" "); - _builder_1.append(this._grammarAccessExtensions.toStringLiteral(it), " "); - _builder_1.append(");"); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("}"); - _builder_1.newLine(); - return _builder_1.toString(); + builder1.append(','); + builder1.newLineIfNotEmpty(); + builder1.append(" "); + builder1.append(this._grammarAccessExtensions.toStringLiteral(it), " "); + builder1.append(");"); + builder1.newLineIfNotEmpty(); + builder1.append('}'); + builder1.newLine(); + return builder1.toString(); } else { throw new IllegalStateException("assignmentEbnf is not supported for " + it); } @@ -1065,43 +931,37 @@ protected String _assignmentEbnf(final RuleCall it, final Assignment assignment, @Override protected String _assignmentEbnf(final CrossReference it, final Assignment assignment, final AntlrOptions options, final boolean supportActions) { if (supportActions) { - StringConcatenation _builder = new StringConcatenation(); - { - boolean _isGatedPredicateRequired = this.annotations.isGatedPredicateRequired(it); - if (_isGatedPredicateRequired) { - _builder.append(this.annotations.generateGatedPredicate(it)); - } + final StringConcatenation builder = new StringConcatenation(); + if (this.annotations.isGatedPredicateRequired(it)) { + builder.append(this.annotations.generateGatedPredicate(it)); } - _builder.newLineIfNotEmpty(); - { - boolean _isBacktrack = options.isBacktrack(); - if (_isBacktrack) { - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("/* */"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - } + builder.newLineIfNotEmpty(); + if (options.isBacktrack()) { + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("/* */"); + builder.newLine(); + builder.append('}'); + builder.newLine(); } - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if ($current==null) {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("$current = "); - _builder.append(this.createModelElement(assignment), " "); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - _builder.append(super._assignmentEbnf(it, assignment, options, supportActions)); - return _builder.toString(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("if ($current==null) {"); + builder.newLine(); + builder.append(" "); + builder.append("$current = "); + builder.append(this.createModelElement(assignment), " "); + builder.append(';'); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append('}'); + builder.newLine(); + builder.append('}'); + builder.newLine(); + builder.append(super._assignmentEbnf(it, assignment, options, supportActions)); + return builder.toString(); } else { return super._assignmentEbnf(it, assignment, options, supportActions); } @@ -1115,119 +975,109 @@ protected String _ebnf2(final RuleCall it, final AntlrOptions options, final boo if (!supportActions) { return super._ebnf2(it, options, supportActions); } else { - AbstractRule rule = it.getRule(); + final AbstractRule rule = it.getRule(); if ((rule instanceof EnumRule && GrammarUtil.isAssigned(it)) || (rule instanceof ParserRule && GrammarUtil.isAssigned(it))) { return super._ebnf2(it, options, supportActions); } else if (rule instanceof EnumRule || (rule instanceof ParserRule && GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement((ParserRule) rule)))) { - StringConcatenation _builder = new StringConcatenation(); - { - if (this.annotations.isGatedPredicateRequired(it)) { - _builder.append(this.annotations.generateGatedPredicate(it)); - } + final StringConcatenation builder = new StringConcatenation(); + if (this.annotations.isGatedPredicateRequired(it)) { + builder.append(this.annotations.generateGatedPredicate(it)); } - _builder.newLineIfNotEmpty(); - { - if (options.isBacktrack()) { - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("/* */"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - } + builder.newLineIfNotEmpty(); + if (options.isBacktrack()) { + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("/* */"); + builder.newLine(); + builder.append('}'); + builder.newLine(); } - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append(this.newCompositeNode(it), " "); - _builder.newLineIfNotEmpty(); - _builder.append("}"); - _builder.newLine(); - _builder.append(super._ebnf2(it, options, supportActions)); - _builder.newLineIfNotEmpty(); - _builder.append("{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("afterParserOrEnumRuleCall();"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - return _builder.toString(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append(this.newCompositeNode(it), " "); + builder.newLineIfNotEmpty(); + builder.append('}'); + builder.newLine(); + builder.append(super._ebnf2(it, options, supportActions)); + builder.newLineIfNotEmpty(); + builder.append('{'); + builder.newLine(); + builder.append(" "); + builder.append("afterParserOrEnumRuleCall();"); + builder.newLine(); + builder.append('}'); + builder.newLine(); + return builder.toString(); } else if (rule instanceof ParserRule) { - StringConcatenation _builder_1 = new StringConcatenation(); - { - if (this.annotations.isGatedPredicateRequired(it)) { - _builder_1.append(this.annotations.generateGatedPredicate(it)); - } + final StringConcatenation builder1 = new StringConcatenation(); + if (this.annotations.isGatedPredicateRequired(it)) { + builder1.append(this.annotations.generateGatedPredicate(it)); } - _builder_1.newLineIfNotEmpty(); - { - if (options.isBacktrack()) { - _builder_1.append("{"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("/* */"); - _builder_1.newLine(); - _builder_1.append("}"); - _builder_1.newLine(); - } + builder1.newLineIfNotEmpty(); + if (options.isBacktrack()) { + builder1.append('{'); + builder1.newLine(); + builder1.append(" "); + builder1.append("/* */"); + builder1.newLine(); + builder1.append('}'); + builder1.newLine(); } - _builder_1.append("{"); - _builder_1.newLine(); - { - if (GrammarUtil.isEObjectFragmentRuleCall(it)) { - _builder_1.append(" "); - _builder_1.append("if ($current==null) {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("$current = "); - _builder_1.append(this.createModelElement(it), " "); - _builder_1.append(";"); - _builder_1.newLineIfNotEmpty(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - } + builder1.append('{'); + builder1.newLine(); + if (GrammarUtil.isEObjectFragmentRuleCall(it)) { + builder1.append(" "); + builder1.append("if ($current==null) {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("$current = "); + builder1.append(this.createModelElement(it), " "); + builder1.append(';'); + builder1.newLineIfNotEmpty(); + builder1.append(" "); + builder1.append('}'); + builder1.newLine(); } - _builder_1.append(" "); - _builder_1.append(this.newCompositeNode(it), " "); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("}"); - _builder_1.newLine(); - String _localVar = this._grammarAccessExtensions.localVar(it); - _builder_1.append(_localVar); - _builder_1.append("="); - _builder_1.append(super._ebnf2(it, options, supportActions)); - _builder_1.newLineIfNotEmpty(); - _builder_1.append("{"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("$current = $"); - _builder_1.append(_localVar, " "); - _builder_1.append(".current;"); - _builder_1.newLineIfNotEmpty(); - _builder_1.append(" "); - _builder_1.append("afterParserOrEnumRuleCall();"); - _builder_1.newLine(); - _builder_1.append("}"); - _builder_1.newLine(); - return _builder_1.toString(); + builder1.append(" "); + builder1.append(this.newCompositeNode(it), " "); + builder1.newLineIfNotEmpty(); + builder1.append('}'); + builder1.newLine(); + final String localVar = this._grammarAccessExtensions.localVar(it); + builder1.append(localVar); + builder1.append('='); + builder1.append(super._ebnf2(it, options, supportActions)); + builder1.newLineIfNotEmpty(); + builder1.append('{'); + builder1.newLine(); + builder1.append(" "); + builder1.append("$current = $"); + builder1.append(localVar, " "); + builder1.append(".current;"); + builder1.newLineIfNotEmpty(); + builder1.append(" "); + builder1.append("afterParserOrEnumRuleCall();"); + builder1.newLine(); + builder1.append('}'); + builder1.newLine(); + return builder1.toString(); } else if (rule instanceof TerminalRule) { - StringConcatenation _builder_2 = new StringConcatenation(); - String _localVar2 = this._grammarAccessExtensions.localVar(it); - _builder_2.append(_localVar2); - _builder_2.append("="); - _builder_2.append(super._ebnf2(it, options, supportActions)); - _builder_2.newLineIfNotEmpty(); - _builder_2.append("{"); - _builder_2.newLine(); - _builder_2.append(" "); - _builder_2.append(this.newLeafNode(it, _localVar2), " "); - _builder_2.newLineIfNotEmpty(); - _builder_2.append("}"); - _builder_2.newLine(); - return _builder_2.toString(); + final StringConcatenation builder2 = new StringConcatenation(); + final String localVar = this._grammarAccessExtensions.localVar(it); + builder2.append(localVar); + builder2.append('='); + builder2.append(super._ebnf2(it, options, supportActions)); + builder2.newLineIfNotEmpty(); + builder2.append('{'); + builder2.newLine(); + builder2.append(" "); + builder2.append(this.newLeafNode(it, localVar), " "); + builder2.newLineIfNotEmpty(); + builder2.append('}'); + builder2.newLine(); + return builder2.toString(); } else { return super._ebnf2(it, options, supportActions); } @@ -1236,25 +1086,24 @@ protected String _ebnf2(final RuleCall it, final AntlrOptions options, final boo @Override protected String compileLexerImports(final Grammar it, final AntlrOptions options) { - StringConcatenation _builder = new StringConcatenation(); - _builder.newLine(); - _builder.append("// Hack: Use our own Lexer superclass by means of import."); - _builder.newLine(); - _builder.append("// Currently there is no other way to specify the superclass for the lexer."); - _builder.newLine(); - { - if (!this.lexerSuperClassName.isEmpty()) { - _builder.append("import "); - _builder.append(this.lexerSuperClassName); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - } else { - _builder.append("import "); - _builder.append(this.getGrammarNaming().getLexerSuperClass(it)); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - } + final StringConcatenation builder = new StringConcatenation(); + builder.newLine(); + builder.append("// Hack: Use our own Lexer superclass by means of import."); + builder.newLine(); + builder.append("// Currently there is no other way to specify the superclass for the lexer."); + builder.newLine(); + if (!this.lexerSuperClassName.isEmpty()) { + builder.append("import "); + builder.append(this.lexerSuperClassName); + builder.append(';'); + builder.newLineIfNotEmpty(); + } else { + builder.append("import "); + builder.append(this.getGrammarNaming().getLexerSuperClass(it)); + builder.append(';'); + builder.newLineIfNotEmpty(); } - return _builder.toString(); + return builder.toString(); } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.java index 98e13fe4c8..b42e511730 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareXtextAntlrGeneratorFragment2.java @@ -60,6 +60,8 @@ import com.google.inject.name.Names; +// CHECKSTYLE:OFF +@SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.TooManyMethods", "PMD.LocalVariableNamingConventions"}) public class AnnotationAwareXtextAntlrGeneratorFragment2 extends XtextAntlrGeneratorFragment2 { private static final String ADDITIONAL_CA_REQUIRED_BUNDLE = "com.avaloq.tools.ddk.xtext"; @@ -237,37 +239,37 @@ protected void addIdeUiBindingsAndImports() { GuiceModuleAccess.BindingFactory ideBindings = new GuiceModuleAccess.BindingFactory() .addConfiguredBinding("ContentAssistLexer", new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("binder.bind("); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("binder.bind("); TypeReference _lexerSuperClass = naming.getLexerSuperClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_lexerSuperClass); - _builder.append(".class)"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(".annotatedWith("); - _builder.append(Names.class, " "); - _builder.append(".named("); + builder.append(_lexerSuperClass); + builder.append(".class)"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(".annotatedWith("); + builder.append(Names.class, " "); + builder.append(".named("); TypeReference _typeRef = TypeReference.typeRef("org.eclipse.xtext.ide.LexerIdeBindings"); - _builder.append(_typeRef, " "); - _builder.append(".CONTENT_ASSIST))"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(".to("); + builder.append(_typeRef, " "); + builder.append(".CONTENT_ASSIST))"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(".to("); TypeReference _lexerClass = naming.getLexerClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_lexerClass, " "); - _builder.append(".class);"); - _builder.newLineIfNotEmpty(); + builder.append(_lexerClass, " "); + builder.append(".class);"); + builder.newLineIfNotEmpty(); } }) .addTypeToType(TypeReference.typeRef("org.eclipse.xtext.ide.editor.contentassist.antlr.IContentAssistParser"), naming.getParserClass(getGrammar())) .addConfiguredBinding("IProposalConflictHelper", new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("binder.bind(org.eclipse.xtext.ide.editor.contentassist.IProposalConflictHelper.class)"); - _builder.newLine(); - _builder.append(" "); - _builder.append(".to(org.eclipse.xtext.ide.editor.contentassist.antlr.AntlrProposalConflictHelper.class);"); - _builder.newLine(); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("binder.bind(org.eclipse.xtext.ide.editor.contentassist.IProposalConflictHelper.class)"); + builder.newLine(); + builder.append(" "); + builder.append(".to(org.eclipse.xtext.ide.editor.contentassist.antlr.AntlrProposalConflictHelper.class);"); + builder.newLine(); } }); if (this.partialParsing) { @@ -287,164 +289,164 @@ protected void appendTo(StringConcatenationClient.TargetStringConcatenation _bui public JavaFileAccess generateContentAssistParser() { final ContentAssistGrammarNaming naming = this.contentAssistNaming; final GeneratedJavaFileAccess file = this.fileFactory.createGeneratedJavaFile(naming.getParserClass(getGrammar())); - StringConcatenationClient _client = new StringConcatenationClient() { + StringConcatenationClient client = new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("public class "); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("public class "); String _simpleName = naming.getParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()).getSimpleName(); - _builder.append(_simpleName); - _builder.append(" extends "); + builder.append(_simpleName); + builder.append(" extends "); TypeReference _parserSuperClass = naming.getParserSuperClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar(), AnnotationAwareXtextAntlrGeneratorFragment2.this.partialParsing); - _builder.append(_parserSuperClass); - _builder.append(" {"); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); + builder.append(_parserSuperClass); + builder.append(" {"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); StringConcatenationClient _initNameMappings = AnnotationAwareXtextAntlrGeneratorFragment2.this.initNameMappings(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_initNameMappings, " "); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@"); - _builder.append(Inject.class, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("private "); + builder.append(_initNameMappings, " "); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); + builder.append("@"); + builder.append(Inject.class, " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("private "); TypeReference _grammarAccess = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_grammarAccess, " "); - _builder.append(" grammarAccess;"); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@"); - _builder.append(Inject.class, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("private "); + builder.append(_grammarAccess, " "); + builder.append(" grammarAccess;"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); + builder.append("@"); + builder.append(Inject.class, " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("private "); TypeReference _typeRef = TypeReference.typeRef(ISemanticPredicates.class); - _builder.append(_typeRef, " "); - _builder.append(" predicates;"); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* Creates compilation context."); - _builder.newLine(); - _builder.append(" "); - _builder.append("*"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* @param Input"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* Stream"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* @return Compilation context"); - _builder.newLine(); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected "); + builder.append(_typeRef, " "); + builder.append(" predicates;"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append("* Creates compilation context."); + builder.newLine(); + builder.append(" "); + builder.append("*"); + builder.newLine(); + builder.append(" "); + builder.append("* @param Input"); + builder.newLine(); + builder.append(" "); + builder.append("* Stream"); + builder.newLine(); + builder.append(" "); + builder.append("* @return Compilation context"); + builder.newLine(); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.append(" "); + builder.append("protected "); TypeReference _typeRef_1 = TypeReference.typeRef(ParserContext.class); - _builder.append(_typeRef_1, " "); - _builder.append(" createParserContext() {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("return new ParserContext();"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected "); + builder.append(_typeRef_1, " "); + builder.append(" createParserContext() {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("return new ParserContext();"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected "); TypeReference _internalParserClass = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_internalParserClass, " "); - _builder.append(" createParser() {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); + builder.append(_internalParserClass, " "); + builder.append(" createParser() {"); + builder.newLineIfNotEmpty(); + builder.append(" "); TypeReference _internalParserClass_1 = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_internalParserClass_1, " "); - _builder.append(" result = new "); + builder.append(_internalParserClass_1, " "); + builder.append(" result = new "); TypeReference _internalParserClass_2 = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_internalParserClass_2, " "); - _builder.append("(null);"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("result.setGrammarAccess(grammarAccess);"); - _builder.newLine(); - _builder.append(" "); - _builder.append("result.setParserContext(createParserContext());"); - _builder.newLine(); - _builder.append(" "); - _builder.append("result.setPredicates(("); + builder.append(_internalParserClass_2, " "); + builder.append("(null);"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("result.setGrammarAccess(grammarAccess);"); + builder.newLine(); + builder.append(" "); + builder.append("result.setParserContext(createParserContext());"); + builder.newLine(); + builder.append(" "); + builder.append("result.setPredicates(("); TypeReference _typeRef_2 = TypeReference.typeRef(AnnotationAwareXtextAntlrGeneratorFragment2.this.predicatesNaming.getSemanticPredicatesFullName(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar())); - _builder.append(_typeRef_2, " "); - _builder.append(")predicates);"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("return result;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); + builder.append(_typeRef_2, " "); + builder.append(")predicates);"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("return result;"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); { boolean _hasSyntheticTerminalRule = AnnotationAwareXtextAntlrGeneratorFragment2.this.hasSyntheticTerminalRule(); if (_hasSyntheticTerminalRule) { - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected "); - _builder.append(TokenSource.class, " "); - _builder.append(" createLexer("); - _builder.append(CharStream.class, " "); - _builder.append(" stream) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("return new "); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected "); + builder.append(TokenSource.class, " "); + builder.append(" createLexer("); + builder.append(CharStream.class, " "); + builder.append(" stream) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append("return new "); TypeReference _tokenSourceClass = naming.getTokenSourceClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_tokenSourceClass, " "); - _builder.append("(super.createLexer(stream));"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); + builder.append(_tokenSourceClass, " "); + builder.append("(super.createLexer(stream));"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); } } - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected String getRuleName("); - _builder.append(AbstractElement.class, " "); - _builder.append(" element) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("return nameMappings.getRuleName(element);"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected String[] getInitialHiddenTokens() {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("return new String[] { "); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected String getRuleName("); + builder.append(AbstractElement.class, " "); + builder.append(" element) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("return nameMappings.getRuleName(element);"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected String[] getInitialHiddenTokens() {"); + builder.newLine(); + builder.append(" "); + builder.append("return new String[] { "); { List _initialHiddenTokens = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.initialHiddenTokens(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); boolean _hasElements = false; @@ -452,69 +454,69 @@ protected void appendTo(StringConcatenationClient.TargetStringConcatenation _bui if (!_hasElements) { _hasElements = true; } else { - _builder.appendImmediate(", ", " "); + builder.appendImmediate(", ", " "); } - _builder.append("\""); - _builder.append(hidden, " "); - _builder.append("\""); + builder.append("\""); + builder.append(hidden, " "); + builder.append("\""); } } - _builder.append(" };"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public "); + builder.append(" };"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("public "); TypeReference _grammarAccess_1 = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_grammarAccess_1, " "); - _builder.append(" getGrammarAccess() {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("return this.grammarAccess;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public void setGrammarAccess("); + builder.append(_grammarAccess_1, " "); + builder.append(" getGrammarAccess() {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("return this.grammarAccess;"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("public void setGrammarAccess("); TypeReference _grammarAccess_2 = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_grammarAccess_2, " "); - _builder.append(" grammarAccess) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("this.grammarAccess = grammarAccess;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public NameMappings getNameMappings() {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("return nameMappings;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public void setNameMappings(NameMappings nameMappings) {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("this.nameMappings = nameMappings;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); + builder.append(_grammarAccess_2, " "); + builder.append(" grammarAccess) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("this.grammarAccess = grammarAccess;"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("public NameMappings getNameMappings() {"); + builder.newLine(); + builder.append(" "); + builder.append("return nameMappings;"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("public void setNameMappings(NameMappings nameMappings) {"); + builder.newLine(); + builder.append(" "); + builder.append("this.nameMappings = nameMappings;"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.append("}"); + builder.newLine(); } }; - file.setContent(_client); + file.setContent(client); return file; } @@ -556,135 +558,135 @@ public JavaFileAccess generateAbstractSemanticPredicate() { } } file.importType(TypeReference.typeRef(Singleton.class)); - StringConcatenationClient _client = new StringConcatenationClient() { + StringConcatenationClient client = new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* Provides semantic predicates as specified in the grammar. Language may need to override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* this class in order to provide concrete implementations for predicates."); - _builder.newLine(); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.append("@Singleton"); - _builder.newLine(); - _builder.append("public class "); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append("* Provides semantic predicates as specified in the grammar. Language may need to override"); + builder.newLine(); + builder.append(" "); + builder.append("* this class in order to provide concrete implementations for predicates."); + builder.newLine(); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.append("@Singleton"); + builder.newLine(); + builder.append("public class "); String _semanticPredicatesSimpleName = AnnotationAwareXtextAntlrGeneratorFragment2.this.predicatesNaming.getSemanticPredicatesSimpleName(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_semanticPredicatesSimpleName); - _builder.append(" extends AbstractSemanticPredicates {"); - _builder.newLineIfNotEmpty(); + builder.append(_semanticPredicatesSimpleName); + builder.append(" extends AbstractSemanticPredicates {"); + builder.newLineIfNotEmpty(); { List _predicates = AnnotationAwareXtextAntlrGeneratorFragment2.this.annotations.predicates(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); for (final GrammarRuleAnnotations.SemanticPredicate element : _predicates) { - _builder.newLine(); - _builder.append(" "); - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* Predicate for grammar rule "); + builder.newLine(); + builder.append(" "); + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* Predicate for grammar rule "); String _name = element.getName(); - _builder.append(_name, " "); - _builder.append("."); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("*"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* @param input"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* Input from Lexer"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* @return {@code true} if the grammar rule is enabled, {@code false} otherwise"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.append(" "); - _builder.append("public boolean "); + builder.append(_name, " "); + builder.append("."); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append("*"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* @param input"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* Input from Lexer"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* @return {@code true} if the grammar rule is enabled, {@code false} otherwise"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.append(" "); + builder.append("public boolean "); String _name_1 = element.getName(); - _builder.append(_name_1, " "); - _builder.append("(ParserContext parserContext) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); + builder.append(_name_1, " "); + builder.append("(ParserContext parserContext) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); String _rulePredicateCondition = AnnotationAwareXtextAntlrGeneratorFragment2.this.getRulePredicateCondition(element); - _builder.append(_rulePredicateCondition, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); + builder.append(_rulePredicateCondition, " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("}"); + builder.newLine(); } } - _builder.newLine(); + builder.newLine(); { List _predicates_1 = AnnotationAwareXtextAntlrGeneratorFragment2.this.annotations.predicates(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); for (final GrammarRuleAnnotations.SemanticPredicate element_1 : _predicates_1) { - _builder.newLine(); - _builder.append(" "); - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* Message for "); + builder.newLine(); + builder.append(" "); + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* Message for "); String _name_2 = element_1.getName(); - _builder.append(_name_2, " "); - _builder.append(" predicate."); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("*"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* @param input"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* Input from Lexer"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* @return {@code true} if the grammar rule is enabled, {@code false} otherwise"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("public String "); + builder.append(_name_2, " "); + builder.append(" predicate."); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append("*"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* @param input"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* Input from Lexer"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* @return {@code true} if the grammar rule is enabled, {@code false} otherwise"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("public String "); String _message = element_1.getMessage(); - _builder.append(_message, " "); - _builder.append("(Token token) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); + builder.append(_message, " "); + builder.append("(Token token) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); String _rulePredicateMessage = AnnotationAwareXtextAntlrGeneratorFragment2.this.getRulePredicateMessage(element_1); - _builder.append(_rulePredicateMessage, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); + builder.append(_rulePredicateMessage, " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append("}"); + builder.newLine(); } } - _builder.append("}"); - _builder.newLine(); + builder.append("}"); + builder.newLine(); } }; - file.setContent(_client); + file.setContent(client); return file; } @@ -697,23 +699,23 @@ protected void appendTo(StringConcatenationClient.TargetStringConcatenation _bui */ public String getRulePredicateMessage(final SemanticPredicate predicate) { if (predicate.getKeywords() != null) { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("return \"Unexpected: \" + token.getText() + \". Expected: \'"); - String _join = Joiner.on("\', \'").join(predicate.getKeywords()); - _builder.append(_join); - _builder.append("\'\";"); - _builder.newLineIfNotEmpty(); - return _builder.toString(); + StringConcatenation msgBuilder = new StringConcatenation(); + msgBuilder.append("return \"Unexpected: \" + token.getText() + \". Expected: \'"); + String join = Joiner.on("\', \'").join(predicate.getKeywords()); + msgBuilder.append(join); + msgBuilder.append("\'\";"); + msgBuilder.newLineIfNotEmpty(); + return msgBuilder.toString(); } else { - StringConcatenation _builder_1 = new StringConcatenation(); - _builder_1.append("/* Default message. Intended to be overridden. */"); - _builder_1.newLine(); - _builder_1.append("return \"Condition "); - String _name = predicate.getName(); - _builder_1.append(_name); - _builder_1.append(" is not fullfilled \";"); - _builder_1.newLineIfNotEmpty(); - return _builder_1.toString(); + StringConcatenation defaultBuilder = new StringConcatenation(); + defaultBuilder.append("/* Default message. Intended to be overridden. */"); + defaultBuilder.newLine(); + defaultBuilder.append("return \"Condition "); + String name = predicate.getName(); + defaultBuilder.append(name); + defaultBuilder.append(" is not fullfilled \";"); + defaultBuilder.newLineIfNotEmpty(); + return defaultBuilder.toString(); } } @@ -727,20 +729,20 @@ public String getRulePredicateMessage(final SemanticPredicate predicate) { public String getRulePredicateCondition(final SemanticPredicate predicate) { if (predicate.getKeywords() != null) { final String condition = predicate.getKeywords().stream().map(s -> { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("\""); - _builder.append(s); - _builder.append("\".equalsIgnoreCase(text)"); - return _builder.toString(); + StringConcatenation kwBuilder = new StringConcatenation(); + kwBuilder.append("\""); + kwBuilder.append(s); + kwBuilder.append("\".equalsIgnoreCase(text)"); + return kwBuilder.toString(); }).collect(Collectors.joining(" || ")); - StringConcatenation _builder = new StringConcatenation(); - _builder.append("String text = parserContext.getInput().LT(1).getText();"); - _builder.newLine(); - _builder.append("return "); - _builder.append(condition); - _builder.append(";"); - _builder.newLineIfNotEmpty(); - return _builder.toString(); + StringConcatenation condBuilder = new StringConcatenation(); + condBuilder.append("String text = parserContext.getInput().LT(1).getText();"); + condBuilder.newLine(); + condBuilder.append("return "); + condBuilder.append(condition); + condBuilder.append(";"); + condBuilder.newLineIfNotEmpty(); + return condBuilder.toString(); } else { return "return " + predicate.getGrammar() + CLASS_SUFFIX + "." + predicate.getName() + "(parserContext);\n"; } @@ -752,46 +754,46 @@ public JavaFileAccess generateProductionParser() { final GeneratedJavaFileAccess file = this.fileFactory.createGeneratedJavaFile(naming.getParserClass(getGrammar())); file.importType(TypeReference.typeRef(this.predicatesNaming.getSemanticPredicatesFullName(getGrammar()))); file.importType(TypeReference.typeRef(ISemanticPredicates.class)); - StringConcatenationClient _client = new StringConcatenationClient() { + StringConcatenationClient client = new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("public class "); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("public class "); String _simpleName = naming.getParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()).getSimpleName(); - _builder.append(_simpleName); - _builder.append(" extends "); - _builder.append(AbstractContextualAntlrParser.class); - _builder.append(" {"); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@"); - _builder.append(Inject.class, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("private "); + builder.append(_simpleName); + builder.append(" extends "); + builder.append(AbstractContextualAntlrParser.class); + builder.append(" {"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); + builder.append("@"); + builder.append(Inject.class, " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("private "); TypeReference _grammarAccess = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_grammarAccess, " "); - _builder.append(" grammarAccess;"); - _builder.newLineIfNotEmpty(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@"); - _builder.append(Inject.class, " "); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("private ISemanticPredicates predicates;"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected void setInitialHiddenTokens("); - _builder.append(XtextTokenStream.class, " "); - _builder.append(" tokenStream) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("tokenStream.setInitialHiddenTokens("); + builder.append(_grammarAccess, " "); + builder.append(" grammarAccess;"); + builder.newLineIfNotEmpty(); + builder.newLine(); + builder.append(" "); + builder.append("@"); + builder.append(Inject.class, " "); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("private ISemanticPredicates predicates;"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected void setInitialHiddenTokens("); + builder.append(XtextTokenStream.class, " "); + builder.append(" tokenStream) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("tokenStream.setInitialHiddenTokens("); { List _initialHiddenTokens = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.initialHiddenTokens(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); boolean _hasElements = false; @@ -799,144 +801,144 @@ protected void appendTo(StringConcatenationClient.TargetStringConcatenation _bui if (!_hasElements) { _hasElements = true; } else { - _builder.appendImmediate(", ", " "); + builder.appendImmediate(", ", " "); } - _builder.append("\""); - _builder.append(hidden, " "); - _builder.append("\""); + builder.append("\""); + builder.append(hidden, " "); + builder.append("\""); } } - _builder.append(");"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); + builder.append(");"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); { boolean _hasSyntheticTerminalRule = AnnotationAwareXtextAntlrGeneratorFragment2.this.hasSyntheticTerminalRule(); if (_hasSyntheticTerminalRule) { - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected "); - _builder.append(TokenSource.class, " "); - _builder.append(" createLexer("); - _builder.append(CharStream.class, " "); - _builder.append(" stream) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(" "); - _builder.append("return new "); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected "); + builder.append(TokenSource.class, " "); + builder.append(" createLexer("); + builder.append(CharStream.class, " "); + builder.append(" stream) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(" "); + builder.append("return new "); TypeReference _tokenSourceClass = naming.getTokenSourceClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_tokenSourceClass, " "); - _builder.append("(super.createLexer(stream));"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* Indentation aware languages do not support partial parsing since the lexer is inherently stateful."); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("* Override and return {@code true} if your terminal splitting is stateless."); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected boolean isReparseSupported() {"); - _builder.newLine(); - _builder.append(" "); - _builder.append(" "); - _builder.append("return false;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); + builder.append(_tokenSourceClass, " "); + builder.append("(super.createLexer(stream));"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* Indentation aware languages do not support partial parsing since the lexer is inherently stateful."); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("* Override and return {@code true} if your terminal splitting is stateless."); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected boolean isReparseSupported() {"); + builder.newLine(); + builder.append(" "); + builder.append(" "); + builder.append("return false;"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); } } - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected "); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected "); TypeReference _internalParserClass = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_internalParserClass, " "); - _builder.append(" createParser("); - _builder.append(XtextTokenStream.class, " "); - _builder.append(" stream) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("return new "); + builder.append(_internalParserClass, " "); + builder.append(" createParser("); + builder.append(XtextTokenStream.class, " "); + builder.append(" stream) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("return new "); TypeReference _internalParserClass_1 = naming.getInternalParserClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_internalParserClass_1, " "); - _builder.append("(stream, getGrammarAccess(), createParserContext(), ("); + builder.append(_internalParserClass_1, " "); + builder.append("(stream, getGrammarAccess(), createParserContext(), ("); String _semanticPredicatesSimpleName = AnnotationAwareXtextAntlrGeneratorFragment2.this.predicatesNaming.getSemanticPredicatesSimpleName(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_semanticPredicatesSimpleName, " "); - _builder.append(") predicates);"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@Override"); - _builder.newLine(); - _builder.append(" "); - _builder.append("protected String getDefaultRuleName() {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("return \""); + builder.append(_semanticPredicatesSimpleName, " "); + builder.append(") predicates);"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@Override"); + builder.newLine(); + builder.append(" "); + builder.append("protected String getDefaultRuleName() {"); + builder.newLine(); + builder.append(" "); + builder.append("return \""); String _name = AntlrGrammarGenUtil.getOriginalElement(IterableExtensions.head(GrammarUtil.allParserRules(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()))).getName(); - _builder.append(_name, " "); - _builder.append("\";"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public "); + builder.append(_name, " "); + builder.append("\";"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("public "); TypeReference _grammarAccess_1 = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_grammarAccess_1, " "); - _builder.append(" getGrammarAccess() {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("return this.grammarAccess;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("public void setGrammarAccess("); + builder.append(_grammarAccess_1, " "); + builder.append(" getGrammarAccess() {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("return this.grammarAccess;"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("public void setGrammarAccess("); TypeReference _grammarAccess_2 = AnnotationAwareXtextAntlrGeneratorFragment2.this.grammarUtil.getGrammarAccess(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_grammarAccess_2, " "); - _builder.append(" grammarAccess) {"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append("this.grammarAccess = grammarAccess;"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); + builder.append(_grammarAccess_2, " "); + builder.append(" grammarAccess) {"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append("this.grammarAccess = grammarAccess;"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.append("}"); + builder.newLine(); } }; - file.setContent(_client); + file.setContent(client); return file; } @@ -962,25 +964,25 @@ protected void addUiBindingsAndImports() { TypeReference.typeRef("org.eclipse.xtext.ui.editor.contentassist.antlr.AntlrProposalConflictHelper")) .addConfiguredBinding("ContentAssistLexer", new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("binder.bind("); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("binder.bind("); TypeReference _lexerSuperClass = naming.getLexerSuperClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_lexerSuperClass); - _builder.append(".class)"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(".annotatedWith("); - _builder.append(Names.class, " "); - _builder.append(".named("); + builder.append(_lexerSuperClass); + builder.append(".class)"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(".annotatedWith("); + builder.append(Names.class, " "); + builder.append(".named("); TypeReference _typeRef = TypeReference.typeRef("org.eclipse.xtext.ide.LexerIdeBindings"); - _builder.append(_typeRef, " "); - _builder.append(".CONTENT_ASSIST))"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(".to("); - _builder.append(caLexerClass, " "); - _builder.append(".class);"); - _builder.newLineIfNotEmpty(); + builder.append(_typeRef, " "); + builder.append(".CONTENT_ASSIST))"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(".to("); + builder.append(caLexerClass, " "); + builder.append(".class);"); + builder.newLineIfNotEmpty(); } }) // registration of the 'ContentAssistLexer' is put in front of the 'HighlightingLexer' @@ -988,47 +990,47 @@ protected void appendTo(StringConcatenationClient.TargetStringConcatenation _bui // several times and the lexer classes' simple names are usually identical .addConfiguredBinding("HighlightingLexer", new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("binder.bind("); - _builder.append(Lexer.class); - _builder.append(".class)"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(".annotatedWith("); - _builder.append(Names.class, " "); - _builder.append(".named("); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("binder.bind("); + builder.append(Lexer.class); + builder.append(".class)"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(".annotatedWith("); + builder.append(Names.class, " "); + builder.append(".named("); TypeReference _typeRef = TypeReference.typeRef("org.eclipse.xtext.ide.LexerIdeBindings"); - _builder.append(_typeRef, " "); - _builder.append(".HIGHLIGHTING))"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(".to("); + builder.append(_typeRef, " "); + builder.append(".HIGHLIGHTING))"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(".to("); TypeReference _lexerClass = AnnotationAwareXtextAntlrGeneratorFragment2.this.productionNaming.getLexerClass(AnnotationAwareXtextAntlrGeneratorFragment2.this.getGrammar()); - _builder.append(_lexerClass, " "); - _builder.append(".class);"); - _builder.newLineIfNotEmpty(); + builder.append(_lexerClass, " "); + builder.append(".class);"); + builder.newLineIfNotEmpty(); } }) .addConfiguredBinding("HighlightingTokenDefProvider", new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("binder.bind("); - _builder.append(ITokenDefProvider.class); - _builder.append(".class)"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(".annotatedWith("); - _builder.append(Names.class, " "); - _builder.append(".named("); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("binder.bind("); + builder.append(ITokenDefProvider.class); + builder.append(".class)"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(".annotatedWith("); + builder.append(Names.class, " "); + builder.append(".named("); TypeReference _typeRef = TypeReference.typeRef("org.eclipse.xtext.ide.LexerIdeBindings"); - _builder.append(_typeRef, " "); - _builder.append(".HIGHLIGHTING))"); - _builder.newLineIfNotEmpty(); - _builder.append(" "); - _builder.append(".to("); - _builder.append(AntlrTokenDefProvider.class, " "); - _builder.append(".class);"); - _builder.newLineIfNotEmpty(); + builder.append(_typeRef, " "); + builder.append(".HIGHLIGHTING))"); + builder.newLineIfNotEmpty(); + builder.append(" "); + builder.append(".to("); + builder.append(AntlrTokenDefProvider.class, " "); + builder.append(".class);"); + builder.newLineIfNotEmpty(); } }) .addTypeToType( @@ -1036,15 +1038,15 @@ protected void appendTo(StringConcatenationClient.TargetStringConcatenation _bui TypeReference.typeRef("org.eclipse.xtext.ui.editor.contentassist.antlr.DelegatingContentAssistContextFactory")) .addConfiguredBinding("ContentAssistLexerProvider", new StringConcatenationClient() { @Override - protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) { - _builder.append("binder.bind("); - _builder.append(caLexerClass); - _builder.append(".class).toProvider("); - _builder.append(LexerProvider.class); - _builder.append(".create("); - _builder.append(caLexerClass); - _builder.append(".class));"); - _builder.newLineIfNotEmpty(); + protected void appendTo(final StringConcatenationClient.TargetStringConcatenation builder) { + builder.append("binder.bind("); + builder.append(caLexerClass); + builder.append(".class).toProvider("); + builder.append(LexerProvider.class); + builder.append(".create("); + builder.append(caLexerClass); + builder.append(".class));"); + builder.newLineIfNotEmpty(); } }); @@ -1060,3 +1062,4 @@ protected void appendTo(StringConcatenationClient.TargetStringConcatenation _bui uiBindings.contributeTo(getLanguage().getEclipsePluginGenModule()); } } +// CHECKSTYLE:ON diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java index d13bda02da..be9188dca3 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java @@ -9,7 +9,6 @@ */ package com.avaloq.tools.ddk.xtext.generator.parser.common; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -46,12 +45,13 @@ import com.google.common.collect.Sets; import com.google.inject.Inject; +// CHECKSTYLE:OFF MagicNumber public class GrammarRuleAnnotations { @EmfAdaptable public static class NoBacktrack { public static class NoBacktrackAdapter extends AdapterImpl { - private GrammarRuleAnnotations.NoBacktrack element; + private final GrammarRuleAnnotations.NoBacktrack element; public NoBacktrackAdapter(final GrammarRuleAnnotations.NoBacktrack element) { this.element = element; @@ -76,6 +76,7 @@ public static GrammarRuleAnnotations.NoBacktrack findInEmfObject(final Notifier return null; } + @SuppressWarnings("PMD.ForLoopVariableCount") public static GrammarRuleAnnotations.NoBacktrack removeFromEmfObject(final Notifier emfObject) { List adapters = emfObject.eAdapters(); for (int i = 0, max = adapters.size(); i < max; i++) { @@ -106,16 +107,7 @@ public int hashCode() { @Override @Pure public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - return true; + return this == obj || (obj != null && getClass() == obj.getClass()); } @Override @@ -133,7 +125,7 @@ public String toString() { @EmfAdaptable public static class SemanticPredicate { public static class SemanticPredicateAdapter extends AdapterImpl { - private GrammarRuleAnnotations.SemanticPredicate element; + private final GrammarRuleAnnotations.SemanticPredicate element; public SemanticPredicateAdapter(final GrammarRuleAnnotations.SemanticPredicate element) { this.element = element; @@ -166,6 +158,7 @@ public static GrammarRuleAnnotations.SemanticPredicate findInEmfObject(final Not return null; } + @SuppressWarnings("PMD.ForLoopVariableCount") public static GrammarRuleAnnotations.SemanticPredicate removeFromEmfObject(final Notifier emfObject) { List adapters = emfObject.eAdapters(); for (int i = 0, max = adapters.size(); i < max; i++) { @@ -188,7 +181,6 @@ public void attachToEmfObject(final Notifier emfObject) { } public SemanticPredicate(final String name, final String message, final String grammar, final List keywords) { - super(); this.name = name; this.message = message; this.grammar = grammar; @@ -285,7 +277,7 @@ public List getKeywords() { @EmfAdaptable public static class GrammarAnnotations { public static class GrammarAnnotationsAdapter extends AdapterImpl { - private GrammarRuleAnnotations.GrammarAnnotations element; + private final GrammarRuleAnnotations.GrammarAnnotations element; public GrammarAnnotationsAdapter(final GrammarRuleAnnotations.GrammarAnnotations element) { this.element = element; @@ -312,6 +304,7 @@ public static GrammarRuleAnnotations.GrammarAnnotations findInEmfObject(final No return null; } + @SuppressWarnings("PMD.ForLoopVariableCount") public static GrammarRuleAnnotations.GrammarAnnotations removeFromEmfObject(final Notifier emfObject) { List adapters = emfObject.eAdapters(); for (int i = 0, max = adapters.size(); i < max; i++) { @@ -334,7 +327,6 @@ public void attachToEmfObject(final Notifier emfObject) { } public GrammarAnnotations(final List predicates) { - super(); this.predicates = predicates; } @@ -491,7 +483,7 @@ public GrammarAnnotations annotateGrammar(final Grammar grammar) { } public Set allInheritedGrammars(final Grammar grammar) { - HashSet result = Sets.newHashSet(); + Set result = Sets.newHashSet(); List allParserRules = GrammarUtil.allParserRules(grammar); for (AbstractRule rule : allParserRules) { Grammar ruleGrammar = GrammarUtil.getGrammar(rule); @@ -612,7 +604,7 @@ public boolean isFirstNonActionElement(final Group group, final AbstractElement } public String generateGatedPredicate(final SemanticPredicate predicate) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(64); sb.append("{predicates."); sb.append(predicate.name); sb.append("(parserContext)}?=>"); @@ -620,7 +612,7 @@ public String generateGatedPredicate(final SemanticPredicate predicate) { } public String generateValidatingPredicate(final SemanticPredicate predicate) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(64); sb.append("{predicates."); sb.append(predicate.name); sb.append("(parserContext) /* @ErrorMessage("); @@ -702,7 +694,7 @@ public NoBacktrack getNoBacktrackAnnotation(final AbstractRule rule) { public SemanticPredicate getKeywordRulePredicate(final String text, final String ruleName, final String grammar) { final Matcher matcher = KEYWORD_RULE_ANNOTATION_PATTERN.matcher(text); if (matcher.find()) { - ArrayList keywordsList = Lists.newArrayList(KEYWORDS_SPLITTER.split(matcher.group(1))); + List keywordsList = Lists.newArrayList(KEYWORDS_SPLITTER.split(matcher.group(1))); return new SemanticPredicate( "is" + ruleName + "Enabled", "get" + ruleName + "EnabledMessage", @@ -765,3 +757,4 @@ public boolean isSemanticPredicate(final AbstractRule rule) { return false; } } +// CHECKSTYLE:ON diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.java index b9b8dc1f82..fb88db62c2 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/resourceFactory/ResourceFactoryFragment2.java @@ -8,7 +8,7 @@ * licence agreement you entered into with Avaloq Group AG. */ -package com.avaloq.tools.ddk.xtext.generator.resourceFactory; +package com.avaloq.tools.ddk.xtext.generator.resourceFactory; // NOPMD PackageCase import java.util.Arrays; import java.util.List; @@ -22,14 +22,15 @@ import org.eclipse.xtend2.lib.StringConcatenationClient; /** - * Implementation that allows the fileExtensions for the fragment to be distinct from language.fileExtensions + * Implementation that allows the fileExtensions for the fragment to be distinct from language.fileExtensions. */ +@SuppressWarnings("PMD.PackageCase") public class ResourceFactoryFragment2 extends AbstractXtextGeneratorFragment { private List fileExtensions; @Inject - private XtextGeneratorNaming _xtextGeneratorNaming; + private XtextGeneratorNaming xtextGeneratorNaming; protected List getFileExtensions() { return fileExtensions; @@ -38,18 +39,22 @@ protected List getFileExtensions() { /** * Either a single file extension or a comma-separated list of extensions for which the language * shall be registered. + * + * @param fileExtensions + * comma-separated file extension list */ public void setFileExtensions(final String fileExtensions) { this.fileExtensions = Arrays.asList(fileExtensions.trim().split("\\s*,\\s*")); } + // CHECKSTYLE:CONSTANTS-OFF // This is ResourceFactoryFragment2#generate with language.fileExtensions replaced by getFileExtensions @Override public void generate() { getLanguage().getRuntimeGenSetup().getRegistrations().add(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append(TypeReference.typeRef(IResourceFactory.class)); target.append(" resourceFactory = injector.getInstance("); target.append(TypeReference.typeRef(IResourceFactory.class)); @@ -77,19 +82,19 @@ protected void appendTo(TargetStringConcatenation target) { }); if (getProjectConfig().getEclipsePlugin() != null && getProjectConfig().getEclipsePlugin().getPluginXml() != null) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("\n"); for (final String fileExtension : getFileExtensions()) { builder.append("\n"); builder.append(" \n"); builder.append(" \n"); builder.append("\n"); builder.append("\n"); builder.append(" \n"); builder.append(" \n"); builder.append("\n"); @@ -97,6 +102,7 @@ protected void appendTo(TargetStringConcatenation target) { getProjectConfig().getEclipsePlugin().getPluginXml().getEntries().add(builder.toString()); } } + // CHECKSTYLE:CONSTANTS-ON } diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java index 74971c5d72..b995334856 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java @@ -25,7 +25,7 @@ public class CompareFragment2 extends ResourceFactoryFragment2 { @Inject - private XtextGeneratorNaming _xtextGeneratorNaming; + private XtextGeneratorNaming xtextGeneratorNaming; private static final Logger LOGGER = LogManager.getLogger(CompareFragment2.class); @@ -71,10 +71,11 @@ public void generate() { } } + // CHECKSTYLE:CONSTANTS-OFF public CharSequence eclipsePluginXmlContribution() { - final TypeReference executableExtensionFactory = _xtextGeneratorNaming.getEclipsePluginExecutableExtensionFactory(getGrammar()); + final TypeReference executableExtensionFactory = xtextGeneratorNaming.getEclipsePluginExecutableExtensionFactory(getGrammar()); final String fileExtensions = String.join(",", getLanguage().getFileExtensions()); - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(1024); builder.append("\n"); builder.append("\n"); builder.append(" \n"); return builder; } + // CHECKSTYLE:CONSTANTS-ON } diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.java index 0e2e33cce4..7ccff8698b 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/contentAssist/AnnotationAwareContentAssistFragment2.java @@ -9,7 +9,7 @@ * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.generator.ui.contentAssist; +package com.avaloq.tools.ddk.xtext.generator.ui.contentAssist; // NOPMD PackageCase import java.util.ArrayList; import java.util.HashSet; @@ -37,6 +37,7 @@ import com.google.inject.Inject; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter", "PMD.PackageCase"}) public class AnnotationAwareContentAssistFragment2 extends ContentAssistFragment2 { /** @@ -54,7 +55,7 @@ public boolean isGenerateProposalProvider() { return generateProposalProvider; } - public void setGenerateProposalProvider(boolean generateProposalProvider) { + public void setGenerateProposalProvider(final boolean generateProposalProvider) { this.generateProposalProvider = generateProposalProvider; } @@ -65,6 +66,7 @@ public void generate() { } } + // CHECKSTYLE:CONSTANTS-OFF // generation of the 'Abstract...ProposalProvider' @Override @@ -119,20 +121,25 @@ protected void generateGenJavaProposalProvider() { javaFile.setTypeComment(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { - target.append("/**"); target.newLine(); + protected void appendTo(final TargetStringConcatenation target) { + target.append("/**"); + target.newLine(); target.append(" * Represents a generated, default implementation of superclass {@link "); target.append(superClass); - target.append("}."); target.newLine(); - target.append(" * Methods are dynamically dispatched on the first parameter, i.e., you can override them"); target.newLine(); - target.append(" * with a more concrete subtype."); target.newLine(); - target.append(" */"); target.newLine(); + target.append("}."); + target.newLine(); + target.append(" * Methods are dynamically dispatched on the first parameter, i.e., you can override them"); + target.newLine(); + target.append(" * with a more concrete subtype."); + target.newLine(); + target.append(" */"); + target.newLine(); } }); javaFile.setContent(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append("public "); if (isGenerateStub()) { target.append("abstract "); @@ -141,7 +148,9 @@ protected void appendTo(TargetStringConcatenation target) { target.append(genClass.getSimpleName()); target.append(" extends "); target.append(superClass); - target.append(" {"); target.newLineIfNotEmpty(); target.newLine(); + target.append(" {"); + target.newLineIfNotEmpty(); + target.newLine(); if (!assignments.isEmpty()) { for (Assignment assignment : assignments) { @@ -161,9 +170,11 @@ protected void appendTo(TargetStringConcatenation target) { target.append(getContentAssistContextClass()); target.append(" context, "); target.append(getICompletionProposalAcceptorClass()); - target.append(" acceptor) {"); target.newLineIfNotEmpty(); + target.append(" acceptor) {"); + target.newLineIfNotEmpty(); target.append(handleKeywordRule(rule)); - target.append(" }"); target.newLineIfNotEmpty(); + target.append(" }"); + target.newLineIfNotEmpty(); } target.newLine(); } @@ -178,33 +189,38 @@ protected void appendTo(TargetStringConcatenation target) { target.append(getContentAssistContextClass()); target.append(" context, "); target.append(getICompletionProposalAcceptorClass()); - target.append(" acceptor) {"); target.newLineIfNotEmpty(); - target.append(" // subclasses may override"); target.newLineIfNotEmpty(); - target.append(" }"); target.newLineIfNotEmpty(); + target.append(" acceptor) {"); + target.newLineIfNotEmpty(); + target.append(" // subclasses may override"); + target.newLineIfNotEmpty(); + target.append(" }"); + target.newLineIfNotEmpty(); } - target.append("}"); target.newLineIfNotEmpty(); + target.append("}"); + target.newLineIfNotEmpty(); } }); javaFile.writeTo(getProjectConfig().getEclipsePlugin().getSrcGen()); } - private StringConcatenationClient handleKeywordRule(AbstractRule rule) { + private StringConcatenationClient handleKeywordRule(final AbstractRule rule) { return new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { SemanticPredicate predAnnotation = annotations.getSemanticPredicateAnnotation(rule); if (predAnnotation != null && predAnnotation.getKeywords() != null) { for (String keyword : predAnnotation.getKeywords()) { target.append(" acceptor.accept(createCompletionProposal(\""); target.append(keyword); - target.append("\", context));"); target.newLineIfNotEmpty(); + target.append("\", context));"); + target.newLineIfNotEmpty(); } } } }; } - private StringConcatenationClient handleAssignment(Assignment assignment) { + private StringConcatenationClient handleAssignment(final Assignment assignment) { // determine all assignments within 'assignment's containing parser rule // assigning the same feature, obtain their expected terminals, ... final List terminals = new ArrayList<>(); @@ -222,7 +238,7 @@ private StringConcatenationClient handleAssignment(Assignment assignment) { return new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append(" public void complete"); target.append(getFQFeatureName(assignment)); target.append("("); @@ -233,24 +249,26 @@ protected void appendTo(TargetStringConcatenation target) { target.append(getContentAssistContextClass()); target.append(" context, "); target.append(getICompletionProposalAcceptorClass()); - target.append(" acceptor) {"); target.newLineIfNotEmpty(); + target.append(" acceptor) {"); + target.newLineIfNotEmpty(); if (terminalTypes.size() > 1) { target.append(handleAssignmentOptions(terminals)); } else { target.append(" "); target.append(assignmentTerminal(assignment.getTerminal(), new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append("assignment.getTerminal()"); } })); } - target.append(" }"); target.newLineIfNotEmpty(); + target.append(" }"); + target.newLineIfNotEmpty(); } }; } - private StringConcatenationClient handleAssignmentOptions(Iterable terminals) { + private StringConcatenationClient handleAssignmentOptions(final Iterable terminals) { final Set processedTerminals = new HashSet<>(); // for each type of terminal occurring in 'terminals' ... @@ -265,19 +283,21 @@ private StringConcatenationClient handleAssignmentOptions(Iterable elements = alternatives.getElements(); for (int i = 0; i < elements.size(); i++) { final int index = i; target.append(assignmentTerminal(elements.get(i), new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation target) { + protected void appendTo(final TargetStringConcatenation target) { target.append("(("); target.append(Alternatives.class); target.append(")"); @@ -356,6 +379,7 @@ protected void appendTo(TargetStringConcatenation target) { }; } + // CHECKSTYLE:CONSTANTS-ON // helper methods private TypeReference getContentAssistContextClass() { @@ -366,11 +390,11 @@ private TypeReference getICompletionProposalAcceptorClass() { return new TypeReference("org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor"); } - private String getFQFeatureName(AbstractRule r) { + private String getFQFeatureName(final AbstractRule r) { return "_" + r.getName(); } - private String getFQFeatureName(Assignment a) { + private String getFQFeatureName(final Assignment a) { String ruleName = GrammarUtil.containingParserRule(a).getName(); String firstUpper = ruleName.substring(0, 1).toUpperCase() + ruleName.substring(1); String featureName = a.getFeature(); diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/AcfKeywordHelper.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/AcfKeywordHelper.java index bbe4a0e00a..fdf9430e6c 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/AcfKeywordHelper.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/AcfKeywordHelper.java @@ -51,6 +51,8 @@ */ public class AcfKeywordHelper implements Adapter { + private static final int INITIAL_BUFFER_CAPACITY = 32; + private final BiMap keywordValueToToken; private final boolean ignoreCase; @@ -221,7 +223,7 @@ public int compare(final String o1, final String o2) { * @return Rule name */ private String createKeywordName(final int count, final String value) { - StringBuilder name = new StringBuilder(); + StringBuilder name = new StringBuilder(INITIAL_BUFFER_CAPACITY); name.append("KEYWORD_"); //$NON-NLS-1$ name.append(count); name.append('_'); diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/CustomClassAwareEcoreGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/CustomClassAwareEcoreGenerator.java index 103987ec51..d3f96ca3b1 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/CustomClassAwareEcoreGenerator.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/CustomClassAwareEcoreGenerator.java @@ -51,8 +51,8 @@ public class CustomClassAwareEcoreGenerator extends EcoreGenerator { // CHECKSTYLE:OFF private boolean generateModel = true; - private boolean generateEdit = false; - private boolean generateEditor = false; + private boolean generateEdit; + private boolean generateEditor; // CHECKSTYLE:ON private ResourceSet resourceSet; diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/StandaloneSetup.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/StandaloneSetup.java index 6967be2173..c2530461fc 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/StandaloneSetup.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/util/StandaloneSetup.java @@ -50,7 +50,7 @@ private List splitCommaSeparatedString(final String input) { return Collections. emptyList(); } String trimmed = input.trim(); - if (trimmed.length() == 0) { + if (trimmed.isEmpty()) { return Collections. emptyList(); } List result = Lists.newArrayList(); diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.java b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.java index aeba6f3453..48c1de34c6 100644 --- a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.java +++ b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeNameProviderGenerator.java @@ -1,3 +1,14 @@ +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + package com.avaloq.tools.ddk.xtext.scope.generator; import com.avaloq.tools.ddk.xtext.expression.expression.Expression; @@ -24,50 +35,65 @@ import org.eclipse.emf.ecore.EPackage; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class ScopeNameProviderGenerator { @Inject - private CodeGenerationX _codeGenerationX; + private CodeGenerationX codeGenerationX; @Inject - private ExpressionExtensionsX _expressionExtensionsX; + private ExpressionExtensionsX expressionExtensionsX; @Inject - private Naming _naming; + private Naming naming; @Inject - private GeneratorUtilX _generatorUtilX; + private GeneratorUtilX generatorUtilX; @Inject - private ScopeProviderX _scopeProviderX; + private ScopeProviderX scopeProviderX; private GenModelUtilX genModelUtil; private CompilationContext compilationContext; + // CHECKSTYLE:CONSTANTS-OFF + /** + * Generates the scope name provider class. + * + * @param it + * the scope model + * @param compilationContext + * the compilation context + * @param genModelUtil + * the gen model utility + * @return the generated source code + */ + // CHECKSTYLE:CHECK-OFF HiddenField public CharSequence generate(final ScopeModel it, final CompilationContext compilationContext, final GenModelUtilX genModelUtil) { + // CHECKSTYLE:CHECK-ON HiddenField this.compilationContext = compilationContext; this.genModelUtil = genModelUtil; - final StringBuilder builder = new StringBuilder(); - builder.append("package ").append(_naming.toJavaPackage(_scopeProviderX.getScopeNameProvider(it))).append(";\n"); - builder.append("\n"); + final StringBuilder builder = new StringBuilder(2048); + builder.append("package ").append(naming.toJavaPackage(scopeProviderX.getScopeNameProvider(it))).append(";\n"); + builder.append('\n'); builder.append("import java.util.Arrays;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import org.eclipse.emf.ecore.EClass;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import org.eclipse.xtext.naming.QualifiedName;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import com.avaloq.tools.ddk.xtext.scoping.AbstractScopeNameProvider;\n"); builder.append("import com.avaloq.tools.ddk.xtext.scoping.INameFunction;\n"); builder.append("import com.avaloq.tools.ddk.xtext.scoping.NameFunctions;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import com.google.common.base.Function;\n"); builder.append("import com.google.inject.Singleton;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("@SuppressWarnings(\"all\")\n"); builder.append("@Singleton\n"); - builder.append("public class ").append(_naming.toSimpleName(_scopeProviderX.getScopeNameProvider(it))).append(" extends AbstractScopeNameProvider {\n"); - builder.append("\n"); + builder.append("public class ").append(naming.toSimpleName(scopeProviderX.getScopeNameProvider(it))).append(" extends AbstractScopeNameProvider {\n"); + builder.append('\n'); builder.append(" @Override\n"); builder.append(" public Iterable internalGetNameFunctions(final EClass eClass) {\n"); if (it.getNaming() != null) { @@ -77,15 +103,16 @@ public CharSequence generate(final ScopeModel it, final CompilationContext compi for (final EPackage p : packages) { builder.append(" if (").append(genModelUtil.qualifiedPackageInterfaceName(p)).append(".eINSTANCE == eClass.getEPackage()) {\n"); builder.append(" switch (eClass.getClassifierID()) {\n"); - builder.append("\n"); + builder.append('\n'); + for (final NamingDefinition n : it.getNaming().getNamings()) { if (Objects.equals(n.getType().getEPackage(), p)) { builder.append(" case ").append(genModelUtil.classifierIdLiteral(n.getType())).append(":\n"); - builder.append(" ").append(_generatorUtilX.javaContributorComment(_generatorUtilX.location(n))).append("\n"); + builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(n))).append('\n'); builder.append(" return ").append(nameFunctions(n.getNaming(), it)).append(";\n"); } } - builder.append("\n"); + builder.append('\n'); builder.append(" default:\n"); builder.append(" return !eClass.getESuperTypes().isEmpty() ? getNameFunctions(eClass.getESuperTypes().get(0)) : null;\n"); builder.append(" }\n"); @@ -94,17 +121,40 @@ public CharSequence generate(final ScopeModel it, final CompilationContext compi } builder.append(" return !eClass.getESuperTypes().isEmpty() ? getNameFunctions(eClass.getESuperTypes().get(0)) : null;\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); builder.append("}\n"); return builder; } + // CHECKSTYLE:CONSTANTS-ON + /** + * Generates name functions for a naming definition. + * + * @param it + * the naming definition + * @param model + * the scope model + * @return the generated name functions + */ public CharSequence nameFunctions(final com.avaloq.tools.ddk.xtext.scope.scope.Naming it, final ScopeModel model) { return nameFunctions(it, model, null, null); } + /** + * Generates name functions for a naming definition with context. + * + * @param it + * the naming definition + * @param model + * the scope model + * @param contextName + * the context name + * @param contextType + * the context type + * @return the generated name functions + */ public CharSequence nameFunctions(final com.avaloq.tools.ddk.xtext.scope.scope.Naming it, final ScopeModel model, final String contextName, final EClass contextType) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("Arrays.asList("); boolean first = true; for (final NamingExpression n : it.getNames()) { @@ -114,16 +164,17 @@ public CharSequence nameFunctions(final com.avaloq.tools.ddk.xtext.scope.scope.N first = false; builder.append(nameFunction(n, model, contextName, contextType)); } - builder.append(")"); + builder.append(')'); return builder; } + // CHECKSTYLE:CONSTANTS-OFF protected String _nameFunction(final NamingExpression it, final ScopeModel model, final String contextName, final EClass contextType) { if (it.isFactory()) { if (contextName == null || contextType == null) { - return _codeGenerationX.javaExpression(it.getExpression(), compilationContext.clone("UNEXPECTED_THIS")); + return codeGenerationX.javaExpression(it.getExpression(), compilationContext.clone("UNEXPECTED_THIS")); } else { - return _codeGenerationX.javaExpression(it.getExpression(), compilationContext.clone("UNEXPECTED_THIS", null, contextName, contextType)); + return codeGenerationX.javaExpression(it.getExpression(), compilationContext.clone("UNEXPECTED_THIS", null, contextName, contextType)); } } else if (it.isExport()) { return "NameFunctions.exportNameFunction()"; @@ -133,7 +184,7 @@ protected String _nameFunction(final NamingExpression it, final ScopeModel model } protected String _nameFunction(final Expression it, final ScopeModel model, final String contextName, final EClass contextType) { - return "EXPRESSION_NOT_SUPPORTED(\"" + _expressionExtensionsX.serialize(it) + "\")"; + return "EXPRESSION_NOT_SUPPORTED(\"" + expressionExtensionsX.serialize(it) + "\")"; } protected String _nameFunction(final StringLiteral it, final ScopeModel model, final String contextName, final EClass contextType) { @@ -146,39 +197,55 @@ protected String _nameFunction(final IntegerLiteral it, final ScopeModel model, protected String _nameFunction(final FeatureCall it, final ScopeModel model, final String contextName, final EClass contextType) { final CompilationContext currentContext = (contextName == null) - ? compilationContext.clone("obj", _scopeProviderX.scopeType(it)) - : compilationContext.clone("obj", _scopeProviderX.scopeType(it), "ctx", contextType); - final StringBuilder builder = new StringBuilder(); - if ((it.getTarget() == null || _codeGenerationX.isThisCall(it.getTarget())) && _codeGenerationX.isSimpleFeatureCall(it, currentContext)) { - builder.append("NameFunctions.fromFeature(").append(genModelUtil.literalIdentifier(_scopeProviderX.feature(it))).append(")"); - } else if (_codeGenerationX.isSimpleNavigation(it, currentContext)) { - builder.append("\n"); + ? compilationContext.clone("obj", scopeProviderX.scopeType(it)) + : compilationContext.clone("obj", scopeProviderX.scopeType(it), "ctx", contextType); + final StringBuilder builder = new StringBuilder(512); + if ((it.getTarget() == null || codeGenerationX.isThisCall(it.getTarget())) && codeGenerationX.isSimpleFeatureCall(it, currentContext)) { + builder.append("NameFunctions.fromFeature(").append(genModelUtil.literalIdentifier(scopeProviderX.feature(it))).append(')'); + } else if (codeGenerationX.isSimpleNavigation(it, currentContext)) { + builder.append('\n'); builder.append("object -> {\n"); - builder.append(" final ").append(genModelUtil.instanceClassName(_scopeProviderX.scopeType(it))).append(" obj = (").append(genModelUtil.instanceClassName(_scopeProviderX.scopeType(it))).append(") object;\n"); - builder.append(" return toQualifiedName(").append(_codeGenerationX.javaExpression(it, currentContext)).append(");\n"); + builder.append(" final ").append(genModelUtil.instanceClassName(scopeProviderX.scopeType(it))).append(" obj = (").append(genModelUtil.instanceClassName(scopeProviderX.scopeType(it))).append(") object;\n"); + builder.append(" return toQualifiedName(").append(codeGenerationX.javaExpression(it, currentContext)).append(");\n"); builder.append(" }\n"); } else { - builder.append("EXPRESSION_NOT_SUPPORTED(\"").append(_expressionExtensionsX.serialize(it)).append("\")"); + builder.append("EXPRESSION_NOT_SUPPORTED(\"").append(expressionExtensionsX.serialize(it)).append("\")"); } return builder.toString(); } protected String _nameFunction(final OperationCall it, final ScopeModel model, final String contextName, final EClass contextType) { final CompilationContext currentContext = (contextName == null) - ? compilationContext.clone("obj", _scopeProviderX.scopeType(it)) - : compilationContext.clone("obj", _scopeProviderX.scopeType(it), "ctx", contextType); - final StringBuilder builder = new StringBuilder(); - if (_codeGenerationX.isCompilable(it, currentContext)) { + ? compilationContext.clone("obj", scopeProviderX.scopeType(it)) + : compilationContext.clone("obj", scopeProviderX.scopeType(it), "ctx", contextType); + final StringBuilder builder = new StringBuilder(512); + if (codeGenerationX.isCompilable(it, currentContext)) { builder.append("object -> {\n"); - builder.append(" final ").append(genModelUtil.instanceClassName(_scopeProviderX.scopeType(it))).append(" obj = (").append(genModelUtil.instanceClassName(_scopeProviderX.scopeType(it))).append(") object;\n"); - builder.append(" return toQualifiedName(").append(_codeGenerationX.javaExpression(it, currentContext)).append(");\n"); + builder.append(" final ").append(genModelUtil.instanceClassName(scopeProviderX.scopeType(it))).append(" obj = (").append(genModelUtil.instanceClassName(scopeProviderX.scopeType(it))).append(") object;\n"); + builder.append(" return toQualifiedName(").append(codeGenerationX.javaExpression(it, currentContext)).append(");\n"); builder.append(" }\n"); } else { - builder.append("EXPRESSION_NOT_SUPPORTED(\"").append(_expressionExtensionsX.serialize(it)).append("\")"); + builder.append("EXPRESSION_NOT_SUPPORTED(\"").append(expressionExtensionsX.serialize(it)).append("\")"); } return builder.toString(); } + // CHECKSTYLE:CONSTANTS-ON + /** + * Dispatches to the appropriate name function generator based on the type of the given object. + * + * @param it + * the object to generate a name function for + * @param model + * the scope model + * @param contextName + * the context name + * @param contextType + * the context type + * @return the generated name function code + * @throws IllegalArgumentException + * if the parameter types are not handled + */ public String nameFunction(final EObject it, final ScopeModel model, final String contextName, final EClass contextType) { if (it instanceof IntegerLiteral integerLiteral) { return _nameFunction(integerLiteral, model, contextName, contextType); diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.java b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.java index 38bbdf9bd2..127296ed50 100644 --- a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.java +++ b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderGenerator.java @@ -1,8 +1,8 @@ /******************************************************************************* * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. it program and the accompanying materials + * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies it distribution, and is available at + * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: @@ -43,6 +43,7 @@ import org.eclipse.emf.ecore.EClass; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class ScopeProviderGenerator { @Inject @@ -60,15 +61,32 @@ public class ScopeProviderGenerator { private CompilationContext compilationContext; private GenModelUtilX genModelUtil; + // CHECKSTYLE:CONSTANTS-OFF + + /** + * Generates the scope provider class source code. + * + * @param it + * the scope model + * @param nameProviderGenerator + * the name provider generator + * @param compilationContext + * the compilation context + * @param genModelUtil + * the gen model utility + * @return the generated source code + */ + // CHECKSTYLE:CHECK-OFF HiddenField public CharSequence generate(final ScopeModel it, final ScopeNameProviderGenerator nameProviderGenerator, final CompilationContext compilationContext, final GenModelUtilX genModelUtil) { + // CHECKSTYLE:CHECK-ON HiddenField this.nameProviderGenerator = nameProviderGenerator; this.compilationContext = compilationContext; this.genModelUtil = genModelUtil; - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(4096); builder.append("package ").append(naming.toJavaPackage(scopeProviderX.getScopeProvider(it))).append(";\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import java.util.Arrays;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import org.apache.logging.log4j.Logger;\n"); builder.append("import org.apache.logging.log4j.LogManager;\n"); builder.append("import org.eclipse.emf.ecore.EClass;\n"); @@ -76,43 +94,54 @@ public CharSequence generate(final ScopeModel it, final ScopeNameProviderGenerat builder.append("import org.eclipse.emf.ecore.EPackage;\n"); builder.append("import org.eclipse.emf.ecore.EReference;\n"); builder.append("import org.eclipse.emf.ecore.resource.Resource;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import org.eclipse.xtext.naming.QualifiedName;\n"); builder.append("import org.eclipse.xtext.resource.IEObjectDescription;\n"); builder.append("import org.eclipse.xtext.scoping.IScope;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import com.avaloq.tools.ddk.xtext.scoping.AbstractNameFunction;\n"); builder.append("import com.avaloq.tools.ddk.xtext.scoping.AbstractPolymorphicScopeProvider;\n"); builder.append("import com.avaloq.tools.ddk.xtext.scoping.IContextSupplier;\n"); builder.append("import com.avaloq.tools.ddk.xtext.scoping.INameFunction;\n"); builder.append("import com.avaloq.tools.ddk.xtext.scoping.NameFunctions;\n"); builder.append("import com.avaloq.tools.ddk.xtext.util.EObjectUtil;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import com.google.common.base.Predicate;\n"); if (!scopeProviderX.allInjections(it).isEmpty()) { builder.append("import com.google.inject.Inject;\n"); } - builder.append("\n"); + builder.append('\n'); builder.append("@SuppressWarnings(\"all\")\n"); builder.append("public class ").append(naming.toSimpleName(scopeProviderX.getScopeProvider(it))).append(" extends AbstractPolymorphicScopeProvider {\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" /** Class-wide logger. */\n"); builder.append(" private static final Logger LOGGER = LogManager.getLogger(").append(naming.toSimpleName(scopeProviderX.getScopeProvider(it))).append(".class);\n"); if (!scopeProviderX.allInjections(it).isEmpty()) { for (final com.avaloq.tools.ddk.xtext.scope.scope.Injection i : scopeProviderX.allInjections(it)) { builder.append(" @Inject\n"); - builder.append(" private ").append(i.getType()).append(" ").append(i.getName()).append(";\n"); + builder.append(" private ").append(i.getType()).append(' ').append(i.getName()).append(";\n"); } } - builder.append("\n"); + builder.append('\n'); builder.append(scopeMethods(it, naming.toSimpleName(it.getName()))); - builder.append("\n"); + builder.append('\n'); builder.append("}\n"); return builder; } + /** + * Generates scope methods for all scope definitions. + * + * @param it + * the scope model + * @param baseName + * the base name + * @return the generated scope methods + * @throws IllegalStateException + * if more than one global rule is found + */ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(4096); // doGetScope with EReference builder.append(" @Override\n"); @@ -122,12 +151,12 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { builder.append(" if (scopeName == null) {\n"); builder.append(" return null;\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" switch (scopeName) {\n"); final Set refScopeNames = refScopes.stream().map(s -> scopeProviderX.getScopeName(s)).collect(Collectors.toCollection(java.util.LinkedHashSet::new)); - for (final String scopeName : refScopeNames) { - builder.append(" case \"").append(scopeName).append("\":\n"); - for (final ScopeDefinition scope : refScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(scopeName)).toList()) { + for (final String refScopeName : refScopeNames) { + builder.append(" case \"").append(refScopeName).append("\":\n"); + for (final ScopeDefinition scope : refScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(refScopeName)).toList()) { builder.append(" if (reference == ").append(genModelUtil.literalIdentifier(scope.getReference())).append(") return ").append(scopeProviderX.scopeMethodName(scope)).append("(context, reference, originalResource);\n"); } builder.append(" break;\n"); @@ -137,7 +166,7 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { } builder.append(" return null;\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); // doGetScope with EClass builder.append(" @Override\n"); @@ -147,12 +176,12 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { builder.append(" if (scopeName == null) {\n"); builder.append(" return null;\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" switch (scopeName) {\n"); final Set typeScopeNames = typeScopes.stream().map(s -> scopeProviderX.getScopeName(s)).collect(Collectors.toCollection(java.util.LinkedHashSet::new)); - for (final String scopeName : typeScopeNames) { - builder.append(" case \"").append(scopeName).append("\":\n"); - for (final ScopeDefinition scope : typeScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(scopeName)).toList()) { + for (final String typeScopeName : typeScopeNames) { + builder.append(" case \"").append(typeScopeName).append("\":\n"); + for (final ScopeDefinition scope : typeScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(typeScopeName)).toList()) { builder.append(" if (type == ").append(genModelUtil.literalIdentifier(scope.getTargetType())).append(") return ").append(scopeProviderX.scopeMethodName(scope)).append("(context, type, originalResource);\n"); } builder.append(" break;\n"); @@ -162,7 +191,7 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { } builder.append(" return null;\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); // doGlobalCache with EReference builder.append(" @Override\n"); @@ -172,9 +201,9 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { builder.append(" if (scopeName != null && context.eContainer() == null) {\n"); builder.append(" switch (scopeName) {\n"); final Set refGlobalNames = refGlobalScopes.stream().map(s -> scopeProviderX.getScopeName(s)).collect(Collectors.toCollection(java.util.LinkedHashSet::new)); - for (final String scopeName : refGlobalNames) { - builder.append(" case \"").append(scopeName).append("\":\n"); - for (final ScopeDefinition scope : refScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(scopeName)).toList()) { + for (final String refGlobalName : refGlobalNames) { + builder.append(" case \"").append(refGlobalName).append("\":\n"); + for (final ScopeDefinition scope : refScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(refGlobalName)).toList()) { final List globalRules = scopeProviderX.allScopeRules(scope).stream().filter(r -> r.getContext().isGlobal()).toList(); if (!globalRules.isEmpty()) { builder.append(" if (reference == ").append(genModelUtil.literalIdentifier(scope.getReference())).append(") return true;\n"); @@ -188,7 +217,7 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { } builder.append(" return false;\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); // doGlobalCache with EClass builder.append(" @Override\n"); @@ -198,9 +227,9 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { builder.append(" if (context.eContainer() == null) {\n"); builder.append(" switch (scopeName) {\n"); final Set typeGlobalNames = typeGlobalScopes.stream().map(s -> scopeProviderX.getScopeName(s)).collect(Collectors.toCollection(java.util.LinkedHashSet::new)); - for (final String scopeName : typeGlobalNames) { - builder.append(" case \"").append(scopeName).append("\":\n"); - for (final ScopeDefinition scope : typeScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(scopeName)).toList()) { + for (final String typeGlobalName : typeGlobalNames) { + builder.append(" case \"").append(typeGlobalName).append("\":\n"); + for (final ScopeDefinition scope : typeScopes.stream().filter(s -> scopeProviderX.getScopeName(s).equals(typeGlobalName)).toList()) { final List globalRules = scopeProviderX.allScopeRules(scope).stream().filter(r -> r.getContext().isGlobal()).toList(); if (!globalRules.isEmpty()) { builder.append(" if (type == ").append(genModelUtil.literalIdentifier(scope.getTargetType())).append(") return true;\n"); @@ -214,7 +243,7 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { } builder.append(" return false;\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); // Per-scope methods for (final ScopeDefinition scope : scopeProviderX.allScopes(it)) { @@ -228,10 +257,10 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { final List localRules = scopeProviderX.allScopeRules(scope).stream().filter(r -> !r.getContext().isGlobal()).toList(); final List globalRules = scopeProviderX.allScopeRules(scope).stream().filter(r -> r.getContext().isGlobal()).toList(); if (globalRules.size() > 1) { - throw new RuntimeException("only one global rule allowed"); + throw new IllegalStateException("only one global rule allowed"); } for (final ScopeRule r : scopeProviderX.sortedRules(scopeProviderX.filterUniqueRules(new ArrayList<>(localRules)))) { - builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append("\n"); + builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append('\n'); if (EClassComparator.isEObjectType(r.getContext().getContextType())) { builder.append(" if (true) {\n"); } else { @@ -243,7 +272,7 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { builder.append(" }\n"); } if (!localRules.isEmpty() || !globalRules.isEmpty()) { - builder.append("\n"); + builder.append('\n'); builder.append(" final EObject eContainer = context.eContainer();\n"); builder.append(" if (eContainer != null) {\n"); builder.append(" return internalGetScope("); @@ -260,28 +289,43 @@ public CharSequence scopeMethods(final ScopeModel it, final String baseName) { } builder.append(", \"").append(scopeProviderX.getScopeName(scope)).append("\", originalResource);\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); } if (!globalRules.isEmpty()) { final ScopeRule r = globalRules.get(0); final List rulesForTypeAndContext = List.of(r); - builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append("\n"); + builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append('\n'); builder.append(" if (context.eResource() != null) {\n"); builder.append(" final Resource ctx = context.eResource();\n"); builder.append(scopeRuleBlock(rulesForTypeAndContext, it, scopeProviderX.contextRef(r) != null ? "ref" : "type", r.getContext().getContextType(), r.getContext().isGlobal())); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); } builder.append(" return null;\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); } return builder; } + /** + * Generates a scope rule block for the given rules. + * + * @param it + * the scope rules + * @param model + * the scope model + * @param typeOrRef + * type or reference identifier + * @param contextType + * the context EClass type + * @param isGlobal + * whether the scope is global + * @return the generated scope rule block + */ public CharSequence scopeRuleBlock(final List it, final ScopeModel model, final String typeOrRef, final EClass contextType, final Boolean isGlobal) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append(" IScope scope = IScope.NULLSCOPE;\n"); builder.append(" try {\n"); if (it.stream().anyMatch(r -> r.getContext().getGuard() != null)) { @@ -301,7 +345,7 @@ public CharSequence scopeRuleBlock(final List it, final ScopeModel mo } builder.append("{\n"); if (it.size() > 1) { - builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append("\n"); + builder.append(" ").append(generatorUtilX.javaContributorComment(generatorUtilX.location(r))).append('\n'); } final List reversed = Lists.newArrayList(r.getExprs()); Collections.reverse(reversed); @@ -315,7 +359,7 @@ public CharSequence scopeRuleBlock(final List it, final ScopeModel mo builder.append(" throw new UnsupportedOperationException(); // continue matching other definitions\n"); builder.append(" }"); } - builder.append("\n"); + builder.append('\n'); } else if (it.size() == 1) { final List reversed = Lists.newArrayList(it.get(0).getExprs()); Collections.reverse(reversed); @@ -348,7 +392,7 @@ protected CharSequence _scopeExpression(final ScopeExpression it, final ScopeMod } protected CharSequence _scopeExpression(final FactoryExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { - final StringBuilder b = new StringBuilder(); + final StringBuilder b = new StringBuilder(512); final CompilationContext ctx = compilationContext.clone("ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType()); b.append("scope = ").append(javaCall(it.getExpr(), ctx)).append("(scope, ctx, ").append(typeOrRef).append(", originalResource"); if (it.getExpr() instanceof OperationCall operationCall) { @@ -373,6 +417,17 @@ protected String _javaCall(final OperationCall it, final CompilationContext ctx) } } + /** + * Dispatches to the appropriate java call generator. + * + * @param it + * the expression + * @param ctx + * the compilation context + * @return the generated java call + * @throws IllegalArgumentException + * if the parameter types are not handled + */ public String javaCall(final Expression it, final CompilationContext ctx) { if (it instanceof OperationCall operationCall) { return _javaCall(operationCall, ctx); @@ -384,7 +439,7 @@ public String javaCall(final Expression it, final CompilationContext ctx) { } protected CharSequence _scopeExpression(final ScopeDelegation it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); if (it.getDelegate() != null) { final String delegateString = expressionExtensionsX.serialize(it.getDelegate()); if ("this.eContainer()".equals(delegateString) || "this.eContainer".equals(delegateString) || "eContainer()".equals(delegateString) || "eContainer".equals(delegateString)) { @@ -394,7 +449,7 @@ protected CharSequence _scopeExpression(final ScopeDelegation it, final ScopeMod } else { builder.append(" scope = newDelegateScope(\"").append(scopeProviderX.locatorString(it)).append("\", scope, "); if (!isGlobal) { - builder.append("() -> IContextSupplier.makeIterable(").append(scopedElements(it.getDelegate(), model, scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType(), "ctx")).append(")"); + builder.append("() -> IContextSupplier.makeIterable(").append(scopedElements(it.getDelegate(), model, scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType(), "ctx")).append(')'); } else { builder.append(scopedElements(it.getDelegate(), model, scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType(), "ctx")); } @@ -420,7 +475,7 @@ protected CharSequence _scopeExpression(final ScopeDelegation it, final ScopeMod } protected CharSequence _scopeExpression(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append(" scope = ").append(scopeExpressionPart(it, model, typeOrRef, scope)); builder.append(scopeExpressionNaming(it, model, typeOrRef, scope)); builder.append(scopeExpressionCasing(it, model, typeOrRef, scope)).append(");\n"); @@ -428,9 +483,9 @@ protected CharSequence _scopeExpression(final NamedScopeExpression it, final Sco } protected CharSequence _scopeExpression(final SimpleScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); if (expressionExtensionsX.isEmptyList(it.getExpr())) { - builder.append(" // Empty scope from ").append(generatorUtilX.location(it)).append("\n"); + builder.append(" // Empty scope from ").append(generatorUtilX.location(it)).append('\n'); } else { builder.append(" scope = ").append(scopeExpressionPart(it, model, typeOrRef, scope)); builder.append(scopeExpressionNaming(it, model, typeOrRef, scope)); @@ -439,6 +494,23 @@ protected CharSequence _scopeExpression(final SimpleScopeExpression it, final Sc return builder; } + /** + * Dispatches to the appropriate scope expression generator. + * + * @param it + * the scope expression + * @param model + * the scope model + * @param typeOrRef + * type or reference identifier + * @param scope + * the scope definition + * @param isGlobal + * whether the scope is global + * @return the generated scope expression + * @throws IllegalArgumentException + * if the parameter types are not handled + */ public CharSequence scopeExpression(final ScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope, final Boolean isGlobal) { if (it instanceof FactoryExpression factoryExpression) { return _scopeExpression(factoryExpression, model, typeOrRef, scope, isGlobal); @@ -468,14 +540,14 @@ protected String _scopeExpressionPart(final SimpleScopeExpression it, final Scop } protected CharSequence _scopeExpressionPart(final GlobalScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); final List matchData = new ArrayList<>(); for (final Object d : it.getData()) { if (d instanceof LambdaDataExpression lambdaDataExpression) { matchData.add(lambdaDataExpression); } } - builder.append("\n"); + builder.append('\n'); if (matchData.isEmpty() && it.getPrefix() == null) { builder.append("newContainerScope("); } else if (matchData.isEmpty() && it.getPrefix() != null) { @@ -483,7 +555,7 @@ protected CharSequence _scopeExpressionPart(final GlobalScopeExpression it, fina } else { builder.append("newDataMatchScope("); } - builder.append("\"").append(scopeProviderX.locatorString(it)).append("\", scope, ctx, "); + builder.append('"').append(scopeProviderX.locatorString(it)).append("\", scope, ctx, "); builder.append(query(it, model, typeOrRef, scope)).append(", originalResource"); if (!matchData.isEmpty()) { builder.append(", //\n"); @@ -509,6 +581,21 @@ protected CharSequence _scopeExpressionPart(final GlobalScopeExpression it, fina return builder; } + /** + * Dispatches to the appropriate scope expression part generator. + * + * @param it + * the named scope expression + * @param model + * the scope model + * @param typeOrRef + * type or reference identifier + * @param scope + * the scope definition + * @return the generated scope expression part + * @throws IllegalArgumentException + * if the parameter types are not handled + */ public CharSequence scopeExpressionPart(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { if (it instanceof GlobalScopeExpression globalScopeExpression) { return _scopeExpressionPart(globalScopeExpression, model, typeOrRef, scope); @@ -521,9 +608,22 @@ public CharSequence scopeExpressionPart(final NamedScopeExpression it, final Sco } } + /** + * Generates a query for a global scope expression. + * + * @param it + * the global scope expression + * @param model + * the scope model + * @param typeOrRef + * type or reference identifier + * @param scope + * the scope definition + * @return the generated query + */ public CharSequence query(final GlobalScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { - final StringBuilder builder = new StringBuilder(); - builder.append("newQuery(").append(genModelUtil.literalIdentifier(it.getType())).append(")"); + final StringBuilder builder = new StringBuilder(512); + builder.append("newQuery(").append(genModelUtil.literalIdentifier(it.getType())).append(')'); final List matchData = new ArrayList<>(); for (final Object d : it.getData()) { if (d instanceof MatchDataExpression matchDataExpression) { @@ -531,11 +631,11 @@ public CharSequence query(final GlobalScopeExpression it, final ScopeModel model } } if (it.getName() != null) { - builder.append(".name(").append(doExpression(it.getName(), model, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType())).append(")"); + builder.append(".name(").append(doExpression(it.getName(), model, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType())).append(')'); } if (!matchData.isEmpty()) { for (final MatchDataExpression d : matchData) { - builder.append(".data(\"").append(codeGenerationX.javaEncode(d.getKey())).append("\", ").append(doExpression(d.getValue(), model, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType())).append(")"); + builder.append(".data(\"").append(codeGenerationX.javaEncode(d.getKey())).append("\", ").append(doExpression(d.getValue(), model, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType())).append(')'); } } if (!it.getDomains().isEmpty() && !"*".equals(it.getDomains().get(0))) { @@ -546,12 +646,13 @@ public CharSequence query(final GlobalScopeExpression it, final ScopeModel model builder.append(", "); } firstDomain = false; - builder.append("\"").append(codeGenerationX.javaEncode(d)).append("\""); + builder.append('"').append(codeGenerationX.javaEncode(d)).append('"'); } - builder.append(")"); + builder.append(')'); } return builder; } + // CHECKSTYLE:CONSTANTS-ON // dispatch scopeExpressionNaming protected String _scopeExpressionNaming(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { @@ -566,6 +667,21 @@ protected String _scopeExpressionNaming(final GlobalScopeExpression it, final Sc return ", " + name(it, model, typeOrRef, "ctx", scopeProviderX.eContainer(it, ScopeRule.class).getContext().getContextType()); } + /** + * Dispatches to the appropriate scope expression naming generator. + * + * @param it + * the named scope expression + * @param model + * the scope model + * @param typeOrRef + * type or reference identifier + * @param scope + * the scope definition + * @return the generated naming expression + * @throws IllegalArgumentException + * if the parameter types are not handled + */ public String scopeExpressionNaming(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { if (it instanceof GlobalScopeExpression globalScopeExpression) { return _scopeExpressionNaming(globalScopeExpression, model, typeOrRef, scope); @@ -578,18 +694,72 @@ public String scopeExpressionNaming(final NamedScopeExpression it, final ScopeMo } } + /** + * Returns the case sensitivity setting for the scope expression. + * + * @param it + * the named scope expression + * @param model + * the scope model + * @param typeOrRef + * type or reference identifier + * @param scope + * the scope definition + * @return the case sensitivity expression + */ public String scopeExpressionCasing(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final ScopeDefinition scope) { return ", " + Boolean.toString(scopeProviderX.isCaseInsensitive(it)); } + /** + * Returns the scoped elements expression. + * + * @param it + * the expression + * @param model + * the scope model + * @param type + * the EClass type + * @param object + * the object name + * @return the scoped elements expression + */ public String scopedElements(final Expression it, final ScopeModel model, final EClass type, final String object) { return doExpression(it, model, object, type); } + /** + * Compiles an expression to Java. + * + * @param it + * the expression + * @param model + * the scope model + * @param object + * the object name + * @param type + * the EClass type + * @return the compiled Java expression + */ public String doExpression(final Expression it, final ScopeModel model, final String object, final EClass type) { return codeGenerationX.javaExpression(it, compilationContext.clone(object, type)); } + /** + * Returns name functions for the given expression. + * + * @param it + * the named scope expression + * @param model + * the scope model + * @param typeOrRef + * type or reference identifier + * @param contextName + * the context name + * @param contextType + * the context type + * @return the name functions expression + */ public String name(final NamedScopeExpression it, final ScopeModel model, final String typeOrRef, final String contextName, final EClass contextType) { if (it.getNaming() != null) { return nameProviderGenerator.nameFunctions(it.getNaming(), model, contextName, contextType).toString(); @@ -598,7 +768,16 @@ public String name(final NamedScopeExpression it, final ScopeModel model, final } } + /** + * Throws a runtime exception with the given message. + * + * @param message + * the error message + * @return never returns + * @throws IllegalStateException + * always thrown with the given message + */ public String error(final String message) { - throw new RuntimeException(message); + throw new IllegalStateException(message); } } diff --git a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.java b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.java index 7fb20c555b..596d7d03c0 100644 --- a/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.java +++ b/com.avaloq.tools.ddk.xtext.scope/src/com/avaloq/tools/ddk/xtext/scope/generator/ScopeProviderX.java @@ -1,8 +1,8 @@ /******************************************************************************* * Copyright (c) 2016 Avaloq Group AG and others. - * All rights reserved. it program and the accompanying materials + * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies it distribution, and is available at + * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: @@ -39,6 +39,7 @@ import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class ScopeProviderX { @Inject @@ -53,19 +54,47 @@ public class ScopeProviderX { /* * CODE GENERATION */ + + /** + * Returns the fully qualified name of the scope provider for the given model. + * + * @param model + * the scope model + * @return the scope provider name + */ public String getScopeProvider(final ScopeModel model) { return naming.toJavaPackage(model.getName()) + ".scoping." + naming.toSimpleName(model.getName()) + "ScopeProvider"; } + /** + * Returns the fully qualified name of the scope name provider for the given model. + * + * @param model + * the scope model + * @return the scope name provider name + */ public String getScopeNameProvider(final ScopeModel model) { return naming.toJavaPackage(model.getName()) + ".scoping." + naming.toSimpleName(model.getName()) + "ScopeNameProvider"; } - // returns the name of the scope method generated for the given scope definition + /** + * Returns the name of the scope method generated for the given scope definition. + * + * @param it + * the scope definition + * @return the scope method name + */ public String scopeMethodName(final ScopeDefinition it) { return getScopeName(it) + "_" + (it.getTargetType() != null ? it.getTargetType().getEPackage().getName() + "_" + it.getTargetType().getName() : it.getContextType().getEPackage().getName() + "_" + it.getContextType().getName() + "_" + it.getReference().getName()); } + /** + * Returns the locator string for the given object. + * + * @param it + * the EObject + * @return the encoded locator string + */ public String locatorString(final EObject it) { final String location = generatorUtilX.location(it); final String[] parts = location.split("/"); @@ -73,10 +102,24 @@ public String locatorString(final EObject it) { return codeGenerationX.javaEncode(last); } + /** + * Returns the called feature name from a feature call. + * + * @param it + * the feature call + * @return the called feature name + */ public String calledFeature(final FeatureCall it) { return it.getType().getId().get(0); } + /** + * Returns the structural feature for the given feature call. + * + * @param it + * the feature call + * @return the structural feature + */ public EStructuralFeature feature(final FeatureCall it) { return scopeType(it).getEStructuralFeature(calledFeature(it)); } @@ -93,6 +136,13 @@ protected List _allScopeRules(final ScopeDefinition it) { return collectAllScopeRules(getModel(it), it); } + /** + * Returns all scope rules for the given scope definition. + * + * @param it + * the scope definition + * @return the list of all scope rules + */ public List allScopeRules(final ScopeDefinition it) { if (it != null) { return _allScopeRules(it); @@ -101,6 +151,15 @@ public List allScopeRules(final ScopeDefinition it) { } } + /** + * Collects all scope rules from the model and included scopes. + * + * @param it + * the scope model + * @param def + * the scope definition to match + * @return the collected scope rules + */ public List collectAllScopeRules(final ScopeModel it, final ScopeDefinition def) { final List myScopeRules = new ArrayList<>(); for (final ScopeDefinition d : it.getScopes()) { @@ -108,11 +167,8 @@ public List collectAllScopeRules(final ScopeModel it, final ScopeDefi myScopeRules.addAll(d.getRules()); } } - final List result; - if (it.getIncludedScopes().isEmpty()) { - result = new ArrayList<>(); - } else { - result = new ArrayList<>(); + final List result = new ArrayList<>(); + if (!it.getIncludedScopes().isEmpty()) { for (final ScopeModel included : it.getIncludedScopes()) { result.addAll(collectAllScopeRules(included, def)); } @@ -121,10 +177,24 @@ public List collectAllScopeRules(final ScopeModel it, final ScopeDefi return result; } + /** + * Returns the rules sorted. + * + * @param it + * the collection of scope rules + * @return the sorted list of rules + */ public List sortedRules(final Collection it) { return ScopingGeneratorUtil.sortedRules(it); } + /** + * Filters the unique rules from the list. + * + * @param it + * the list of scope rules + * @return the set of unique rules + */ public Set filterUniqueRules(final List it) { return it.stream() .map(r -> it.stream().filter(r2 -> hasSameContext(r2, r)).findFirst().orElse(null)) @@ -138,6 +208,15 @@ protected boolean _isEqual(final ScopeRule a, final ScopeRule b) { && Objects.equals(expressionExtensionsX.serialize(a.getContext().getGuard()), expressionExtensionsX.serialize(b.getContext().getGuard())); } + /** + * Returns whether two scope rules have the same context. + * + * @param a + * the first scope rule + * @param b + * the second scope rule + * @return true if the rules have the same context + */ public boolean hasSameContext(final ScopeRule a, final ScopeRule b) { return ruleSignature(a).equals(ruleSignature(b)); } @@ -154,11 +233,8 @@ public boolean hasSameContext(final ScopeRule a, final ScopeRule b) { // dispatch allScopes protected List _allScopes(final ScopeModel it) { final List myScopes = it.getScopes(); - final List result; - if (it.getIncludedScopes().isEmpty()) { - result = new ArrayList<>(); - } else { - result = new ArrayList<>(); + final List result = new ArrayList<>(); + if (!it.getIncludedScopes().isEmpty()) { for (final ScopeModel included : it.getIncludedScopes()) { result.addAll(allScopes(included)); } @@ -172,6 +248,13 @@ protected List _allScopes(final Void it) { return new ArrayList<>(); } + /** + * Returns the list of all local and inherited scope definitions. + * + * @param it + * the scope model + * @return the list of all scope definitions + */ public List allScopes(final ScopeModel it) { if (it != null) { return _allScopes(it); @@ -180,6 +263,13 @@ public List allScopes(final ScopeModel it) { } } + /** + * Returns the scope name for the given definition. + * + * @param it + * the scope definition + * @return the scope name, or "scope" if not set + */ public String getScopeName(final ScopeDefinition it) { if (it.getName() == null) { return "scope"; @@ -188,12 +278,17 @@ public String getScopeName(final ScopeDefinition it) { } } + /** + * Returns whether the list contains a scope equal to the given scope. + * + * @param list + * the list of scope definitions + * @param scope + * the scope definition to check + * @return true if the list contains an equal scope + */ public boolean hasScope(final List list, final ScopeDefinition scope) { - if (list.isEmpty()) { - return false; - } else { - return list.stream().anyMatch(s -> isEqual(s, scope)); - } + return !list.isEmpty() && list.stream().anyMatch(s -> isEqual(s, scope)); } // dispatch isEqual(ScopeDefinition, ScopeDefinition) @@ -225,6 +320,15 @@ protected EClass _scopeType(final Expression it) { } } + /** + * Returns the scope type for the given object. + * + * @param it + * the EObject (ScopeDefinition, ScopeRule, or Expression) + * @return the scope EClass type + * @throws IllegalArgumentException + * if the parameter type is not handled + */ public EClass scopeType(final EObject it) { if (it instanceof ScopeDefinition scopeDefinition) { return _scopeType(scopeDefinition); @@ -237,6 +341,13 @@ public EClass scopeType(final EObject it) { } } + /** + * Returns the type or reference of the scope definition. + * + * @param it + * the scope definition + * @return the type or reference + */ public ENamedElement typeOrRef(final ScopeDefinition it) { if (it.getReference() != null) { return it.getReference(); @@ -245,6 +356,13 @@ public ENamedElement typeOrRef(final ScopeDefinition it) { } } + /** + * Returns the context reference of the scope rule. + * + * @param it + * the scope rule + * @return the context reference + */ public EReference contextRef(final ScopeRule it) { return getScope(it).getReference(); } @@ -256,11 +374,8 @@ public EReference contextRef(final ScopeRule it) { // dispatch allInjections protected List _allInjections(final ScopeModel it) { final List myInjections = it.getInjections(); - final List result; - if (it.getIncludedScopes().isEmpty()) { - result = new ArrayList<>(); - } else { - result = new ArrayList<>(); + final List result = new ArrayList<>(); + if (!it.getIncludedScopes().isEmpty()) { for (final ScopeModel included : it.getIncludedScopes()) { result.addAll(allInjections(included)); } @@ -274,6 +389,13 @@ protected List _allInjections(final Void it) { return new ArrayList<>(); } + /** + * Returns the list of all local and inherited injections. + * + * @param it + * the scope model + * @return the list of all injections + */ public List allInjections(final ScopeModel it) { if (it != null) { return _allInjections(it); @@ -282,12 +404,17 @@ public List allInjections(final ScopeModel it) { } } + /** + * Returns whether the list contains an injection equal to the given injection. + * + * @param list + * the list of injections + * @param injection + * the injection to check + * @return true if the list contains an equal injection + */ public boolean hasInjection(final List list, final Injection injection) { - if (list.isEmpty()) { - return false; - } else { - return list.stream().anyMatch(i -> isEqual(i, injection)); - } + return !list.isEmpty() && list.stream().anyMatch(i -> isEqual(i, injection)); } // dispatch isEqual(Injection, Injection) @@ -298,6 +425,14 @@ protected boolean _isEqual(final Injection a, final Injection b) { /* * SCOPE EXPRESSIONS */ + + /** + * Returns whether the named scope expression is case insensitive. + * + * @param it + * the named scope expression + * @return true if case insensitive + */ public boolean isCaseInsensitive(final NamedScopeExpression it) { return ScopingGeneratorUtil.isCaseInsensitive(it); } @@ -305,18 +440,51 @@ public boolean isCaseInsensitive(final NamedScopeExpression it) { /* * ECONTAINER */ + + /** + * Returns the scope model from the given object's resource. + * + * @param it + * the EObject + * @return the scope model + */ public ScopeModel getModel(final EObject it) { return (ScopeModel) it.eResource().getContents().get(0); } + /** + * Returns the enclosing scope definition for the given object. + * + * @param it + * the EObject + * @return the enclosing scope definition + */ public /*cached*/ ScopeDefinition getScope(final EObject it) { return eContainer(it, ScopeDefinition.class); } + /** + * Returns the enclosing naming definition for the given object. + * + * @param it + * the EObject + * @return the enclosing naming definition + */ public /*cached*/ NamingDefinition getNamingDef(final EObject it) { return eContainer(it, NamingDefinition.class); } + /** + * Finds the nearest ancestor of the given type. + * + * @param + * the ancestor type + * @param it + * the EObject + * @param type + * the class of the ancestor type + * @return the nearest ancestor of the given type, or null + */ public T eContainer(final EObject it, final Class type) { if (it == null) { return null; @@ -333,9 +501,11 @@ public T eContainer(final EObject it, final Class type) { * ECORE */ // dispatch isEqual(EClass, EClass) + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity protected boolean _isEqual(final EClass a, final EClass b) { return a == b || (a != null && b != null && a.getName().equals(b.getName()) && a.getEPackage().getNsURI().equals(b.getEPackage().getNsURI())); } + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity protected boolean _isEqualVoidVoid(final Void a, final Void b) { return true; @@ -350,11 +520,23 @@ protected boolean _isEqualVoidObject(final Void a, final EObject b) { } // dispatch isEqual(EReference, EReference) + // CHECKSTYLE:CHECK-OFF BooleanExpressionComplexity protected boolean _isEqual(final EReference a, final EReference b) { return a == b || (a != null && b != null && a.getName().equals(b.getName()) && isEqual(a.getEContainingClass(), b.getEContainingClass())); } - - // Public dispatcher for isEqual - handles all type combinations + // CHECKSTYLE:CHECK-ON BooleanExpressionComplexity + + /** + * Public dispatcher for isEqual - handles all type combinations. + * + * @param a + * the first object + * @param b + * the second object + * @return true if the two objects are considered equal + * @throws IllegalArgumentException + * if the parameter types are not handled + */ public boolean isEqual(final Object a, final Object b) { if (a instanceof ScopeRule ruleA && b instanceof ScopeRule ruleB) { return _isEqual(ruleA, ruleB); From 3b3f888e217a34606b0739575e299b3fcdd47252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 17:01:39 +0100 Subject: [PATCH 15/23] style: fix UnnecessaryBoxing in AnnotationAwareAntlrGrammarGenerator Co-Authored-By: Claude Opus 4.6 --- .../parser/antlr/AnnotationAwareAntlrGrammarGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java index ed5fb293eb..35f2c10681 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrGrammarGenerator.java @@ -332,7 +332,7 @@ protected String compileEntryReturns(final ParserRule it, final AntlrOptions opt protected String compileInit(final AbstractRule it, final AntlrOptions options) { final StringConcatenation builder = new StringConcatenation(); if (it instanceof ParserRule) { - builder.append(AntlrGrammarGenUtil.getParameterList((ParserRule) it, Boolean.valueOf(!this.isPassCurrentIntoFragment()), this.getCurrentType())); + builder.append(AntlrGrammarGenUtil.getParameterList((ParserRule) it, !this.isPassCurrentIntoFragment(), this.getCurrentType())); } builder.append(" returns "); builder.append(this.compileReturns(it, options)); From a15f188a4d51f8e73f7be827cf1e19a4d1dea68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 19:03:40 +0100 Subject: [PATCH 16/23] style: fix all remaining PMD and checkstyle violations in migrated code Resolve ~600 PMD and Checkstyle violations across all modules affected by the Xtend-to-Java migration: check.core, check.core.test, check.ui, check.ui.test, checkcfg.core, checkcfg.core.test, format.generator, export.generator, generator.test, and generator. Co-Authored-By: Claude Opus 4.6 --- .../core/generator/IssueCodeValueTest.java | 3 +- .../ddk/check/core/test/BasicModelTest.java | 2 + .../ddk/check/core/test/CheckScopingTest.java | 2 + .../IssueCodeToLabelMapGenerationTest.java | 42 +- .../check/core/test/ProjectBasedTests.java | 2 +- .../check/core/test/util/CheckModelUtil.java | 78 +- .../check/core/test/util/CheckTestUtil.java | 3 +- .../check/formatting/CheckFormattingTest.java | 2042 +++++++++-------- .../CheckApiAccessValidationsTest.java | 1 + .../check/validation/CheckValidationTest.java | 6 +- .../check/compiler/CheckGeneratorConfig.java | 6 +- .../ddk/check/formatting2/CheckFormatter.java | 106 +- .../ddk/check/generator/CheckGenerator.java | 87 +- .../generator/CheckGeneratorExtensions.java | 284 ++- .../check/generator/CheckGeneratorNaming.java | 50 +- .../check/jvmmodel/CheckJvmModelInferrer.java | 252 +- .../ddk/check/scoping/CheckScopeProvider.java | 24 +- .../ddk/check/typing/CheckTypeComputer.java | 7 +- .../ui/test/quickfix/CheckQuickfixTest.java | 44 +- .../ddk/check/ui/wizard/CheckNewProject.java | 20 +- .../ui/wizard/CheckQuickfixProvider.java | 12 +- .../CheckCfgContentAssistTest.java | 6 +- .../scoping/CheckCfgScopeProviderTest.java | 23 +- .../checkcfg/syntax/CheckCfgSyntaxTest.java | 18 +- ...CfgConfiguredParameterValidationsTest.java | 4 +- .../checkcfg/generator/CheckCfgGenerator.java | 3 +- .../jvmmodel/CheckCfgJvmModelInferrer.java | 18 +- .../util/PropertiesInferenceHelper.java | 24 +- .../validation/ConfiguredParameterChecks.java | 2 +- .../export/generator/ExportFragment2.java | 10 +- .../format/generator/FormatFragment2.java | 8 +- .../test/XbaseGeneratorFragmentTest.java | 30 +- ...areAntlrContentAssistGrammarGenerator.java | 2 +- 33 files changed, 1721 insertions(+), 1500 deletions(-) diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java index 2e5d74ef04..5832942e93 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java @@ -12,6 +12,7 @@ package com.avaloq.tools.ddk.check.core.generator; import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; @@ -88,7 +89,7 @@ public void testIssueCodeValue() throws Exception { // ACT List compiledClassesList; - ByteArrayInputStream sourceStream = new ByteArrayInputStream(source.getBytes()); + ByteArrayInputStream sourceStream = new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)); try { compiledClassesList = generateAndCompile(sourceStream); } finally { diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.java index 7acf251db5..620fc244fc 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BasicModelTest.java @@ -30,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +// CHECKSTYLE:CONSTANTS-OFF @InjectWith(CheckUiInjectorProvider.class) @ExtendWith(InjectionExtension.class) public class BasicModelTest { @@ -118,3 +119,4 @@ public void testKeywordAsIdentifier() throws Exception { "Syntax errors not expected but occurred"); } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.java index 05e454d12d..9489ecf5ad 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/CheckScopingTest.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +// CHECKSTYLE:CONSTANTS-OFF @InjectWith(CheckUiInjectorProvider.class) @ExtendWith(InjectionExtension.class) public class CheckScopingTest extends AbstractCheckTestCase { @@ -82,3 +83,4 @@ public void testCheckDescriptionIsInferred() throws Exception { assertEquals("This check is javadoc-like commented.", check.getDescription(), "Referenced check cannot be resolved"); } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java index 6b8ef8b9d7..a81e4178c8 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java @@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; import java.util.List; import org.eclipse.xtext.testing.InjectWith; @@ -28,6 +29,7 @@ /** * Unit test for auto generation of check issue code to label map. */ +// CHECKSTYLE:CONSTANTS-OFF @InjectWith(CheckInjectorProvider.class) @ExtendWith(InjectionExtension.class) @SuppressWarnings("nls") @@ -43,16 +45,16 @@ public class IssueCodeToLabelMapGenerationTest extends AbstractCheckGenerationTe @Test public void testMapGenerationWithNoChecks() { // ARRANGE - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("package "); builder.append(PACKAGE_NAME); - builder.append("\n"); - builder.append("\n"); + builder.append('\n'); + builder.append('\n'); builder.append("catalog "); builder.append(CATALOG_NAME); - builder.append("\n"); + builder.append('\n'); builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); - builder.append("\n"); + builder.append('\n'); builder.append("}\n"); final String source = builder.toString(); @@ -69,21 +71,22 @@ public void testMapGenerationWithNoChecks() { @Test public void testMapGeneration() { // ARRANGE + // CHECKSTYLE:CHECK-OFF VariableDeclarationUsageDistance // @Format-Off - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(2048); builder.append("package "); builder.append(PACKAGE_NAME); - builder.append("\n"); - builder.append("\n"); + builder.append('\n'); + builder.append('\n'); builder.append("import com.avaloq.tools.ddk.check.check.Check\n"); builder.append("import com.avaloq.tools.ddk.check.check.Context\n"); builder.append("import com.avaloq.tools.ddk.check.check.Documented\n"); - builder.append("\n"); + builder.append('\n'); builder.append("catalog "); builder.append(CATALOG_NAME); - builder.append("\n"); + builder.append('\n'); builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" live error ID1 \"Label 1\"\n"); builder.append(" message \"Message 1\" {\n"); builder.append(" for Documented elem {\n"); @@ -93,7 +96,7 @@ public void testMapGeneration() { builder.append(" }\n"); builder.append(" }\n"); builder.append(" }\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" live error ID2 \"Label 2\"\n"); builder.append(" message \"Message 2\" {\n"); builder.append(" for Documented elem {\n"); @@ -105,6 +108,7 @@ public void testMapGeneration() { builder.append(" }\n"); builder.append("}\n"); final String source = builder.toString(); + // CHECKSTYLE:CHECK-ON VariableDeclarationUsageDistance // @Format-On final List expectedCatalog = List.of("put(MyCatalogIssueCodes.ID_1,\"Label1\")", "put(MyCatalogIssueCodes.ID_2,\"Label2\")"); @@ -123,17 +127,8 @@ public void testMapGeneration() { */ public void testMapGeneration(final String source, final List expectedCatalog) { // ACT - List compiledClassesList; - final ByteArrayInputStream sourceStream = new ByteArrayInputStream(source.getBytes()); - try { - compiledClassesList = generateAndCompile(sourceStream); - } finally { - try { - sourceStream.close(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + final ByteArrayInputStream sourceStream = new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)); + final List compiledClassesList = generateAndCompile(sourceStream); // ASSERT final String catalogClassName = CATALOG_NAME + CATALOG_NAME_SUFFIX; @@ -149,3 +144,4 @@ public void testMapGeneration(final String source, final List expectedCa } } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.java index e11cba04f4..7c2e0ddc37 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/ProjectBasedTests.java @@ -65,7 +65,7 @@ private boolean isEmpty(final IFile file) throws CoreException { try { return s.read() < 0; } catch (Exception e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } finally { try { s.close(); diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java index 3ab30f53e3..4307aa6a6e 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java @@ -13,6 +13,7 @@ import java.util.List; +// CHECKSTYLE:CONSTANTS-OFF /** * Provides utility operations for Check model stubs. Only partial models * are returned as strings. @@ -21,45 +22,64 @@ public class CheckModelUtil { /** * Returns a base model stub with package (com.test), catalog (c) and grammar (g). + * + * @return the model stub string */ public String modelWithGrammar() { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("package com.test"); - builder.append("\n"); + builder.append('\n'); builder.append("catalog c for grammar g {"); return builder.toString(); } /** * Returns a base model stub with a default category. + * + * @return the model stub string */ public String modelWithCategory() { String modelWithGrammar = this.modelWithGrammar(); - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("category \"Default Category\" {"); return modelWithGrammar + builder.toString(); } /** * Returns a dummy category with given ID. + * + * @param id + * the category ID + * @param label + * the category label + * @return the category string */ public String emptyCategory(final String id, final String label) { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("category "); builder.append(id); builder.append(" \""); builder.append(label); builder.append("\" {\n"); - builder.append("}"); + builder.append('}'); return builder.toString(); } /** * Returns a base model stub with a severity range. + * + * @param min + * the minimum severity + * @param max + * the maximum severity + * @param severity + * the default severity + * @return the model stub string */ + // CHECKSTYLE:CHECK-OFF VariableDeclarationUsageDistance public String modelWithSeverityRange(final String min, final String max, final String severity) { String modelWithCategory = this.modelWithCategory(); - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("@SeverityRange("); builder.append(min); builder.append(" .. "); @@ -75,10 +95,16 @@ public String modelWithSeverityRange(final String min, final String max, final S /** * Returns a base model stub with a severity range and a default check. + * + * @param min + * the minimum severity + * @param max + * the maximum severity + * @return the model stub string */ public String modelWithSeverityRange(final String min, final String max) { String modelWithCategory = this.modelWithCategory(); - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("@SeverityRange("); builder.append(min); builder.append(" .. "); @@ -89,20 +115,27 @@ public String modelWithSeverityRange(final String min, final String max) { /** * Returns a base model stub with a check of given ID. + * + * @param id + * the check ID + * @return the model stub string */ public String modelWithCheck(final String id) { String modelWithCategory = this.modelWithCategory(); - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("error "); builder.append(id); builder.append(" \"Some Error\" ()\n"); builder.append("message \"My Message\" {"); return modelWithCategory + builder.toString(); } + // CHECKSTYLE:CHECK-ON VariableDeclarationUsageDistance /** * Returns a base model stub with a check (SomeError) with severity 'error' * and message (MyMessage). + * + * @return the model stub string */ public String modelWithCheck() { return this.modelWithCheck("ID"); @@ -110,37 +143,47 @@ public String modelWithCheck() { /** * Returns a dummy check with given ID. + * + * @param id + * the check ID + * @return the check string */ public String emptyCheck(final String id) { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("error "); builder.append(id); builder.append(" \"Some Error\" ()\n"); builder.append("message \"My message\" {\n"); - builder.append("}"); + builder.append('}'); return builder.toString(); } /** * Returns a base model stub with a context using context type ContextType * 'ctx'. + * + * @return the model stub string */ public String modelWithContext() { String modelWithCheck = this.modelWithCheck(); - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("for ContextType ctx {"); return modelWithCheck + builder.toString(); } /** * Returns a base model stub with a give collection of contexts. + * + * @param contexts + * the list of context strings + * @return the model stub string */ public String modelWithContexts(final List contexts) { String modelWithCheck = this.modelWithCheck(); - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); for (final String c : contexts) { - builder.append(c.toString()); - builder.append("\n"); + builder.append(c); + builder.append('\n'); builder.append(" "); } return modelWithCheck + builder.toString(); @@ -148,9 +191,11 @@ public String modelWithContexts(final List contexts) { /** * Returns a complete Check model with multiple SL_ and ML_COMMENTS. + * + * @return the model stub string */ public String modelWithComments() { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("package com.test // SL1\n"); builder.append("/* ML1 */\n"); builder.append("catalog c /* ML2 */ for grammar g {\n"); @@ -167,7 +212,8 @@ public String modelWithComments() { builder.append(" }\n"); builder.append(" }\n"); builder.append(" } // SL7\n"); - builder.append("}"); + builder.append('}'); return builder.toString(); } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.java index 2525de8865..7290a60488 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckTestUtil.java @@ -11,7 +11,6 @@ package com.avaloq.tools.ddk.check.core.test.util; import com.google.common.collect.Lists; -import java.util.ArrayList; import java.util.List; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; @@ -37,7 +36,7 @@ public T getInstanceOf(final EObject context, final Class * Gets the all instances of given type type having given value value on structural feature feature. */ public Iterable getAllInstancesOf(final EObject context, final Class type, final EStructuralFeature feature, final Object value) { - final ArrayList result = Lists.newArrayList(); + final List result = Lists.newArrayList(); for (final T candidate : EcoreUtil2.getAllContentsOfType(context, type)) { Object valueOfFeature = candidate.eGet(feature); if (valueOfFeature != null && valueOfFeature.equals(value)) { diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.java index d80cf6b812..452f2ad293 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/formatting/CheckFormattingTest.java @@ -23,163 +23,165 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +// CHECKSTYLE:CONSTANTS-OFF @InjectWith(CheckUiInjectorProvider.class) @ExtendWith(InjectionExtension.class) public class CheckFormattingTest { @Inject - private FormatterTestHelper _formatterTestHelper; + private FormatterTestHelper formatterTestHelper; /** * Test that correctly formatted Check sources are not modified. */ @Test public void testFormattedSource() { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("package com.avaloq.tools.ddk.check.formatting"); - _builder.newLine(); - _builder.newLine(); - _builder.append("import com.avaloq.tools.ddk.check.check.*"); - _builder.newLine(); - _builder.newLine(); - _builder.append("catalog CheckFormattingTest"); - _builder.newLine(); - _builder.append("for grammar com.avaloq.tools.ddk.check.Check {"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("category \"Label\" {"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); - _builder.newLine(); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.append(" "); - _builder.append("live error UniqueID \"Label\""); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"message\" {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("live error anotherid \"Label\""); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"message {0}, {1}\" {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("def Name"); - _builder.newLine(); - _builder.append(" "); - _builder.append("for Category list {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("issue anotherid on list bind (3, 2) data (\"\")"); - _builder.newLine(); - _builder.append(" "); - _builder.append("val size ="); - _builder.newLine(); - _builder.append(" "); - _builder.append("if (list.checks !== null) list.checks.size else 0"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if (list.checks?.size > 1) {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("// SL: string value of list"); - _builder.newLine(); - _builder.append(" "); - _builder.append("String::valueOf(list)"); - _builder.newLine(); - _builder.append(" "); - _builder.append("issue UniqueID on list#checks[0]"); - _builder.newLine(); - _builder.append(" "); - _builder.append("} else {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("/* ML: string value of size */"); - _builder.newLine(); - _builder.append(" "); - _builder.append("String::valueOf(size)"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@SeverityRange(warning .. error)"); - _builder.newLine(); - _builder.append(" "); - _builder.append("onSave error lastID \"Label\""); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"message\" {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("// single line comment"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* This check is javadoc-like commented."); - _builder.newLine(); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.append(" "); - _builder.append("warning CategoryNamedW \"Category named W\" (boolean foo = false, boolean bar = true)"); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"Category named \'w\'\" {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("for Category c {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("issue"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - final String input = _builder.toString(); + // CHECKSTYLE:CHECK-OFF VariableDeclarationUsageDistance + StringConcatenation builder = new StringConcatenation(); + builder.append("package com.avaloq.tools.ddk.check.formatting"); + builder.newLine(); + builder.newLine(); + builder.append("import com.avaloq.tools.ddk.check.check.*"); + builder.newLine(); + builder.newLine(); + builder.append("catalog CheckFormattingTest"); + builder.newLine(); + builder.append("for grammar com.avaloq.tools.ddk.check.Check {"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("category \"Label\" {"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + builder.newLine(); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.append(" "); + builder.append("live error UniqueID \"Label\""); + builder.newLine(); + builder.append(" "); + builder.append("message \"message\" {"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("live error anotherid \"Label\""); + builder.newLine(); + builder.append(" "); + builder.append("message \"message {0}, {1}\" {"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("def Name"); + builder.newLine(); + builder.append(" "); + builder.append("for Category list {"); + builder.newLine(); + builder.append(" "); + builder.append("issue anotherid on list bind (3, 2) data (\"\")"); + builder.newLine(); + builder.append(" "); + builder.append("val size ="); + builder.newLine(); + builder.append(" "); + builder.append("if (list.checks !== null) list.checks.size else 0"); + builder.newLine(); + builder.append(" "); + builder.append("if (list.checks?.size > 1) {"); + builder.newLine(); + builder.append(" "); + builder.append("// SL: string value of list"); + builder.newLine(); + builder.append(" "); + builder.append("String::valueOf(list)"); + builder.newLine(); + builder.append(" "); + builder.append("issue UniqueID on list#checks[0]"); + builder.newLine(); + builder.append(" "); + builder.append("} else {"); + builder.newLine(); + builder.append(" "); + builder.append("/* ML: string value of size */"); + builder.newLine(); + builder.append(" "); + builder.append("String::valueOf(size)"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@SeverityRange(warning .. error)"); + builder.newLine(); + builder.append(" "); + builder.append("onSave error lastID \"Label\""); + builder.newLine(); + builder.append(" "); + builder.append("message \"message\" {"); + builder.newLine(); + builder.append(" "); + builder.append("// single line comment"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append("* This check is javadoc-like commented."); + builder.newLine(); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.append(" "); + builder.append("warning CategoryNamedW \"Category named W\" (boolean foo = false, boolean bar = true)"); + builder.newLine(); + builder.append(" "); + builder.append("message \"Category named \'w\'\" {"); + builder.newLine(); + builder.append(" "); + builder.append("for Category c {"); + builder.newLine(); + builder.append(" "); + builder.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); + builder.newLine(); + builder.append(" "); + builder.append("issue"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.append("}"); + builder.newLine(); + final String input = builder.toString(); - _formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { + formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { // these preferences are usually picked up from the resource, but we are not using a resource here. MapBasedPreferenceValues prefs = new MapBasedPreferenceValues(); prefs.put(FormatterPreferenceKeys.indentation, " "); @@ -187,6 +189,7 @@ public void testFormattedSource() { it.setToBeFormatted(input); it.setExpectation(input); }); + // CHECKSTYLE:CHECK-ON VariableDeclarationUsageDistance } /** @@ -194,197 +197,198 @@ public void testFormattedSource() { */ @Test public void testWSAdded() { - StringConcatenation _builder = new StringConcatenation(); - _builder.append("package com.avaloq.tools.ddk.check.formatting import com.avaloq.tools.ddk.check.check.* catalog CheckFormattingTest"); - _builder.newLine(); - _builder.append("for grammar com.avaloq.tools.ddk.check.Check{category \"Label\"{/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); - _builder.newLine(); - _builder.append(" "); - _builder.append("*/live error UniqueID \"Label\""); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"message\"{}live error anotherid \"Label\""); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"message {0}, {1}\" {}}"); - _builder.newLine(); - _builder.append(" "); - _builder.append("def Name for Category list{issue anotherid on list bind(3,2)data(\"\")"); - _builder.newLine(); - _builder.append(" "); - _builder.append("val size=if(list.checks !== null)list.checks.size else 0"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if(list.checks?.size>1){"); - _builder.newLine(); - _builder.append(" "); - _builder.append("// SL: string value of list"); - _builder.newLine(); - _builder.append(" "); - _builder.append("String::valueOf(list)issue UniqueID on list#checks[0]}else{/* ML: string value of size */String::valueOf(size)}}"); - _builder.newLine(); - _builder.append(" "); - _builder.append("@SeverityRange(warning..error)onSave error lastID\"Label\"message \"message\" {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("// single line comment"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* This check is javadoc-like commented."); - _builder.newLine(); - _builder.append(" "); - _builder.append("*/warning CategoryNamedW \"Category named W\"(boolean foo=false,boolean bar=true)message \"Category named \'w\'\"{"); - _builder.newLine(); - _builder.append(" "); - _builder.append("for Category c {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("if(\'w\'.equalsIgnoreCase(c.name)){issue}"); - _builder.newLine(); - _builder.append("}}}"); - _builder.newLine(); - final String input = _builder.toString(); + // CHECKSTYLE:CHECK-OFF VariableDeclarationUsageDistance + StringConcatenation builder = new StringConcatenation(); + builder.append("package com.avaloq.tools.ddk.check.formatting import com.avaloq.tools.ddk.check.check.* catalog CheckFormattingTest"); + builder.newLine(); + builder.append("for grammar com.avaloq.tools.ddk.check.Check{category \"Label\"{/**"); + builder.newLine(); + builder.append(" "); + builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + builder.newLine(); + builder.append(" "); + builder.append("*/live error UniqueID \"Label\""); + builder.newLine(); + builder.append(" "); + builder.append("message \"message\"{}live error anotherid \"Label\""); + builder.newLine(); + builder.append(" "); + builder.append("message \"message {0}, {1}\" {}}"); + builder.newLine(); + builder.append(" "); + builder.append("def Name for Category list{issue anotherid on list bind(3,2)data(\"\")"); + builder.newLine(); + builder.append(" "); + builder.append("val size=if(list.checks !== null)list.checks.size else 0"); + builder.newLine(); + builder.append(" "); + builder.append("if(list.checks?.size>1){"); + builder.newLine(); + builder.append(" "); + builder.append("// SL: string value of list"); + builder.newLine(); + builder.append(" "); + builder.append("String::valueOf(list)issue UniqueID on list#checks[0]}else{/* ML: string value of size */String::valueOf(size)}}"); + builder.newLine(); + builder.append(" "); + builder.append("@SeverityRange(warning..error)onSave error lastID\"Label\"message \"message\" {"); + builder.newLine(); + builder.append(" "); + builder.append("// single line comment"); + builder.newLine(); + builder.append(" "); + builder.append("}/**"); + builder.newLine(); + builder.append(" "); + builder.append("* This check is javadoc-like commented."); + builder.newLine(); + builder.append(" "); + builder.append("*/warning CategoryNamedW \"Category named W\"(boolean foo=false,boolean bar=true)message \"Category named \'w\'\"{"); + builder.newLine(); + builder.append(" "); + builder.append("for Category c {"); + builder.newLine(); + builder.append(" "); + builder.append("if(\'w\'.equalsIgnoreCase(c.name)){issue}"); + builder.newLine(); + builder.append("}}}"); + builder.newLine(); + final String input = builder.toString(); - StringConcatenation _builder_1 = new StringConcatenation(); - _builder_1.append("package com.avaloq.tools.ddk.check.formatting"); - _builder_1.newLine(); - _builder_1.append("import com.avaloq.tools.ddk.check.check.*"); - _builder_1.newLine(); - _builder_1.append("catalog CheckFormattingTest"); - _builder_1.newLine(); - _builder_1.append("for grammar com.avaloq.tools.ddk.check.Check {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("category \"Label\" {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("/**"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("*/"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("live error UniqueID \"Label\""); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("message \"message\" {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("live error anotherid \"Label\""); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("message \"message {0}, {1}\" {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("def Name"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("for Category list {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("issue anotherid on list bind (3, 2) data (\"\")"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("val size ="); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("if (list.checks !== null) list.checks.size else 0"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("if (list.checks?.size > 1) {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("// SL: string value of list"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("String::valueOf(list)"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("issue UniqueID on list#checks[0]"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("} else { /* ML: string value of size */"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("String::valueOf(size)"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("@SeverityRange(warning .. error)"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("onSave error lastID \"Label\""); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("message \"message\" {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("// single line comment"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("/**"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("* This check is javadoc-like commented."); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("*/"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("warning CategoryNamedW \"Category named W\" (boolean foo = false, boolean bar = true)"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("message \"Category named \'w\'\" {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("for Category c {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("issue"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append("}"); - _builder_1.newLine(); - final String expected = _builder_1.toString(); + StringConcatenation builder1 = new StringConcatenation(); + builder1.append("package com.avaloq.tools.ddk.check.formatting"); + builder1.newLine(); + builder1.append("import com.avaloq.tools.ddk.check.check.*"); + builder1.newLine(); + builder1.append("catalog CheckFormattingTest"); + builder1.newLine(); + builder1.append("for grammar com.avaloq.tools.ddk.check.Check {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("category \"Label\" {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("/**"); + builder1.newLine(); + builder1.append(" "); + builder1.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + builder1.newLine(); + builder1.append(" "); + builder1.append("*/"); + builder1.newLine(); + builder1.append(" "); + builder1.append("live error UniqueID \"Label\""); + builder1.newLine(); + builder1.append(" "); + builder1.append("message \"message\" {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("live error anotherid \"Label\""); + builder1.newLine(); + builder1.append(" "); + builder1.append("message \"message {0}, {1}\" {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("def Name"); + builder1.newLine(); + builder1.append(" "); + builder1.append("for Category list {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("issue anotherid on list bind (3, 2) data (\"\")"); + builder1.newLine(); + builder1.append(" "); + builder1.append("val size ="); + builder1.newLine(); + builder1.append(" "); + builder1.append("if (list.checks !== null) list.checks.size else 0"); + builder1.newLine(); + builder1.append(" "); + builder1.append("if (list.checks?.size > 1) {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("// SL: string value of list"); + builder1.newLine(); + builder1.append(" "); + builder1.append("String::valueOf(list)"); + builder1.newLine(); + builder1.append(" "); + builder1.append("issue UniqueID on list#checks[0]"); + builder1.newLine(); + builder1.append(" "); + builder1.append("} else { /* ML: string value of size */"); + builder1.newLine(); + builder1.append(" "); + builder1.append("String::valueOf(size)"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("@SeverityRange(warning .. error)"); + builder1.newLine(); + builder1.append(" "); + builder1.append("onSave error lastID \"Label\""); + builder1.newLine(); + builder1.append(" "); + builder1.append("message \"message\" {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("// single line comment"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("/**"); + builder1.newLine(); + builder1.append(" "); + builder1.append("* This check is javadoc-like commented."); + builder1.newLine(); + builder1.append(" "); + builder1.append("*/"); + builder1.newLine(); + builder1.append(" "); + builder1.append("warning CategoryNamedW \"Category named W\" (boolean foo = false, boolean bar = true)"); + builder1.newLine(); + builder1.append(" "); + builder1.append("message \"Category named \'w\'\" {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("for Category c {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("issue"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append("}"); + builder1.newLine(); + final String expected = builder1.toString(); - _formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { + formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { // these preferences are usually picked up from the resource, but we are not using a resource here. MapBasedPreferenceValues prefs = new MapBasedPreferenceValues(); prefs.put(FormatterPreferenceKeys.indentation, " "); @@ -392,6 +396,7 @@ public void testWSAdded() { it.setToBeFormatted(input); it.setExpectation(expected); }); + // CHECKSTYLE:CHECK-ON VariableDeclarationUsageDistance } /** @@ -399,691 +404,692 @@ public void testWSAdded() { */ @Test public void testWSRemoved() { - StringConcatenation _builder = new StringConcatenation(); - _builder.append(" "); - _builder.append("package"); - _builder.newLine(); - _builder.append(" "); - _builder.append("com.avaloq.tools.ddk.check.formatting"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append("import"); - _builder.newLine(); - _builder.append(" "); - _builder.append("com.avaloq.tools.ddk.check.check.*"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append("catalog"); - _builder.newLine(); - _builder.append(" "); - _builder.append("CheckFormattingTest"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append("for"); - _builder.newLine(); - _builder.append(" "); - _builder.append("grammar"); - _builder.newLine(); - _builder.append(" "); - _builder.append("com.avaloq.tools.ddk.check.Check"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("category"); - _builder.newLine(); - _builder.append(" "); - _builder.append("\"Label\""); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); - _builder.newLine(); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("live"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("error"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("UniqueID"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("\"Label\""); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("message"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("\"message\""); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("live error anotherid \"Label\""); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"message {0}, {1}\" {"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("def"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("Name"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("for"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("Category"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("list"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("issue"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("anotherid"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("on"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("list"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("bind"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("3"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(","); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("2"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("data"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("\"\""); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("val"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("size"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("="); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("if"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("list"); - _builder.newLine(); - _builder.append(" "); - _builder.append("."); - _builder.newLine(); - _builder.append(" "); - _builder.append("checks"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("!=="); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("null"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("list . checks . size"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("else"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("0"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("if"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("list.checks ?. size"); - _builder.newLine(); - _builder.append(" "); - _builder.append("> 1)"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("// SL: string value of list"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("String"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("::"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("valueOf"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("list"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("issue UniqueID on list # checks"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("["); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("0"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("]"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("else"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("{"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("/* ML: string value of size */"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("String :: valueOf ( size )"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("@"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("SeverityRange"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("warning"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(".."); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("error"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("onSave error lastID \"Label\""); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"message\" {"); - _builder.newLine(); - _builder.append(" "); - _builder.append("// single line comment"); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("/**"); - _builder.newLine(); - _builder.append(" "); - _builder.append("* This check is javadoc-like commented."); - _builder.newLine(); - _builder.append(" "); - _builder.append("*/"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("warning CategoryNamedW \"Category named W\""); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("("); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("boolean"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("foo"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("="); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("false"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(","); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("boolean"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("bar"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("="); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("true"); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append(")"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("message \"Category named \'w\'\" {"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("for Category c {"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("issue"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append(" "); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - _builder.append("}"); - _builder.newLine(); - _builder.newLine(); - _builder.newLine(); - final String input = _builder.toString(); + // CHECKSTYLE:CHECK-OFF VariableDeclarationUsageDistance + StringConcatenation builder = new StringConcatenation(); + builder.append(" "); + builder.append("package"); + builder.newLine(); + builder.append(" "); + builder.append("com.avaloq.tools.ddk.check.formatting"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append("import"); + builder.newLine(); + builder.append(" "); + builder.append("com.avaloq.tools.ddk.check.check.*"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append("catalog"); + builder.newLine(); + builder.append(" "); + builder.append("CheckFormattingTest"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append("for"); + builder.newLine(); + builder.append(" "); + builder.append("grammar"); + builder.newLine(); + builder.append(" "); + builder.append("com.avaloq.tools.ddk.check.Check"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("{"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("category"); + builder.newLine(); + builder.append(" "); + builder.append("\"Label\""); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("{"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + builder.newLine(); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("live"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("error"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("UniqueID"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("\"Label\""); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("message"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("\"message\""); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("{"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("live error anotherid \"Label\""); + builder.newLine(); + builder.append(" "); + builder.append("message \"message {0}, {1}\" {"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("def"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("Name"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("for"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("Category"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("list"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("{"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("issue"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("anotherid"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("on"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("list"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("bind"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("("); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("3"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(","); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("2"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(")"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("data"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("("); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("\"\""); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(")"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("val"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("size"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("="); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("if"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("("); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("list"); + builder.newLine(); + builder.append(" "); + builder.append("."); + builder.newLine(); + builder.append(" "); + builder.append("checks"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("!=="); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("null"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(")"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("list . checks . size"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("else"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("0"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("if"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("("); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("list.checks ?. size"); + builder.newLine(); + builder.append(" "); + builder.append("> 1)"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("{"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("// SL: string value of list"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("String"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("::"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("valueOf"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("("); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("list"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(")"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("issue UniqueID on list # checks"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("["); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("0"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("]"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("else"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("{"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("/* ML: string value of size */"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("String :: valueOf ( size )"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("@"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("SeverityRange"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("("); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("warning"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(".."); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("error"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(")"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("onSave error lastID \"Label\""); + builder.newLine(); + builder.append(" "); + builder.append("message \"message\" {"); + builder.newLine(); + builder.append(" "); + builder.append("// single line comment"); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("/**"); + builder.newLine(); + builder.append(" "); + builder.append("* This check is javadoc-like commented."); + builder.newLine(); + builder.append(" "); + builder.append("*/"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("warning CategoryNamedW \"Category named W\""); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("("); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("boolean"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("foo"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("="); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("false"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(","); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("boolean"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("bar"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("="); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("true"); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append(")"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("message \"Category named \'w\'\" {"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("for Category c {"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("issue"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append(" "); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + builder.append("}"); + builder.newLine(); + builder.newLine(); + builder.newLine(); + final String input = builder.toString(); - StringConcatenation _builder_1 = new StringConcatenation(); - _builder_1.append("package com.avaloq.tools.ddk.check.formatting"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append("import com.avaloq.tools.ddk.check.check.*"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append("catalog CheckFormattingTest"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append("for grammar com.avaloq.tools.ddk.check.Check {"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("category \"Label\" {"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("/**"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("*/"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("live error UniqueID \"Label\""); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("message \"message\" {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("live error anotherid \"Label\""); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("message \"message {0}, {1}\" {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("def Name"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("for Category list {"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("issue anotherid on list bind (3, 2) data (\"\")"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("val size ="); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("if (list.checks !== null) list.checks.size else 0"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("if (list.checks?.size > 1) {"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("// SL: string value of list"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("String::valueOf("); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("list"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append(")"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("issue UniqueID on list#checks[0]"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("} else {"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("/* ML: string value of size */"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("String::valueOf(size)"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("@SeverityRange(warning .. error)"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("onSave error lastID \"Label\""); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("message \"message\" {"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("// single line comment"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("/**"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("* This check is javadoc-like commented."); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("*/"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("warning CategoryNamedW \"Category named W\" (boolean foo = false,"); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("boolean bar = true)"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("message \"Category named \'w\'\" {"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("for Category c {"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("issue"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.newLine(); - _builder_1.append(" "); - _builder_1.append("}"); - _builder_1.newLine(); - _builder_1.append("}"); - _builder_1.newLine(); - final String expected = _builder_1.toString(); + StringConcatenation builder1 = new StringConcatenation(); + builder1.append("package com.avaloq.tools.ddk.check.formatting"); + builder1.newLine(); + builder1.newLine(); + builder1.append("import com.avaloq.tools.ddk.check.check.*"); + builder1.newLine(); + builder1.newLine(); + builder1.append("catalog CheckFormattingTest"); + builder1.newLine(); + builder1.newLine(); + builder1.append("for grammar com.avaloq.tools.ddk.check.Check {"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("category \"Label\" {"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("/**"); + builder1.newLine(); + builder1.append(" "); + builder1.append("* @todo Document check. 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + builder1.newLine(); + builder1.append(" "); + builder1.append("*/"); + builder1.newLine(); + builder1.append(" "); + builder1.append("live error UniqueID \"Label\""); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("message \"message\" {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("live error anotherid \"Label\""); + builder1.newLine(); + builder1.append(" "); + builder1.append("message \"message {0}, {1}\" {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("def Name"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("for Category list {"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("issue anotherid on list bind (3, 2) data (\"\")"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("val size ="); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("if (list.checks !== null) list.checks.size else 0"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("if (list.checks?.size > 1) {"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("// SL: string value of list"); + builder1.newLine(); + builder1.append(" "); + builder1.append("String::valueOf("); + builder1.newLine(); + builder1.append(" "); + builder1.append("list"); + builder1.newLine(); + builder1.append(" "); + builder1.append(")"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("issue UniqueID on list#checks[0]"); + builder1.newLine(); + builder1.append(" "); + builder1.append("} else {"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("/* ML: string value of size */"); + builder1.newLine(); + builder1.append(" "); + builder1.append("String::valueOf(size)"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("@SeverityRange(warning .. error)"); + builder1.newLine(); + builder1.append(" "); + builder1.append("onSave error lastID \"Label\""); + builder1.newLine(); + builder1.append(" "); + builder1.append("message \"message\" {"); + builder1.newLine(); + builder1.append(" "); + builder1.append("// single line comment"); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("/**"); + builder1.newLine(); + builder1.append(" "); + builder1.append("* This check is javadoc-like commented."); + builder1.newLine(); + builder1.append(" "); + builder1.append("*/"); + builder1.newLine(); + builder1.append(" "); + builder1.append("warning CategoryNamedW \"Category named W\" (boolean foo = false,"); + builder1.newLine(); + builder1.append(" "); + builder1.append("boolean bar = true)"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("message \"Category named \'w\'\" {"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("for Category c {"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("if (\'w\'.equalsIgnoreCase(c.name)) {"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("issue"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.newLine(); + builder1.append(" "); + builder1.append("}"); + builder1.newLine(); + builder1.append("}"); + builder1.newLine(); + final String expected = builder1.toString(); - _formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { + formatterTestHelper.assertFormatted((FormatterTestRequest it) -> { // these preferences are usually picked up from the resource, but we are not using a resource here. MapBasedPreferenceValues prefs = new MapBasedPreferenceValues(); prefs.put(FormatterPreferenceKeys.indentation, " "); @@ -1091,5 +1097,7 @@ public void testWSRemoved() { it.setToBeFormatted(input); it.setExpectation(expected); }); + // CHECKSTYLE:CHECK-ON VariableDeclarationUsageDistance } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java index c7b4cc7e35..988c09965e 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java @@ -31,6 +31,7 @@ public class CheckApiAccessValidationsTest { @Inject private ValidationTestHelper helper; + @SuppressWarnings("PMD.SignatureDeclareThrowsException") private CheckCatalog getTestSource(final String importText) throws Exception { return parser.parse( "package com.avaloq.example.stuff.checks\n" diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.java index d0b3caef93..7760493162 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckValidationTest.java @@ -17,7 +17,7 @@ import com.google.common.collect.Lists; import com.google.inject.Inject; -import java.util.ArrayList; +import java.util.List; import org.eclipse.xtext.testing.InjectWith; import org.eclipse.xtext.testing.extensions.InjectionExtension; @@ -35,6 +35,7 @@ *

  • com.avaloq.tools.ddk.check.validation.ClasspathBasedChecks * */ +// CHECKSTYLE:CONSTANTS-OFF @InjectWith(CheckUiInjectorProvider.class) @ExtendWith(InjectionExtension.class) @SuppressWarnings("nls") @@ -103,7 +104,7 @@ public void testPackageNameIsInvalid() throws Exception { @Disabled("Tests do not work because of scoping issues at run-time") public void testContextTypeIsUnique() throws Exception { // should fail - ArrayList contexts = Lists.newArrayList("for C c {issue}", "for C d {issue}"); + List contexts = Lists.newArrayList("for C c {issue}", "for C d {issue}"); CheckCatalog model = parser.parse(modelUtil.modelWithContexts(contexts)); helper.assertError(model, CheckPackage.Literals.CONTEXT, IssueCodes.CONTEXT_TYPES_NOT_UNIQUE); @@ -331,3 +332,4 @@ public void testDefaultSeverityInRange_5() throws Exception { } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.java index a82f81c2a0..56dd771bc8 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/compiler/CheckGeneratorConfig.java @@ -14,15 +14,15 @@ public class CheckGeneratorConfig extends GeneratorConfig { - private final String GENERATE_DOCUMENTATION_PROPERTY = "com.avaloq.tools.ddk.check.GenerateDocumentationForAllChecks"; + private static final String GENERATE_DOCUMENTATION_PROPERTY = "com.avaloq.tools.ddk.check.GenerateDocumentationForAllChecks"; - private boolean generateLanguageInternalChecks = false; + private boolean generateLanguageInternalChecks; public boolean isGenerateLanguageInternalChecks() { return generateLanguageInternalChecks; } - public void setGenerateLanguageInternalChecks(boolean generateLanguageInternalChecks) { + public void setGenerateLanguageInternalChecks(final boolean generateLanguageInternalChecks) { this.generateLanguageInternalChecks = generateLanguageInternalChecks; } diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.java index 8edcaa6d70..78d93cf5f9 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/formatting2/CheckFormatter.java @@ -71,10 +71,11 @@ import org.eclipse.xtext.xtype.XImportDeclaration; import org.eclipse.xtext.xtype.XImportSection; +@SuppressWarnings({"checkstyle:MethodName"}) public class CheckFormatter extends XbaseWithAnnotationsFormatter { @Inject - private CheckGrammarAccess _checkGrammarAccess; + private CheckGrammarAccess checkGrammarAccess; /** * Common formatting for curly brackets that are not handled by the parent formatter. @@ -84,7 +85,8 @@ public class CheckFormatter extends XbaseWithAnnotationsFormatter { * @param document * the formattable document. */ - private void formatCurlyBracket(EObject semanticElement, IFormattableDocument document) { + // CHECKSTYLE:CHECK-OFF MagicNumber + private void formatCurlyBracket(final EObject semanticElement, final IFormattableDocument document) { // low priority so that it can be overridden by other custom formatting rules. final ISemanticRegion open = regionFor(semanticElement).keyword("{"); final ISemanticRegion close = regionFor(semanticElement).keyword("}"); @@ -110,7 +112,7 @@ private void formatCurlyBracket(EObject semanticElement, IFormattableDocument do * @param document * the formattable document. */ - private void globalFormatting(IEObjectRegion requestRoot, IFormattableDocument document) { + private void globalFormatting(final IEObjectRegion requestRoot, final IFormattableDocument document) { // autowrap everywhere. default to one-space between semantic regions. // low priority so that it can be overridden by other custom formatting rules. boolean firstRegion = true; @@ -130,8 +132,9 @@ private void globalFormatting(IEObjectRegion requestRoot, IFormattableDocument d } } } + // CHECKSTYLE:CHECK-ON MagicNumber - protected void _format(CheckCatalog checkcatalog, IFormattableDocument document) { + protected void _format(final CheckCatalog checkcatalog, final IFormattableDocument document) { document.prepend(checkcatalog, (IHiddenRegionFormatter it) -> { it.noSpace(); it.setNewLines(0); @@ -180,7 +183,7 @@ protected void _format(CheckCatalog checkcatalog, IFormattableDocument document) } @Override - protected void _format(XImportSection ximportsection, IFormattableDocument document) { + protected void _format(final XImportSection ximportsection, final IFormattableDocument document) { // Generated model traversal for (XImportDeclaration importDeclarations : ximportsection.getImportDeclarations()) { // ADDED: formatting added before each import @@ -192,7 +195,7 @@ protected void _format(XImportSection ximportsection, IFormattableDocument docum } } - protected void _format(Category category, IFormattableDocument document) { + protected void _format(final Category category, final IFormattableDocument document) { document.prepend(category, (IHiddenRegionFormatter it) -> { it.setNewLines(1, 2, 2); }); @@ -204,7 +207,7 @@ protected void _format(Category category, IFormattableDocument document) { } } - protected void _format(Check check, IFormattableDocument document) { + protected void _format(final Check check, final IFormattableDocument document) { document.prepend(check, (IHiddenRegionFormatter it) -> { it.setNewLines(1, 2, 2); }); @@ -242,7 +245,7 @@ protected void _format(Check check, IFormattableDocument document) { } } - protected void _format(SeverityRange severityrange, IFormattableDocument document) { + protected void _format(final SeverityRange severityrange, final IFormattableDocument document) { final ISemanticRegion range = regionFor(severityrange).keyword("SeverityRange"); document.surround(range, (IHiddenRegionFormatter it) -> { it.noSpace(); @@ -260,7 +263,7 @@ protected void _format(SeverityRange severityrange, IFormattableDocument documen }); } - protected void _format(Member member, IFormattableDocument document) { + protected void _format(final Member member, final IFormattableDocument document) { // Generated model traversal for (XAnnotation annotations : member.getAnnotations()) { this.format(annotations, document); @@ -269,7 +272,7 @@ protected void _format(Member member, IFormattableDocument document) { this.format(member.getValue(), document); } - protected void _format(Implementation implementation, IFormattableDocument document) { + protected void _format(final Implementation implementation, final IFormattableDocument document) { document.prepend(implementation, (IHiddenRegionFormatter it) -> { it.setNewLines(1, 2, 2); }); @@ -278,25 +281,25 @@ protected void _format(Implementation implementation, IFormattableDocument docum this.format(implementation.getContext(), document); } - protected void _format(FormalParameter formalparameter, IFormattableDocument document) { + protected void _format(final FormalParameter formalparameter, final IFormattableDocument document) { // Generated model traversal this.format(formalparameter.getType(), document); this.format(formalparameter.getRight(), document); } - protected void _format(XUnaryOperation xunaryoperation, IFormattableDocument document) { + protected void _format(final XUnaryOperation xunaryoperation, final IFormattableDocument document) { // Generated model traversal this.format(xunaryoperation.getOperand(), document); } - protected void _format(XListLiteral xlistliteral, IFormattableDocument document) { + protected void _format(final XListLiteral xlistliteral, final IFormattableDocument document) { // Generated model traversal for (XExpression elements : xlistliteral.getElements()) { this.format(elements, document); } } - protected void _format(Context context, IFormattableDocument document) { + protected void _format(final Context context, final IFormattableDocument document) { document.surround(context, (IHiddenRegionFormatter it) -> { it.setNewLines(1, 2, 2); }); @@ -306,12 +309,12 @@ protected void _format(Context context, IFormattableDocument document) { this.format(context.getConstraint(), document); } - protected void _format(ContextVariable contextvariable, IFormattableDocument document) { + protected void _format(final ContextVariable contextvariable, final IFormattableDocument document) { // Generated model traversal this.format(contextvariable.getType(), document); } - protected void _format(XGuardExpression xguardexpression, IFormattableDocument document) { + protected void _format(final XGuardExpression xguardexpression, final IFormattableDocument document) { document.prepend(xguardexpression, (IHiddenRegionFormatter it) -> { it.setNewLines(1, 2, 2); }); @@ -320,13 +323,13 @@ protected void _format(XGuardExpression xguardexpression, IFormattableDocument d this.format(xguardexpression.getGuard(), document); } - protected void _format(XIssueExpression xissueexpression, IFormattableDocument document) { + protected void _format(final XIssueExpression xissueexpression, final IFormattableDocument document) { // High priority to override formatting from adjacent regions and parent formatter. document.prepend(xissueexpression, (IHiddenRegionFormatter it) -> { it.highPriority(); it.setNewLines(1, 2, 2); }); - _checkGrammarAccess.getXIssueExpressionAccess().findKeywords("#").forEach((Keyword kw) -> { + checkGrammarAccess.getXIssueExpressionAccess().findKeywords("#").forEach((Keyword kw) -> { final ISemanticRegion hash = regionFor(xissueexpression).keyword(kw); document.surround(hash, (IHiddenRegionFormatter it) -> { it.highPriority(); @@ -343,14 +346,14 @@ protected void _format(XIssueExpression xissueexpression, IFormattableDocument d it.highPriority(); it.noSpace(); }); - _checkGrammarAccess.getXIssueExpressionAccess().findKeywords("(").forEach((Keyword kw) -> { + checkGrammarAccess.getXIssueExpressionAccess().findKeywords("(").forEach((Keyword kw) -> { final ISemanticRegion open = regionFor(xissueexpression).keyword(kw); document.append(open, (IHiddenRegionFormatter it) -> { it.highPriority(); it.noSpace(); }); }); - _checkGrammarAccess.getXIssueExpressionAccess().findKeywords(")").forEach((Keyword kw) -> { + checkGrammarAccess.getXIssueExpressionAccess().findKeywords(")").forEach((Keyword kw) -> { final ISemanticRegion close = regionFor(xissueexpression).keyword(kw); document.prepend(close, (IHiddenRegionFormatter it) -> { it.highPriority(); @@ -393,7 +396,7 @@ protected void _format(XIssueExpression xissueexpression, IFormattableDocument d } @Override - protected void _format(XIfExpression xifexpression, IFormattableDocument document) { + protected void _format(final XIfExpression xifexpression, final IFormattableDocument document) { // High priority to override formatting from adjacent regions and parent formatter. document.prepend(xifexpression, (IHiddenRegionFormatter it) -> { it.highPriority(); @@ -430,24 +433,24 @@ protected void _format(XIfExpression xifexpression, IFormattableDocument documen } @Override - protected void _format(XMemberFeatureCall xfeaturecall, IFormattableDocument document) { + protected void _format(final XMemberFeatureCall xfeaturecall, final IFormattableDocument document) { // set no space after '::' in CheckUtil::hasQualifiedName(..., and also not after plain "." or "?." // High priority to override formatting from adjacent regions and parent formatter. - _checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords(".").forEach((Keyword kw) -> { + checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords(".").forEach((Keyword kw) -> { final ISemanticRegion dot = regionFor(xfeaturecall).keyword(kw); document.append(dot, (IHiddenRegionFormatter it) -> { it.highPriority(); it.noSpace(); }); }); - _checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords("?.").forEach((Keyword kw) -> { + checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords("?.").forEach((Keyword kw) -> { final ISemanticRegion queryDot = regionFor(xfeaturecall).keyword(kw); document.append(queryDot, (IHiddenRegionFormatter it) -> { it.highPriority(); it.noSpace(); }); }); - _checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords("::").forEach((Keyword kw) -> { + checkGrammarAccess.getXMemberFeatureCallAccess().findKeywords("::").forEach((Keyword kw) -> { final ISemanticRegion colonColon = regionFor(xfeaturecall).keyword(kw); document.append(colonColon, (IHiddenRegionFormatter it) -> { it.highPriority(); @@ -461,160 +464,109 @@ protected void _format(XMemberFeatureCall xfeaturecall, IFormattableDocument doc @Override @XbaseGenerated - public void format(Object xlistliteral, IFormattableDocument document) { + public void format(final Object xlistliteral, final IFormattableDocument document) { if (xlistliteral instanceof JvmTypeParameter) { _format((JvmTypeParameter) xlistliteral, document); - return; } else if (xlistliteral instanceof JvmFormalParameter) { _format((JvmFormalParameter) xlistliteral, document); - return; } else if (xlistliteral instanceof XtextResource) { _format((XtextResource) xlistliteral, document); - return; } else if (xlistliteral instanceof XAssignment) { _format((XAssignment) xlistliteral, document); - return; } else if (xlistliteral instanceof XBinaryOperation) { _format((XBinaryOperation) xlistliteral, document); - return; } else if (xlistliteral instanceof XDoWhileExpression) { _format((XDoWhileExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XFeatureCall) { _format((XFeatureCall) xlistliteral, document); - return; } else if (xlistliteral instanceof XListLiteral) { _format((XListLiteral) xlistliteral, document); - return; } else if (xlistliteral instanceof XMemberFeatureCall) { _format((XMemberFeatureCall) xlistliteral, document); - return; } else if (xlistliteral instanceof XPostfixOperation) { _format((XPostfixOperation) xlistliteral, document); - return; } else if (xlistliteral instanceof XUnaryOperation) { _format((XUnaryOperation) xlistliteral, document); - return; } else if (xlistliteral instanceof XWhileExpression) { _format((XWhileExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XFunctionTypeRef) { _format((XFunctionTypeRef) xlistliteral, document); - return; } else if (xlistliteral instanceof Category) { _format((Category) xlistliteral, document); - return; } else if (xlistliteral instanceof Check) { _format((Check) xlistliteral, document); - return; } else if (xlistliteral instanceof CheckCatalog) { _format((CheckCatalog) xlistliteral, document); - return; } else if (xlistliteral instanceof Context) { _format((Context) xlistliteral, document); - return; } else if (xlistliteral instanceof Implementation) { _format((Implementation) xlistliteral, document); - return; } else if (xlistliteral instanceof Member) { _format((Member) xlistliteral, document); - return; } else if (xlistliteral instanceof XGuardExpression) { _format((XGuardExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XIssueExpression) { _format((XIssueExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof JvmGenericArrayTypeReference) { _format((JvmGenericArrayTypeReference) xlistliteral, document); - return; } else if (xlistliteral instanceof JvmParameterizedTypeReference) { _format((JvmParameterizedTypeReference) xlistliteral, document); - return; } else if (xlistliteral instanceof JvmWildcardTypeReference) { _format((JvmWildcardTypeReference) xlistliteral, document); - return; } else if (xlistliteral instanceof XBasicForLoopExpression) { _format((XBasicForLoopExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XBlockExpression) { _format((XBlockExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XCastedExpression) { _format((XCastedExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XClosure) { _format((XClosure) xlistliteral, document); - return; } else if (xlistliteral instanceof XCollectionLiteral) { _format((XCollectionLiteral) xlistliteral, document); - return; } else if (xlistliteral instanceof XConstructorCall) { _format((XConstructorCall) xlistliteral, document); - return; } else if (xlistliteral instanceof XForLoopExpression) { _format((XForLoopExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XIfExpression) { _format((XIfExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XInstanceOfExpression) { _format((XInstanceOfExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XReturnExpression) { _format((XReturnExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XSwitchExpression) { _format((XSwitchExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XSynchronizedExpression) { _format((XSynchronizedExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XThrowExpression) { _format((XThrowExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XTryCatchFinallyExpression) { _format((XTryCatchFinallyExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XTypeLiteral) { _format((XTypeLiteral) xlistliteral, document); - return; } else if (xlistliteral instanceof XVariableDeclaration) { _format((XVariableDeclaration) xlistliteral, document); - return; } else if (xlistliteral instanceof XAnnotation) { _format((XAnnotation) xlistliteral, document); - return; } else if (xlistliteral instanceof ContextVariable) { _format((ContextVariable) xlistliteral, document); - return; } else if (xlistliteral instanceof FormalParameter) { _format((FormalParameter) xlistliteral, document); - return; } else if (xlistliteral instanceof SeverityRange) { _format((SeverityRange) xlistliteral, document); - return; } else if (xlistliteral instanceof JvmTypeConstraint) { _format((JvmTypeConstraint) xlistliteral, document); - return; } else if (xlistliteral instanceof XExpression) { _format((XExpression) xlistliteral, document); - return; } else if (xlistliteral instanceof XImportDeclaration) { _format((XImportDeclaration) xlistliteral, document); - return; } else if (xlistliteral instanceof XImportSection) { _format((XImportSection) xlistliteral, document); - return; } else if (xlistliteral instanceof EObject) { _format((EObject) xlistliteral, document); - return; } else if (xlistliteral == null) { _format((Void) null, document); - return; } else if (xlistliteral != null) { _format(xlistliteral, document); - return; } else { throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(xlistliteral, document).toString()); diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java index ff0ebe09eb..d963e2b268 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java @@ -40,13 +40,14 @@ import org.eclipse.xtext.xbase.lib.IteratorExtensions; import org.eclipse.xtext.xbase.lib.StringExtensions; +@SuppressWarnings({"checkstyle:MethodName"}) public class CheckGenerator extends JvmModelGenerator { @Inject private CheckGeneratorExtensions generatorExtensions; @Inject - private CheckGeneratorNaming _checkGeneratorNaming; + private CheckGeneratorNaming checkGeneratorNaming; @Inject private CheckCompiler compiler; @@ -55,7 +56,7 @@ public class CheckGenerator extends JvmModelGenerator { private ICheckGeneratorConfigProvider generatorConfigProvider; @Override - public void doGenerate(Resource resource, IFileSystemAccess fsa) { + public void doGenerate(final Resource resource, final IFileSystemAccess fsa) { super.doGenerate(resource, fsa); // Generate validator, catalog, and preference initializer from inferred Jvm models. URI uri = null; if (resource != null) { @@ -64,8 +65,8 @@ public void doGenerate(Resource resource, IFileSystemAccess fsa) { final CheckGeneratorConfig config = generatorConfigProvider.get(uri); Iterable catalogs = Iterables.filter(IteratorExtensions.toIterable(resource.getAllContents()), CheckCatalog.class); for (CheckCatalog catalog : catalogs) { - fsa.generateFile(_checkGeneratorNaming.issueCodesFilePath(catalog), compileIssueCodes(catalog)); - fsa.generateFile(_checkGeneratorNaming.standaloneSetupPath(catalog), compileStandaloneSetup(catalog)); + fsa.generateFile(checkGeneratorNaming.issueCodesFilePath(catalog), compileIssueCodes(catalog)); + fsa.generateFile(checkGeneratorNaming.standaloneSetupPath(catalog), compileStandaloneSetup(catalog)); // change output path for service registry fsa.generateFile( @@ -75,15 +76,16 @@ public void doGenerate(Resource resource, IFileSystemAccess fsa) { // generate documentation for SCA-checks only if (config != null && (config.doGenerateDocumentationForAllChecks() || !config.isGenerateLanguageInternalChecks())) { // change output path for html files to docs/ - fsa.generateFile(_checkGeneratorNaming.docFileName(catalog), CheckGeneratorConstants.CHECK_DOC_OUTPUT, compileDoc(catalog)); + fsa.generateFile(checkGeneratorNaming.docFileName(catalog), CheckGeneratorConstants.CHECK_DOC_OUTPUT, compileDoc(catalog)); } } } + // CHECKSTYLE:CONSTANTS-OFF /* Documentation compiler, generates HTML output. */ - public CharSequence compileDoc(CheckCatalog catalog) { + public CharSequence compileDoc(final CheckCatalog catalog) { final CharSequence body = bodyDoc(catalog); - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(512); sb.append("\n"); sb.append("\n"); sb.append("\n"); @@ -91,51 +93,51 @@ public CharSequence compileDoc(CheckCatalog catalog) { sb.append(" \n"); sb.append(" ").append(catalog.getName()).append("\n"); sb.append("\n"); - sb.append("\n"); + sb.append('\n'); sb.append("\n"); sb.append("

    Check Catalog ").append(catalog.getName()).append("

    \n"); final String formattedDescription = generatorExtensions.formatDescription(catalog.getDescription()); if (formattedDescription != null) { sb.append("

    ").append(formattedDescription).append("

    \n"); } - sb.append(" ").append(body).append("\n"); + sb.append(" ").append(body).append('\n'); sb.append("\n"); - sb.append("\n"); + sb.append('\n'); sb.append("\n"); return sb; } - public CharSequence bodyDoc(CheckCatalog catalog) { - final StringBuilder sb = new StringBuilder(); + public CharSequence bodyDoc(final CheckCatalog catalog) { + final StringBuilder sb = new StringBuilder(512); for (Check check : catalog.getChecks()) { - sb.append("

    ").append(check.getLabel()) .append(" (").append(check.getDefaultSeverity().name().toLowerCase()) .append(")

    \n"); final String formattedCheckDescription = generatorExtensions.formatDescription(check.getDescription()); if (formattedCheckDescription != null) { - sb.append(formattedCheckDescription).append("\n"); + sb.append(formattedCheckDescription).append('\n'); } sb.append("

    Message: ").append(generatorExtensions.replacePlaceholder(check.getMessage())) .append("


    \n"); } for (Category category : catalog.getCategories()) { sb.append("
    \n"); - sb.append("

    ").append(category.getLabel()).append("

    \n"); final String formattedCategoryDescription = generatorExtensions.formatDescription(category.getDescription()); if (formattedCategoryDescription != null) { - sb.append(" ").append(formattedCategoryDescription).append("\n"); + sb.append(" ").append(formattedCategoryDescription).append('\n'); } for (Check check : category.getChecks()) { - sb.append("
    \n"); sb.append("

    ").append(check.getLabel()) .append(" (").append(check.getDefaultSeverity().name().toLowerCase()) .append(")

    \n"); final String formattedCheckDescription = generatorExtensions.formatDescription(check.getDescription()); if (formattedCheckDescription != null) { - sb.append(" ").append(formattedCheckDescription).append("\n"); + sb.append(" ").append(formattedCheckDescription).append('\n'); } sb.append("

    Message: ").append(generatorExtensions.replacePlaceholder(check.getMessage())) .append("

    \n"); @@ -150,7 +152,7 @@ public CharSequence bodyDoc(CheckCatalog catalog) { * Creates an IssueCodes file for a Check Catalog. Every Check Catalog will have its own file * of issue codes. */ - public CharSequence compileIssueCodes(CheckCatalog catalog) { + public CharSequence compileIssueCodes(final CheckCatalog catalog) { final Iterable allIssues = generatorExtensions.checkAndImplementationIssues(catalog); final Function1 keyFunction = (XIssueExpression issue) -> { return CheckGeneratorExtensions.issueCode(issue); @@ -159,24 +161,24 @@ public CharSequence compileIssueCodes(CheckCatalog catalog) { return CheckGeneratorExtensions.issueName(issue); }; final Map allIssueNames = IterableExtensions.toMap(allIssues, keyFunction, valueFunction); - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(512); if (!StringExtensions.isNullOrEmpty(catalog.getPackageName())) { sb.append("package ").append(catalog.getPackageName()).append(";\n"); } - sb.append("\n"); + sb.append('\n'); sb.append("/**\n"); sb.append(" * Issue codes which may be used to address validation issues (for instance in quickfixes).\n"); sb.append(" */\n"); sb.append("@SuppressWarnings(\"all\")\n"); sb.append("public final class ").append(CheckGeneratorNaming.issueCodesClassName(catalog)).append(" {\n"); - sb.append("\n"); + sb.append('\n'); final List sortedKeys = IterableExtensions.sort(allIssueNames.keySet()); for (String issueCode : sortedKeys) { sb.append(" public static final String ").append(issueCode) .append(" = \"").append(CheckGeneratorExtensions.issueCodeValue(catalog, allIssueNames.get(issueCode))) .append("\";\n"); } - sb.append("\n"); + sb.append('\n'); sb.append(" private ").append(CheckGeneratorNaming.issueCodesClassName(catalog)).append("() {\n"); sb.append(" // Prevent instantiation.\n"); sb.append(" }\n"); @@ -187,55 +189,55 @@ public CharSequence compileIssueCodes(CheckCatalog catalog) { /* * Generates the Java standalone setup class which will be called by the ServiceRegistry. */ - public CharSequence compileStandaloneSetup(CheckCatalog catalog) { - final StringBuilder sb = new StringBuilder(); + public CharSequence compileStandaloneSetup(final CheckCatalog catalog) { + final StringBuilder sb = new StringBuilder(2048); if (!StringExtensions.isNullOrEmpty(catalog.getPackageName())) { sb.append("package ").append(catalog.getPackageName()).append(";\n"); } - sb.append("\n"); + sb.append('\n'); sb.append("import org.apache.logging.log4j.Logger;\n"); sb.append("import org.apache.logging.log4j.LogManager;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("import com.avaloq.tools.ddk.check.runtime.configuration.ModelLocation;\n"); sb.append("import com.avaloq.tools.ddk.check.runtime.registry.ICheckCatalogRegistry;\n"); sb.append("import com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorRegistry;\n"); sb.append("import com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorStandaloneSetup;\n"); - sb.append("\n"); + sb.append('\n'); sb.append("/**\n"); sb.append(" * Standalone setup for ").append(catalog.getName()).append(" as required by the standalone builder.\n"); sb.append(" */\n"); sb.append("@SuppressWarnings(\"nls\")\n"); - sb.append("public class ").append(_checkGeneratorNaming.standaloneSetupClassName(catalog)) + sb.append("public class ").append(checkGeneratorNaming.standaloneSetupClassName(catalog)) .append(" implements ICheckValidatorStandaloneSetup {\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" private static final Logger LOG = LogManager.getLogger(") - .append(_checkGeneratorNaming.standaloneSetupClassName(catalog)).append(".class);\n"); + .append(checkGeneratorNaming.standaloneSetupClassName(catalog)).append(".class);\n"); final Grammar grammar = catalog.getGrammar(); if (grammar != null) { sb.append(" private static final String GRAMMAR_NAME = \"") .append(grammar.getName()).append("\";\n"); } sb.append(" private static final String CATALOG_FILE_PATH = \"") - .append(_checkGeneratorNaming.checkFilePath(catalog)).append("\";\n"); - sb.append("\n"); + .append(checkGeneratorNaming.checkFilePath(catalog)).append("\";\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public void doSetup() {\n"); sb.append(" ICheckValidatorRegistry.INSTANCE.registerValidator("); if (grammar != null) { sb.append("GRAMMAR_NAME, "); } - sb.append("new ").append(_checkGeneratorNaming.validatorClassName(catalog)).append("());\n"); + sb.append("new ").append(checkGeneratorNaming.validatorClassName(catalog)).append("());\n"); sb.append(" ICheckCatalogRegistry.INSTANCE.registerCatalog("); if (grammar != null) { sb.append("GRAMMAR_NAME, "); } sb.append("new ModelLocation(\n"); - sb.append(" ").append(_checkGeneratorNaming.standaloneSetupClassName(catalog)) + sb.append(" ").append(checkGeneratorNaming.standaloneSetupClassName(catalog)) .append(".class.getClassLoader().getResource(CATALOG_FILE_PATH), CATALOG_FILE_PATH));\n"); sb.append(" LOG.info(\"Standalone setup done for ") - .append(_checkGeneratorNaming.checkFilePath(catalog)).append("\");\n"); + .append(checkGeneratorNaming.checkFilePath(catalog)).append("\");\n"); sb.append(" }\n"); - sb.append("\n"); + sb.append('\n'); sb.append(" @Override\n"); sb.append(" public String toString() {\n"); sb.append(" return \"CheckValidatorSetup(") @@ -244,26 +246,27 @@ public CharSequence compileStandaloneSetup(CheckCatalog catalog) { sb.append("}\n"); return sb; } + // CHECKSTYLE:CONSTANTS-ON /* * Writes contents of the service registry file containing fully qualified class names of all validators. * See also http://docs.oracle.com/javase/1.4.2/docs/api/javax/imageio/spi/ServiceRegistry.html */ - public CharSequence generateServiceRegistry(CheckCatalog catalog, String serviceRegistryFileName, IFileSystemAccess fsa) { + public CharSequence generateServiceRegistry(final CheckCatalog catalog, final String serviceRegistryFileName, final IFileSystemAccess fsa) { final OutputConfiguration config = ((AbstractFileSystemAccess) fsa).getOutputConfigurations().get(CheckGeneratorConstants.CHECK_REGISTRY_OUTPUT); final String outputDirectory = config.getOutputDirectory(); final String path = outputDirectory + "/" + serviceRegistryFileName; final Set contents = generatorExtensions.getContents(catalog, path); - contents.add(_checkGeneratorNaming.qualifiedStandaloneSetupClassName(catalog)); - final StringBuilder sb = new StringBuilder(); + contents.add(checkGeneratorNaming.qualifiedStandaloneSetupClassName(catalog)); + final StringBuilder sb = new StringBuilder(512); for (String c : contents) { - sb.append(c).append("\n"); + sb.append(c).append('\n'); } return sb; } @Override - public ITreeAppendable _generateMember(JvmField field, ITreeAppendable appendable, GeneratorConfig config) { + public ITreeAppendable _generateMember(final JvmField field, final ITreeAppendable appendable, final GeneratorConfig config) { // Suppress generation of the "artificial" fields for FormalParameters in check impls, but not elsewhere. if (field.isFinal() && !field.isStatic()) { // A bit hacky to use this as the distinction... final FormalParameter parameter = compiler.getFormalParameter(field); diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java index 7e4fd560d6..7f735e97c2 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java @@ -12,6 +12,7 @@ import java.io.InputStreamReader; import java.io.StringReader; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; @@ -40,11 +41,20 @@ import org.eclipse.xtext.validation.CheckType; import org.eclipse.xtext.xbase.lib.ListExtensions; -import static com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming.*; +import static com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming.issueCodesClassName; +import static com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming.parent; +@SuppressWarnings({"checkstyle:MethodName"}) public class CheckGeneratorExtensions { - protected String _qualifiedIssueCodeName(XIssueExpression issue) { + /** + * Returns the qualified Java name for an issue code. + * + * @param issue + * the issue expression + * @return the qualified issue code name, or {@code null} if the issue code is null + */ + protected String _qualifiedIssueCodeName(final XIssueExpression issue) { String result = issueCode(issue); if (result == null) { return null; @@ -53,13 +63,25 @@ protected String _qualifiedIssueCodeName(XIssueExpression issue) { } } - /* Returns the qualified Java name for an issue code. */ - protected String _qualifiedIssueCodeName(Context context) { + /** + * Returns the qualified Java name for an issue code. + * + * @param context + * the context + * @return the qualified issue code name + */ + protected String _qualifiedIssueCodeName(final Context context) { return issueCodesClassName(parent(context, CheckCatalog.class)) + "." + issueCode(context); } - /* Gets the simple issue code name for a check. */ - protected static String _issueCode(Check check) { + /** + * Gets the simple issue code name for a check. + * + * @param check + * the check + * @return the issue code string + */ + protected static String _issueCode(final Check check) { if (null != check.getName()) { return splitCamelCase(check.getName()).toUpperCase(); } else { @@ -67,8 +89,14 @@ protected static String _issueCode(Check check) { } } - /* Gets the simple issue code name for an issue expression. */ - protected static String _issueCode(XIssueExpression issue) { + /** + * Gets the simple issue code name for an issue expression. + * + * @param issue + * the issue expression + * @return the issue code string + */ + protected static String _issueCode(final XIssueExpression issue) { if (issue.getIssueCode() != null) { return splitCamelCase(issue.getIssueCode()).toUpperCase(); } else if (issue.getCheck() != null && !issue.getCheck().eIsProxy()) { @@ -80,8 +108,14 @@ protected static String _issueCode(XIssueExpression issue) { } } - /* Gets the simple issue code name for a check. */ - protected static String _issueName(Check check) { + /** + * Gets the simple issue code name for a check. + * + * @param check + * the check + * @return the issue name string + */ + protected static String _issueName(final Check check) { if (null != check.getName()) { return check.getName(); } else { @@ -89,8 +123,14 @@ protected static String _issueName(Check check) { } } - /* Gets the simple issue code name for an issue expression. */ - protected static String _issueName(XIssueExpression issue) { + /** + * Gets the simple issue code name for an issue expression. + * + * @param issue + * the issue expression + * @return the issue name string + */ + protected static String _issueName(final XIssueExpression issue) { if (issue.getIssueCode() != null) { return issue.getIssueCode(); } else if (issue.getCheck() != null && !issue.getCheck().eIsProxy()) { @@ -102,23 +142,50 @@ protected static String _issueName(XIssueExpression issue) { } } - public static String issueCodePrefix(CheckCatalog catalog) { + /** + * Returns the issue code prefix for a catalog. + * + * @param catalog + * the check catalog + * @return the issue code prefix + */ + public static String issueCodePrefix(final CheckCatalog catalog) { return catalog.getPackageName() + "." + issueCodesClassName(catalog) + "."; } - /* Returns the value of an issue code. */ - public static String issueCodeValue(EObject object, String issueName) { + /** + * Returns the value of an issue code. + * + * @param object + * the EObject context + * @param issueName + * the issue name + * @return the issue code value + */ + public static String issueCodeValue(final EObject object, final String issueName) { CheckCatalog catalog = parent(object, CheckCatalog.class); return issueCodePrefix(catalog) + CheckUtil.toIssueCodeName(splitCamelCase(issueName)); } - /* Gets the issue label for a Check. */ - protected String _issueLabel(Check check) { + /** + * Gets the issue label for a Check. + * + * @param check + * the check + * @return the label + */ + protected String _issueLabel(final Check check) { return check.getLabel(); } - /* Gets the issue label for an issue expression. */ - protected String _issueLabel(XIssueExpression issue) { + /** + * Gets the issue label for an issue expression. + * + * @param issue + * the issue expression + * @return the label + */ + protected String _issueLabel(final XIssueExpression issue) { if (issue.getCheck() != null && !issue.getCheck().eIsProxy()) { return issueLabel(issue.getCheck()); } else if (parent(issue, Check.class) != null) { @@ -129,7 +196,7 @@ protected String _issueLabel(XIssueExpression issue) { } /* Converts a string such as "AbcDef" to "ABC_DEF". */ - public static String splitCamelCase(String string) { + public static String splitCamelCase(final String string) { return string.replaceAll( String.format( "%s|%s|%s", @@ -141,7 +208,14 @@ public static String splitCamelCase(String string) { ); } - public CheckType checkType(Check check) { + /** + * Returns the CheckType for a check. + * + * @param check + * the check + * @return the check type + */ + public CheckType checkType(final Check check) { /* TODO handle the case of independent check implementations * An Implementation is not a Check and has no kind, * but it may execute checks of various types. @@ -159,37 +233,84 @@ public CheckType checkType(Check check) { }; } - /* Returns a default CheckType for a non-Check context. */ - public CheckType checkType(Context context) { + /** + * Returns a default CheckType for a non-Check context. + * + * @param context + * the context + * @return the check type + */ + public CheckType checkType(final Context context) { EObject container = context.eContainer(); Check check = (container instanceof Check) ? (Check) container : null; return checkType(check); } - public String checkTypeQName(Context context) { + /** + * Returns the qualified CheckType name for a context. + * + * @param context + * the context + * @return the qualified check type name + */ + public String checkTypeQName(final Context context) { return "CheckType." + checkType(context); } - public Iterable issues(EObject object) { + /** + * Returns all issue expressions contained in an EObject. + * + * @param object + * the object to search + * @return the issue expressions + */ + public Iterable issues(final EObject object) { return Iterables.filter(EcoreUtil2.eAllContents(object), XIssueExpression.class); } - public Iterable issues(CheckCatalog catalog) { + /** + * Returns all issue expressions for all checks in a catalog. + * + * @param catalog + * the check catalog + * @return the issue expressions + */ + public Iterable issues(final CheckCatalog catalog) { return Iterables.concat(ListExtensions.map(catalog.getAllChecks(), check -> issues(check))); } - public Iterable issues(Implementation implementation) { + /** + * Returns all issue expressions for an implementation. + * + * @param implementation + * the implementation + * @return the issue expressions + */ + public Iterable issues(final Implementation implementation) { return issues(implementation.getContext()); } - /* Returns all Check and Implementation Issues for a CheckCatalog. Issues are not necessarily unique. */ - public Iterable checkAndImplementationIssues(CheckCatalog catalog) { + /** + * Returns all Check and Implementation Issues for a CheckCatalog. Issues are not necessarily unique. + * + * @param catalog + * the check catalog + * @return all issue expressions + */ + public Iterable checkAndImplementationIssues(final CheckCatalog catalog) { Iterable checkIssues = issues(catalog); // Issues for all Checks Iterable implIssues = Iterables.concat(ListExtensions.map(catalog.getImplementations(), impl -> issues(impl))); // Issues for all Implementations return Iterables.concat(checkIssues, implIssues); // all Issue instances } - public Check issuedCheck(XIssueExpression expression) { + /** + * Returns the check associated with an issue expression. + * + * @param expression + * the issue expression + * @return the associated check, or {@code null} + */ + public Check issuedCheck(final XIssueExpression expression) { if (expression.getCheck() != null) { return expression.getCheck(); } else { @@ -205,8 +326,12 @@ public Check issuedCheck(XIssueExpression expression) { /** * Gets the IFile which is associated with given object's eResource, or null if none * could be determined. + * + * @param object + * the EObject + * @return the associated file, or {@code null} */ - public IFile fileForObject(EObject object) { + public IFile fileForObject(final EObject object) { Resource res = object.eResource(); if (res.getURI().isPlatform()) { return (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(res.getURI().toPlatformString(true)); @@ -217,16 +342,24 @@ public IFile fileForObject(EObject object) { /** * Gets the IProject which is associated with a given EObject or null * if none could be determined. + * + * @param object + * the EObject + * @return the associated project, or {@code null} */ - public IProject projectForObject(EObject object) { + public IProject projectForObject(final EObject object) { IFile file = object != null ? fileForObject(object) : null; return file != null ? file.getProject() : null; } /** * Gets the name of the project in which given object is contained. + * + * @param object + * the EObject + * @return the bundle name, or {@code null} */ - public String bundleName(EObject object) { + public String bundleName(final EObject object) { IProject proj = projectForObject(object); if (proj != null) { return proj.getName(); @@ -234,19 +367,28 @@ public String bundleName(EObject object) { return null; } - /* - * Replace binding placeholders of a message with "...". + /** + * Replace binding placeholders of a message with "...". + * + * @param message + * the message + * @return the message with placeholders replaced */ - public String replacePlaceholder(String message) { + public String replacePlaceholder(final String message) { Pattern p = Pattern.compile("\\{[0-9]+\\}"); Matcher m = p.matcher(message); return m.replaceAll("..."); } - /* - * Format the Check description for Eclipse Help + /** + * Format the Check description for Eclipse Help. + * + * @param comment + * the comment to format + * @return the formatted HTML, or {@code null} */ - public String formatDescription(String comment) { + // CHECKSTYLE:CHECK-OFF IllegalCatch + public String formatDescription(final String comment) { if (comment == null) { return null; } @@ -257,24 +399,47 @@ public String formatDescription(String comment) { return null; } } + // CHECKSTYLE:CHECK-ON IllegalCatch - public Set getContents(CheckCatalog catalog, String path) { + /** + * Gets the contents of a file in the project. + * + * @param catalog + * the check catalog + * @param path + * the file path + * @return the set of lines + * @throws IllegalStateException + * if the file cannot be read + */ + public Set getContents(final CheckCatalog catalog, final String path) { IProject project = projectForObject(catalog); if (project != null) { // In some compiler tests we may not have a project. IFile file = project.getFile(new Path(path)); if (file.exists()) { - try (InputStreamReader reader = new InputStreamReader(file.getContents())) { + // CHECKSTYLE:CHECK-OFF IllegalCatch + try (InputStreamReader reader = new InputStreamReader(file.getContents(), StandardCharsets.UTF_8)) { List content = CharStreams.readLines(reader); return Sets.newTreeSet(content); } catch (Exception e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } + // CHECKSTYLE:CHECK-ON IllegalCatch } } return new LinkedHashSet<>(); } - public String qualifiedIssueCodeName(EObject context) { + /** + * Returns the qualified issue code name for an EObject. + * + * @param context + * the EObject context + * @return the qualified issue code name + * @throws IllegalArgumentException + * if the parameter type is not handled + */ + public String qualifiedIssueCodeName(final EObject context) { if (context instanceof Context) { return _qualifiedIssueCodeName((Context) context); } else if (context instanceof XIssueExpression) { @@ -285,7 +450,16 @@ public String qualifiedIssueCodeName(EObject context) { } } - public static String issueCode(EObject check) { + /** + * Returns the issue code for an EObject. + * + * @param check + * the EObject (Check or XIssueExpression) + * @return the issue code string + * @throws IllegalArgumentException + * if the parameter type is not handled + */ + public static String issueCode(final EObject check) { if (check instanceof Check) { return _issueCode((Check) check); } else if (check instanceof XIssueExpression) { @@ -296,7 +470,16 @@ public static String issueCode(EObject check) { } } - public static String issueName(EObject check) { + /** + * Returns the issue name for an EObject. + * + * @param check + * the EObject (Check or XIssueExpression) + * @return the issue name string + * @throws IllegalArgumentException + * if the parameter type is not handled + */ + public static String issueName(final EObject check) { if (check instanceof Check) { return _issueName((Check) check); } else if (check instanceof XIssueExpression) { @@ -307,7 +490,16 @@ public static String issueName(EObject check) { } } - public String issueLabel(EObject check) { + /** + * Returns the issue label for an EObject. + * + * @param check + * the EObject (Check or XIssueExpression) + * @return the label string + * @throws IllegalArgumentException + * if the parameter type is not handled + */ + public String issueLabel(final EObject check) { if (check instanceof Check) { return _issueLabel((Check) check); } else if (check instanceof XIssueExpression) { diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java index 374f4735cc..f5248e31c2 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java @@ -28,12 +28,12 @@ public class CheckGeneratorNaming { @Inject private IQualifiedNameProvider nameProvider; - public static T parent(EObject object, Class c) { + public static T parent(final EObject object, final Class c) { return EcoreUtil2.getContainerOfType(object, c); } // creates a pathName out of a qualified javaPackagename - public String asPath(String javaPackageName) { + public String asPath(final String javaPackageName) { if (javaPackageName != null) { return javaPackageName.replace('.', '/') + "/"; } else { @@ -42,92 +42,92 @@ public String asPath(String javaPackageName) { } /* Gets the class name of the check validator. */ - public String validatorClassName(CheckCatalog c) { + public String validatorClassName(final CheckCatalog c) { return c.getName() + "CheckImpl"; } /* Gets the fully qualified class name of the check validator. */ - public String qualifiedValidatorClassName(CheckCatalog c) { + public String qualifiedValidatorClassName(final CheckCatalog c) { return c.getPackageName() + "." + validatorClassName(c); } /* Gets the file path of the check validator. */ - public String validatorFilePath(CheckCatalog c) { + public String validatorFilePath(final CheckCatalog c) { return asPath(c.getPackageName()) + validatorClassName(c) + ".java"; } /* Gets the check catalog class name. */ - public String catalogClassName(CheckCatalog c) { + public String catalogClassName(final CheckCatalog c) { return c.getName() + "CheckCatalog"; } /* Gets the qualified check catalog class name. */ - public String qualifiedCatalogClassName(CheckCatalog c) { + public String qualifiedCatalogClassName(final CheckCatalog c) { return c.getPackageName() + "." + catalogClassName(c); } /* Gets the preference initializer class name. */ - public String preferenceInitializerClassName(CheckCatalog c) { + public String preferenceInitializerClassName(final CheckCatalog c) { return c.getName() + "PreferenceInitializer"; } /* Gets the qualified standalone setup class name. */ - public String qualifiedStandaloneSetupClassName(CheckCatalog c) { + public String qualifiedStandaloneSetupClassName(final CheckCatalog c) { return c.getPackageName() + "." + standaloneSetupClassName(c); } /* Gets the standalone setup class name. */ - public String standaloneSetupClassName(CheckCatalog c) { + public String standaloneSetupClassName(final CheckCatalog c) { return c.getName() + "StandaloneSetup"; } /* Gets the qualified preference initializer class name. */ - public String qualifiedPreferenceInitializerClassName(CheckCatalog c) { + public String qualifiedPreferenceInitializerClassName(final CheckCatalog c) { return c.getPackageName() + "." + preferenceInitializerClassName(c); } /* Gets the standalone setup class file path. */ - public String standaloneSetupPath(CheckCatalog c) { + public String standaloneSetupPath(final CheckCatalog c) { return asPath(c.getPackageName()) + standaloneSetupClassName(c) + ".java"; } /* Gets the documentation file name. */ - public String docFileName(CheckCatalog c) { + public String docFileName(final CheckCatalog c) { return c.getName() + ".html"; } /* Gets the issue codes class name. */ - public static String issueCodesClassName(CheckCatalog c) { + public static String issueCodesClassName(final CheckCatalog c) { return c.getName() + ISSUE_CODES_CLASS_NAME_SUFFIX; } /* Gets the issue codes file path. */ - public String issueCodesFilePath(CheckCatalog c) { + public String issueCodesFilePath(final CheckCatalog c) { return asPath(c.getPackageName()) + issueCodesClassName(c) + ".java"; } /* Gets the quickfix provider class name. */ - public String quickfixClassName(CheckCatalog c) { + public String quickfixClassName(final CheckCatalog c) { return c.getName() + "QuickfixProvider"; } /* Gets the qualified quickfix provider class name. */ - public String qualifiedQuickfixClassName(CheckCatalog c) { + public String qualifiedQuickfixClassName(final CheckCatalog c) { return c.getPackageName() + "." + quickfixClassName(c); } /* Gets the quickfix provider file path. */ - public String quickfixFilePath(CheckCatalog c) { + public String quickfixFilePath(final CheckCatalog c) { return asPath(c.getPackageName()) + quickfixClassName(c) + ".java"; } /* Gets the full path to the check file, e.g. com/avaloq/MyChecks.check. */ - public String checkFilePath(CheckCatalog c) { + public String checkFilePath(final CheckCatalog c) { return asPath(c.getPackageName()) + c.getName() + ".check"; } /* Gets the name of the getter method generated for a formal parameter. */ - public String formalParameterGetterName(FormalParameter p) { + public String formalParameterGetterName(final FormalParameter p) { Check check = (Check) p.eContainer(); return "get" + StringExtensions.toFirstUpper(check.getName()) @@ -136,12 +136,12 @@ public String formalParameterGetterName(FormalParameter p) { } /* Gets the name of the getter method generated for a field. */ - public String fieldGetterName(String fieldName) { + public String fieldGetterName(final String fieldName) { return "get" + StringExtensions.toFirstUpper(fieldName); } /* Check catalog instance name in the validator */ - public String catalogInstanceName(EObject object) { + public String catalogInstanceName(final EObject object) { return StringExtensions.toFirstLower(EcoreUtil2.getContainerOfType(object, CheckCatalog.class).getName()) + "Catalog"; } @@ -161,18 +161,18 @@ public String qualifiedDefaultValidatorClassName() { } /* Gets the prefix for the context id (used in contexts.xml) */ - public String getContextIdPrefix(QualifiedName catalog) { + public String getContextIdPrefix(final QualifiedName catalog) { return catalog.getLastSegment().toString().toLowerCase() + "_"; // TODO make context id use fully qualified catalog names } /* Gets the full context id (used in contexts.xml) */ - public String getContextId(Check check) { + public String getContextId(final Check check) { CheckCatalog catalog = parent(check, CheckCatalog.class); return getContextIdPrefix(nameProvider.apply(catalog)) + check.getLabel().replaceAll(" ", "").replaceAll("\"", "").replaceAll("'", "").toLowerCase(); } /* Gets the full context id (used in contexts.xml) */ - public String getContextId(Category category) { + public String getContextId(final Category category) { CheckCatalog catalog = parent(category, CheckCatalog.class); return getContextIdPrefix(nameProvider.apply(catalog)) + category.getLabel().replaceAll(" ", "").replaceAll("\"", "").replaceAll("'", "").toLowerCase(); } diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java index 16e81a8091..d1d8e96106 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java @@ -10,7 +10,6 @@ *******************************************************************************/ package com.avaloq.tools.ddk.check.jvmmodel; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -88,6 +87,7 @@ *

    The JVM model should contain all elements that would appear in the Java code * which is generated from the source model. Other models link against the JVM model rather than the source model.

    */ +@SuppressWarnings({"checkstyle:MethodName"}) public class CheckJvmModelInferrer extends AbstractModelInferrer { @Inject @@ -97,15 +97,17 @@ public class CheckJvmModelInferrer extends AbstractModelInferrer { private CheckLocationInFileProvider locationInFileProvider; @Inject - private CheckGeneratorExtensions _checkGeneratorExtensions; + private CheckGeneratorExtensions checkGeneratorExtensions; @Inject - private CheckGeneratorNaming _checkGeneratorNaming; + private CheckGeneratorNaming checkGeneratorNaming; @Inject - private JvmTypesBuilder _jvmTypesBuilder; + private JvmTypesBuilder jvmTypesBuilder; - protected void _infer(CheckCatalog catalog, IJvmDeclaredTypeAcceptor acceptor, boolean preIndexingPhase) { + // CHECKSTYLE:CONSTANTS-OFF + // CHECKSTYLE:CHECK-OFF LambdaBodyLength + protected void _infer(final CheckCatalog catalog, final IJvmDeclaredTypeAcceptor acceptor, final boolean preIndexingPhase) { // The xbase automatic scoping mechanism (typeRef()) cannot find secondary classes in the same resource. It can // only find indexed resources (either in the JDT index or in the xtext index). However, we'll initialize the // JVM validator class before the resource gets indexed, so the JVM catalog class cannot be found yet when we @@ -114,7 +116,7 @@ protected void _infer(CheckCatalog catalog, IJvmDeclaredTypeAcceptor acceptor, b if (preIndexingPhase) { return; } - JvmGenericType catalogClass = _jvmTypesBuilder.toClass(catalog, _checkGeneratorNaming.qualifiedCatalogClassName(catalog)); + JvmGenericType catalogClass = jvmTypesBuilder.toClass(catalog, checkGeneratorNaming.qualifiedCatalogClassName(catalog)); JvmTypeReference issueCodeToLabelMapTypeRef = _typeReferenceBuilder.typeRef(ImmutableMap.class, _typeReferenceBuilder.typeRef(String.class), _typeReferenceBuilder.typeRef(String.class)); acceptor.accept(catalogClass, (JvmGenericType it) -> { JvmTypeReference parentType = checkedTypeRef(catalog, AbstractIssue.class); @@ -123,30 +125,30 @@ protected void _infer(CheckCatalog catalog, IJvmDeclaredTypeAcceptor acceptor, b } Iterables.addAll(it.getAnnotations(), createAnnotation(checkedTypeRef(catalog, Singleton.class), (JvmAnnotationReference it1) -> { })); - _jvmTypesBuilder.setDocumentation(it, "Issues for " + catalog.getName() + "."); + jvmTypesBuilder.setDocumentation(it, "Issues for " + catalog.getName() + "."); Iterables.addAll(it.getMembers(), createInjectedField(catalog, "checkConfigurationStoreService", checkedTypeRef(catalog, ICheckConfigurationStoreService.class))); // Create map of issue code to label and associated getter - it.getMembers().add(_jvmTypesBuilder.toField(catalog, _checkGeneratorNaming.issueCodeToLabelMapFieldName(), issueCodeToLabelMapTypeRef, (JvmField it1) -> { + it.getMembers().add(jvmTypesBuilder.toField(catalog, checkGeneratorNaming.issueCodeToLabelMapFieldName(), issueCodeToLabelMapTypeRef, (JvmField it1) -> { it1.setStatic(true); it1.setFinal(true); // Get all issue codes and labels - Iterable issues = _checkGeneratorExtensions.checkAndImplementationIssues(catalog); + Iterable issues = checkGeneratorExtensions.checkAndImplementationIssues(catalog); // Use a TreeMap to eliminate duplicates, // and also to sort by qualified issue code name so autogenerated files are more readable and less prone to spurious ordering changes. // Do this when compiling the Check, to avoid discovering duplicates at runtime. - TreeMap sortedUniqueQualifiedIssueCodeNamesAndLabels = new TreeMap(); + Map sortedUniqueQualifiedIssueCodeNamesAndLabels = new TreeMap(); for (XIssueExpression issue : issues) { - String qualifiedIssueCodeName = _checkGeneratorExtensions.qualifiedIssueCodeName(issue); - String issueLabel = StringEscapeUtils.escapeJava(_checkGeneratorExtensions.issueLabel(issue)); + String qualifiedIssueCodeName = checkGeneratorExtensions.qualifiedIssueCodeName(issue); + String issueLabel = StringEscapeUtils.escapeJava(checkGeneratorExtensions.issueLabel(issue)); String existingIssueLabel = sortedUniqueQualifiedIssueCodeNamesAndLabels.putIfAbsent(qualifiedIssueCodeName, issueLabel); if (null != existingIssueLabel && !Objects.equals(issueLabel, existingIssueLabel)) { // This qualified issue code name is already in the map, with a different label. Fail the build. throw new IllegalArgumentException("Multiple issues found with qualified issue code name: " + qualifiedIssueCodeName); } } - _jvmTypesBuilder.setInitializer(it1, (ITreeAppendable appendable) -> { - StringBuilder sb = new StringBuilder(); + jvmTypesBuilder.setInitializer(it1, (ITreeAppendable appendable) -> { + StringBuilder sb = new StringBuilder(512); sb.append(ImmutableMap.class.getSimpleName()).append(".<").append(String.class.getSimpleName()).append(", ").append(String.class.getSimpleName()).append(">builderWithExpectedSize(").append(sortedUniqueQualifiedIssueCodeNamesAndLabels.entrySet().size()).append(")\n"); for (Map.Entry qualifiedIssueCodeNameAndLabel : sortedUniqueQualifiedIssueCodeNamesAndLabels.entrySet()) { sb.append(" .put(").append(qualifiedIssueCodeNameAndLabel.getKey()).append(", \"").append(qualifiedIssueCodeNameAndLabel.getValue()).append("\")\n"); @@ -155,44 +157,44 @@ protected void _infer(CheckCatalog catalog, IJvmDeclaredTypeAcceptor acceptor, b appendable.append(sb.toString()); }); })); - it.getMembers().add(_jvmTypesBuilder.toMethod(catalog, _checkGeneratorNaming.fieldGetterName(_checkGeneratorNaming.issueCodeToLabelMapFieldName()), issueCodeToLabelMapTypeRef, (JvmOperation it1) -> { - _jvmTypesBuilder.setDocumentation(it1, "Get map of issue code to label for " + catalog.getName() + ".\n\n@returns Map of issue code to label for " + catalog.getName() + ".\n"); + it.getMembers().add(jvmTypesBuilder.toMethod(catalog, checkGeneratorNaming.fieldGetterName(checkGeneratorNaming.issueCodeToLabelMapFieldName()), issueCodeToLabelMapTypeRef, (JvmOperation it1) -> { + jvmTypesBuilder.setDocumentation(it1, "Get map of issue code to label for " + catalog.getName() + ".\n\n@returns Map of issue code to label for " + catalog.getName() + ".\n"); it1.setStatic(true); it1.setFinal(true); - _jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { - appendable.append("return " + _checkGeneratorNaming.issueCodeToLabelMapFieldName() + ";"); + jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { + appendable.append("return " + checkGeneratorNaming.issueCodeToLabelMapFieldName() + ";"); }); })); Iterables.addAll(it.getMembers(), IterableExtensions.filterNull(Iterables.concat(ListExtensions.>map(catalog.getAllChecks(), (Check c) -> createIssue(catalog, c))))); }); - acceptor.accept(_jvmTypesBuilder.toClass(catalog, _checkGeneratorNaming.qualifiedValidatorClassName(catalog)), (JvmGenericType it) -> { + acceptor.accept(jvmTypesBuilder.toClass(catalog, checkGeneratorNaming.qualifiedValidatorClassName(catalog)), (JvmGenericType it) -> { JvmTypeReference parentType = checkedTypeRef(catalog, DispatchingCheckImpl.class); if (parentType != null) { it.getSuperTypes().add(parentType); } // Constructor will be added automatically. - _jvmTypesBuilder.setDocumentation(it, "Validator for " + catalog.getName() + "."); + jvmTypesBuilder.setDocumentation(it, "Validator for " + catalog.getName() + "."); // Create catalog injections - Iterables.addAll(it.getMembers(), createInjectedField(catalog, _checkGeneratorNaming.catalogInstanceName(catalog), _typeReferenceBuilder.typeRef(catalogClass))); + Iterables.addAll(it.getMembers(), createInjectedField(catalog, checkGeneratorNaming.catalogInstanceName(catalog), _typeReferenceBuilder.typeRef(catalogClass))); // Create fields - Iterables.addAll(it.getMembers(), ListExtensions.map(catalog.getMembers(), (Member m) -> _jvmTypesBuilder.toField(m, m.getName(), m.getType(), (JvmField it1) -> { - _jvmTypesBuilder.setInitializer(it1, m.getValue()); - _jvmTypesBuilder.addAnnotations(it1, m.getAnnotations()); + Iterables.addAll(it.getMembers(), ListExtensions.map(catalog.getMembers(), (Member m) -> jvmTypesBuilder.toField(m, m.getName(), m.getType(), (JvmField it1) -> { + jvmTypesBuilder.setInitializer(it1, m.getValue()); + jvmTypesBuilder.addAnnotations(it1, m.getAnnotations()); }))); // Create catalog name function - it.getMembers().add(_jvmTypesBuilder.toMethod(catalog, "getQualifiedCatalogName", _typeReferenceBuilder.typeRef(String.class), (JvmOperation it1) -> { - _jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { + it.getMembers().add(jvmTypesBuilder.toMethod(catalog, "getQualifiedCatalogName", _typeReferenceBuilder.typeRef(String.class), (JvmOperation it1) -> { + jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { appendable.append("return \"" + catalog.getPackageName() + "." + catalog.getName() + "\";"); }); })); // Create getter for map of issue code to label - it.getMembers().add(_jvmTypesBuilder.toMethod(catalog, _checkGeneratorNaming.fieldGetterName(_checkGeneratorNaming.issueCodeToLabelMapFieldName()), issueCodeToLabelMapTypeRef, (JvmOperation it1) -> { + it.getMembers().add(jvmTypesBuilder.toMethod(catalog, checkGeneratorNaming.fieldGetterName(checkGeneratorNaming.issueCodeToLabelMapFieldName()), issueCodeToLabelMapTypeRef, (JvmOperation it1) -> { it1.setFinal(true); - _jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { - appendable.append("return " + _checkGeneratorNaming.catalogClassName(catalog) + "." + _checkGeneratorNaming.fieldGetterName(_checkGeneratorNaming.issueCodeToLabelMapFieldName()) + "();"); + jvmTypesBuilder.setBody(it1, (ITreeAppendable appendable) -> { + appendable.append("return " + checkGeneratorNaming.catalogClassName(catalog) + "." + checkGeneratorNaming.fieldGetterName(checkGeneratorNaming.issueCodeToLabelMapFieldName()) + "();"); }); })); @@ -206,39 +208,40 @@ protected void _infer(CheckCatalog catalog, IJvmDeclaredTypeAcceptor acceptor, b // Create methods for stand-alone context implementations Iterables.addAll(it.getMembers(), IterableExtensions.filterNull(ListExtensions.map(catalog.getImplementations(), (Implementation impl) -> createCheckMethod(impl.getContext())))); }); - acceptor.accept(_jvmTypesBuilder.toClass(catalog, _checkGeneratorNaming.qualifiedPreferenceInitializerClassName(catalog)), (JvmGenericType it) -> { + acceptor.accept(jvmTypesBuilder.toClass(catalog, checkGeneratorNaming.qualifiedPreferenceInitializerClassName(catalog)), (JvmGenericType it) -> { JvmTypeReference parentType = checkedTypeRef(catalog, AbstractPreferenceInitializer.class); if (parentType != null) { it.getSuperTypes().add(parentType); } - it.getMembers().add(_jvmTypesBuilder.toField(catalog, "RUNTIME_NODE_NAME", _typeReferenceBuilder.typeRef(String.class), (JvmField it1) -> { + it.getMembers().add(jvmTypesBuilder.toField(catalog, "RUNTIME_NODE_NAME", _typeReferenceBuilder.typeRef(String.class), (JvmField it1) -> { it1.setStatic(true); it1.setFinal(true); - _jvmTypesBuilder.setInitializer(it1, (ITreeAppendable appendable) -> { - appendable.append("\"" + _checkGeneratorExtensions.bundleName(catalog) + "\""); + jvmTypesBuilder.setInitializer(it1, (ITreeAppendable appendable) -> { + appendable.append("\"" + checkGeneratorExtensions.bundleName(catalog) + "\""); }); })); Iterables.addAll(it.getMembers(), createFormalParameterFields(catalog)); Iterables.addAll(it.getMembers(), createPreferenceInitializerMethods(catalog)); }); } + // CHECKSTYLE:CHECK-ON LambdaBodyLength - private JvmOperation createDispatcherMethod(CheckCatalog catalog) { + private JvmOperation createDispatcherMethod(final CheckCatalog catalog) { JvmTypeReference objectBaseJavaTypeRef = checkedTypeRef(catalog, EObject.class); - return _jvmTypesBuilder.toMethod(catalog, "validate", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + return jvmTypesBuilder.toMethod(catalog, "validate", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { it.setVisibility(JvmVisibility.PUBLIC); - it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "checkMode", checkedTypeRef(catalog, CheckMode.class))); - it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "object", objectBaseJavaTypeRef)); - it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "diagnosticCollector", checkedTypeRef(catalog, DiagnosticCollector.class))); + it.getParameters().add(jvmTypesBuilder.toParameter(catalog, "checkMode", checkedTypeRef(catalog, CheckMode.class))); + it.getParameters().add(jvmTypesBuilder.toParameter(catalog, "object", objectBaseJavaTypeRef)); + it.getParameters().add(jvmTypesBuilder.toParameter(catalog, "diagnosticCollector", checkedTypeRef(catalog, DiagnosticCollector.class))); Iterables.addAll(it.getAnnotations(), createAnnotation(checkedTypeRef(catalog, Override.class), (JvmAnnotationReference it1) -> { })); - _jvmTypesBuilder.setBody(it, (ITreeAppendable out) -> { + jvmTypesBuilder.setBody(it, (ITreeAppendable out) -> { emitDispatcherMethodBody(out, catalog, objectBaseJavaTypeRef); }); }); } - private void emitDispatcherMethodBody(ITreeAppendable out, CheckCatalog catalog, JvmTypeReference objectBaseJavaTypeRef) { + private void emitDispatcherMethodBody(final ITreeAppendable out, final CheckCatalog catalog, final JvmTypeReference objectBaseJavaTypeRef) { /* A catalog may contain both Check and Implementation objects, * which in turn may contain Context objects. * Categories may optionally be used for grouping checks, and @@ -259,9 +262,9 @@ private void emitDispatcherMethodBody(ITreeAppendable out, CheckCatalog catalog, * We use an OrderedMap for deterministic ordering of check type checks. * For Context objects we retain their order of appearance, apart from groupings. */ - TreeMap> contextsByCheckType = new TreeMap>(); + Map> contextsByCheckType = new TreeMap>(); for (Context context : allContexts) { - contextsByCheckType.compute(_checkGeneratorExtensions.checkType(context), (CheckType k, List lst) -> lst != null ? lst : new ArrayList()).add(context); + contextsByCheckType.compute(checkGeneratorExtensions.checkType(context), (CheckType k, List lst) -> lst != null ? lst : new java.util.ArrayList()).add(context); } String baseTypeName = objectBaseJavaTypeRef.getQualifiedName(); @@ -284,14 +287,14 @@ private void emitDispatcherMethodBody(ITreeAppendable out, CheckCatalog catalog, } } - private void emitInstanceOfConditionals(ITreeAppendable out, List contexts, CheckCatalog catalog, String baseTypeName) { + private void emitInstanceOfConditionals(final ITreeAppendable out, final List contexts, final CheckCatalog catalog, final String baseTypeName) { /* Contexts grouped by fully qualified variable type name, * otherwise in order of appearance. */ - TreeMap> contextsByVarType = new TreeMap>(); + Map> contextsByVarType = new TreeMap>(); for (Context context : contexts) { contextsByVarType.compute(context.getContextVariable().getType().getQualifiedName(), - (String k, List lst) -> lst != null ? lst : new ArrayList() + (String k, List lst) -> lst != null ? lst : new java.util.ArrayList() ).add(context); } @@ -302,7 +305,7 @@ private void emitInstanceOfConditionals(ITreeAppendable out, List conte emitInstanceOfTree(out, forest, null, contextsByVarType, catalog, baseTypeName, 0); } - private void emitInstanceOfTree(ITreeAppendable out, InstanceOfCheckOrderer.Forest forest, String node, Map> contextsByVarType, CheckCatalog catalog, String baseTypeName, int level) { + private void emitInstanceOfTree(final ITreeAppendable out, final InstanceOfCheckOrderer.Forest forest, final String node, final Map> contextsByVarType, final CheckCatalog catalog, final String baseTypeName, final int level) { if (node != null) { String typeName = node; if (Objects.equals(typeName, baseTypeName)) { @@ -316,16 +319,16 @@ private void emitInstanceOfTree(ITreeAppendable out, InstanceOfCheckOrderer.Fore } out.newLine(); - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(512); if (typeName != null) { - sb.append("if (object instanceof final ").append(typeName).append(" ").append(varName).append(") "); + sb.append("if (object instanceof final ").append(typeName).append(' ').append(varName).append(") "); } - sb.append("{"); + sb.append('{'); out.append(sb.toString()); out.increaseIndentation(); - List contexts = contextsByVarType.get(node); - for (Context context : contexts) { + List ctxList = contextsByVarType.get(node); + for (Context context : ctxList) { emitCheckMethodCall(out, varName, context, catalog); // with preceding newline } } @@ -342,7 +345,7 @@ private void emitInstanceOfTree(ITreeAppendable out, InstanceOfCheckOrderer.Fore } } - private void emitCheckMethodCall(ITreeAppendable out, String varName, Context context, CheckCatalog catalog) { + private void emitCheckMethodCall(final ITreeAppendable out, final String varName, final Context context, final CheckCatalog catalog) { String methodName = generateContextMethodName(context); String jMethodName = toJavaLiteral(methodName); String qMethodName = toJavaLiteral(catalog.getName(), methodName); @@ -351,11 +354,11 @@ private void emitCheckMethodCall(ITreeAppendable out, String varName, Context co out.append("validate(" + jMethodName + ", " + qMethodName + ", object,\n () -> " + methodName + "(" + varName + ", diagnosticCollector), diagnosticCollector);"); } - private String toJavaLiteral(String... strings) { + private String toJavaLiteral(final String... strings) { return "\"" + Strings.convertToJavaString(String.join(".", strings)) + "\""; } - private Iterable createInjectedField(CheckCatalog context, String fieldName, JvmTypeReference type) { + private Iterable createInjectedField(final CheckCatalog context, final String fieldName, final JvmTypeReference type) { // Generate @Inject private typeName fieldName; if (type == null) { return Collections.emptyList(); @@ -363,13 +366,13 @@ private Iterable createInjectedField(CheckCatalog context, String fiel JvmField field = typesFactory.createJvmField(); field.setSimpleName(fieldName); field.setVisibility(JvmVisibility.PRIVATE); - field.setType(_jvmTypesBuilder.cloneWithProxies(type)); + field.setType(jvmTypesBuilder.cloneWithProxies(type)); Iterables.addAll(field.getAnnotations(), createAnnotation(checkedTypeRef(context, Inject.class), (JvmAnnotationReference it) -> { })); return Collections.singleton(field); } - private Iterable createCheck(Check chk) { + private Iterable createCheck(final Check chk) { // If we don't have FormalParameters, there's no need to do all this song and dance with inner classes. if (chk.getFormalParameters().isEmpty()) { return ListExtensions.map(chk.getContexts(), (Context ctx) -> (JvmMember) createCheckMethod(ctx)); @@ -378,7 +381,7 @@ private Iterable createCheck(Check chk) { } } - private Iterable createCheckWithParameters(Check chk) { + private Iterable createCheckWithParameters(final Check chk) { // Generate an inner class, plus a field holding an instance of that class. // Put the formal parameters into that class as fields. // For each check context, generate a run method. @@ -388,18 +391,18 @@ private Iterable createCheckWithParameters(Check chk) { // don't use them; we only need them for scoping based on this inferred model. List newMembers = Lists.newArrayList(); // First the class - JvmGenericType checkClass = _jvmTypesBuilder.toClass(chk, StringExtensions.toFirstUpper(chk.getName()) + "Class", (JvmGenericType it) -> { + JvmGenericType checkClass = jvmTypesBuilder.toClass(chk, StringExtensions.toFirstUpper(chk.getName()) + "Class", (JvmGenericType it) -> { it.getSuperTypes().add(_typeReferenceBuilder.typeRef(Object.class)); it.setVisibility(JvmVisibility.PRIVATE); // Add a fields for the parameters, so that they can be linked. We suppress generation of these fields in the generator, // and replace all references by calls to the getter function in the catalog. - Iterables.addAll(it.getMembers(), IterableExtensions.map(IterableExtensions.filter(chk.getFormalParameters(), (FormalParameter f) -> f.getType() != null && f.getName() != null), (FormalParameter f) -> _jvmTypesBuilder.toField(f, f.getName(), f.getType(), (JvmField it1) -> { + Iterables.addAll(it.getMembers(), IterableExtensions.map(IterableExtensions.filter(chk.getFormalParameters(), (FormalParameter f) -> f.getType() != null && f.getName() != null), (FormalParameter f) -> jvmTypesBuilder.toField(f, f.getName(), f.getType(), (JvmField it1) -> { it1.setFinal(true); }))); }); newMembers.add(checkClass); - newMembers.add(_jvmTypesBuilder.toField(chk, StringExtensions.toFirstLower(chk.getName()) + "Impl", _typeReferenceBuilder.typeRef(checkClass), (JvmField it) -> { - _jvmTypesBuilder.setInitializer(it, (ITreeAppendable appendable) -> { + newMembers.add(jvmTypesBuilder.toField(chk, StringExtensions.toFirstLower(chk.getName()) + "Impl", _typeReferenceBuilder.typeRef(checkClass), (JvmField it) -> { + jvmTypesBuilder.setInitializer(it, (ITreeAppendable appendable) -> { appendable.append("new " + checkClass.getSimpleName() + "()"); }); })); @@ -409,7 +412,7 @@ private Iterable createCheckWithParameters(Check chk) { return newMembers; } - private JvmOperation createCheckExecution(Context ctx) { + private JvmOperation createCheckExecution(final Context ctx) { if (ctx == null || ctx.getContextVariable() == null) { return null; } @@ -419,15 +422,15 @@ private JvmOperation createCheckExecution(Context ctx) { simpleName = ctxVarType.getSimpleName(); } String functionName = "run" + StringExtensions.toFirstUpper(simpleName); - return _jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + return jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { String paramName = ctx.getContextVariable().getName() == null ? CheckConstants.IT : ctx.getContextVariable().getName(); - it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, paramName, ctx.getContextVariable().getType())); - it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); - _jvmTypesBuilder.setBody(it, ctx.getConstraint()); + it.getParameters().add(jvmTypesBuilder.toParameter(ctx, paramName, ctx.getContextVariable().getType())); + it.getParameters().add(jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); + jvmTypesBuilder.setBody(it, ctx.getConstraint()); }); } - private Iterable createCheckAnnotation(Context ctx) { + private Iterable createCheckAnnotation(final Context ctx) { JvmTypeReference checkTypeTypeRef = checkedTypeRef(ctx, CheckType.class); if (checkTypeTypeRef == null) { return Collections.emptyList(); @@ -438,8 +441,8 @@ private Iterable createCheckAnnotation(Context ctx) { XMemberFeatureCall memberCall = XbaseFactory.eINSTANCE.createXMemberFeatureCall(); memberCall.setMemberCallTarget(featureCall); // The grammar doesn't use the CheckType constants directly... - String name = _checkGeneratorExtensions.checkTypeQName(ctx); - int i = name.lastIndexOf("."); + String name = checkGeneratorExtensions.checkTypeQName(ctx); + int i = name.lastIndexOf('.'); if (i >= 0) { name = name.substring(i + 1); } @@ -450,11 +453,11 @@ private Iterable createCheckAnnotation(Context ctx) { ctx.eResource().getContents().add(memberCall); return createAnnotation(checkedTypeRef(ctx, org.eclipse.xtext.validation.Check.class), (JvmAnnotationReference it) -> { - it.getExplicitValues().add(_jvmTypesBuilder.toJvmAnnotationValue(memberCall)); + it.getExplicitValues().add(jvmTypesBuilder.toJvmAnnotationValue(memberCall)); }); } - private JvmOperation createCheckCaller(Context ctx, Check chk) { + private JvmOperation createCheckCaller(final Context ctx, final Check chk) { if (ctx == null || ctx.getContextVariable() == null) { return null; } @@ -468,12 +471,12 @@ private JvmOperation createCheckCaller(Context ctx, Check chk) { // into the XBlockExpression of ctx.constraint. Just copying them doesn't work; modifies the source model! // Therefore, we generate something new: each check becomes a local class - return _jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { - it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, "context", ctx.getContextVariable().getType())); - it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); + return jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + it.getParameters().add(jvmTypesBuilder.toParameter(ctx, "context", ctx.getContextVariable().getType())); + it.getParameters().add(jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); Iterables.addAll(it.getAnnotations(), createCheckAnnotation(ctx)); - _jvmTypesBuilder.setDocumentation(it, functionName + "."); // Well, that's not very helpful, but it is what the old compiler did... - _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + jvmTypesBuilder.setDocumentation(it, functionName + "."); // Well, that's not very helpful, but it is what the old compiler did... + jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { JvmTypeReference ctxVarType1 = ctx.getContextVariable().getType(); String simpleName1 = null; if (ctxVarType1 != null) { @@ -484,24 +487,24 @@ private JvmOperation createCheckCaller(Context ctx, Check chk) { }); } - private JvmOperation createCheckMethod(Context ctx) { + private JvmOperation createCheckMethod(final Context ctx) { // Simple case for contexts of checks that do not have formal parameters. No need to generate nested classes for these. if (ctx == null || ctx.getContextVariable() == null) { return null; } String functionName = generateContextMethodName(ctx); - return _jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + return jvmTypesBuilder.toMethod(ctx, functionName, _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { String paramName = ctx.getContextVariable().getName() == null ? CheckConstants.IT : ctx.getContextVariable().getName(); - it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, paramName, ctx.getContextVariable().getType())); - it.getParameters().add(_jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); + it.getParameters().add(jvmTypesBuilder.toParameter(ctx, paramName, ctx.getContextVariable().getType())); + it.getParameters().add(jvmTypesBuilder.toParameter(ctx, "diagnosticCollector", checkedTypeRef(ctx, DiagnosticCollector.class))); Iterables.addAll(it.getAnnotations(), createCheckAnnotation(ctx)); - _jvmTypesBuilder.setDocumentation(it, functionName + "."); // Well, that's not very helpful, but it is what the old compiler did... - _jvmTypesBuilder.setBody(it, ctx.getConstraint()); + jvmTypesBuilder.setDocumentation(it, functionName + "."); // Well, that's not very helpful, but it is what the old compiler did... + jvmTypesBuilder.setBody(it, ctx.getConstraint()); }); } - private String generateContextMethodName(Context ctx) { + private String generateContextMethodName(final Context ctx) { EObject container = ctx.eContainer(); String baseName; if (container instanceof Check check) { @@ -521,7 +524,8 @@ private String generateContextMethodName(Context ctx) { // CheckCatalog - private Iterable createIssue(CheckCatalog catalog, Check check) { + // CHECKSTYLE:CHECK-OFF LambdaBodyLength + private Iterable createIssue(final CheckCatalog catalog, final Check check) { List members = Lists.newArrayList(); for (FormalParameter parameter : check.getFormalParameters()) { JvmTypeReference returnType = parameter.getType(); @@ -545,52 +549,53 @@ private Iterable createIssue(CheckCatalog catalog, Check check) { String parameterKey = CheckPropertiesGenerator.parameterKey(parameter, check); String defaultName = "null"; if (parameter.getRight() != null) { - defaultName = CheckGeneratorExtensions.splitCamelCase(_checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; + defaultName = CheckGeneratorExtensions.splitCamelCase(checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; // Is generated into the PreferenceInitializer. Actually, since we do have it in the initializer, passing it here again // as default value is just a safety measure if something went wrong and the property shouldn't be set. } - String javaDefaultValue = _checkGeneratorNaming.preferenceInitializerClassName(catalog) + "." + defaultName; - members.add(_jvmTypesBuilder.toMethod(parameter, _checkGeneratorNaming.formalParameterGetterName(parameter), returnType, (JvmOperation it) -> { - _jvmTypesBuilder.setDocumentation(it, "Gets the run-time value of formal parameter " + parameter.getName() + ". The value\nreturned is either the default as defined in the check definition, or the\nconfigured value, if existing.\n\n@param context\n the context object used to determine the current project in\n order to check if a configured value exists in a project scope\n@return the run-time value of " + parameter.getName() + ""); + String javaDefaultValue = checkGeneratorNaming.preferenceInitializerClassName(catalog) + "." + defaultName; + members.add(jvmTypesBuilder.toMethod(parameter, checkGeneratorNaming.formalParameterGetterName(parameter), returnType, (JvmOperation it) -> { + jvmTypesBuilder.setDocumentation(it, "Gets the run-time value of formal parameter " + parameter.getName() + ". The value\nreturned is either the default as defined in the check definition, or the\nconfigured value, if existing.\n\n@param context\n the context object used to determine the current project in\n order to check if a configured value exists in a project scope\n@return the run-time value of " + parameter.getName() + ""); JvmTypeReference eObjectTypeRef = checkedTypeRef(parameter, EObject.class); if (eObjectTypeRef != null) { - it.getParameters().add(_jvmTypesBuilder.toParameter(parameter, "context", eObjectTypeRef)); + it.getParameters().add(jvmTypesBuilder.toParameter(parameter, "context", eObjectTypeRef)); } - _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { appendable.append("return checkConfigurationStoreService.getCheckConfigurationStore(context)." + operation + "(\"" + parameterKey + "\", " + javaDefaultValue + ");"); }); })); } // end if } // end for - members.add(_jvmTypesBuilder.toMethod(check, "get" + StringExtensions.toFirstUpper(check.getName()) + "Message", _typeReferenceBuilder.typeRef(String.class), (JvmOperation it) -> { - _jvmTypesBuilder.setDocumentation(it, CheckJvmModelInferrerUtil.GET_MESSAGE_DOCUMENTATION); + members.add(jvmTypesBuilder.toMethod(check, "get" + StringExtensions.toFirstUpper(check.getName()) + "Message", _typeReferenceBuilder.typeRef(String.class), (JvmOperation it) -> { + jvmTypesBuilder.setDocumentation(it, CheckJvmModelInferrerUtil.GET_MESSAGE_DOCUMENTATION); // Generate one parameter "Object... bindings" it.setVarArgs(true); - it.getParameters().add(_jvmTypesBuilder.toParameter(check, "bindings", _jvmTypesBuilder.addArrayTypeDimension(_typeReferenceBuilder.typeRef(Object.class)))); - _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + it.getParameters().add(jvmTypesBuilder.toParameter(check, "bindings", jvmTypesBuilder.addArrayTypeDimension(_typeReferenceBuilder.typeRef(Object.class)))); + jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { appendable.append("return org.eclipse.osgi.util.NLS.bind(\"" + Strings.convertToJavaString(check.getMessage()) + "\", bindings);"); }); // TODO (minor): how to get NLS into the imports? })); JvmTypeReference severityType = checkedTypeRef(check, SeverityKind.class); if (severityType != null) { - members.add(_jvmTypesBuilder.toMethod(check, "get" + StringExtensions.toFirstUpper(check.getName()) + "SeverityKind", severityType, (JvmOperation it) -> { - _jvmTypesBuilder.setDocumentation(it, "Gets the {@link SeverityKind severity kind} of check\n" + check.getLabel() + ". The severity kind returned is either the\ndefault ({@code " + check.getDefaultSeverity().name() + "}), as is set in the check definition, or the\nconfigured value, if existing.\n\n@param context\n the context object used to determine the current project in\n order to check if a configured value exists in a project scope\n@return the severity kind of this check: returns the default (" + check.getDefaultSeverity().name() + ") if\n no configuration for this check was found, else the configured\n value looked up in the configuration store"); + members.add(jvmTypesBuilder.toMethod(check, "get" + StringExtensions.toFirstUpper(check.getName()) + "SeverityKind", severityType, (JvmOperation it) -> { + jvmTypesBuilder.setDocumentation(it, "Gets the {@link SeverityKind severity kind} of check\n" + check.getLabel() + ". The severity kind returned is either the\ndefault ({@code " + check.getDefaultSeverity().name() + "}), as is set in the check definition, or the\nconfigured value, if existing.\n\n@param context\n the context object used to determine the current project in\n order to check if a configured value exists in a project scope\n@return the severity kind of this check: returns the default (" + check.getDefaultSeverity().name() + ") if\n no configuration for this check was found, else the configured\n value looked up in the configuration store"); JvmTypeReference eObjectTypeRef = checkedTypeRef(check, EObject.class); if (eObjectTypeRef != null) { - it.getParameters().add(_jvmTypesBuilder.toParameter(check, "context", eObjectTypeRef)); + it.getParameters().add(jvmTypesBuilder.toParameter(check, "context", eObjectTypeRef)); } - _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { appendable.append("final int result = checkConfigurationStoreService.getCheckConfigurationStore(context).getInt(\"" + CheckPropertiesGenerator.checkSeverityKey(check) + "\", " + check.getDefaultSeverity().getValue() + ");\nreturn SeverityKind.values()[result];"); }); })); } return members; } + // CHECKSTYLE:CHECK-ON LambdaBodyLength // PreferenceInitializer. - private Iterable createFormalParameterFields(CheckCatalog catalog) { + private Iterable createFormalParameterFields(final CheckCatalog catalog) { // For each formal parameter, create a public static final field with a unique name derived from the formal parameter and // set it to its right-hand side expression. We let Java evaluate this! EList checks = catalog.getChecks(); @@ -600,12 +605,12 @@ private Iterable createFormalParameterFields(CheckCatalog catalog) { for (Check c : allChecks) { for (FormalParameter parameter : c.getFormalParameters()) { if (parameter.getType() != null && parameter.getRight() != null) { - String defaultName = CheckGeneratorExtensions.splitCamelCase(_checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; - result.add(_jvmTypesBuilder.toField(parameter, defaultName, parameter.getType(), (JvmField it) -> { + String defaultName = CheckGeneratorExtensions.splitCamelCase(checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; + result.add(jvmTypesBuilder.toField(parameter, defaultName, parameter.getType(), (JvmField it) -> { it.setVisibility(JvmVisibility.PUBLIC); it.setFinal(true); it.setStatic(true); - _jvmTypesBuilder.setInitializer(it, parameter.getRight()); + jvmTypesBuilder.setInitializer(it, parameter.getRight()); })); } } @@ -613,26 +618,27 @@ private Iterable createFormalParameterFields(CheckCatalog catalog) { return result; } - private Iterable createPreferenceInitializerMethods(CheckCatalog catalog) { + // CHECKSTYLE:CHECK-OFF LambdaBodyLength + private Iterable createPreferenceInitializerMethods(final CheckCatalog catalog) { JvmTypeReference prefStore = checkedTypeRef(catalog, IEclipsePreferences.class); List result = Lists.newArrayList(); if (prefStore != null) { - result.add(_jvmTypesBuilder.toMethod(catalog, "initializeDefaultPreferences", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + result.add(jvmTypesBuilder.toMethod(catalog, "initializeDefaultPreferences", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { Iterables.addAll(it.getAnnotations(), createAnnotation(checkedTypeRef(catalog, Override.class), (JvmAnnotationReference it1) -> { })); it.setVisibility(JvmVisibility.PUBLIC); - _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { appendable.append("IEclipsePreferences preferences = org.eclipse.core.runtime.preferences.InstanceScope.INSTANCE.getNode(RUNTIME_NODE_NAME);\n\ninitializeSeverities(preferences);\ninitializeFormalParameters(preferences);"); }); })); EList checks = catalog.getChecks(); Iterable flattenedCatChecks = Iterables.concat(ListExtensions.>map(catalog.getCategories(), (Category cat) -> cat.getChecks())); Iterable allChecks = Iterables.concat(checks, flattenedCatChecks); - result.add(_jvmTypesBuilder.toMethod(catalog, "initializeSeverities", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + result.add(jvmTypesBuilder.toMethod(catalog, "initializeSeverities", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { it.setVisibility(JvmVisibility.PRIVATE); - it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "preferences", prefStore)); - _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + it.getParameters().add(jvmTypesBuilder.toParameter(catalog, "preferences", prefStore)); + jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { StringBuilder sb = new StringBuilder(); for (Check c : allChecks) { sb.append("preferences.putInt(\"").append(CheckPropertiesGenerator.checkSeverityKey(c)).append("\", ").append(c.getDefaultSeverity().getValue()).append(");\n"); @@ -640,15 +646,15 @@ private Iterable createPreferenceInitializerMethods(CheckCatalog cata appendable.append(sb.toString()); }); })); - result.add(_jvmTypesBuilder.toMethod(catalog, "initializeFormalParameters", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { + result.add(jvmTypesBuilder.toMethod(catalog, "initializeFormalParameters", _typeReferenceBuilder.typeRef("void"), (JvmOperation it) -> { it.setVisibility(JvmVisibility.PRIVATE); - it.getParameters().add(_jvmTypesBuilder.toParameter(catalog, "preferences", _jvmTypesBuilder.cloneWithProxies(prefStore))); - _jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { + it.getParameters().add(jvmTypesBuilder.toParameter(catalog, "preferences", jvmTypesBuilder.cloneWithProxies(prefStore))); + jvmTypesBuilder.setBody(it, (ITreeAppendable appendable) -> { for (Check c : allChecks) { for (FormalParameter parameter : c.getFormalParameters()) { if (parameter.getRight() != null) { String key = CheckPropertiesGenerator.parameterKey(parameter, c); - String defaultFieldName = CheckGeneratorExtensions.splitCamelCase(_checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; + String defaultFieldName = CheckGeneratorExtensions.splitCamelCase(checkGeneratorNaming.formalParameterGetterName(parameter)).toUpperCase() + "_DEFAULT"; JvmTypeReference jvmType = parameter.getType(); String typeName = jvmType.getQualifiedName(); if (typeName != null && typeName.startsWith("java.util.List<")) { @@ -661,9 +667,9 @@ private Iterable createPreferenceInitializerMethods(CheckCatalog cata appendable.append("// Found " + key + " with " + typeName + "\n"); } } else { - String operation; + String prefOperation; if (typeName != null) { - operation = switch (typeName) { + prefOperation = switch (typeName) { case "java.lang.Boolean" -> "putBoolean"; case "boolean" -> "putBoolean"; case "java.lang.Integer" -> "putInt"; @@ -671,9 +677,9 @@ private Iterable createPreferenceInitializerMethods(CheckCatalog cata default -> "put"; }; } else { - operation = "put"; + prefOperation = "put"; } - appendable.append("preferences." + operation + "(\"" + key + "\", " + defaultFieldName + ");\n"); + appendable.append("preferences." + prefOperation + "(\"" + key + "\", " + defaultFieldName + ");\n"); } } } @@ -683,8 +689,10 @@ private Iterable createPreferenceInitializerMethods(CheckCatalog cata } return result; } + // CHECKSTYLE:CHECK-ON LambdaBodyLength + // CHECKSTYLE:CONSTANTS-ON - private Iterable createAnnotation(JvmTypeReference typeRef, Procedure1 initializer) { + private Iterable createAnnotation(final JvmTypeReference typeRef, final Procedure1 initializer) { if (typeRef == null) { return Collections.emptyList(); } @@ -698,7 +706,7 @@ private Iterable createAnnotation(JvmTypeReference typeR // Error handling etc. - private void createError(String message, EObject context, EStructuralFeature feature) { + private void createError(final String message, final EObject context, final EStructuralFeature feature) { Resource rsc = context.eResource(); if (rsc != null) { EStructuralFeature f = feature; @@ -709,11 +717,11 @@ private void createError(String message, EObject context, EStructuralFeature fea } } - private void createTypeNotFoundError(String name, EObject context) { + private void createTypeNotFoundError(final String name, final EObject context) { createError("Type " + name + " not found; check project setup (missing required bundle?)", context, null); } - private JvmTypeReference checkedTypeRef(EObject context, Class clazz) { + private JvmTypeReference checkedTypeRef(final EObject context, final Class clazz) { if (clazz == null) { createTypeNotFoundError("", context); return null; @@ -726,13 +734,11 @@ private JvmTypeReference checkedTypeRef(EObject context, Class clazz) { return result; } - public void infer(EObject catalog, IJvmDeclaredTypeAcceptor acceptor, boolean preIndexingPhase) { + public void infer(final EObject catalog, final IJvmDeclaredTypeAcceptor acceptor, final boolean preIndexingPhase) { if (catalog instanceof CheckCatalog checkCatalog) { _infer(checkCatalog, acceptor, preIndexingPhase); - return; } else if (catalog != null) { _infer(catalog, acceptor, preIndexingPhase); - return; } else { throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(catalog, acceptor, preIndexingPhase).toString()); diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.java index 36a7a159cd..73c8cffbe7 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/scoping/CheckScopeProvider.java @@ -59,6 +59,7 @@ import org.eclipse.xtext.xbase.lib.ListExtensions; import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver; +@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"}) public class CheckScopeProvider extends XbaseWithAnnotationsBatchScopeProvider { @Inject @@ -80,7 +81,7 @@ public class CheckScopeProvider extends XbaseWithAnnotationsBatchScopeProvider { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=368263 // will otherwise cause the builder to fail during linking. @Override - public IScope getScope(EObject context, EReference reference) { + public IScope getScope(final EObject context, final EReference reference) { IScope res = scope(context, reference); if (res != null) { return res; @@ -89,7 +90,7 @@ public IScope getScope(EObject context, EReference reference) { } } - protected IScope _scope(XIssueExpression context, EReference reference) { + protected IScope _scope(final XIssueExpression context, final EReference reference) { if (reference == CheckPackage.Literals.XISSUE_EXPRESSION__MARKER_FEATURE) { JvmTypeReference jvmTypeRef; if (context.getMarkerObject() != null) { @@ -128,9 +129,10 @@ protected IScope _scope(XIssueExpression context, EReference reference) { return null; } - protected IScope _scope(CheckCatalog context, EReference reference) { + protected IScope _scope(final CheckCatalog context, final EReference reference) { if (reference == CheckPackage.Literals.CHECK_CATALOG__GRAMMAR) { IResourceServiceProvider.Registry reg = IResourceServiceProvider.Registry.INSTANCE; + // CHECKSTYLE:CHECK-OFF IllegalCatch Collection descriptions = Collections2.transform(reg.getExtensionToFactoryMap().keySet(), (String e) -> { URI dummyUri = URI.createURI("foo:/foo." + e); @@ -141,9 +143,9 @@ protected IScope _scope(CheckCatalog context, EReference reference) { return null; } }); + // CHECKSTYLE:CHECK-ON IllegalCatch // We look first in the workspace for a grammar and then in the registry for a registered grammar - IScope parentScope = MapBasedScope.createScope(IScope.NULLSCOPE, Iterables.filter(descriptions, Predicates.notNull())); - return parentScope; + return MapBasedScope.createScope(IScope.NULLSCOPE, Iterables.filter(descriptions, Predicates.notNull())); } else if (reference == CheckPackage.Literals.XISSUE_EXPRESSION__CHECK) { List descriptions = ListExtensions.map(context.getAllChecks(), (Check c) -> EObjectDescription.create(checkQualifiedNameProvider.getFullyQualifiedName(c), c)); @@ -153,11 +155,11 @@ protected IScope _scope(CheckCatalog context, EReference reference) { } // default implementation will throw an illegal argument exception - protected IScope _scope(EObject context, EReference reference) { + protected IScope _scope(final EObject context, final EReference reference) { return null; } - public IScope scope(EObject context, EReference reference) { + public IScope scope(final EObject context, final EReference reference) { if (context instanceof CheckCatalog) { return _scope((CheckCatalog) context, reference); } else if (context instanceof XIssueExpression) { @@ -170,11 +172,11 @@ public IScope scope(EObject context, EReference reference) { } } - public EClass classForJvmType(EObject context, JvmType jvmType) { + public EClass classForJvmType(final EObject context, final JvmType jvmType) { if (jvmType != null && !jvmType.eIsProxy()) { String qualifiedName = jvmType.getQualifiedName(); - String qualifiedPackageName = qualifiedName.substring(0, qualifiedName.lastIndexOf(".")); - String packageName = qualifiedPackageName.substring(qualifiedPackageName.lastIndexOf(".") + 1); + String qualifiedPackageName = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')); + String packageName = qualifiedPackageName.substring(qualifiedPackageName.lastIndexOf('.') + 1); EPackage ePackage = getEPackage(context.eResource(), packageName); if (ePackage != null) { EClassifier eClassifier = ((EPackage) EcoreUtil.resolve(ePackage, context)).getEClassifier(jvmType.getSimpleName()); @@ -186,7 +188,7 @@ public EClass classForJvmType(EObject context, JvmType jvmType) { return null; } - public EPackage getEPackage(Resource context, String name) { + public EPackage getEPackage(final Resource context, final String name) { // not using for-each loop, as it could result in a ConcurrentModificationException when a resource is demand-loaded EList resources = context.getResourceSet().getResources(); for (int i = 0; i < resources.size(); i++) { diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.java index 4efa5a7b53..b23635d95c 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/typing/CheckTypeComputer.java @@ -19,10 +19,11 @@ import org.eclipse.xtext.xbase.annotations.typesystem.XbaseWithAnnotationsTypeComputer; import org.eclipse.xtext.xbase.typesystem.computation.ITypeComputationState; +@SuppressWarnings({"checkstyle:MethodName"}) public class CheckTypeComputer extends XbaseWithAnnotationsTypeComputer { @Override - public void computeTypes(XExpression expression, ITypeComputationState state) { + public void computeTypes(final XExpression expression, final ITypeComputationState state) { if (expression instanceof XIssueExpression) { _computeTypes((XIssueExpression) expression, state); } else if (expression instanceof XGuardExpression) { @@ -34,7 +35,7 @@ public void computeTypes(XExpression expression, ITypeComputationState state) { } } - protected void _computeTypes(XIssueExpression expression, ITypeComputationState state) { + protected void _computeTypes(final XIssueExpression expression, final ITypeComputationState state) { if (expression.getMarkerObject() != null) { state.withExpectation(getTypeForName(EObject.class, state)).computeTypes(expression.getMarkerObject()); } @@ -53,7 +54,7 @@ protected void _computeTypes(XIssueExpression expression, ITypeComputationState state.acceptActualType(getPrimitiveVoid(state)); } - protected void _computeTypes(XGuardExpression expression, ITypeComputationState state) { + protected void _computeTypes(final XGuardExpression expression, final ITypeComputationState state) { state.withExpectation(getTypeForName(Boolean.class, state)).computeTypes(expression.getGuard()); state.acceptActualType(getPrimitiveVoid(state)); } diff --git a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java index d0c9fbf31c..d9567dae2b 100644 --- a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java +++ b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java @@ -37,6 +37,7 @@ * Test quickfixes for Check files. */ @SuppressWarnings("nls") +// CHECKSTYLE:CONSTANTS-OFF public class CheckQuickfixTest extends AbstractCheckQuickfixTest { private static final String PACKAGE_NAME = "com.avaloq.test"; @@ -45,11 +46,11 @@ public class CheckQuickfixTest extends AbstractCheckQuickfixTest { private boolean oldAutoBuildState; public String getTestSourceFileName(final String catalogName) { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append(PACKAGE_NAME.replace(".", "/")); - builder.append("/"); + builder.append('/'); builder.append(catalogName); - builder.append("."); + builder.append('.'); builder.append(getXtextTestUtil().getFileExtension()); return builder.toString(); } @@ -97,11 +98,11 @@ private void cleanUp() { @Test @BugTest(value = "DSL-244") public void testImportFix() { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("package "); builder.append(PACKAGE_NAME); - builder.append("\n"); - builder.append("\n"); + builder.append('\n'); + builder.append('\n'); builder.append("catalog "); builder.append(getTestSourceModelName()); builder.append(" for grammar org.eclipse.xtext.Xtext\n"); @@ -130,32 +131,32 @@ public void testImportFix() { @Test public void testAddID() { // ARRANGE - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("package "); builder.append(PACKAGE_NAME); - builder.append("\n"); - builder.append("\n"); + builder.append('\n'); + builder.append('\n'); builder.append("catalog "); builder.append(getTestSourceModelName()); - builder.append("\n"); + builder.append('\n'); builder.append("for grammar org.eclipse.xtext.Xtext {\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" warning \"Test Warning\"\n"); builder.append(" message \"This is a Test Warning\" {\n"); builder.append(" }\n"); builder.append("}\n"); final String sourceContent = builder.toString(); - StringBuilder builder2 = new StringBuilder(); + StringBuilder builder2 = new StringBuilder(512); builder2.append("package "); builder2.append(PACKAGE_NAME); - builder2.append("\n"); - builder2.append("\n"); + builder2.append('\n'); + builder2.append('\n'); builder2.append("catalog "); builder2.append(getTestSourceModelName()); - builder2.append("\n"); + builder2.append('\n'); builder2.append("for grammar org.eclipse.xtext.Xtext {\n"); - builder2.append("\n"); + builder2.append('\n'); builder2.append(" warning TestWarning \"Test Warning\"\n"); builder2.append(" message \"This is a Test Warning\" {\n"); builder2.append(" }\n"); @@ -187,17 +188,17 @@ public void testBulkApplyingQuickfix() { // Add catalogs containing multiple instances of the same quickfixable marker for (final String catalogName : catalogNames) { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new StringBuilder(512); builder.append("package "); builder.append(PACKAGE_NAME); - builder.append("\n"); - builder.append("\n"); + builder.append('\n'); + builder.append('\n'); builder.append("catalog "); builder.append(catalogName); - builder.append("\n"); + builder.append('\n'); builder.append("for grammar org.eclipse.xtext.Xtext {\n"); for (final String checkLabel : checkLabels) { - builder.append("\n"); + builder.append('\n'); builder.append(" live error \""); builder.append(checkLabel); builder.append("\"\n"); @@ -238,3 +239,4 @@ public void testBulkApplyingQuickfix() { } } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java index e008b56e83..c1e619867b 100644 --- a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java +++ b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java @@ -12,6 +12,7 @@ import org.eclipse.xtext.generator.IFileSystemAccess; +// CHECKSTYLE:CONSTANTS-OFF public class CheckNewProject { public void doGenerate(final CheckProjectInfo info, final IFileSystemAccess fsa) { @@ -23,20 +24,20 @@ public String fileName(final CheckProjectInfo info) { } public CharSequence fileContent(final CheckProjectInfo info) { - final StringBuilder builder = new StringBuilder(); - builder.append("package ").append(info.getPackageName()).append("\n"); - builder.append("\n"); + final StringBuilder builder = new StringBuilder(512); + builder.append("package ").append(info.getPackageName()).append('\n'); + builder.append('\n'); builder.append(fileImports(info)); - builder.append("\n"); - builder.append("\n"); + builder.append('\n'); + builder.append('\n'); builder.append("/**\n"); - builder.append(" * Check catalog for ").append(info.getGrammar().getName()).append("\n"); + builder.append(" * Check catalog for ").append(info.getGrammar().getName()).append('\n'); builder.append(" */\n"); - builder.append("catalog ").append(info.getCatalogName()).append("\n"); + builder.append("catalog ").append(info.getCatalogName()).append('\n'); builder.append("for grammar ").append(info.getGrammar().getName()).append(" {\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" // Add categories and checks\n"); - builder.append("\n"); + builder.append('\n'); builder.append("}\n"); return builder; } @@ -50,3 +51,4 @@ public CharSequence fileImports(final CheckProjectInfo info) { } } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java index 01812e8f79..63b53cac72 100644 --- a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java +++ b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java @@ -12,6 +12,7 @@ import org.eclipse.xtext.generator.IFileSystemAccess; +// CHECKSTYLE:CONSTANTS-OFF public class CheckQuickfixProvider { public void doGenerate(final CheckProjectInfo info, final IFileSystemAccess fsa) { @@ -23,11 +24,11 @@ public String fileName(final CheckProjectInfo info) { } public CharSequence fileContent(final CheckProjectInfo info) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(2048); builder.append("package ").append(info.getPackageName()).append(";\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreQuickfixProvider;\n"); - builder.append("\n"); + builder.append('\n'); builder.append("/**\n"); builder.append(" * Default quickfix provider for ").append(info.getCatalogName()).append(".\n"); builder.append(" *

    \n"); @@ -36,7 +37,7 @@ public CharSequence fileContent(final CheckProjectInfo info) { builder.append(" *

    \n"); builder.append(" */\n"); builder.append("public class ").append(info.getCatalogName()).append("QuickfixProvider implements ICoreQuickfixProvider {\n"); - builder.append("\n"); + builder.append('\n'); builder.append("// @CoreFix(value = MyIssueCodes.NAME_ENTITY_0)\n"); builder.append("// public void fixEntityNameFirstUpper(final Issue issue,\n"); builder.append("// ICoreIssueResolutionAcceptor acceptor) {\n"); @@ -55,8 +56,9 @@ public CharSequence fileContent(final CheckProjectInfo info) { builder.append("// }\n"); builder.append("// });\n"); builder.append("// }\n"); - builder.append("\n"); + builder.append('\n'); builder.append("}\n"); return builder; } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java index 7090d26552..8bdde50623 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java @@ -31,6 +31,7 @@ @ExtendWith(InjectionExtension.class) @InjectWith(CheckCfgUiInjectorProvider.class) +// CHECKSTYLE:CONSTANTS-OFF public class CheckCfgContentAssistTest extends AbstractAcfContentAssistTest { @Override @@ -58,7 +59,7 @@ protected void afterAllTests() { @Test public void testConfiguredParameterProposals() { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("check configuration Test {\n"); builder.append(" catalog TestChecks {\n"); builder.append(" default Test (\n"); @@ -71,7 +72,7 @@ public void testConfiguredParameterProposals() { @BugTest(value = "DSL-1811", unresolved = true) public void testNoTypeMismatchedParameterValueProposals() { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("check configuration Test {\n"); builder.append(" catalog TestChecks {\n"); builder.append(" default Test (\n"); @@ -82,3 +83,4 @@ public void testNoTypeMismatchedParameterValueProposals() { assertKernelSourceProposals("NoTypeMismatchedParameterValueProposals.checkcfg", builder); } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java index 7b9c59886a..5b6035896d 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java @@ -44,25 +44,26 @@ protected void registerRequiredSources() { *

    */ @BugTest(value = "DSL-1498") + @SuppressWarnings("PMD.SignatureDeclareThrowsException") // test method public void testCatalogsAreInCorrectPackage() throws Exception { // ARRANGE - final List EXP_PACKAGE_NAME_PREFIX = List.of("com", "avaloq", "tools", "ddk"); + final List expPackageNamePrefix = List.of("com", "avaloq", "tools", "ddk"); // Define test data - final int CURSOR_POS = getTag(); - final StringBuilder sourceBuilder = new StringBuilder(); + final int cursorPos = getTag(); + final StringBuilder sourceBuilder = new StringBuilder(512); sourceBuilder.append("check configuration testCheckCfg {\n"); - sourceBuilder.append(" ").append(mark(CURSOR_POS)).append("\n"); + sourceBuilder.append(" ").append(mark(cursorPos)).append('\n'); sourceBuilder.append("}\n"); - final String SOURCE_CONTENT = sourceBuilder.toString(); + final String sourceContent = sourceBuilder.toString(); // Register a check configuration source, and get a context model - registerModel(getTestSourceFileName(), SOURCE_CONTENT); - final EObject context = getMarkerTagsInfo().getModel(CURSOR_POS); + registerModel(getTestSourceFileName(), sourceContent); + final EObject context = getMarkerTagsInfo().getModel(cursorPos); if (null == context) { - throw new NullPointerException("Got null context model"); + throw new IllegalStateException("Got null context model"); } // ACT @@ -70,7 +71,7 @@ public void testCatalogsAreInCorrectPackage() throws Exception { // Get catalogs final Iterable elements = scopeProvider.getScope(context, CheckcfgPackage.Literals.CONFIGURED_CATALOG__CATALOG).getAllElements(); if (!elements.iterator().hasNext()) { - throw new Exception("Scope has no elements"); + throw new IllegalStateException("Scope has no elements"); } // ASSERT @@ -78,8 +79,8 @@ public void testCatalogsAreInCorrectPackage() throws Exception { elements.forEach((IEObjectDescription element) -> { // Check catalog has the correct fully-qualified package name final List actualName = element.getName().getSegments(); - final List actualPackageName = actualName.subList(0, EXP_PACKAGE_NAME_PREFIX.size()); - assertArrayEquals(EXP_PACKAGE_NAME_PREFIX.toArray(), actualPackageName.toArray(), "Catalog must have the correct fully-qualified package name"); + final List actualPackageName = actualName.subList(0, expPackageNamePrefix.size()); + assertArrayEquals(expPackageNamePrefix.toArray(), actualPackageName.toArray(), "Catalog must have the correct fully-qualified package name"); }); } } diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java index 4f4e2f33f4..07d4fff82e 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +// CHECKSTYLE:CONSTANTS-OFF public class CheckCfgSyntaxTest extends AbstractValidationTest { @Override @@ -34,11 +35,11 @@ protected List getRequiredSourceFileNames() { @BeforeAll public void setup() { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("package checkcfgtest\n"); - builder.append("\n"); + builder.append('\n'); builder.append("import com.avaloq.tools.ddk.check.check.Check\n"); - builder.append("\n"); + builder.append('\n'); builder.append("catalog CheckCfgTestChecks\n"); builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); builder.append(" /**\n"); @@ -58,7 +59,7 @@ public void setup() { @Test public void testSyntax() { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(256); builder.append("check configuration checkconfiguration {\n"); builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); builder.append(" default TestError\n"); @@ -70,7 +71,7 @@ public void testSyntax() { @Test public void testSyntaxConfiguredLanguage() { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(256); builder.append("check configuration checkconfiguration\n"); builder.append(" for com.avaloq.tools.ddk.^check.TestLanguage {\n"); builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); @@ -83,14 +84,14 @@ public void testSyntaxConfiguredLanguage() { @Test public void testPropertiesOnAllLevels() { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("check configuration checkconfiguration\n"); builder.append(" integrationRelevant = true\n"); builder.append(" testBooleanList = #[true, false, false]\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" for com.avaloq.tools.ddk.^check.TestLanguage {\n"); builder.append(" nameOverrides = #['altName1', 'altName2']\n"); - builder.append("\n"); + builder.append('\n'); builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); builder.append(" default TestError(testNumber = 3, testNumberList = #[1, 2, 3])\n"); builder.append(" }\n"); @@ -99,3 +100,4 @@ public void testPropertiesOnAllLevels() { validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource); } } +// CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.java index 6997192f55..3a1cfaf046 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgConfiguredParameterValidationsTest.java @@ -54,11 +54,11 @@ protected void afterAllTests() { public void testConfiguredParameterValues() { final TestPropertySpecificationWithExpectedValues allowedOnly = TestPropertySpecificationWithExpectedValues.INSTANCE; final TestPropertySpecificationWithOutExpectedValues acceptsAny = TestPropertySpecificationWithOutExpectedValues.INSTANCE; - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("check configuration Test\n"); builder.append(" ").append(allowedOnly.getName()).append(" = ").append(error(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)).append("\"notAllowed\"\n"); builder.append(" for com.avaloq.tools.ddk.^check.TestLanguage {\n"); - builder.append(" ").append(allowedOnly.getName()).append(" = ").append(noDiagnostic(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)).append("\"").append(allowedOnly.getExpectedValues()[0]).append("\"\n"); + builder.append(" ").append(allowedOnly.getName()).append(" = ").append(noDiagnostic(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)).append('"').append(allowedOnly.getExpectedValues()[0]).append("\"\n"); builder.append(" ").append(acceptsAny.getName()).append(" = ").append(noDiagnostic(IssueCodes.PARAMETER_VALUE_NOT_ALLOWED)).append("\"whatever\"\n"); builder.append(" }\n"); validateKernelSourceStrictly("ConfiguredParameterValues.checkcfg", builder); diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.java index 040e857ede..f4be5ecb85 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.java +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.java @@ -30,6 +30,7 @@ public String outputPath() { return ".settings"; } + @SuppressWarnings("PMD.UnusedFormalParameter") // parameter kept for API consistency public String fileName(final CheckConfiguration configuration) { return ICheckConfigurationStoreService.DEFAULT_CHECK_CONFIGURATION_NODE + ".prefs"; } @@ -48,7 +49,7 @@ public CharSequence compile(final CheckConfiguration config) { final Properties properties = propertiesGenerator.convertToProperties(config); final StringBuilder builder = new StringBuilder(); for (final Object k : properties.keySet()) { - builder.append(k).append("=").append(properties.get(k)).append("\n"); + builder.append(k).append('=').append(properties.get(k)).append('\n'); } return builder; } diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.java index 2ac14f51c1..ba69d5f89a 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.java +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/jvmmodel/CheckCfgJvmModelInferrer.java @@ -35,13 +35,13 @@ public void _infer(final EObject element, final IJvmDeclaredTypeAcceptor accepto // Here you explain how your model is mapped to Java elements, by writing the actual translation code. // An example based on the initial hellow world example could look like this: -// acceptor.accept(element.toClass("my.company.greeting.MyGreetings") [ -// for (greeting : element.greetings) { -// members += greeting.toMethod(greeting.name, greeting.newTypeRef(typeof(String))) [ -// it.body [''' -// return "Hello «greeting.name»"; -// '''] -// ] -// } -// ]) +// acceptor.accept(element.toClass("my.company.greeting.MyGreetings") [ +// for (greeting : element.greetings) { +// members += greeting.toMethod(greeting.name, greeting.newTypeRef(typeof(String))) [ +// it.body [''' +// return "Hello «greeting.name»"; +// '''] +// ] +// } +// ]) } diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java index 109526bfb0..0338a7809d 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java @@ -78,22 +78,14 @@ public EList getProperties(final CheckConfiguration checkConfig } public JvmTypeReference inferType(final ICheckCfgPropertySpecification contribution, final JvmTypeReferenceBuilder referenceBuilder) { - switch (contribution.getType()) { - case BOOLEAN: - return referenceBuilder.typeRef(BOOLEAN); - case NUMBER: - return referenceBuilder.typeRef(NUMBER); - case STRING: - return referenceBuilder.typeRef(STRING); - case NUMBERS: - return referenceBuilder.typeRef(NUMBER_LIST); - case STRINGS: - return referenceBuilder.typeRef(STRING_LIST); - case BOOLEANS: - return referenceBuilder.typeRef(BOOLEAN_LIST); - default: - return null; - } + return switch (contribution.getType()) { + case BOOLEAN -> referenceBuilder.typeRef(BOOLEAN); + case NUMBER -> referenceBuilder.typeRef(NUMBER); + case STRING -> referenceBuilder.typeRef(STRING); + case NUMBERS -> referenceBuilder.typeRef(NUMBER_LIST); + case STRINGS -> referenceBuilder.typeRef(STRING_LIST); + case BOOLEANS -> referenceBuilder.typeRef(BOOLEAN_LIST); + }; } public JvmTypeReference inferListType(final XListLiteral newValue, final JvmTypeReferenceBuilder referenceBuilder) { diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.java index 5e2bd8b823..e0dd2d96cd 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.java +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/ConfiguredParameterChecks.java @@ -35,7 +35,7 @@ public class ConfiguredParameterChecks extends FormalParameterCheckBase { /** * Verifies that numeric literals in the default values of formal parameters are all integral values. - * @param parameterto check. + * @param parameter the configured parameter to check. */ @Check public void checkFormalParameterNumbersAreIntegers(final ConfiguredParameter parameter) { diff --git a/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.java b/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.java index 093fb16267..6462aaa982 100644 --- a/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.java +++ b/com.avaloq.tools.ddk.xtext.export.generator/src/com/avaloq/tools/ddk/xtext/export/generator/ExportFragment2.java @@ -29,7 +29,7 @@ public class ExportFragment2 extends AbstractXtextGeneratorFragment { @Inject - private XtextGeneratorNaming _xtextGeneratorNaming; + private XtextGeneratorNaming xtextGeneratorNaming; private boolean hasExports = true; @@ -38,9 +38,9 @@ public class ExportFragment2 extends AbstractXtextGeneratorFragment { */ private static final Logger LOGGER = LogManager.getLogger(ExportFragment2.class); - private final String DDK_XTEXT_RUNTIME_BUNDLE = "com.avaloq.tools.ddk.xtext"; + private static final String DDK_XTEXT_RUNTIME_BUNDLE = "com.avaloq.tools.ddk.xtext"; - public void setHasExports(boolean hasExports) { + public void setHasExports(final boolean hasExports) { this.hasExports = hasExports; } @@ -49,9 +49,9 @@ public void generate() { if (LOGGER.isInfoEnabled()) { LOGGER.info("executing generate for " + getClass().getName()); } - final String namingPackage = _xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".naming"; + final String namingPackage = xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".naming"; final String namingPrefix = namingPackage + "." + GrammarUtil.getSimpleName(getGrammar()); - final String resourcePackage = _xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".resource"; + final String resourcePackage = xtextGeneratorNaming.getRuntimeBasePackage(getGrammar()) + ".resource"; final String resourcePrefix = resourcePackage + "." + GrammarUtil.getSimpleName(getGrammar()); if (hasExports) { diff --git a/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.java b/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.java index 63580874de..53614efcb9 100644 --- a/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.java +++ b/com.avaloq.tools.ddk.xtext.format.generator/src/com/avaloq/tools/ddk/xtext/format/generator/FormatFragment2.java @@ -148,13 +148,14 @@ protected void doGenerateStubFiles() { } } + // CHECKSTYLE:CONSTANTS-OFF protected XtendFileAccess doGetXtendStubFile() { final XtendFileAccess xtendFile = fileAccessFactory.createXtendFile(getFormatterStub(getGrammar())); xtendFile.setResourceSet(getLanguage().getResourceSet()); xtendFile.setContent(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation builder) { + protected void appendTo(final TargetStringConcatenation builder) { builder.append("import com.avaloq.tools.ddk.xtext.formatting.ExtendedLineEntry"); builder.newLine(); builder.append("import java.util.List"); @@ -238,7 +239,7 @@ protected JavaFileAccess doGetJavaStubFile() { javaFile.setContent(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation builder) { + protected void appendTo(final TargetStringConcatenation builder) { builder.append("import com.avaloq.tools.ddk.xtext.formatting.ExtendedLineEntry;"); builder.newLine(); builder.append("import java.util.List;"); @@ -333,7 +334,7 @@ protected TextFileAccess doGetFormatStubFile() { formatFile.setContent(new StringConcatenationClient() { @Override - protected void appendTo(TargetStringConcatenation builder) { + protected void appendTo(final TargetStringConcatenation builder) { builder.append("formatter for "); builder.append(getGrammar().getName()); builder.newLineIfNotEmpty(); @@ -342,4 +343,5 @@ protected void appendTo(TargetStringConcatenation builder) { }); return formatFile; } + // CHECKSTYLE:CONSTANTS-ON } diff --git a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java index a1a62f8cf9..1c6fdcc2a1 100644 --- a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java +++ b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java @@ -47,12 +47,13 @@ @ExtendWith(InjectionExtension.class) public class XbaseGeneratorFragmentTest { + // CHECKSTYLE:CONSTANTS-OFF @RegisterExtension - public BugTestAwareRule bugTestRule = BugTestAwareRule.getInstance(); + private final BugTestAwareRule bugTestRule = BugTestAwareRule.getInstance(); - private final String thisPackageName = "thisPackage"; - private final String xtypePackageName = "xtype"; - private final String xImportSectionRuleName = "XImportSection"; + private static final String THIS_PACKAGE_NAME = "thisPackage"; + private static final String XTYPE_PACKAGE_NAME = "xtype"; + private static final String X_IMPORT_SECTION_RULE_NAME = "XImportSection"; private final XbaseUsageDetector detector = new XbaseUsageDetector(); @@ -132,7 +133,7 @@ private void setExpectationsForUsesXImportSection(final Grammar mockGrammar, fin when(mockGrammar.getUsedGrammars()).thenReturn(new BasicEList()); // Calls made per rule by XbaseGeneratorFragmentOverride.usesXImportSection.apply() - setExpectationsForApply(mockRootRule, thisPackageName, "rootRule"); + setExpectationsForApply(mockRootRule, THIS_PACKAGE_NAME, "rootRule"); Iterator mockLeafRuleIterator = mockLeafRules.iterator(); Iterator> packageAndRuleNameIterator = Arrays.asList(packageAndRuleNamesOfLeafRules).iterator(); @@ -168,10 +169,10 @@ public void testUsesXImportSectionWhenNotUsed() { setExpectationsForUsesXImportSection( mockGrammar, Pair.of(null, "leafRule1"), - Pair.of(thisPackageName, "leafRule2"), - Pair.of(xtypePackageName, "leafRule3"), - Pair.of(null, xImportSectionRuleName), - Pair.of(thisPackageName, xImportSectionRuleName) + Pair.of(THIS_PACKAGE_NAME, "leafRule2"), + Pair.of(XTYPE_PACKAGE_NAME, "leafRule3"), + Pair.of(null, X_IMPORT_SECTION_RULE_NAME), + Pair.of(THIS_PACKAGE_NAME, X_IMPORT_SECTION_RULE_NAME) ); // ACT @@ -194,11 +195,11 @@ public void testUsesXImportSectionWhenUsed() { setExpectationsForUsesXImportSection( mockGrammar, Pair.of(null, "leafRule1"), - Pair.of(thisPackageName, "leafRule2"), - Pair.of(xtypePackageName, "leafRule3"), - Pair.of(null, xImportSectionRuleName), - Pair.of(thisPackageName, xImportSectionRuleName), - Pair.of(xtypePackageName, xImportSectionRuleName) + Pair.of(THIS_PACKAGE_NAME, "leafRule2"), + Pair.of(XTYPE_PACKAGE_NAME, "leafRule3"), + Pair.of(null, X_IMPORT_SECTION_RULE_NAME), + Pair.of(THIS_PACKAGE_NAME, X_IMPORT_SECTION_RULE_NAME), + Pair.of(XTYPE_PACKAGE_NAME, X_IMPORT_SECTION_RULE_NAME) ); // ACT @@ -207,5 +208,6 @@ public void testUsesXImportSectionWhenUsed() { // ASSERT assertTrue(usesXImportSection, "usesXImportSection() should return true when the grammar uses XImportSection"); } + // CHECKSTYLE:CONSTANTS-ON } diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java index d45de6b2c3..5002a8487e 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java @@ -267,7 +267,7 @@ protected CharSequence compileRules(final Grammar g, final AntlrOptions options) GrammarUtil.getAllGroups(g)), GrammarUtil.getAllUnorderedGroups(g)), GrammarUtil.getAllAssignments(g)), - (EObject it) -> Boolean.valueOf(this._grammarAccessExtensions.isCalled(GrammarUtil.containingRule(it), g))); + (EObject it) -> this._grammarAccessExtensions.isCalled(GrammarUtil.containingRule(it), g)); for (final EObject rule : allRulesAndElements) { builder.newLine(); builder.append(this.compileRule(rule, g, options)); From 9b443d07e11c2613f630c97404205e61b87e8f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 19:45:37 +0100 Subject: [PATCH 17/23] style: fix remaining PMD violations (StringToString, UnnecessaryCast, MissingOverride, LooseCoupling) Co-Authored-By: Claude Opus 4.6 --- .../tools/ddk/check/generator/CheckGeneratorNaming.java | 2 +- .../tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java | 3 ++- .../generator/xbase/test/XbaseGeneratorFragmentTest.java | 8 ++++---- ...AnnotationAwareAntlrContentAssistGrammarGenerator.java | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java index f5248e31c2..e5cabd3e8e 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorNaming.java @@ -162,7 +162,7 @@ public String qualifiedDefaultValidatorClassName() { /* Gets the prefix for the context id (used in contexts.xml) */ public String getContextIdPrefix(final QualifiedName catalog) { - return catalog.getLastSegment().toString().toLowerCase() + "_"; // TODO make context id use fully qualified catalog names + return catalog.getLastSegment().toLowerCase() + "_"; // TODO make context id use fully qualified catalog names } /* Gets the full context id (used in contexts.xml) */ diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java index d1d8e96106..46cfaf00d7 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/jvmmodel/CheckJvmModelInferrer.java @@ -375,7 +375,7 @@ private Iterable createInjectedField(final CheckCatalog context, final private Iterable createCheck(final Check chk) { // If we don't have FormalParameters, there's no need to do all this song and dance with inner classes. if (chk.getFormalParameters().isEmpty()) { - return ListExtensions.map(chk.getContexts(), (Context ctx) -> (JvmMember) createCheckMethod(ctx)); + return ListExtensions.map(chk.getContexts(), (Context ctx) -> createCheckMethod(ctx)); } else { return createCheckWithParameters(chk); } @@ -734,6 +734,7 @@ private JvmTypeReference checkedTypeRef(final EObject context, final Class cl return result; } + @Override public void infer(final EObject catalog, final IJvmDeclaredTypeAcceptor acceptor, final boolean preIndexingPhase) { if (catalog instanceof CheckCatalog checkCatalog) { _infer(checkCatalog, acceptor, preIndexingPhase); diff --git a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java index 1c6fdcc2a1..c609e1f336 100644 --- a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java +++ b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java @@ -22,7 +22,7 @@ import com.avaloq.tools.ddk.test.core.jupiter.BugTest; import com.avaloq.tools.ddk.test.core.jupiter.BugTestAwareRule; -import org.eclipse.emf.common.util.BasicEList; +import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EPackage; import org.eclipse.xtext.AbstractElement; import org.eclipse.xtext.AbstractMetamodelDeclaration; @@ -89,14 +89,14 @@ private void setExpectationsForApply(final ParserRule mockRule, final String pac private void setExpectationsForUsesXImportSection(final Grammar mockGrammar, final Pair... packageAndRuleNamesOfLeafRules) { final ParserRule mockRootRule = mock(ParserRule.class); final Group mockAlternatives = mock(Group.class); - final BasicEList mockElements = new BasicEList(); + final EList mockElements = new org.eclipse.emf.common.util.BasicEList(); - final BasicEList mockLeafRules = new BasicEList(); + final EList mockLeafRules = new org.eclipse.emf.common.util.BasicEList(); for (final Pair pair : packageAndRuleNamesOfLeafRules) { mockLeafRules.add(mock(ParserRule.class)); } - final BasicEList mockRules = new BasicEList(); + final EList mockRules = new org.eclipse.emf.common.util.BasicEList(); mockRules.add(mockRootRule); mockRules.addAll(mockLeafRules); diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java index 5002a8487e..84af51bb82 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/antlr/AnnotationAwareAntlrContentAssistGrammarGenerator.java @@ -1160,6 +1160,7 @@ protected String crossrefEbnf(final EnumRule it, final RuleCall call, final Cros return this._grammarAccessExtensions.ruleName(it); } + @Override protected String crossrefEbnf(final AbstractRule it, final RuleCall call, final CrossReference ref, final boolean supportActions) { if (GrammarUtil.isDatatypeRule(AntlrGrammarGenUtil.getOriginalElement(it))) { return this._grammarAccessExtensions.ruleName(it); From ba4ed9fcba4ec23e60e544a857f60fc2945e33b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 19:48:56 +0100 Subject: [PATCH 18/23] style: fix UseCollectionIsEmpty in PropertiesInferenceHelper Co-Authored-By: Claude Opus 4.6 --- .../tools/ddk/checkcfg/util/PropertiesInferenceHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java index 0338a7809d..c1694675cc 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/util/PropertiesInferenceHelper.java @@ -89,7 +89,7 @@ public JvmTypeReference inferType(final ICheckCfgPropertySpecification contribut } public JvmTypeReference inferListType(final XListLiteral newValue, final JvmTypeReferenceBuilder referenceBuilder) { - if (newValue.getElements().size() < 1) { + if (newValue.getElements().isEmpty()) { return null; } final XExpression firstElement = newValue.getElements().get(0); From 9eaf951d68f9194d48f8bb2e432bfab628106bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 21:07:39 +0100 Subject: [PATCH 19/23] fix: resolve BasicEList compilation error in XbaseGeneratorFragmentTest Co-Authored-By: Claude Opus 4.6 --- .../xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java index c609e1f336..733fb05fb3 100644 --- a/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java +++ b/com.avaloq.tools.ddk.xtext.generator.test/src/com/avaloq/tools/ddk/xtext/generator/xbase/test/XbaseGeneratorFragmentTest.java @@ -130,7 +130,7 @@ private void setExpectationsForUsesXImportSection(final Grammar mockGrammar, fin // Calls made by doSwitch(grammar) when(mockGrammar.eClass()).thenReturn(XtextPackage.Literals.GRAMMAR); when(mockGrammar.isDefinesHiddenTokens()).thenReturn(false); - when(mockGrammar.getUsedGrammars()).thenReturn(new BasicEList()); + when(mockGrammar.getUsedGrammars()).thenReturn(new org.eclipse.emf.common.util.BasicEList()); // Calls made per rule by XbaseGeneratorFragmentOverride.usesXImportSection.apply() setExpectationsForApply(mockRootRule, THIS_PACKAGE_NAME, "rootRule"); From 51d439dee14104ee28d20ffb36fb024ba2f0b3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sun, 1 Mar 2026 23:29:57 +0100 Subject: [PATCH 20/23] docs: add handover summary for Xtend-to-Java migration session Co-Authored-By: Claude Opus 4.6 --- HANDOVER.md | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 HANDOVER.md diff --git a/HANDOVER.md b/HANDOVER.md new file mode 100644 index 0000000000..541d52a79f --- /dev/null +++ b/HANDOVER.md @@ -0,0 +1,118 @@ +# Handover — Fix All PMD & Checkstyle Violations for Xtend-to-Java Migration + +*Generated: Sun Mar 1 23:26 CET 2026* +*Branch: feature/xtend-to-java-migration* +*Last commit: 645407dd5 — fix: resolve BasicEList compilation error in XbaseGeneratorFragmentTest* + +## What We Were Working On + +Resolving all PMD and Checkstyle violations introduced by the Xtend-to-Java migration on the `feature/xtend-to-java-migration` branch. The migration converted ~90 Xtend files to Java 21 across the entire dsl-devkit project, and the auto-generated Java code had widespread style violations that failed CI. + +The initial plan estimated ~542 violations across 12 files in 4 modules. In practice, violations were discovered iteratively across **10+ modules and 36 files**, totaling roughly 600+ violations. + +## What Got Done + +- [x] Fixed all PMD and Checkstyle violations — CI is fully green (all 3 jobs: maven-verify, pmd, checkstyle) +- [x] 4 commits covering the fixes: + - `18fb5a34e` — bulk fix across 33 files in 10 modules + - `8d4d826d7` — StringToString, UnnecessaryCast, MissingOverride, LooseCoupling + - `ab0d6df10` — UseCollectionIsEmpty in PropertiesInferenceHelper + - `645407dd5` — BasicEList compilation error in XbaseGeneratorFragmentTest +- [x] All pushed and CI confirmed green (run 22551555855) + +### Modules touched: +- `check.core` (8 files) — largest module, ~510 violations +- `check.core.test` (10 files) — ~150 violations +- `check.ui` (2 files) +- `check.ui.test` (1 file) +- `checkcfg.core` (4 files) +- `checkcfg.core.test` (4 files) +- `xtext.format.generator` (1 file) +- `xtext.export.generator` (1 file) +- `xtext.generator.test` (1 file) +- `xtext.generator` (1 file) + +### Fix categories applied: +- **FinalParams** (~354): Added `final` to method parameters +- **UnnecessaryReturn** (~53): Removed trailing `return;` in void dispatch methods +- **MethodName** (~27): Class-level `@SuppressWarnings({"checkstyle:MethodName"})` for dispatch methods (`_format()`, `_scope()`, etc.) +- **AppendCharacterWithChar** (~20): `.append("x")` → `.append('x')` +- **MultipleStringLiterals** (~32): `CHECKSTYLE:CONSTANTS-OFF/ON` wrappers +- **MemberName** (~6): Renamed `_fieldName` → `fieldName` +- **MissingOverride**: Added `@Override` annotations +- **LooseCoupling**: Changed implementation types to interfaces (`BasicEList` → `EList`, `TreeMap` → `Map`, `ArrayList` → `List`) +- **InsufficientStringBufferDeclaration**: Increased `StringBuilder` capacities +- **Various others**: IllegalCatch suppression, JavadocMethod tags, UseIndexOfChar, ExhaustiveSwitchHasDefault, etc. + +## What Worked + +- **Parallel team agents** for the initial bulk work — two agents handled `check.core` (8 files) and the smaller modules (4 files) simultaneously, getting the majority of mechanical fixes done quickly. +- **Iterative verification loop** — running `mvn checkstyle:check pmd:check` after each round of fixes, then fixing what remained. This was essential because new modules kept appearing as CI checks expanded beyond the initial plan. +- **Suppression patterns** for rules that couldn't be fixed (dispatch method names, intentional exception catching): + - `// CHECKSTYLE:CONSTANTS-OFF` / `// CHECKSTYLE:CONSTANTS-ON` + - `// CHECKSTYLE:CHECK-OFF ` / `// CHECKSTYLE:CHECK-ON ` + - `@SuppressWarnings({"checkstyle:MethodName", "PMD.UnusedFormalParameter"})` + +## What Didn't Work + +- **Local PMD checks without `compile`** — Running `mvn checkstyle:check pmd:check` without a prior `compile` phase misses PMD rules that require type resolution (MissingOverride, UnnecessaryCast, LooseCoupling, UseCollectionIsEmpty). This caused violations to slip through local verification and only appear in CI. +- **Grepping build output with `head -30`** — When verifying with `--fail-at-end`, the first 30 lines were all `0 Checkstyle violations` messages, hiding the actual `BUILD FAILURE` at the bottom. A compilation error was missed because of this. +- **Initial scope estimation** — The plan identified 4 modules but violations existed in 10+. Each CI run surfaced new modules we hadn't checked locally. +- **Agent-generated fixes sometimes incomplete** — Agents fixed the obvious cases but missed edge cases (e.g., expanding a star import but not checking all usages, changing an import without updating all references). + +## Key Decisions & Rationale + +1. **Suppress vs fix for MethodName violations**: Dispatch methods like `_format()`, `_scope()`, `_computeTypes()` must keep underscore prefixes (Xtext dispatch pattern). Used class-level `@SuppressWarnings` rather than renaming. + +2. **CHECKSTYLE:CONSTANTS-OFF for MultipleStringLiterals**: Template-generating methods that build Java source code via StringBuilder inherently have repeated string literals. Extracting constants would hurt readability. + +3. **CHECKSTYLE:CHECK-OFF for IllegalCatch**: Some methods intentionally catch `Exception` (e.g., in code generation utilities). Suppressed rather than changed. + +4. **Switch to `mvn clean compile pmd:check` for local verification**: After discovering that PMD needs compiled classes for type-resolution rules, this became the correct local verification command. + +## Lessons Learned & Gotchas + +1. **PMD type-resolution rules need compiled code**: `MissingOverride`, `UnnecessaryCast`, `LooseCoupling`, `UseCollectionIsEmpty` all need class files. Always run `mvn clean compile pmd:check` locally, not just `pmd:check`. + +2. **Checkstyle does NOT need compilation** — it works purely on source files. + +3. **`--fail-at-end` hides early failures** — When grepping output, always check the final `BUILD SUCCESS/FAILURE` line, not just intermediate results. + +4. **Xtend dispatch methods produce underscore-prefixed Java methods** — These are a known pattern (`_methodName`) that Xtext's dispatch resolution depends on. They cannot be renamed. + +5. **CI modules are discovered incrementally** — The Maven reactor with `--fail-at-end` skips downstream modules when an upstream module fails. Fixing one module can unblock compilation of others, revealing their violations. + +6. **`ByteArrayInputStream.close()` is a no-op** — When simplifying try-finally around BAIS, safe to just remove the close call entirely. + +7. **PMD's InsufficientStringBufferDeclaration calculates actual string sizes** — A StringBuilder(512) may still trigger if the appended content totals >512 bytes. Some methods needed 2048. + +## Next Steps + +1. **Consider squashing the 4 style-fix commits** before merging to master — they're all part of the same logical change. The commits are `18fb5a34e`, `8d4d826d7`, `ab0d6df10`, `645407dd5`. + +2. **Clean up untracked `xtend-gen/` directories** — 25 untracked `xtend-gen/` directories remain from the migration. These should either be `.gitignore`d or removed. + +3. **Consider adding `mvn clean compile pmd:check` to the local dev workflow** — Document that `pmd:check` alone misses type-resolution rules. + +4. **PR is ready for review** — CI is green. The PR is #1274 on the dsl-devkit repo. + +## Key Files & Locations + +| File | Purpose | +|------|---------| +| `check.core/.../formatting2/CheckFormatter.java` | Largest single file fix (~143 violations). Dispatch-based formatter. | +| `check.core/.../jvmmodel/CheckJvmModelInferrer.java` | JVM model inference with dispatch methods. Had LooseCoupling, UnnecessaryCast, MissingOverride. | +| `check.core/.../generator/CheckGeneratorExtensions.java` | Code generation utilities. Star import expansion, JavadocMethod, IllegalCatch. | +| `check.core/.../generator/CheckGenerator.java` | Main code generator. AppendCharWithChar, InsufficientStringBufferDeclaration. | +| `check.core/.../generator/CheckGeneratorNaming.java` | Naming conventions. StringToString fix (getLastSegment().toString() redundant). | +| `check.core/.../scoping/CheckScopeProvider.java` | Scoping with dispatch methods. UnusedFormalParameter, UseIndexOfChar. | +| `xtext.generator.test/.../XbaseGeneratorFragmentTest.java` | Test file. LooseCoupling (BasicEList→EList), ConstantName renames, ImmutableField. | +| `xtext.generator/.../AnnotationAwareAntlrContentAssistGrammarGenerator.java` | Grammar generator. MissingOverride, UnnecessaryBoxing fixes. | +| `checkcfg.core/.../PropertiesInferenceHelper.java` | Properties inference. ExhaustiveSwitchHasDefault (switch expression), UseCollectionIsEmpty. | +| `check.core.test/.../util/CheckModelUtil.java` | Test model utilities. JavadocMethod, VariableDeclarationUsageDistance, AppendCharWithChar. | + +## Additional Notes + +- The `xtend-gen/` directories in the untracked files list are leftover from the Xtend build infrastructure that was removed in commit `41edd59ab`. They should be added to `.gitignore` or deleted. +- The worktree branches (`worktree-agent-*`) visible in `git branch` are leftovers from agent execution. They can be cleaned up with `git branch -D`. +- You may want to add `HANDOVER.md` to `.gitignore`. From b26386d6361357eb22df2622e9917b110191ece3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Tue, 3 Mar 2026 00:02:06 +0100 Subject: [PATCH 21/23] refactor: replace StringBuilder patterns with String.format() and text blocks Replace StringBuilder.append() chains with more readable alternatives: - Text blocks with String.format() for file skeleton generators (CheckNewProject, CheckQuickfixProvider, CheckProjectFactory, ExportGenerator) - String.format() for toString() methods in scope classes and resource descriptions - Simple string concatenation for trivial cases (EObjectUtil, AbstractLabelProvider, ClasspathBasedChecks, DirectLinkingResourceStorageLoadable) - String.join() for loop-based string building (ScopeTrace) Also widens toClient() parameter from StringBuilder to CharSequence in StandaloneBuilderIntegrationFragment2 and LspBuilderIntegrationFragment2, and removes unused INITIAL_BUFFER_CAPACITY constants. 18 files changed, net -106 lines removed. Co-Authored-By: Claude Opus 4.6 --- .../validation/ClasspathBasedChecks.java | 9 +-- .../ddk/check/ui/wizard/CheckNewProject.java | 31 ++++---- .../check/ui/wizard/CheckProjectFactory.java | 11 +-- .../ui/wizard/CheckQuickfixProvider.java | 70 +++++++++---------- .../export/generator/ExportGenerator.java | 22 +++--- .../LspBuilderIntegrationFragment2.java | 10 ++- ...StandaloneBuilderIntegrationFragment2.java | 10 +-- .../ui/labeling/AbstractLabelProvider.java | 4 +- .../validation/AbstractValidElementBase.java | 6 +- .../FixedCopiedResourceDescription.java | 10 +-- .../DirectLinkingResourceStorageLoadable.java | 7 +- .../persistence/ProxyCompositeNode.java | 11 +-- .../xtext/scoping/AbstractRecursiveScope.java | 14 +--- .../xtext/scoping/ContainerBasedScope.java | 21 +----- .../ddk/xtext/scoping/DelegatingScope.java | 21 ++---- .../scoping/PrefixedContainerBasedScope.java | 24 +------ .../tools/ddk/xtext/scoping/ScopeTrace.java | 16 +---- .../tools/ddk/xtext/util/EObjectUtil.java | 7 +- 18 files changed, 99 insertions(+), 205 deletions(-) diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/validation/ClasspathBasedChecks.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/validation/ClasspathBasedChecks.java index 38d069fd2e..ad7dc84e3a 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/validation/ClasspathBasedChecks.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/validation/ClasspathBasedChecks.java @@ -54,13 +54,8 @@ public void checkFileNamingConventions(final CheckCatalog catalog) { Resource resource = catalog.eResource(); URI resourceURI = resource.getURI(); String packageName = catalog.getPackageName(); - StringBuilder classpathURIBuilder = new StringBuilder(ClasspathUriUtil.CLASSPATH_SCHEME); - classpathURIBuilder.append(":/"); - if (packageName != null) { - classpathURIBuilder.append(packageName.replace(DOT, SLASH)).append(SLASH); - } - classpathURIBuilder.append(resourceURI.lastSegment()); - URI classpathURI = URI.createURI(classpathURIBuilder.toString()); + String packagePath = packageName != null ? packageName.replace(DOT, SLASH) + SLASH : ""; + URI classpathURI = URI.createURI(ClasspathUriUtil.CLASSPATH_SCHEME + ":/" + packagePath + resourceURI.lastSegment()); URIConverter uriConverter = resource.getResourceSet().getURIConverter(); try { URI normalizedClasspathURI = uriConverter.normalize(classpathURI); diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java index c1e619867b..6774928b18 100644 --- a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java +++ b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckNewProject.java @@ -24,22 +24,21 @@ public String fileName(final CheckProjectInfo info) { } public CharSequence fileContent(final CheckProjectInfo info) { - final StringBuilder builder = new StringBuilder(512); - builder.append("package ").append(info.getPackageName()).append('\n'); - builder.append('\n'); - builder.append(fileImports(info)); - builder.append('\n'); - builder.append('\n'); - builder.append("/**\n"); - builder.append(" * Check catalog for ").append(info.getGrammar().getName()).append('\n'); - builder.append(" */\n"); - builder.append("catalog ").append(info.getCatalogName()).append('\n'); - builder.append("for grammar ").append(info.getGrammar().getName()).append(" {\n"); - builder.append('\n'); - builder.append(" // Add categories and checks\n"); - builder.append('\n'); - builder.append("}\n"); - return builder; + return String.format(""" + package %s + + %s + + /** + * Check catalog for %s + */ + catalog %s + for grammar %s { + + // Add categories and checks + + } + """, info.getPackageName(), fileImports(info), info.getGrammar().getName(), info.getCatalogName(), info.getGrammar().getName()); } public CharSequence fileImports(final CheckProjectInfo info) { diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckProjectFactory.java b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckProjectFactory.java index 5325583f85..e3e4ab5293 100644 --- a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckProjectFactory.java +++ b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckProjectFactory.java @@ -46,14 +46,17 @@ protected void enhanceProject(final IProject project, final SubMonitor subMonito * @throws CoreException * the core exception */ - @SuppressWarnings("PMD.InsufficientStringBufferDeclaration") private void createPluginXML(final IProject project, final IProgressMonitor monitor) throws CoreException { - final StringBuilder content = new StringBuilder("\n\n"); - content.append("\n\n"); + final String content = """ + + + + + """; SubMonitor subMonitor = SubMonitor.convert(monitor, 2); try { - createFile("plugin.xml", project, content.toString(), subMonitor.newChild(1)); + createFile("plugin.xml", project, content, subMonitor.newChild(1)); } finally { subMonitor.done(); } diff --git a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java index 63b53cac72..5c74639ced 100644 --- a/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java +++ b/com.avaloq.tools.ddk.check.ui/src/com/avaloq/tools/ddk/check/ui/wizard/CheckQuickfixProvider.java @@ -24,41 +24,41 @@ public String fileName(final CheckProjectInfo info) { } public CharSequence fileContent(final CheckProjectInfo info) { - final StringBuilder builder = new StringBuilder(2048); - builder.append("package ").append(info.getPackageName()).append(";\n"); - builder.append('\n'); - builder.append("import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreQuickfixProvider;\n"); - builder.append('\n'); - builder.append("/**\n"); - builder.append(" * Default quickfix provider for ").append(info.getCatalogName()).append(".\n"); - builder.append(" *

    \n"); - builder.append(" * Note that this class name must start with the catalog name and have QuickfixProvider\n"); - builder.append(" * as suffix. It must be located in the same Java package as the catalog file.\n"); - builder.append(" *

    \n"); - builder.append(" */\n"); - builder.append("public class ").append(info.getCatalogName()).append("QuickfixProvider implements ICoreQuickfixProvider {\n"); - builder.append('\n'); - builder.append("// @CoreFix(value = MyIssueCodes.NAME_ENTITY_0)\n"); - builder.append("// public void fixEntityNameFirstUpper(final Issue issue,\n"); - builder.append("// ICoreIssueResolutionAcceptor acceptor) {\n"); - builder.append("// acceptor.accept(issue, \"Correct entity name\",\n"); - builder.append("// \"Correct name by setting first letter to upper case.\",\n"); - builder.append("// null, new ICoreSemanticModification() {\n"); - builder.append("// public void apply(EObject element, ICoreModificationContext context) {\n"); - builder.append("// if (element instanceof Entity) {\n"); - builder.append("// final Entity entity = (Entity) element;\n"); - builder.append("// String newName = String.valueOf(entity.getName().charAt(0)).toUpperCase();\n"); - builder.append("// if (entity.getName().length() > 1) {\n"); - builder.append("// newName += entity.getName().substring(1, entity.getName().length());\n"); - builder.append("// }\n"); - builder.append("// entity.setName(newName);\n"); - builder.append("// }\n"); - builder.append("// }\n"); - builder.append("// });\n"); - builder.append("// }\n"); - builder.append('\n'); - builder.append("}\n"); - return builder; + return String.format(""" + package %1$s; + + import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreQuickfixProvider; + + /** + * Default quickfix provider for %2$s. + *

    + * Note that this class name must start with the catalog name and have QuickfixProvider + * as suffix. It must be located in the same Java package as the catalog file. + *

    + */ + public class %2$sQuickfixProvider implements ICoreQuickfixProvider { + + // @CoreFix(value = MyIssueCodes.NAME_ENTITY_0) + // public void fixEntityNameFirstUpper(final Issue issue, + // ICoreIssueResolutionAcceptor acceptor) { + // acceptor.accept(issue, "Correct entity name", + // "Correct name by setting first letter to upper case.", + // null, new ICoreSemanticModification() { + // public void apply(EObject element, ICoreModificationContext context) { + // if (element instanceof Entity) { + // final Entity entity = (Entity) element; + // String newName = String.valueOf(entity.getName().charAt(0)).toUpperCase(); + // if (entity.getName().length() > 1) { + // newName += entity.getName().substring(1, entity.getName().length()); + // } + // entity.setName(newName); + // } + // } + // }); + // } + + } + """, info.getPackageName(), info.getCatalogName()); } } // CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java index 460b277f79..6f6dd5417a 100644 --- a/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java +++ b/com.avaloq.tools.ddk.xtext.export/src/com/avaloq/tools/ddk/xtext/export/generator/ExportGenerator.java @@ -112,18 +112,16 @@ public void generateFragmentProvider(final ExportModel model, final IFileSystemA if (model.getExports().stream().anyMatch(e -> e.isFingerprint() && e.getFragmentAttribute() != null) || model.isExtension()) { fsa.generateFile(fileName, fragmentProviderGenerator.generate(model, compilationContext, genModelUtil)); } else if (!model.getExports().isEmpty()) { - // CHECKSTYLE:CONSTANTS-OFF - final StringBuilder sb = new StringBuilder(512); - sb.append("package ").append(naming.toJavaPackage(exportGeneratorX.getFragmentProvider(model))).append(";\n"); - sb.append('\n'); - sb.append("import com.avaloq.tools.ddk.xtext.linking.ShortFragmentProvider;\n"); - sb.append('\n'); - sb.append('\n'); - sb.append("public class ").append(naming.toSimpleName(exportGeneratorX.getFragmentProvider(model))).append(" extends ShortFragmentProvider {\n"); - sb.append('\n'); - sb.append("}\n"); - // CHECKSTYLE:CONSTANTS-ON - fsa.generateFile(fileName, sb); + fsa.generateFile(fileName, String.format(""" + package %s; + + import com.avaloq.tools.ddk.xtext.linking.ShortFragmentProvider; + + + public class %s extends ShortFragmentProvider { + + } + """, naming.toJavaPackage(exportGeneratorX.getFragmentProvider(model)), naming.toSimpleName(exportGeneratorX.getFragmentProvider(model)))); } } diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java index 70eb62efc7..61a5f783ce 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/LspBuilderIntegrationFragment2.java @@ -39,7 +39,7 @@ public class LspBuilderIntegrationFragment2 extends AbstractXtextGeneratorFragme @Inject private XtextGeneratorNaming packageNaming; - private static final int INITIAL_BUFFER_CAPACITY = 128; + private TypeReference createSuffixedTypeReference(final String suffix) { return new TypeReference( @@ -68,11 +68,9 @@ public void generate() { } public void generateServiceRegistration() { - StringBuilder sb = new StringBuilder(INITIAL_BUFFER_CAPACITY); - sb.append(getLspBuildSetupServiceClass().getName()); - sb.append('\n'); + String content = getLspBuildSetupServiceClass().getName() + '\n'; fileAccessFactory.createTextFile("META-INF/services/com.avaloq.tools.ddk.xtext.build.ILspLanguageSetup", - toClient(sb)).writeTo(getProjectConfig().getGenericIde().getSrcGen()); + toClient(content)).writeTo(getProjectConfig().getGenericIde().getSrcGen()); } // CHECKSTYLE:CONSTANTS-OFF @@ -204,7 +202,7 @@ public void generateBuildSetup() { } // CHECKSTYLE:CONSTANTS-ON - private static StringConcatenationClient toClient(final StringBuilder sb) { + private static StringConcatenationClient toClient(final CharSequence sb) { final String content = sb.toString(); return new StringConcatenationClient() { @Override diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java index 633a102e64..21dc9136a2 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/builder/StandaloneBuilderIntegrationFragment2.java @@ -59,14 +59,10 @@ public void generate() { generateBuildSetup(); } - private static final int INITIAL_BUFFER_CAPACITY = 128; - public void generateServiceRegistration() { - StringBuilder sb = new StringBuilder(INITIAL_BUFFER_CAPACITY); - sb.append(getStandaloneBuildSetupServiceClass().getName()); - sb.append('\n'); + String content = getStandaloneBuildSetupServiceClass().getName() + '\n'; fileAccessFactory.createTextFile("META-INF/services/com.avaloq.tools.ddk.xtext.build.IDynamicSetupService", - toClient(sb)).writeTo(getProjectConfig().getRuntime().getSrcGen()); + toClient(content)).writeTo(getProjectConfig().getRuntime().getSrcGen()); } // CHECKSTYLE:CONSTANTS-OFF @@ -195,7 +191,7 @@ public void generateBuildSetup() { } // CHECKSTYLE:CONSTANTS-ON - private static StringConcatenationClient toClient(final StringBuilder sb) { + private static StringConcatenationClient toClient(final CharSequence sb) { final String content = sb.toString(); return new StringConcatenationClient() { @Override diff --git a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/labeling/AbstractLabelProvider.java b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/labeling/AbstractLabelProvider.java index a14651d210..59f719d124 100644 --- a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/labeling/AbstractLabelProvider.java +++ b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/labeling/AbstractLabelProvider.java @@ -230,9 +230,7 @@ protected Object getStyledLabel(final EObject modelElement, final EStructuralFea } } if (valueString != null && valueString.length() > MAX_FEATURE_VALUE_LENGTH) { - StringBuilder stringBuilder = new StringBuilder(valueString.substring(0, MAX_FEATURE_VALUE_LENGTH - CONTINUED.length())); - stringBuilder.append(CONTINUED); - valueString = stringBuilder.toString(); + valueString = valueString.substring(0, MAX_FEATURE_VALUE_LENGTH - CONTINUED.length()) + CONTINUED; } } return assignmentStyledString(name, valueString); diff --git a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/validation/AbstractValidElementBase.java b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/validation/AbstractValidElementBase.java index 692c7ebe58..574f288bf9 100644 --- a/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/validation/AbstractValidElementBase.java +++ b/com.avaloq.tools.ddk.xtext.ui/src/com/avaloq/tools/ddk/xtext/ui/validation/AbstractValidElementBase.java @@ -109,11 +109,7 @@ public IConfigurationElement getConfigurationElement() { @Override public String toString() { - StringBuilder b = new StringBuilder(this.getClass().getSimpleName()); - b.append("(\""); //$NON-NLS-1$ - b.append(getElementTypeName()); - b.append("\")"); //$NON-NLS-1$ - return b.toString(); + return this.getClass().getSimpleName() + "(\"" + getElementTypeName() + "\")"; //$NON-NLS-1$ //$NON-NLS-2$ } /** diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/FixedCopiedResourceDescription.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/FixedCopiedResourceDescription.java index 200e85debd..56e715a6ef 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/FixedCopiedResourceDescription.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/FixedCopiedResourceDescription.java @@ -105,15 +105,7 @@ public Iterable getReferenceDescriptions() { @Override public String toString() { - StringBuilder result = new StringBuilder(getClass().getName()); - result.append('@'); - result.append(Integer.toHexString(hashCode())); - - result.append(" (URI: "); //$NON-NLS-1$ - result.append(uri); - result.append(')'); - - return result.toString(); + return String.format("%s@%s (URI: %s)", getClass().getName(), Integer.toHexString(hashCode()), uri); //$NON-NLS-1$ } @Override diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/DirectLinkingResourceStorageLoadable.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/DirectLinkingResourceStorageLoadable.java index 5c95737318..d62a837cff 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/DirectLinkingResourceStorageLoadable.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/DirectLinkingResourceStorageLoadable.java @@ -108,12 +108,9 @@ protected void loadFeatureValue(final InternalEObject internalEObject, final ESt super.loadFeatureValue(internalEObject, eStructuralFeatureData); // CHECKSTYLE:OFF } catch (Exception e) { - StringBuilder infoMessage = new StringBuilder(100); // CHECKSTYLE:ON - infoMessage.append("Failed to load feature's value. Owner: ").append(internalEObject.eClass()); //$NON-NLS-1$ - if (eStructuralFeatureData.eStructuralFeature != null) { - infoMessage.append(", feature name: ").append(eStructuralFeatureData.eStructuralFeature.getName()); //$NON-NLS-1$ - } + String infoMessage = "Failed to load feature's value. Owner: " + internalEObject.eClass() //$NON-NLS-1$ + + (eStructuralFeatureData.eStructuralFeature != null ? ", feature name: " + eStructuralFeatureData.eStructuralFeature.getName() : ""); //$NON-NLS-1$ //$NON-NLS-2$ LOG.info(infoMessage); throw e; } diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/ProxyCompositeNode.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/ProxyCompositeNode.java index d1d0b56992..c2f226049c 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/ProxyCompositeNode.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/persistence/ProxyCompositeNode.java @@ -178,16 +178,11 @@ private CompositeNode delegate() { * @return the string */ private String toString(final EObject eObject) { - StringBuilder result = new StringBuilder(eObject.getClass().getName()); - result.append('@'); - result.append(Integer.toHexString(hashCode())); - + String result = String.format("%s@%s", eObject.getClass().getName(), Integer.toHexString(hashCode())); //$NON-NLS-1$ if (eObject.eIsProxy() && eObject instanceof InternalEObject internal) { - result.append(" (eProxyURI: "); //$NON-NLS-1$ - result.append(internal.eProxyURI()); - result.append(')'); + result += " (eProxyURI: " + internal.eProxyURI() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } - return result.toString(); + return result; } @Override diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/AbstractRecursiveScope.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/AbstractRecursiveScope.java index b826607984..89c8ef437d 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/AbstractRecursiveScope.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/AbstractRecursiveScope.java @@ -229,20 +229,12 @@ public String getId() { @SuppressWarnings("nls") @Override public String toString() { - final StringBuilder result = new StringBuilder(getClass().getName()); - result.append('@'); - result.append(Integer.toHexString(hashCode())); - - result.append(" (id: "); - result.append(getId()); - result.append(')'); - + String result = String.format("%s@%s (id: %s)", getClass().getName(), Integer.toHexString(hashCode()), getId()); final IScope outerScope = getParent(); if (outerScope != IScope.NULLSCOPE) { - result.append("\n >> "); - result.append(outerScope.toString().replaceAll("\\\n", "\n ")); + result += "\n >> " + outerScope.toString().replaceAll("\\\n", "\n "); } - return result.toString(); + return result; } } diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/ContainerBasedScope.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/ContainerBasedScope.java index d2b719e15a..9fcdedfdd4 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/ContainerBasedScope.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/ContainerBasedScope.java @@ -135,26 +135,11 @@ protected Iterable getAllLocalElements() { @SuppressWarnings("nls") @Override public String toString() { - final StringBuilder result = new StringBuilder(getClass().getName()); - result.append('@'); - result.append(Integer.toHexString(hashCode())); - - result.append(" (id: "); - result.append(getId()); - - result.append(", query: "); - result.append(criteria); - - result.append(", container: "); - result.append(container); - - result.append(')'); - + String result = String.format("%s@%s (id: %s, query: %s, container: %s)", getClass().getName(), Integer.toHexString(hashCode()), getId(), criteria, container); final IScope parent = getParent(); if (parent != IScope.NULLSCOPE) { - result.append("\n >> "); - result.append(parent.toString().replaceAll("\\\n", "\n ")); + result += "\n >> " + parent.toString().replaceAll("\\\n", "\n "); } - return result.toString(); + return result; } } diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/DelegatingScope.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/DelegatingScope.java index da2da8889b..3b16992f1a 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/DelegatingScope.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/DelegatingScope.java @@ -267,26 +267,13 @@ protected Iterable getLocalElementsByName(final QualifiedNa @SuppressWarnings("nls") @Override public String toString() { - final StringBuilder result = new StringBuilder(getClass().getName()); - result.append('@'); - result.append(Integer.toHexString(hashCode())); - - result.append(" (id: "); - result.append(getId()); - final Iterable delegateScopes = getDelegates(); - if (delegateScopes != null && !Iterables.isEmpty(delegateScopes)) { - result.append(", delegates: "); - result.append(Iterables.toString(delegateScopes)); - } - result.append(')'); - + String delegatesSuffix = delegateScopes != null && !Iterables.isEmpty(delegateScopes) ? ", delegates: " + Iterables.toString(delegateScopes) : ""; + String result = String.format("%s@%s (id: %s%s)", getClass().getName(), Integer.toHexString(hashCode()), getId(), delegatesSuffix); final IScope outerScope = getParent(); if (outerScope != IScope.NULLSCOPE) { - result.append("\n >> "); - result.append(outerScope.toString().replaceAll("\\\n", "\n ")); + result += "\n >> " + outerScope.toString().replaceAll("\\\n", "\n "); } - - return result.toString(); + return result; } } diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/PrefixedContainerBasedScope.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/PrefixedContainerBasedScope.java index 04e8def8bb..cf8f2388e8 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/PrefixedContainerBasedScope.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/PrefixedContainerBasedScope.java @@ -134,29 +134,11 @@ public IEObjectDescription apply(final IEObjectDescription input) { @SuppressWarnings("nls") @Override public String toString() { - final StringBuilder result = new StringBuilder(getClass().getName()); - result.append('@'); - result.append(Integer.toHexString(hashCode())); - - result.append(" (id: "); - result.append(getId()); - - result.append(", prefix: "); - result.append(prefix); - - result.append(", query: "); - result.append(criteria); - - result.append(", container: "); - result.append(container); - - result.append(')'); - + String result = String.format("%s@%s (id: %s, prefix: %s, query: %s, container: %s)", getClass().getName(), Integer.toHexString(hashCode()), getId(), prefix, criteria, container); final IScope parent = getParent(); if (parent != IScope.NULLSCOPE) { - result.append("\n >> "); - result.append(parent.toString().replaceAll("\\\n", "\n ")); + result += "\n >> " + parent.toString().replaceAll("\\\n", "\n "); } - return result.toString(); + return result; } } diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/ScopeTrace.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/ScopeTrace.java index 86f478da21..e50a05070b 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/ScopeTrace.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/ScopeTrace.java @@ -10,7 +10,6 @@ *******************************************************************************/ package com.avaloq.tools.ddk.xtext.scoping; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -47,20 +46,7 @@ public List getFullTrace() { @SuppressWarnings("nls") @Override public String toString() { - final StringBuilder builder = new StringBuilder(getClass().getName()); - builder.append('@'); - builder.append(Integer.toHexString(hashCode())); - builder.append(" ["); - - for (final Iterator i = elements.iterator(); i.hasNext();) { - builder.append(i.next()); - if (i.hasNext()) { - builder.append(" >> "); - } - } - - builder.append(']'); - return builder.toString(); + return String.format("%s@%s [%s]", getClass().getName(), Integer.toHexString(hashCode()), String.join(" >> ", elements)); } /** diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/EObjectUtil.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/EObjectUtil.java index 145d96009e..397a9ee47e 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/EObjectUtil.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/EObjectUtil.java @@ -242,13 +242,8 @@ public static String getFileLocation(final EObject object) { // CHECKSTYLE:CHECK-OFF MagicNumber String path = uri.isPlatform() ? '/' + String.join("/", uri.segmentsList().subList(3, uri.segmentCount())) : uri.path(); //$NON-NLS-1$ // CHECKSTYLE:CHECK-ON MagicNumber - StringBuilder result = new StringBuilder(path); final ICompositeNode node = NodeModelUtils.getNode(object); - if (node != null) { - result.append(':').append(node.getStartLine()); - } - - return result.toString(); + return node != null ? path + ":" + node.getStartLine() : path; //$NON-NLS-1$ } } From 76087e2da754e52cafcf78f967195da695c2a8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Tue, 3 Mar 2026 08:51:30 +0100 Subject: [PATCH 22/23] refactor: convert string concatenation to text blocks in test DSL sources Co-Authored-By: Claude Opus 4.6 --- .../core/generator/IssueCodeValueTest.java | 80 ++++++++++--------- .../tools/ddk/check/core/test/BugAig830.java | 22 ++--- .../CheckApiAccessValidationsTest.java | 15 ++-- .../ddk/checkcfg/validation/CheckCfgTest.java | 28 +++---- .../ddk/xtext/format/FormatParsingTest.java | 16 ++-- 5 files changed, 84 insertions(+), 77 deletions(-) diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java index 5832942e93..e8efc53ce6 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/generator/IssueCodeValueTest.java @@ -41,45 +41,47 @@ public class IssueCodeValueTest extends AbstractCheckGenerationTestCase { public void testIssueCodeValue() throws Exception { // ARRANGE // @Format-Off - String source = "package " + PACKAGE_NAME + "\n" - + "\n" - + "import com.avaloq.tools.ddk.check.check.Check\n" - + "import com.avaloq.tools.ddk.check.check.Context\n" - + "import com.avaloq.tools.ddk.check.check.Documented\n" - + "\n" - + "catalog " + CATALOG_NAME + "\n" - + "for grammar com.avaloq.tools.ddk.check.Check {\n" - + "\n" - + " live error MyCheck1 \"Label 1\"\n" - + " message \"Message 1\" {\n" - + " for Documented elem {\n" - + " switch elem {\n" - + " Context : issue on elem\n" - + " Check : issue on elem\n" - + " }\n" - + " }\n" - + " }\n" - + "\n" - + " live error MyCheck_2 \"Label 2\"\n" - + " message \"Message 2\" {\n" - + " for Documented elem {\n" - + " switch elem {\n" - + " Context : issue on elem\n" - + " Check : issue on elem\n" - + " }\n" - + " }\n" - + " }\n" - + "\n" - + " live error MYCheck3 \"Label 3\"\n" - + " message \"Message 3\" {\n" - + " for Documented elem {\n" - + " switch elem {\n" - + " Context : issue on elem\n" - + " Check : issue on elem\n" - + " }\n" - + " }\n" - + " }\n" - + "}\n"; + String source = String.format(""" + package %s + + import com.avaloq.tools.ddk.check.check.Check + import com.avaloq.tools.ddk.check.check.Context + import com.avaloq.tools.ddk.check.check.Documented + + catalog %s + for grammar com.avaloq.tools.ddk.check.Check { + + live error MyCheck1 "Label 1" + message "Message 1" { + for Documented elem { + switch elem { + Context : issue on elem + Check : issue on elem + } + } + } + + live error MyCheck_2 "Label 2" + message "Message 2" { + for Documented elem { + switch elem { + Context : issue on elem + Check : issue on elem + } + } + } + + live error MYCheck3 "Label 3" + message "Message 3" { + for Documented elem { + switch elem { + Context : issue on elem + Check : issue on elem + } + } + } + } + """, PACKAGE_NAME, CATALOG_NAME); // @Format-On Map expectedIssueCodeValues = Map.of( diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.java index e01d28d99e..a30426c4e4 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/BugAig830.java @@ -34,16 +34,18 @@ public class BugAig830 { private ParseHelper parser; private String getModel() { - return "package abc\n" - + "import org.eclipse.xtext.xbase.XVariableDeclaration\n" - + "catalog Abc\n" - + "for grammar com.avaloq.tools.ddk.check.Check {\n" - + " live error \"Test\" {\n" - + " for XVariableDeclaration v {\n" - + " issue on v#name\n" - + " }\n" - + " }\n" - + "}\n"; + return """ + package abc + import org.eclipse.xtext.xbase.XVariableDeclaration + catalog Abc + for grammar com.avaloq.tools.ddk.check.Check { + live error "Test" { + for XVariableDeclaration v { + issue on v#name + } + } + } + """; } /* Tests that EPackages which are not of declared target language can be referenced. */ diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java index 988c09965e..db5af0aec7 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/validation/CheckApiAccessValidationsTest.java @@ -33,13 +33,14 @@ public class CheckApiAccessValidationsTest { @SuppressWarnings("PMD.SignatureDeclareThrowsException") private CheckCatalog getTestSource(final String importText) throws Exception { - return parser.parse( - "package com.avaloq.example.stuff.checks\n" - + "import " + importText + "\n" - + "catalog CommonChecks\n" - + "for grammar com.avaloq.tools.ddk.check.TestLanguage\n" - + "{\n" - + "}"); + return parser.parse(String.format(""" + package com.avaloq.example.stuff.checks + import %s + catalog CommonChecks + for grammar com.avaloq.tools.ddk.check.TestLanguage + { + } + """, importText)); } @Test diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java index 233f50a70f..da813cec3f 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java @@ -33,25 +33,25 @@ public class CheckCfgTest { @Test public void testValidLanguageOk() throws Exception { - final CheckConfiguration model = parser.parse( - "check configuration Test\n" - + "\n" - + "for com.avaloq.tools.ddk.^check.TestLanguage {\n" - + "\n" - + "}\n" - + "\n"); + final CheckConfiguration model = parser.parse(""" + check configuration Test + + for com.avaloq.tools.ddk.^check.TestLanguage { + + } + """); helper.assertNoIssues(model); } @Test public void testUnknownLanguageNotOk() throws Exception { - final CheckConfiguration model = parser.parse( - "check configuration Test\n" - + "\n" - + "for com.avaloq.tools.ddk.^check.Unknown {\n" - + "\n" - + "}\n" - + "\n"); + final CheckConfiguration model = parser.parse(""" + check configuration Test + + for com.avaloq.tools.ddk.^check.Unknown { + + } + """); helper.assertError(model, CheckcfgPackage.Literals.CONFIGURED_LANGUAGE_VALIDATOR, IssueCodes.UNKNOWN_LANGUAGE); } diff --git a/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.java b/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.java index 68171d233a..5e0d528088 100644 --- a/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.java +++ b/com.avaloq.tools.ddk.xtext.format.test/src/com/avaloq/tools/ddk/xtext/format/FormatParsingTest.java @@ -24,13 +24,15 @@ public class FormatParsingTest { @Test public void loadModel() throws Exception { - String input = "formatter for MyDsl\n" - + "\n" - + "const String SOME_STRING = \"\";\n" - + "const int SOME_INT = 2;\n" - + "\n" - + "Person {\n" - + "} "; + String input = """ + formatter for MyDsl + + const String SOME_STRING = ""; + const int SOME_INT = 2; + + Person { + } + """; final FormatConfiguration result = parseHelper.parse(input); assertNotNull(result); boolean hasSyntaxErrors = ((XtextResource) result.eResource()).getParseResult().hasSyntaxErrors(); From 719498502c2d79f6aab8fe328c2616e035e99bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Tue, 3 Mar 2026 21:07:16 +0100 Subject: [PATCH 23/23] refactor: convert remaining StringBuilder patterns to text blocks and simple concatenation Replace StringBuilder.append() chains with Java 21 text blocks, String.format(), and simple concatenation across 11 files where the pattern was a mechanical artifact of the Xtend-to-Java migration. Remaining StringBuilder instances (74 across 20 files) are intentionally kept where loops, interleaved conditionals, or dispatch group consistency make them the better choice. Co-Authored-By: Claude Opus 4.6 --- .../IssueCodeToLabelMapGenerationTest.java | 90 +++++++-------- .../check/core/test/util/CheckModelUtil.java | 103 +++++------------- .../ddk/check/generator/CheckGenerator.java | 37 +++---- .../ui/test/quickfix/CheckQuickfixTest.java | 95 +++++++--------- .../CheckCfgContentAssistTest.java | 38 ++++--- .../scoping/CheckCfgScopeProviderTest.java | 6 +- .../checkcfg/syntax/CheckCfgSyntaxTest.java | 92 ++++++++-------- .../format/generator/FormatGenerator.java | 24 ++-- .../jvmmodel/FormatJvmModelInferrer.java | 6 +- .../parser/common/GrammarRuleAnnotations.java | 14 +-- .../ui/compare/CompareFragment2.java | 44 ++++---- 11 files changed, 229 insertions(+), 320 deletions(-) diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java index a81e4178c8..7cac84859d 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/IssueCodeToLabelMapGenerationTest.java @@ -45,18 +45,14 @@ public class IssueCodeToLabelMapGenerationTest extends AbstractCheckGenerationTe @Test public void testMapGenerationWithNoChecks() { // ARRANGE - StringBuilder builder = new StringBuilder(512); - builder.append("package "); - builder.append(PACKAGE_NAME); - builder.append('\n'); - builder.append('\n'); - builder.append("catalog "); - builder.append(CATALOG_NAME); - builder.append('\n'); - builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); - builder.append('\n'); - builder.append("}\n"); - final String source = builder.toString(); + final String source = String.format(""" + package %s + + catalog %s + for grammar com.avaloq.tools.ddk.check.Check { + + } + """, PACKAGE_NAME, CATALOG_NAME); // check for the construction of an empty map final List expectedCatalog = List.of("ImmutableMap.builderWithExpectedSize(0).build()"); @@ -71,45 +67,37 @@ public void testMapGenerationWithNoChecks() { @Test public void testMapGeneration() { // ARRANGE - // CHECKSTYLE:CHECK-OFF VariableDeclarationUsageDistance - // @Format-Off - StringBuilder builder = new StringBuilder(2048); - builder.append("package "); - builder.append(PACKAGE_NAME); - builder.append('\n'); - builder.append('\n'); - builder.append("import com.avaloq.tools.ddk.check.check.Check\n"); - builder.append("import com.avaloq.tools.ddk.check.check.Context\n"); - builder.append("import com.avaloq.tools.ddk.check.check.Documented\n"); - builder.append('\n'); - builder.append("catalog "); - builder.append(CATALOG_NAME); - builder.append('\n'); - builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); - builder.append('\n'); - builder.append(" live error ID1 \"Label 1\"\n"); - builder.append(" message \"Message 1\" {\n"); - builder.append(" for Documented elem {\n"); - builder.append(" switch elem {\n"); - builder.append(" Context : issue on elem\n"); - builder.append(" Check : issue on elem\n"); - builder.append(" }\n"); - builder.append(" }\n"); - builder.append(" }\n"); - builder.append('\n'); - builder.append(" live error ID2 \"Label 2\"\n"); - builder.append(" message \"Message 2\" {\n"); - builder.append(" for Documented elem {\n"); - builder.append(" switch elem {\n"); - builder.append(" Context : issue on elem\n"); - builder.append(" Check : issue on elem\n"); - builder.append(" }\n"); - builder.append(" }\n"); - builder.append(" }\n"); - builder.append("}\n"); - final String source = builder.toString(); - // CHECKSTYLE:CHECK-ON VariableDeclarationUsageDistance - // @Format-On + final String source = String.format(""" + package %s + + import com.avaloq.tools.ddk.check.check.Check + import com.avaloq.tools.ddk.check.check.Context + import com.avaloq.tools.ddk.check.check.Documented + + catalog %s + for grammar com.avaloq.tools.ddk.check.Check { + + live error ID1 "Label 1" + message "Message 1" { + for Documented elem { + switch elem { + Context : issue on elem + Check : issue on elem + } + } + } + + live error ID2 "Label 2" + message "Message 2" { + for Documented elem { + switch elem { + Context : issue on elem + Check : issue on elem + } + } + } + } + """, PACKAGE_NAME, CATALOG_NAME); final List expectedCatalog = List.of("put(MyCatalogIssueCodes.ID_1,\"Label1\")", "put(MyCatalogIssueCodes.ID_2,\"Label2\")"); diff --git a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java index 4307aa6a6e..daf7251851 100644 --- a/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java +++ b/com.avaloq.tools.ddk.check.core.test/src/com/avaloq/tools/ddk/check/core/test/util/CheckModelUtil.java @@ -26,11 +26,7 @@ public class CheckModelUtil { * @return the model stub string */ public String modelWithGrammar() { - StringBuilder builder = new StringBuilder(512); - builder.append("package com.test"); - builder.append('\n'); - builder.append("catalog c for grammar g {"); - return builder.toString(); + return "package com.test\n" + "catalog c for grammar g {"; } /** @@ -39,10 +35,7 @@ public String modelWithGrammar() { * @return the model stub string */ public String modelWithCategory() { - String modelWithGrammar = this.modelWithGrammar(); - StringBuilder builder = new StringBuilder(512); - builder.append("category \"Default Category\" {"); - return modelWithGrammar + builder.toString(); + return this.modelWithGrammar() + "category \"Default Category\" {"; } /** @@ -55,14 +48,7 @@ public String modelWithCategory() { * @return the category string */ public String emptyCategory(final String id, final String label) { - StringBuilder builder = new StringBuilder(512); - builder.append("category "); - builder.append(id); - builder.append(" \""); - builder.append(label); - builder.append("\" {\n"); - builder.append('}'); - return builder.toString(); + return String.format("category %s \"%s\" {\n}", id, label); } /** @@ -76,21 +62,8 @@ public String emptyCategory(final String id, final String label) { * the default severity * @return the model stub string */ - // CHECKSTYLE:CHECK-OFF VariableDeclarationUsageDistance public String modelWithSeverityRange(final String min, final String max, final String severity) { - String modelWithCategory = this.modelWithCategory(); - StringBuilder builder = new StringBuilder(512); - builder.append("@SeverityRange("); - builder.append(min); - builder.append(" .. "); - builder.append(max); - builder.append(")\n"); - builder.append(" "); - builder.append(severity); - builder.append(" ID \"My Check\" ()\n"); - builder.append(" "); - builder.append("message \"My Message\""); - return modelWithCategory + builder.toString(); + return this.modelWithCategory() + String.format("@SeverityRange(%s .. %s)\n %s ID \"My Check\" ()\n message \"My Message\"", min, max, severity); } /** @@ -103,14 +76,7 @@ public String modelWithSeverityRange(final String min, final String max, final S * @return the model stub string */ public String modelWithSeverityRange(final String min, final String max) { - String modelWithCategory = this.modelWithCategory(); - StringBuilder builder = new StringBuilder(512); - builder.append("@SeverityRange("); - builder.append(min); - builder.append(" .. "); - builder.append(max); - builder.append(")\n"); - return modelWithCategory + builder.toString() + modelWithCheck(); + return this.modelWithCategory() + String.format("@SeverityRange(%s .. %s)\n", min, max) + modelWithCheck(); } /** @@ -121,15 +87,8 @@ public String modelWithSeverityRange(final String min, final String max) { * @return the model stub string */ public String modelWithCheck(final String id) { - String modelWithCategory = this.modelWithCategory(); - StringBuilder builder = new StringBuilder(512); - builder.append("error "); - builder.append(id); - builder.append(" \"Some Error\" ()\n"); - builder.append("message \"My Message\" {"); - return modelWithCategory + builder.toString(); + return this.modelWithCategory() + String.format("error %s \"Some Error\" ()\nmessage \"My Message\" {", id); } - // CHECKSTYLE:CHECK-ON VariableDeclarationUsageDistance /** * Returns a base model stub with a check (SomeError) with severity 'error' @@ -149,13 +108,7 @@ public String modelWithCheck() { * @return the check string */ public String emptyCheck(final String id) { - StringBuilder builder = new StringBuilder(512); - builder.append("error "); - builder.append(id); - builder.append(" \"Some Error\" ()\n"); - builder.append("message \"My message\" {\n"); - builder.append('}'); - return builder.toString(); + return String.format("error %s \"Some Error\" ()\nmessage \"My message\" {\n}", id); } /** @@ -165,10 +118,7 @@ public String emptyCheck(final String id) { * @return the model stub string */ public String modelWithContext() { - String modelWithCheck = this.modelWithCheck(); - StringBuilder builder = new StringBuilder(512); - builder.append("for ContextType ctx {"); - return modelWithCheck + builder.toString(); + return this.modelWithCheck() + "for ContextType ctx {"; } /** @@ -195,25 +145,24 @@ public String modelWithContexts(final List contexts) { * @return the model stub string */ public String modelWithComments() { - StringBuilder builder = new StringBuilder(512); - builder.append("package com.test // SL1\n"); - builder.append("/* ML1 */\n"); - builder.append("catalog c /* ML2 */ for grammar g {\n"); - builder.append(" // SL2\n"); - builder.append(" category \"My cat\" {\n"); - builder.append(" /* ML3 */\n"); - builder.append(" // SL3\n"); - builder.append(" error MYerr \"My Err\" (int Abc = 23) message \"A\" {\n"); - builder.append(" for Atype thisName {\n"); - builder.append(" val x = 3 // SL4\n"); - builder.append(" // SL5\n"); - builder.append(" /* ML5 */ issue /* ML4 */\n"); - builder.append(" // SL6\n"); - builder.append(" }\n"); - builder.append(" }\n"); - builder.append(" } // SL7\n"); - builder.append('}'); - return builder.toString(); + return """ + package com.test // SL1 + /* ML1 */ + catalog c /* ML2 */ for grammar g { + // SL2 + category "My cat" { + /* ML3 */ + // SL3 + error MYerr "My Err" (int Abc = 23) message "A" { + for Atype thisName { + val x = 3 // SL4 + // SL5 + /* ML5 */ issue /* ML4 */ + // SL6 + } + } + } // SL7 + }"""; } } // CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java index d963e2b268..7e46ee1492 100644 --- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java +++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.java @@ -85,26 +85,25 @@ public void doGenerate(final Resource resource, final IFileSystemAccess fsa) { /* Documentation compiler, generates HTML output. */ public CharSequence compileDoc(final CheckCatalog catalog) { final CharSequence body = bodyDoc(catalog); - final StringBuilder sb = new StringBuilder(512); - sb.append("\n"); - sb.append("\n"); - sb.append("\n"); - sb.append(" \n"); - sb.append(" \n"); - sb.append(" ").append(catalog.getName()).append("\n"); - sb.append("\n"); - sb.append('\n'); - sb.append("\n"); - sb.append("

    Check Catalog ").append(catalog.getName()).append("

    \n"); final String formattedDescription = generatorExtensions.formatDescription(catalog.getDescription()); - if (formattedDescription != null) { - sb.append("

    ").append(formattedDescription).append("

    \n"); - } - sb.append(" ").append(body).append('\n'); - sb.append("\n"); - sb.append('\n'); - sb.append("\n"); - return sb; + final String descriptionHtml = formattedDescription != null ? "

    " + formattedDescription + "

    \n" : ""; + final String name = catalog.getName(); + return String.format(""" + + + + + + %1$s + + + +

    Check Catalog %1$s

    + %2$s %3$s + + + + """, name, descriptionHtml, body); } public CharSequence bodyDoc(final CheckCatalog catalog) { diff --git a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java index d9567dae2b..f0940dd04a 100644 --- a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java +++ b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/CheckQuickfixTest.java @@ -46,13 +46,7 @@ public class CheckQuickfixTest extends AbstractCheckQuickfixTest { private boolean oldAutoBuildState; public String getTestSourceFileName(final String catalogName) { - StringBuilder builder = new StringBuilder(512); - builder.append(PACKAGE_NAME.replace(".", "/")); - builder.append('/'); - builder.append(catalogName); - builder.append('.'); - builder.append(getXtextTestUtil().getFileExtension()); - return builder.toString(); + return PACKAGE_NAME.replace(".", "/") + '/' + catalogName + '.' + getXtextTestUtil().getFileExtension(); } @Override @@ -98,24 +92,21 @@ private void cleanUp() { @Test @BugTest(value = "DSL-244") public void testImportFix() { - StringBuilder builder = new StringBuilder(512); - builder.append("package "); - builder.append(PACKAGE_NAME); - builder.append('\n'); - builder.append('\n'); - builder.append("catalog "); - builder.append(getTestSourceModelName()); - builder.append(" for grammar org.eclipse.xtext.Xtext\n"); - builder.append("{\n"); - builder.append(" /** Missing import test */\n"); - builder.append(" warning TestWarning \"Test Warning\"\n"); - builder.append(" message \"This is a Test Warning\" {\n"); - builder.append(" for AbstractRule c {\n"); - builder.append(" issue\n"); - builder.append(" }\n"); - builder.append(" }\n"); - builder.append("}\n"); - createTestSource(getTestSourceFileName(), builder.toString()); + String source = String.format(""" + package %s + + catalog %s for grammar org.eclipse.xtext.Xtext + { + /** Missing import test */ + warning TestWarning "Test Warning" + message "This is a Test Warning" { + for AbstractRule c { + issue + } + } + } + """, PACKAGE_NAME, getTestSourceModelName()); + createTestSource(getTestSourceFileName(), source); openEditor(getTestSourceFileName()); final String quickfixLabel = "Import 'AbstractRule' (org.eclipse.xtext)"; final List beforeIssues = getXtextTestUtil().getIssues(getDocument()); @@ -131,37 +122,29 @@ public void testImportFix() { @Test public void testAddID() { // ARRANGE - StringBuilder builder = new StringBuilder(512); - builder.append("package "); - builder.append(PACKAGE_NAME); - builder.append('\n'); - builder.append('\n'); - builder.append("catalog "); - builder.append(getTestSourceModelName()); - builder.append('\n'); - builder.append("for grammar org.eclipse.xtext.Xtext {\n"); - builder.append('\n'); - builder.append(" warning \"Test Warning\"\n"); - builder.append(" message \"This is a Test Warning\" {\n"); - builder.append(" }\n"); - builder.append("}\n"); - final String sourceContent = builder.toString(); - - StringBuilder builder2 = new StringBuilder(512); - builder2.append("package "); - builder2.append(PACKAGE_NAME); - builder2.append('\n'); - builder2.append('\n'); - builder2.append("catalog "); - builder2.append(getTestSourceModelName()); - builder2.append('\n'); - builder2.append("for grammar org.eclipse.xtext.Xtext {\n"); - builder2.append('\n'); - builder2.append(" warning TestWarning \"Test Warning\"\n"); - builder2.append(" message \"This is a Test Warning\" {\n"); - builder2.append(" }\n"); - builder2.append("}\n"); - final String expectedContent = builder2.toString(); + final String sourceContent = String.format(""" + package %s + + catalog %s + for grammar org.eclipse.xtext.Xtext { + + warning "Test Warning" + message "This is a Test Warning" { + } + } + """, PACKAGE_NAME, getTestSourceModelName()); + + final String expectedContent = String.format(""" + package %s + + catalog %s + for grammar org.eclipse.xtext.Xtext { + + warning TestWarning "Test Warning" + message "This is a Test Warning" { + } + } + """, PACKAGE_NAME, getTestSourceModelName()); // ACT and ASSERT assertQuickFixExistsAndSuccessfulInCustomerSource(IssueCodes.MISSING_ID_ON_CHECK, diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java index 8bdde50623..aadb55cf26 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/contentassist/CheckCfgContentAssistTest.java @@ -59,28 +59,30 @@ protected void afterAllTests() { @Test public void testConfiguredParameterProposals() { - final StringBuilder builder = new StringBuilder(512); - builder.append("check configuration Test {\n"); - builder.append(" catalog TestChecks {\n"); - builder.append(" default Test (\n"); - builder.append(" ").append(TestPropertySpecificationWithExpectedValues.INSTANCE.getName()).append(" = ").append(expected(TestPropertySpecificationWithExpectedValues.INSTANCE.getExpectedValues())).append("\"banana\"\n"); - builder.append(" )\n"); - builder.append(" }\n"); - builder.append("}\n"); - assertKernelSourceProposals("ConfiguredParameterProposals.checkcfg", builder); + final String source = String.format(""" + check configuration Test { + catalog TestChecks { + default Test ( + %s = %s"banana" + ) + } + } + """, TestPropertySpecificationWithExpectedValues.INSTANCE.getName(), expected(TestPropertySpecificationWithExpectedValues.INSTANCE.getExpectedValues())); + assertKernelSourceProposals("ConfiguredParameterProposals.checkcfg", source); } @BugTest(value = "DSL-1811", unresolved = true) public void testNoTypeMismatchedParameterValueProposals() { - final StringBuilder builder = new StringBuilder(512); - builder.append("check configuration Test {\n"); - builder.append(" catalog TestChecks {\n"); - builder.append(" default Test (\n"); - builder.append(" ").append(TestPropertySpecificationWithExpectedValues.INSTANCE.getName()).append(" = ").append(expectedExactly(TestPropertySpecificationWithExpectedValues.INSTANCE.getExpectedValues())).append("\"banana\"\n"); - builder.append(" )\n"); - builder.append(" }\n"); - builder.append("}\n"); - assertKernelSourceProposals("NoTypeMismatchedParameterValueProposals.checkcfg", builder); + final String source = String.format(""" + check configuration Test { + catalog TestChecks { + default Test ( + %s = %s"banana" + ) + } + } + """, TestPropertySpecificationWithExpectedValues.INSTANCE.getName(), expectedExactly(TestPropertySpecificationWithExpectedValues.INSTANCE.getExpectedValues())); + assertKernelSourceProposals("NoTypeMismatchedParameterValueProposals.checkcfg", source); } } // CHECKSTYLE:CONSTANTS-ON diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java index 5b6035896d..4faa393319 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/scoping/CheckCfgScopeProviderTest.java @@ -53,11 +53,7 @@ public void testCatalogsAreInCorrectPackage() throws Exception { // Define test data final int cursorPos = getTag(); - final StringBuilder sourceBuilder = new StringBuilder(512); - sourceBuilder.append("check configuration testCheckCfg {\n"); - sourceBuilder.append(" ").append(mark(cursorPos)).append('\n'); - sourceBuilder.append("}\n"); - final String sourceContent = sourceBuilder.toString(); + final String sourceContent = "check configuration testCheckCfg {\n " + mark(cursorPos) + "\n}\n"; // Register a check configuration source, and get a context model registerModel(getTestSourceFileName(), sourceContent); diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java index 07d4fff82e..a041240077 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/syntax/CheckCfgSyntaxTest.java @@ -35,68 +35,68 @@ protected List getRequiredSourceFileNames() { @BeforeAll public void setup() { - final StringBuilder builder = new StringBuilder(512); - builder.append("package checkcfgtest\n"); - builder.append('\n'); - builder.append("import com.avaloq.tools.ddk.check.check.Check\n"); - builder.append('\n'); - builder.append("catalog CheckCfgTestChecks\n"); - builder.append("for grammar com.avaloq.tools.ddk.check.Check {\n"); - builder.append(" /**\n"); - builder.append(" * Test Error Documentation\n"); - builder.append(" */\n"); - builder.append(" live error TestError \"Test Error\"\n"); - builder.append(" message \"Test Error message.\" {\n"); - builder.append(" for Check c {\n"); - builder.append(" issue on c#name;\n"); - builder.append(" }\n"); - builder.append(" }\n"); - builder.append("}\n"); - final String checkSource = builder.toString(); + final String checkSource = """ + package checkcfgtest + + import com.avaloq.tools.ddk.check.check.Check + + catalog CheckCfgTestChecks + for grammar com.avaloq.tools.ddk.check.Check { + /** + * Test Error Documentation + */ + live error TestError "Test Error" + message "Test Error message." { + for Check c { + issue on c#name; + } + } + } + """; addCustomerSourceToWorkspace("customer$sca_testchecks.check", checkSource); IResourcesSetupUtil.waitForBuild(); } @Test public void testSyntax() { - final StringBuilder builder = new StringBuilder(256); - builder.append("check configuration checkconfiguration {\n"); - builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); - builder.append(" default TestError\n"); - builder.append(" }\n"); - builder.append("}\n"); - final String checkcfgSource = builder.toString(); + final String checkcfgSource = """ + check configuration checkconfiguration { + catalog checkcfgtest.CheckCfgTestChecks { + default TestError + } + } + """; validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource); } @Test public void testSyntaxConfiguredLanguage() { - final StringBuilder builder = new StringBuilder(256); - builder.append("check configuration checkconfiguration\n"); - builder.append(" for com.avaloq.tools.ddk.^check.TestLanguage {\n"); - builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); - builder.append(" default TestError\n"); - builder.append(" }\n"); - builder.append(" }\n"); - final String checkcfgSource = builder.toString(); + final String checkcfgSource = """ + check configuration checkconfiguration + for com.avaloq.tools.ddk.^check.TestLanguage { + catalog checkcfgtest.CheckCfgTestChecks { + default TestError + } + } + """; validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource); } @Test public void testPropertiesOnAllLevels() { - final StringBuilder builder = new StringBuilder(512); - builder.append("check configuration checkconfiguration\n"); - builder.append(" integrationRelevant = true\n"); - builder.append(" testBooleanList = #[true, false, false]\n"); - builder.append('\n'); - builder.append(" for com.avaloq.tools.ddk.^check.TestLanguage {\n"); - builder.append(" nameOverrides = #['altName1', 'altName2']\n"); - builder.append('\n'); - builder.append(" catalog checkcfgtest.CheckCfgTestChecks {\n"); - builder.append(" default TestError(testNumber = 3, testNumberList = #[1, 2, 3])\n"); - builder.append(" }\n"); - builder.append(" }\n"); - final String checkcfgSource = builder.toString(); + final String checkcfgSource = """ + check configuration checkconfiguration + integrationRelevant = true + testBooleanList = #[true, false, false] + + for com.avaloq.tools.ddk.^check.TestLanguage { + nameOverrides = #['altName1', 'altName2'] + + catalog checkcfgtest.CheckCfgTestChecks { + default TestError(testNumber = 3, testNumberList = #[1, 2, 3]) + } + } + """; validateCustomerSourceStrictly("checkconfiguration.checkcfg", checkcfgSource); } } diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java index 741c218efb..e3c6122bd0 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/generator/FormatGenerator.java @@ -98,16 +98,20 @@ public void doGenerate(final Resource resource, final IFileSystemAccess fsa) { } public CharSequence generateSrc(final FormatConfiguration model) { - final StringBuilder builder = new StringBuilder(256); - builder.append("package ").append(Strings.skipLastToken(getFormatterName(model, ""), ".")).append(";\n"); - builder.append('\n'); - builder.append("/**\n"); - builder.append(" * The formatting configuration for ").append(Strings.lastToken(model.getTargetGrammar().getName(), ".")).append(".\n"); - builder.append(" */\n"); - builder.append("public class ").append(Strings.lastToken(getFormatterName(model, ""), ".")).append(" extends ").append(Strings.lastToken(getFormatterName(model, "Abstract"), ".")).append(" {\n"); - builder.append(" // TODO: Provide a correct implementation of getSLCommentRule() and getMLCommentRule() in this class\n"); - builder.append("}\n"); - return builder; + String packageName = Strings.skipLastToken(getFormatterName(model, ""), "."); + String grammarName = Strings.lastToken(model.getTargetGrammar().getName(), "."); + String className = Strings.lastToken(getFormatterName(model, ""), "."); + String baseClassName = Strings.lastToken(getFormatterName(model, "Abstract"), "."); + return String.format(""" + package %s; + + /** + * The formatting configuration for %s. + */ + public class %s extends %s { + // TODO: Provide a correct implementation of getSLCommentRule() and getMLCommentRule() in this class + } + """, packageName, grammarName, className, baseClassName); } @Override diff --git a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java index 356cd007d7..41cc326177 100644 --- a/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java +++ b/com.avaloq.tools.ddk.xtext.format/src/com/avaloq/tools/ddk/xtext/format/jvmmodel/FormatJvmModelInferrer.java @@ -231,11 +231,7 @@ public boolean inferGetGrammarAccess(final FormatConfiguration format, final Jvm jvmTypesBuilder.operator_add(op.getAnnotations(), overrideAnnotation); } jvmTypesBuilder.setBody(op, (ITreeAppendable body) -> { - StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_CAPACITY); - sb.append("return ("); - sb.append(GrammarUtil.getSimpleName(format.getTargetGrammar())).append("GrammarAccess"); - sb.append(") super.getGrammarAccess();"); - body.append(sb); + body.append("return (" + GrammarUtil.getSimpleName(format.getTargetGrammar()) + "GrammarAccess) super.getGrammarAccess();"); }); }); return jvmTypesBuilder.operator_add(it.getMembers(), method); diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java index be9188dca3..7a271ba1fd 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/parser/common/GrammarRuleAnnotations.java @@ -604,21 +604,11 @@ public boolean isFirstNonActionElement(final Group group, final AbstractElement } public String generateGatedPredicate(final SemanticPredicate predicate) { - StringBuilder sb = new StringBuilder(64); - sb.append("{predicates."); - sb.append(predicate.name); - sb.append("(parserContext)}?=>"); - return sb.toString(); + return "{predicates." + predicate.name + "(parserContext)}?=>"; } public String generateValidatingPredicate(final SemanticPredicate predicate) { - StringBuilder sb = new StringBuilder(64); - sb.append("{predicates."); - sb.append(predicate.name); - sb.append("(parserContext) /* @ErrorMessage("); - sb.append(predicate.message); - sb.append(") */}?"); - return sb.toString(); + return "{predicates." + predicate.name + "(parserContext) /* @ErrorMessage(" + predicate.message + ") */}?"; } /** diff --git a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java index b995334856..ce45eb2957 100644 --- a/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java +++ b/com.avaloq.tools.ddk.xtext.generator/src/com/avaloq/tools/ddk/xtext/generator/ui/compare/CompareFragment2.java @@ -74,28 +74,30 @@ public void generate() { // CHECKSTYLE:CONSTANTS-OFF public CharSequence eclipsePluginXmlContribution() { final TypeReference executableExtensionFactory = xtextGeneratorNaming.getEclipsePluginExecutableExtensionFactory(getGrammar()); + final String grammarName = getGrammar().getName(); final String fileExtensions = String.join(",", getLanguage().getFileExtensions()); - final StringBuilder builder = new StringBuilder(1024); - builder.append("\n"); - builder.append("\n"); - builder.append(" \n"); - builder.append(" \n"); - builder.append("\n"); - builder.append("\n"); - builder.append(" \n"); - builder.append(" \n"); - builder.append("\n"); - builder.append("\n"); - builder.append(" \n"); - builder.append(" \n"); - builder.append("\n"); - return builder; + final String simpleName = GrammarUtil.getSimpleName(getGrammar()); + return String.format(""" + + + + + + + + + + + + + + """, TypeReference.typeRef(CompareFragment2.class), grammarName, executableExtensionFactory, fileExtensions, simpleName); } // CHECKSTYLE:CONSTANTS-ON }