Merge: Namespace for
authorJean Privat <jean@pryen.org>
Wed, 14 Jan 2015 03:13:38 +0000 (22:13 -0500)
committerJean Privat <jean@pryen.org>
Wed, 14 Jan 2015 03:13:38 +0000 (22:13 -0500)
Better implementation for `full_name` and `c_name` that make them shorter and use the project as the namespace of public entities.

Examples of fullnames of entities used in messages

* A public class `A` defined in the module `m` of the project `p` was `p::m::A`, now it is `p::A`.
* A public method `x` defined in a class `A` in the module `m` of the project `p` was `p::m::A::x`, now it is `p::A::x`

Exeaple of fullnames for entities that are used internally:

* The refinement of `A` in a module `p::n` was `p::n#p::m::A`, now it is `p::n#A`
* The redefinition of `x` in a class `B` in `p::n` was `p::n#p::m::B#p::m::A::x`, now it is `p::n#B#A::x`

The `c_name` get some comparable simplifications, so C identifiers will be simpler and will less overflow in unwind or in valgrind.

Note: please ignore the first commits that come from #1069

Pull-Request: #1092
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

src/model/mmodule.nit
src/model/model.nit
src/model/mproject.nit
tests/sav/nitunit_args4.res
tests/sav/nitunit_args5.res

index e66f164..b11a594 100644 (file)
@@ -76,6 +76,14 @@ class MModule
        # The group of module in the project if any
        var mgroup: nullable MGroup
 
+       # The project of the module if any
+       # Safe alias for `mgroup.mproject`
+       fun mproject: nullable MProject
+       do
+               var g = mgroup
+               if g == null then return null else return g.mproject
+       end
+
        # The short name of the module
        redef var name: String
 
@@ -104,6 +112,22 @@ class MModule
                end
        end
 
+       # The namespace used for entities according to their visibility `v`.
+       #
+       # Public entities use only the project as a namespace.
+       # Private entities use the `full_name` (i.e. "project::module")
+       #
+       # This method is used by entities to implement their `full_name`.
+       fun namespace_for(v: MVisibility): String do
+               if v <= private_visibility then return full_name
+               var mgroup = self.mgroup
+               if mgroup == null then
+                       return full_name
+               else
+                       return mgroup.mproject.full_name
+               end
+       end
+
        # Return the name of the global C identifier associated to `self`.
        # This name is used to prefix files and other C identifiers associated with `self`.
        redef var c_name: String is lazy do
@@ -117,6 +141,19 @@ class MModule
                return res
        end
 
+       # C identifier version of `namespace_for`.
+       # See `c_name`
+       #
+       # This method is used by entities to implement their `c_name`.
+       fun c_namespace_for(v: MVisibility): String do
+               if v <= private_visibility then return c_name
+               var mgroup = self.mgroup
+               if mgroup == null then
+                       return c_name
+               else
+                       return mgroup.mproject.c_name
+               end
+       end
 
        # Create a new empty module and register it to a model
        init
index 4d8ddc4..ff12710 100644 (file)
@@ -361,9 +361,13 @@ class MClass
        #
        # It is the name of the class prefixed by the full_name of the `intro_mmodule`
        # Example: `"owner::module::MyClass"`
-       redef var full_name is lazy do return "{self.intro_mmodule.full_name}::{name}"
+       redef var full_name is lazy do
+               return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
+       end
 
-       redef var c_name is lazy do return "{intro_mmodule.c_name}__{name.to_cmangle}"
+       redef var c_name is lazy do
+               return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
+       end
 
        # The number of generic formal parameters
        # 0 if the class is not generic
@@ -539,17 +543,29 @@ class MClassDef
        # Example: "my_module#intro_module::MyClass"
        redef var full_name is lazy do
                if is_intro then
+                       # public gives 'p#A'
+                       # private gives 'p::m#A'
+                       return "{mmodule.namespace_for(mclass.visibility)}#{mclass.name}"
+               else if mclass.intro_mmodule.mproject != mmodule.mproject then
+                       # public gives 'q::n#p::A'
+                       # private gives 'q::n#p::m::A'
+                       return "{mmodule.full_name}#{mclass.full_name}"
+               else if mclass.visibility > private_visibility then
+                       # public gives 'p::n#A'
                        return "{mmodule.full_name}#{mclass.name}"
                else
-                       return "{mmodule.full_name}#{mclass.full_name}"
+                       # private gives 'p::n#::m::A' (redundant p is omitted)
+                       return "{mmodule.full_name}#::{mclass.intro_mmodule.name}::{mclass.name}"
                end
        end
 
        redef var c_name is lazy do
                if is_intro then
-                       return mclass.c_name
+                       return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
+               else if mclass.intro_mmodule.mproject == mmodule.mproject and mclass.visibility > private_visibility then
+                       return "{mmodule.c_name}___{mclass.name.to_cmangle}"
                else
-                       return "{mmodule.c_name}__{mclass.c_name.to_cmangle}"
+                       return "{mmodule.c_name}___{mclass.c_name}"
                end
        end
 
@@ -1738,11 +1754,12 @@ abstract class MProperty
        # It is the short-`name` prefixed by the short-name of the class and the full-name of the module.
        # Example: "my_project::my_module::MyClass::my_method"
        redef var full_name is lazy do
-               return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
+               return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
        end
 
        redef var c_name is lazy do
-               return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.c_name}__{name.to_cmangle}"
+               # FIXME use `namespace_for`
+               return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
        end
 
        # The visibility of the property
@@ -2018,42 +2035,66 @@ abstract class MPropDef
        # Therefore the combination of identifiers is awful,
        # the worst case being
        #
