blob: 0cf59787925c522d727aecd9624337f8a2cb9975 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2015 Willink Transformations 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:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.xtext.essentialocl.scoping;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.internal.messages.PivotMessagesInternal;
import org.eclipse.ocl.pivot.internal.scoping.Attribution;
import org.eclipse.ocl.pivot.internal.utilities.PivotConstantsInternal;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.xtext.base.attributes.ImportCSAttribution;
import org.eclipse.ocl.xtext.base.cs2as.CS2AS;
import org.eclipse.ocl.xtext.base.cs2as.CS2AS.AbstractUnresolvedProxyMessageProvider;
import org.eclipse.ocl.xtext.base.cs2as.CS2AS.MessageBinder;
import org.eclipse.ocl.xtext.basecs.BaseCSPackage;
import org.eclipse.ocl.xtext.basecs.ElementCS;
import org.eclipse.ocl.xtext.basecs.ImportCS;
import org.eclipse.ocl.xtext.basecs.ModelElementRefCS;
import org.eclipse.ocl.xtext.basecs.PathElementCS;
import org.eclipse.ocl.xtext.basecs.PathNameCS;
import org.eclipse.ocl.xtext.basecs.SpecificationCS;
import org.eclipse.ocl.xtext.basecs.PathTypeCS;
import org.eclipse.ocl.xtext.essentialocl.attributes.IfThenExpCSAttribution;
import org.eclipse.ocl.xtext.essentialocl.attributes.LambdaLiteralExpCSAttribution;
import org.eclipse.ocl.xtext.essentialocl.attributes.LetExpCSAttribution;
import org.eclipse.ocl.xtext.essentialocl.attributes.LetVariableCSAttribution;
import org.eclipse.ocl.xtext.essentialocl.attributes.NavigatingArgCSAttribution;
import org.eclipse.ocl.xtext.essentialocl.attributes.NavigationOperatorCSAttribution;
import org.eclipse.ocl.xtext.essentialocl.attributes.NavigationUtil;
import org.eclipse.ocl.xtext.essentialocl.attributes.ShadowPartCSAttribution;
import org.eclipse.ocl.xtext.essentialoclcs.EssentialOCLCSPackage;
import org.eclipse.ocl.xtext.essentialoclcs.ExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.InfixExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.NameExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.NavigatingArgCS;
import org.eclipse.ocl.xtext.essentialoclcs.NavigationRole;
import org.eclipse.ocl.xtext.essentialoclcs.NestedExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.OperatorExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.PrefixExpCS;
import org.eclipse.ocl.xtext.essentialoclcs.RoundBracketedClauseCS;
import org.eclipse.ocl.xtext.essentialoclcs.PathExpCS;
public class EssentialOCLScoping
{
public static void init() {
Map<EClassifier, Attribution> registry = Attribution.REGISTRY;
registry.put(EssentialOCLCSPackage.Literals.IF_THEN_EXP_CS, IfThenExpCSAttribution.INSTANCE);
registry.put(EssentialOCLCSPackage.Literals.LAMBDA_LITERAL_EXP_CS, LambdaLiteralExpCSAttribution.INSTANCE);
registry.put(EssentialOCLCSPackage.Literals.LET_EXP_CS, LetExpCSAttribution.INSTANCE);
registry.put(EssentialOCLCSPackage.Literals.LET_VARIABLE_CS, LetVariableCSAttribution.INSTANCE); // Needed for let deeply nested in Iterator/CollectionLiteral
registry.put(EssentialOCLCSPackage.Literals.NAVIGATING_ARG_CS, NavigatingArgCSAttribution.INSTANCE);
registry.put(EssentialOCLCSPackage.Literals.INFIX_EXP_CS, NavigationOperatorCSAttribution.INSTANCE);
registry.put(EssentialOCLCSPackage.Literals.SHADOW_PART_CS, ShadowPartCSAttribution.INSTANCE);
CS2AS.addUnresolvedProxyMessageProvider(new PathElementCSUnresolvedProxyMessageProvider());
}
private static final class PathElementCSUnresolvedProxyMessageProvider extends AbstractUnresolvedProxyMessageProvider
{
private PathElementCSUnresolvedProxyMessageProvider() {
super(BaseCSPackage.Literals.PATH_ELEMENT_CS__REFERRED_ELEMENT);
}
@Override
public String getMessage(@NonNull EObject eObject, @NonNull String linkText) {
PathElementCS csPathElement = (PathElementCS) eObject;
PathNameCS pathName = csPathElement.getOwningPathName();
List<PathElementCS> path = pathName.getOwnedPathElements();
int index = path.indexOf(csPathElement);
for (int i = 0; i < index; i++) {
PathElementCS csElement = path.get(i);
Element element = csElement.basicGetReferredElement();
if ((element == null) || element.eIsProxy()) {
return null; // Suppress nested unresolved message
}
}
ElementCS csContext = pathName.getContext();
if (csContext == null) {
csContext = (ElementCS) pathName.eContainer();
}
assert csContext != null;
String messageTemplate;
String argumentText = null;
ExpCS navigationArgument = null;
Type sourceType = null;
if ((index + 1) < path.size()) {
messageTemplate = PivotMessagesInternal.UnresolvedNamespace_ERROR_;
}
else if (csContext instanceof NameExpCS) {
NameExpCS csNameExp = (NameExpCS)csContext;
navigationArgument = csNameExp;
RoundBracketedClauseCS csRoundBracketedClause = csNameExp.getOwnedRoundBracketedClause();
if (csRoundBracketedClause != null) {
argumentText = getOperationArguments(csRoundBracketedClause);
List<NavigatingArgCS> arguments = csRoundBracketedClause.getOwnedArguments();
if ((arguments.size() > 0) && (arguments.get(0).getRole() == NavigationRole.ITERATOR)) {
messageTemplate = PivotMessagesInternal.UnresolvedIterationCall_ERROR_;
}
else {
messageTemplate = csNameExp.getSourceTypeValue() != null ? PivotMessagesInternal.UnresolvedStaticOperationCall_ERROR_ : PivotMessagesInternal.UnresolvedOperationCall_ERROR_;
}
}
else {
messageTemplate = csNameExp.getSourceTypeValue() != null ? PivotMessagesInternal.UnresolvedStaticProperty_ERROR_ : PivotMessagesInternal.UnresolvedProperty_ERROR_;
}
if (csNameExp.getSourceTypeValue() != null) {
sourceType = csNameExp.getSourceTypeValue();
}
}
else if (csContext instanceof PathExpCS) {
messageTemplate = PivotMessagesInternal.UnresolvedType_ERROR_;
}
else if (csContext instanceof PathTypeCS) {
messageTemplate = PivotMessagesInternal.UnresolvedType_ERROR_;
}
else if (csContext instanceof ExpCS) {
navigationArgument = (ExpCS)csContext;
messageTemplate = PivotMessagesInternal.UnresolvedProperty_ERROR_;
}
else if (csContext instanceof ImportCS) {
return ImportCSAttribution.INSTANCE.getMessage(csContext, linkText); // FIXME return a messageTemplate
}
else if (csContext instanceof ModelElementRefCS) {
messageTemplate = "Unresolved ModelElement ''{0}''";
}
else {
messageTemplate = "Unresolved ''{0}'' ''{1}''";
}
assert messageTemplate != null;
TypedElement source = null;
ExpCS csSource = navigationArgument;
for (ExpCS aSource = csSource; aSource != null; ) { // FIXME rewrite me
OperatorExpCS csOperator = aSource.getLocalParent();
if ((csOperator != null) && (csOperator.getSource() != aSource)) {
csSource = csOperator.getSource();
break;
}
EObject eContainer = aSource.eContainer();
if (eContainer instanceof NavigatingArgCS) {
aSource = ((NavigatingArgCS)eContainer).getOwningRoundBracketedClause().getOwningNameExp();
}
else if (eContainer instanceof InfixExpCS) {
aSource = (InfixExpCS)eContainer;
}
else if (eContainer instanceof PrefixExpCS) {
aSource = (PrefixExpCS)eContainer;
}
else if (eContainer instanceof NestedExpCS) {
aSource = (NestedExpCS)eContainer;
}
else if (eContainer instanceof SpecificationCS) {
ExpressionInOCL expression = PivotUtil.getContainingExpressionInOCL(((SpecificationCS)eContainer).getPivot());
source = expression!= null ? expression.getOwnedContext() : null;
break;
}
else {
break;
}
}
if (source == null) {
if ((csSource != null) && (csSource != navigationArgument)) {
source = PivotUtil.getPivot(OCLExpression.class, csSource);
}
}
String typeText = "";
if (source != null) {
typeText = PivotConstantsInternal.UNKNOWN_TYPE_TEXT;
if (sourceType == null) {
sourceType = source.getType();
}
if (sourceType != null) {
OperatorExpCS csParent = navigationArgument != null ? navigationArgument.getLocalParent() : null;
if (!PivotUtil.isAggregate(sourceType) && NavigationUtil.isNavigationInfixExp(csParent) && (csParent != null) && PivotUtil.isAggregateNavigationOperator(((InfixExpCS)csParent).getName())) {
typeText = "Set(" + sourceType.toString() + ")";
}
else {
typeText = sourceType.toString();
}
}
}
MessageBinder messageBinder = CS2AS.getMessageBinder();
String messageText;
if (argumentText == null) {
messageText = messageBinder.bind(csContext, messageTemplate, typeText, linkText);
}
else {
messageText = messageBinder.bind(csContext, messageTemplate, typeText, linkText, argumentText);
}
return messageText;
}
public String getOperationArguments(@NonNull RoundBracketedClauseCS csRoundBracketedClause) {
List<NavigatingArgCS> arguments = csRoundBracketedClause.getOwnedArguments();
StringBuilder s = new StringBuilder();
for (NavigatingArgCS csArgument : arguments) {
TypedElement pivot = PivotUtil.getPivot(TypedElement.class, csArgument);
if ((pivot != null) && !pivot.eIsProxy()) {
if (s.length() > 0) {
s.append(", ");
}
Type type = pivot.getType();
s.append(String.valueOf(type));
}
else {
s.append(csArgument.toString());
}
}
return s.toString();
}
}
}