10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
18AST_MATCHER(ImplicitCastExpr, isPartOfExplicitCast) {
19 return Node.isPartOfExplicitCast();
27 assert(
E ==
E->IgnoreParens() &&
"Already skipped all parens!");
30 const auto *BO = dyn_cast<BinaryOperator>(
E);
31 if (!BO || BO->getOpcode() != BO_Mul)
34 return BO->getLHS()->IgnoreParens();
41 UseCXXStaticCastsInCppSources(
42 Options.get(
"UseCXXStaticCastsInCppSources", true)),
43 UseCXXHeadersInCppSources(Options.get(
"UseCXXHeadersInCppSources", true)),
44 IncludeInserter(Options.getLocalOrGlobal(
"IncludeStyle",
45 utils::IncludeSorter::IS_LLVM),
46 areDiagsSelfContained()) {}
49 const SourceManager &SM, Preprocessor *
PP, Preprocessor *ModuleExpanderPP) {
56 UseCXXStaticCastsInCppSources);
57 Options.
store(Opts,
"UseCXXHeadersInCppSources", UseCXXHeadersInCppSources);
61std::optional<FixItHint>
62ImplicitWideningOfMultiplicationResultCheck::includeStddefHeader(
63 SourceLocation File) {
65 Result->SourceManager->getFileID(File),
66 ShouldUseCXXHeader ?
"<cstddef>" :
"<stddef.h>");
69void ImplicitWideningOfMultiplicationResultCheck::handleImplicitCastExpr(
70 const ImplicitCastExpr *ICE) {
71 ASTContext *Context = Result->Context;
73 const Expr *
E = ICE->getSubExpr()->IgnoreParens();
74 QualType Ty = ICE->getType();
75 QualType ETy =
E->getType();
77 assert(!ETy->isDependentType() && !Ty->isDependentType() &&
78 "Don't expect to ever get here in template Context.");
81 unsigned SrcWidth = Context->getIntWidth(ETy);
82 unsigned TgtWidth = Context->getIntWidth(Ty);
83 if (TgtWidth <= SrcWidth)
93 diag(
E->getBeginLoc(),
"performing an implicit widening conversion to type "
94 "%0 of a multiplication performed in type %1")
95 << Ty <<
E->getType();
98 auto Diag =
diag(
E->getBeginLoc(),
99 "make conversion explicit to silence this warning",
101 <<
E->getSourceRange();
103 if (ShouldUseCXXStaticCast)
104 Diag << FixItHint::CreateInsertion(
105 E->getBeginLoc(),
"static_cast<" + Ty.getAsString() +
">(")
106 << FixItHint::CreateInsertion(
E->getEndLoc(),
")");
108 Diag << FixItHint::CreateInsertion(
E->getBeginLoc(),
109 "(" + Ty.getAsString() +
")(")
110 << FixItHint::CreateInsertion(
E->getEndLoc(),
")");
111 Diag << includeStddefHeader(
E->getBeginLoc());
117 if (Ty->isSignedIntegerType() == ETy->isSignedIntegerType())
119 else if (Ty->isSignedIntegerType()) {
120 assert(ETy->isUnsignedIntegerType() &&
121 "Expected source type to be signed.");
122 WideExprTy = Context->getCorrespondingUnsignedType(Ty);
124 assert(Ty->isUnsignedIntegerType() &&
125 "Expected target type to be unsigned.");
126 assert(ETy->isSignedIntegerType() &&
127 "Expected source type to be unsigned.");
128 WideExprTy = Context->getCorrespondingSignedType(Ty);
132 auto Diag =
diag(
E->getBeginLoc(),
"perform multiplication in a wider type",
134 << LHS->getSourceRange();
136 if (ShouldUseCXXStaticCast)
137 Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
139 WideExprTy.getAsString() +
">(")
140 << FixItHint::CreateInsertion(LHS->getEndLoc(),
")");
142 Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
143 "(" + WideExprTy.getAsString() +
")");
144 Diag << includeStddefHeader(LHS->getBeginLoc());
148void ImplicitWideningOfMultiplicationResultCheck::handlePointerOffsetting(
150 ASTContext *Context = Result->Context;
154 const Expr *PointerExpr =
nullptr, *IndexExpr =
nullptr;
155 if (
const auto *BO = dyn_cast<BinaryOperator>(
E)) {
156 PointerExpr = BO->getLHS();
157 IndexExpr = BO->getRHS();
158 }
else if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(
E)) {
159 PointerExpr = ASE->getLHS();
160 IndexExpr = ASE->getRHS();
164 if (IndexExpr->getType()->isPointerType())
165 std::swap(PointerExpr, IndexExpr);
167 if (!PointerExpr->getType()->isPointerType() ||
168 IndexExpr->getType()->isPointerType())
171 IndexExpr = IndexExpr->IgnoreParens();
173 QualType IndexExprType = IndexExpr->getType();
177 if (IndexExprType->isDependentType())
180 QualType SSizeTy = Context->getPointerDiffType();
181 QualType USizeTy = Context->getSizeType();
182 QualType SizeTy = IndexExprType->isSignedIntegerType() ? SSizeTy : USizeTy;
185 StringRef TyAsString =
186 IndexExprType->isSignedIntegerType() ?
"ptrdiff_t" :
"size_t";
189 if (Context->getIntWidth(IndexExprType) >= Context->getIntWidth(SizeTy))
199 diag(
E->getBeginLoc(),
200 "result of multiplication in type %0 is used as a pointer offset after "
201 "an implicit widening conversion to type '%1'")
202 << IndexExprType << TyAsString;
205 auto Diag =
diag(IndexExpr->getBeginLoc(),
206 "make conversion explicit to silence this warning",
208 << IndexExpr->getSourceRange();
210 if (ShouldUseCXXStaticCast)
211 Diag << FixItHint::CreateInsertion(
212 IndexExpr->getBeginLoc(),
213 (Twine(
"static_cast<") + TyAsString +
">(").str())
214 << FixItHint::CreateInsertion(IndexExpr->getEndLoc(),
")");
216 Diag << FixItHint::CreateInsertion(IndexExpr->getBeginLoc(),
217 (Twine(
"(") + TyAsString +
")(").str())
218 << FixItHint::CreateInsertion(IndexExpr->getEndLoc(),
")");
219 Diag << includeStddefHeader(IndexExpr->getBeginLoc());
224 diag(IndexExpr->getBeginLoc(),
"perform multiplication in a wider type",
226 << LHS->getSourceRange();
228 if (ShouldUseCXXStaticCast)
229 Diag << FixItHint::CreateInsertion(
231 (Twine(
"static_cast<") + TyAsString +
">(").str())
232 << FixItHint::CreateInsertion(LHS->getEndLoc(),
")");
234 Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
235 (Twine(
"(") + TyAsString +
")").str());
236 Diag << includeStddefHeader(LHS->getBeginLoc());
241 MatchFinder *Finder) {
242 Finder->addMatcher(implicitCastExpr(unless(anyOf(isInTemplateInstantiation(),
243 isPartOfExplicitCast())),
244 hasCastKind(CK_IntegralCast))
248 arraySubscriptExpr(unless(isInTemplateInstantiation())).bind(
"x"),
this);
249 Finder->addMatcher(binaryOperator(unless(isInTemplateInstantiation()),
250 hasType(isAnyPointer()),
251 hasAnyOperatorName(
"+",
"-",
"+=",
"-="))
257 const MatchFinder::MatchResult &Result) {
258 this->Result = &Result;
259 ShouldUseCXXStaticCast =
260 UseCXXStaticCastsInCppSources && Result.Context->getLangOpts().CPlusPlus;
262 UseCXXHeadersInCppSources && Result.Context->getLangOpts().CPlusPlus;
264 if (
const auto *MatchedDecl = Result.Nodes.getNodeAs<ImplicitCastExpr>(
"x"))
265 handleImplicitCastExpr(MatchedDecl);
266 else if (
const auto *MatchedDecl =
267 Result.Nodes.getNodeAs<ArraySubscriptExpr>(
"x"))
268 handlePointerOffsetting(MatchedDecl);
269 else if (
const auto *MatchedDecl =
270 Result.Nodes.getNodeAs<BinaryOperator>(
"x"))
271 handlePointerOffsetting(MatchedDecl);
::clang::DynTypedNode Node
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.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
ImplicitWideningOfMultiplicationResultCheck(StringRef Name, ClangTidyContext *Context)
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerPreprocessor(Preprocessor *PP)
Registers this with the Preprocessor PP, must be called before this class is used.
std::optional< FixItHint > createIncludeInsertion(FileID FileID, llvm::StringRef Header)
Creates a Header inclusion directive fixit in the File FileID.
IncludeSorter::IncludeStyle getStyle() const
AST_MATCHER(Decl, declHasNoReturnAttr)
matches a Decl if it has a "no return" attribute of any kind
static const Expr * getLHSOfMulBinOp(const Expr *E)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::StringMap< ClangTidyValue > OptionMap