-       # ~~~nitish
-       # "{mclassdef.mmodule.full_name}#{mclassdef.mclass.intro_mmodule.full_name}::{mclassdef.name}#{mproperty.intro_mclassdef.mmodule.full_name}::{mproperty.intro_mclassdef.name}::{name}"
-       # ~~~
+       #  * a property "p::m::A::x"
+       #  * redefined in a refinement of a class "q::n::B"
+       #  * in a module "r::o"
+       #  * so "r::o#q::n::B#p::m::A::x"
        #
        # Fortunately, the full-name is simplified when entities are repeated.
-       # The simplest form is "my_module#MyClass#my_property".
+       # For the previous case, the simplest form is "p#A#x".
        redef var full_name is lazy do
                var res = new FlatBuffer
-               res.append mclassdef.mmodule.full_name
-               res.append "#"
-               if not mclassdef.is_intro then
-                       res.append mclassdef.mclass.intro_mmodule.full_name
-                       res.append "::"
-               end
-               res.append mclassdef.name
+
+               # The first part is the mclassdef. Worst case is "r::o#q::n::B"
+               res.append mclassdef.full_name
+
                res.append "#"
-               if mproperty.intro_mclassdef.mmodule != mclassdef.mmodule then
-                       res.append mproperty.intro_mclassdef.mmodule.full_name
-                       res.append "::"
-               end
-               if mclassdef.mclass != mproperty.intro_mclassdef.mclass then
-                       res.append mproperty.intro_mclassdef.mclass.name
-                       res.append "::"
+
+               if mclassdef.mclass == mproperty.intro_mclassdef.mclass then
+                       # intro are unambiguous in a class
+                       res.append name
+               else
+                       # Just try to simplify each part
+                       if mclassdef.mmodule.mproject != mproperty.intro_mclassdef.mmodule.mproject then
+                               # precise "p::m" only if "p" != "r"
+                               res.append mproperty.intro_mclassdef.mmodule.full_name
+                               res.append "::"
+                       else if mproperty.visibility <= private_visibility then
+                               # Same project ("p"=="q"), but private visibility,
+                               # does the module part ("::m") need to be displayed
+                               if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mproject then
+                                       res.append "::"
+                                       res.append mproperty.intro_mclassdef.mmodule.name
+                                       res.append "::"
+                               end
+                       end
+                       if mclassdef.mclass != mproperty.intro_mclassdef.mclass then
+                               # precise "B" only if not the same class than "A"
+                               res.append mproperty.intro_mclassdef.name
+                               res.append "::"
+                       end
+                       # Always use the property name "x"
+                       res.append mproperty.name
                end
-               res.append name
                return res.to_s
        end
 
        redef var c_name is lazy do
                var res = new FlatBuffer
                res.append mclassdef.c_name
-               res.append "__"
-               if is_intro then
+               res.append "___"
+               if mclassdef.mclass == mproperty.intro_mclassdef.mclass then
                        res.append name.to_cmangle
                else
-                       res.append mproperty.c_name.to_cmangle
+                       if mclassdef.mmodule != mproperty.intro_mclassdef.mmodule then
+                               res.append mproperty.intro_mclassdef.mmodule.c_name
+                               res.append "__"
+                       end
+                       if mclassdef.mclass != mproperty.intro_mclassdef.mclass then
+                               res.append mproperty.intro_mclassdef.name.to_cmangle
+                               res.append "__"
+                       end
+                       res.append mproperty.name.to_cmangle
                end
                return res.to_s
        end
index 9002009..283d54c 100644 (file)
@@ -27,6 +27,10 @@ class MProject
        # The name of the project
        redef var name: String
 
+       redef fun full_name do return name
+
+       redef var c_name = name.to_cmangle is lazy
+
        # The model of the project
        redef var model: Model
 
index faaa0c9..91eb55f 100644 (file)
@@ -5,17 +5,17 @@ Entities: 4; Documented ones: 3; With nitunits: 3; Failures: 0
 TestSuites:
 No test cases found
 Class suites: 0; Test Cases: 0; Failures: 0
-<testsuites><testsuite package="test_nitunit2"><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::foo1"><system-err></system-err><system-out>if true then
+<testsuites><testsuite package="test_nitunit2"><testcase classname="nitunit.test_nitunit2.standard::Object" name="test_nitunit2::Object::foo1"><system-err></system-err><system-out>if true then
 
    assert true
 
 end
-</system-out></testcase><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::bar2"><system-err></system-err><system-out>if true then
+</system-out></testcase><testcase classname="nitunit.test_nitunit2.standard::Object" name="test_nitunit2::Object::bar2"><system-err></system-err><system-out>if true then
 
     assert true
 
 end
-</system-out></testcase><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::foo3"><system-err></system-err><system-out>var a = 1
+</system-out></testcase><testcase classname="nitunit.test_nitunit2.standard::Object" name="test_nitunit2::Object::foo3"><system-err></system-err><system-out>var a = 1
 assert a == 1
 assert a == 1
 </system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
index 7019ad0..356eaf4 100644 (file)
@@ -5,7 +5,7 @@ Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 0
 TestSuites:
 No test cases found
 Class suites: 0; Test Cases: 0; Failures: 0
-<testsuites><testsuite package="test_doc2"><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo1"><system-err></system-err><system-out>assert true # tested
-</system-out></testcase><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo2"><system-err></system-err><system-out>assert true # tested
-</system-out></testcase><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo3"><system-err></system-err><system-out>assert true # tested
+<testsuites><testsuite package="test_doc2"><testcase classname="nitunit.test_doc2.standard::Object" name="test_doc2::Object::foo1"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2.standard::Object" name="test_doc2::Object::foo2"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2.standard::Object" name="test_doc2::Object::foo3"><system-err></system-err><system-out>assert true # tested
 </system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file