315 lines
7.0 KiB
ReStructuredText
315 lines
7.0 KiB
ReStructuredText
======================
|
|
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.
|