Fix for Bug 301314 - CallHierarchy should consider lifting as role
instance creation
diff --git a/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/corext/CallHierarchyAdaptor.java b/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/corext/CallHierarchyAdaptor.java
index 1a9b126..c79ebd3 100644
--- a/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/corext/CallHierarchyAdaptor.java
+++ b/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/corext/CallHierarchyAdaptor.java
@@ -24,14 +24,23 @@
 import java.util.Map;
 import java.util.StringTokenizer;
 
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
 import org.eclipse.jdt.core.search.SearchMatch;
+import org.eclipse.jdt.core.search.SearchParticipant;
+import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.internal.corext.callhierarchy.MethodCall;
+import org.eclipse.jdt.internal.corext.util.SearchUtils;
 import org.eclipse.objectteams.otdt.core.ICallinMapping;
 import org.eclipse.objectteams.otdt.core.ICalloutMapping;
 import org.eclipse.objectteams.otdt.core.IMethodMapping;
@@ -64,6 +73,9 @@
 	 */
 	protected class MappingReferenceSearchRequestor playedBy MethodReferencesSearchRequestor
 	{
+		protected MappingReferenceSearchRequestor() {
+			base();
+		}
 		acceptSearchMatch <- replace acceptSearchMatch;
 	    @SuppressWarnings("basecall")
 		callin void acceptSearchMatch(SearchMatch match) {
@@ -96,6 +108,7 @@
 
 	    boolean getRequireExactMatch()               -> get boolean fRequireExactMatch;
 	    CallSearchResultCollector getSearchResults() -> get CallSearchResultCollector fSearchResults;
+		Map<String, MethodCall> getCallers()		 -> Map<String, MethodCall> getCallers();
 	}
 
 	/**
@@ -162,12 +175,15 @@
 				// directly fetch affected callins without search
 				children = getCallinsAffectedByGuard(member);
 			}
-			if (children != null)
+			if (children != null) {
 				// if found add result:
 				addReferencedMembers(children);
-			else
-				// nothing-found scenarii, revert to normal behavior:
-				base.doFindChildren(progressMonitor);
+				return;
+			}
+			if (handleRoleInstantiations(member, progressMonitor))
+				return;
+			// nothing-found scenarii, revert to normal behavior:
+			base.doFindChildren(progressMonitor);
 		}
 
 		private void addReferencedMembers(IMember[] children) {
@@ -192,17 +208,20 @@
 		IMember[] getCallinsAffectedByGuard(IMember member) {
 			/* default: */ return null;
 		}
+		boolean handleRoleInstantiations(IMember member, IProgressMonitor progressMonitor) {
+			/* default: */ return false;
+		}
 		
 		// callouts:
