Merge: modelize: ask that attributes in refinements are either noautoninit or have...
[nit.git] / src / modelize / modelize_property.nit
index 9924245..91c552f 100644 (file)
@@ -206,9 +206,9 @@ redef class ModelBuilder
                                var mreadpropdef = npropdef.mreadpropdef
                                if mreadpropdef == null or mreadpropdef.msignature == null then return # Skip broken attribute
                                if npropdef.noinit then continue # Skip noinit attribute
-                               var atautoinit = npropdef.get_single_annotation("autoinit", self)
-                               if atautoinit != null then
-                                       # For autoinit attributes, call the reader to force
+                               var atlateinit = npropdef.get_single_annotation("lateinit", self)
+                               if atlateinit != null then
+                                       # For lateinit attributes, call the reader to force
                                        # the lazy initialization of the attribute.
                                        initializers.add(mreadpropdef.mproperty)
                                        mreadpropdef.mproperty.is_autoinit = true
@@ -299,25 +299,19 @@ redef class ModelBuilder
                                        abort
                                end
                        end
-               else if noautoinit != null then
-                       if initializers.is_empty then
-                               warning(noautoinit, "useless-noautoinit", "Warning: the list of autoinit is already empty.")
-                       end
-                       # Just clear initializers
-                       mparameters.clear
-                       initializers.clear
                else
                        # Search the longest-one and checks for conflict
                        var longest = spropdefs.first
                        if spropdefs.length > 1 then
-                               # Check for conflict in the order of initializers
-                               # Each initializer list must me a prefix of the longest list
                                # part 1. find the longest list
                                for spd in spropdefs do
                                        if spd.initializers.length > longest.initializers.length then longest = spd
                                end
                                # part 2. compare
-                               for spd in spropdefs do
+                               # Check for conflict in the order of initializers
+                               # Each initializer list must me a prefix of the longest list
+                               # If `noautoinit` is set, just ignore conflicts
+                               if noautoinit == null then for spd in spropdefs do
                                        var i = 0
                                        for p in spd.initializers do
                                                if p != longest.initializers[i] then
@@ -330,17 +324,27 @@ redef class ModelBuilder
                                end
                        end
 
-                       # Can we just inherit?
-                       if spropdefs.length == 1 and mparameters.is_empty and defined_init == null then
-                               self.toolcontext.info("{mclassdef} inherits the basic constructor {longest}", 3)
-                               mclassdef.mclass.root_init = longest
-                               return
-                       end
+                       if noautoinit != null then
+                               # If there is local or inherited initializers, then complain.
+                               if initializers.is_empty and longest.initializers.is_empty then
+                                       warning(noautoinit, "useless-noautoinit", "Warning: the list of autoinit is already empty.")
+                               end
+                               # Just clear initializers
+                               mparameters.clear
+                               initializers.clear
+                       else
+                               # Can we just inherit?
+                               if spropdefs.length == 1 and mparameters.is_empty and defined_init == null then
+                                       self.toolcontext.info("{mclassdef} inherits the basic constructor {longest}", 3)
+                                       mclassdef.mclass.root_init = longest
+                                       return
+                               end
 
-                       # Combine the inherited list to what is collected
-                       if longest.initializers.length > 0 then
-                               mparameters.prepend longest.new_msignature.mparameters
-                               initializers.prepend longest.initializers
+                               # Combine the inherited list to what is collected
+                               if longest.initializers.length > 0 then
+                                       mparameters.prepend longest.new_msignature.mparameters
+                                       initializers.prepend longest.initializers
+                               end
                        end
                end
 
@@ -656,6 +660,8 @@ redef class APropdef
                return true
        end
 
+       # Checks for useless type in redef signatures.
+       private fun check_repeated_types(modelbuilder: ModelBuilder) do end
 end
 
 redef class ASignature
@@ -1051,6 +1057,28 @@ redef class AMethPropdef
                        var nt = nsig.n_type
                        if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef)
                end
