[PATCH] D102325: [clang-tidy] cppcoreguidelines-virtual-base-class-destructor: a new check
Aaron Ballman via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 2 06:47:07 PDT 2021
aaron.ballman added a comment.
Have you tried running this over any large C++ code bases to see how often the diagnostics trigger and whether there are false positives? If not, you should probably do so -- one concern I have is with a private virtual destructor; I could imagine people using that for a class that is intended to be created but not destroyed (like a singleton).
================
Comment at: clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp:99
+ CheckFactories.registerCheck<VirtualBaseClassDestructorCheck>(
+ "cppcoreguidelines-virtual-base-class-destructor");
}
----------------
I think this may be a bit confusing of a name for the check -- this suggests to me it's about virtual base classes and their destructors, but the check is really more about defining a destructor properly in a class used as a base class with a vtable. However, this check follows the enforcement from the rule rather than the rule wording itself -- it doesn't care whether the class is ever used as a base class or not, it only cares whether the class contains a virtual function. How about: `cppcoreguidelines-virtual-class-destructor`? (Probably worth it to rename the check at the same time to keep the public check name and the internal check implementation names consistent.)
================
Comment at: clang-tools-extra/clang-tidy/cppcoreguidelines/VirtualBaseClassDestructorCheck.cpp:28
+ cxxRecordDecl(
+ anyOf(isStruct(), isClass()),
+ anyOf(has(cxxMethodDecl(isVirtual())), InheritsVirtualMethod),
----------------
I believe you can remove this without changing the behavior -- unions can't have virtual member functions anyway.
================
Comment at: clang-tools-extra/clang-tidy/cppcoreguidelines/VirtualBaseClassDestructorCheck.cpp:80
+ Loc = StructOrClass.getEndLoc();
+ DestructorString.append("public:");
+ AppendLineBreak = true;
----------------
================
Comment at: clang-tools-extra/clang-tidy/cppcoreguidelines/VirtualBaseClassDestructorCheck.cpp:89-93
+ DestructorString.append("\n")
+ .append("virtual ~")
+ .append(StructOrClass.getName().str())
+ .append("() = default;")
+ .append(AppendLineBreak ? "\n" : "");
----------------
This should be using an `llvm::Twine` (https://llvm.org/docs/ProgrammersManual.html#the-twine-class).
================
Comment at: clang-tools-extra/clang-tidy/cppcoreguidelines/VirtualBaseClassDestructorCheck.cpp:117-121
+ std::string()
+ .append(Visibility)
+ .append(":\n")
+ .append(Visibility == "public" && !Destructor.isVirtual() ? "virtual "
+ : "");
----------------
This function should also be using a Twine for much of this -- basically, Twine helps you build up a string from various components (some `std::string`, some `StringRef`, some `const char *`, etc) in an efficient manner that only does memory allocation when needing the full string contents.
================
Comment at: clang-tools-extra/clang-tidy/cppcoreguidelines/VirtualBaseClassDestructorCheck.cpp:123-125
+ if (Visibility == "protected" && Destructor.isVirtualAsWritten()) {
+ OriginalDestructor = eraseKeyword(OriginalDestructor, "virtual ");
+ }
----------------
================
Comment at: clang-tools-extra/clang-tidy/cppcoreguidelines/VirtualBaseClassDestructorCheck.cpp:135-141
+ if (Destructor.isExplicitlyDefaulted()) {
+ EndLocation =
+ utils::lexer::findNextTerminator(Destructor.getEndLoc(), SM, LangOpts)
+ .getLocWithOffset(1);
+ } else {
+ EndLocation = Destructor.getEndLoc().getLocWithOffset(1);
+ }
----------------
================
Comment at: clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-virtual-base-class-destructor.rst:6-8
+Finds base classes and structs whose destructor is neither public and virtual
+nor protected and non-virtual. A base class's destructor should be specified in
+one of these ways to prevent undefined behaviour.
----------------
================
Comment at: clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-virtual-base-class-destructor.rst:24-50
+ struct Foo { // NOK, protected destructor should not be virtual
+ virtual void f();
+ protected:
+ virtual ~Foo(){};
+ };
+
+ class Bar { // NOK, public destructor should be virtual
----------------
There are a bunch of trailing semicolons in the example code that can be removed.
================
Comment at: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-virtual-base-class-destructor.cpp:6
+// CHECK-MESSAGES: :[[@LINE+2]]:8: note: make it protected
+// As we have 2 conflicting fixes in notes, no fix is applied.
+struct PrivateVirtualBaseStruct {
----------------
Thank you for the comment about the fix not being applied!
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D102325/new/
https://reviews.llvm.org/D102325
More information about the cfe-commits
mailing list