diff options
author | Christian W. Damus | 2020-12-11 20:50:56 +0000 |
---|---|---|
committer | Christian W. Damus | 2020-12-11 20:50:56 +0000 |
commit | 15b20e90540e9d3c7fc1022a0aae492a61d579ee (patch) | |
tree | 39842b17be869e7eec531643e36c87ab460d91d2 | |
parent | 21127e8b971970df64664cf8b5317c2ece7b55bd (diff) | |
download | org.eclipse.papyrus-15b20e90540e9d3c7fc1022a0aae492a61d579ee.tar.gz org.eclipse.papyrus-15b20e90540e9d3c7fc1022a0aae492a61d579ee.tar.xz org.eclipse.papyrus-15b20e90540e9d3c7fc1022a0aae492a61d579ee.zip |
Bug 569357: [Toolsmiths] ElementTypes: Model and Plug-in Validation
- handle extraction of bundle dependency name from bundleresource:// URIs
- aupport aggregation of the same diagnostic from different sources into a single marker
https://bugs.eclipse.org/bugs/show_bug.cgi?id=569357
Signed-off-by: Christian W. Damus <give.a.damus@gmail.com>
Change-Id: Id284fafe7d33c06628becfe13fec6144ac81dfc0
6 files changed, 371 insertions, 17 deletions
diff --git a/plugins/toolsmiths/builder/org.eclipse.papyrus.toolsmiths.plugin.builder/src/org/eclipse/papyrus/toolsmiths/plugin/builder/PluginCheckerBuilder.java b/plugins/toolsmiths/builder/org.eclipse.papyrus.toolsmiths.plugin.builder/src/org/eclipse/papyrus/toolsmiths/plugin/builder/PluginCheckerBuilder.java index d698ad0c8e5..64e49f148f9 100644 --- a/plugins/toolsmiths/builder/org.eclipse.papyrus.toolsmiths.plugin.builder/src/org/eclipse/papyrus/toolsmiths/plugin/builder/PluginCheckerBuilder.java +++ b/plugins/toolsmiths/builder/org.eclipse.papyrus.toolsmiths.plugin.builder/src/org/eclipse/papyrus/toolsmiths/plugin/builder/PluginCheckerBuilder.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Function; +import java.util.stream.Stream; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; @@ -29,13 +30,13 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.DiagnosticChain; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.papyrus.toolsmiths.validation.common.checkers.DiagnosticEquivalence; import org.eclipse.papyrus.toolsmiths.validation.common.checkers.IPluginChecker2; +import org.eclipse.papyrus.toolsmiths.validation.common.utils.CheckerDiagnosticChain; import org.eclipse.papyrus.toolsmiths.validation.common.utils.MarkersService; import com.google.common.collect.ListMultimap; @@ -117,7 +118,7 @@ public class PluginCheckerBuilder extends AbstractPapyrusBuilder { // And one more for actually creating problem markers. SubMonitor subMonitor = SubMonitor.convert(monitor, (1 + sets.keySet().size()) * checkerFactories.size() + 1); - BasicDiagnostic diagnostics = new BasicDiagnostic(); + CheckerDiagnosticChain diagnostics = new CheckerDiagnosticChain(); // First, see about checking the project as a whole check(builtProject, null, null, diagnostics, subMonitor); @@ -130,7 +131,7 @@ public class PluginCheckerBuilder extends AbstractPapyrusBuilder { // Create markers if the validation is not OK if (diagnostics.getSeverity() > Diagnostic.OK) { - wrap(diagnostics).getChildren().stream().distinct().forEach(this::createMarker); + wrap(diagnostics.stream()).distinct().forEach(this::createMarker); } subMonitor.worked(1); @@ -189,4 +190,8 @@ public class PluginCheckerBuilder extends AbstractPapyrusBuilder { : diagnosticEquivalence.wrap(diagnostic); } + private Stream<Diagnostic> wrap(Stream<Diagnostic> diagnostics) { + return diagnostics.map(this::wrap); + } + } diff --git a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/AbstractPluginChecker.java b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/AbstractPluginChecker.java index 4699ce1c29f..c044fef3a59 100644 --- a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/AbstractPluginChecker.java +++ b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/AbstractPluginChecker.java @@ -17,6 +17,7 @@ package org.eclipse.papyrus.toolsmiths.validation.common.checkers; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; @@ -25,6 +26,7 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.papyrus.toolsmiths.validation.common.utils.CheckerDiagnosticChain; import org.eclipse.papyrus.toolsmiths.validation.common.utils.MarkersService; import com.google.common.collect.Lists; @@ -78,13 +80,13 @@ public abstract class AbstractPluginChecker implements IPluginChecker, IPluginCh @Override public void check(IProgressMonitor monitor) { - BasicDiagnostic diagnostics = new BasicDiagnostic(); + CheckerDiagnosticChain diagnostics = new CheckerDiagnosticChain(diagnosticEquivalence); check(diagnostics, monitor); // Create markers if the validation is not OK if (diagnostics.getSeverity() > Diagnostic.OK) { - wrap(diagnostics).getChildren().stream().distinct().forEach(this::createMarker); + wrap(diagnostics.stream()).distinct().forEach(this::createMarker); } } @@ -129,4 +131,8 @@ public abstract class AbstractPluginChecker implements IPluginChecker, IPluginCh : diagnosticEquivalence.wrap(diagnostic); } + private Stream<Diagnostic> wrap(Stream<Diagnostic> diagnostics) { + return diagnostics.map(this::wrap); + } + } diff --git a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/IPluginChecker2.java b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/IPluginChecker2.java index 3c2b062d1f6..0341f72a5e0 100644 --- a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/IPluginChecker2.java +++ b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/IPluginChecker2.java @@ -15,10 +15,14 @@ package org.eclipse.papyrus.toolsmiths.validation.common.checkers; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; @@ -30,6 +34,7 @@ import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.DiagnosticChain; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.osgi.util.NLS; import org.eclipse.papyrus.infra.emf.utils.ResourceUtils; import org.eclipse.papyrus.toolsmiths.validation.common.Activator; @@ -167,6 +172,69 @@ public interface IPluginChecker2 { return new MarkerAttribute(IMarker.LOCATION, location); } + /** + * Create a dynamic message argument to be plugged into the message when creating a marker from the diagnostic. + * The power of dynamic messages comes from how they are accumulated: when appending a diagnostic that has dynamic + * message arguments to a {@code DiagnosticChain}, the message arguments will be merged with an existing dynamic-message + * diagnostic that represents the same problem (is otherwise equivalent). Of course, this only works with the + * diagnostic chain that is passed by the <em>Plugin Builder</em> and to its checkers. + * + * @param index + * the message parameter index to fill + * @param value + * the value to fill it with + * + * @return the dynamic message argument + */ + static DynamicMessageArgument dynamicMessageArgument(int index, Object value) { + return new DynamicMessageArgument(index, value); + } + + /** + * Query whether a {@code diagnostic} has a "dynamic message" that is composed from its + * arguments at the time of creating the marker. + * + * @param diagnostic + * a diagnostic + * @return whether it has any {@linkplain #dynamicMessageArgument(int, Object) dynamic message arguments} + * + * @see #dynamicMessageArgument(int, Object) + */ + static boolean hasDynamicMessage(Diagnostic diagnostic) { + List<?> data = diagnostic.getData(); + return data != null && data.stream().anyMatch(DynamicMessageArgument.class::isInstance); + } + + /** + * Compose the "dynamic message" from a {@code diagnostic}. + * + * @param diagnostic + * a diagnostic that {@linkplain #hasDynamicMessage(Diagnostic) has a dynamic message} + * @return the dynamic message + * + * @see #hasDynamicMessage(Diagnostic) + * @see #dynamicMessageArgument(int, Object) + */ + static String getDynamicMessage(Diagnostic diagnostic) { + Object[] args = DynamicMessageArgument.stream(diagnostic) + .map(DynamicMessageArgument::getValueAsString) + .toArray(); + return NLS.bind(diagnostic.getMessage(), args); + } + + /** + * Get the message of a {@code diagnostic}, whether it is a {@linkplain Diagnostic#getMessage() static message} + * or a {@linkplain #getDynamicMessage(Diagnostic) dynamic message}. Whichever it is, it will be the message + * that should be stored in the marker. + * + * @param diagnostic + * a diagnostic + * @return its message + */ + static String getMessage(Diagnostic diagnostic) { + return hasDynamicMessage(diagnostic) ? getDynamicMessage(diagnostic) : diagnostic.getMessage(); + } + // // Nested types // @@ -392,4 +460,132 @@ public interface IPluginChecker2 { } + /** + * <p> + * A token to put in the {@linkplain Diagnostic#getData() data list} of a {@link Diagnostic} to specify a positional + * argument in a dynamic message that is composed when creating the marker from the message pattern. + * </p> + * <p> + * The values of dynamic message arguments are ignored in the comparison of {@link Diagnostic}s because all values + * in the same position from diagnostics of the same message pattern and severity (and other attributes) are combined + * when generating the message for the marker. + * </p> + */ + static final class DynamicMessageArgument implements Comparable<DynamicMessageArgument> { + private final int index; + private Object value; + + /** + * Create a new positional dynamic message argument. + * + * @param index + * the index of the message parameter to substitute + * @param value + * the value to substitute for that parameter + */ + public DynamicMessageArgument(int index, Object value) { + this.index = index; + this.value = value; + } + + public int getIndex() { + return index; + } + + public Object getValue() { + return value; + } + + public String getValueAsString() { + if (value == null) { + return ""; //$NON-NLS-1$ + } + if (value instanceof Collection) { + return ((Collection<?>) value).stream() + .filter(Objects::nonNull) + .map(Object::toString) + .collect(Collectors.joining(", ")); //$NON-NLS-1$ + } + return String.valueOf(value); + } + + public void merge(DynamicMessageArgument argument) { + if (argument.getIndex() != getIndex()) { + throw new IllegalArgumentException("attempt to merge arguments at different positions"); //$NON-NLS-1$ + } + + if (this.value == null) { + this.value = safeCopy(argument.getValue()); + } else if (this.value instanceof Collection<?>) { + @SuppressWarnings("unchecked") + Collection<Object> collection = (Collection<Object>) this.value; + merge(collection, safeCopy(argument.getValue())); + } else { + Collection<Object> collection = new ArrayList<>(); + collection.add(this.value); + merge(collection, safeCopy(argument.getValue())); + this.value = collection; + } + } + + private Object safeCopy(Object value) { + if (value instanceof Collection) { + return List.copyOf((Collection<?>) value); + } + + return value; + } + + private void merge(Collection<Object> collection, Object value) { + if (value == null) { + // Pass + } else if (value instanceof Collection) { + collection.addAll((Collection<?>) value); + } else { + collection.add(value); + } + } + + @Override + public int compareTo(DynamicMessageArgument o) { + return Integer.compare(getIndex(), o.getIndex()); + } + + @Override + public int hashCode() { + return index; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof DynamicMessageArgument)) { + return false; + } + DynamicMessageArgument other = (DynamicMessageArgument) obj; + return other.getIndex() == getIndex(); + } + + @Override + public String toString() { + return String.format("{%d}=\"%s\"", index, value); + } + + /** + * Obtain a stream over the dynamic message arguments of a {@code diagnostic}, in position order. + * + * @param diagnostic + * a diagnostic + * @return its dynamic message arguments, in order + */ + public static Stream<DynamicMessageArgument> stream(Diagnostic diagnostic) { + return diagnostic.getData().stream() + .filter(DynamicMessageArgument.class::isInstance).map(DynamicMessageArgument.class::cast) + .sorted(); + } + + } + } diff --git a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/ModelDependenciesChecker.java b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/ModelDependenciesChecker.java index d2e2b8d9426..51e2cb5986a 100644 --- a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/ModelDependenciesChecker.java +++ b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/checkers/ModelDependenciesChecker.java @@ -17,12 +17,15 @@ package org.eclipse.papyrus.toolsmiths.validation.common.checkers; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Function; import java.util.function.ToIntFunction; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; @@ -47,6 +50,7 @@ import org.eclipse.papyrus.toolsmiths.validation.common.utils.ProjectManagementS import org.eclipse.pde.internal.core.ibundle.IManifestHeader; import org.eclipse.pde.internal.core.text.bundle.BundleModel; import org.eclipse.pde.internal.core.text.bundle.ManifestHeader; +import org.osgi.framework.Bundle; import org.osgi.framework.Constants; /** @@ -56,6 +60,9 @@ import org.osgi.framework.Constants; @SuppressWarnings("restriction") public class ModelDependenciesChecker extends AbstractPluginChecker { + /** The URI scheme for Equinox's internal <tt>bundleresource://</tt> URIs. */ + private static final String BUNDLE_RESOURCE_SCHEME = "bundleresource"; //$NON-NLS-1$ + /** * The EMF model resource. */ @@ -67,6 +74,9 @@ public class ModelDependenciesChecker extends AbstractPluginChecker { private final List<Function<? super Resource, ? extends Collection<String>>> additionalDependencyFunctions = new ArrayList<>(); + /** Regex to parse the bundle ID out of a URI of <tt>bundleresource:</tt> scheme. */ + private final Pattern bundleResourceAuthorityPattern = Pattern.compile("^\\d+"); //$NON-NLS-1$ + /** * Initializes me to report all missing bundle dependencies as errors. * @@ -189,7 +199,7 @@ public class ModelDependenciesChecker extends AbstractPluginChecker { if (!requiredPlugins.isEmpty()) { requiredPlugins.stream().forEach(requiredPlugin -> { int severity = severityFunction.applyAsInt(requiredPlugin); - errors.add(new ManifestError(getMarkerType(), "The plug-in '" + requiredPlugin + "' must be declared as required plug-in (for '" + resourceName + "').", severity, Constants.REQUIRE_BUNDLE)); + errors.add(new ManifestError(getMarkerType(), "The plug-in ''" + requiredPlugin + "'' must be declared as required plug-in (for ''{0}'').", severity, Constants.REQUIRE_BUNDLE, resourceName)); }); reportErrors(diagnostics, errors); } @@ -209,7 +219,7 @@ public class ModelDependenciesChecker extends AbstractPluginChecker { final IFile manifestFile = ProjectManagementService.getManifestFile(getProject()); BundleModel textBundleModel = prepareTextBundleModel(manifestFile); errors.stream().forEach(error -> { - reportBundleError(diagnostics, manifestFile, textBundleModel, error.type, error.message, error.severity, error.header); + reportBundleError(diagnostics, manifestFile, textBundleModel, error.type, error.message, error.severity, error.header, error.dependentName); }); } } @@ -229,14 +239,22 @@ public class ModelDependenciesChecker extends AbstractPluginChecker { * the severity of the marker to create * @param header * the header entry of the manifest file on which marker is created. + * @param sourceName + * the name of the source of the problem, e.g. the file or whatever that implies the problem */ - private void reportBundleError(DiagnosticChain diagnostics, IFile manifestFile, BundleModel textBundleModel, String type, String message, int severity, String header) { + private void reportBundleError(DiagnosticChain diagnostics, IFile manifestFile, BundleModel textBundleModel, String type, String message, int severity, String header, String sourceName) { Diagnostic diagnostic; if (textBundleModel != null) { - diagnostic = createDiagnostic(manifestFile, severity, 0, message, - IPluginChecker2.markerType(type), - IPluginChecker2.lineNumber(getLineNumber(textBundleModel.getBundle().getManifestHeader(header)))); + List<Object> data = new ArrayList<>(Arrays.asList(IPluginChecker2.markerType(type), + IPluginChecker2.lineNumber(getLineNumber(textBundleModel.getBundle().getManifestHeader(header))))); + + if (sourceName != null) { + // All source names for the same dependency are collected and dynamically injected into the diagnostic message + data.add(IPluginChecker2.dynamicMessageArgument(0, sourceName)); + } + + diagnostic = createDiagnostic(manifestFile, severity, 0, message, data.toArray()); } else { diagnostic = createDiagnostic(manifestFile, severity, 0, message); @@ -381,10 +399,24 @@ public class ModelDependenciesChecker extends AbstractPluginChecker { private String getPluginNameFromURI(final URI uri) { String pluginName = null; - // Take we correct segment (without authority) - final int takenSegment = uri.hasAuthority() ? 0 : 1; - if (uri.segmentCount() > takenSegment) { - pluginName = uri.segment(takenSegment); + if ((uri.isPlatformPlugin() || uri.isPlatformResource()) && uri.segmentCount() > 1) { + pluginName = uri.segment(1); + } else if (BUNDLE_RESOURCE_SCHEME.equals(uri.scheme()) && uri.hasAuthority()) { + Bundle bundle = null; + Matcher m = bundleResourceAuthorityPattern.matcher(uri.authority()); + if (m.find()) { + long bundleID = Long.parseLong(m.group()); + bundle = Activator.getDefault().getBundle().getBundleContext().getBundle(bundleID); + } + if (bundle != null) { + pluginName = bundle.getSymbolicName(); + } + } else { + // Best guess. Take the correct segment (without authority) + final int takenSegment = uri.hasAuthority() ? 0 : 1; + if (uri.segmentCount() > takenSegment) { + pluginName = uri.segment(takenSegment); + } } return pluginName; @@ -435,12 +467,14 @@ public class ModelDependenciesChecker extends AbstractPluginChecker { private final String message; private final int severity; private final String header; + private final String dependentName; - public ManifestError(String type, String message, int severity, String header) { + ManifestError(String type, String message, int severity, String header, String dependentName) { this.type = type; this.message = message; this.severity = severity; this.header = header; + this.dependentName = dependentName; } } } diff --git a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/utils/CheckerDiagnosticChain.java b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/utils/CheckerDiagnosticChain.java new file mode 100644 index 00000000000..39cc4b4e13a --- /dev/null +++ b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/utils/CheckerDiagnosticChain.java @@ -0,0 +1,113 @@ +/***************************************************************************** + * Copyright (c) 2020 CEA LIST and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * CEA LIST - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.toolsmiths.validation.common.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.DiagnosticChain; +import org.eclipse.papyrus.toolsmiths.validation.common.checkers.DiagnosticEquivalence; +import org.eclipse.papyrus.toolsmiths.validation.common.checkers.IPluginChecker2; +import org.eclipse.papyrus.toolsmiths.validation.common.checkers.IPluginChecker2.DynamicMessageArgument; + +/** + * A diagnostic chain implementation that supports the merging of {@link Diagnostic}s for + * {@linkplain IPluginChecker2#dynamicMessageArgument(int, Object) dynamic message arguments}. + * + * @see IPluginChecker2#dynamicMessageArgument(int, Object) + * @see IPluginChecker2#getDynamicMessage(Diagnostic) + */ +public final class CheckerDiagnosticChain implements DiagnosticChain, Iterable<Diagnostic> { + + private final DiagnosticEquivalence diagnosticEquivalence; + private final List<Diagnostic> diagnostics = new ArrayList<>(); + private int severity; + + /** + * Initializes me with the specified diagnostic equivalence semantics. + * + * @param diagnosticEquivalence + * my diagnostic equivalence semantics + */ + public CheckerDiagnosticChain(DiagnosticEquivalence diagnosticEquivalence) { + super(); + + this.diagnosticEquivalence = diagnosticEquivalence; + } + + /** + * Initializes me with the default diagnostic equivalence. + * + * @see DiagnosticEquivalence#DEFAULT + */ + public CheckerDiagnosticChain() { + this(DiagnosticEquivalence.DEFAULT); + } + + @Override + public void add(Diagnostic diagnostic) { + // Find an existing equivalent diagnostic and merge the message arguments + Optional<Diagnostic> existing = !IPluginChecker2.hasDynamicMessage(diagnostic) + ? Optional.empty() + : stream().filter(diag -> diagnosticEquivalence.equals(diag, diagnostic)).findFirst(); + + existing.ifPresentOrElse(target -> { + // The diagnostics could not have been equivalent had they not the same number of arguments + List<DynamicMessageArgument> targetArgs = DynamicMessageArgument.stream(target).collect(Collectors.toList()); + List<DynamicMessageArgument> sourceArgs = DynamicMessageArgument.stream(diagnostic).collect(Collectors.toList()); + IntStream.range(0, targetArgs.size()).forEach(i -> targetArgs.get(i).merge(sourceArgs.get(i))); + }, () -> { + // This is the first diagnostic on this dynamic message pattern + diagnostics.add(diagnostic); + severity = Math.max(severity, diagnostic.getSeverity()); + }); + } + + @Override + public void addAll(Diagnostic diagnostic) { + diagnostic.getChildren().forEach(this::add); + } + + @Override + public void merge(Diagnostic diagnostic) { + if (diagnostic.getChildren().isEmpty()) { + add(diagnostic); + } else { + addAll(diagnostic); + } + } + + @Override + public Iterator<Diagnostic> iterator() { + return Collections.unmodifiableList(diagnostics).iterator(); + } + + public Stream<Diagnostic> stream() { + return diagnostics.stream(); + } + + public int getSeverity() { + return severity; + } + +} diff --git a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/utils/MarkersService.java b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/utils/MarkersService.java index 894d8c06575..9ce43d6bb4d 100644 --- a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/utils/MarkersService.java +++ b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/utils/MarkersService.java @@ -84,7 +84,7 @@ public class MarkersService { ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR; - IMarker result = createMarker(resource, type, diagnostic.getMessage(), severity); + IMarker result = createMarker(resource, type, IPluginChecker2.getMessage(diagnostic), severity); String target = null; StringBuilder related = null; |