model: add `MEntity::is_broken`
authorJean Privat <jean@pryen.org>
Tue, 6 Oct 2015 19:00:21 +0000 (15:00 -0400)
committerJean Privat <jean@pryen.org>
Tue, 6 Oct 2015 19:00:21 +0000 (15:00 -0400)
Signed-off-by: Jean Privat <jean@pryen.org>

src/loader.nit
src/model/model_base.nit
src/modelize/modelize_class.nit
src/modelize/modelize_property.nit

index a59ccf0..f5b7be1 100644 (file)
@@ -811,11 +811,13 @@ redef class ModelBuilder
                        # Load the imported module
                        var suppath = seach_module_by_amodule_name(aimport.n_name, mmodule.mgroup)
                        if suppath == null then
+                               mmodule.is_broken = true
                                nmodule.mmodule = null # invalidate the module
                                continue # Skip error
                        end
                        var sup = load_module_path(suppath)
                        if sup == null then
+                               mmodule.is_broken = true
                                nmodule.mmodule = null # invalidate the module
                                continue # Skip error
                        end
@@ -824,16 +826,20 @@ redef class ModelBuilder
                        imported_modules.add(sup)
                        var mvisibility = aimport.n_visibility.mvisibility
                        if mvisibility == protected_visibility then
+                               mmodule.is_broken = true
                                error(aimport.n_visibility, "Error: only properties can be protected.")
+                               mmodule.is_broken = true
                                nmodule.mmodule = null # invalidate the module
                                return
                        end
                        if sup == mmodule then
                                error(aimport.n_name, "Error: dependency loop in module {mmodule}.")
+                               mmodule.is_broken = true
                                nmodule.mmodule = null # invalidate the module
                        end
                        if sup.in_importation < mmodule then
                                error(aimport.n_name, "Error: dependency loop between modules {mmodule} and {sup}.")
+                               mmodule.is_broken = true
                                nmodule.mmodule = null # invalidate the module
                                return
                        end
@@ -843,6 +849,7 @@ redef class ModelBuilder
                        var mod_name = "core"
                        var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
                        if sup == null then
+                               mmodule.is_broken = true
                                nmodule.mmodule = null # invalidate the module
                        else # Skip error
                                imported_modules.add(sup)
index 396d5e1..8b33f15 100644 (file)
@@ -64,6 +64,20 @@ abstract class MEntity
 
        # A Model Entity has a direct link to its model
        fun model: Model is abstract
+
+       # The indication that the entity did not pass some semantic verifications.
+       #
+       # This simple flag is set by a given analysis to say that the entity is broken and unusable in
+       # an execution.
+       # When an entity status is set to broken, it is usually associated with a error message.
+       #
+       # If it is safe to do so, clients of the model SHOULD just skip broken entities in their processing.
+       # Clients that do not care about the executability (e.g. metrics) MAY still process the entity or
+       # perform specific checks to determinate the validity of the entity.
+       #
+       # Note that the broken status is not propagated to enclosing and enclosed entities.
+       # e.g. a broken method does not make the whole module broken.
+       var is_broken = false is writable
 end
 
 # Something that represents a concern
