merged from HEAD: prevent end-less recursion
diff --git a/plugins/org.eclipse.dltk.ruby.core/src/org/eclipse/dltk/ruby/internal/parser/mixin/RubyMixinClass.java b/plugins/org.eclipse.dltk.ruby.core/src/org/eclipse/dltk/ruby/internal/parser/mixin/RubyMixinClass.java
index 3eb3e6d..5fea05b 100644
--- a/plugins/org.eclipse.dltk.ruby.core/src/org/eclipse/dltk/ruby/internal/parser/mixin/RubyMixinClass.java
+++ b/plugins/org.eclipse.dltk.ruby.core/src/org/eclipse/dltk/ruby/internal/parser/mixin/RubyMixinClass.java
@@ -161,37 +161,7 @@
 		return s;
 	}
 
-	private boolean isRecursiveInclusion(Set includedKeys) {
-		IMixinElement mixinElement = model.getRawModel().get(key);
-		if (mixinElement == null)
-			return false;
-		Object[] allObjects = mixinElement.getAllObjects();
-		for (int i = 0; i < allObjects.length; i++) {
-			RubyMixinElementInfo info = (RubyMixinElementInfo) allObjects[i];
-			if (info == null) {
-				continue;
-			}
-			if (info.getKind() == RubyMixinElementInfo.K_INCLUDE) {
-				String inclKey = (String) info.getObject();
-				if (/* !this.isMeta() && */!inclKey
-						.endsWith(RubyMixin.INSTANCE_SUFFIX))
-					inclKey += RubyMixin.INSTANCE_SUFFIX;
-				if (includedKeys.contains(inclKey))
-					return true;
-				IRubyMixinElement element = model.createRubyElement(inclKey);
-				if (element instanceof RubyMixinClass) {
-					includedKeys.add(inclKey);
-					if (((RubyMixinClass) element)
-							.isRecursiveInclusion(includedKeys))
-						return true;
-					includedKeys.remove(inclKey);
-				}
-			}
-		}
-		return false;
-	}
-
-	public RubyMixinClass[] getIncluded() {
+	protected RubyMixinClass[] getIncluded() {
 		List result = new ArrayList();
 		HashSet names = new HashSet();
 		IMixinElement mixinElement = model.getRawModel().get(key);
@@ -205,17 +175,15 @@
 			}
 			if (info.getKind() == RubyMixinElementInfo.K_INCLUDE) {
 				String inclKey = (String) info.getObject();
-				if (!names.contains(inclKey)) {
-					names.add(inclKey);
+				if (names.add(inclKey)) {
 					if (/* !this.isMeta() && */!inclKey
 							.endsWith(RubyMixin.INSTANCE_SUFFIX))
 						inclKey += RubyMixin.INSTANCE_SUFFIX;
 					IRubyMixinElement element = model
 							.createRubyElement(inclKey);
-					if (element instanceof RubyMixinClass
-					// ssanders: Break recursive inclusion
-							&& ((element instanceof RubyObjectMixinClass) || !((RubyMixinClass) element)
-									.isRecursiveInclusion(new HashSet())))
+					// TODO if element is not found - try to use different path
+					// combinations
+					if (element instanceof RubyMixinClass)
 						result.add(element);
 				}
 			}
@@ -224,7 +192,7 @@
 				.size()]);
 	}
 
