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