1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 #include <unordered_map>
14 #include <unordered_set>
18 #include "config_clang.h"
19 #include "clang/AST/CXXInheritance.h"
20 #include "clang/AST/StmtVisitor.h"
22 // Look for declared constructors that can be trivial (and therefore don't need to be declared)
26 class TrivialConstructor
: public loplugin::FilteringPlugin
<TrivialConstructor
>
29 explicit TrivialConstructor(loplugin::InstantiationData
const& data
)
30 : FilteringPlugin(data
)
34 virtual void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
36 bool VisitCXXConstructorDecl(CXXConstructorDecl
const*);
39 bool HasTrivialConstructorBody(const CXXRecordDecl
* BaseClassDecl
,
40 const CXXRecordDecl
* MostDerivedClassDecl
);
41 bool FieldHasTrivialConstructorBody(const FieldDecl
* Field
);
44 bool TrivialConstructor::VisitCXXConstructorDecl(CXXConstructorDecl
const* constructorDecl
)
46 if (ignoreLocation(constructorDecl
))
48 if (!constructorDecl
->hasTrivialBody())
50 if (constructorDecl
->isExplicit())
52 if (!constructorDecl
->isDefaultConstructor())
54 if (constructorDecl
->getNumParams() != 0)
56 if (!constructorDecl
->inits().empty())
58 if (constructorDecl
->getExceptionSpecType() != EST_None
)
60 if (constructorDecl
->getAccess() != AS_public
)
62 if (!constructorDecl
->isThisDeclarationADefinition())
64 if (isInUnoIncludeFile(
65 compiler
.getSourceManager().getSpellingLoc(constructorDecl
->getLocation())))
67 const CXXRecordDecl
* recordDecl
= constructorDecl
->getParent();
68 if (std::distance(recordDecl
->ctor_begin(), recordDecl
->ctor_end()) != 1)
70 // Constructor templates are not included in ctor_begin()..ctor_end() above, so also do a slow
71 // check across all decls():
72 for (auto d
: recordDecl
->decls())
74 if (auto const d2
= dyn_cast
<FunctionTemplateDecl
>(d
))
76 if (isa
<CXXConstructorDecl
>(d2
->getTemplatedDecl()))
82 if (!HasTrivialConstructorBody(recordDecl
, recordDecl
))
85 report(DiagnosticsEngine::Warning
, "no need for explicit constructor decl",
86 constructorDecl
->getLocation())
87 << constructorDecl
->getSourceRange();
88 if (constructorDecl
->getCanonicalDecl() != constructorDecl
)
90 constructorDecl
= constructorDecl
->getCanonicalDecl();
91 report(DiagnosticsEngine::Warning
, "no need for explicit constructor decl",
92 constructorDecl
->getLocation())
93 << constructorDecl
->getSourceRange();
98 bool TrivialConstructor::HasTrivialConstructorBody(const CXXRecordDecl
* BaseClassDecl
,
99 const CXXRecordDecl
* MostDerivedClassDecl
)
101 if (BaseClassDecl
!= MostDerivedClassDecl
&& !BaseClassDecl
->hasTrivialDefaultConstructor())
105 for (const auto* field
: BaseClassDecl
->fields())
106 if (!FieldHasTrivialConstructorBody(field
))
109 // Check non-virtual bases.
110 for (const auto& I
: BaseClassDecl
->bases())
114 if (!I
.getType()->isRecordType())
116 const CXXRecordDecl
* NonVirtualBase
= I
.getType()->getAsCXXRecordDecl();
117 if (NonVirtualBase
&& !HasTrivialConstructorBody(NonVirtualBase
, MostDerivedClassDecl
))
121 if (BaseClassDecl
== MostDerivedClassDecl
)
123 // Check virtual bases.
124 for (const auto& I
: BaseClassDecl
->vbases())
126 if (!I
.getType()->isRecordType())
128 const CXXRecordDecl
* VirtualBase
= I
.getType()->getAsCXXRecordDecl();
129 if (VirtualBase
&& !HasTrivialConstructorBody(VirtualBase
, MostDerivedClassDecl
))
136 bool TrivialConstructor::FieldHasTrivialConstructorBody(const FieldDecl
* Field
)
138 QualType FieldBaseElementType
= compiler
.getASTContext().getBaseElementType(Field
->getType());
140 const RecordType
* RT
= FieldBaseElementType
->getAs
<RecordType
>();
144 CXXRecordDecl
* FieldClassDecl
= cast
<CXXRecordDecl
>(RT
->getDecl());
146 // The constructor for an implicit anonymous union member is never invoked.
147 if (FieldClassDecl
->isUnion() && FieldClassDecl
->isAnonymousStructOrUnion())
150 return FieldClassDecl
->hasTrivialDefaultConstructor();
153 loplugin::Plugin::Registration
<TrivialConstructor
> X("trivialconstructor", true);
156 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */