blob: aec4109a6c4d95398eba897e91403a98862bcc65 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.xtext.base.utilities;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EObjectValidator;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.utilities.LabelUtil;
import org.eclipse.ocl.xtext.base.cs2as.CS2AS;
import org.eclipse.xtext.diagnostics.Severity;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.util.IAcceptor;
import org.eclipse.xtext.validation.AbstractInjectableValidator;
import org.eclipse.xtext.validation.CancelableDiagnostician;
import org.eclipse.xtext.validation.CheckMode;
import org.eclipse.xtext.validation.CheckType;
import org.eclipse.xtext.validation.Issue;
import org.eclipse.xtext.validation.ResourceValidatorImpl;
import org.eclipse.xtext.validation.impl.ConcreteSyntaxEValidator;
import com.google.common.collect.Lists;
/**
* PivotResourceValidator extends CS Resource validation to the referenced Pivot resources and attempts
* to indicate Pivot validation problems in the appropriate CS context.
*/
public class PivotResourceValidator extends ResourceValidatorImpl
{
public static class ValidationDiagnostic extends BasicDiagnostic implements Resource.Diagnostic
{
private ValidationDiagnostic(String message) {
super(WARNING, EObjectValidator.DIAGNOSTIC_SOURCE, 0, message, null);
}
@Override
public int getColumn() {
return 0; // This could be computed from the CS
}
@Override
public int getLine() {
return 0; // This could be computed from the CS
}
@Override
public String getLocation() {
return null; // This could be computed from the CS
}
public Integer getOffset() {
return null; // This could be computed from the CS
}
public Integer getLength() {
return 10; // This could be computed from the CS
}
}
private static final Logger log = Logger.getLogger(PivotResourceValidator.class);
public static final String HAS_SYNTAX_ERRORS = "has_syntax_errors";
protected ValidationDiagnostic createDefaultDiagnostic(Diagnostician diagnostician, EObject pivotObject) {
// Object objectLabel = diagnostician.getObjectLabel(pivotObject);
// return new ValidationDiagnostic(EcorePlugin.INSTANCE.getString("_UI_DiagnosticRoot_diagnostic",
// new Object[] { objectLabel }), new Object[] { pivotObject });
return new ValidationDiagnostic("");
}
protected void issueFromDiagnostics(IAcceptor<Issue> acceptor, ValidationDiagnostic diagnostic) {
for (Diagnostic childDiagnostic : diagnostic.getChildren()) {
// System.out.println(" issueFromEValidatorDiagnostic " + childDiagnostic);
issueFromEValidatorDiagnostic(childDiagnostic, acceptor);
}
}
protected void performValidation(IAcceptor<Issue> acceptor, Resource asResource, CancelIndicator monitor) {
// System.out.println(Thread.currentThread().getName() + " performValidation " + NameUtil.debugSimpleName(asResource));
Diagnostician diagnostician = getDiagnostician();
Map<Object, Object> context = LabelUtil.createDefaultContext(diagnostician);
// List<Resource> resources = asResource.getResourceSet().getResources();
// for (int i = 0; i < resources.size(); i++) {
Resource pResource = asResource; //resources.get(i);
// if (PivotConstants.ORPHANAGE_URI.equals(String.valueOf(pResource.getURI()))) {
// continue; // GC may not have eliminated all the dangling references
// }
// System.out.println(" performValidation " + pResource.getURI() + " on " + Thread.currentThread().getName());
removeValidationDiagnostics(pResource.getErrors());
removeValidationDiagnostics(pResource.getWarnings());
List<EObject> contents = pResource.getContents();
for (int j = 0; j < contents.size(); j++) { // Beware concurrent unload
try {
if (monitor.isCanceled())
return;
EObject pObject = contents.get(j);
ValidationDiagnostic diagnostic = createDefaultDiagnostic(diagnostician, pObject);
diagnostician.validate(pObject, diagnostic, context);
if (!diagnostic.getChildren().isEmpty()) {
if (diagnostic.getSeverity() == Diagnostic.ERROR) {
pResource.getErrors().add(diagnostic);
}
else if (diagnostic.getSeverity() == Diagnostic.WARNING) {
pResource.getWarnings().add(diagnostic);
}
issueFromDiagnostics(acceptor, diagnostic);
}
} catch (RuntimeException e) {
if (!monitor.isCanceled()) {
pResource.getErrors().add(new ValidationDiagnostic(e.getMessage()));
// log.error(e.getMessage(), e);
}
}
}
// }
}
protected void removeValidationDiagnostics(List<Resource.Diagnostic> diagnostics) {
// System.out.println(Thread.currentThread().getName() + " removeValidationDiagnostics ");
for (int i = diagnostics.size()-1; i >= 0; i--) {
Resource.Diagnostic diagnostic = diagnostics.get(i);
if (diagnostic instanceof ValidationDiagnostic) {
diagnostics.remove(i);
}
}
}
/* protected void reuseValidation(IAcceptor<Issue> acceptor, Resource asResource, CancelIndicator monitor) {
// System.out.println(Thread.currentThread().getName() + " reuseValidation " + NameUtil.debugSimpleName(asResource));
ResourceSet resourceSet = asResource.getResourceSet();
if (resourceSet != null) {
for (Resource pResource : resourceSet.getResources()) {
// System.out.println(" reuseValidation " + pResource.getURI() + " on " + Thread.currentThread().getName());
for (Resource.Diagnostic diagnostic : pResource.getErrors()) {
if (diagnostic instanceof ValidationDiagnostic) {
issueFromDiagnostics(acceptor, (ValidationDiagnostic)diagnostic);
}
}
for (Resource.Diagnostic diagnostic : pResource.getWarnings()) {
if (diagnostic instanceof ValidationDiagnostic) {
issueFromDiagnostics(acceptor, (ValidationDiagnostic)diagnostic);
}
}
}
}
} */
// FIXME BUG 389675 Remove duplication with respect to inherited method
@Override
public List<Issue> validate(Resource resource, final CheckMode mode, CancelIndicator mon) {
// System.out.println(Thread.currentThread().getName() + " validate start " + NameUtil.debugSimpleName(resource));
// System.out.println(new Date() + " Validate " + mode + " : " + csResource.getURI() + " on " + Thread.currentThread().getName());
final CancelIndicator monitor = mon == null ? CancelIndicator.NullImpl : mon;
resolveProxies(resource, monitor);
if (monitor.isCanceled())
return Collections.emptyList();
final List<Issue> result = Lists.newArrayListWithExpectedSize(resource.getErrors().size()
+ resource.getWarnings().size());
try {
IAcceptor<Issue> acceptor = createAcceptor(result);
// Syntactical and linking errors
// Collect EMF Resource Diagnostics
if (mode.shouldCheck(CheckType.FAST)) {
for (int i = 0; i < resource.getErrors().size(); i++) {
if (monitor.isCanceled())
return Collections.emptyList();
issueFromXtextResourceDiagnostic(resource.getErrors().get(i), Severity.ERROR, acceptor);
}
for (int i = 0; i < resource.getWarnings().size(); i++) {
if (monitor.isCanceled())
return Collections.emptyList();
issueFromXtextResourceDiagnostic(resource.getWarnings().get(i), Severity.WARNING, acceptor);
}
}
if (monitor.isCanceled())
return Collections.emptyList();
boolean syntaxDiagFail = !result.isEmpty();
logCheckStatus(resource, syntaxDiagFail, "Syntax");
// Validation errors
// Collect validator Diagnostics
for (EObject ele : resource.getContents()) {
try {
if (monitor.isCanceled())
return Collections.emptyList();
Diagnostician diagnostician = getDiagnostician();
Map<Object, Object> options = LabelUtil.createDefaultContext(diagnostician);
options.put(CheckMode.KEY, mode);
options.put(CancelableDiagnostician.CANCEL_INDICATOR, monitor);
// disable concrete syntax validation, since a semantic model that has been parsed
// from the concrete syntax always complies with it - otherwise there are parse errors.
options.put(ConcreteSyntaxEValidator.DISABLE_CONCRETE_SYNTAX_EVALIDATOR, Boolean.TRUE);
// see EObjectValidator.getRootEValidator(Map<Object, Object>)
boolean hasSyntaxError = false;
if (resource instanceof XtextResource) {
options.put(AbstractInjectableValidator.CURRENT_LANGUAGE_NAME, ((XtextResource) resource).getLanguageName());
if (resource instanceof BaseCSResource) {
BaseCSResource csResource = (BaseCSResource)resource;
@NonNull List<Resource.Diagnostic> errors = csResource.getErrors();
hasSyntaxError = ElementUtil.hasSyntaxError(errors);
if (hasSyntaxError) {
options.put(PivotResourceValidator.HAS_SYNTAX_ERRORS, Boolean.TRUE);
}
}
}
if (!hasSyntaxError) {
Diagnostic diagnostic = getDiagnostician().validate(ele, options);
if (!diagnostic.getChildren().isEmpty()) {
for (Diagnostic childDiagnostic : diagnostic.getChildren()) {
issueFromEValidatorDiagnostic(childDiagnostic, acceptor);
}
} else {
issueFromEValidatorDiagnostic(diagnostic, acceptor);
}
}
} catch (RuntimeException e) {
if (!monitor.isCanceled()) { // Fix Bug 462544 working around Xtext Bug 461764
log.error(e.getMessage(), e);
}
}
}
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
}
if (monitor.isCanceled())
return Collections.emptyList();
if (resource instanceof BaseCSResource) {
BaseCSResource csResource = (BaseCSResource)resource;
CS2AS cs2as = csResource.findCS2AS();
if (cs2as != null) {
Resource asResource = cs2as.getASResource();
IAcceptor<Issue> acceptor = createAcceptor(result);
// if (mode.shouldCheck(CheckType.EXPENSIVE)) {
performValidation(acceptor, asResource, monitor);
// }
// else {
// reuseValidation(acceptor, asResource, monitor);
// }
}
}
// System.out.println(Thread.currentThread().getName() + " validate end " + NameUtil.debugSimpleName(resource));
return result;
}
private void logCheckStatus(final Resource resource, boolean parserDiagFail, String string) {
if (log.isDebugEnabled()) {
log.debug(string + " check " + (parserDiagFail ? "FAIL" : "OK") + "! Resource: " + resource.getURI());
}
}
}