aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/clang14/tools/extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp
diff options
context:
space:
mode:
authorvitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
committervitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
commit6ffe9e53658409f212834330e13564e4952558f6 (patch)
tree85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/clang14/tools/extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp
parent726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff)
downloadydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/clang14/tools/extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp')
-rw-r--r--contrib/libs/clang14/tools/extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp179
1 files changed, 179 insertions, 0 deletions
diff --git a/contrib/libs/clang14/tools/extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp b/contrib/libs/clang14/tools/extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp
new file mode 100644
index 0000000000..e9d97383cd
--- /dev/null
+++ b/contrib/libs/clang14/tools/extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp
@@ -0,0 +1,179 @@
+//===--- SignedCharMisuseCheck.cpp - clang-tidy ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SignedCharMisuseCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+static constexpr int UnsignedASCIIUpperBound = 127;
+
+static Matcher<TypedefDecl> hasAnyListedName(const std::string &Names) {
+ const std::vector<std::string> NameList =
+ utils::options::parseStringList(Names);
+ return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
+}
+
+SignedCharMisuseCheck::SignedCharMisuseCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ CharTypdefsToIgnoreList(Options.get("CharTypdefsToIgnore", "")),
+ DiagnoseSignedUnsignedCharComparisons(
+ Options.get("DiagnoseSignedUnsignedCharComparisons", true)) {}
+
+void SignedCharMisuseCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CharTypdefsToIgnore", CharTypdefsToIgnoreList);
+ Options.store(Opts, "DiagnoseSignedUnsignedCharComparisons",
+ DiagnoseSignedUnsignedCharComparisons);
+}
+
+// Create a matcher for char -> integer cast.
+BindableMatcher<clang::Stmt> SignedCharMisuseCheck::charCastExpression(
+ bool IsSigned, const Matcher<clang::QualType> &IntegerType,
+ const std::string &CastBindName) const {
+ // We can ignore typedefs which are some kind of integer types
+ // (e.g. typedef char sal_Int8). In this case, we don't need to
+ // worry about the misinterpretation of char values.
+ const auto IntTypedef = qualType(
+ hasDeclaration(typedefDecl(hasAnyListedName(CharTypdefsToIgnoreList))));
+
+ auto CharTypeExpr = expr();
+ if (IsSigned) {
+ CharTypeExpr = expr(hasType(
+ qualType(isAnyCharacter(), isSignedInteger(), unless(IntTypedef))));
+ } else {
+ CharTypeExpr = expr(hasType(qualType(
+ isAnyCharacter(), unless(isSignedInteger()), unless(IntTypedef))));
+ }
+
+ const auto ImplicitCastExpr =
+ implicitCastExpr(hasSourceExpression(CharTypeExpr),
+ hasImplicitDestinationType(IntegerType))
+ .bind(CastBindName);
+
+ const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
+ const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
+ const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
+
+ // We catch any type of casts to an integer. We need to have these cast
+ // expressions explicitly to catch only those casts which are direct children
+ // of the checked expressions. (e.g. assignment, declaration).
+ return traverse(TK_AsIs, expr(anyOf(ImplicitCastExpr, CStyleCastExpr,
+ StaticCastExpr, FunctionalCastExpr)));
+}
+
+void SignedCharMisuseCheck::registerMatchers(MatchFinder *Finder) {
+ const auto IntegerType =
+ qualType(isInteger(), unless(isAnyCharacter()), unless(booleanType()))
+ .bind("integerType");
+ const auto SignedCharCastExpr =
+ charCastExpression(true, IntegerType, "signedCastExpression");
+ const auto UnSignedCharCastExpr =
+ charCastExpression(false, IntegerType, "unsignedCastExpression");
+
+ // Catch assignments with signed char -> integer conversion.
+ const auto AssignmentOperatorExpr =
+ expr(binaryOperator(hasOperatorName("="), hasLHS(hasType(IntegerType)),
+ hasRHS(SignedCharCastExpr)));
+
+ Finder->addMatcher(AssignmentOperatorExpr, this);
+
+ // Catch declarations with signed char -> integer conversion.
+ const auto Declaration = varDecl(isDefinition(), hasType(IntegerType),
+ hasInitializer(SignedCharCastExpr));
+
+ Finder->addMatcher(Declaration, this);
+
+ if (DiagnoseSignedUnsignedCharComparisons) {
+ // Catch signed char/unsigned char comparison.
+ const auto CompareOperator =
+ expr(binaryOperator(hasAnyOperatorName("==", "!="),
+ anyOf(allOf(hasLHS(SignedCharCastExpr),
+ hasRHS(UnSignedCharCastExpr)),
+ allOf(hasLHS(UnSignedCharCastExpr),
+ hasRHS(SignedCharCastExpr)))))
+ .bind("comparison");
+
+ Finder->addMatcher(CompareOperator, this);
+ }
+
+ // Catch array subscripts with signed char -> integer conversion.
+ // Matcher for C arrays.
+ const auto CArraySubscript =
+ arraySubscriptExpr(hasIndex(SignedCharCastExpr)).bind("arraySubscript");
+
+ Finder->addMatcher(CArraySubscript, this);
+
+ // Matcher for std arrays.
+ const auto STDArraySubscript =
+ cxxOperatorCallExpr(
+ hasOverloadedOperatorName("[]"),
+ hasArgument(0, hasType(cxxRecordDecl(hasName("::std::array")))),
+ hasArgument(1, SignedCharCastExpr))
+ .bind("arraySubscript");
+
+ Finder->addMatcher(STDArraySubscript, this);
+}
+
+void SignedCharMisuseCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *SignedCastExpression =
+ Result.Nodes.getNodeAs<ImplicitCastExpr>("signedCastExpression");
+ const auto *IntegerType = Result.Nodes.getNodeAs<QualType>("integerType");
+ assert(SignedCastExpression);
+ assert(IntegerType);
+
+ // Ignore the match if we know that the signed char's value is not negative.
+ // The potential misinterpretation happens for negative values only.
+ Expr::EvalResult EVResult;
+ if (!SignedCastExpression->isValueDependent() &&
+ SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
+ *Result.Context)) {
+ llvm::APSInt Value = EVResult.Val.getInt();
+ if (Value.isNonNegative())
+ return;
+ }
+
+ if (const auto *Comparison = Result.Nodes.getNodeAs<Expr>("comparison")) {
+ const auto *UnSignedCastExpression =
+ Result.Nodes.getNodeAs<ImplicitCastExpr>("unsignedCastExpression");
+
+ // We can ignore the ASCII value range also for unsigned char.
+ Expr::EvalResult EVResult;
+ if (!UnSignedCastExpression->isValueDependent() &&
+ UnSignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
+ *Result.Context)) {
+ llvm::APSInt Value = EVResult.Val.getInt();
+ if (Value <= UnsignedASCIIUpperBound)
+ return;
+ }
+
+ diag(Comparison->getBeginLoc(),
+ "comparison between 'signed char' and 'unsigned char'");
+ } else if (Result.Nodes.getNodeAs<Expr>("arraySubscript")) {
+ diag(SignedCastExpression->getBeginLoc(),
+ "'signed char' to %0 conversion in array subscript; "
+ "consider casting to 'unsigned char' first.")
+ << *IntegerType;
+ } else {
+ diag(SignedCastExpression->getBeginLoc(),
+ "'signed char' to %0 conversion; "
+ "consider casting to 'unsigned char' first.")
+ << *IntegerType;
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang