diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/google')
7 files changed, 80 insertions, 335 deletions
diff --git a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp deleted file mode 100644 index 3a5a9cd..0000000 --- a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp +++ /dev/null @@ -1,279 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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()))) - .bind("cast"), - this); - - Finder->addMatcher( - cxxFunctionalCastExpr( - hasDestinationType(hasCanonicalType(anyOf( - builtinType(), references(qualType()), pointsTo(qualType())))), - unless( - hasSourceExpression(anyOf(cxxConstructExpr(), 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()); - if (const auto *CastExpr = dyn_cast<CXXFunctionalCastExpr>(Expr)) - return CharSourceRange::getCharRange(CastExpr->getBeginLoc(), - CastExpr->getLParenLoc()); - 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); -} - -static bool sameTypeAsWritten(QualType X, QualType Y) { - if (X.getCanonicalType() != Y.getCanonicalType()) - return false; - - auto TC = X->getTypeClass(); - if (TC != Y->getTypeClass()) - return false; - - switch (TC) { - case Type::Typedef: - return declaresSameEntity(cast<TypedefType>(X)->getDecl(), - cast<TypedefType>(Y)->getDecl()); - case Type::Pointer: - return sameTypeAsWritten(cast<PointerType>(X)->getPointeeType(), - cast<PointerType>(Y)->getPointeeType()); - case Type::RValueReference: - case Type::LValueReference: - return sameTypeAsWritten(cast<ReferenceType>(X)->getPointeeType(), - cast<ReferenceType>(Y)->getPointeeType()); - default: - return true; - } -} - -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); - - const 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. - if (sameTypeAsWritten(SourceTypeAsWritten, DestTypeAsWritten)) { - 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().ends_with(".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())) - .ends_with(".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()) { - const QualType Dest = DestType.getNonReferenceType(); - const 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/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.h b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.h deleted file mode 100644 index a305bd5..0000000 --- a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.h +++ /dev/null @@ -1,41 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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: -/// https://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; - std::optional<TraversalKind> getCheckTraversalKind() const override { - return TK_IgnoreUnlessSpelledInSource; - } -}; - -} // namespace clang::tidy::google::readability - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDCSTYLECASTSCHECK_H diff --git a/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp b/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp index 6b96f71..92d590c 100644 --- a/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp @@ -14,7 +14,6 @@ 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:"), diff --git a/clang-tools-extra/clang-tidy/google/CMakeLists.txt b/clang-tools-extra/clang-tidy/google/CMakeLists.txt index 1d4229e..982a188 100644 --- a/clang-tools-extra/clang-tidy/google/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/google/CMakeLists.txt @@ -4,7 +4,6 @@ set(LLVM_LINK_COMPONENTS ) add_clang_library(clangTidyGoogleModule STATIC - AvoidCStyleCastsCheck.cpp AvoidNSObjectNewCheck.cpp AvoidThrowingObjCExceptionCheck.cpp AvoidUnderscoreInGoogletestNameCheck.cpp @@ -25,6 +24,7 @@ add_clang_library(clangTidyGoogleModule STATIC LINK_LIBS clangTidy + clangTidyModernizeModule clangTidyReadabilityModule clangTidyUtils diff --git a/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp b/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp index aff8b45..ce46b3f 100644 --- a/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp @@ -9,10 +9,10 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "../modernize/AvoidCStyleCastCheck.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" @@ -67,7 +67,7 @@ public: CheckFactories .registerCheck<readability::AvoidUnderscoreInGoogletestNameCheck>( "google-readability-avoid-underscore-in-googletest-name"); - CheckFactories.registerCheck<readability::AvoidCStyleCastsCheck>( + CheckFactories.registerCheck<modernize::AvoidCStyleCastCheck>( "google-readability-casting"); CheckFactories.registerCheck<readability::TodoCommentCheck>( "google-readability-todo"); diff --git a/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp b/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp index 7331b36..2789e4d 100644 --- a/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp @@ -11,42 +11,102 @@ #include "clang/Lex/Preprocessor.h" #include <optional> -namespace clang::tidy::google::readability { +namespace clang::tidy { + +namespace google::readability { + +enum class StyleKind { Parentheses, Hyphen }; + +} // namespace google::readability + +template <> struct OptionEnumMapping<google::readability::StyleKind> { + static ArrayRef<std::pair<google::readability::StyleKind, StringRef>> + getEnumMapping() { + static constexpr std::pair<google::readability::StyleKind, StringRef> + Mapping[] = { + {google::readability::StyleKind::Hyphen, "Hyphen"}, + {google::readability::StyleKind::Parentheses, "Parentheses"}, + }; + return {Mapping}; + } +}; + +} // namespace clang::tidy +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 *(\\(.*\\))?:?( )?(.*)$") {} + TodoMatch(R"(^// *TODO *((\((.*)\))?:?( )?|: *(.*) *- *)?(.*)$)") { + const llvm::StringRef TodoStyleString = + Check.Options.get("Style", "Hyphen"); + for (const auto &[Value, Name] : + OptionEnumMapping<StyleKind>::getEnumMapping()) { + if (Name == TodoStyleString) { + TodoStyle = Value; + return; + } + } + Check.configurationDiag( + "invalid value '%0' for " + "google-readability-todo.Style; valid values are " + "'Parentheses' and 'Hyphen'. Defaulting to 'Hyphen'") + << TodoStyleString; + } bool HandleComment(Preprocessor &PP, SourceRange Range) override { const StringRef Text = Lexer::getSourceText(CharSourceRange::getCharRange(Range), PP.getSourceManager(), PP.getLangOpts()); - SmallVector<StringRef, 4> Matches; + SmallVector<StringRef, 7> Matches; if (!TodoMatch.match(Text, &Matches)) return false; - const StringRef Username = Matches[1]; - const StringRef Comment = Matches[3]; + const StyleKind ParsedStyle = + !Matches[3].empty() ? StyleKind::Parentheses : StyleKind::Hyphen; + const StringRef Username = + ParsedStyle == StyleKind::Parentheses ? Matches[3] : Matches[5]; + const StringRef Comment = Matches[6]; - if (!Username.empty()) + if (!Username.empty() && + (ParsedStyle == StyleKind::Parentheses || !Comment.empty())) { return false; + } - const std::string NewText = - ("// TODO(" + Twine(User) + "): " + Comment).str(); + if (Username.empty()) { + Check.diag(Range.getBegin(), "missing username/bug in TODO") + << FixItHint::CreateReplacement( + CharSourceRange::getCharRange(Range), + createReplacementString(Username, Comment)); + } + + if (Comment.empty()) + Check.diag(Range.getBegin(), "missing details in TODO"); - Check.diag(Range.getBegin(), "missing username/bug in TODO") - << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Range), - NewText); return false; } + std::string createReplacementString(const StringRef Username, + const StringRef Comment) const { + if (TodoStyle == StyleKind::Parentheses) { + return ("// TODO(" + Twine(User) + + "): " + (Comment.empty() ? "some details" : Comment)) + .str(); + } + return ("// TODO: " + Twine(User) + " - " + + (Comment.empty() ? "some details" : Comment)) + .str(); + } + + StyleKind getTodoStyle() const { return TodoStyle; } + private: TodoCommentCheck &Check; std::string User; llvm::Regex TodoMatch; + StyleKind TodoStyle = StyleKind::Hyphen; }; TodoCommentCheck::TodoCommentCheck(StringRef Name, ClangTidyContext *Context) @@ -62,4 +122,8 @@ void TodoCommentCheck::registerPPCallbacks(const SourceManager &SM, PP->addCommentHandler(Handler.get()); } +void TodoCommentCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "Style", Handler->getTodoStyle()); +} + } // namespace clang::tidy::google::readability diff --git a/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h b/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h index 08cea13..800bc0f 100644 --- a/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h +++ b/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h @@ -27,6 +27,8 @@ public: void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + private: class TodoCommentHandler; std::unique_ptr<TodoCommentHandler> Handler; |
