fun class_not_found(qid: AQclassid, mmodule: MModule)
do
var name = qid.n_id.text
+ var qname = qid.full_name
+
+ if bad_class_names[mmodule].has(qname) then
+ error(qid, "Error: class `{qname}` not found in module `{mmodule}`.")
+ return
+ end
+ bad_class_names[mmodule].add(qname)
var all_classes = model.get_mclasses_by_name(name)
+ var hints = new Array[String]
+
+ # Look for conflicting classes.
+ if all_classes != null then for c in all_classes do
+ if not mmodule.is_visible(c.intro_mmodule, c.visibility) then continue
+ if not qid.accept(c) then continue
+ hints.add "`{c.full_name}`"
+ end
+ if hints.length > 1 then
+ error(qid, "Error: ambiguous class name `{qname}` in module `{mmodule}`. Conflicts are between {hints.join(",", " and ")}.")
+ return
+ end
+ hints.clear
# Look for imported but invisible classes.
if all_classes != null then for c in all_classes do
if not mmodule.in_importation <= c.intro_mmodule then continue
if mmodule.is_visible(c.intro_mmodule, c.visibility) then continue
if not qid.accept(c) then continue
- error(ntype, "Error: class `{c.full_name}` not visible in module `{mmodule}`.")
+ error(qid, "Error: class `{c.full_name}` not visible in module `{mmodule}`.")
return
end
# Look for not imported but known classes from importable modules
- var hints = new Array[String]
if all_classes != null then for c in all_classes do
if mmodule.in_importation <= c.intro_mmodule then continue
if c.intro_mmodule.in_importation <= mmodule then continue
hints.add "`{c.intro_mmodule.full_name}`"
end
if hints.not_empty then
- error(ntype, "Error: class `{name}` not found in module `{mmodule}`. Maybe import {hints.join(",", " or ")}?")
+ error(qid, "Error: class `{qname}` not found in module `{mmodule}`. Maybe import {hints.join(",", " or ")}?")
return
end
# Look for classes with an approximative name.
- var bestd = name.length / 2 # limit up to 50% name change
+ var bests = new BestDistance[MClass](qname.length - name.length / 2) # limit up to 50% name change
for c in model.mclasses do
if not mmodule.in_importation <= c.intro_mmodule then continue
if not mmodule.is_visible(c.intro_mmodule, c.visibility) then continue
- var d = name.levenshtein_distance(c.name)
- if d <= bestd then
- if d < bestd then
- hints.clear
- bestd = d
- end
- hints.add "`{c.full_name}`"
- end
+ var d = qname.levenshtein_distance(c.name)
+ bests.update(d, c)
+ d = qname.levenshtein_distance(c.full_name)
+ bests.update(d, c)
end
- if hints.not_empty then
- error(ntype, "Error: class `{name}` not found in module `{mmodule}`. Did you mean {hints.join(",", " or ")}?")
+ if bests.best_items.not_empty then
+ for c in bests.best_items do hints.add "`{c.full_name}`"
+ error(qid, "Error: class `{qname}` not found in module `{mmodule}`. Did you mean {hints.join(",", " or ")}?")
return
end
- error(ntype, "Error: class `{name}` not found in module `{mmodule}`.")
+ error(qid, "Error: class `{qname}` not found in module `{mmodule}`.")
end
+ # List of already reported bad class names.
+ # Used to not perform and repeat hints again and again.
+ private var bad_class_names = new MultiHashMap[MModule, String]
+
# Return the static type associated to the node `ntype`.
# `mmodule` and `mclassdef` is the context where the call is made (used to understand formal types)
# In case of problem, an error is displayed on `ntype` and null is returned.
end
return true
end
+
+ # The pretty name represented by self.
+ fun full_name: String
+ do
+ var res = n_id.text
+ var nqualified = n_qualified
+ if nqualified == null then return res
+ var ncid = nqualified.n_classid
+ if ncid != null then res = ncid.text + "::" + res
+ var nids = nqualified.n_id
+ if nids.not_empty then for n in nids.reverse_iterator do
+ res = n.text + "::" + res
+ end
+ return res
+ end
end