index 14c8e94..b3ab0bb 100644 (file)
@@ -116,12 +116,15 @@ redef class ModelBuilder
                        #print "new class {mclass}"
                else if nclassdef isa AStdClassdef and nmodule.mclass2nclassdef.has_key(mclass) then
                        error(nclassdef, "Error: a class `{name}` is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
+                       mclass.is_broken = true
                        return
                else if nclassdef isa AStdClassdef and nclassdef.n_kwredef == null then
                        error(nclassdef, "Redef Error: `{name}` is an imported class. Add the `redef` keyword to refine it.")
+                       mclass.is_broken = true
                        return
                else if arity != 0 and mclass.arity != arity then
                        error(nclassdef, "Redef Error: expected {mclass.arity} formal parameter(s) for {mclass.signature_to_s}; got {arity}.")
+                       mclass.is_broken = true
                        return
                else if nkind != null and mkind != concrete_kind and mclass.kind != mkind then
                        error(nkind, "Redef Error: refinement changed the kind from `{mclass.kind}` to `{mkind}`.")
index eec36f4..e3f5ea1 100644 (file)
@@ -110,6 +110,7 @@ redef class ModelBuilder
                                if mpropdef.bound == null then continue
                                if not check_virtual_types_circularity(npropdef, mpropdef.mproperty, mclassdef.bound_mtype, mclassdef.mmodule) then
                                        # Invalidate the bound
+                                       mpropdef.is_broken = true
                                        mpropdef.bound = mclassdef.mmodule.model.null_type
                                end
                        end
@@ -720,6 +721,7 @@ redef class ASignature
                                res = false
                        end
                end
+               if not res then is_broken = true
                return res
        end
 end
@@ -831,8 +833,14 @@ redef class AMethPropdef
                        mprop.is_new = n_kwnew != null
                        if mprop.is_new then mclassdef.mclass.has_new_factory = true
                        if name == "sys" then mprop.is_toplevel = true # special case for sys allowed in `new` factories
-                       self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop)
+                       if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) then
+                               mprop.is_broken = true
+                               return
+                       end
                else
+                       if mprop.is_broken then
+                               return
+                       end
                        if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, not self isa AMainMethPropdef, mprop) then return
                        check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
                end
@@ -841,7 +849,10 @@ redef class AMethPropdef
                if is_init then
                        for p, n in mclassdef.mprop2npropdef do
                                if p != mprop and p isa MMethod and p.name == name then
-                                       check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, p)
+                                       if not check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, p) then
+                                               mprop.is_broken = true
+                                               return
+                                       end
                                        break
                                end
                        end
@@ -993,13 +1004,14 @@ redef class AMethPropdef
                var mclassdef = mpropdef.mclassdef
                var mmodule = mclassdef.mmodule
                var nsig = self.n_signature
-               var mysignature = self.mpropdef.msignature
+               var mysignature = mpropdef.msignature
                if mysignature == null then return # Error thus skiped
 
                # Check
                if nsig != null then
                        if not nsig.check_signature(modelbuilder, mclassdef) then
-                               self.mpropdef.msignature = null # invalidate
+                               mpropdef.msignature = null # invalidate
+                               mpropdef.is_broken = true
                                return # Forward error
                        end
                end
@@ -1014,7 +1026,8 @@ redef class AMethPropdef
                        var ret_type = mysignature.return_mtype
                        if ret_type != null and precursor_ret_type == null then
                                modelbuilder.error(nsig.n_type.as(not null), "Redef Error: `{mpropdef.mproperty}` is a procedure, not a function.")
-                               self.mpropdef.msignature = null
+                               mpropdef.msignature = null
+                               mpropdef.is_broken = true
                                return
                        end
 
@@ -1026,7 +1039,8 @@ redef class AMethPropdef
                                        var node = nsig.n_params[i]
                                        if not modelbuilder.check_sametype(node, mmodule, mclassdef.bound_mtype, myt, prt) then
                                                modelbuilder.error(node, "Redef Error: expected `{prt}` for parameter `{mysignature.mparameters[i].name}'; got `{myt}`.")
-                                               self.mpropdef.msignature = null
+                                               mpropdef.msignature = null
+                                               mpropdef.is_broken = true
                                        end
                                end
                        end
@@ -1039,7 +1053,8 @@ redef class AMethPropdef
                                        ret_type = precursor_ret_type
                                else if not modelbuilder.check_subtype(node, mmodule, mclassdef.bound_mtype, ret_type, precursor_ret_type) then
                                        modelbuilder.error(node, "Redef Error: expected `{precursor_ret_type}` for return type; got `{ret_type}`.")
-                                       self.mpropdef.msignature = null
+                                       mpropdef.msignature = null
+                                       mpropdef.is_broken = true
                                end
                        end
                end