| /******************************************************************************* |
| * 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(); |
| } |
| } |
| } |