aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-tidy/google
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/google')
-rw-r--r--clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp279
-rw-r--r--clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.h41
-rw-r--r--clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp1
-rw-r--r--clang-tools-extra/clang-tidy/google/CMakeLists.txt2
-rw-r--r--clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp86
-rw-r--r--clang-tools-extra/clang-tidy/google/TodoCommentCheck.h2
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;