diff --git a/tools/cldr-code/src/main/java/org/unicode/cldr/util/Containment.java b/tools/cldr-code/src/main/java/org/unicode/cldr/util/Containment.java index 622201e55ec..57a47ed668c 100644 --- a/tools/cldr-code/src/main/java/org/unicode/cldr/util/Containment.java +++ b/tools/cldr-code/src/main/java/org/unicode/cldr/util/Containment.java @@ -10,6 +10,7 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -59,6 +60,8 @@ public class Containment { static final Map toOrder = new LinkedHashMap<>(); static int level = 0; static int order; + /** track whether any errors, such as loops, were detected */ + public static boolean hadErrors = false; static { initOrder("001"); @@ -188,6 +191,7 @@ private static void resetOrder(String newTerritory, String oldTerritory) { // } final Integer oldOrder = toOrder.get(oldTerritory); if (oldOrder == null) { + hadErrors = true; throw new IllegalArgumentException(oldTerritory + " not yet defined"); } toOrder.put(newTerritory, oldOrder); @@ -203,7 +207,13 @@ public Set getSubontinents() { public static Set> getAllDirected(Multimap multimap, String lang) { LinkedHashSet> result = new LinkedHashSet<>(); - getAllDirected(multimap, lang, new ArrayList(), result); + getAllDirected( + multimap, + lang, + new ArrayList(), + result, + new LinkedList(), + new HashSet()); return result; } @@ -211,8 +221,30 @@ private static void getAllDirected( Multimap multimap, String lang, ArrayList target, - Set> targets) { - target.add(lang); + Set> targets, + List depth, + Set loops) { + int alreadySawThis = depth.indexOf(lang); + if (alreadySawThis != -1) { + hadErrors = true; + if (loops.add(lang)) { + System.err.println( + "WARNING: CLDR-15020 getAllDirected(): Loops Detected: " + + String.join(" -> ", depth) + + " -> " + + lang); + } // else: already reported it. + return; + } else { + depth.add(lang); + } + if (!target.add(lang)) { + hadErrors = true; + throw new StackOverflowError("Error: Saw " + lang + " multiple times in this target."); + } else if (depth.size() > 999) { + hadErrors = true; + throw new StackOverflowError("Error: Too deep getting " + lang); + } Collection parents = multimap.get(lang); int size = parents.size(); if (size == 0) { @@ -220,20 +252,29 @@ private static void getAllDirected( } else if (size == 1) { for (String parent : parents) { if (parent.equals(lang)) { + hadErrors = true; System.err.println("ERR: " + lang + " is its own parent"); } else { - getAllDirected(multimap, parent, target, targets); + getAllDirected(multimap, parent, target, targets, depth, loops); } } } else { for (String parent : parents) { if (parent.equals(lang)) { + hadErrors = true; System.err.println("ERR: " + lang + " is its own parent"); } else { - getAllDirected(multimap, parent, (ArrayList) target.clone(), targets); + getAllDirected( + multimap, + parent, + (ArrayList) target.clone(), + targets, + depth, + loops); } } } + depth.remove(lang); // pop stack } /** diff --git a/tools/cldr-rdf/src/main/java/org/unicode/cldr/tool/GenerateLanguageContainment.java b/tools/cldr-rdf/src/main/java/org/unicode/cldr/tool/GenerateLanguageContainment.java index a5ebeddc0ee..ad60c98af77 100644 --- a/tools/cldr-rdf/src/main/java/org/unicode/cldr/tool/GenerateLanguageContainment.java +++ b/tools/cldr-rdf/src/main/java/org/unicode/cldr/tool/GenerateLanguageContainment.java @@ -345,6 +345,10 @@ void add(List chain) { public static void main(String[] args) throws IOException { new GenerateLanguageContainment().run(args); + if (Containment.hadErrors) { + System.err.println("ERROR: Containment Errors detected, see errors above."); + System.exit(1); + } } void run(String[] args) throws IOException {