10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Lex/Lexer.h" 13 #include "../utils/LexerUtils.h" 24 static std::set<const FieldDecl *>
26 std::set<const FieldDecl *> Result;
27 for (
const auto *Field : Record->fields()) {
29 if (Field->isUnnamedBitfield())
39 std::set<const Type *> Result;
40 for (
auto Base : Record->bases()) {
42 const auto *BaseType =
Base.getTypeSourceInfo()->getType().getTypePtr();
43 Result.insert(BaseType);
52 const ValueDecl *Var) {
53 return ignoringImpCasts(
54 memberExpr(hasObjectExpression(declRefExpr(to(varDecl(equalsNode(Var))))),
55 member(fieldDecl(equalsNode(Field)))));
61 const CXXConstructorDecl *Ctor) {
63 if (Ctor->getMinRequiredArguments() != 1)
66 const auto *
Record = Ctor->getParent();
67 const auto *Param = Ctor->getParamDecl(0);
74 for (
const auto *
Base : BasesToInit) {
78 cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
80 withInitializer(cxxConstructExpr(
81 hasType(equalsNode(
Base)),
82 hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
85 0, declRefExpr(to(varDecl(equalsNode(Param)))))))))),
92 for (
const auto *Field : FieldsToInit) {
96 cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
97 isMemberInitializer(), forField(equalsNode(Field)),
98 withInitializer(anyOf(
100 initListExpr(has(AccessToFieldInParam)),
102 hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
104 hasArgument(0, AccessToFieldInParam))))))),
111 return Ctor->getNumCtorInitializers() ==
112 BasesToInit.size() + FieldsToInit.size();
119 const CXXMethodDecl *Operator) {
120 const auto *
Record = Operator->getParent();
121 const auto *Param = Operator->getParamDecl(0);
127 const auto *Compound = cast<CompoundStmt>(Operator->getBody());
132 if (Compound->body_empty() ||
133 match(returnStmt(has(ignoringParenImpCasts(unaryOperator(
134 hasOperatorName(
"*"), hasUnaryOperand(cxxThisExpr()))))),
135 *Compound->body_back(), *Context)
140 for (
const auto *
Base : BasesToInit) {
149 compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(
152 onImplicitObjectArgument(
153 implicitCastExpr(hasImplicitDestinationType(
154 pointsTo(type(equalsNode(
Base)))),
155 hasSourceExpression(cxxThisExpr()))),
157 callee(cxxMethodDecl(isCopyAssignmentOperator())),
161 hasArgument(0, declRefExpr(to(varDecl(equalsNode(Param))))))))),
168 for (
const auto *Field : FieldsToInit) {
173 auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
174 member(fieldDecl(equalsNode(Field))));
177 compoundStmt(has(ignoringParenImpCasts(stmt(anyOf(
178 binaryOperator(hasOperatorName(
"="), hasLHS(LHS), hasRHS(RHS)),
179 cxxOperatorCallExpr(hasOverloadedOperatorName(
"="),
180 argumentCountIs(2), hasArgument(0, LHS),
181 hasArgument(1, RHS))))))),
188 return Compound->size() == BasesToInit.size() + FieldsToInit.size() + 1;
192 static bool bodyEmpty(
const ASTContext *Context,
const CompoundStmt *Body) {
193 bool Invalid =
false;
194 StringRef
Text = Lexer::getSourceText(
195 CharSourceRange::getCharRange(Body->getLBracLoc().getLocWithOffset(1),
196 Body->getRBracLoc()),
197 Context->getSourceManager(), Context->getLangOpts(), &Invalid);
198 return !Invalid && std::strspn(Text.data(),
" \t\r\n") == Text.size();
201 UseEqualsDefaultCheck::UseEqualsDefaultCheck(StringRef
Name,
204 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true) != 0) {}
215 Finder->addMatcher(cxxDestructorDecl(isDefinition()).bind(SpecialFunction),
222 allOf(unless(hasAnyConstructorInitializer(isWritten())),
223 parameterCountIs(0)),
225 allOf(isCopyConstructor(),
229 parameterCountIs(1))))
230 .bind(SpecialFunction),
234 cxxMethodDecl(isDefinition(), isCopyAssignmentOperator(),
238 hasParameter(0, hasType(lValueReferenceType())))
239 .bind(SpecialFunction),
244 std::string SpecialFunctionName;
247 const auto *SpecialFunctionDecl =
250 if (IgnoreMacros && SpecialFunctionDecl->getLocation().isMacroID())
255 if (SpecialFunctionDecl->isDeleted() ||
256 SpecialFunctionDecl->isExplicitlyDefaulted() ||
257 SpecialFunctionDecl->isLateTemplateParsed() ||
258 SpecialFunctionDecl->isTemplateInstantiation() ||
259 !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
262 const auto *Body = dyn_cast<CompoundStmt>(SpecialFunctionDecl->getBody());
267 if (!SpecialFunctionDecl->isCopyAssignmentOperator() && !Body->body_empty())
271 bool ApplyFix = SpecialFunctionDecl->isCopyAssignmentOperator() ||
274 std::vector<FixItHint> RemoveInitializers;
276 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
277 if (Ctor->getNumParams() == 0) {
278 SpecialFunctionName =
"default constructor";
282 SpecialFunctionName =
"copy constructor";
284 for (
const auto *Init : Ctor->inits()) {
285 RemoveInitializers.emplace_back(
286 FixItHint::CreateRemoval(Init->getSourceRange()));
289 }
else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
290 SpecialFunctionName =
"destructor";
294 SpecialFunctionName =
"copy-assignment operator";
299 SourceLocation
Location = SpecialFunctionDecl->getLocation();
300 if (Location.isMacroID())
301 Location = Body->getBeginLoc();
303 auto Diag =
diag(Location,
"use '= default' to define a trivial " +
304 SpecialFunctionName);
309 Body->getSourceRange().getEnd().getLocWithOffset(1),
310 Result.Context->getSourceManager(), Result.Context->getLangOpts());
311 StringRef Replacement =
312 Token && Token->is(tok::semi) ?
"= default" :
"= default;";
313 Diag << FixItHint::CreateReplacement(Body->getSourceRange(), Replacement)
314 << 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
Optional< Token > findNextTokenSkippingComments(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts)
===– 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.
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.