-		void setElementMap(Map<String,MethodCall> map)	-> set Map<String,MethodCall> fElements;
-		Map<String, MethodCall> getFElements() 	   		-> get Map<String,MethodCall> fElements;
-		void setMethodCall(MethodCall methodCall)  		-> set MethodCall fMethodCall;
-		void initCalls()                      		    -> void initCalls();
-		IMember getMember()                        		-> IMember getMember();
-		MethodCall getMethodCall()                 		-> MethodCall getMethodCall();
-		Map<String,MethodCall> lookupMethod(MethodCall methodCall)
-														-> Map<String,MethodCall> lookupMethod(MethodCall methodCall);
-		void addCallToCache(MethodCall methodCall) 		-> void addCallToCache(MethodCall methodCall);
+				  void setElementMap(Map<String,MethodCall> map)-> set Map<String,MethodCall> fElements;
+		protected Map<String, MethodCall> getFElements()		-> get Map<String,MethodCall> fElements;
+				  void setMethodCall(MethodCall methodCall)  	-> set MethodCall fMethodCall;
+		protected void initCalls()                  		    -> void initCalls();
+				  IMember getMember()                       	-> IMember getMember();
+				  MethodCall getMethodCall()                 	-> MethodCall getMethodCall();
+				  Map<String,MethodCall> lookupMethod(MethodCall methodCall)
+				  												-> Map<String,MethodCall> lookupMethod(MethodCall methodCall);
+		protected void addCallToCache(MethodCall methodCall) 	-> void addCallToCache(MethodCall methodCall);
 	}
 	
 	/**
@@ -235,6 +254,10 @@
 		extends MethodMappingWrapper
 		playedBy CallerMethodWrapper
 	{
+		IJavaSearchScope getAccurateSearchScope(IJavaSearchScope defaultSearchScope,	IMember member)
+			-> IJavaSearchScope getAccurateSearchScope(IJavaSearchScope defaultSearchScope, IMember arg1);
+		IJavaSearchScope getSearchScope() -> IJavaSearchScope getSearchScope();
+		
 		@Override
 		public IMethod[] getCallinMethods(ICallinMapping callinMapping)
 			throws JavaModelException 
@@ -334,6 +357,81 @@
 				return mList.toArray(new IMember[mList.size()]);
 			}
 		}
+
+		boolean handleRoleInstantiations(IMember member, IProgressMonitor monitor) {
+			if (member.getElementType() == IJavaElement.METHOD) {
+				if (isLiftingCtor((IMethod)member)) {
+					return findRoleInstantiations(member.getDeclaringType(), monitor);
+				}
+			} else if (member.getElementType() == IJavaElement.TYPE) {
+				IType type = (IType) member;
+				if (OTModelManager.isRole(type)) {
+					return findRoleInstantiations(type, monitor);
+				}
+			}
+			return false;
+		}
+
+		private boolean isLiftingCtor(IMethod method) {
+			try {
+				if (!method.isConstructor()) return false;
+				String[] parameterTypes = method.getParameterTypes();
+				if (parameterTypes.length != 1) return false;
+				IType declaringType = method.getDeclaringType();
+				IOTType otType = OTModelManager.getOTElement(declaringType);
+				if (otType == null || !otType.isRole()) return false;
+				String baseClassName = ((IRoleType) otType).getBaseclassName();
+				if (baseClassName == null) return false;
+				String paramType = Signature.toString(parameterTypes[0]);
+				if (baseClassName.indexOf('.') != -1)
+					return baseClassName.equals(paramType);
+				return baseClassName.equals(Signature.getSimpleName(paramType));
+			} catch (JavaModelException jme) {
+				return false;
+			}
+		}
+
+		boolean findRoleInstantiations(IType roleType, IProgressMonitor monitor) {
+			try {
+				initCalls();
+				Map<String, MethodCall> fElements = getFElements();
+				// search-engine based search for constructor invocations and lifting references:
+				Map<String, MethodCall> ctorElements = searchRoleCtorInvocations(roleType, monitor);
+				if (!ctorElements.isEmpty()) {
+					for (MethodCall call: ctorElements.values())
+						addCallToCache(call);
+					fElements.putAll(ctorElements);
+				}
+				// direct lookup of all non-static callins in this role:
+				IRoleType otRoleType = (IRoleType) OTModelManager.getOTElement(roleType);
+				for (IMethodMapping mapping : otRoleType.getMethodMappings(IRoleType.CALLINS)) {
+					if (!Flags.isStatic(mapping.getRoleMethod().getFlags())) {
+						MethodCall call = new MethodCall(mapping);
+						addCallToCache(call);
+						fElements.put(mapping.getHandleIdentifier(), call);
+					}
+				}
+				return true;
+			} catch (CoreException ex) {
+				return false; // search failed or some found element doesn't exist?
+			}			
+		}
+
+		Map<String, MethodCall> searchRoleCtorInvocations(IType roleType, IProgressMonitor monitor) throws CoreException {
+			// mimicked after pieces from CallerMethodWrapper.findChildren():
+			SearchPattern pattern= SearchPattern.createPattern(roleType,
+					IJavaSearchConstants.CLASS_INSTANCE_CREATION_TYPE_REFERENCE, // this is lifting-aware!
+					SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
+			SearchEngine searchEngine= new SearchEngine();
+			MappingReferenceSearchRequestor searchRequestor= new MappingReferenceSearchRequestor();
+			IJavaSearchScope defaultSearchScope= getSearchScope();
+			boolean isWorkspaceScope= SearchEngine.createWorkspaceScope().equals(defaultSearchScope);
+			IJavaSearchScope searchScope= isWorkspaceScope ? getAccurateSearchScope(defaultSearchScope, roleType) : defaultSearchScope;
+			searchEngine.search(pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, searchScope, searchRequestor,
+					monitor);
+			return searchRequestor.getCallers();
+		}
+
 		
 		// while searching for children in a caller-hierarchy, constrain all
 		// method-mapping matches to the non-declaration side.