diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/tools/extra/clang-tidy/google | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/tools/extra/clang-tidy/google')
34 files changed, 2549 insertions, 0 deletions
diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp new file mode 100644 index 0000000000..b7dcaf2016 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp @@ -0,0 +1,258 @@ +//===--- AvoidCStyleCastsCheck.cpp - clang-tidy -----------------*- C++ -*-===// +// +// 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 "AvoidCStyleCastsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::readability { + +void AvoidCStyleCastsCheck::registerMatchers( + ast_matchers::MatchFinder *Finder) { + Finder->addMatcher( + cStyleCastExpr( + // Filter out (EnumType)IntegerLiteral construct, which is generated + // for non-type template arguments of enum types. + // FIXME: Remove this once this is fixed in the AST. + unless(hasParent(substNonTypeTemplateParmExpr())), + // Avoid matches in template instantiations. + unless(isInTemplateInstantiation())) + .bind("cast"), + this); + Finder->addMatcher( + cxxFunctionalCastExpr(unless(hasDescendant(cxxConstructExpr())), + unless(hasDescendant(initListExpr()))) + .bind("cast"), + this); +} + +static bool needsConstCast(QualType SourceType, QualType DestType) { + while ((SourceType->isPointerType() && DestType->isPointerType()) || + (SourceType->isReferenceType() && DestType->isReferenceType())) { + SourceType = SourceType->getPointeeType(); + DestType = DestType->getPointeeType(); + if (SourceType.isConstQualified() && !DestType.isConstQualified()) { + return (SourceType->isPointerType() == DestType->isPointerType()) && + (SourceType->isReferenceType() == DestType->isReferenceType()); + } + } + return false; +} + +static bool pointedUnqualifiedTypesAreEqual(QualType T1, QualType T2) { + while ((T1->isPointerType() && T2->isPointerType()) || + (T1->isReferenceType() && T2->isReferenceType())) { + T1 = T1->getPointeeType(); + T2 = T2->getPointeeType(); + } + return T1.getUnqualifiedType() == T2.getUnqualifiedType(); +} + +static clang::CharSourceRange getReplaceRange(const ExplicitCastExpr *Expr) { + if (const auto *CastExpr = dyn_cast<CStyleCastExpr>(Expr)) { + return CharSourceRange::getCharRange( + CastExpr->getLParenLoc(), + CastExpr->getSubExprAsWritten()->getBeginLoc()); + } else if (const auto *CastExpr = dyn_cast<CXXFunctionalCastExpr>(Expr)) { + return CharSourceRange::getCharRange(CastExpr->getBeginLoc(), + CastExpr->getLParenLoc()); + } else + llvm_unreachable("Unsupported CastExpr"); +} + +static StringRef getDestTypeString(const SourceManager &SM, + const LangOptions &LangOpts, + const ExplicitCastExpr *Expr) { + SourceLocation BeginLoc; + SourceLocation EndLoc; + + if (const auto *CastExpr = dyn_cast<CStyleCastExpr>(Expr)) { + BeginLoc = CastExpr->getLParenLoc().getLocWithOffset(1); + EndLoc = CastExpr->getRParenLoc().getLocWithOffset(-1); + } else if (const auto *CastExpr = dyn_cast<CXXFunctionalCastExpr>(Expr)) { + BeginLoc = CastExpr->getBeginLoc(); + EndLoc = CastExpr->getLParenLoc().getLocWithOffset(-1); + } else + llvm_unreachable("Unsupported CastExpr"); + + return Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), + SM, LangOpts); +} + +void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) { + const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast"); + + // Ignore casts in macros. + if (CastExpr->getExprLoc().isMacroID()) + return; + + // Casting to void is an idiomatic way to mute "unused variable" and similar + // warnings. + if (CastExpr->getCastKind() == CK_ToVoid) + return; + + auto IsFunction = [](QualType T) { + T = T.getCanonicalType().getNonReferenceType(); + return T->isFunctionType() || T->isFunctionPointerType() || + T->isMemberFunctionPointerType(); + }; + + const QualType DestTypeAsWritten = + CastExpr->getTypeAsWritten().getUnqualifiedType(); + const QualType SourceTypeAsWritten = + CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType(); + const QualType SourceType = SourceTypeAsWritten.getCanonicalType(); + const QualType DestType = DestTypeAsWritten.getCanonicalType(); + + CharSourceRange ReplaceRange = getReplaceRange(CastExpr); + + bool FnToFnCast = + IsFunction(SourceTypeAsWritten) && IsFunction(DestTypeAsWritten); + + const bool ConstructorCast = !CastExpr->getTypeAsWritten().hasQualifiers() && + DestTypeAsWritten->isRecordType() && + !DestTypeAsWritten->isElaboratedTypeSpecifier(); + + if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) { + // Function pointer/reference casts may be needed to resolve ambiguities in + // case of overloaded functions, so detection of redundant casts is trickier + // in this case. Don't emit "redundant cast" warnings for function + // pointer/reference types. + QualType Src = SourceTypeAsWritten, Dst = DestTypeAsWritten; + if (const auto *ElTy = dyn_cast<ElaboratedType>(Src)) + Src = ElTy->getNamedType(); + if (const auto *ElTy = dyn_cast<ElaboratedType>(Dst)) + Dst = ElTy->getNamedType(); + if (Src == Dst) { + diag(CastExpr->getBeginLoc(), "redundant cast to the same type") + << FixItHint::CreateRemoval(ReplaceRange); + return; + } + } + + // The rest of this check is only relevant to C++. + // We also disable it for Objective-C++. + if (!getLangOpts().CPlusPlus || getLangOpts().ObjC) + return; + // Ignore code inside extern "C" {} blocks. + if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context) + .empty()) + return; + // Ignore code in .c files and headers included from them, even if they are + // compiled as C++. + if (getCurrentMainFile().endswith(".c")) + return; + + SourceManager &SM = *Result.SourceManager; + + // Ignore code in .c files #included in other files (which shouldn't be done, + // but people still do this for test and other purposes). + if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc())).endswith(".c")) + return; + + // Leave type spelling exactly as it was (unlike + // getTypeAsWritten().getAsString() which would spell enum types 'enum X'). + StringRef DestTypeString = getDestTypeString(SM, getLangOpts(), CastExpr); + + auto Diag = + diag(CastExpr->getBeginLoc(), "C-style casts are discouraged; use %0"); + + auto ReplaceWithCast = [&](std::string CastText) { + const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts(); + if (!isa<ParenExpr>(SubExpr) && !isa<CXXFunctionalCastExpr>(CastExpr)) { + CastText.push_back('('); + Diag << FixItHint::CreateInsertion( + Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM, + getLangOpts()), + ")"); + } + Diag << FixItHint::CreateReplacement(ReplaceRange, CastText); + }; + auto ReplaceWithNamedCast = [&](StringRef CastType) { + Diag << CastType; + ReplaceWithCast((CastType + "<" + DestTypeString + ">").str()); + }; + auto ReplaceWithConstructorCall = [&]() { + Diag << "constructor call syntax"; + // FIXME: Validate DestTypeString, maybe. + ReplaceWithCast(DestTypeString.str()); + }; + // Suggest appropriate C++ cast. See [expr.cast] for cast notation semantics. + switch (CastExpr->getCastKind()) { + case CK_FunctionToPointerDecay: + ReplaceWithNamedCast("static_cast"); + return; + case CK_ConstructorConversion: + if (ConstructorCast) { + ReplaceWithConstructorCall(); + } else { + ReplaceWithNamedCast("static_cast"); + } + return; + case CK_NoOp: + if (FnToFnCast) { + ReplaceWithNamedCast("static_cast"); + return; + } + if (SourceType == DestType) { + Diag << "static_cast (if needed, the cast may be redundant)"; + ReplaceWithCast(("static_cast<" + DestTypeString + ">").str()); + return; + } + if (needsConstCast(SourceType, DestType) && + pointedUnqualifiedTypesAreEqual(SourceType, DestType)) { + ReplaceWithNamedCast("const_cast"); + return; + } + if (ConstructorCast) { + ReplaceWithConstructorCall(); + return; + } + if (DestType->isReferenceType()) { + QualType Dest = DestType.getNonReferenceType(); + QualType Source = SourceType.getNonReferenceType(); + if (Source == Dest.withConst() || + SourceType.getNonReferenceType() == DestType.getNonReferenceType()) { + ReplaceWithNamedCast("const_cast"); + return; + } + break; + } + [[fallthrough]]; + case clang::CK_IntegralCast: + // Convert integral and no-op casts between builtin types and enums to + // static_cast. A cast from enum to integer may be unnecessary, but it's + // still retained. + if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) && + (DestType->isBuiltinType() || DestType->isEnumeralType())) { + ReplaceWithNamedCast("static_cast"); + return; + } + break; + case CK_BitCast: + // FIXME: Suggest const_cast<...>(reinterpret_cast<...>(...)) replacement. + if (!needsConstCast(SourceType, DestType)) { + if (SourceType->isVoidPointerType()) + ReplaceWithNamedCast("static_cast"); + else + ReplaceWithNamedCast("reinterpret_cast"); + return; + } + break; + default: + break; + } + + Diag << "static_cast/const_cast/reinterpret_cast"; +} + +} // namespace clang::tidy::google::readability diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidCStyleCastsCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidCStyleCastsCheck.h new file mode 100644 index 0000000000..485640d230 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidCStyleCastsCheck.h @@ -0,0 +1,38 @@ +//===--- AvoidCStyleCastsCheck.h - clang-tidy -------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDCSTYLECASTSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDCSTYLECASTSCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::readability { + +/// Finds usages of C-style casts. +/// +/// https://google.github.io/styleguide/cppguide.html#Casting +/// +/// Corresponding cpplint.py check name: 'readability/casting'. +/// +/// This check is similar to `-Wold-style-cast`, but it suggests automated fixes +/// in some cases. The reported locations should not be different from the +/// ones generated by `-Wold-style-cast`. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/readability-casting.html +class AvoidCStyleCastsCheck : public ClangTidyCheck { +public: + AvoidCStyleCastsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDCSTYLECASTSCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidNSObjectNewCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidNSObjectNewCheck.cpp new file mode 100644 index 0000000000..adcbf245ef --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidNSObjectNewCheck.cpp @@ -0,0 +1,123 @@ +//===--- AvoidNSObjectNewCheck.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 "AvoidNSObjectNewCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" +#include "llvm/Support/FormatVariadic.h" +#include <map> +#include <string> + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::objc { + +static bool isMessageExpressionInsideMacro(const ObjCMessageExpr *Expr) { + SourceLocation ReceiverLocation = Expr->getReceiverRange().getBegin(); + if (ReceiverLocation.isMacroID()) + return true; + + SourceLocation SelectorLocation = Expr->getSelectorStartLoc(); + if (SelectorLocation.isMacroID()) + return true; + + return false; +} + +// Walk up the class hierarchy looking for an -init method, returning true +// if one is found and has not been marked unavailable. +static bool isInitMethodAvailable(const ObjCInterfaceDecl *ClassDecl) { + while (ClassDecl != nullptr) { + for (const auto *MethodDecl : ClassDecl->instance_methods()) { + if (MethodDecl->getSelector().getAsString() == "init") + return !MethodDecl->isUnavailable(); + } + ClassDecl = ClassDecl->getSuperClass(); + } + + // No -init method found in the class hierarchy. This should occur only rarely + // in Objective-C code, and only really applies to classes not derived from + // NSObject. + return false; +} + +// Returns the string for the Objective-C message receiver. Keeps any generics +// included in the receiver class type, which are stripped if the class type is +// used. While the generics arguments will not make any difference to the +// returned code at this time, the style guide allows them and they should be +// left in any fix-it hint. +static StringRef getReceiverString(SourceRange ReceiverRange, + const SourceManager &SM, + const LangOptions &LangOpts) { + CharSourceRange CharRange = Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(ReceiverRange), SM, LangOpts); + return Lexer::getSourceText(CharRange, SM, LangOpts); +} + +static FixItHint getCallFixItHint(const ObjCMessageExpr *Expr, + const SourceManager &SM, + const LangOptions &LangOpts) { + // Check whether the messaged class has a known factory method to use instead + // of -init. + StringRef Receiver = + getReceiverString(Expr->getReceiverRange(), SM, LangOpts); + // Some classes should use standard factory methods instead of alloc/init. + std::map<StringRef, StringRef> ClassToFactoryMethodMap = {{"NSDate", "date"}, + {"NSNull", "null"}}; + auto FoundClassFactory = ClassToFactoryMethodMap.find(Receiver); + if (FoundClassFactory != ClassToFactoryMethodMap.end()) { + StringRef ClassName = FoundClassFactory->first; + StringRef FactorySelector = FoundClassFactory->second; + std::string NewCall = + std::string(llvm::formatv("[{0} {1}]", ClassName, FactorySelector)); + return FixItHint::CreateReplacement(Expr->getSourceRange(), NewCall); + } + + if (isInitMethodAvailable(Expr->getReceiverInterface())) { + std::string NewCall = + std::string(llvm::formatv("[[{0} alloc] init]", Receiver)); + return FixItHint::CreateReplacement(Expr->getSourceRange(), NewCall); + } + + return {}; // No known replacement available. +} + +void AvoidNSObjectNewCheck::registerMatchers(MatchFinder *Finder) { + // Add two matchers, to catch calls to +new and implementations of +new. + Finder->addMatcher( + objcMessageExpr(isClassMessage(), hasSelector("new")).bind("new_call"), + this); + Finder->addMatcher( + objcMethodDecl(isClassMethod(), isDefinition(), hasName("new")) + .bind("new_override"), + this); +} + +void AvoidNSObjectNewCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *CallExpr = + Result.Nodes.getNodeAs<ObjCMessageExpr>("new_call")) { + // Don't warn if the call expression originates from a macro expansion. + if (isMessageExpressionInsideMacro(CallExpr)) + return; + + diag(CallExpr->getExprLoc(), "do not create objects with +new") + << getCallFixItHint(CallExpr, *Result.SourceManager, + Result.Context->getLangOpts()); + } + + if (const auto *DeclExpr = + Result.Nodes.getNodeAs<ObjCMethodDecl>("new_override")) { + diag(DeclExpr->getBeginLoc(), "classes should not override +new"); + } +} + +} // namespace clang::tidy::google::objc diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidNSObjectNewCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidNSObjectNewCheck.h new file mode 100644 index 0000000000..37b9440396 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidNSObjectNewCheck.h @@ -0,0 +1,35 @@ +//===--- AvoidNSObjectNewCheck.h - clang-tidy -------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDNSOBJECTNEWCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDNSOBJECTNEWCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::objc { + +/// This check finds Objective-C code that uses +new to create object instances, +/// or overrides +new in classes. Both are forbidden by Google's Objective-C +/// style guide. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/objc-avoid-nsobject-new.html +class AvoidNSObjectNewCheck : public ClangTidyCheck { +public: + AvoidNSObjectNewCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.ObjC; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google::objc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDNSOBJECTNEWCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp new file mode 100644 index 0000000000..8346ef2a2a --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp @@ -0,0 +1,57 @@ +//===--- AvoidThrowingObjCExceptionCheck.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 "AvoidThrowingObjCExceptionCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::objc { + +void AvoidThrowingObjCExceptionCheck::registerMatchers(MatchFinder *Finder) { + + Finder->addMatcher(objcThrowStmt().bind("throwStmt"), this); + Finder->addMatcher( + objcMessageExpr(anyOf(hasSelector("raise:format:"), + hasSelector("raise:format:arguments:")), + hasReceiverType(asString("NSException"))) + .bind("raiseException"), + this); +} + +void AvoidThrowingObjCExceptionCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *MatchedStmt = + Result.Nodes.getNodeAs<ObjCAtThrowStmt>("throwStmt"); + const auto *MatchedExpr = + Result.Nodes.getNodeAs<ObjCMessageExpr>("raiseException"); + auto SourceLoc = MatchedStmt == nullptr ? MatchedExpr->getSelectorStartLoc() + : MatchedStmt->getThrowLoc(); + + // Early return on invalid locations. + if (SourceLoc.isInvalid()) + return; + + // If the match location was in a macro, check if the macro was in a system + // header. + if (SourceLoc.isMacroID()) { + SourceManager &SM = *Result.SourceManager; + auto MacroLoc = SM.getImmediateMacroCallerLoc(SourceLoc); + + // Matches in system header macros should be ignored. + if (SM.isInSystemHeader(MacroLoc)) + return; + } + + diag(SourceLoc, + "pass in NSError ** instead of throwing exception to indicate " + "Objective-C errors"); +} + +} // namespace clang::tidy::google::objc diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h new file mode 100644 index 0000000000..f8b191a376 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h @@ -0,0 +1,35 @@ +//===--- AvoidThrowingObjCExceptionCheck.h - clang-tidy----------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::objc { + +/// The check is to find usage of @throw invocation in Objective-C code. +/// We should avoid using @throw for Objective-C exceptions according to +/// the Google Objective-C Style Guide. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/objc-avoid-throwing-exception.html +class AvoidThrowingObjCExceptionCheck : public ClangTidyCheck { + public: + AvoidThrowingObjCExceptionCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.ObjC; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google::objc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.cpp new file mode 100644 index 0000000000..8ffcf47645 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.cpp @@ -0,0 +1,84 @@ +//===--- AvoidUnderscoreInGoogletestNameCheck.cpp - clang-tidy --*- C++ -*-===// +// +// 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 <string> + +#include "AvoidUnderscoreInGoogletestNameCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/MacroArgs.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" + +namespace clang::tidy::google::readability { + +constexpr llvm::StringLiteral KDisabledTestPrefix = "DISABLED_"; + +// Determines whether the macro is a Googletest test macro. +static bool isGoogletestTestMacro(StringRef MacroName) { + static const llvm::StringSet<> MacroNames = {"TEST", "TEST_F", "TEST_P", + "TYPED_TEST", "TYPED_TEST_P"}; + return MacroNames.find(MacroName) != MacroNames.end(); +} + +namespace { + +class AvoidUnderscoreInGoogletestNameCallback : public PPCallbacks { +public: + AvoidUnderscoreInGoogletestNameCallback( + Preprocessor *PP, AvoidUnderscoreInGoogletestNameCheck *Check) + : PP(PP), Check(Check) {} + + // Detects expansions of the TEST, TEST_F, TEST_P, TYPED_TEST, TYPED_TEST_P + // macros and checks that their arguments do not have any underscores. + void MacroExpands(const Token &MacroNameToken, + const MacroDefinition &MacroDefinition, SourceRange Range, + const MacroArgs *Args) override { + IdentifierInfo *NameIdentifierInfo = MacroNameToken.getIdentifierInfo(); + if (!NameIdentifierInfo) + return; + StringRef MacroName = NameIdentifierInfo->getName(); + if (!isGoogletestTestMacro(MacroName) || !Args || + Args->getNumMacroArguments() < 2) + return; + const Token *TestCaseNameToken = Args->getUnexpArgument(0); + const Token *TestNameToken = Args->getUnexpArgument(1); + if (!TestCaseNameToken || !TestNameToken) + return; + std::string TestCaseName = PP->getSpelling(*TestCaseNameToken); + if (TestCaseName.find('_') != std::string::npos) + Check->diag(TestCaseNameToken->getLocation(), + "avoid using \"_\" in test case name \"%0\" according to " + "Googletest FAQ") + << TestCaseName; + + std::string TestNameMaybeDisabled = PP->getSpelling(*TestNameToken); + StringRef TestName = TestNameMaybeDisabled; + TestName.consume_front(KDisabledTestPrefix); + if (TestName.contains('_')) + Check->diag(TestNameToken->getLocation(), + "avoid using \"_\" in test name \"%0\" according to " + "Googletest FAQ") + << TestName; + } + +private: + Preprocessor *PP; + AvoidUnderscoreInGoogletestNameCheck *Check; +}; + +} // namespace + +void AvoidUnderscoreInGoogletestNameCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + PP->addPPCallbacks( + std::make_unique<AvoidUnderscoreInGoogletestNameCallback>(PP, this)); +} + +} // namespace clang::tidy::google::readability diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.h new file mode 100644 index 0000000000..baec40e440 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/AvoidUnderscoreInGoogletestNameCheck.h @@ -0,0 +1,31 @@ +//===--- AvoidUnderscoreInGoogletestNameCheck.h - clang-tidy ----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDUNDERSCOREINGOOGLETESTNAMECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDUNDERSCOREINGOOGLETESTNAMECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::readability { + +// Check for underscores in the names of googletest tests, per +// https://google.github.io/googletest/faq.html#why-should-test-suite-names-and-test-names-not-contain-underscore +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/readability-avoid-underscore-in-googletest-name.html +class AvoidUnderscoreInGoogletestNameCheck : public ClangTidyCheck { +public: + using ClangTidyCheck::ClangTidyCheck; + + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; +}; + +} // namespace clang::tidy::google::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDUNDERSCOREINGOOGLETESTNAMECHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/DefaultArgumentsCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/DefaultArgumentsCheck.cpp new file mode 100644 index 0000000000..0b14a51c12 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/DefaultArgumentsCheck.cpp @@ -0,0 +1,31 @@ +//===--- DefaultArgumentsCheck.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 "DefaultArgumentsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google { + +void DefaultArgumentsCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + cxxMethodDecl(anyOf(isOverride(), isVirtual()), + hasAnyParameter(parmVarDecl(hasInitializer(expr())))) + .bind("Decl"), + this); +} + +void DefaultArgumentsCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("Decl"); + diag(MatchedDecl->getLocation(), + "default arguments on virtual or override methods are prohibited"); +} + +} // namespace clang::tidy::google diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/DefaultArgumentsCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/DefaultArgumentsCheck.h new file mode 100644 index 0000000000..a8f0b0112f --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/DefaultArgumentsCheck.h @@ -0,0 +1,32 @@ +//===--- DefaultArgumentsCheck.h - clang-tidy--------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google { + +/// Checks that default parameters are not given for virtual methods. +/// +/// See https://google.github.io/styleguide/cppguide.html#Default_Arguments +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/default-arguments.html +class DefaultArgumentsCheck : public ClangTidyCheck { +public: + DefaultArgumentsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitConstructorCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitConstructorCheck.cpp new file mode 100644 index 0000000000..f6b7ebca52 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitConstructorCheck.cpp @@ -0,0 +1,147 @@ +//===--- ExplicitConstructorCheck.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 "ExplicitConstructorCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google { + +void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + cxxConstructorDecl(unless(anyOf(isImplicit(), // Compiler-generated. + isDeleted(), isInstantiated()))) + .bind("ctor"), + this); + Finder->addMatcher( + cxxConversionDecl(unless(anyOf(isExplicit(), // Already marked explicit. + isImplicit(), // Compiler-generated. + isDeleted(), isInstantiated()))) + + .bind("conversion"), + this); +} + +// Looks for the token matching the predicate and returns the range of the found +// token including trailing whitespace. +static SourceRange findToken(const SourceManager &Sources, + const LangOptions &LangOpts, + SourceLocation StartLoc, SourceLocation EndLoc, + bool (*Pred)(const Token &)) { + if (StartLoc.isMacroID() || EndLoc.isMacroID()) + return SourceRange(); + FileID File = Sources.getFileID(Sources.getSpellingLoc(StartLoc)); + StringRef Buf = Sources.getBufferData(File); + const char *StartChar = Sources.getCharacterData(StartLoc); + Lexer Lex(StartLoc, LangOpts, StartChar, StartChar, Buf.end()); + Lex.SetCommentRetentionState(true); + Token Tok; + do { + Lex.LexFromRawLexer(Tok); + if (Pred(Tok)) { + Token NextTok; + Lex.LexFromRawLexer(NextTok); + return SourceRange(Tok.getLocation(), NextTok.getLocation()); + } + } while (Tok.isNot(tok::eof) && Tok.getLocation() < EndLoc); + + return SourceRange(); +} + +static bool declIsStdInitializerList(const NamedDecl *D) { + // First use the fast getName() method to avoid unnecessary calls to the + // slow getQualifiedNameAsString(). + return D->getName() == "initializer_list" && + D->getQualifiedNameAsString() == "std::initializer_list"; +} + +static bool isStdInitializerList(QualType Type) { + Type = Type.getCanonicalType(); + if (const auto *TS = Type->getAs<TemplateSpecializationType>()) { + if (const TemplateDecl *TD = TS->getTemplateName().getAsTemplateDecl()) + return declIsStdInitializerList(TD); + } + if (const auto *RT = Type->getAs<RecordType>()) { + if (const auto *Specialization = + dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl())) + return declIsStdInitializerList(Specialization->getSpecializedTemplate()); + } + return false; +} + +void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) { + constexpr char WarningMessage[] = + "%0 must be marked explicit to avoid unintentional implicit conversions"; + + if (const auto *Conversion = + Result.Nodes.getNodeAs<CXXConversionDecl>("conversion")) { + if (Conversion->isOutOfLine()) + return; + SourceLocation Loc = Conversion->getLocation(); + // Ignore all macros until we learn to ignore specific ones (e.g. used in + // gmock to define matchers). + if (Loc.isMacroID()) + return; + diag(Loc, WarningMessage) + << Conversion << FixItHint::CreateInsertion(Loc, "explicit "); + return; + } + + const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor"); + if (Ctor->isOutOfLine() || Ctor->getNumParams() == 0 || + Ctor->getMinRequiredArguments() > 1) + return; + + bool TakesInitializerList = isStdInitializerList( + Ctor->getParamDecl(0)->getType().getNonReferenceType()); + if (Ctor->isExplicit() && + (Ctor->isCopyOrMoveConstructor() || TakesInitializerList)) { + auto IsKwExplicit = [](const Token &Tok) { + return Tok.is(tok::raw_identifier) && + Tok.getRawIdentifier() == "explicit"; + }; + SourceRange ExplicitTokenRange = + findToken(*Result.SourceManager, getLangOpts(), + Ctor->getOuterLocStart(), Ctor->getEndLoc(), IsKwExplicit); + StringRef ConstructorDescription; + if (Ctor->isMoveConstructor()) + ConstructorDescription = "move"; + else if (Ctor->isCopyConstructor()) + ConstructorDescription = "copy"; + else + ConstructorDescription = "initializer-list"; + + auto Diag = diag(Ctor->getLocation(), + "%0 constructor should not be declared explicit") + << ConstructorDescription; + if (ExplicitTokenRange.isValid()) { + Diag << FixItHint::CreateRemoval( + CharSourceRange::getCharRange(ExplicitTokenRange)); + } + return; + } + + if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor() || + TakesInitializerList) + return; + + bool SingleArgument = + Ctor->getNumParams() == 1 && !Ctor->getParamDecl(0)->isParameterPack(); + SourceLocation Loc = Ctor->getLocation(); + diag(Loc, WarningMessage) + << (SingleArgument + ? "single-argument constructors" + : "constructors that are callable with a single argument") + << FixItHint::CreateInsertion(Loc, "explicit "); +} + +} // namespace clang::tidy::google diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitConstructorCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitConstructorCheck.h new file mode 100644 index 0000000000..e4434ac71d --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitConstructorCheck.h @@ -0,0 +1,35 @@ +//===--- ExplicitConstructorCheck.h - clang-tidy ----------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITCONSTRUCTORCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITCONSTRUCTORCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google { + +/// Checks that all single-argument constructors are explicit. +/// +/// See https://google.github.io/styleguide/cppguide.html#Explicit_Constructors +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/explicit-constructor.html +class ExplicitConstructorCheck : public ClangTidyCheck { +public: + ExplicitConstructorCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITCONSTRUCTORCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitMakePairCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitMakePairCheck.cpp new file mode 100644 index 0000000000..d911b58cb8 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitMakePairCheck.cpp @@ -0,0 +1,68 @@ +//===--- ExplicitMakePairCheck.cpp - clang-tidy -----------------*- C++ -*-===// +// +// 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 "ExplicitMakePairCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace { +AST_MATCHER(DeclRefExpr, hasExplicitTemplateArgs) { + return Node.hasExplicitTemplateArgs(); +} +} // namespace + +namespace tidy::google::build { + +void ExplicitMakePairCheck::registerMatchers( + ast_matchers::MatchFinder *Finder) { + // Look for std::make_pair with explicit template args. Ignore calls in + // templates. + Finder->addMatcher( + callExpr(unless(isInTemplateInstantiation()), + callee(expr(ignoringParenImpCasts( + declRefExpr(hasExplicitTemplateArgs(), + to(functionDecl(hasName("::std::make_pair")))) + .bind("declref"))))) + .bind("call"), + this); +} + +void ExplicitMakePairCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call"); + const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declref"); + + // Sanity check: The use might have overriden ::std::make_pair. + if (Call->getNumArgs() != 2) + return; + + const Expr *Arg0 = Call->getArg(0)->IgnoreParenImpCasts(); + const Expr *Arg1 = Call->getArg(1)->IgnoreParenImpCasts(); + + // If types don't match, we suggest replacing with std::pair and explicit + // template arguments. Otherwise just remove the template arguments from + // make_pair. + if (Arg0->getType() != Call->getArg(0)->getType() || + Arg1->getType() != Call->getArg(1)->getType()) { + diag(Call->getBeginLoc(), "for C++11-compatibility, use pair directly") + << FixItHint::CreateReplacement( + SourceRange(DeclRef->getBeginLoc(), DeclRef->getLAngleLoc()), + "std::pair<"); + } else { + diag(Call->getBeginLoc(), + "for C++11-compatibility, omit template arguments from make_pair") + << FixItHint::CreateRemoval( + SourceRange(DeclRef->getLAngleLoc(), DeclRef->getRAngleLoc())); + } +} + +} // namespace tidy::google::build +} // namespace clang diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitMakePairCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitMakePairCheck.h new file mode 100644 index 0000000000..2c796a2811 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/ExplicitMakePairCheck.h @@ -0,0 +1,38 @@ +//===--- ExplicitMakePairCheck.h - clang-tidy -------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITMAKEPAIRCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITMAKEPAIRCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::build { + +/// Check that `make_pair`'s template arguments are deduced. +/// +/// G++ 4.6 in C++11 mode fails badly if `make_pair`'s template arguments are +/// specified explicitly, and such use isn't intended in any case. +/// +/// Corresponding cpplint.py check name: 'build/explicit_make_pair'. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/build-explicit-make-pair.html +class ExplicitMakePairCheck : public ClangTidyCheck { +public: + ExplicitMakePairCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google::build + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITMAKEPAIRCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/FunctionNamingCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/FunctionNamingCheck.cpp new file mode 100644 index 0000000000..e42b4e9a1a --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/FunctionNamingCheck.cpp @@ -0,0 +1,117 @@ +//===--- FunctionNamingCheck.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 "FunctionNamingCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/Support/Regex.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::objc { + +namespace { + +std::string validFunctionNameRegex(bool RequirePrefix) { + // Allow the following name patterns for all functions: + // • ABFoo (prefix + UpperCamelCase) + // • ABURL (prefix + capitalized acronym/initialism) + // + // If no prefix is required, additionally allow the following name patterns: + // • Foo (UpperCamelCase) + // • URL (capitalized acronym/initialism) + // + // The function name following the prefix can contain standard and + // non-standard capitalized character sequences including acronyms, + // initialisms, and prefixes of symbols (e.g., UIColorFromNSString). For this + // reason, the regex only verifies that the function name after the prefix + // begins with a capital letter followed by an arbitrary sequence of + // alphanumeric characters. + // + // If a prefix is required, the regex checks for a capital letter followed by + // another capital letter or number that is part of the prefix and another + // capital letter or number that begins the name following the prefix. + std::string FunctionNameMatcher = + std::string(RequirePrefix ? "[A-Z][A-Z0-9]+" : "") + "[A-Z][a-zA-Z0-9]*"; + return std::string("::(") + FunctionNameMatcher + ")$"; +} + +/// For now we will only fix functions of static storage class with names like +/// 'functionName' or 'function_name' and convert them to 'FunctionName'. For +/// other cases the user must determine an appropriate name on their own. +FixItHint generateFixItHint(const FunctionDecl *Decl) { + // A fixit can be generated for functions of static storage class but + // otherwise the check cannot determine the appropriate function name prefix + // to use. + if (Decl->getStorageClass() != SC_Static) + return FixItHint(); + + StringRef Name = Decl->getName(); + std::string NewName = Decl->getName().str(); + + size_t Index = 0; + bool AtWordBoundary = true; + while (Index < NewName.size()) { + char Ch = NewName[Index]; + if (isalnum(Ch)) { + // Capitalize the first letter after every word boundary. + if (AtWordBoundary) { + NewName[Index] = toupper(NewName[Index]); + AtWordBoundary = false; + } + + // Advance the index after every alphanumeric character. + Index++; + } else { + // Strip out any characters other than alphanumeric characters. + NewName.erase(Index, 1); + AtWordBoundary = true; + } + } + + // Generate a fixit hint if the new name is different. + if (NewName != Name) + return FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())), + llvm::StringRef(NewName)); + + return FixItHint(); +} + +} // namespace + +void FunctionNamingCheck::registerMatchers(MatchFinder *Finder) { + // Enforce Objective-C function naming conventions on all functions except: + // • Functions defined in system headers. + // • C++ member functions. + // • Namespaced functions. + // • Implicitly defined functions. + // • The main function. + Finder->addMatcher( + functionDecl( + unless(anyOf(isExpansionInSystemHeader(), cxxMethodDecl(), + hasAncestor(namespaceDecl()), isMain(), isImplicit(), + matchesName(validFunctionNameRegex(true)), + allOf(isStaticStorageClass(), + matchesName(validFunctionNameRegex(false)))))) + .bind("function"), + this); +} + +void FunctionNamingCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("function"); + + bool IsGlobal = MatchedDecl->getStorageClass() != SC_Static; + diag(MatchedDecl->getLocation(), + "%select{static function|function in global namespace}1 named %0 must " + "%select{be in|have an appropriate prefix followed by}1 Pascal case as " + "required by Google Objective-C style guide") + << MatchedDecl << IsGlobal << generateFixItHint(MatchedDecl); +} + +} // namespace clang::tidy::google::objc diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/FunctionNamingCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/FunctionNamingCheck.h new file mode 100644 index 0000000000..560bb52f15 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/FunctionNamingCheck.h @@ -0,0 +1,39 @@ +//===--- FunctionNamingCheck.h - clang-tidy ---------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_FUNCTION_NAMING_CHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_FUNCTION_NAMING_CHECK_H + +#include "../ClangTidyCheck.h" +#include "llvm/ADT/StringRef.h" + +namespace clang::tidy::google::objc { + +/// Finds function names that do not conform to the recommendations of the +/// Google Objective-C Style Guide. Function names should be in upper camel case +/// including capitalized acronyms and initialisms. Functions that are not of +/// static storage class must also have an appropriate prefix. The function +/// `main` is an exception. Note that this check does not apply to Objective-C +/// method or property declarations. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/objc-function-naming.html +class FunctionNamingCheck : public ClangTidyCheck { +public: + FunctionNamingCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.ObjC; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google::objc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_FUNCTION_NAMING_CHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp new file mode 100644 index 0000000000..1c2a4e1cd3 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp @@ -0,0 +1,74 @@ +//===--- GlobalNamesInHeadersCheck.cpp - clang-tidy -----------------*- C++ -*-===// +// +// 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 "GlobalNamesInHeadersCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::readability { + +GlobalNamesInHeadersCheck::GlobalNamesInHeadersCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + RawStringHeaderFileExtensions(Options.getLocalOrGlobal( + "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { + if (!utils::parseFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, + utils::defaultFileExtensionDelimiters())) { + this->configurationDiag("Invalid header file extension: '%0'") + << RawStringHeaderFileExtensions; + } +} + +void GlobalNamesInHeadersCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions); +} + +void GlobalNamesInHeadersCheck::registerMatchers( + ast_matchers::MatchFinder *Finder) { + Finder->addMatcher(decl(anyOf(usingDecl(), usingDirectiveDecl()), + hasDeclContext(translationUnitDecl())) + .bind("using_decl"), + this); +} + +void GlobalNamesInHeadersCheck::check(const MatchFinder::MatchResult &Result) { + const auto *D = Result.Nodes.getNodeAs<Decl>("using_decl"); + // If it comes from a macro, we'll assume it is fine. + if (D->getBeginLoc().isMacroID()) + return; + + // Ignore if it comes from the "main" file ... + if (Result.SourceManager->isInMainFile( + Result.SourceManager->getExpansionLoc(D->getBeginLoc()))) { + // unless that file is a header. + if (!utils::isSpellingLocInHeaderFile( + D->getBeginLoc(), *Result.SourceManager, HeaderFileExtensions)) + return; + } + + if (const auto *UsingDirective = dyn_cast<UsingDirectiveDecl>(D)) { + if (UsingDirective->getNominatedNamespace()->isAnonymousNamespace()) { + // Anonymous namespaces inject a using directive into the AST to import + // the names into the containing namespace. + // We should not have them in headers, but there is another warning for + // that. + return; + } + } + + diag(D->getBeginLoc(), + "using declarations in the global namespace in headers are prohibited"); +} + +} // namespace clang::tidy::google::readability diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalNamesInHeadersCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalNamesInHeadersCheck.h new file mode 100644 index 0000000000..a152e2c360 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalNamesInHeadersCheck.h @@ -0,0 +1,44 @@ +//===--- GlobalNamesInHeadersCheck.h - clang-tidy ---------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBALNAMESINHEADERSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBALNAMESINHEADERSCHECK_H + +#include "../ClangTidyCheck.h" +#include "../utils/FileExtensionsUtils.h" + +namespace clang::tidy::google::readability { + +/// Flag global namespace pollution in header files. +/// Right now it only triggers on using declarations and directives. +/// +/// The check supports these options: +/// - `HeaderFileExtensions`: a semicolon-separated list of filename +/// extensions of header files (the filename extensions should not contain +/// "." prefix). ";h;hh;hpp;hxx" by default. +/// +/// For extension-less header files, using an empty string or leaving an +/// empty string between ";" if there are other filename extensions. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/global-names-in-headers.html +class GlobalNamesInHeadersCheck : public ClangTidyCheck { +public: + GlobalNamesInHeadersCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + const StringRef RawStringHeaderFileExtensions; + utils::FileExtensionsSet HeaderFileExtensions; +}; + +} // namespace clang::tidy::google::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBALNAMESINHEADERSCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalVariableDeclarationCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalVariableDeclarationCheck.cpp new file mode 100644 index 0000000000..a2a728f3b3 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalVariableDeclarationCheck.cpp @@ -0,0 +1,98 @@ +//===--- GlobalVariableDeclarationCheck.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 "GlobalVariableDeclarationCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" + +#include <string> + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::objc { + +namespace { + +AST_MATCHER(VarDecl, isLocalVariable) { return Node.isLocalVarDecl(); } + +FixItHint generateFixItHint(const VarDecl *Decl, bool IsConst) { + if (IsConst && (Decl->getStorageClass() != SC_Static)) { + // No fix available if it is not a static constant, since it is difficult + // to determine the proper fix in this case. + return FixItHint(); + } + + char FC = Decl->getName()[0]; + if (!llvm::isAlpha(FC) || Decl->getName().size() == 1) { + // No fix available if first character is not alphabetical character, or it + // is a single-character variable, since it is difficult to determine the + // proper fix in this case. Users should create a proper variable name by + // their own. + return FixItHint(); + } + char SC = Decl->getName()[1]; + if ((FC == 'k' || FC == 'g') && !llvm::isAlpha(SC)) { + // No fix available if the prefix is correct but the second character is + // not alphabetical, since it is difficult to determine the proper fix in + // this case. + return FixItHint(); + } + + auto NewName = (IsConst ? "k" : "g") + + llvm::StringRef(std::string(1, FC)).upper() + + Decl->getName().substr(1).str(); + + return FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())), + llvm::StringRef(NewName)); +} +} // namespace + +void GlobalVariableDeclarationCheck::registerMatchers(MatchFinder *Finder) { + // need to add two matchers since we need to bind different ids to distinguish + // constants and variables. Since bind() can only be called on node matchers, + // we cannot make it in one matcher. + // + // Note that hasGlobalStorage() matches static variables declared locally + // inside a function or method, so we need to exclude those with + // isLocalVariable(). + Finder->addMatcher( + varDecl(hasGlobalStorage(), unless(hasType(isConstQualified())), + unless(isLocalVariable()), unless(matchesName("::g[A-Z]"))) + .bind("global_var"), + this); + Finder->addMatcher(varDecl(hasGlobalStorage(), hasType(isConstQualified()), + unless(isLocalVariable()), + unless(matchesName("::(k[A-Z])|([A-Z][A-Z0-9])"))) + .bind("global_const"), + this); +} + +void GlobalVariableDeclarationCheck::check( + const MatchFinder::MatchResult &Result) { + if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("global_var")) { + if (Decl->isStaticDataMember()) + return; + diag(Decl->getLocation(), + "non-const global variable '%0' must have a name which starts with " + "'g[A-Z]'") + << Decl->getName() << generateFixItHint(Decl, false); + } + if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("global_const")) { + if (Decl->isStaticDataMember()) + return; + diag(Decl->getLocation(), + "const global variable '%0' must have a name which starts with " + "an appropriate prefix") + << Decl->getName() << generateFixItHint(Decl, true); + } +} + +} // namespace clang::tidy::google::objc diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalVariableDeclarationCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalVariableDeclarationCheck.h new file mode 100644 index 0000000000..550224b26d --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/GlobalVariableDeclarationCheck.h @@ -0,0 +1,35 @@ +//===--- GlobalVariableDeclarationCheck.h - clang-tidy-----------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_GLOBAL_VARIABLE_DECLARATION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_GLOBAL_VARIABLE_DECLARATION_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::objc { + +/// The check for Objective-C global variables and constants naming convention. +/// The declaration should follow the patterns of 'k[A-Z].*' (constants) or +/// 'g[A-Z].*' (variables). +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/objc-global-variable-declaration.html +class GlobalVariableDeclarationCheck : public ClangTidyCheck { + public: + GlobalVariableDeclarationCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.ObjC; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google::objc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_GLOBAL_VARIABLE_DECLARATION_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/GoogleTidyModule.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/GoogleTidyModule.cpp new file mode 100644 index 0000000000..830a37af1a --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/GoogleTidyModule.cpp @@ -0,0 +1,105 @@ +//===--- GoogleTidyModule.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 "../ClangTidy.h" +#include "../ClangTidyModule.h" +#include "../ClangTidyModuleRegistry.h" +#include "../readability/BracesAroundStatementsCheck.h" +#include "../readability/FunctionSizeCheck.h" +#include "../readability/NamespaceCommentCheck.h" +#include "AvoidCStyleCastsCheck.h" +#include "AvoidNSObjectNewCheck.h" +#include "AvoidThrowingObjCExceptionCheck.h" +#include "AvoidUnderscoreInGoogletestNameCheck.h" +#include "DefaultArgumentsCheck.h" +#include "ExplicitConstructorCheck.h" +#include "ExplicitMakePairCheck.h" +#include "FunctionNamingCheck.h" +#include "GlobalNamesInHeadersCheck.h" +#include "GlobalVariableDeclarationCheck.h" +#include "IntegerTypesCheck.h" +#include "OverloadedUnaryAndCheck.h" +#include "TodoCommentCheck.h" +#include "UnnamedNamespaceInHeaderCheck.h" +#include "UpgradeGoogletestCaseCheck.h" +#include "UsingNamespaceDirectiveCheck.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy { +namespace google { + +class GoogleModule : public ClangTidyModule { + public: + void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck<build::ExplicitMakePairCheck>( + "google-build-explicit-make-pair"); + CheckFactories.registerCheck<build::UnnamedNamespaceInHeaderCheck>( + "google-build-namespaces"); + CheckFactories.registerCheck<build::UsingNamespaceDirectiveCheck>( + "google-build-using-namespace"); + CheckFactories.registerCheck<DefaultArgumentsCheck>( + "google-default-arguments"); + CheckFactories.registerCheck<ExplicitConstructorCheck>( + "google-explicit-constructor"); + CheckFactories.registerCheck<readability::GlobalNamesInHeadersCheck>( + "google-global-names-in-headers"); + CheckFactories.registerCheck<objc::AvoidNSObjectNewCheck>( + "google-objc-avoid-nsobject-new"); + CheckFactories.registerCheck<objc::AvoidThrowingObjCExceptionCheck>( + "google-objc-avoid-throwing-exception"); + CheckFactories.registerCheck<objc::FunctionNamingCheck>( + "google-objc-function-naming"); + CheckFactories.registerCheck<objc::GlobalVariableDeclarationCheck>( + "google-objc-global-variable-declaration"); + CheckFactories.registerCheck<runtime::IntegerTypesCheck>( + "google-runtime-int"); + CheckFactories.registerCheck<runtime::OverloadedUnaryAndCheck>( + "google-runtime-operator"); + CheckFactories + .registerCheck<readability::AvoidUnderscoreInGoogletestNameCheck>( + "google-readability-avoid-underscore-in-googletest-name"); + CheckFactories.registerCheck<readability::AvoidCStyleCastsCheck>( + "google-readability-casting"); + CheckFactories.registerCheck<readability::TodoCommentCheck>( + "google-readability-todo"); + CheckFactories + .registerCheck<clang::tidy::readability::BracesAroundStatementsCheck>( + "google-readability-braces-around-statements"); + CheckFactories.registerCheck<clang::tidy::readability::FunctionSizeCheck>( + "google-readability-function-size"); + CheckFactories + .registerCheck<clang::tidy::readability::NamespaceCommentCheck>( + "google-readability-namespace-comments"); + CheckFactories.registerCheck<UpgradeGoogletestCaseCheck>( + "google-upgrade-googletest-case"); + } + + ClangTidyOptions getModuleOptions() override { + ClangTidyOptions Options; + auto &Opts = Options.CheckOptions; + Opts["google-readability-braces-around-statements.ShortStatementLines"] = + "1"; + Opts["google-readability-function-size.StatementThreshold"] = "800"; + Opts["google-readability-namespace-comments.ShortNamespaceLines"] = "10"; + Opts["google-readability-namespace-comments.SpacesBeforeComments"] = "2"; + return Options; + } +}; + +// Register the GoogleTidyModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add<GoogleModule> X("google-module", + "Adds Google lint checks."); + +} // namespace google + +// This anchor is used to force the linker to link in the generated object file +// and thus register the GoogleModule. +volatile int GoogleModuleAnchorSource = 0; + +} // namespace clang::tidy diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/IntegerTypesCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/IntegerTypesCheck.cpp new file mode 100644 index 0000000000..53c6f5aa79 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/IntegerTypesCheck.cpp @@ -0,0 +1,146 @@ +//===--- IntegerTypesCheck.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 "IntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/AttrKinds.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Lexer.h" + +namespace clang { + +using namespace ast_matchers; + +static Token getTokenAtLoc(SourceLocation Loc, + const MatchFinder::MatchResult &MatchResult, + IdentifierTable &IdentTable) { + Token Tok; + if (Lexer::getRawToken(Loc, Tok, *MatchResult.SourceManager, + MatchResult.Context->getLangOpts(), false)) + return Tok; + + if (Tok.is(tok::raw_identifier)) { + IdentifierInfo &Info = IdentTable.get(Tok.getRawIdentifier()); + Tok.setIdentifierInfo(&Info); + Tok.setKind(Info.getTokenID()); + } + return Tok; +} + +namespace tidy::google::runtime { + +IntegerTypesCheck::IntegerTypesCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + UnsignedTypePrefix(Options.get("UnsignedTypePrefix", "uint")), + SignedTypePrefix(Options.get("SignedTypePrefix", "int")), + TypeSuffix(Options.get("TypeSuffix", "")) {} + +void IntegerTypesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "UnsignedTypePrefix", UnsignedTypePrefix); + Options.store(Opts, "SignedTypePrefix", SignedTypePrefix); + Options.store(Opts, "TypeSuffix", TypeSuffix); +} + +void IntegerTypesCheck::registerMatchers(MatchFinder *Finder) { + // Match any integer types, unless they are passed to a printf-based API: + // + // http://google.github.io/styleguide/cppguide.html#64-bit_Portability + // "Where possible, avoid passing arguments of types specified by + // bitwidth typedefs to printf-based APIs." + Finder->addMatcher(typeLoc(loc(isInteger()), + unless(hasAncestor(callExpr( + callee(functionDecl(hasAttr(attr::Format))))))) + .bind("tl"), + this); + IdentTable = std::make_unique<IdentifierTable>(getLangOpts()); +} + +void IntegerTypesCheck::check(const MatchFinder::MatchResult &Result) { + auto TL = *Result.Nodes.getNodeAs<TypeLoc>("tl"); + SourceLocation Loc = TL.getBeginLoc(); + + if (Loc.isInvalid() || Loc.isMacroID()) + return; + + // Look through qualification. + if (auto QualLoc = TL.getAs<QualifiedTypeLoc>()) + TL = QualLoc.getUnqualifiedLoc(); + + auto BuiltinLoc = TL.getAs<BuiltinTypeLoc>(); + if (!BuiltinLoc) + return; + + Token Tok = getTokenAtLoc(Loc, Result, *IdentTable); + // Ensure the location actually points to one of the builting integral type + // names we're interested in. Otherwise, we might be getting this match from + // implicit code (e.g. an implicit assignment operator of a class containing + // an array of non-POD types). + if (!Tok.isOneOf(tok::kw_short, tok::kw_long, tok::kw_unsigned, + tok::kw_signed)) + return; + + bool IsSigned; + unsigned Width; + const TargetInfo &TargetInfo = Result.Context->getTargetInfo(); + + // Look for uses of short, long, long long and their unsigned versions. + switch (BuiltinLoc.getTypePtr()->getKind()) { + case BuiltinType::Short: + Width = TargetInfo.getShortWidth(); + IsSigned = true; + break; + case BuiltinType::Long: + Width = TargetInfo.getLongWidth(); + IsSigned = true; + break; + case BuiltinType::LongLong: + Width = TargetInfo.getLongLongWidth(); + IsSigned = true; + break; + case BuiltinType::UShort: + Width = TargetInfo.getShortWidth(); + IsSigned = false; + break; + case BuiltinType::ULong: + Width = TargetInfo.getLongWidth(); + IsSigned = false; + break; + case BuiltinType::ULongLong: + Width = TargetInfo.getLongLongWidth(); + IsSigned = false; + break; + default: + return; + } + + // We allow "unsigned short port" as that's reasonably common and required by + // the sockets API. + const StringRef Port = "unsigned short port"; + const char *Data = Result.SourceManager->getCharacterData(Loc); + if (!std::strncmp(Data, Port.data(), Port.size()) && + !isAsciiIdentifierContinue(Data[Port.size()])) + return; + + std::string Replacement = + ((IsSigned ? SignedTypePrefix : UnsignedTypePrefix) + Twine(Width) + + TypeSuffix) + .str(); + + // We don't add a fix-it as changing the type can easily break code, + // e.g. when a function requires a 'long' argument on all platforms. + // QualTypes are printed with implicit quotes. + diag(Loc, "consider replacing %0 with '%1'") << BuiltinLoc.getType() + << Replacement; +} + +} // namespace tidy::google::runtime +} // namespace clang diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/IntegerTypesCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/IntegerTypesCheck.h new file mode 100644 index 0000000000..e7c3f659bf --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/IntegerTypesCheck.h @@ -0,0 +1,50 @@ +//===--- IntegerTypesCheck.h - clang-tidy -----------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_INTEGERTYPESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_INTEGERTYPESCHECK_H + +#include "../ClangTidyCheck.h" + +#include <memory> + +namespace clang { + +class IdentifierTable; + +namespace tidy::google::runtime { + +/// Finds uses of `short`, `long` and `long long` and suggest replacing them +/// with `u?intXX(_t)?`. +/// +/// Corresponding cpplint.py check: 'runtime/int'. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/runtime-int.html +class IntegerTypesCheck : public ClangTidyCheck { +public: + IntegerTypesCheck(StringRef Name, ClangTidyContext *Context); + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus && !LangOpts.ObjC; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Options) override; + +private: + const StringRef UnsignedTypePrefix; + const StringRef SignedTypePrefix; + const StringRef TypeSuffix; + + std::unique_ptr<IdentifierTable> IdentTable; +}; + +} // namespace tidy::google::runtime +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_INTEGERTYPESCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/OverloadedUnaryAndCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/OverloadedUnaryAndCheck.cpp new file mode 100644 index 0000000000..a7536607e5 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/OverloadedUnaryAndCheck.cpp @@ -0,0 +1,39 @@ +//===--- OverloadedUnaryAndCheck.cpp - clang-tidy ---------------*- C++ -*-===// +// +// 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 "OverloadedUnaryAndCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::runtime { + +void OverloadedUnaryAndCheck::registerMatchers( + ast_matchers::MatchFinder *Finder) { + // Match unary methods that overload operator&. + Finder->addMatcher( + cxxMethodDecl(parameterCountIs(0), hasOverloadedOperatorName("&")) + .bind("overload"), + this); + // Also match freestanding unary operator& overloads. Be careful not to match + // binary methods. + Finder->addMatcher(functionDecl(unless(cxxMethodDecl()), parameterCountIs(1), + hasOverloadedOperatorName("&")) + .bind("overload"), + this); +} + +void OverloadedUnaryAndCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Decl = Result.Nodes.getNodeAs<FunctionDecl>("overload"); + diag(Decl->getBeginLoc(), + "do not overload unary operator&, it is dangerous."); +} + +} // namespace clang::tidy::google::runtime diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/OverloadedUnaryAndCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/OverloadedUnaryAndCheck.h new file mode 100644 index 0000000000..3c3b668754 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/OverloadedUnaryAndCheck.h @@ -0,0 +1,37 @@ +//===--- OverloadedUnaryAndCheck.h - clang-tidy -----------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OVERLOADEDUNARYANDCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OVERLOADEDUNARYANDCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::runtime { + +/// Finds overloads of unary `operator &`. +/// +/// https://google.github.io/styleguide/cppguide.html#Operator_Overloading +/// +/// Corresponding cpplint.py check name: 'runtime/operator'. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/runtime-operator.html +class OverloadedUnaryAndCheck : public ClangTidyCheck { +public: + OverloadedUnaryAndCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::google::runtime + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OVERLOADEDUNARYANDCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/TodoCommentCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/TodoCommentCheck.cpp new file mode 100644 index 0000000000..adad54aa24 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/TodoCommentCheck.cpp @@ -0,0 +1,64 @@ +//===--- TodoCommentCheck.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 "TodoCommentCheck.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Preprocessor.h" +#include <optional> + +namespace clang::tidy::google::readability { + +class TodoCommentCheck::TodoCommentHandler : public CommentHandler { +public: + TodoCommentHandler(TodoCommentCheck &Check, std::optional<std::string> User) + : Check(Check), User(User ? *User : "unknown"), + TodoMatch("^// *TODO *(\\(.*\\))?:?( )?(.*)$") {} + + bool HandleComment(Preprocessor &PP, SourceRange Range) override { + StringRef Text = + Lexer::getSourceText(CharSourceRange::getCharRange(Range), + PP.getSourceManager(), PP.getLangOpts()); + + SmallVector<StringRef, 4> Matches; + if (!TodoMatch.match(Text, &Matches)) + return false; + + StringRef Username = Matches[1]; + StringRef Comment = Matches[3]; + + if (!Username.empty()) + return false; + + std::string NewText = ("// TODO(" + Twine(User) + "): " + Comment).str(); + + Check.diag(Range.getBegin(), "missing username/bug in TODO") + << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Range), + NewText); + return false; + } + +private: + TodoCommentCheck &Check; + std::string User; + llvm::Regex TodoMatch; +}; + +TodoCommentCheck::TodoCommentCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + Handler(std::make_unique<TodoCommentHandler>( + *this, Context->getOptions().User)) {} + +TodoCommentCheck::~TodoCommentCheck() = default; + +void TodoCommentCheck::registerPPCallbacks(const SourceManager &SM, + Preprocessor *PP, + Preprocessor *ModuleExpanderPP) { + PP->addCommentHandler(Handler.get()); +} + +} // namespace clang::tidy::google::readability diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/TodoCommentCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/TodoCommentCheck.h new file mode 100644 index 0000000000..de540d810a --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/TodoCommentCheck.h @@ -0,0 +1,37 @@ +//===--- TodoCommentCheck.h - clang-tidy ------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_TODOCOMMENTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_TODOCOMMENTCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::readability { + +/// Finds TODO comments without a username or bug number. +/// +/// Corresponding cpplint.py check: 'readability/todo' +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/readability-todo.html +class TodoCommentCheck : public ClangTidyCheck { +public: + TodoCommentCheck(StringRef Name, ClangTidyContext *Context); + ~TodoCommentCheck(); + + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + +private: + class TodoCommentHandler; + std::unique_ptr<TodoCommentHandler> Handler; +}; + +} // namespace clang::tidy::google::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_TODOCOMMENTCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp new file mode 100644 index 0000000000..72de9c1e94 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp @@ -0,0 +1,54 @@ +//===--- UnnamedNamespaceInHeaderCheck.cpp - clang-tidy ---------*- C++ -*-===// +// +// 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 "UnnamedNamespaceInHeaderCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::build { + +UnnamedNamespaceInHeaderCheck::UnnamedNamespaceInHeaderCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + RawStringHeaderFileExtensions(Options.getLocalOrGlobal( + "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { + if (!utils::parseFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, + utils::defaultFileExtensionDelimiters())) { + this->configurationDiag("Invalid header file extension: '%0'") + << RawStringHeaderFileExtensions; + } +} + +void UnnamedNamespaceInHeaderCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions); +} + +void UnnamedNamespaceInHeaderCheck::registerMatchers( + ast_matchers::MatchFinder *Finder) { + Finder->addMatcher(namespaceDecl(isAnonymous()).bind("anonymousNamespace"), + this); +} + +void UnnamedNamespaceInHeaderCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *N = Result.Nodes.getNodeAs<NamespaceDecl>("anonymousNamespace"); + SourceLocation Loc = N->getBeginLoc(); + if (!Loc.isValid()) + return; + + if (utils::isPresumedLocInHeaderFile(Loc, *Result.SourceManager, + HeaderFileExtensions)) + diag(Loc, "do not use unnamed namespaces in header files"); +} + +} // namespace clang::tidy::google::build diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h new file mode 100644 index 0000000000..ac26746a47 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h @@ -0,0 +1,50 @@ +//===--- UnnamedNamespaceInHeaderCheck.h - clang-tidy -----------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UNNAMEDNAMESPACEINHEADERCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UNNAMEDNAMESPACEINHEADERCHECK_H + +#include "../ClangTidyCheck.h" +#include "../utils/FileExtensionsUtils.h" + +namespace clang::tidy::google::build { + +/// Finds anonymous namespaces in headers. +/// +/// The check supports these options: +/// - `HeaderFileExtensions`: a semicolon-separated list of filename +/// extensions of header files (The filename extensions should not contain +/// "." prefix). ";h;hh;hpp;hxx" by default. +/// +/// For extension-less header files, using an empty string or leaving an +/// empty string between ";" if there are other filename extensions. +/// +/// https://google.github.io/styleguide/cppguide.html#Namespaces +/// +/// Corresponding cpplint.py check name: 'build/namespaces'. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/build-namespaces.html +class UnnamedNamespaceInHeaderCheck : public ClangTidyCheck { +public: + UnnamedNamespaceInHeaderCheck(StringRef Name, ClangTidyContext *Context); + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + const StringRef RawStringHeaderFileExtensions; + utils::FileExtensionsSet HeaderFileExtensions; +}; + +} // namespace clang::tidy::google::build + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UNNAMEDNAMESPACEINHEADERCHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp new file mode 100644 index 0000000000..e7b4f9d665 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp @@ -0,0 +1,351 @@ +//===--- UpgradeGoogletestCaseCheck.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 "UpgradeGoogletestCaseCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include <optional> + +using namespace clang::ast_matchers; + +namespace clang::tidy::google { + +static const llvm::StringRef RenameCaseToSuiteMessage = + "Google Test APIs named with 'case' are deprecated; use equivalent APIs " + "named with 'suite'"; + +static std::optional<llvm::StringRef> +getNewMacroName(llvm::StringRef MacroName) { + std::pair<llvm::StringRef, llvm::StringRef> ReplacementMap[] = { + {"TYPED_TEST_CASE", "TYPED_TEST_SUITE"}, + {"TYPED_TEST_CASE_P", "TYPED_TEST_SUITE_P"}, + {"REGISTER_TYPED_TEST_CASE_P", "REGISTER_TYPED_TEST_SUITE_P"}, + {"INSTANTIATE_TYPED_TEST_CASE_P", "INSTANTIATE_TYPED_TEST_SUITE_P"}, + {"INSTANTIATE_TEST_CASE_P", "INSTANTIATE_TEST_SUITE_P"}, + }; + + for (auto &Mapping : ReplacementMap) { + if (MacroName == Mapping.first) + return Mapping.second; + } + + return std::nullopt; +} + +namespace { + +class UpgradeGoogletestCasePPCallback : public PPCallbacks { +public: + UpgradeGoogletestCasePPCallback(UpgradeGoogletestCaseCheck *Check, + Preprocessor *PP) + : ReplacementFound(false), Check(Check), PP(PP) {} + + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *) override { + macroUsed(MacroNameTok, MD, Range.getBegin(), CheckAction::Rename); + } + + void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, + const MacroDirective *Undef) override { + if (Undef != nullptr) + macroUsed(MacroNameTok, MD, Undef->getLocation(), CheckAction::Warn); + } + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + if (!ReplacementFound && MD != nullptr) { + // We check if the newly defined macro is one of the target replacements. + // This ensures that the check creates warnings only if it is including a + // recent enough version of Google Test. + llvm::StringRef FileName = PP->getSourceManager().getFilename( + MD->getMacroInfo()->getDefinitionLoc()); + ReplacementFound = FileName.endswith("gtest/gtest-typed-test.h") && + PP->getSpelling(MacroNameTok) == "TYPED_TEST_SUITE"; + } + } + + void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) override { + macroUsed(MacroNameTok, MD, Range.getBegin(), CheckAction::Warn); + } + + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + macroUsed(MacroNameTok, MD, Loc, CheckAction::Warn); + } + + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + macroUsed(MacroNameTok, MD, Loc, CheckAction::Warn); + } + +private: + enum class CheckAction { Warn, Rename }; + + void macroUsed(const clang::Token &MacroNameTok, const MacroDefinition &MD, + SourceLocation Loc, CheckAction Action) { + if (!ReplacementFound) + return; + + std::string Name = PP->getSpelling(MacroNameTok); + + std::optional<llvm::StringRef> Replacement = getNewMacroName(Name); + if (!Replacement) + return; + + llvm::StringRef FileName = PP->getSourceManager().getFilename( + MD.getMacroInfo()->getDefinitionLoc()); + if (!FileName.endswith("gtest/gtest-typed-test.h")) + return; + + DiagnosticBuilder Diag = Check->diag(Loc, RenameCaseToSuiteMessage); + + if (Action == CheckAction::Rename) + Diag << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(Loc, Loc), *Replacement); + } + + bool ReplacementFound; + UpgradeGoogletestCaseCheck *Check; + Preprocessor *PP; +}; + +} // namespace + +void UpgradeGoogletestCaseCheck::registerPPCallbacks(const SourceManager &, + Preprocessor *PP, + Preprocessor *) { + PP->addPPCallbacks( + std::make_unique<UpgradeGoogletestCasePPCallback>(this, PP)); +} + +void UpgradeGoogletestCaseCheck::registerMatchers(MatchFinder *Finder) { + auto LocationFilter = + unless(isExpansionInFileMatching("gtest/gtest(-typed-test)?\\.h$")); + + // Matchers for the member functions that are being renamed. In each matched + // Google Test class, we check for the existence of one new method name. This + // makes sure the check gives warnings only if the included version of Google + // Test is recent enough. + auto Methods = + cxxMethodDecl( + anyOf( + cxxMethodDecl( + hasAnyName("SetUpTestCase", "TearDownTestCase"), + ofClass( + cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl( + hasName("::testing::Test"), + hasMethod(hasName("SetUpTestSuite"))))) + .bind("class"))), + cxxMethodDecl( + hasName("test_case_name"), + ofClass( + cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl( + hasName("::testing::TestInfo"), + hasMethod(hasName("test_suite_name"))))) + .bind("class"))), + cxxMethodDecl( + hasAnyName("OnTestCaseStart", "OnTestCaseEnd"), + ofClass(cxxRecordDecl( + isSameOrDerivedFrom(cxxRecordDecl( + hasName("::testing::TestEventListener"), + hasMethod(hasName("OnTestSuiteStart"))))) + .bind("class"))), + cxxMethodDecl( + hasAnyName("current_test_case", "successful_test_case_count", + "failed_test_case_count", "total_test_case_count", + "test_case_to_run_count", "GetTestCase"), + ofClass(cxxRecordDecl( + isSameOrDerivedFrom(cxxRecordDecl( + hasName("::testing::UnitTest"), + hasMethod(hasName("current_test_suite"))))) + .bind("class"))))) + .bind("method"); + + Finder->addMatcher(expr(anyOf(callExpr(callee(Methods)).bind("call"), + declRefExpr(to(Methods)).bind("ref")), + LocationFilter), + this); + + Finder->addMatcher( + usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(Methods)), LocationFilter) + .bind("using"), + this); + + Finder->addMatcher(cxxMethodDecl(Methods, LocationFilter), this); + + // Matchers for `TestCase` -> `TestSuite`. The fact that `TestCase` is an + // alias and not a class declaration ensures we only match with a recent + // enough version of Google Test. + auto TestCaseTypeAlias = + typeAliasDecl(hasName("::testing::TestCase")).bind("test-case"); + Finder->addMatcher( + typeLoc(loc(qualType(typedefType(hasDeclaration(TestCaseTypeAlias)))), + unless(hasAncestor(decl(isImplicit()))), LocationFilter) + .bind("typeloc"), + this); + Finder->addMatcher( + usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(TestCaseTypeAlias))) + .bind("using"), + this); + Finder->addMatcher( + typeLoc(loc(usingType(hasUnderlyingType( + typedefType(hasDeclaration(TestCaseTypeAlias))))), + unless(hasAncestor(decl(isImplicit()))), LocationFilter) + .bind("typeloc"), + this); +} + +static llvm::StringRef getNewMethodName(llvm::StringRef CurrentName) { + std::pair<llvm::StringRef, llvm::StringRef> ReplacementMap[] = { + {"SetUpTestCase", "SetUpTestSuite"}, + {"TearDownTestCase", "TearDownTestSuite"}, + {"test_case_name", "test_suite_name"}, + {"OnTestCaseStart", "OnTestSuiteStart"}, + {"OnTestCaseEnd", "OnTestSuiteEnd"}, + {"current_test_case", "current_test_suite"}, + {"successful_test_case_count", "successful_test_suite_count"}, + {"failed_test_case_count", "failed_test_suite_count"}, + {"total_test_case_count", "total_test_suite_count"}, + {"test_case_to_run_count", "test_suite_to_run_count"}, + {"GetTestCase", "GetTestSuite"}}; + + for (auto &Mapping : ReplacementMap) { + if (CurrentName == Mapping.first) + return Mapping.second; + } + + llvm_unreachable("Unexpected function name"); +} + +template <typename NodeType> +static bool isInInstantiation(const NodeType &Node, + const MatchFinder::MatchResult &Result) { + return !match(isInTemplateInstantiation(), Node, *Result.Context).empty(); +} + +template <typename NodeType> +static bool isInTemplate(const NodeType &Node, + const MatchFinder::MatchResult &Result) { + internal::Matcher<NodeType> IsInsideTemplate = + hasAncestor(decl(anyOf(classTemplateDecl(), functionTemplateDecl()))); + return !match(IsInsideTemplate, Node, *Result.Context).empty(); +} + +static bool +derivedTypeHasReplacementMethod(const MatchFinder::MatchResult &Result, + llvm::StringRef ReplacementMethod) { + const auto *Class = Result.Nodes.getNodeAs<CXXRecordDecl>("class"); + return !match(cxxRecordDecl( + unless(isExpansionInFileMatching( + "gtest/gtest(-typed-test)?\\.h$")), + hasMethod(cxxMethodDecl(hasName(ReplacementMethod)))), + *Class, *Result.Context) + .empty(); +} + +static CharSourceRange +getAliasNameRange(const MatchFinder::MatchResult &Result) { + if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) { + return CharSourceRange::getTokenRange( + Using->getNameInfo().getSourceRange()); + } + return CharSourceRange::getTokenRange( + Result.Nodes.getNodeAs<TypeLoc>("typeloc")->getSourceRange()); +} + +void UpgradeGoogletestCaseCheck::check(const MatchFinder::MatchResult &Result) { + llvm::StringRef ReplacementText; + CharSourceRange ReplacementRange; + if (const auto *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("method")) { + ReplacementText = getNewMethodName(Method->getName()); + + bool IsInInstantiation; + bool IsInTemplate; + bool AddFix = true; + if (const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>("call")) { + const auto *Callee = llvm::cast<MemberExpr>(Call->getCallee()); + ReplacementRange = CharSourceRange::getTokenRange(Callee->getMemberLoc(), + Callee->getMemberLoc()); + IsInInstantiation = isInInstantiation(*Call, Result); + IsInTemplate = isInTemplate<Stmt>(*Call, Result); + } else if (const auto *Ref = Result.Nodes.getNodeAs<DeclRefExpr>("ref")) { + ReplacementRange = + CharSourceRange::getTokenRange(Ref->getNameInfo().getSourceRange()); + IsInInstantiation = isInInstantiation(*Ref, Result); + IsInTemplate = isInTemplate<Stmt>(*Ref, Result); + } else if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) { + ReplacementRange = + CharSourceRange::getTokenRange(Using->getNameInfo().getSourceRange()); + IsInInstantiation = isInInstantiation(*Using, Result); + IsInTemplate = isInTemplate<Decl>(*Using, Result); + } else { + // This branch means we have matched a function declaration / definition + // either for a function from googletest or for a function in a derived + // class. + + ReplacementRange = CharSourceRange::getTokenRange( + Method->getNameInfo().getSourceRange()); + IsInInstantiation = isInInstantiation(*Method, Result); + IsInTemplate = isInTemplate<Decl>(*Method, Result); + + // If the type of the matched method is strictly derived from a googletest + // type and has both the old and new member function names, then we cannot + // safely rename (or delete) the old name version. + AddFix = !derivedTypeHasReplacementMethod(Result, ReplacementText); + } + + if (IsInInstantiation) { + if (MatchedTemplateLocations.count(ReplacementRange.getBegin()) == 0) { + // For each location matched in a template instantiation, we check if + // the location can also be found in `MatchedTemplateLocations`. If it + // is not found, that means the expression did not create a match + // without the instantiation and depends on template parameters. A + // manual fix is probably required so we provide only a warning. + diag(ReplacementRange.getBegin(), RenameCaseToSuiteMessage); + } + return; + } + + if (IsInTemplate) { + // We gather source locations from template matches not in template + // instantiations for future matches. + MatchedTemplateLocations.insert(ReplacementRange.getBegin()); + } + + if (!AddFix) { + diag(ReplacementRange.getBegin(), RenameCaseToSuiteMessage); + return; + } + } else { + // This is a match for `TestCase` to `TestSuite` refactoring. + assert(Result.Nodes.getNodeAs<TypeAliasDecl>("test-case") != nullptr); + ReplacementText = "TestSuite"; + ReplacementRange = getAliasNameRange(Result); + + // We do not need to keep track of template instantiations for this branch, + // because we are matching a `TypeLoc` for the alias declaration. Templates + // will only be instantiated with the true type name, `TestSuite`. + } + + DiagnosticBuilder Diag = + diag(ReplacementRange.getBegin(), RenameCaseToSuiteMessage); + + ReplacementRange = Lexer::makeFileCharRange( + ReplacementRange, *Result.SourceManager, Result.Context->getLangOpts()); + if (ReplacementRange.isInvalid()) + // An invalid source range likely means we are inside a macro body. A manual + // fix is likely needed so we do not create a fix-it hint. + return; + + Diag << FixItHint::CreateReplacement(ReplacementRange, ReplacementText); +} + +} // namespace clang::tidy::google diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/UpgradeGoogletestCaseCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/UpgradeGoogletestCaseCheck.h new file mode 100644 index 0000000000..61b09b9a9f --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/UpgradeGoogletestCaseCheck.h @@ -0,0 +1,39 @@ +//===--- UpgradeGoogletestCaseCheck.h - clang-tidy --------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UPGRADEGOOGLETESTCASECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UPGRADEGOOGLETESTCASECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google { + +/// Finds uses of deprecated Googletest APIs with names containing "case" and +/// replaces them with equivalent names containing "suite". +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/google/upgrade-googletest-case.html +class UpgradeGoogletestCaseCheck : public ClangTidyCheck { +public: + UpgradeGoogletestCaseCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + llvm::DenseSet<SourceLocation> MatchedTemplateLocations; +}; + +} // namespace clang::tidy::google + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UPGRADEGOOGLETESTCASECHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp new file mode 100644 index 0000000000..2f4913b2d4 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp @@ -0,0 +1,56 @@ +//===--- UsingNamespaceDirectiveCheck.cpp - clang-tidy ----------*- C++ -*-===// +// +// 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 "UsingNamespaceDirectiveCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::google::build { + +void UsingNamespaceDirectiveCheck::registerMatchers( + ast_matchers::MatchFinder *Finder) { + Finder->addMatcher(usingDirectiveDecl().bind("usingNamespace"), this); +} + +void UsingNamespaceDirectiveCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *U = Result.Nodes.getNodeAs<UsingDirectiveDecl>("usingNamespace"); + SourceLocation Loc = U->getBeginLoc(); + if (U->isImplicit() || !Loc.isValid()) + return; + + // Do not warn if namespace is a std namespace with user-defined literals. The + // user-defined literals can only be used with a using directive. + if (isStdLiteralsNamespace(U->getNominatedNamespace())) + return; + + diag(Loc, "do not use namespace using-directives; " + "use using-declarations instead"); + // TODO: We could suggest a list of using directives replacing the using + // namespace directive. +} + +bool UsingNamespaceDirectiveCheck::isStdLiteralsNamespace( + const NamespaceDecl *NS) { + if (!NS->getName().endswith("literals")) + return false; + + const auto *Parent = dyn_cast_or_null<NamespaceDecl>(NS->getParent()); + if (!Parent) + return false; + + if (Parent->isStdNamespace()) + return true; + + return Parent->getName() == "literals" && Parent->getParent() && + Parent->getParent()->isStdNamespace(); +} +} // namespace clang::tidy::google::build diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/UsingNamespaceDirectiveCheck.h b/contrib/libs/clang16/tools/extra/clang-tidy/google/UsingNamespaceDirectiveCheck.h new file mode 100644 index 0000000000..b7abac1311 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/UsingNamespaceDirectiveCheck.h @@ -0,0 +1,50 @@ +//===--- UsingNamespaceDirectiveCheck.h - clang-tidy ------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_USINGNAMESPACEDIRECTIVECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_USINGNAMESPACEDIRECTIVECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::build { + +/// Finds using namespace directives. +/// +/// https://google.github.io/styleguide/cppguide.html#Namespaces +/// +/// The check implements the following rule of the Google C++ Style Guide: +/// +/// You may not use a using-directive to make all names from a namespace +/// available. +/// +/// \code +/// // Forbidden -- This pollutes the namespace. +/// using namespace foo; +/// \endcode +/// +/// Corresponding cpplint.py check name: `build/namespaces`. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/google/build-using-namespace.html +class UsingNamespaceDirectiveCheck : public ClangTidyCheck { +public: + UsingNamespaceDirectiveCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + static bool isStdLiteralsNamespace(const NamespaceDecl *NS); +}; + +} // namespace clang::tidy::google::build + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_USINGNAMESPACEDIRECTIVECHECK_H diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/google/ya.make b/contrib/libs/clang16/tools/extra/clang-tidy/google/ya.make new file mode 100644 index 0000000000..ed6ef25f9b --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/google/ya.make @@ -0,0 +1,52 @@ +# Generated by devtools/yamaker. + +LIBRARY() + +LICENSE(Apache-2.0 WITH LLVM-exception) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +PEERDIR( + contrib/libs/clang16 + contrib/libs/clang16/include + contrib/libs/clang16/lib + contrib/libs/clang16/lib/AST + contrib/libs/clang16/lib/ASTMatchers + contrib/libs/clang16/lib/Basic + contrib/libs/clang16/lib/Lex + contrib/libs/clang16/tools/extra/clang-tidy/readability + contrib/libs/clang16/tools/extra/clang-tidy/utils + contrib/libs/llvm16 + contrib/libs/llvm16/lib/Frontend/OpenMP + contrib/libs/llvm16/lib/Support +) + +ADDINCL( + contrib/libs/clang16/tools/extra/clang-tidy/google +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + AvoidCStyleCastsCheck.cpp + AvoidNSObjectNewCheck.cpp + AvoidThrowingObjCExceptionCheck.cpp + AvoidUnderscoreInGoogletestNameCheck.cpp + DefaultArgumentsCheck.cpp + ExplicitConstructorCheck.cpp + ExplicitMakePairCheck.cpp + FunctionNamingCheck.cpp + GlobalNamesInHeadersCheck.cpp + GlobalVariableDeclarationCheck.cpp + GoogleTidyModule.cpp + IntegerTypesCheck.cpp + OverloadedUnaryAndCheck.cpp + TodoCommentCheck.cpp + UnnamedNamespaceInHeaderCheck.cpp + UpgradeGoogletestCaseCheck.cpp + UsingNamespaceDirectiveCheck.cpp +) + +END() |