================ @@ -0,0 +1,310 @@ +====================== +Clang-Change-Namespace +====================== + +.. contents:: + +.. toctree:: + :maxdepth: 1 + +:program:`clang-change-namespace` can be used to change the surrounding +namespaces of class/function definitions. + +Classes/functions in the moved namespace will have new namespaces while +references to symbols (e.g. types, functions) which are not defined in the +changed namespace will be correctly qualified by prepending namespace specifiers +before them. This will try to add shortest namespace specifiers possible. + +When a symbol reference needs to be fully-qualified, this adds a `::` prefix to +the namespace specifiers unless the new namespace is the global namespace. For +classes, only classes that are declared/defined in the given namespace in +specified files will be moved: forward declarations will remain in the old +namespace. The will be demonstrated in the next example. + +Example usage +------------- + +For example, consider this `test.cc` example here with the forward declared +class `FWD` and the defined class `A`, both in the namespace `a`. + +.. code-block:: c++ + + namespace a { + class FWD; + class A { + FWD *fwd; + }; + } // namespace a + +And now let's change the namespace `a` to `x`. + +.. code-block:: console + + clang-change-namespace \ + --old_namespace "a" \ + --new_namespace "x" \ + --file_pattern "test.cc" \ + --i \ + test.cc + +Note that in the code below there's still the forward decalred class `FWD` that +stayed in the namespace `a`. It wasn't moved to the new namespace because it +wasn't defined/declared here in `a` but only forward declared. + +.. code-block:: c++ + + namespace a { + class FWD; + } // namespace a + namespace x { + + class A { + a::FWD *fwd; + }; + } // namespace x + + +Another example +--------------- + +Consider this `test.cc` file: + +.. code-block:: c++ + + namespace na { + class X {}; + namespace nb { + class Y { + X x; + }; + } // namespace nb + } // namespace na + +To move the definition of class `Y` from namespace `na::nb` to `x::y`, run: + +.. code-block:: console + + clang-change-namespace \ + --old_namespace "na::nb" \ + --new_namespace "x::y" \ + --file_pattern "test.cc" \ + --i \ + test.cc + +This will overwrite `test.cc` to look like this: + +.. code-block:: c++ + + namespace na { + class X {}; + + } // namespace na + namespace x { + namespace y { + class Y { + na::X x; + }; + } // namespace y + } // namespace x + +Note, that we've successfully moved the class `Y` from namespace `na::nb` to +namespace `x::y`. + +Caveats +======= + +Content already exists in new namespace +--------------------------------------- + +Consider this `test.cc` example that defines two `class A` one inside the +namespace `a` and one in namespace `b`: + +.. code-block:: c++ + + namespace a { + class A { + int classAFromWithinNamespace_a; + }; + } // namespace a + + namespace b { + class A { + int classAFromWithinNamespace_b; + }; + } //namespace b + +Let's move everything from the namespace `a` to the global namespace +(`--new_namespace ""` means global namespace): + +.. code-block:: console + + clang-change-namespace \ + --old_namespace "a" \ + --new_namespace "b" \ + --file_pattern test.cc \ + test.cc + +As expected we now have to definitions of `class A` inside the namespace `b`: + +.. code-block:: c++ + + namespace b { + class A { + int classAFromWithinNamespace_a; + }; + } // namespace b + + namespace b { + class A { + int classAFromWithinNamespace_b; + }; + } //namespace b + +The re-factoring looks correct but the code will not compile due to the name +duplication. It is not up to the tool to ensure compilability in that sense. +But one has to be aware of that. + +Inline namespace doesn't work +----------------------------- + +Consider this usage of two versions of implementations for a `greet` function: + +.. code-block:: c++ + + #include <cstdio> + + namespace Greeter { + inline namespace Version1 { + const char* greet() { return "Hello from version 1!"; } + } // namespace Version1 + namespace Version2 { + const char* greet() { return "Hello from version 2!"; } + } // namespace Version2 + } // namespace Greeter + + int main(int argc, char* argv[]) { + printf("%s\n", Greeter::greet()); + return 0; + } + +Note, that currently `Greeter::greet()` will result in a call to +`Greeter::Version1::greet()` because that's the inlined namespace. + +Let's say you want to move one and make `Version2` the default now and remove +the `inline` from the `Version1`. First let's try to turn `namespace Version2` +into `inline namespace Version2`: + +.. code-block:: console + + clang-change-namespace \ + --old_namespace "Greeter::Version2" \ + --new_namespace "inline Version2" \ + --file_pattern main.cc main.cc + +But this will put the `inline` keyword in the wrong place resulting in: + +.. code-block:: c++ + + #include <cstdio> + + namespace Greeter { + inline namespace Version1 { + const char* greet() { return "Hello from version 1!"; } + } // namespace Version1 + + } // namespace Greeter + namespace inline Greeter { + namespace Version2 { + const char *greet() { return "Hello from version 2!"; } + } // namespace Version2 + } // namespace inline Greeter + + int main(int argc, char* argv[]) { + printf("%s\n", Greeter::greet()); + return 0; + } + +Apparently one cannot use `:program:`clang-change-namespace` to inline a ---------------- kwk wrote:
I get that and you're right. Removed in 64ad789b414b74efb47c0a73aa2f9955dd015504. https://github.com/llvm/llvm-project/pull/148277 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits