aaron.ballman added inline comments.
================ Comment at: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-virtual-class-destructor.cpp:216-218 +template <typename T> +struct TemplatedDerived : PublicVirtualBaseStruct { +}; ---------------- whisperity wrote: > carlosgalvezp wrote: > > aaron.ballman wrote: > > > I think there are more interesting template test cases that should be > > > checked. > > > ``` > > > // What to do when the derived type is definitely polymorphic > > > // but the base class may or may not be? > > > template <typename Ty> > > > struct Derived : Ty { > > > virtual void func(); > > > }; > > > > > > struct S {}; > > > struct T { virtual ~T(); }; > > > > > > void instantiate() { > > > Derived<S> d1; // Diagnose > > > Derived<T> d2; // Don't diagnose > > > } > > > ``` > > > > > Very interesting example. > > > > The problem is that the diagnostic is shown where `Derived` is, not where > > the template is instantiated. How to go about that? > > > > Seems like more testing and better diagnostics are needed to lower the > > amount of false positives, I wonder if we should disable the test meanwhile? > First, let's try to see if printing, to the user, the matched record, prints > `Derived<S>` instead of just `Derived`, irrespective of the location. If the > matcher matched the instantiation, the printing/formatting logic should > **really** pick that up. > > It would be very hard to get to the `VarDecl` with the specific type if your > matcher logic starts the top-level matching from the type definitions > (`cxxRecordDecl(...)`). > > If we **really** want to put some sort of a diagnostic at the location at the > places where the type is used, it could be done with another pass over the > AST. However, that has an associated runtime cost, and also could create > bazillions of `note: used here`-esque messages... But certainly doable. I > believe this is `typeLoc`, but `typeLoc` is always a thing I never understand > and every time I may end up using it it takes me a lot of reading to > understand it for a short time to use it. > > ---- > > If the previous step failed, you could still go around in a much more > convoluted way: > > However, there is something called a `ClassTemplateSpecializationDecl` (see > the AST for @aaron.ballman's example here: http://godbolt.org/z/9qd7d1rs6), > which surely should have an associated matcher. > > ``` > | |-ClassTemplateSpecializationDecl <line:1:1, line:4:1> line:2:8 struct > Derived definition > | | |-DefinitionData polymorphic literal has_constexpr_non_copy_move_ctor > can_const_default_init > | | | |-DefaultConstructor exists non_trivial constexpr defaulted_is_constexpr > | | | |-CopyConstructor simple non_trivial has_const_param > implicit_has_const_param > | | | |-MoveConstructor exists simple non_trivial > | | | |-CopyAssignment simple non_trivial has_const_param > implicit_has_const_param > | | | |-MoveAssignment exists simple non_trivial > | | | `-Destructor simple irrelevant trivial > | | |-public 'S':'S' > | | |-TemplateArgument type 'S' > | | | `-RecordType 'S' > | | | `-CXXRecord 'S' > | | |-CXXRecordDecl prev 0x55ebcec4e600 <col:1, col:8> col:8 implicit struct > Derived > ``` > > The location for the "template specialisation" is still the location of the > primary template (as it is not an //explicit specialisation//), but at least > somehow in the AST the information of //"Which type was this class template > instantiated with?"// (`S`) is stored, so it is very likely that you can > either match on this directly, or if you can't match that way, you could > match all of these `ClassTemplateSpecializationDecl`s and check if their type > parameter matches a `ProblematicClassOrStruct`. > > Of course, this becomes extra nasty the moment we have multiple template > parameters, or nested stuff, `template template`s (brrrr...). > > This will still not give you the location of the variable definition, but at > least you would have in your hand the template specialisation/instantiation > instance properly. Oh, I may have caused some confusion with the comments in my example, sorry for that! I was imagining the diagnostics would be emitted on the line with the class declaration, but I commented on which instantiation I thought should diagnose. Being more explicit with what I was thinking: ``` // What to do when the derived type is definitely polymorphic // but the base class may or may not be? template <typename Ty> struct Derived : Ty { // Diagnostic emitted here virtual void func(); }; struct S {}; struct T { virtual ~T(); }; void instantiate() { Derived<S> d1; // Instantiation causes a diagnostic above Derived<T> d2; // Instantiation does not cause a diagnostic above } ``` CHANGES SINCE LAST ACTION https://reviews.llvm.org/D110614/new/ https://reviews.llvm.org/D110614 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits