clang-tools 10.0.0

SignedCharMisuseCheck.cpp
Go to the documentation of this file.
1 //===--- SignedCharMisuseCheck.cpp - clang-tidy ---------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "SignedCharMisuseCheck.h"
10 #include "../utils/OptionsUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13
14 using namespace clang::ast_matchers;
15 using namespace clang::ast_matchers::internal;
16
17 namespace clang {
18 namespace tidy {
19 namespace bugprone {
20
21 static Matcher<TypedefDecl> hasAnyListedName(const std::string &Names) {
22 const std::vector<std::string> NameList =
23 utils::options::parseStringList(Names);
24 return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
25 }
26
27 SignedCharMisuseCheck::SignedCharMisuseCheck(StringRef Name,
28 ClangTidyContext *Context)
29 : ClangTidyCheck(Name, Context),
30 CharTypdefsToIgnoreList(Options.get("CharTypdefsToIgnore", "")) {}
31
32 void SignedCharMisuseCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
33 Options.store(Opts, "CharTypdefsToIgnore", CharTypdefsToIgnoreList);
34 }
35
36 void SignedCharMisuseCheck::registerMatchers(MatchFinder *Finder) {
37 // We can ignore typedefs which are some kind of integer types
38 // (e.g. typedef char sal_Int8). In this case, we don't need to
39 // worry about the misinterpretation of char values.
40 const auto IntTypedef = qualType(
41 hasDeclaration(typedefDecl(hasAnyListedName(CharTypdefsToIgnoreList))));
42
43 const auto SignedCharType = expr(hasType(qualType(
44 allOf(isAnyCharacter(), isSignedInteger(), unless(IntTypedef)))));
45
46 const auto IntegerType = qualType(allOf(isInteger(), unless(isAnyCharacter()),
47 unless(booleanType())))
48 .bind("integerType");
49
50 // We are interested in signed char -> integer conversion.
51 const auto ImplicitCastExpr =
52 implicitCastExpr(hasSourceExpression(SignedCharType),
53 hasImplicitDestinationType(IntegerType))
54 .bind("castExpression");
55
56 const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
57 const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
58 const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
59
60 // We catch any type of casts to an integer. We need to have these cast
61 // expressions explicitly to catch only those casts which are direct children
62 // of an assignment/declaration.
63 const auto CastExpr = expr(anyOf(ImplicitCastExpr, CStyleCastExpr,
64 StaticCastExpr, FunctionalCastExpr));
65
66 // Catch assignments with the suspicious type conversion.
67 const auto AssignmentOperatorExpr = expr(binaryOperator(
68 hasOperatorName("="), hasLHS(hasType(IntegerType)), hasRHS(CastExpr)));
69
70 Finder->addMatcher(AssignmentOperatorExpr, this);
71
72 // Catch declarations with the suspicious type conversion.
73 const auto Declaration =
74 varDecl(isDefinition(), hasType(IntegerType), hasInitializer(CastExpr));
75
76 Finder->addMatcher(Declaration, this);
77 }
78
79 void SignedCharMisuseCheck::check(const MatchFinder::MatchResult &Result) {
80 const auto *CastExpression =
81 Result.Nodes.getNodeAs<ImplicitCastExpr>("castExpression");
82 const auto *IntegerType = Result.Nodes.getNodeAs<QualType>("integerType");
83 assert(CastExpression);
84 assert(IntegerType);
85
86 // Ignore the match if we know that the value is not negative.
87 // The potential misinterpretation happens for negative values only.
88 Expr::EvalResult EVResult;
89 if (!CastExpression->isValueDependent() &&
90 CastExpression->getSubExpr()->EvaluateAsInt(EVResult, *Result.Context)) {
91 llvm::APSInt Value1 = EVResult.Val.getInt();
92 if (Value1.isNonNegative())
93 return;
94 }
95
96 diag(CastExpression->getBeginLoc(),
97 "'signed char' to %0 conversion; "
98 "consider casting to 'unsigned char' first.")
99 << *IntegerType;
100 }
101
102 } // namespace bugprone
103 } // namespace tidy
104 } // namespace clang
clang::ast_matchers
Definition: AbseilMatcher.h:14
clang::tidy::bugprone::hasAnyListedName
static Matcher< TypedefDecl > hasAnyListedName(const std::string &Names)
Definition: SignedCharMisuseCheck.cpp:21
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:47
clang::tidy::utils::options::parseStringList
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
Definition: OptionsUtils.cpp:18
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:184
clang::tidy::ClangTidyCheck::OptionsView::store
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.
Definition: ClangTidyCheck.cpp:58
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:97
SignedCharMisuseCheck.h
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::bugprone::SignedCharMisuseCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: SignedCharMisuseCheck.cpp:32
clang::tidy::bugprone::SignedCharMisuseCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: SignedCharMisuseCheck.cpp:36
internal
clang::tidy::bugprone::SignedCharMisuseCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: SignedCharMisuseCheck.cpp:79
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:77
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidyCheck.cpp:21