Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /refs/heads/main /. /docs /writing_clang_plugins.md
blob: 555cb2e0fdd92e76cf13c073d5a96c87848e953b [file] [log] [blame] [view]
andybons3322f762015-08-24 21:37:09[diff] [blame]1# Don't write a clang plugin
2
nodire7e901b02015-08-25 15:30:11[diff] [blame]3[TOC]
4
andybons3322f762015-08-24 21:37:09[diff] [blame]5Make sure you really want to write a clang plugin.
6
nodire7e901b02015-08-25 15:30:11[diff] [blame]7*The clang plugin apiisnot stable.If you write a plugin, _you_ are
8 responsiblefor 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 shouldnotuse a clang plugin todo things that can bedonein a
12 PRESUBMIT check(e.g. checking that the headersin a file are sorted).
andybons3322f762015-08-24 21:37:09[diff] [blame]13
14Valid reasonsfor writing a plugin arefor example:
15
nodire7e901b02015-08-25 15:30:11[diff] [blame]16*You want to add a chromium-specific error message.
17*You want to write an automatic code rewriter.
andybons3322f762015-08-24 21:37:09[diff] [blame]18
nodire7e901b02015-08-25 15:30:11[diff] [blame]19In both cases, please inform
xiaoyin.l1003c0b2016-12-06 02:51:17[diff] [blame]20[clang@chromium.org](https://groups.google.com/a/chromium.org/group/clang/topics)
nodire7e901b02015-08-25 15:30:11[diff] [blame]21of your plans before you pursue them.
andybons3322f762015-08-24 21:37:09[diff] [blame]22
23# Having said that
24
nodire7e901b02015-08-25 15:30:11[diff] [blame]25clang currently has minimal documentation on its plugininterface; 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:09[diff] [blame]28
29# Building your plugin
30
31## Just copy the clang build system
32
Asami Doib6bc93e2f2025-05-06 10:03:47[diff] [blame]33I suggest you make a new dir in `llvm-project/clang/examples/` and copy the
nodire7e901b02015-08-25 15:30:11[diff] [blame]34Makefile from `PrintFunctionNames` there. This way, you'll just leverage the
35existing clang build system.You canthen build your pluginwith
andybons3322f762015-08-24 21:37:09[diff] [blame]36
Asami Doib6bc93e2f2025-05-06 10:03:47[diff] [blame]37 make-C llvm-project/clang/examples/myplugin
andybons3322f762015-08-24 21:37:09[diff] [blame]38
nodire7e901b02015-08-25 15:30:11[diff] [blame]39See[Using plugins](clang.md) on how touse your pluginwhile building chromium
40with clang.
andybons3322f762015-08-24 21:37:09[diff] [blame]41
nodire7e901b02015-08-25 15:30:11[diff] [blame]42## Use the interface in tools/clang/plugins/ChromeClassTester.h
andybons3322f762015-08-24 21:37:09[diff] [blame]43
nodire7e901b02015-08-25 15:30:11[diff] [blame]44Here'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:09[diff] [blame]47
nodire7e901b02015-08-25 15:30:11[diff] [blame]48## Or if you're doing something really different, copyPrintFunctionNames.cpp
andybons3322f762015-08-24 21:37:09[diff] [blame]49
nodire7e901b02015-08-25 15:30:11[diff] [blame]50`PrintFunctionNames.cpp`is a pluginin the clang distribution.Itis theHello
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:09[diff] [blame]54
nodire7e901b02015-08-25 15:30:11[diff] [blame]55```cpp
andybons3322f762015-08-24 21:37:09[diff] [blame]56static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
57X("print-fns", "print function names");
58```
59
nodire7e901b02015-08-25 15:30:11[diff] [blame]60This 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:09[diff] [blame]63
nodire7e901b02015-08-25 15:30:11[diff] [blame]64Your`PluginASTAction` subclass exists just to build your`ASTConsumer`, which
65receives declarations, sort of like a SAX parser.
andybons3322f762015-08-24 21:37:09[diff] [blame]66
67## Your ASTConsumer
68
nodire7e901b02015-08-25 15:30:11[diff] [blame]69Thereis doxygen documentation onwhen each`ASTConsumer::Handle` methodis
Asami Doib6bc93e2f2025-05-06 10:03:47[diff] [blame]70calledin`llvm-project/clang/include/clang/AST/ASTConsumer.h`.Forthis
nodire7e901b02015-08-25 15:30:11[diff] [blame]71tutorial, I'll assume you only want to look at type definitions (struct, class,
72enum definitions), so we'll startwith:
andybons3322f762015-08-24 21:37:09[diff] [blame]73
nodire7e901b02015-08-25 15:30:11[diff] [blame]74```cpp
andybons3322f762015-08-24 21:37:09[diff] [blame]75class TagConsumer : public ASTConsumer {
nodire7e901b02015-08-25 15:30:11[diff] [blame]76 public:
77 virtual void HandleTagDeclDefinition(TagDecl *D) {
78 }
andybons3322f762015-08-24 21:37:09[diff] [blame]79};
andybons3322f762015-08-24 21:37:09[diff] [blame]80```
81
nodire7e901b02015-08-25 15:30:11[diff] [blame]82The data type passedinis the`Decl`, whichis a giantclass hierarchy spanning
83the following files:
andybons3322f762015-08-24 21:37:09[diff] [blame]84
Asami Doib6bc93e2f2025-05-06 10:03:47[diff] [blame]85*`llvm-project/clang/include/clang/AST/DeclBase.h`: declares the`Decl`
86class, alongwith 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:11[diff] [blame]91 You'll find mostDecl subclasses dealingwith templates here,
92 alongwith things like`UsingDirectiveDecl`,`CXXConstructorDecl`, etc.
andybons3322f762015-08-24 21:37:09[diff] [blame]93
nodire7e901b02015-08-25 15:30:11[diff] [blame]94Theinterface on these classesis massive;We'll only cover some of the basics,
95but some basics about source location and errors.
andybons3322f762015-08-24 21:37:09[diff] [blame]96
97## Emitting Errors
98
nodire7e901b02015-08-25 15:30:11[diff] [blame]99Lots 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:47[diff] [blame]102`llvm-project/clang/include/clang/Basic/SourceLocation.h`, for reference.)
andybons3322f762015-08-24 21:37:09[diff] [blame]103
Asami Doib6bc93e2f2025-05-06 10:03:47[diff] [blame]104Errors 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:09[diff] [blame]109
nodire7e901b02015-08-25 15:30:11[diff] [blame]110```cpp
andybons3322f762015-08-24 21:37:09[diff] [blame]111void emitWarning(CompilerInstance& instance, SourceLocation loc, const char* error) {
112 FullSourceLoc full(loc, instance.getSourceManager());
Asami Doib6bc93e2f2025-05-06 10:03:47[diff] [blame]113 unsigned id = instance.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Warning, error);
andybons3322f762015-08-24 21:37:09[diff] [blame]114 DiagnosticBuilder B = instance.getDiagnostics().Report(full, id);
115}
116```
117
nodire7e901b02015-08-25 15:30:11[diff] [blame]118(The above is the simplest error reporting. See
Asami Doib6bc93e2f2025-05-06 10:03:47[diff] [blame]119`llvm-project/clang/include/clang/Basic/Diagnostic.h` for all the things you can
nodire7e901b02015-08-25 15:30:11[diff] [blame]120do, like `FixItHint`s if you want to get fancy!)
andybons3322f762015-08-24 21:37:09[diff] [blame]121
122## Downcast early, Downcast often
123
nodire7e901b02015-08-25 15:30:11[diff] [blame]124The 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'tuse the standard`dynamic_cast<>()`
Asami Doib6bc93e2f2025-05-06 10:03:47[diff] [blame]127builtin todo it.Instead, you'll use llvm-project/clang's home built RTTI
128system:
andybons3322f762015-08-24 21:37:09[diff] [blame]129
nodire7e901b02015-08-25 15:30:11[diff] [blame]130```cpp
andybons3322f762015-08-24 21:37:09[diff] [blame]131 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:11[diff] [blame]138## A (not at all exhaustive) list of things you can do with (CXX)RecordDecl
andybons3322f762015-08-24 21:37:09[diff] [blame]139
nodire7e901b02015-08-25 15:30:11[diff] [blame]140*Iterate across all constructors(`CXXRecordDecl::ctor_begin()`,
141`CXXReocrdDecl::ctor_end()`)
142*`CXXRecordDecl::isPOD()`:isthis aPlainOldDatatype(a type that hasno
143 constructionor destruction semantics)?
144*Checkif certain properties of theclass:`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 thebase classes of a record type
150(`CXXRecordDecl::bases_begin()`,`CXXRecordDecl::bases_end()`)
151*Get the simplestring name`NamedDecl::getNameAsString()`.(This methodis
152 deprecated, but the replacementassert()s on error conditions).(If you had
153`struct One {}`,this method wouldreturn"One".)
andybons3322f762015-08-24 21:37:09[diff] [blame]154
155## Modifying existing plugins
156
nodire7e901b02015-08-25 15:30:11[diff] [blame]157If you want to add additional checks to the existing plugins, be sure to add the
158new diagnostic behind a flag(there are several examples ofthisin the plugins
159already).The reasonforthisis that the pluginis bundledwith clang,and the
160new check willget deployedwith thenext clang roll.If your check fires,then
161thenext clang roll would now be blocked on cleaning up the whole codebasefor
162your check– and evenif 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.

[8]ページ先頭

©2009-2025 Movatter.jp