«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..531d54f3c1
--- /dev/null
+++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGeneratorExtensions.java
@@ -0,0 +1,522 @@
+/*******************************************************************************
+ * 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.nio.charset.StandardCharsets;
+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 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 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 static com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming.issueCodesClassName;
+import static com.avaloq.tools.ddk.check.generator.CheckGeneratorNaming.parent;
+
+
+/**
+ * Extension methods used by the Check generator.
+ */
+@SuppressWarnings({"checkstyle:MethodName", "nls"})
+public class CheckGeneratorExtensions {
+
+ /**
+ * 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) {
+ final 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.
+ *
+ * @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.
+ *
+ * @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 {
+ 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.
+ *
+ * @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()) {
+ 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.
+ *
+ * @param check
+ * the check
+ * @return the issue name string
+ */
+ protected static String _issueName(final 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.
+ *
+ * @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()) {
+ return issueName(issue.getCheck());
+ } else if (parent(issue, Check.class) != null) {
+ return issueName(parent(issue, Check.class));
+ } else {
+ return "ErrorIssueCodeName_XIssueExpresion"; // should not happen
+ }
+ }
+
+ /**
+ * 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