+               check_repeated_types(modelbuilder)
+       end
+
+       # For parameters, type is always useless in a redef.
+       # For return type, type is useless if not covariant with introduction.
+       redef fun check_repeated_types(modelbuilder) do
+               if mpropdef.is_intro or n_signature == null then return
+               # check params
+               for param in n_signature.n_params do
+                       if param.n_type != null then
+                               modelbuilder.advice(param.n_type, "useless-signature", "Warning: useless type repetition on parameter `{param.n_id.text}` for redefined method `{mpropdef.name}`")
+                       end
+               end
+               # get intro
+               var intro = mpropdef.mproperty.intro
+               var n_intro = modelbuilder.mpropdef2npropdef.get_or_null(intro)
+               if n_intro == null or not n_intro isa AMethPropdef then return
+               # check return type
+               var ret_type = n_signature.ret_type
+               if ret_type != null and ret_type == n_intro.n_signature.ret_type then
+                       modelbuilder.advice(n_signature.n_type, "useless-signature", "Warning: useless return type repetition for redefined method `{mpropdef.name}`")
+               end
        end
 end
 
@@ -1187,17 +1215,17 @@ redef class AAttrPropdef
                end
 
                var atlazy = self.get_single_annotation("lazy", modelbuilder)
-               var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
-               if atlazy != null or atautoinit != null then
-                       if atlazy != null and atautoinit != null then
-                               modelbuilder.error(atlazy, "Error: `lazy` incompatible with `autoinit`.")
+               var atlateinit = self.get_single_annotation("lateinit", modelbuilder)
+               if atlazy != null or atlateinit != null then
+                       if atlazy != null and atlateinit != null then
+                               modelbuilder.error(atlazy, "Error: `lazy` incompatible with `lateinit`.")
                                return
                        end
                        if not has_value then
                                if atlazy != null then
                                        modelbuilder.error(atlazy, "Error: `lazy` attributes need a value.")
-                               else if atautoinit != null then
-                                       modelbuilder.error(atautoinit, "Error: `autoinit` attributes need a value.")
+                               else if atlateinit != null then
+                                       modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.")
                                end
                                has_value = true
                                return
@@ -1293,6 +1321,9 @@ redef class AAttrPropdef
                                else if nexpr isa AIntExpr then
                                        var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
                                        if cla != null then mtype = cla.mclass_type
+                               else if nexpr isa AByteExpr then
+                                       var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Byte")
+                                       if cla != null then mtype = cla.mclass_type
                                else if nexpr isa AFloatExpr then
                                        var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Float")
                                        if cla != null then mtype = cla.mclass_type
@@ -1350,6 +1381,7 @@ redef class AAttrPropdef
                if mlazypropdef != null then
                        mlazypropdef.static_mtype = modelbuilder.model.get_mclasses_by_name("Bool").first.mclass_type
                end
+               check_repeated_types(modelbuilder)
        end
 
        redef fun check_signature(modelbuilder)
@@ -1454,6 +1486,25 @@ redef class AAttrPropdef
                        end
                end
        end
+
+       # Type is useless if the attribute type is the same thant the intro.
+       redef fun check_repeated_types(modelbuilder) do
+               if mreadpropdef.is_intro or n_type == null then return
+               # get intro
+               var intro = mreadpropdef.mproperty.intro
+               var n_intro = modelbuilder.mpropdef2npropdef.get_or_null(intro)
+               if n_intro == null then return
+               # get intro type
+               var ntype = null
+               if n_intro isa AMethPropdef then
+                       ntype = n_intro.n_signature.ret_type
+               else if n_intro isa AAttrPropdef and n_intro.n_type != null then
+                       ntype = n_intro.n_type.mtype
+               end
+               # check
+               if ntype ==null or ntype != n_type.mtype then return
+               modelbuilder.advice(n_type, "useless-signature", "Warning: useless type repetition on redefined attribute `{mpropdef.name}`")
+       end
 end
 
 redef class ATypePropdef