diff options
author | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
commit | 6ffe9e53658409f212834330e13564e4952558f6 (patch) | |
tree | 85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/clang14/tools/extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp | |
parent | 726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff) | |
download | ydb-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.cpp | 179 |
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 |