[PATCH] D116514: [clangd] Add code action to generate a constructor for a C++ class
Sam McCall via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 31 07:17:37 PDT 2022
sammccall added a comment.
In D116514#3311780 <https://reviews.llvm.org/D116514#3311780>, @avogelsgesang wrote:
> Can we add this tweak as the default "fix-it" action for
>
>> Class '...' does not declare any constructor to initialize its non-modifiable members
>
> on structs like
>
> struct X {
> int& a;
> }
>
> ?
Not easy to do in this patch, we don't have a good way to associate fixes with clang diagnostics yet.
It's a useful idea but needs a little design I guess.
(-Wswitch kind of works by always marking the tweak as a "fix", which semantically doesn't work here)
================
Comment at: clang-tools-extra/clangd/refactor/tweaks/MemberwiseConstructor.cpp:49
+ Class = N->ASTNode.get<CXXRecordDecl>();
+ if (!Class || !Class->isThisDeclarationADefinition() || Class->isUnion())
+ return false;
----------------
avogelsgesang wrote:
> njames93 wrote:
> > avogelsgesang wrote:
> > > do we also need to exclude anonymous class declarations here? (Not sure if those are also modelled as `CXXRecordDecl` in the clang AST...)
> > Good point, should also ensure there is a test case for this as well.
> On 2nd thought: To trigger this tweak, I click on the class name, and since anonymous structs don't have class names, I think the tweak can't even be triggered.
>
> Still probably worth a check here, just to be sure. Or at least an `assert`+ comment in the code
Good catch, it's also possible to trigger the code action on the class's braces.
Excluded and added test.
================
Comment at: clang-tools-extra/clangd/refactor/tweaks/MemberwiseConstructor.cpp:133
+ // Decide what to do based on the field type.
+ class Visitor : public TypeVisitor<Visitor, FieldAction> {
+ public:
----------------
avogelsgesang wrote:
> Is this visitor able to look through `using MyType = int;` and `typedef`?
> I think we should also add a test case
We call getCanonicalType() before visiting.
================
Comment at: clang-tools-extra/clangd/refactor/tweaks/MemberwiseConstructor.cpp:203
+ return CopyRef;
+ return Fail;
+ }
----------------
njames93 wrote:
> If C is default constructible, would it be nice to skip here instead of failing?
Yeah, if it's default constructible but *not movable* then it's probably reasonable.
(The default constructor should be public, but actually this applies to all constructors, so I added this condition everywhere)
================
Comment at: clang-tools-extra/clangd/refactor/tweaks/MemberwiseConstructor.cpp:211
+ if (Fields.size() == 1)
+ OS << "explicit ";
+ OS << Class->getName() << "(";
----------------
njames93 wrote:
> Some codebases may not want these to be explicit, would it be wiser to use config to control this?
I'm not sure that adding an option solves a problem, so I'd rather not add one yet.
In most cases, the programmer should be deciding whether the constructor is explicit or not on a case-by-case basis. Having a configurable adds complexity without relieving significant burden.
We do have to have some default, and explicit for single-arg constructors is IMO a better default (recommended by [cppcoreguidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c46-by-default-declare-single-argument-constructors-explicit), [google style guide](https://google.github.io/styleguide/cppguide.html#Implicit_Conversions))
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D116514/new/
https://reviews.llvm.org/D116514
More information about the cfe-commits
mailing list