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

Side by Side Diff: docs/writing_clang_plugins.md

Issue 1310373005: Doc style: writing_clang_plugins.md (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Created 5 years, 3 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 # Don't write a clang plugin 1 # Don't write a clang plugin
2 2
3 [TOC]
4
5 TODO: although cs.chromium.org
6 [finds](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/l lvm/)
7 `src/third_party/llvm`, it
8 [does not exist in Gitiles](https://chromium.googlesource.com/src/third_party/ll vm/).
nodir 2015/08/24 22:55:30 I don't know where it is gone. Can you help? I'd l
Bons 2015/08/25 00:38:26 put a TODO in
9
3 Make sure you really want to write a clang plugin. 10 Make sure you really want to write a clang plugin.
4 11
5 * The clang plugin api is not stable. If you write a plugin, _you_ are respons ible for making sure it's updated when we update clang. 12 * The clang plugin api is not stable. If you write a plugin, _you_ are
6 * If you're adding a generally useful warning, it should be added to upstream clang, not to a plugin. 13 responsible for making sure it's updated when we update clang.
7 * You should not use a clang plugin to do things that can be done in a PRESUBM IT check (e.g. checking that the headers in a file are sorted). 14 * If you're adding a generally useful warning, it should be added to upstream
15 clang, not to a plugin.
16 * You should not use a clang plugin to do things that can be done in a
17 PRESUBMIT check (e.g. checking that the headers in a file are sorted).
8 18
9 Valid reasons for writing a plugin are for example: 19 Valid reasons for writing a plugin are for example:
10 20
11 * You want to add a chromium-specific error message. 21 * You want to add a chromium-specific error message.
12 * You want to write an automatic code rewriter. 22 * You want to write an automatic code rewriter.
13 23
14 In both cases, please inform [clang@chromium.org](http://groups.google.com/a/chr omium.org/group/clang/topics) of your plans before you pursue them. 24 In both cases, please inform
25 [clang@chromium.org](http://groups.google.com/a/chromium.org/group/clang/topics)
26 of your plans before you pursue them.
15 27
16 # Having said that 28 # Having said that
17 29
18 clang currently has minimal documentation on its plugin interface; it's mostly d oxygen annotations in the source. This is an attempt to be half map to the heade r files/half tutorial. 30 clang currently has minimal documentation on its plugin interface; it's mostly
31 doxygen annotations in the source. This is an attempt to be half map to the
32 header files/half tutorial.
19 33
20 # Building your plugin 34 # Building your plugin
21 35
22 ## Just copy the clang build system 36 ## Just copy the clang build system
23 37
24 I suggest you make a new dir in **llvm/tools/clang/examples/** and copy the Make file from `PrintFunctionNames` there. This way, you'll just leverage the existin g clang build system. You can then build your plugin with 38 I suggest you make a new dir in `llvm/tools/clang/examples/` and copy the
39 Makefile from `PrintFunctionNames` there. This way, you'll just leverage the
40 existing clang build system. You can then build your plugin with
25 41
26 ``` 42 make -C llvm/tools/clang/examples/myplugin
27 make -C llvm/tools/clang/examples/myplugin
28 ```
29 43
30 See ["Using plugins"](Clang.md) on how to use your plugin while building chromiu m with clang. 44 See [Using plugins](Clang.md) on how to use your plugin while building chromium
45 with clang.
31 46
32 ## Use the interface in `tools/clang/plugins/ChromeClassTester.h` 47 ## Use the interface in tools/clang/plugins/ChromeClassTester.h
33 48
34 Here's a canned interface that filters code, only passing class definitions in n on-blacklisted headers. The users of `ChromeClassTester` are good code to study to see what you can do. 49 Here's a canned interface that filters code, only passing class definitions in
50 non-blacklisted headers. The users of `ChromeClassTester` are good code to study
51 to see what you can do.
35 52
36 ## Or if you're doing something really different, just copy `PrintFunctionNames. cpp` 53 ## Or if you're doing something really different, copy PrintFunctionNames.cpp
37 54
38 `PrintFunctionNames.cpp` is a plugin in the clang distribution. It is the Hello World of plugins. As a most basic skeleton, it's a good starting point. Change a ll the identifiers that start with `PrintFunction` to your desired name. Take no te of the final line: 55 `PrintFunctionNames.cpp` is a plugin in the clang distribution. It is the Hello
56 World of plugins. As a most basic skeleton, it's a good starting point. Change
57 all the identifiers that start with `PrintFunction` to your desired name. Take
58 note of the final line:
39 59
40 ``` 60 ```cpp
41 static FrontendPluginRegistry::Add<PrintFunctionNamesAction> 61 static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
42 X("print-fns", "print function names"); 62 X("print-fns", "print function names");
43 ``` 63 ```
44 64
45 This registers your PluginASTAction with a string plugin name that can be invoke d on the command line. Note that everything else is in an anonymous namespace; a ll other symbols aren't exported. 65 This registers your `PluginASTAction` with a string plugin name that can be
66 invoked on the command line. Note that everything else is in an anonymous
67 namespace; all other symbols aren't exported.
46 68
47 Your `PluginASTAction` subclass exists just to build your ASTConsumer, which rec eives declarations, sort of like a SAX parser. 69 Your `PluginASTAction` subclass exists just to build your `ASTConsumer`, which
70 receives declarations, sort of like a SAX parser.
48 71
49 ## Your ASTConsumer 72 ## Your ASTConsumer
50 73
51 There is doxygen documentation on when each `ASTConsumer::Handle` method is call ed in **llvm/tools/clang/include/clang/AST/ASTConsumer.h**. For this tutorial, I 'll assume you only want to look at type definitions (struct, class, enum defini tions), so we'll start with: 74 There is doxygen documentation on when each `ASTConsumer::Handle` method is
75 called in `llvm/tools/clang/include/clang/AST/ASTConsumer.h`. For this
76 tutorial, I'll assume you only want to look at type definitions (struct, class,
77 enum definitions), so we'll start with:
52 78
53 ``` 79 ```cpp
54 class TagConsumer : public ASTConsumer { 80 class TagConsumer : public ASTConsumer {
55 public: 81 public:
56 virtual void HandleTagDeclDefinition(TagDecl *D) { 82 virtual void HandleTagDeclDefinition(TagDecl *D) {
57 } 83 }
58 }; 84 };
59
60 ``` 85 ```
61 86
62 The data type passed in is the `Decl`, which is a giant class hierarchy spanning the following files: 87 The data type passed in is the `Decl`, which is a giant class hierarchy spanning
88 the following files:
63 89
64 * `llvm/tools/clang/include/clang/AST/DeclBase.h`: declares the `Decl` class, along with some utility classes you won't use. 90 * `llvm/tools/clang/include/clang/AST/DeclBase.h`: declares the `Decl` class,
65 * `llvm/tools/clang/include/clang/AST/Decl.h`: declares subclasses of `Decl`, for example, `FunctionDecl` (a function declaration), `TagDecl` (the base class for struct/class/enum/etc), `TypedefDecl`, etc. 91 along with some utility classes you won't use.
66 * `llvm/tools/clang/include/clang/AST/DeclCXX.h`: C++ specific types. You'll f ind most Decl subclasses dealing with templates here, along with things like `Us ingDirectiveDecl`, `CXXConstructorDecl`, etc. 92 * `llvm/tools/clang/include/clang/AST/Decl.h`: declares subclasses of `Decl`,
93 for example, `FunctionDecl` (a function declaration), `TagDecl` (the base cl ass for struct/class/enum/etc), `TypedefDecl`, etc.
94 * `llvm/tools/clang/include/clang/AST/DeclCXX.h`: C++ specific types.
95 You'll find most Decl subclasses dealing with templates here,
96 along with things like `UsingDirectiveDecl`, `CXXConstructorDecl`, etc.
67 97
68 The interface on these classes is massive; We'll only cover some of the basics, but some basics about source location and errors. 98 The interface on these classes is massive; We'll only cover some of the basics,
99 but some basics about source location and errors.
69 100
70 ## Emitting Errors 101 ## Emitting Errors
71 102
72 Lots of location information is stored in the `Decl` tree. Most `Decl` subclasse s have multiple methods that return a `SourceLocation`, but lets use `TagDecl::g etInnerLocStart()` as an example. (`SourceLocation` is defined in `llvm/tools/cl ang/include/clang/Basic/SourceLocation.h`, for reference.) 103 Lots of location information is stored in the `Decl` tree. Most `Decl`
104 subclasses have multiple methods that return a `SourceLocation`, but lets use
105 `TagDecl::getInnerLocStart()` as an example. (`SourceLocation` is defined in
106 `llvm/tools/clang/include/clang/Basic/SourceLocation.h`, for reference.)
73 107
74 Errors are emitted to the user through the `CompilerInstance`. You will probably want to pass the `CompilerInstance` object passed to `ASTAction::CreateASTConsu mer` to your ASTConsumer subclass for reporting. You interact with the user thro ugh the `Diagnostic` object. You could report errors to the user like this: 108 Errors are emitted to the user through the `CompilerInstance`. You will probably want to pass the `CompilerInstance` object passed to `ASTAction::CreateASTConsu mer` to your ASTConsumer subclass for reporting. You interact with the user thro ugh the `Diagnostic` object. You could report errors to the user like this:
75 109
76 ``` 110 ```cpp
77 void emitWarning(CompilerInstance& instance, SourceLocation loc, const char* err or) { 111 void emitWarning(CompilerInstance& instance, SourceLocation loc, const char* err or) {
78 FullSourceLoc full(loc, instance.getSourceManager()); 112 FullSourceLoc full(loc, instance.getSourceManager());
79 unsigned id = instance.getCustomDiagID(Diagnostic::Warning, error); 113 unsigned id = instance.getCustomDiagID(Diagnostic::Warning, error);
80 DiagnosticBuilder B = instance.getDiagnostics().Report(full, id); 114 DiagnosticBuilder B = instance.getDiagnostics().Report(full, id);
81 } 115 }
82 ``` 116 ```
83 117
84 (The above is the simplest error reporting. See **llvm/tools/clang/include/clang /Basic/Diagnostic.h** for all the things you can do, like `FixItHint`s if you wa nt to get fancy!) 118 (The above is the simplest error reporting. See
119 `llvm/tools/clang/include/clang/Basic/Diagnostic.h` for all the things you can
120 do, like `FixItHint`s if you want to get fancy!)
85 121
86 ## Downcast early, Downcast often 122 ## Downcast early, Downcast often
87 123
88 The clang library will give you the most general types possible. For example `Ta gDecl` has comparably minimal interface. The library is designed so you will be downcasting all the time, and you won't use the standard `dynamic_cast<>()` buil tin to do it. Instead, you'll use llvm/clang's home built RTTI system: 124 The clang library will give you the most general types possible. For example
125 `TagDecl` has comparably minimal interface. The library is designed so you will
126 be downcasting all the time, and you won't use the standard `dynamic_cast<>()`
127 builtin to do it. Instead, you'll use llvm/clang's home built RTTI system:
89 128
90 ``` 129 ```cpp
91 virtual void HandleTagDeclDefinition(TagDecl* tag) { 130 virtual void HandleTagDeclDefinition(TagDecl* tag) {
92 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) { 131 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
93 // Do stuff with |record|. 132 // Do stuff with |record|.
94 } 133 }
95 } 134 }
96 ``` 135 ```
97 136
98 ## A (not at all exhaustive) list of things you can do with `(CXX)RecordDecl` 137 ## A (not at all exhaustive) list of things you can do with (CXX)RecordDecl
99 138
100 * Iterate across all constructors (`CXXRecordDecl::ctor_begin()`, `CXXReocrdDe cl::ctor_end()`) 139 * Iterate across all constructors (`CXXRecordDecl::ctor_begin()`,
101 * `CXXRecordDecl::isPOD()`: is this a Plain Old Datatype (a type that has no c onstruction or destruction semantics)? 140 `CXXReocrdDecl::ctor_end()`)
102 * Check if certain properties of the class: `CXXRecordDecl::isAbstract()`, `CX XRecordDecl::hasTrivialConstructor()`, `CXXRecordDecl::hasTrivialDestructor()`, etc. 141 * `CXXRecordDecl::isPOD()`: is this a Plain Old Datatype (a type that has no
103 * Iterate across all fields/member variables (`RecordDecl::field_begin()`, `Re cordDecl::field_end()`) 142 construction or destruction semantics)?
104 * Iterate across all of the base classes of a record type (`CXXRecordDecl::bas es_begin()`, `CXXRecordDecl::bases_end()`) 143 * Check if certain properties of the class: `CXXRecordDecl::isAbstract()`,
105 * Get the simple string name `NamedDecl::getNameAsString()`. (This method is d eprecated, but the replacement assert()s on error conditions). (If you had `stru ct One {}`, this method would return "One".) 144 `CXXRecordDecl::hasTrivialConstructor()`,
145 `CXXRecordDecl::hasTrivialDestructor()`, etc.
146 * Iterate across all fields/member variables (`RecordDecl::field_begin()`,
147 `RecordDecl::field_end()`)
148 * Iterate across all of the base classes of a record type
149 (`CXXRecordDecl::bases_begin()`, `CXXRecordDecl::bases_end()`)
150 * Get the simple string name `NamedDecl::getNameAsString()`. (This method is
151 deprecated, but the replacement assert()s on error conditions). (If you had
152 `struct One {}`, this method would return "One".)
106 153
107 ## Modifying existing plugins 154 ## Modifying existing plugins
108 155
109 If you want to add additional checks to the existing plugins, be sure to add the new diagnostic behind a flag (there are several examples of this in the plugins already). The reason for this is that the plugin is bundled with clang, and the new check will get deployed with the next clang roll. If your check fires, then the next clang roll would now be blocked on cleaning up the whole codebase for your check – and even if the check doesn't fire at the moment, maybe that regres ses until the next clang roll happens. If your new check is behind a flag, then the clang roll can happen first, and you can add the flag to enable your check a fter that, and then turn on the check everywhere once you know that the codebase is clean. 156 If you want to add additional checks to the existing plugins, be sure to add the
157 new diagnostic behind a flag (there are several examples of this in the plugins
158 already). The reason for this is that the plugin is bundled with clang, and the
159 new check will get deployed with the next clang roll. If your check fires, then
160 the next clang roll would now be blocked on cleaning up the whole codebase for
161 your check – and even if the check doesn't fire at the moment, maybe that
162 regresses until the next clang roll happens. If your new check is behind a flag,
163 then the clang roll can happen first, and you can add the flag to enable your
164 check after that, and then turn on the check everywhere once you know that the
165 codebase is clean.
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