Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: docs/clang_tool_refactoring.md

Issue 1577483003: Update documentation for clang tool refactoring. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: clarify Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Clang Tool Refactoring 1 # Clang Tool Refactoring
2 2
3 [TOC] 3 [TOC]
4 4
5 ## Introduction
6
7 Clang tools can help with global refactorings of Chromium code. Clang tools can
8 take advantage of clang's AST to perform refactorings that would be impossible
9 with a traditional find-and-replace regexp:
10
11 * Constructing `scoped_ptr<T>` from `NULL`: <https://crbug.com/173286>
12 * Implicit conversions of `scoped_refptr<T>` to `T*`: <https://crbug.com/11061 0>
13 * Rename everything in Blink to follow Chromium style: <https://crbug.com/5637 93>
14
5 ## Caveats 15 ## Caveats
6 16
7 * The current workflow requires git. 17 An invocation of the clang tool runs on one build config. Code that only
8 * This doesn't work on Windows... yet. I'm hoping to have a proof-of-concept 18 compiles on one platform or code that is guarded by a set of compile-time flags
9 working on Windows as well ~~in a month~~ several centuries from now. 19 can be problematic. Performing a global refactoring typically requires running
20 the tool once in each build config with code that needs to be updated.
21
22 Other minor issues:
23
24 * Requires a git checkout.
25 * Requires [some hacks to run on Windows](https://codereview.chromium.org/7188 73004).
10 26
11 ## Prerequisites 27 ## Prerequisites
12 28
13 Everything needed should be in a default Chromium checkout using gclient. 29 A Chromium checkout created with `fetch` should have everything needed.
14 `third_party/llvm-build/Release+Asserts/bin` should be in your `$PATH`.
15 30
16 ## Writing the Tool 31 For convenience, add `third_party/llvm-build/Release+Asserts/bin` to `$PATH`.
17 32
18 An example clang tool is being implemented in 33 ## Writing the tool
19 https://codereview.chromium.org/12746010/. Other useful resources might be the
20 [basic tutorial for Clang's AST matchers](http://clang.llvm.org/docs/LibASTMatch ersTutorial.html)
21 or the
22 [AST matcher reference](http://clang.llvm.org/docs/LibASTMatchersReference.html) .
23 34
24 Build your tool by running the following command (requires cmake version 2.8.10 35 LLVM uses C++11 and CMake. Source code for Chromium clang tools lives in
25 or later): 36 [//tools/clang](https://chromium.googlesource.com/chromium/src/tools/clang/+/mas ter).
37 It is generally easiest to use one of the already-written tools as the base for
38 writing a new tool.
39
40 Chromium clang tools generally follow this pattern:
41
42 1. Instantiate a [`clang::ast_matchers::MatchFinder`](
43 http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder.htm l).
44 2. Call `addMatcher()` to register [`clang::ast_matchers::MatchFinder::MatchCal lback`](
45 http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder_1_1 MatchCallback.html) actions to execute when [matching](http://clang.llvm.org/doc s/LibASTMatchersReference.html) the AST.
46 3. Create a new `clang::tooling::FrontendActionFactory` from the `MatchFinder`.
47 4. Run the action across the specified files with
48 [`clang::tooling::ClangTool::run`](http://clang.llvm.org/doxygen/classclang_ 1_1tooling_1_1ClangTool.html#acec91f63b45ac7ee2d6c94cb9c10dab3).
49 5. Serialize generated [`clang::tooling::Replacement`](
50 http://clang.llvm.org/doxygen/classclang_1_1tooling_1_1Replacement.html)s to
51 `stdout`.
52
53 Other useful references when writing the tool:
54
55 * [Clang doxygen reference](http://clang.llvm.org/doxygen/index.html)
56 * [Tutorial for building tools using LibTooling and LibASTMatchers](http://cla ng.llvm.org/docs/LibASTMatchersTutorial.html)
57
58 ### Edit serialization format
59 ```
60 ==== BEGIN EDITS ====
61 r:::path/to/file1:::offset1:::length1:::replacement text
62 r:::path/to/file2:::offset2:::length2:::replacement text
63
64 ...
65
66 ==== END EDITS ====
67 ```
68
69 The header and footer are required. Each line between the header and footer
70 represents one edit. Fields are separated by `:::`, and the first field must
71 be `r` (for replacement). In the future, this may be extended to handle header
72 insertion/removal. A deletion is an edit with no replacement text.
73
74 The edits are applied by [`run_tool.py`](#Running), which understands certain
75 conventions:
76
77 * The tool should munge newlines in replacement text to `\0`. The script
78 knows to translate `\0` back to newlines when applying edits.
79 * When removing an element from a 'list' (e.g. function parameters,
80 initializers), the tool should emit a deletion for just the element. The
81 script understands how to extend the deletion to remove commas, etc. as
82 needed.
83
84 TODO: Document more about `SourceLocation` and how spelling loc differs from
85 expansion loc, etc.
86
87 ### Why not RefactoringTool?
88 While clang has a [`clang::tooling::RefactoringTool`](
89 http://clang.llvm.org/doxygen/classclang_1_1tooling_1_1RefactoringTool.html) to
90 automatically apply the generated replacements and save the results, it doesn't
91 work well for Chromium:
92
93 * Clang tools run actions serially, so runtime scales poorly to tens of
94 thousands of files.
95 * A parsing error in any file (quite common in NaCl source) prevents any of
96 the generated replacements from being applied.
97
98 ## Building
99 Synopsis:
100 ```shell
101 tools/clang/scripts/update.py --force-local-build --without-android \
102 --tools blink_gc_plugin plugins rewrite_to_chrome_style
103 ```
104 Running this command builds the [Oilpan plugin](https://chromium.googlesource.co m/chromium/src/+/master/tools/clang/blink_gc_plugin/),
105 the [Chrome style
106 plugin](https://chromium.googlesource.com/chromium/src/+/master/tools/clang/plug ins/),
107 and the [Blink to Chrome style rewriter](https://chromium.googlesource.com/chrom ium/src/+/master/tools/clang/rewrite_to_chrome_style/). Additional arguments to `--tools` should be the name of
108 subdirectories in
109 [//tools/clang](https://chromium.googlesource.com/chromium/src/+/master/tools/cl ang).
110 Generally, `--tools` should always include `blink_gc_plugin` and `plugins`: othe rwise, Chromium won't build.
111
112 ## Running
113 First, build all chromium targets to avoid failures due to missing dependecies
114 that are generated as part of the build:
115 ```shell
116 ninja -C out/Debug
117 ```
118
119 Then run the actual tool:
120 ```
121 tools/clang/scripts/run_tool.py <toolname> \
122 --generate-compdb
123 out/Debug <path 1> <path 2> ...
124 ```
125
126 `--generate-compdb` can be omitted if the compile DB was already generated and
127 the list of build flags and source files has not changed since generation.
128
129 `<path 1>`, `<path 2>`, etc are optional arguments to filter the files to run
130 the tool across. This is helpful when sharding global refactorings into smaller
131 chunks. For example, the following command will run the `empty_string` tool
132 across just the files in `//base`:
26 133
27 ```shell 134 ```shell
28 tools/clang/scripts/update.py --force-local-build --without-android \ 135 tools/clang/scripts/run_tool.py empty_string \
29 --tools <tools> 136 --generated-compdb \
137 out/Debug base
30 ``` 138 ```
31 139
32 `<tools>` is a semicolon delimited list of subdirectories in `tools/clang` to 140 ## Debugging
33 build. The resulting binary will end up in 141 Dumping the AST for a file:
34 `third_party/llvm-build/Release+Asserts/bin`. For example, to build the Chrome
35 plugin and the empty\_string tool, run the following:
36
37 ```shell
38 tools/clang/scripts/update.py --force-local-build --without-android \
39 --tools plugins empty_string
40 ```
41
42 When writing AST matchers, the following can be helpful to see what clang thinks
43 the AST is:
44
45 ```shell 142 ```shell
46 clang++ -cc1 -ast-dump foo.cc 143 clang++ -cc1 -ast-dump foo.cc
47 ``` 144 ```
48 145
49 ## Running the tool 146 Using `clang-query` to dynamically test matchers (requires checking out
50 147 and building [clang-tools-extras](https://github.com/llvm-mirror/clang-tools-ext ra)):
51 First, you'll need to generate the compilation database with the following
52 command:
53
54 ```shell 148 ```shell
55 cd $HOME/src/chrome/src 149 clang-query -p path/to/compdb base/memory/ref_counted.cc
56 ninja -C out/Debug -t compdb cc cxx objc objcxx > \
57 out/Debug/compile_commands.json
58 ``` 150 ```
59 151
60 This will dump the command lines used to build the C/C++ modules in all of 152 `printf` debugging:
61 Chromium into the resulting file. Then run the following command to run your 153 ```c++
62 tool across all Chromium code: 154 clang::Decl* decl = result.Nodes.getNodeAs<clang::Decl>("decl");
63 155 decl->dumpColor();
64 ```shell 156 clang::Stmt* stmt = result.Nodes.getNodeAs<clang::Stmt>("stmt");
65 # Make sure all chromium targets are built to avoid missing generated 157 stmt->dumpColor();
66 # dependencies
67 ninja -C out/Debug
68 tools/clang/scripts/run_tool.py <toolname> \
69 <path/to/directory/with/compile_commands.json> <path 1> <path 2> ...
70 ``` 158 ```
71 159 By default, the script hides the output of the tool. The easiest way to change
72 `<path 1>`, `<path 2>`, etc are optional arguments you use to filter the files 160 that is to `return 1` from the `main()` function of the clang tool.
73 that will be rewritten. For example, if you only want to run the `empty-string`
74 tool on files in `chrome/browser/extensions` and `sync`, you'd do something like :
75
76 ```shell
77 tools/clang/scripts/run_tool.py empty_string out/Debug \
78 chrome/browser/extensions sync
79 ```
80
81 ## Limitations
82
83 Since the compile database is generated by ninja, that means that files that
84 aren't compiled on that platform won't be processed. That means if you want to
85 apply a change across all Chromium platforms, you'll have to run the tool once
86 on each platform.
87 161
88 ## Testing 162 ## Testing
89 163 Synposis:
90 `test_tool.py` is the test harness for running tests. To use it, simply run:
91
92 ```shell 164 ```shell
93 test_tool.py <tool name> 165 test_tool.py <tool name>
94 ``` 166 ```
95 167
96 Note that name of the built tool and the subdirectory it lives in at 168 The name of the tool binary and the subdirectory for the tool in
97 `tools/clang` must match. What the test harness does is find all files that 169 `//tools/clang` must match. The test runner finds all files that match the
98 match the pattern `*-original.cc` in your tool's tests subdirectory. It then 170 pattern `//tools/clang/<tool name>/tests/*-original.cc`, runs the tool across
99 runs the tool across those files and compares it to the expected result, stored 171 those files, and compared it to the `*-expected.cc` version. If there is a
100 in `*-expected.cc` 172 mismatch, the result is saved in `*-actual.cc`.
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698