Author: Konrad Kleine Date: 2025-08-18T21:46:34+02:00 New Revision: f5a648f9193a16b1136772096c3024a0d8b3fb34
URL: https://github.com/llvm/llvm-project/commit/f5a648f9193a16b1136772096c3024a0d8b3fb34 DIFF: https://github.com/llvm/llvm-project/commit/f5a648f9193a16b1136772096c3024a0d8b3fb34.diff LOG: [doc] Add documentation for clang-change-namespace (#148277) This adds rst documentation for the `clang-change-namespace` program. Fixes #35519 Added: clang-tools-extra/docs/clang-change-namespace.rst Modified: clang-tools-extra/docs/index.rst Removed: ################################################################################ diff --git a/clang-tools-extra/docs/clang-change-namespace.rst b/clang-tools-extra/docs/clang-change-namespace.rst new file mode 100644 index 0000000000000..1eab83f5069b6 --- /dev/null +++ b/clang-tools-extra/docs/clang-change-namespace.rst @@ -0,0 +1,314 @@ +====================== +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 namespace `a` to namespace `b`: + +.. 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; + } + +One cannot use `:program:`clang-change-namespace` to inline a namespace. + +Symbol references not updated +----------------------------- + +Consider this `test.cc` file: + +.. code-block:: c++ + + namespace old { + struct foo {}; + } // namespace old + + namespace b { + old::foo g_foo; + } // namespace b + +Notice that namespace `b` defines a global variable of type `old::foo`. If we +now change the name of the `old` namespace to `modern`, the reference will not +be updated: + +.. code-block:: console + + clang-change-namespace \ + --old_namespace "old" \ + --new_namespace "modern" \ + --file_pattern test.cc \ + test.cc + +.. code-block:: c++ + + namespace modern { + struct foo {}; + } // namespace modern + + namespace b { + old::foo g_foo; + } // namespace b + +`g_foo` is still of the no longer existing type `old::foo` while instead it +should use `modern::foo`. + +Only symbol references in the moved namespace are updated, not outside of it. + + +:program:`clang-change-namespace` Command Line Options +====================================================== + +.. option:: --allowed_file=<string> + + A file containing regexes of symbol names that are not expected to be updated + when changing namespaces around them. + +.. option:: --dump_result + + Dump new file contents in YAML, if specified. + +.. option:: --extra-arg=<string> + + Additional argument to append to the compiler command line + +.. option:: --extra-arg-before=<string> + + Additional argument to prepend to the compiler command line + +.. option:: --file_pattern=<string> + + Only rename namespaces in files that match the given regular expression + pattern. + +.. option:: -i + + Inplace edit <file>s, if specified. + +.. option:: --new_namespace=<string> + + New namespace. Use `""` when you target the global namespace. + +.. option:: --old_namespace=<string> + + Old namespace. + +.. option:: -p <string> + + Build path + +.. option:: --style=<string> + + The style name used for reformatting. diff --git a/clang-tools-extra/docs/index.rst b/clang-tools-extra/docs/index.rst index 9f7324fcf7419..3f3a99d1b70c6 100644 --- a/clang-tools-extra/docs/index.rst +++ b/clang-tools-extra/docs/index.rst @@ -17,6 +17,7 @@ Contents clang-tidy/index clang-include-fixer + clang-change-namespace modularize pp-trace clangd <https://clangd.llvm.org/> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits