blob: 7658a069c720f9797a97f06607876c681df8daf9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2019 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.serializer;
import java.util.List;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.Import;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.utilities.Nameable;
import org.eclipse.ocl.pivot.utilities.URIUtil;
import org.eclipse.ocl.xtext.base.as2cs.AliasAnalysis;
import org.eclipse.ocl.xtext.base.utilities.BaseCSResource;
import org.eclipse.ocl.xtext.basecs.ImportCS;
import org.eclipse.ocl.xtext.basecs.PathElementCS;
import org.eclipse.ocl.xtext.basecs.PathElementWithURICS;
import org.eclipse.ocl.xtext.basecs.PathNameCS;
import org.eclipse.ocl.xtext.basecs.RootPackageCS;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.conversion.IValueConverterService;
import org.eclipse.xtext.conversion.ValueConverterException;
import org.eclipse.xtext.linking.impl.LinkingHelper;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic;
import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic.Acceptor;
import org.eclipse.xtext.serializer.tokens.CrossReferenceSerializer;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
// FIXME Temporary workaround for Bug 361577
@SuppressWarnings("restriction")
public class BaseCrossReferenceSerializer extends CrossReferenceSerializer
{
protected class AcceptorHelper
{
protected final EObject semanticObject;
protected final CrossReference crossref;
protected final EObject target;
protected final IScope scope;
protected final @Nullable Acceptor errors;
private @Nullable List<ISerializationDiagnostic> recordedErrors = null;
public AcceptorHelper(EObject semanticObject, CrossReference crossref, EObject target, IScope scope, @Nullable Acceptor errors) {
this.semanticObject = semanticObject;
this.crossref = crossref;
this.target = target;
this.scope = scope;
this.errors = errors;
}
public @Nullable String convert(String unconverted, String ruleName) {
try {
return valueConverter.toString(unconverted, ruleName);
} catch (ValueConverterException e) {
record(unconverted, e);
return null;
}
}
protected @Nullable String convert(List<String> segments, String ruleName) {
int iMax = segments.size();
String[] converted = new String[iMax];
String unconverted = null;
try {
for (int i = 0; i < iMax; i++) {
unconverted = segments.get(i);
if ((i > 0) && "UnrestrictedName".equals(ruleName)) {
converted[i] = valueConverter.toString(unconverted, "UnreservedName");
}
else {
converted[i] = valueConverter.toString(unconverted, ruleName);
}
}
return qualifiedNameConverter.toString(new QualifiedName(converted) {});
} catch (ValueConverterException e) {
record(unconverted, e);
return null;
}
}
protected void record(String unconverted, @NonNull ValueConverterException e) {
if (errors != null) {
List<ISerializationDiagnostic> recordedErrors2 = recordedErrors;
if (recordedErrors2 == null)
recordedErrors = recordedErrors2 = Lists.newArrayList();
recordedErrors2.add(diagnostics.getValueConversionExceptionDiagnostic(semanticObject, crossref, unconverted, e));
}
}
protected void report(boolean foundOne) {
Acceptor errors2 = errors;
if (errors2 != null) {
if (recordedErrors != null)
for (ISerializationDiagnostic diag : recordedErrors)
errors2.accept(diag);
if (!foundOne)
errors2.accept(diagnostics.getNoEObjectDescriptionFoundDiagnostic(semanticObject, crossref, target, scope));
}
}
}
@Inject
private LinkingHelper linkingHelper;
@Inject
private IQualifiedNameConverter qualifiedNameConverter;
@Inject
private IValueConverterService valueConverter;
@Override
protected String getCrossReferenceNameFromScope(EObject semanticObject,
CrossReference crossref, EObject target, IScope scope, Acceptor errors) {
AcceptorHelper helper = new AcceptorHelper(semanticObject, crossref, target, scope, errors);
boolean foundOne = false;
final String ruleName = linkingHelper.getRuleNameFrom(crossref);
if ("URI".equals(ruleName)) {
if (semanticObject instanceof PathElementWithURICS) {
PathElementWithURICS pathElementWithURICS = (PathElementWithURICS)semanticObject;
String uri = pathElementWithURICS.getUri();
if (uri != null) {
String converted = helper.convert(uri, ruleName);
if (converted != null) {
return converted;
}
}
}
// This fallback is used, but perhaps only erroneously tests show one PathElementWithURICS and one IncludeCS
//System.out.println(ruleName + " 1=> " + semanticObject.eClass().getName());
Iterable<IEObjectDescription> elements = scope.getElements(target);
for (IEObjectDescription desc : elements) {
URI uri = URI.createURI(desc.getName().toString());
URI baseURI = semanticObject.eResource().getURI();
URI deresolvedURI = URIUtil.deresolve(uri, baseURI);
String unconverted = deresolvedURI.toString();
String converted = helper.convert(unconverted, ruleName);
if (converted != null) {
return converted;
}
}
}
else if (semanticObject instanceof PathElementCS) {
// UnrestrictedName or UnreservedName
PathElementCS pathElement = (PathElementCS)semanticObject;
PathNameCS pathName = pathElement.getOwningPathName();
int index = pathName.getOwnedPathElements().indexOf(pathElement);
Element element = pathElement.getReferredElement();
if ((element != null) && !element.eIsProxy()) {
Resource csResource = pathElement.eResource();
assert csResource != null;
NamedElement namedElement = csResource instanceof BaseCSResource ? ((BaseCSResource)csResource).isPathable(element) : null;
if (namedElement != null) {
String name = namedElement.getName();
if ((index == 0) && (namedElement instanceof org.eclipse.ocl.pivot.Package)) {
EObject root = EcoreUtil.getRootContainer(semanticObject);
Resource asResource = null;
if (root instanceof RootPackageCS) {
EObject root2 = ((RootPackageCS)root).getPivot();
asResource = EcoreUtil.getRootContainer(root2).eResource();
}
Resource elementResource = namedElement.eResource();
if ((elementResource != csResource) && (elementResource != asResource)) {
AliasAnalysis adapter = AliasAnalysis.getAdapter(csResource);
String alias = adapter.getAlias(namedElement, null);
if (alias != null) {
name = alias;
}
}
}
String converted = helper.convert(name, ruleName);
if (converted != null) {
return converted;
}
}
else {
URI uri;
EObject eTarget = element.getESObject();
if (eTarget != null) {
uri = EcoreUtil.getURI(eTarget);
}
else {
uri = EcoreUtil.getURI(element);
}
URI baseURI = semanticObject.eResource().getURI();
URI deresolvedURI = URIUtil.deresolve(uri, baseURI);
String unconverted = deresolvedURI.toString();
String converted = helper.convert(unconverted, ruleName);
if (converted != null) {
return converted;
}
}
}
// Never get here
//System.out.println(ruleName + " 2=> " + semanticObject.eClass().getName());
}
else {
if (target instanceof org.eclipse.ocl.pivot.Package) {
EObject semanticRoot = EcoreUtil.getRootContainer(semanticObject);
if (semanticRoot instanceof RootPackageCS) {
for (ImportCS csImport : ((RootPackageCS)semanticRoot).getOwnedImports()) {
Element asElement = csImport.getPivot();
if (asElement instanceof Import) {
Import asImport = (Import)asElement;
String aliasName = asImport.getName();
if ((aliasName != null) && (asImport.getImportedNamespace() == target)) {
return aliasName;
}
}
}
}
}
// Always UnrestrictedName => ReferenceCS
//System.out.println(ruleName + " 3=> " + semanticObject.eClass().getName());
Iterable<IEObjectDescription> elements = scope.getElements(target);
for (IEObjectDescription desc : elements) {
foundOne = true;
QualifiedName name = desc.getName();
if (name.getSegmentCount() > 0) {
String unconverted = name.getLastSegment();
String converted = helper.convert(unconverted, ruleName);
if (converted != null) {
return converted;
}
}
}
if (target instanceof Nameable) { // OCLstdlib MetaclassNameCS
return ((Nameable)target).getName();
}
}
helper.report(foundOne);
return null;
}
}