sclass ConceptsRefChecker { Concepts cc; new L errors; sclass Err {} srecord ErrNoBackRef(Concept.Ref ref, Concept dest) > Err {} srecord ErrSuperfluousBackRef(Concept.Ref ref, Concept dest) > Err {} srecord ErrDuplicateRef(Concept c) > Err {} srecord ErrNullRef(Concept c) > Err {} srecord ErrMissingRef(Concept c, Concept.Ref ref) > Err {} srecord ErrSuperfluousRef(Concept c, Concept.Ref ref) > Err {} // a reference from a concept that is not in the concepts list srecord ErrDanglingSource(Concept.Ref ref, Concept dest) > Err {} // a reference to a concept that is not in the concepts list srecord ErrDanglingDestination(Concept.Ref ref, Concept dest) > Err {} *() {} *(Concepts *cc) {} L run() { errors.clear(); if (cc == null) ret errors; Cl concepts = cc.allConcepts(); print("Checking " + nConcepts(concepts)); for (Concept c : concepts) try { O badElement = firstElementNotSubclassing(c.backRefs, Concept.Ref.class); if (badElement != null) continue with print("Bad element in backRefs of " + c + ": " + badElement); for (Concept.Ref ref : cloneList(c.backRefs)) { if (ref! != c) errors.add(new ErrSuperfluousBackRef(ref, c)); if (ref.concept()._concepts != cc) errors.add(new ErrDanglingSource(ref, c)); } badElement = firstElementNotSubclassing(c.refs, Concept.Ref.class); if (badElement != null) continue with print("Bad element in backRefs of " + c + ": " + badElement); L refs = cloneList(c.refs); if (!allUnique(refs)) errors.add(new ErrDuplicateRef(c)); if (contains(refs, null)) errors.add(new ErrNullRef(c)); refs = nonNulls(refs); Cl actualRefs = scanConceptForRefs(c); for (ConceptRef ref : listMinusSet(refs, actualRefs)) errors.add(new ErrSuperfluousRef(c, ref)); for (ConceptRef ref : listMinusSet(actualRefs, refs)) errors.add(new ErrMissingRef(c, ref)); for (Concept.Ref ref : refs) if (ref.has()) { if (!contains(ref->backRefs, ref)) errors.add(new ErrNoBackRef(ref, c)); if (ref->_concepts != cc) errors.add(new ErrDanglingDestination(ref, c)); } } catch print e { print("Error processing concept " + c); } ret errors; } L errors() { ret errors; } S fixAll() { new LS out; for (Err err : cloneAndClear(errors)) { out.add("Processing " + err); if (err cast ErrNoBackRef) { err.ref.index(); out.add(" reference added"); } else out.add(" TODO - fix not implemented"); } ret lines(out); } }