blob: 555cb2e0fdd92e76cf13c073d5a96c87848e953b [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
andybons3322f762015-08-24 21:37:095Make sure you really want to write a clang plugin.
6
nodire7e901b02015-08-25 15:30:117* The clang plugin api is not stable. If you write a plugin, _you_ are
8 responsible for making sure it's updated when we update clang.
9* If you're adding a generally useful warning, it should be added to upstream
10 clang, not to a plugin.
11* You should not use a clang plugin to do things that can be done in a
12 PRESUBMIT check (e.g. checking that the headers in a file are sorted).
andybons3322f762015-08-24 21:37:0913
14Valid reasons for writing a plugin are for example:
15
nodire7e901b02015-08-25 15:30:1116* You want to add a chromium-specific error message.
17* You want to write an automatic code rewriter.
andybons3322f762015-08-24 21:37:0918
nodire7e901b02015-08-25 15:30:1119In both cases, please inform
xiaoyin.l1003c0b2016-12-06 02:51:1720[clang@chromium.org](https://groups.google.com/a/chromium.org/group/clang/topics)
nodire7e901b02015-08-25 15:30:1121of your plans before you pursue them.
andybons3322f762015-08-24 21:37:0922
23# Having said that
24
nodire7e901b02015-08-25 15:30:1125clang currently has minimal documentation on its plugin interface; it's mostly
26doxygen annotations in the source. This is an attempt to be half map to the
27header files/half tutorial.
andybons3322f762015-08-24 21:37:0928
29# Building your plugin
30
31## Just copy the clang build system
32
Asami Doib6bc93e2f2025-05-06 10:03:4733I suggest you make a new dir in `llvm-project/clang/examples/` and copy the
nodire7e901b02015-08-25 15:30:1134Makefile from `PrintFunctionNames` there. This way, you'll just leverage the
35existing clang build system. You can then build your plugin with
andybons3322f762015-08-24 21:37:0936
Asami Doib6bc93e2f2025-05-06 10:03:4737 make -C llvm-project/clang/examples/myplugin
andybons3322f762015-08-24 21:37:0938
nodire7e901b02015-08-25 15:30:1139See [Using plugins](clang.md) on how to use your plugin while building chromium
40with clang.
andybons3322f762015-08-24 21:37:0941
nodire7e901b02015-08-25 15:30:1142## Use the interface in tools/clang/plugins/ChromeClassTester.h
andybons3322f762015-08-24 21:37:0943
nodire7e901b02015-08-25 15:30:1144Here's a canned interface that filters code, only passing class definitions in
45non-blacklisted headers. The users of `ChromeClassTester` are good code to study
46to see what you can do.
andybons3322f762015-08-24 21:37:0947
nodire7e901b02015-08-25 15:30:1148## Or if you're doing something really different, copy PrintFunctionNames.cpp
andybons3322f762015-08-24 21:37:0949
nodire7e901b02015-08-25 15:30:1150`PrintFunctionNames.cpp` is a plugin in the clang distribution. It is the Hello
51World of plugins. As a most basic skeleton, it's a good starting point. Change
52all the identifiers that start with `PrintFunction` to your desired name. Take
53note of the final line:
andybons3322f762015-08-24 21:37:0954
nodire7e901b02015-08-25 15:30:1155```cpp
andybons3322f762015-08-24 21:37:0956static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
57X("print-fns", "print function names");
58```
59
nodire7e901b02015-08-25 15:30:1160This registers your `PluginASTAction` with a string plugin name that can be
61invoked on the command line. Note that everything else is in an anonymous
62namespace; all other symbols aren't exported.
andybons3322f762015-08-24 21:37:0963
nodire7e901b02015-08-25 15:30:1164Your `PluginASTAction` subclass exists just to build your `ASTConsumer`, which
65receives declarations, sort of like a SAX parser.
andybons3322f762015-08-24 21:37:0966
67## Your ASTConsumer
68
nodire7e901b02015-08-25 15:30:1169There is doxygen documentation on when each `ASTConsumer::Handle` method is
Asami Doib6bc93e2f2025-05-06 10:03:4770called in `llvm-project/clang/include/clang/AST/ASTConsumer.h`. For this
nodire7e901b02015-08-25 15:30:1171tutorial, I'll assume you only want to look at type definitions (struct, class,
72enum definitions), so we'll start with:
andybons3322f762015-08-24 21:37:0973
nodire7e901b02015-08-25 15:30:1174```cpp
andybons3322f762015-08-24 21:37:0975class TagConsumer : public ASTConsumer {
nodire7e901b02015-08-25 15:30:1176 public:
77 virtual void HandleTagDeclDefinition(TagDecl *D) {
78 }
andybons3322f762015-08-24 21:37:0979};
andybons3322f762015-08-24 21:37:0980```
81
nodire7e901b02015-08-25 15:30:1182The data type passed in is the `Decl`, which is a giant class hierarchy spanning
83the following files:
andybons3322f762015-08-24 21:37:0984
Asami Doib6bc93e2f2025-05-06 10:03:4785* `llvm-project/clang/include/clang/AST/DeclBase.h`: declares the `Decl`
86 class, along with some utility classes you won't use.
87* `llvm-project/clang/include/clang/AST/Decl.h`: declares subclasses of
88 `Decl`, for example, `FunctionDecl` (a function declaration), `TagDecl` (the
89 base class for struct/class/enum/etc), `TypedefDecl`, etc.
90* `llvm-project/clang/include/clang/AST/DeclCXX.h`: C++ specific types.
nodire7e901b02015-08-25 15:30:1191 You'll find most Decl subclasses dealing with templates here,
92 along with things like `UsingDirectiveDecl`, `CXXConstructorDecl`, etc.
andybons3322f762015-08-24 21:37:0993
nodire7e901b02015-08-25 15:30:1194The interface on these classes is massive; We'll only cover some of the basics,
95but some basics about source location and errors.
andybons3322f762015-08-24 21:37:0996
97## Emitting Errors
98
nodire7e901b02015-08-25 15:30:1199Lots of location information is stored in the `Decl` tree. Most `Decl`
100subclasses have multiple methods that return a `SourceLocation`, but lets use
101`TagDecl::getInnerLocStart()` as an example. (`SourceLocation` is defined in
Asami Doib6bc93e2f2025-05-06 10:03:47102`llvm-project/clang/include/clang/Basic/SourceLocation.h`, for reference.)
andybons3322f762015-08-24 21:37:09103
Asami Doib6bc93e2f2025-05-06 10:03:47104Errors are emitted to the user through the `CompilerInstance`. You will probably
105want to pass the `CompilerInstance` object passed to
106`ASTAction::CreateASTConsumer` to your ASTConsumer subclass for reporting. You
107interact with the user through the `Diagnostic` object. You could report errors
108to the user like this:
andybons3322f762015-08-24 21:37:09109
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());
Asami Doib6bc93e2f2025-05-06 10:03:47113 unsigned id = instance.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Warning, error);
andybons3322f762015-08-24 21:37:09114 DiagnosticBuilder B = instance.getDiagnostics().Report(full, id);
115}
116```
117
nodire7e901b02015-08-25 15:30:11118(The above is the simplest error reporting. See
Asami Doib6bc93e2f2025-05-06 10:03:47119`llvm-project/clang/include/clang/Basic/Diagnostic.h` for all the things you can
nodire7e901b02015-08-25 15:30:11120do, 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<>()`
Asami Doib6bc93e2f2025-05-06 10:03:47127builtin to do it. Instead, you'll use llvm-project/clang's home built RTTI
128system:
andybons3322f762015-08-24 21:37:09129
nodire7e901b02015-08-25 15:30:11130```cpp
andybons3322f762015-08-24 21:37:09131 virtual void HandleTagDeclDefinition(TagDecl* tag) {
132 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
133 // Do stuff with |record|.
134 }
135 }
136```
137
nodire7e901b02015-08-25 15:30:11138## A (not at all exhaustive) list of things you can do with (CXX)RecordDecl
andybons3322f762015-08-24 21:37:09139
nodire7e901b02015-08-25 15:30:11140* Iterate across all constructors (`CXXRecordDecl::ctor_begin()`,
141 `CXXReocrdDecl::ctor_end()`)
142* `CXXRecordDecl::isPOD()`: is this a Plain Old Datatype (a type that has no
143 construction or destruction semantics)?
144* Check if certain properties of the class: `CXXRecordDecl::isAbstract()`,
145 `CXXRecordDecl::hasTrivialConstructor()`,
146 `CXXRecordDecl::hasTrivialDestructor()`, etc.
147* Iterate across all fields/member variables (`RecordDecl::field_begin()`,
148 `RecordDecl::field_end()`)
149* Iterate across all of the base classes of a record type
150 (`CXXRecordDecl::bases_begin()`, `CXXRecordDecl::bases_end()`)
151* Get the simple string name `NamedDecl::getNameAsString()`. (This method is
152 deprecated, but the replacement assert()s on error conditions). (If you had
153 `struct One {}`, this method would return "One".)
andybons3322f762015-08-24 21:37:09154
155## Modifying existing plugins
156
nodire7e901b02015-08-25 15:30:11157If you want to add additional checks to the existing plugins, be sure to add the
158new diagnostic behind a flag (there are several examples of this in the plugins
159already). The reason for this is that the plugin is bundled with clang, and the
160new check will get deployed with the next clang roll. If your check fires, then
161the next clang roll would now be blocked on cleaning up the whole codebase for
162your check – and even if the check doesn't fire at the moment, maybe that
163regresses until the next clang roll happens. If your new check is behind a flag,
164then the clang roll can happen first, and you can add the flag to enable your
165check after that, and then turn on the check everywhere once you know that the
166codebase is clean.