================
@@ -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
+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
----------------
kwk wrote:

You're right. I went with consistency and modified the oneliner by breaking it 
up in c653ba231982e175abc22f1f4d7e079c474b8e0b.

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

Reply via email to