Skip to content

Commit f5a648f

Browse files
authored
[doc] Add documentation for clang-change-namespace (#148277)
This adds rst documentation for the `clang-change-namespace` program. Fixes #35519
1 parent 9403c2d commit f5a648f

File tree

2 files changed

+315
-0
lines changed

2 files changed

+315
-0
lines changed
Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
======================
2+
Clang-Change-Namespace
3+
======================
4+
5+
.. contents::
6+
7+
.. toctree::
8+
:maxdepth: 1
9+
10+
:program:`clang-change-namespace` can be used to change the surrounding
11+
namespaces of class/function definitions.
12+
13+
Classes/functions in the moved namespace will have new namespaces while
14+
references to symbols (e.g. types, functions) which are not defined in the
15+
changed namespace will be correctly qualified by prepending namespace specifiers
16+
before them. This will try to add shortest namespace specifiers possible.
17+
18+
When a symbol reference needs to be fully-qualified, this adds a `::` prefix to
19+
the namespace specifiers unless the new namespace is the global namespace. For
20+
classes, only classes that are declared/defined in the given namespace in
21+
specified files will be moved: forward declarations will remain in the old
22+
namespace. The will be demonstrated in the next example.
23+
24+
Example usage
25+
-------------
26+
27+
For example, consider this `test.cc` example here with the forward declared
28+
class `FWD` and the defined class `A`, both in the namespace `a`.
29+
30+
.. code-block:: c++
31+
32+
namespace a {
33+
class FWD;
34+
class A {
35+
FWD *fwd;
36+
};
37+
} // namespace a
38+
39+
And now let's change the namespace `a` to `x`.
40+
41+
.. code-block:: console
42+
43+
clang-change-namespace \
44+
--old_namespace "a" \
45+
--new_namespace "x" \
46+
--file_pattern "test.cc" \
47+
--i \
48+
test.cc
49+
50+
Note that in the code below there's still the forward decalred class `FWD` that
51+
stayed in the namespace `a`. It wasn't moved to the new namespace because it
52+
wasn't defined/declared here in `a` but only forward declared.
53+
54+
.. code-block:: c++
55+
56+
namespace a {
57+
class FWD;
58+
} // namespace a
59+
namespace x {
60+
61+
class A {
62+
a::FWD *fwd;
63+
};
64+
} // namespace x
65+
66+
67+
Another example
68+
---------------
69+
70+
Consider this `test.cc` file:
71+
72+
.. code-block:: c++
73+
74+
namespace na {
75+
class X {};
76+
namespace nb {
77+
class Y {
78+
X x;
79+
};
80+
} // namespace nb
81+
} // namespace na
82+
83+
To move the definition of class `Y` from namespace `na::nb` to `x::y`, run:
84+
85+
.. code-block:: console
86+
87+
clang-change-namespace \
88+
--old_namespace "na::nb" \
89+
--new_namespace "x::y" \
90+
--file_pattern "test.cc" \
91+
--i \
92+
test.cc
93+
94+
This will overwrite `test.cc` to look like this:
95+
96+
.. code-block:: c++
97+
98+
namespace na {
99+
class X {};
100+
101+
} // namespace na
102+
namespace x {
103+
namespace y {
104+
class Y {
105+
na::X x;
106+
};
107+
} // namespace y
108+
} // namespace x
109+
110+
Note, that we've successfully moved the class `Y` from namespace `na::nb` to
111+
namespace `x::y`.
112+
113+
Caveats
114+
=======
115+
116+
Content already exists in new namespace
117+
---------------------------------------
118+
119+
Consider this `test.cc` example that defines two `class A` one inside the
120+
namespace `a` and one in namespace `b`:
121+
122+
.. code-block:: c++
123+
124+
namespace a {
125+
class A {
126+
int classAFromWithinNamespace_a;
127+
};
128+
} // namespace a
129+
130+
namespace b {
131+
class A {
132+
int classAFromWithinNamespace_b;
133+
};
134+
} //namespace b
135+
136+
Let's move everything from namespace `a` to namespace `b`:
137+
138+
.. code-block:: console
139+
140+
clang-change-namespace \
141+
--old_namespace "a" \
142+
--new_namespace "b" \
143+
--file_pattern test.cc \
144+
test.cc
145+
146+
As expected we now have to definitions of `class A` inside the namespace `b`:
147+
148+
.. code-block:: c++
149+
150+
namespace b {
151+
class A {
152+
int classAFromWithinNamespace_a;
153+
};
154+
} // namespace b
155+
156+
namespace b {
157+
class A {
158+
int classAFromWithinNamespace_b;
159+
};
160+
} //namespace b
161+
162+
The re-factoring looks correct but the code will not compile due to the name
163+
duplication. It is not up to the tool to ensure compilability in that sense.
164+
But one has to be aware of that.
165+
166+
Inline namespace doesn't work
167+
-----------------------------
168+
169+
Consider this usage of two versions of implementations for a `greet` function:
170+
171+
.. code-block:: c++
172+
173+
#include <cstdio>
174+
175+
namespace Greeter {
176+
inline namespace Version1 {
177+
const char* greet() { return "Hello from version 1!"; }
178+
} // namespace Version1
179+
namespace Version2 {
180+
const char* greet() { return "Hello from version 2!"; }
181+
} // namespace Version2
182+
} // namespace Greeter
183+
184+
int main(int argc, char* argv[]) {
185+
printf("%s\n", Greeter::greet());
186+
return 0;
187+
}
188+
189+
Note, that currently `Greeter::greet()` will result in a call to
190+
`Greeter::Version1::greet()` because that's the inlined namespace.
191+
192+
Let's say you want to move one and make `Version2` the default now and remove
193+
the `inline` from the `Version1`. First let's try to turn `namespace Version2`
194+
into `inline namespace Version2`:
195+
196+
.. code-block:: console
197+
198+
clang-change-namespace \
199+
--old_namespace "Greeter::Version2" \
200+
--new_namespace "inline Version2" \
201+
--file_pattern main.cc main.cc
202+
203+
But this will put the `inline` keyword in the wrong place resulting in:
204+
205+
.. code-block:: c++
206+
207+
#include <cstdio>
208+
209+
namespace Greeter {
210+
inline namespace Version1 {
211+
const char* greet() { return "Hello from version 1!"; }
212+
} // namespace Version1
213+
214+
} // namespace Greeter
215+
namespace inline Greeter {
216+
namespace Version2 {
217+
const char *greet() { return "Hello from version 2!"; }
218+
} // namespace Version2
219+
} // namespace inline Greeter
220+
221+
int main(int argc, char* argv[]) {
222+
printf("%s\n", Greeter::greet());
223+
return 0;
224+
}
225+
226+
One cannot use `:program:`clang-change-namespace` to inline a namespace.
227+
228+
Symbol references not updated
229+
-----------------------------
230+
231+
Consider this `test.cc` file:
232+
233+
.. code-block:: c++
234+
235+
namespace old {
236+
struct foo {};
237+
} // namespace old
238+
239+
namespace b {
240+
old::foo g_foo;
241+
} // namespace b
242+
243+
Notice that namespace `b` defines a global variable of type `old::foo`. If we
244+
now change the name of the `old` namespace to `modern`, the reference will not
245+
be updated:
246+
247+
.. code-block:: console
248+
249+
clang-change-namespace \
250+
--old_namespace "old" \
251+
--new_namespace "modern" \
252+
--file_pattern test.cc \
253+
test.cc
254+
255+
.. code-block:: c++
256+
257+
namespace modern {
258+
struct foo {};
259+
} // namespace modern
260+
261+
namespace b {
262+
old::foo g_foo;
263+
} // namespace b
264+
265+
`g_foo` is still of the no longer existing type `old::foo` while instead it
266+
should use `modern::foo`.
267+
268+
Only symbol references in the moved namespace are updated, not outside of it.
269+
270+
271+
:program:`clang-change-namespace` Command Line Options
272+
======================================================
273+
274+
.. option:: --allowed_file=<string>
275+
276+
A file containing regexes of symbol names that are not expected to be updated
277+
when changing namespaces around them.
278+
279+
.. option:: --dump_result
280+
281+
Dump new file contents in YAML, if specified.
282+
283+
.. option:: --extra-arg=<string>
284+
285+
Additional argument to append to the compiler command line
286+
287+
.. option:: --extra-arg-before=<string>
288+
289+
Additional argument to prepend to the compiler command line
290+
291+
.. option:: --file_pattern=<string>
292+
293+
Only rename namespaces in files that match the given regular expression
294+
pattern.
295+
296+
.. option:: -i
297+
298+
Inplace edit <file>s, if specified.
299+
300+
.. option:: --new_namespace=<string>
301+
302+
New namespace. Use `""` when you target the global namespace.
303+
304+
.. option:: --old_namespace=<string>
305+
306+
Old namespace.
307+
308+
.. option:: -p <string>
309+
310+
Build path
311+
312+
.. option:: --style=<string>
313+
314+
The style name used for reformatting.

clang-tools-extra/docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Contents
1717

1818
clang-tidy/index
1919
clang-include-fixer
20+
clang-change-namespace
2021
modularize
2122
pp-trace
2223
clangd <https://clangd.llvm.org/>

0 commit comments

Comments
 (0)