blob: 90578c4c9cdc922ff50c97044e00c570917865ae [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2013 (c) GK Software AG
*
* 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
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Please visit http://www.objectteams.org for updates and contact.
*
* Contributors:
* Stephan Herrmann - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.ui.compare;
import java.util.Iterator;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.dom.CallinMappingDeclaration;
import org.eclipse.jdt.core.dom.CalloutMappingDeclaration;
import org.eclipse.jdt.core.dom.MethodSpec;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.objectteams.otdt.core.IOTJavaElement;
import org.eclipse.objectteams.otdt.ui.ImageManager;
import org.eclipse.swt.graphics.Image;
import base org.eclipse.jdt.internal.ui.compare.JavaCompareUtilities;
import base org.eclipse.jdt.internal.ui.compare.JavaNode;
import base org.eclipse.jdt.internal.ui.compare.JavaParseTreeBuilder;
/**
* Make OT elements known to the java structure compare view.
* We used slightly different strategies for types (role/team) and method bindings:
*
* For types we let JavaNodes be created the regular way with the normal typeCode (CLASS/INTERFACE),
* but before that we record in {@link #otTypeCode} if we've seen a team and/or role.
* This information will be picked up after the constructor of JavaNode and stored in
* field {@link StructureCompare.Node#otType}.
* This strategy doesn't, however, work for method mappings, because a role method and
* a method binding of the same name/signature would be merged into one structural node
* (comparison just by type code and ID).
*
* For method mappings we create a JavaNode with a OT-specific type code right away.
* Now we only have to tell a few utility methods how to handles these type codes.
* See role {@link StructureCompare.Util}.
*/
@SuppressWarnings("restriction")
public team class StructureCompare {
// additions to constants in org.eclipse.jdt.internal.ui.compare.JavaNode
public static final int TEAM = 20;
public static final int ROLE = 21;
public static final int TEAM_ROLE = 22;
public static final int CALLOUT = 23;
public static final int CALLIN = 24;
// additions to constants in org.eclipse.jdt.internal.ui.compare.JavaCompareUtilities.METHOD
public static final char C_CALLOUT = '>';
public static final char C_CALLIN = '!';
// drop-box: when creating a JavaNode, while this field holds a non-null value,
// -> decorate the JavaNode with a Node that stores the otType.
ThreadLocal<Integer> otTypeCode = new ThreadLocal<Integer>();
/**
* A structure node that maintains to type codes:
* <ul><li>one from original JDT/UI (in the base object)</li>
* <li>plus an OT-specific type code (for roles, teams)</li></ul>
*/
@SuppressWarnings("decapsulation") // invisible base class
protected class Node playedBy JavaNode {
protected int getCLASS() -> get int CLASS;
int getTypeCode() -> int getTypeCode();
Image getImage() <- replace Image getImage();
int otType;
void init() <- after JavaNode(JavaNode parent, int type, String name, int start, int length)
base when (otTypeCode.get() != null);
void init() {
this.otType = otTypeCode.get();
otTypeCode.set(null);
}
@SuppressWarnings("basecall")
callin Image getImage() {
String imgName;
switch (this.otType) {
case TEAM:
imgName = ImageManager.TEAM_IMG; break;
case TEAM_ROLE:
imgName = ImageManager.TEAM_ROLE_IMG; break;
case ROLE:
imgName = ImageManager.ROLECLASS_IMG; break;
default:
switch (getTypeCode()) {
case CALLOUT:
imgName = ImageManager.CALLOUTBINDING_IMG; break;
case CALLIN:
imgName = ImageManager.CALLINBINDING_REPLACE_IMG; break;
default:
return base.getImage();
}
}
return org.eclipse.objectteams.otdt.ui.ImageManager.getSharedInstance().get(imgName);
}
}
/**
* Detect OT-elements during tree traversal and
* - create {@link JavaNode} instances with tweaked type code (method mappings), or,
* - trigger creationg of {@link Node} role instances with additional type code for team/role.
*/
@SuppressWarnings("decapsulation") // invisible base class
protected class TreeBuilder playedBy JavaParseTreeBuilder {
void push(int type, String name, int declarationStart, int length)
-> void push(int type, String name, int declarationStart, int length);
void pop() -> void pop();
String getType(Type type) -> String getType(Type type);
void markOTType(TypeDeclaration node) <- before boolean visit(TypeDeclaration node);
boolean visitCallout(CalloutMappingDeclaration node) <- replace boolean visit(CalloutMappingDeclaration node);
boolean visitCallin(CallinMappingDeclaration node) <- replace boolean visit(CallinMappingDeclaration node);
void pop() <- after void endVisit(CalloutMappingDeclaration node);
void pop() <- after void endVisit(CallinMappingDeclaration node);
void markOTType(TypeDeclaration node) {
if (node.isTeam()) {
if (node.isRole()) otTypeCode.set(TEAM_ROLE);
else otTypeCode.set(TEAM);
} else if (node.isRole()) {
otTypeCode.set(ROLE);
}
}
@SuppressWarnings("basecall")
callin boolean visitCallout(CalloutMappingDeclaration node) {
String signature= getSignature((MethodSpec) node.getRoleMappingElement());
push(CALLOUT, signature, node.getStartPosition(), node.getLength());
return false;
}
@SuppressWarnings("basecall")
callin boolean visitCallin(CallinMappingDeclaration node) {
String signature= getSignature((MethodSpec) node.getRoleMappingElement());
push(CALLIN, signature, node.getStartPosition(), node.getLength());
return false;
}
private String getSignature(MethodSpec node) {
StringBuffer buffer= new StringBuffer();
buffer.append(node.getName().toString());
buffer.append('(');
boolean first= true;
@SuppressWarnings("unchecked")
Iterator<SingleVariableDeclaration> iterator= node.parameters().iterator();
while (iterator.hasNext()) {
SingleVariableDeclaration svd= iterator.next();
if (!first)
buffer.append(", "); //$NON-NLS-1$
buffer.append(getType(svd.getType()));
if (svd.isVarargs())
buffer.append("..."); //$NON-NLS-1$
first= false;
}
buffer.append(')');
return buffer.toString();
}
}
/**
* Tell this utility how to handle callin/callout codes/ids.
*/
protected class Util playedBy JavaCompareUtilities {
@SuppressWarnings("decapsulation")
buildID <- replace buildID;
@SuppressWarnings("basecall")
static callin String buildID(int type, String name) {
switch(type) {
case CALLOUT:
StringBuilder sb = new StringBuilder();
sb.append(C_CALLOUT);
sb.append(name);
return sb.toString();
case CALLIN:
sb = new StringBuilder();
sb.append(C_CALLIN);
sb.append(name);
return sb.toString();
default:
return base.buildID(type, name);
}
}
@SuppressWarnings("decapsulation")
getJavaElementID <- replace getJavaElementID;
@SuppressWarnings("basecall")
static callin String getJavaElementID(IJavaElement je) {
switch (je.getElementType()) {
case IOTJavaElement.CALLOUT_MAPPING:
StringBuilder sb = new StringBuilder();
sb.append(C_CALLOUT);
sb.append(JavaElementLabels.getElementLabel(je, JavaElementLabels.M_PARAMETER_TYPES));
return sb.toString();
case IOTJavaElement.CALLIN_MAPPING:
sb = new StringBuilder();
sb.append(C_CALLIN);
sb.append(JavaElementLabels.getElementLabel(je, JavaElementLabels.M_PARAMETER_TYPES));
return sb.toString();
default:
return base.getJavaElementID(je);
}
}
}
}