10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
19AST_MATCHER(ImplicitCastExpr, isPartOfExplicitCast) {
20 return Node.isPartOfExplicitCast();
28 assert(
E ==
E->IgnoreParens() &&
"Already skipped all parens!");
31 const auto *BO = dyn_cast<BinaryOperator>(
E);
32 if (!BO || BO->getOpcode() != BO_Mul)
35 return BO->getLHS()->IgnoreParens();
42 UseCXXStaticCastsInCppSources(
43 Options.get(
"UseCXXStaticCastsInCppSources", true)),
44 UseCXXHeadersInCppSources(Options.get(
"UseCXXHeadersInCppSources", true)),
45 IncludeInserter(Options.getLocalOrGlobal(
"IncludeStyle",
46 utils::IncludeSorter::IS_LLVM),
47 areDiagsSelfContained()) {}
50 const SourceManager &SM, Preprocessor *
PP, Preprocessor *ModuleExpanderPP) {
57 UseCXXStaticCastsInCppSources);
58 Options.
store(Opts,
"UseCXXHeadersInCppSources", UseCXXHeadersInCppSources);
62std::optional<FixItHint>
63ImplicitWideningOfMultiplicationResultCheck::includeStddefHeader(
64 SourceLocation File) {
66 Result->SourceManager->getFileID(File),
67 ShouldUseCXXHeader ?
"<cstddef>" :
"<stddef.h>");
70void ImplicitWideningOfMultiplicationResultCheck::handleImplicitCastExpr(
71 const ImplicitCastExpr *ICE) {
72 ASTContext *Context = Result->Context;
74 const Expr *
E = ICE->getSubExpr()->IgnoreParens();
75 QualType Ty = ICE->getType();
76 QualType ETy =
E->getType();
78 assert(!ETy->isDependentType() && !Ty->isDependentType() &&
79 "Don't expect to ever get here in template Context.");
82 unsigned SrcWidth = Context->getIntWidth(ETy);
83 unsigned TgtWidth = Context->getIntWidth(Ty);
84 if (TgtWidth <= SrcWidth)
94 diag(
E->getBeginLoc(),
"performing an implicit widening conversion to type "
95 "%0 of a multiplication performed in type %1")
96 << Ty <<
E->getType();
99 auto Diag =
diag(
E->getBeginLoc(),
100 "make conversion explicit to silence this warning",
102 <<
E->getSourceRange();
103 const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
104 E->getEndLoc(), 0, *Result->SourceManager,
getLangOpts());
105 if (ShouldUseCXXStaticCast)
106 Diag << FixItHint::CreateInsertion(
107 E->getBeginLoc(),
"static_cast<" + Ty.getAsString() +
">(")
108 << FixItHint::CreateInsertion(EndLoc,
")");
110 Diag << FixItHint::CreateInsertion(
E->getBeginLoc(),
111 "(" + Ty.getAsString() +
")(")
112 << FixItHint::CreateInsertion(EndLoc,
")");
113 Diag << includeStddefHeader(
E->getBeginLoc());
119 if (Ty->isSignedIntegerType() == ETy->isSignedIntegerType())
121 else if (Ty->isSignedIntegerType()) {
122 assert(ETy->isUnsignedIntegerType() &&
123 "Expected source type to be signed.");
124 WideExprTy = Context->getCorrespondingUnsignedType(Ty);
126 assert(Ty->isUnsignedIntegerType() &&
127 "Expected target type to be unsigned.");
128 assert(ETy->isSignedIntegerType() &&
129 "Expected source type to be unsigned.");
130 WideExprTy = Context->getCorrespondingSignedType(Ty);
134 auto Diag =
diag(
E->getBeginLoc(),
"perform multiplication in a wider type",
136 << LHS->getSourceRange();
138 if (ShouldUseCXXStaticCast)
139 Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
141 WideExprTy.getAsString() +
">(")
142 << FixItHint::CreateInsertion(
143 Lexer::getLocForEndOfToken(LHS->getEndLoc(), 0,
144 *Result->SourceManager,
148 Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
149 "(" + WideExprTy.getAsString() +
")");
150 Diag << includeStddefHeader(LHS->getBeginLoc());
154void ImplicitWideningOfMultiplicationResultCheck::handlePointerOffsetting(
156 ASTContext *Context = Result->Context;
160 const Expr *PointerExpr =
nullptr, *IndexExpr =
nullptr;
161 if (
const auto *BO = dyn_cast<BinaryOperator>(
E)) {
162 PointerExpr = BO->getLHS();
163 IndexExpr = BO->getRHS();
164 }
else if (
const auto *ASE = dyn_cast<ArraySubscriptExpr>(
E)) {
165 PointerExpr = ASE->getLHS();
166 IndexExpr = ASE->getRHS();
170 if (IndexExpr->getType()->isPointerType())
171 std::swap(PointerExpr, IndexExpr);
173 if (!PointerExpr->getType()->isPointerType() ||
174 IndexExpr->getType()->isPointerType())
177 IndexExpr = IndexExpr->IgnoreParens();
179 QualType IndexExprType = IndexExpr->getType();
183 if (IndexExprType->isDependentType())
186 QualType SSizeTy = Context->getPointerDiffType();
187 QualType USizeTy = Context->getSizeType();
188 QualType SizeTy = IndexExprType->isSignedIntegerType() ? SSizeTy : USizeTy;
191 StringRef TyAsString =
192 IndexExprType->isSignedIntegerType() ?
"ptrdiff_t" :
"size_t";
195 if (Context->getIntWidth(IndexExprType) >= Context->getIntWidth(SizeTy))
205 diag(
E->getBeginLoc(),
206 "result of multiplication in type %0 is used as a pointer offset after "
207 "an implicit widening conversion to type '%1'")
208 << IndexExprType << TyAsString;
211 auto Diag =
diag(IndexExpr->getBeginLoc(),
212 "make conversion explicit to silence this warning",
214 << IndexExpr->getSourceRange();
215 const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
216 IndexExpr->getEndLoc(), 0, *Result->SourceManager,
getLangOpts());
217 if (ShouldUseCXXStaticCast)
218 Diag << FixItHint::CreateInsertion(
219 IndexExpr->getBeginLoc(),
220 (Twine(
"static_cast<") + TyAsString +
">(").str())
221 << FixItHint::CreateInsertion(EndLoc,
")");
223 Diag << FixItHint::CreateInsertion(IndexExpr->getBeginLoc(),
224 (Twine(
"(") + TyAsString +
")(").str())
225 << FixItHint::CreateInsertion(EndLoc,
")");
226 Diag << includeStddefHeader(IndexExpr->getBeginLoc());
231 diag(IndexExpr->getBeginLoc(),
"perform multiplication in a wider type",
233 << LHS->getSourceRange();
235 if (ShouldUseCXXStaticCast)
236 Diag << FixItHint::CreateInsertion(
238 (Twine(
"static_cast<") + TyAsString +
">(").str())
239 << FixItHint::CreateInsertion(
240 Lexer::getLocForEndOfToken(IndexExpr->getEndLoc(), 0,
241 *Result->SourceManager,
245 Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
246 (Twine(
"(") + TyAsString +
")").str());
247 Diag << includeStddefHeader(LHS->getBeginLoc());
252 MatchFinder *Finder) {
253 Finder->addMatcher(implicitCastExpr(unless(anyOf(isInTemplateInstantiation(),
254 isPartOfExplicitCast())),
255 hasCastKind(CK_IntegralCast))
259 arraySubscriptExpr(unless(isInTemplateInstantiation())).bind(
"x"),
this);
260 Finder->addMatcher(binaryOperator(unless(isInTemplateInstantiation()),
261 hasType(isAnyPointer()),
262 hasAnyOperatorName(
"+",
"-",
"+=",
"-="))
268 const MatchFinder::MatchResult &Result) {
269 this->Result = &Result;
270 ShouldUseCXXStaticCast =
271 UseCXXStaticCastsInCppSources && Result.Context->getLangOpts().CPlusPlus;
273 UseCXXHeadersInCppSources && Result.Context->getLangOpts().CPlusPlus;
275 if (
const auto *MatchedDecl = Result.Nodes.getNodeAs<ImplicitCastExpr>(
"x"))
276 handleImplicitCastExpr(MatchedDecl);
277 else if (
const auto *MatchedDecl =
278 Result.Nodes.getNodeAs<ArraySubscriptExpr>(
"x"))
279 handlePointerOffsetting(MatchedDecl);
280 else if (
const auto *MatchedDecl =
281 Result.Nodes.getNodeAs<BinaryOperator>(
"x"))
282 handlePointerOffsetting(MatchedDecl);
llvm::SmallString< 256U > Name
::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.
const LangOptions & getLangOpts() const
Returns the language options from the context.
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