blob: b8a65f6d50efd615d51605d50274ab368d7f7452 [file] [log] [blame] [view]
andybons3322f762015-08-24 21:37:091# Don't write a clang plugin
2
nodire7e901b02015-08-25 15:30:113[TOC]
4
5TODO: although cs.chromium.org
6[finds](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/llvm/)
7`src/third_party/llvm`, it
8[does not exist in Gitiles](https://chromium.googlesource.com/src/third_party/llvm/).
9
andybons3322f762015-08-24 21:37:0910Make sure you really want to write a clang plugin.
11
nodire7e901b02015-08-25 15:30:1112* The clang plugin api is not stable. If you write a plugin, _you_ are
13 responsible for making sure it's updated when we update clang.
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).
andybons3322f762015-08-24 21:37:0918
19Valid reasons for writing a plugin are for example:
20
nodire7e901b02015-08-25 15:30:1121* You want to add a chromium-specific error message.
22* You want to write an automatic code rewriter.
andybons3322f762015-08-24 21:37:0923
nodire7e901b02015-08-25 15:30:1124In both cases, please inform
25[clang@chromium.org](http://groups.google.com/a/chromium.org/group/clang/topics)
26of your plans before you pursue them.
andybons3322f762015-08-24 21:37:0927
28# Having said that
29
nodire7e901b02015-08-25 15:30:1130clang currently has minimal documentation on its plugin interface; it's mostly
31doxygen annotations in the source. This is an attempt to be half map to the
32header files/half tutorial.
andybons3322f762015-08-24 21:37:0933
34# Building your plugin
35
36## Just copy the clang build system
37
nodire7e901b02015-08-25 15:30:1138I suggest you make a new dir in `llvm/tools/clang/examples/` and copy the
39Makefile from `PrintFunctionNames` there. This way, you'll just leverage the
40existing clang build system. You can then build your plugin with
andybons3322f762015-08-24 21:37:0941
nodire7e901b02015-08-25 15:30:1142 make -C llvm/tools/clang/examples/myplugin
andybons3322f762015-08-24 21:37:0943
nodire7e901b02015-08-25 15:30:1144See [Using plugins](clang.md) on how to use your plugin while building chromium
45with clang.
andybons3322f762015-08-24 21:37:0946
nodire7e901b02015-08-25 15:30:1147## Use the interface in tools/clang/plugins/ChromeClassTester.h
andybons3322f762015-08-24 21:37:0948
nodire7e901b02015-08-25 15:30:1149Here's a canned interface that filters code, only passing class definitions in
50non-blacklisted headers. The users of `ChromeClassTester` are good code to study
51to see what you can do.
andybons3322f762015-08-24 21:37:0952
nodire7e901b02015-08-25 15:30:1153## Or if you're doing something really different, copy PrintFunctionNames.cpp
andybons3322f762015-08-24 21:37:0954
nodire7e901b02015-08-25 15:30:1155`PrintFunctionNames.cpp` is a plugin in the clang distribution. It is the Hello
56World of plugins. As a most basic skeleton, it's a good starting point. Change
57all the identifiers that start with `PrintFunction` to your desired name. Take
58note of the final line:
andybons3322f762015-08-24 21:37:0959
nodire7e901b02015-08-25 15:30:1160```cpp
andybons3322f762015-08-24 21:37:0961static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
62X("print-fns", "print function names");
63```
64
nodire7e901b02015-08-25 15:30:1165This registers your `PluginASTAction` with a string plugin name that can be
66invoked on the command line. Note that everything else is in an anonymous
67namespace; all other symbols aren't exported.
andybons3322f762015-08-24 21:37:0968
nodire7e901b02015-08-25 15:30:1169Your `PluginASTAction` subclass exists just to build your `ASTConsumer`, which
70receives declarations, sort of like a SAX parser.
andybons3322f762015-08-24 21:37:0971
72## Your ASTConsumer
73
nodire7e901b02015-08-25 15:30:1174There is doxygen documentation on when each `ASTConsumer::Handle` method is
75called in `llvm/tools/clang/include/clang/AST/ASTConsumer.h`. For this
76tutorial, I'll assume you only want to look at type definitions (struct, class,
77enum definitions), so we'll start with:
andybons3322f762015-08-24 21:37:0978
nodire7e901b02015-08-25 15:30:1179```cpp
andybons3322f762015-08-24 21:37:0980class TagConsumer : public ASTConsumer {
nodire7e901b02015-08-25 15:30:1181 public:
82 virtual void HandleTagDeclDefinition(TagDecl *D) {
83 }
andybons3322f762015-08-24 21:37:0984};
andybons3322f762015-08-24 21:37:0985```
86
nodire7e901b02015-08-25 15:30:1187The data type passed in is the `Decl`, which is a giant class hierarchy spanning
88the following files:
andybons3322f762015-08-24 21:37:0989
nodire7e901b02015-08-25 15:30:1190* `llvm/tools/clang/include/clang/AST/DeclBase.h`: declares the `Decl` class,
91 along with some utility classes you won't use.
92* `llvm/tools/clang/include/clang/AST/Decl.h`: declares subclasses of `Decl`,
93 for example, `FunctionDecl` (a function declaration), `TagDecl` (the base class 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.
andybons3322f762015-08-24 21:37:0997
nodire7e901b02015-08-25 15:30:1198The interface on these classes is massive; We'll only cover some of the basics,
99but some basics about source location and errors.
andybons3322f762015-08-24 21:37:09100
101## Emitting Errors
102
nodire7e901b02015-08-25 15:30:11103Lots of location information is stored in the `Decl` tree. Most `Decl`
104subclasses 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.)
andybons3322f762015-08-24 21:37:09107
108Errors are emitted to the user through the `CompilerInstance`. You will probably want to pass the `CompilerInstance` object passed to `ASTAction::CreateASTConsumer` to your ASTConsumer subclass for reporting. You interact with the user through the `Diagnostic` object. You could report errors to the user like this:
109
nodire7e901b02015-08-25 15:30:11110```cpp
andybons3322f762015-08-24 21:37:09111void emitWarning(CompilerInstance& instance, SourceLocation loc, const char* error) {
112 FullSourceLoc full(loc, instance.getSourceManager());
113 unsigned id = instance.getCustomDiagID(Diagnostic::Warning, error);
114 DiagnosticBuilder B = instance.getDiagnostics().Report(full, id);
115}
116```
117
nodire7e901b02015-08-25 15:30:11118(The above is the simplest error reporting. See
119`llvm/tools/clang/include/clang/Basic/Diagnostic.h` for all the things you can
120do, like `FixItHint`s if you want to get fancy!)
andybons3322f762015-08-24 21:37:09121
122## Downcast early, Downcast often
123
nodire7e901b02015-08-25 15:30:11124The 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
126be downcasting all the time, and you won't use the standard `dynamic_cast<>()`
127builtin to do it. Instead, you'll use llvm/clang's home built RTTI system:
andybons3322f762015-08-24 21:37:09128
nodire7e901b02015-08-25 15:30:11129```cpp
andybons3322f762015-08-24 21:37:09130 virtual void HandleTagDeclDefinition(TagDecl* tag) {
131 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
132 // Do stuff with |record|.
133 }
134 }
135```
136
nodire7e901b02015-08-25 15:30:11137## A (not at all exhaustive) list of things you can do with (CXX)RecordDecl
andybons3322f762015-08-24 21:37:09138
nodire7e901b02015-08-25 15:30:11139* Iterate across all constructors (`CXXRecordDecl::ctor_begin()`,
140 `CXXReocrdDecl::ctor_end()`)
141* `CXXRecordDecl::isPOD()`: is this a Plain Old Datatype (a type that has no
142 construction or destruction semantics)?
143* Check if certain properties of the class: `CXXRecordDecl::isAbstract()`,
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".)
andybons3322f762015-08-24 21:37:09153
154## Modifying existing plugins
155
nodire7e901b02015-08-25 15:30:11156If you want to add additional checks to the existing plugins, be sure to add the
157new diagnostic behind a flag (there are several examples of this in the plugins
158already). The reason for this is that the plugin is bundled with clang, and the
159new check will get deployed with the next clang roll. If your check fires, then
160the next clang roll would now be blocked on cleaning up the whole codebase for
161your check – and even if the check doesn't fire at the moment, maybe that
162regresses until the next clang roll happens. If your new check is behind a flag,
163then the clang roll can happen first, and you can add the flag to enable your
164check after that, and then turn on the check everywhere once you know that the
165codebase is clean.