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

Reply via email to