11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
15 using namespace clang::ast_matchers;
22 switch (InitType->getScalarTypeKind()) {
23 case Type::STK_CPointer:
24 case Type::STK_BlockPointer:
25 case Type::STK_ObjCObjectPointer:
26 case Type::STK_MemberPointer:
32 case Type::STK_Integral:
33 switch (InitType->getAs<BuiltinType>()->getKind()) {
34 case BuiltinType::Char_U:
35 case BuiltinType::UChar:
36 case BuiltinType::Char_S:
37 case BuiltinType::SChar:
39 case BuiltinType::WChar_U:
40 case BuiltinType::WChar_S:
42 case BuiltinType::Char16:
44 case BuiltinType::Char32:
50 case Type::STK_Floating:
51 switch (InitType->getAs<BuiltinType>()->getKind()) {
52 case BuiltinType::Half:
53 case BuiltinType::Float:
59 case Type::STK_FloatingComplex:
60 case Type::STK_IntegralComplex:
62 InitType->getAs<ComplexType>()->getElementType());
64 llvm_unreachable(
"Invalid scalar type kind");
68 switch (E->getStmtClass()) {
69 case Stmt::CXXNullPtrLiteralExprClass:
70 case Stmt::ImplicitValueInitExprClass:
72 case Stmt::InitListExprClass:
73 return cast<InitListExpr>(E)->getNumInits() == 0;
74 case Stmt::CharacterLiteralClass:
75 return !cast<CharacterLiteral>(E)->getValue();
76 case Stmt::CXXBoolLiteralExprClass:
77 return !cast<CXXBoolLiteralExpr>(E)->getValue();
78 case Stmt::IntegerLiteralClass:
79 return !cast<IntegerLiteral>(E)->getValue();
80 case Stmt::FloatingLiteralClass: {
81 llvm::APFloat Value = cast<FloatingLiteral>(E)->getValue();
82 return Value.isZero() && !Value.isNegative();
90 auto *UnaryOp = dyn_cast<UnaryOperator>(E);
91 if (UnaryOp && UnaryOp->getOpcode() == UO_Plus)
92 return UnaryOp->getSubExpr();
97 auto *InitList = dyn_cast<InitListExpr>(E);
98 if (InitList && InitList->getNumInits() == 1)
99 return InitList->getInit(0);
110 if (E1->getStmtClass() != E2->getStmtClass())
113 switch (E1->getStmtClass()) {
114 case Stmt::UnaryOperatorClass:
115 return sameValue(cast<UnaryOperator>(E1)->getSubExpr(),
116 cast<UnaryOperator>(E2)->getSubExpr());
117 case Stmt::CharacterLiteralClass:
118 return cast<CharacterLiteral>(E1)->getValue() ==
119 cast<CharacterLiteral>(E2)->getValue();
120 case Stmt::CXXBoolLiteralExprClass:
121 return cast<CXXBoolLiteralExpr>(E1)->getValue() ==
122 cast<CXXBoolLiteralExpr>(E2)->getValue();
123 case Stmt::IntegerLiteralClass:
124 return cast<IntegerLiteral>(E1)->getValue() ==
125 cast<IntegerLiteral>(E2)->getValue();
126 case Stmt::FloatingLiteralClass:
127 return cast<FloatingLiteral>(E1)->getValue().bitwiseIsEqual(
128 cast<FloatingLiteral>(E2)->getValue());
129 case Stmt::StringLiteralClass:
130 return cast<StringLiteral>(E1)->getString() ==
131 cast<StringLiteral>(E2)->getString();
132 case Stmt::DeclRefExprClass:
133 return cast<DeclRefExpr>(E1)->getDecl() == cast<DeclRefExpr>(E2)->getDecl();
139 UseDefaultMemberInitCheck::UseDefaultMemberInitCheck(StringRef
Name,
142 UseAssignment(Options.get(
"UseAssignment", 0) != 0),
143 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", 1) != 0) {}
156 anyOf(stringLiteral(), characterLiteral(), integerLiteral(),
157 unaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"-")),
158 hasUnaryOperand(integerLiteral())),
160 unaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"-")),
161 hasUnaryOperand(floatLiteral())),
162 cxxBoolLiteral(), cxxNullPtrLiteralExpr(), implicitValueInitExpr(),
163 declRefExpr(to(enumConstantDecl())));
167 isDefaultConstructor(), unless(isInstantiated()),
168 forEachConstructorInitializer(
169 allOf(forField(unless(anyOf(isBitField(),
170 hasInClassInitializer(anything())))),
171 cxxCtorInitializer(isWritten(),
172 withInitializer(ignoringImplicit(Init)))
178 unless(ast_matchers::isTemplateInstantiation()),
179 forEachConstructorInitializer(
180 allOf(forField(hasInClassInitializer(anything())),
181 cxxCtorInitializer(isWritten(),
182 withInitializer(ignoringImplicit(Init)))
183 .bind(
"existing")))),
188 if (
const auto *Default =
189 Result.Nodes.getNodeAs<CXXCtorInitializer>(
"default"))
190 checkDefaultInit(Result, Default);
191 else if (
const auto *Existing =
192 Result.Nodes.getNodeAs<CXXCtorInitializer>(
"existing"))
193 checkExistingInit(Result, Existing);
195 llvm_unreachable(
"Bad Callback. No node provided.");
198 void UseDefaultMemberInitCheck::checkDefaultInit(
199 const MatchFinder::MatchResult &Result,
const CXXCtorInitializer *Init) {
200 const FieldDecl *Field = Init->getMember();
202 SourceLocation StartLoc = Field->getLocStart();
203 if (StartLoc.isMacroID() && IgnoreMacros)
206 SourceLocation FieldEnd =
207 Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), 0,
209 SourceLocation LParenEnd = Lexer::getLocForEndOfToken(
210 Init->getLParenLoc(), 0, *Result.SourceManager,
getLangOpts());
211 CharSourceRange InitRange =
212 CharSourceRange::getCharRange(LParenEnd, Init->getRParenLoc());
215 diag(Field->getLocation(),
"use default member initializer for %0")
217 << FixItHint::CreateInsertion(FieldEnd, UseAssignment ?
" = " :
"{")
218 << FixItHint::CreateInsertionFromRange(FieldEnd, InitRange);
220 if (UseAssignment && isa<ImplicitValueInitExpr>(Init->getInit()))
221 Diag << FixItHint::CreateInsertion(
225 Diag << FixItHint::CreateInsertion(FieldEnd,
"}");
227 Diag << FixItHint::CreateRemoval(Init->getSourceRange());
230 void UseDefaultMemberInitCheck::checkExistingInit(
231 const MatchFinder::MatchResult &Result,
const CXXCtorInitializer *Init) {
232 const FieldDecl *Field = Init->getMember();
234 if (!
sameValue(Field->getInClassInitializer(), Init->getInit()))
237 diag(Init->getSourceLocation(),
"member initializer for %0 is redundant")
239 << FixItHint::CreateRemoval(Init->getSourceRange());
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
LangOptions getLangOpts() const
Returns the language options from the context.
std::unique_ptr< ast_matchers::MatchFinder > Finder
static const Expr * getInitializer(const Expr *E)
static const Expr * ignoreUnaryPlus(const Expr *E)
Base class for all clang-tidy checks.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
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.
std::map< std::string, std::string > OptionMap
static StringRef getValueOfValueInit(const QualType InitType)
static bool isZero(const Expr *E)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
ClangTidyContext & Context
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
static bool sameValue(const Expr *E1, const Expr *E2)