10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Lex/Lexer.h" 23 static std::set<const FieldDecl *>
25 std::set<const FieldDecl *>
Result;
26 for (
const auto *Field : Record->fields()) {
28 if (Field->isUnnamedBitfield())
38 std::set<const Type *>
Result;
39 for (
auto Base : Record->bases()) {
41 const auto *BaseType =
Base.getTypeSourceInfo()->getType().getTypePtr();
42 Result.insert(BaseType);
51 const ValueDecl *Var) {
52 return ignoringImpCasts(
53 memberExpr(hasObjectExpression(declRefExpr(to(varDecl(equalsNode(Var))))),
54 member(fieldDecl(equalsNode(Field)))));
60 const CXXConstructorDecl *Ctor) {
62 if (Ctor->getMinRequiredArguments() != 1)
65 const auto *
Record = Ctor->getParent();
66 const auto *Param = Ctor->getParamDecl(0);
73 for (
const auto *
Base : BasesToInit) {
77 cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
79 withInitializer(cxxConstructExpr(
80 hasType(equalsNode(
Base)),
81 hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
84 0, declRefExpr(to(varDecl(equalsNode(Param)))))))))),
91 for (
const auto *Field : FieldsToInit) {
95 cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
96 isMemberInitializer(), forField(equalsNode(Field)),
97 withInitializer(anyOf(
99 initListExpr(has(AccessToFieldInParam)),
101 hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
103 hasArgument(0, AccessToFieldInParam))))))),
110 return Ctor->getNumCtorInitializers() ==
111 BasesToInit.size() + FieldsToInit.size();
118 const CXXMethodDecl *Operator) {
119 const auto *
Record = Operator->getParent();
120 const auto *Param = Operator->getParamDecl(0);
126 const auto *Compound = cast<CompoundStmt>(Operator->getBody());
131 if (Compound->body_empty() ||
132 match(returnStmt(has(ignoringParenImpCasts(unaryOperator(
133 hasOperatorName(
"*"), hasUnaryOperand(cxxThisExpr()))))),
134 *Compound->body_back(), *Context)
139 for (
const auto *
Base : BasesToInit) {
148 compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(
151 onImplicitObjectArgument(
152 implicitCastExpr(hasImplicitDestinationType(
153 pointsTo(type(equalsNode(
Base)))),
154 hasSourceExpression(cxxThisExpr()))),
156 callee(cxxMethodDecl(isCopyAssignmentOperator())),
160 hasArgument(0, declRefExpr(to(varDecl(equalsNode(Param))))))))),
167 for (
const auto *Field : FieldsToInit) {
172 auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
173 member(fieldDecl(equalsNode(Field))));
176 compoundStmt(has(ignoringParenImpCasts(stmt(anyOf(
177 binaryOperator(hasOperatorName(
"="), hasLHS(LHS), hasRHS(RHS)),
178 cxxOperatorCallExpr(hasOverloadedOperatorName(
"="),
179 argumentCountIs(2), hasArgument(0, LHS),
180 hasArgument(1, RHS))))))),
187 return Compound->size() == BasesToInit.size() + FieldsToInit.size() + 1;
191 static bool bodyEmpty(
const ASTContext *Context,
const CompoundStmt *Body) {
192 bool Invalid =
false;
193 StringRef
Text = Lexer::getSourceText(
194 CharSourceRange::getCharRange(Body->getLBracLoc().getLocWithOffset(1),
195 Body->getRBracLoc()),
196 Context->getSourceManager(), Context->getLangOpts(), &Invalid);
197 return !Invalid && std::strspn(Text.data(),
" \t\r\n") == Text.size();
200 UseEqualsDefaultCheck::UseEqualsDefaultCheck(StringRef
Name,
203 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true) != 0) {}
214 Finder->addMatcher(cxxDestructorDecl(isDefinition()).bind(SpecialFunction),
221 allOf(unless(hasAnyConstructorInitializer(isWritten())),
222 parameterCountIs(0)),
224 allOf(isCopyConstructor(),
228 parameterCountIs(1))))
229 .bind(SpecialFunction),
233 cxxMethodDecl(isDefinition(), isCopyAssignmentOperator(),
237 hasParameter(0, hasType(lValueReferenceType())))
238 .bind(SpecialFunction),
243 std::string SpecialFunctionName;
246 const auto *SpecialFunctionDecl =
249 if (IgnoreMacros && SpecialFunctionDecl->getLocation().isMacroID())
254 if (SpecialFunctionDecl->isDeleted() ||
255 SpecialFunctionDecl->isExplicitlyDefaulted() ||
256 SpecialFunctionDecl->isLateTemplateParsed() ||
257 SpecialFunctionDecl->isTemplateInstantiation() ||
258 !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
261 const auto *Body = dyn_cast<CompoundStmt>(SpecialFunctionDecl->getBody());
266 if (!SpecialFunctionDecl->isCopyAssignmentOperator() && !Body->body_empty())
270 bool ApplyFix = SpecialFunctionDecl->isCopyAssignmentOperator() ||
273 std::vector<FixItHint> RemoveInitializers;
275 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
276 if (Ctor->getNumParams() == 0) {
277 SpecialFunctionName =
"default constructor";
281 SpecialFunctionName =
"copy constructor";
283 for (
const auto *Init : Ctor->inits()) {
284 RemoveInitializers.emplace_back(
285 FixItHint::CreateRemoval(Init->getSourceRange()));
288 }
else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
289 SpecialFunctionName =
"destructor";
293 SpecialFunctionName =
"copy-assignment operator";
298 SourceLocation
Location = SpecialFunctionDecl->getLocation();
299 if (Location.isMacroID())
300 Location = Body->getBeginLoc();
302 auto Diag =
diag(Location,
"use '= default' to define a trivial " +
303 SpecialFunctionName);
306 Diag << FixItHint::CreateReplacement(Body->getSourceRange(),
"= default;")
307 << RemoveInitializers;
static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context, const CXXMethodDecl *Operator)
Checks that the given method is an overloading of the assignment operator, has copy signature...
static const char SpecialFunction[]
llvm::SmallVector< uint64_t, 1024 > Record
Base class for all clang-tidy checks.
const LangOptions & getLangOpts() const
Returns the language options from the context.
static bool bodyEmpty(const ASTContext *Context, const CompoundStmt *Body)
Returns false if the body has any non-whitespace character.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
std::vector< std::string > match(const SymbolIndex &I, const FuzzyFindRequest &Req, bool *Incomplete)
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
internal::Matcher< Expr > accessToFieldInVar(const FieldDecl *Field, const ValueDecl *Var)
Returns a matcher that matches member expressions where the base is the variable declared as Var and ...
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context, const CXXConstructorDecl *Ctor)
Check that the given constructor has copy signature and that it copy-initializes all its bases and me...
static std::set< const Type * > getAllDirectBases(const CXXRecordDecl *Record)
Returns the names of the direct bases of Record, both virtual and non-virtual.
static std::set< const FieldDecl * > getAllNamedFields(const CXXRecordDecl *Record)
Finds all the named non-static fields of Record.
std::unique_ptr< GlobalCompilationDatabase > Base
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.