If a virtual method is marked as call_super, the
override method must call it, simpler feature like @CallSuper
in Android Java.
Details
- Reviewers
aaron.ballman erichkeane john.brawn
Diff Detail
- Repository
- rG LLVM Github Monorepo
Unit Tests
Event Timeline
clang/test/Frontend/plugin-call-super.cpp | ||
---|---|---|
8 | If I remove the keyword "virtual" here, the isVirtual() will return false. To my knowledge "final" means this method cannot be overridden, but it is still a virtual method, right? |
clang/docs/ClangPlugins.rst | ||
---|---|---|
117 ↗ | (On Diff #303772) | The number of underlines here looks off -- can you verify it's correct? |
119 ↗ | (On Diff #303772) | Should add backticks around call_super since it's syntax. Also, sub-classes should be subclasses. "call it in overridden the method" -> "call it in the overridden method" |
119 ↗ | (On Diff #303772) | There should be more explanation here about what concepts the example demonstrates. For example, one interesting bit to me is that it shows how you can add a custom attribute that's useful even if it does not generate an AST node for the attribute. |
clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp | ||
26 | Comments should be grammatical including starting with a capital letter and trailing punctuation. (Should be corrected elsewhere in the patch as well.) | |
33 | Is the functionality for getting names out of a NamedDecl insufficient? | |
44 | ctor should probably be explicit | |
44 | Can drop clang:: prefixed everywhere since you have a using declaration at the top of the file. | |
64 | Should put single quotes around call_super as it's a syntactic element. I'm not certain that %0 and %1 are necessary because the overridden methods will have the same names. I think you can drop the %1 and rely on the note to point out where the overridden method lives. | |
67 | Single quotes around call_super here as well; we usually phrase this sort of thing as "overridden method marked 'call_super' here | |
74 | Single quotes around call_super and we should use consistent terminology for "attached" vs "marked". | |
77 | Won't this visit every method declaration multiple times? Once for the declaration itself (as we encounter it) and once for each time it's listed as an overridden method? | |
81 | We typically elide the braces for single-line substatements. | |
91 | FWIW, you can pass Overridden and MethodDecl in directly rather than trying to scrape the name out yourself -- the diagnostics engine knows how to properly turn a NamedDecl into a string for diagnostics. | |
136 | For the C++11 spelling, it should be in the clang attribute namespace rather than the standard attribute namespace. | |
151 | Single quotes around the attribute name. | |
191 | Can you add a newline to the end of the file? | |
clang/test/Frontend/plugin-call-super.cpp | ||
8 | Only virtual functions can be marked final, so yes, it's still a virtual function. isVirtual() tells you whether the user wrote virtual themselves, but I'm not certain why isVirtual() would return false there -- the function overrides a method, so I would have expected this to return true: https://github.com/llvm/llvm-project/blob/master/clang/include/clang/AST/DeclCXX.h#L2023 |
clang/docs/ClangPlugins.rst | ||
---|---|---|
119 ↗ | (On Diff #303772) | "how you can add a custom attribute that's useful even if it does not generate an AST node for the attribute", do you mean I should add an Annotation Attribute object even I don't use it? So that when someone dumps the AST, the call_super attribute will show? Or do you mean to explain the inner implementation of how could the RecursiveASTVisitor knows the declaration is marked as call_super, even if I didn't add any extra attribute nodes to this declaration node? |
clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp | ||
33 | fullName() here is used to get a string which format is "class_name::method_name", I think NamedDecl::getName or NamedDecl::getNameAsString only gets the method name, without the class name. Or is there an easy way to accomplish this? | |
64 | About the '%0' and '%1' problem, same as the comment about "fullName()" function, since the overridden methods have the same name, I want use "class_name::method_name" to distinguish between these methods to make users clear. It would very nice if you could help to come up with a decent warning message which is better than this, I tried some but none of them give a compiler-warning-style feeling... | |
91 | Same problem, a decent warning message is welcome, I don't like this scrape-name-thing either. |
clang/docs/ClangPlugins.rst | ||
---|---|---|
119 ↗ | (On Diff #303772) | I got you point, please ignore the comment above. Since this is an example, I should mention more about this example itself rather than how to use this plugin, right? |
Add more details in ClangPlugins.rst.
Re-design overridden usage checking.
Fix some code style issues.
clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp | ||
---|---|---|
134 | AddAfterMainAction will get run after IR codes were generated, I found this when writing test cases, so it would be better to use AddBeforeMainAction |
I have more review to do on this but have to run for a while and wanted to get you this feedback sooner rather than later.
clang/docs/ClangPlugins.rst | ||
---|---|---|
119 ↗ | (On Diff #304129) | Sorry, I was unclear, it should be *double* backticks around syntax elements like call_super, not single backticks. |
122–123 ↗ | (On Diff #304129) | Slight tweaking for grammar: This example shows that attribute plugins combined with PluginASTAction in Clang can do some of the same things which Java Annotations do. (with double backticks around PluginASTAction) |
125 ↗ | (On Diff #304129) | Slight tweaking for grammar: Unlike the other attribute plugin examples, this one does not attach an attribute AST node to the declaration AST node. Instead, it keeps a separate list of attributed declarations, which may be faster than using Decl::getAttr<T>() in some cases. The disadvantage of this approach is that the attribute is not part of the AST, which means that dumping the AST will lose the attribute information, pretty printing the AST won't write the attribute back out to source, and AST matchers will not be able to match against the attribute on the declaration. (with double backticks around Decl::getAttr<T>()) |
117 ↗ | (On Diff #303772) | This still appears to be incorrect and will cause build errors for the documentation. |
119 ↗ | (On Diff #303772) |
Exactly! |
clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp | ||
64 |
How about: virtual function %q0 is marked as 'call_super' but this overriding method does not call the base version and "function marked 'call_super' here" | |
91 | You can use %q0 to specify that you want a qualified name printed, I believe, which should do what you want with the function name. |
clang/docs/ClangPlugins.rst | ||
---|---|---|
117 ↗ | (On Diff #303772) | Do you mean that there's a command to build the documentation and currently my patch will cause a failure on it? I thought this ClangPlugins.rst is only an documentation with markdown, but seems that it's not what I thought? Currently I will make sure there's no build error on the plugin itself and the regression test case, and make sure the |
I just enabled LLVM_ENABLE_DOXYGEN LLVM_BUILD_DOCS, and use make doxygen-clang, it seems no error with my newest patch, is this
This still appears to be incorrect and will cause build errors for the documentation.
use the same way?
clang/docs/ClangPlugins.rst | ||
---|---|---|
117 ↗ | (On Diff #303772) |
Yes, we have a bot that builds docs: http://lab.llvm.org:8011/#/builders/92
It is a documentation file with markdown, but the markdown bots will complain if a markdown file cannot be built (they treat markdown warnings as errors).
Most of the time that's enough because the markdown usage is pretty trivial and can be inspected by sight for obvious issues (so people don't typically have to set up their build environments to generate documentation and test it with every patch). In this case, the issue is with the underlines under the title. The number of underlines needs to match the number of characters in the title, but in this case there are 20 = characters but 23 title characters. |
clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp | ||
10–11 | How about: This Clang plugin checks that overrides of the marked virtual function directly call the marked function. | |
81 | supper is used -> the superclass method is called | |
85 | are not get called, warning -> are not called, warn | |
153 | Instead of methods, how about virtual functions? Then the logic can be: if (!TheMethod || !TheMethod->isVirtual()) and you can remove the diagnostic below. | |
167–169 | attr is added) save the address of the Decl in sets -> .attr is added). Save the address of the Decl in a set | |
clang/test/Frontend/plugin-call-super.cpp | ||
2–3 | The way we would typically test something like this is to pass -fsyntax-only and -verify to verify the diagnostics rather than using FileCheck, because the plugin doesn't have any impact on code generation (just diagnostics). This makes the test faster to check (and is a bit easier than using FileCheck). |
clang/docs/ClangPlugins.rst | ||
---|---|---|
117 ↗ | (On Diff #303772) | It seems that only a committee member can trigger this bot, any way I can test on my own environment? So that I can make sure the doc will compile successfully before uploading patches? As I mentioned before, using make doxygen-clang will succeed even the = characters are not match with title characters, so it seems that the bot doesn't use this way. |
clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp | ||
70 | Call lateDiagAppertainsToDecl in every VisitCXXMethodDecl functions is not very efficiency, since marked methods are already saved. | |
105 | Move the lateDiagAppertainsToDecl() here and only check marked functions. |
clang/docs/ClangPlugins.rst | ||
---|---|---|
117 ↗ | (On Diff #303772) | You can test in your own environment (if a build bot can do it, so can anyone else). I don't typically build docs locally so my instructions are untested, but I think you need to set the following cmake variables: LLVM_BUILD_DOCS=YES ' enables building docs LLVM_ENABLE_SPHINX=YES ' enable building sphinx docs (.rst files) You also have to have Sphinx installed (you can do this using pip install -U Sphinx) and on the PATH before you configure cmake for Clang. Doxygen is a different documentation format than Sphinx. Doxygen handles building the docs from comments in the source files. Sphinx is what turns these .rst files into HTML. If you enable Sphinx builds from cmake there should be a target added that lets you build those docs. |
clang/test/Frontend/plugin-call-super.cpp | ||
6 | Hmm, this seems wrong to me -- we do expect diagnostics from this file. | |
19–20 | These warnings and notes (and the warning a few lines up) are ones I would have expected to catch using // expected-warning {{virtual function 'Base2::Test' is marked as 'call_super' but this overriding method does not call the base version}} style checks instead of needing to use FileCheck. Do plugin-based diagnostics not get caught by -verify? I expect this test file to fail as currently written because of the expected-no-diagnostics, but I've not done a whole lot of testing of plugins before. |
use VerifyDiagnosticConsumer (-verify) instead of FileCheck for syntax only feature test.
remove illustration in ClangPlugins.rst (which is not very appropriate)
clang/docs/ClangPlugins.rst | ||
---|---|---|
116 ↗ | (On Diff #305405) | After a whole day's research of Sphinx, I figured out that ClangPlugins.rst is the "proto-type" of https://clang.llvm.org/docs/ClangPlugins.html, which is the document on how to use Clang plugin features. This leads that my change in ClangPlugins.rst are not very appropriate, sort of off-topic. Sorry I don't notice the rest of the file, and misunderstood it as a documents for examples. I decide to move the illustration to the source code. |
clang/test/Frontend/plugin-call-super.cpp | ||
---|---|---|
19–20 | -verify works well with plugins, I just tested, thanks for pointing out this elegant test way for syntax only features. |
clang/docs/ClangPlugins.rst | ||
---|---|---|
116 ↗ | (On Diff #305405) | You're correct that the .rst file is the prototype for the public HTML documentation, sorry for not making that more clear sooner. I think it's fine to have the documentation either in the header file (as you've switched to) or within this file (since it is showing a slightly different way to define a plugin-based attribute). |
clang/test/Frontend/plugin-call-super.cpp | ||
6 | Rather than duplicating the test logic like this, you can pass a custom prefix to -verify that gets used when checking the expected results. e.g., // RUN: %clang ... -verify=callsuper ... // RUN: %clang ... -verify=nocallsuper -DBAD_CALLSUPER ... // callsuper-no-diagnostics ... void Derive::Test() { // nocallsuper-expected-warning {{virtual function ... }} Base1::Test(); #ifndef BAD_CALLSUPER Base2::Test(); #endif } |
LGTM, thank you for the new plugin example! Do you need me to commit on your behalf? If so, are you okay with Yafei Liu <psionic12@outlook.com> for attribution?
@aaron.ballman That would be nice if your could help, and Yafei Liu <psionic12@outlook.com> is okay.
Thank you for the new example, I've commit on your behalf in 2ce6352e46344d97fed6a3ca6de7228345956191
How about: This Clang plugin checks that overrides of the marked virtual function directly call the marked function.