X-Git-Url: http://nitlanguage.org diff --git a/src/modelbuilder_base.nit b/src/modelbuilder_base.nit index 5986770..5cc235f 100644 --- a/src/modelbuilder_base.nit +++ b/src/modelbuilder_base.nit @@ -86,6 +86,7 @@ class ModelBuilder # # If more than one class exists, then null is silently returned. # It is up to the caller to post-analysis the result and display a correct error message. + # The method `class_not_found` can be used to display such a message. fun try_get_mclass_by_qid(qid: AQclassid, mmodule: MModule): nullable MClass do var name = qid.n_id.text @@ -334,21 +335,50 @@ class ModelBuilder # If everything fail, then give up with class by proposing things. # # TODO Give hints on formal types (param and virtual) - # TODO How to move this in a libified autonomous code? + class_not_found(qid, mmodule) + ntype.is_broken = true + return null + end + + # Print an error and suggest hints when the class identified by `qid` in `mmodule` is not found. + # + # This just print error messages. + 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}`.") - return null + 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 @@ -357,33 +387,33 @@ class ModelBuilder 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 ")}?") - return null + 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 ")}?") - return null + 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}`.") - return null + 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. @@ -540,4 +570,19 @@ redef class AQclassid 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