-	public RubyMixinClass[] getExtended() {
+	protected RubyMixinClass[] getExtended() {
 		List result = new ArrayList();
 		HashSet names = new HashSet();
 		IMixinElement mixinElement = model.getRawModel().get(key);
@@ -238,8 +206,7 @@
 			}
 			if (info.getKind() == RubyMixinElementInfo.K_EXTEND) {
 				String extKey = (String) info.getObject();
-				if (!names.contains(extKey)) {
-					names.add(extKey);
+				if (!names.add(extKey)) {
 					if (/* !this.isMeta() && */!extKey
 							.endsWith(RubyMixin.INSTANCE_SUFFIX))
 						extKey += RubyMixin.INSTANCE_SUFFIX;
@@ -255,7 +222,14 @@
 
 	public void findMethods(String prefix, boolean includeTopLevel,
 			IMixinSearchRequestor requestor) {
+		findMethods(prefix, includeTopLevel, requestor, new HashSet());
+	}
 
+	protected void findMethods(String prefix, boolean includeTopLevel,
+			IMixinSearchRequestor requestor, Set processedKeys) {
+		if (!processedKeys.add(key)) {
+			return;
+		}
 		IMixinElement mixinElement = model.getRawModel().get(key);
 		if (mixinElement == null)
 			return;
@@ -266,8 +240,7 @@
 						.createRubyElement(children[i]);
 				if (element instanceof RubyMixinMethod) {
 					requestor.acceptResult(element);
-				}
-				if (element instanceof RubyMixinAlias) {
+				} else if (element instanceof RubyMixinAlias) {
 					RubyMixinAlias alias = (RubyMixinAlias) element;
 					IRubyMixinElement oldElement = alias.getOldElement();
 					if (oldElement instanceof RubyMixinMethod) {
@@ -281,12 +254,14 @@
 
 		RubyMixinClass[] included = this.getIncluded();
 		for (int i = 0; i < included.length; i++) {
-			included[i].findMethods(prefix, includeTopLevel, requestor);
+			included[i].findMethods(prefix, includeTopLevel, requestor,
+					processedKeys);
 		}
 
 		RubyMixinClass[] extended = this.getExtended();
 		for (int i = 0; i < extended.length; i++) {
-			extended[i].findMethods(prefix, includeTopLevel, requestor);
+			extended[i].findMethods(prefix, includeTopLevel, requestor,
+					processedKeys);
 		}
 
 		if (!this.key.endsWith(RubyMixin.VIRTUAL_SUFFIX)) {
@@ -294,11 +269,8 @@
 			if (superclass != null) {
 
 				if (!superclass.getKey().equals(key)) {
-					RubyMixinMethod[] methods = superclass.findMethods(prefix,
-							includeTopLevel);
-					for (int j = 0; j < methods.length; j++) {
-						requestor.acceptResult(methods[j]);
-					}
+					superclass.findMethods(prefix, includeTopLevel, requestor,
+							processedKeys);
 				}
 			}
 		} else {
@@ -307,7 +279,8 @@
 			IRubyMixinElement realElement = model.createRubyElement(stdKey);
 			if (realElement instanceof RubyMixinClass) {
 				RubyMixinClass rubyMixinClass = (RubyMixinClass) realElement;
-				rubyMixinClass.findMethods(prefix, includeTopLevel, requestor);
+				rubyMixinClass.findMethods(prefix, includeTopLevel, requestor,
+						processedKeys);
 			}
 		}
 
@@ -327,13 +300,21 @@
 				}
 			}
 
-		});
+		}, new HashSet());
 		return (RubyMixinMethod[]) result.toArray(new RubyMixinMethod[result
 				.size()]);
 	}
 
 	public void findMethodsExact(String methodName,
 			IMixinSearchRequestor requestor) {
+		findMethodsExact(methodName, requestor, new HashSet());
+	}
+
+	protected void findMethodsExact(String methodName,
+			IMixinSearchRequestor requestor, Set processedKeys) {
+		if (!processedKeys.add(key)) {
+			return;
+		}
 
 		IMixinElement mixinElement = model.getRawModel().get(key);
 		if (mixinElement == null)
@@ -345,8 +326,7 @@
 						.createRubyElement(children[i]);
 				if (element instanceof RubyMixinMethod) {
 					requestor.acceptResult(element);
-				}
-				if (element instanceof RubyMixinAlias) {
+				} else if (element instanceof RubyMixinAlias) {
 					RubyMixinAlias alias = (RubyMixinAlias) element;
 					IRubyMixinElement oldElement = alias.getOldElement();
 					if (oldElement instanceof RubyMixinMethod) {
@@ -360,12 +340,12 @@
 
 		RubyMixinClass[] included = this.getIncluded();
 		for (int i = 0; i < included.length; i++) {
-			included[i].findMethodsExact(methodName, requestor);
+			included[i].findMethodsExact(methodName, requestor, processedKeys);
 		}
 
 		RubyMixinClass[] extended = this.getExtended();
 		for (int i = 0; i < extended.length; i++) {
-			extended[i].findMethodsExact(methodName, requestor);
+			extended[i].findMethodsExact(methodName, requestor, processedKeys);
 		}
 
 		if (!this.key.endsWith(RubyMixin.VIRTUAL_SUFFIX)) {
@@ -373,11 +353,8 @@
 			if (superclass != null) {
 
 				if (!superclass.getKey().equals(key)) {
-					RubyMixinMethod[] methods = superclass
-							.findMethodsExact(methodName);
-					for (int j = 0; j < methods.length; j++) {
-						requestor.acceptResult(methods[j]);
-					}
+					superclass.findMethodsExact(methodName, requestor,
+							processedKeys);
 				}
 			}
 		} else {
@@ -386,7 +363,8 @@
 			IRubyMixinElement realElement = model.createRubyElement(stdKey);
 			if (realElement instanceof RubyMixinClass) {
 				RubyMixinClass rubyMixinClass = (RubyMixinClass) realElement;
-				rubyMixinClass.findMethodsExact(methodName, requestor);
+				rubyMixinClass.findMethodsExact(methodName, requestor,
+						processedKeys);
 			}
 		}
 
@@ -406,7 +384,7 @@
 				}
 			}
 
-		});
+		}, new HashSet());
 		return (RubyMixinMethod[]) result.toArray(new RubyMixinMethod[result
 				.size()]);
 	}