UseEqualsDefaultCheck.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. //===--- UseEqualsDefaultCheck.cpp - clang-tidy----------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "UseEqualsDefaultCheck.h"
  9. #include "../utils/LexerUtils.h"
  10. #include "../utils/Matchers.h"
  11. #include "clang/AST/ASTContext.h"
  12. #include "clang/ASTMatchers/ASTMatchFinder.h"
  13. #include "clang/Lex/Lexer.h"
  14. #include <optional>
  15. using namespace clang::ast_matchers;
  16. namespace clang::tidy::modernize {
  17. static const char SpecialFunction[] = "SpecialFunction";
  18. /// Finds all the named non-static fields of \p Record.
  19. static std::set<const FieldDecl *>
  20. getAllNamedFields(const CXXRecordDecl *Record) {
  21. std::set<const FieldDecl *> Result;
  22. for (const auto *Field : Record->fields()) {
  23. // Static data members are not in this range.
  24. if (Field->isUnnamedBitfield())
  25. continue;
  26. Result.insert(Field);
  27. }
  28. return Result;
  29. }
  30. /// Returns the names of the direct bases of \p Record, both virtual and
  31. /// non-virtual.
  32. static std::set<const Type *> getAllDirectBases(const CXXRecordDecl *Record) {
  33. std::set<const Type *> Result;
  34. for (auto Base : Record->bases()) {
  35. // CXXBaseSpecifier.
  36. const auto *BaseType = Base.getTypeSourceInfo()->getType().getTypePtr();
  37. Result.insert(BaseType);
  38. }
  39. return Result;
  40. }
  41. /// Returns a matcher that matches member expressions where the base is
  42. /// the variable declared as \p Var and the accessed member is the one declared
  43. /// as \p Field.
  44. internal::Matcher<Expr> accessToFieldInVar(const FieldDecl *Field,
  45. const ValueDecl *Var) {
  46. return ignoringImpCasts(
  47. memberExpr(hasObjectExpression(declRefExpr(to(varDecl(equalsNode(Var))))),
  48. member(fieldDecl(equalsNode(Field)))));
  49. }
  50. /// Check that the given constructor has copy signature and that it
  51. /// copy-initializes all its bases and members.
  52. static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context,
  53. const CXXConstructorDecl *Ctor) {
  54. // An explicitly-defaulted constructor cannot have default arguments.
  55. if (Ctor->getMinRequiredArguments() != 1)
  56. return false;
  57. const auto *Record = Ctor->getParent();
  58. const auto *Param = Ctor->getParamDecl(0);
  59. // Base classes and members that have to be copied.
  60. auto BasesToInit = getAllDirectBases(Record);
  61. auto FieldsToInit = getAllNamedFields(Record);
  62. // Ensure that all the bases are copied.
  63. for (const auto *Base : BasesToInit) {
  64. // The initialization of a base class should be a call to a copy
  65. // constructor of the base.
  66. if (match(
  67. traverse(TK_AsIs,
  68. cxxConstructorDecl(
  69. forEachConstructorInitializer(cxxCtorInitializer(
  70. isBaseInitializer(),
  71. withInitializer(cxxConstructExpr(
  72. hasType(equalsNode(Base)),
  73. hasDeclaration(
  74. cxxConstructorDecl(isCopyConstructor())),
  75. argumentCountIs(1),
  76. hasArgument(0, declRefExpr(to(varDecl(
  77. equalsNode(Param))))))))))),
  78. *Ctor, *Context)
  79. .empty())
  80. return false;
  81. }
  82. // Ensure that all the members are copied.
  83. for (const auto *Field : FieldsToInit) {
  84. auto AccessToFieldInParam = accessToFieldInVar(Field, Param);
  85. // The initialization is a CXXConstructExpr for class types.
  86. if (match(traverse(
  87. TK_AsIs,
  88. cxxConstructorDecl(
  89. forEachConstructorInitializer(cxxCtorInitializer(
  90. isMemberInitializer(), forField(equalsNode(Field)),
  91. withInitializer(anyOf(
  92. AccessToFieldInParam,
  93. initListExpr(has(AccessToFieldInParam)),
  94. cxxConstructExpr(
  95. hasDeclaration(
  96. cxxConstructorDecl(isCopyConstructor())),
  97. argumentCountIs(1),
  98. hasArgument(0, AccessToFieldInParam)))))))),
  99. *Ctor, *Context)
  100. .empty())
  101. return false;
  102. }
  103. // Ensure that we don't do anything else, like initializing an indirect base.
  104. return Ctor->getNumCtorInitializers() ==
  105. BasesToInit.size() + FieldsToInit.size();
  106. }
  107. /// Checks that the given method is an overloading of the assignment
  108. /// operator, has copy signature, returns a reference to "*this" and copies
  109. /// all its members and subobjects.
  110. static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context,
  111. const CXXMethodDecl *Operator) {
  112. const auto *Record = Operator->getParent();
  113. const auto *Param = Operator->getParamDecl(0);
  114. // Base classes and members that have to be copied.
  115. auto BasesToInit = getAllDirectBases(Record);
  116. auto FieldsToInit = getAllNamedFields(Record);
  117. const auto *Compound = cast<CompoundStmt>(Operator->getBody());
  118. // The assignment operator definition has to end with the following return
  119. // statement:
  120. // return *this;
  121. if (Compound->body_empty() ||
  122. match(traverse(
  123. TK_AsIs,
  124. returnStmt(has(ignoringParenImpCasts(unaryOperator(
  125. hasOperatorName("*"), hasUnaryOperand(cxxThisExpr())))))),
  126. *Compound->body_back(), *Context)
  127. .empty())
  128. return false;
  129. // Ensure that all the bases are copied.
  130. for (const auto *Base : BasesToInit) {
  131. // Assignment operator of a base class:
  132. // Base::operator=(Other);
  133. //
  134. // Clang translates this into:
  135. // ((Base*)this)->operator=((Base)Other);
  136. //
  137. // So we are looking for a member call that fulfills:
  138. if (match(traverse(
  139. TK_AsIs,
  140. compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(
  141. // - The object is an implicit cast of 'this' to a
  142. // pointer to
  143. // a base class.
  144. onImplicitObjectArgument(implicitCastExpr(
  145. hasImplicitDestinationType(hasCanonicalType(pointsTo(
  146. type(equalsNode(Base->getCanonicalTypeInternal()
  147. .getTypePtr()))))),
  148. hasSourceExpression(cxxThisExpr()))),
  149. // - The called method is the operator=.
  150. callee(cxxMethodDecl(isCopyAssignmentOperator())),
  151. // - The argument is (an implicit cast to a Base of)
  152. // the argument taken by "Operator".
  153. argumentCountIs(1),
  154. hasArgument(
  155. 0, declRefExpr(to(varDecl(equalsNode(Param)))))))))),
  156. *Compound, *Context)
  157. .empty())
  158. return false;
  159. }
  160. // Ensure that all the members are copied.
  161. for (const auto *Field : FieldsToInit) {
  162. // The assignment of data members:
  163. // Field = Other.Field;
  164. // Is a BinaryOperator in non-class types, and a CXXOperatorCallExpr
  165. // otherwise.
  166. auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
  167. member(fieldDecl(equalsNode(Field))));
  168. auto RHS = accessToFieldInVar(Field, Param);
  169. if (match(traverse(TK_AsIs,
  170. compoundStmt(has(ignoringParenImpCasts(binaryOperation(
  171. hasOperatorName("="), hasLHS(LHS), hasRHS(RHS)))))),
  172. *Compound, *Context)
  173. .empty())
  174. return false;
  175. }
  176. // Ensure that we don't do anything else.
  177. return Compound->size() == BasesToInit.size() + FieldsToInit.size() + 1;
  178. }
  179. /// Returns false if the body has any non-whitespace character.
  180. static bool bodyEmpty(const ASTContext *Context, const CompoundStmt *Body) {
  181. bool Invalid = false;
  182. StringRef Text = Lexer::getSourceText(
  183. CharSourceRange::getCharRange(Body->getLBracLoc().getLocWithOffset(1),
  184. Body->getRBracLoc()),
  185. Context->getSourceManager(), Context->getLangOpts(), &Invalid);
  186. return !Invalid && std::strspn(Text.data(), " \t\r\n") == Text.size();
  187. }
  188. UseEqualsDefaultCheck::UseEqualsDefaultCheck(StringRef Name,
  189. ClangTidyContext *Context)
  190. : ClangTidyCheck(Name, Context),
  191. IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
  192. void UseEqualsDefaultCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
  193. Options.store(Opts, "IgnoreMacros", IgnoreMacros);
  194. }
  195. namespace {
  196. AST_MATCHER(CXXMethodDecl, isOutOfLine) { return Node.isOutOfLine(); }
  197. } // namespace
  198. void UseEqualsDefaultCheck::registerMatchers(MatchFinder *Finder) {
  199. // Skip unions/union-like classes since their constructors behave differently
  200. // when defaulted vs. empty.
  201. auto IsUnionLikeClass = recordDecl(
  202. anyOf(isUnion(),
  203. has(fieldDecl(isImplicit(), hasType(cxxRecordDecl(isUnion()))))));
  204. const LangOptions &LangOpts = getLangOpts();
  205. auto IsPublicOrOutOfLineUntilCPP20 =
  206. LangOpts.CPlusPlus20
  207. ? cxxConstructorDecl()
  208. : cxxConstructorDecl(anyOf(isOutOfLine(), isPublic()));
  209. // Destructor.
  210. Finder->addMatcher(
  211. cxxDestructorDecl(unless(hasParent(IsUnionLikeClass)), isDefinition())
  212. .bind(SpecialFunction),
  213. this);
  214. Finder->addMatcher(
  215. cxxConstructorDecl(
  216. unless(
  217. hasParent(decl(anyOf(IsUnionLikeClass, functionTemplateDecl())))),
  218. isDefinition(),
  219. anyOf(
  220. // Default constructor.
  221. allOf(unless(hasAnyConstructorInitializer(isWritten())),
  222. unless(isVariadic()), parameterCountIs(0),
  223. IsPublicOrOutOfLineUntilCPP20),
  224. // Copy constructor.
  225. allOf(isCopyConstructor(),
  226. // Discard constructors that can be used as a copy
  227. // constructor because all the other arguments have
  228. // default values.
  229. parameterCountIs(1))))
  230. .bind(SpecialFunction),
  231. this);
  232. // Copy-assignment operator.
  233. Finder->addMatcher(
  234. cxxMethodDecl(unless(hasParent(
  235. decl(anyOf(IsUnionLikeClass, functionTemplateDecl())))),
  236. isDefinition(), isCopyAssignmentOperator(),
  237. // isCopyAssignmentOperator() allows the parameter to be
  238. // passed by value, and in this case it cannot be
  239. // defaulted.
  240. hasParameter(0, hasType(lValueReferenceType())),
  241. // isCopyAssignmentOperator() allows non lvalue reference
  242. // return types, and in this case it cannot be defaulted.
  243. returns(qualType(hasCanonicalType(
  244. allOf(lValueReferenceType(pointee(type())),
  245. unless(matchers::isReferenceToConst()))))))
  246. .bind(SpecialFunction),
  247. this);
  248. }
  249. void UseEqualsDefaultCheck::check(const MatchFinder::MatchResult &Result) {
  250. // Both CXXConstructorDecl and CXXDestructorDecl inherit from CXXMethodDecl.
  251. const auto *SpecialFunctionDecl =
  252. Result.Nodes.getNodeAs<CXXMethodDecl>(SpecialFunction);
  253. if (IgnoreMacros && SpecialFunctionDecl->getLocation().isMacroID())
  254. return;
  255. // Discard explicitly deleted/defaulted special member functions and those
  256. // that are not user-provided (automatically generated).
  257. if (SpecialFunctionDecl->isDeleted() ||
  258. SpecialFunctionDecl->isExplicitlyDefaulted() ||
  259. SpecialFunctionDecl->isLateTemplateParsed() ||
  260. SpecialFunctionDecl->isTemplateInstantiation() ||
  261. !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
  262. return;
  263. const auto *Body = dyn_cast<CompoundStmt>(SpecialFunctionDecl->getBody());
  264. if (!Body)
  265. return;
  266. // If there is code inside the body, don't warn.
  267. if (!SpecialFunctionDecl->isCopyAssignmentOperator() && !Body->body_empty())
  268. return;
  269. // If there are comments inside the body, don't do the change.
  270. bool ApplyFix = SpecialFunctionDecl->isCopyAssignmentOperator() ||
  271. bodyEmpty(Result.Context, Body);
  272. std::vector<FixItHint> RemoveInitializers;
  273. unsigned MemberType;
  274. if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
  275. if (Ctor->getNumParams() == 0) {
  276. MemberType = 0;
  277. } else {
  278. if (!isCopyConstructorAndCanBeDefaulted(Result.Context, Ctor))
  279. return;
  280. MemberType = 1;
  281. // If there are constructor initializers, they must be removed.
  282. for (const auto *Init : Ctor->inits()) {
  283. RemoveInitializers.emplace_back(
  284. FixItHint::CreateRemoval(Init->getSourceRange()));
  285. }
  286. }
  287. } else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
  288. MemberType = 2;
  289. } else {
  290. if (!isCopyAssignmentAndCanBeDefaulted(Result.Context, SpecialFunctionDecl))
  291. return;
  292. MemberType = 3;
  293. }
  294. // The location of the body is more useful inside a macro as spelling and
  295. // expansion locations are reported.
  296. SourceLocation Location = SpecialFunctionDecl->getLocation();
  297. if (Location.isMacroID())
  298. Location = Body->getBeginLoc();
  299. auto Diag = diag(
  300. Location,
  301. "use '= default' to define a trivial %select{default constructor|copy "
  302. "constructor|destructor|copy-assignment operator}0");
  303. Diag << MemberType;
  304. if (ApplyFix) {
  305. SourceLocation UnifiedEnd = utils::lexer::getUnifiedEndLoc(
  306. *Body, Result.Context->getSourceManager(),
  307. Result.Context->getLangOpts());
  308. // Skipping comments, check for a semicolon after Body->getSourceRange()
  309. std::optional<Token> Token = utils::lexer::findNextTokenSkippingComments(
  310. UnifiedEnd, Result.Context->getSourceManager(),
  311. Result.Context->getLangOpts());
  312. StringRef Replacement =
  313. Token && Token->is(tok::semi) ? "= default" : "= default;";
  314. Diag << FixItHint::CreateReplacement(Body->getSourceRange(), Replacement)
  315. << RemoveInitializers;
  316. }
  317. }
  318. } // namespace clang::tidy::modernize