diff options
author | Rashmi Mudduluru <r_mudduluru@apple.com> | 2022-08-02 13:53:50 -0700 |
---|---|---|
committer | Rashmi Mudduluru <r_mudduluru@apple.com> | 2022-08-02 13:57:44 -0700 |
commit | 95a92995d45fc6fada43ecd91eba3e7aea90487a (patch) | |
tree | cc390513c46c6641975727a76b6814e105f0045d /clang-tools-extra/clang-tidy | |
parent | 803386da2ff80f0a5e75d2baee6dfa79d9d8d26f (diff) | |
download | llvm-95a92995d45fc6fada43ecd91eba3e7aea90487a.zip llvm-95a92995d45fc6fada43ecd91eba3e7aea90487a.tar.gz llvm-95a92995d45fc6fada43ecd91eba3e7aea90487a.tar.bz2 |
Adds the NSDateFormatter checker to clang-tidy
Differential Revision: https://reviews.llvm.org/D126097
Diffstat (limited to 'clang-tools-extra/clang-tidy')
4 files changed, 157 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/objc/CMakeLists.txt b/clang-tools-extra/clang-tidy/objc/CMakeLists.txt index 1129c6a..bdd125c 100644 --- a/clang-tools-extra/clang-tidy/objc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/objc/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_library(clangTidyObjCModule ForbiddenSubclassingCheck.cpp MissingHashCheck.cpp NSInvocationArgumentLifetimeCheck.cpp + NSDateFormatterCheck.cpp ObjCTidyModule.cpp PropertyDeclarationCheck.cpp SuperSelfCheck.cpp diff --git a/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp b/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp new file mode 100644 index 0000000..fdc8377 --- /dev/null +++ b/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp @@ -0,0 +1,116 @@ +//===--- NSDateFormatterCheck.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 "NSDateFormatterCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace objc { + +void NSDateFormatterCheck::registerMatchers(MatchFinder *Finder) { + // Adding matchers. + + Finder->addMatcher( + objcMessageExpr(hasSelector("setDateFormat:"), + hasReceiverType(asString("NSDateFormatter *")), + hasArgument(0, ignoringImpCasts( + objcStringLiteral().bind("str_lit")))), + this); +} + +static char ValidDatePatternChars[] = { + 'G', 'y', 'Y', 'u', 'U', 'r', 'Q', 'q', 'M', 'L', 'I', 'w', 'W', 'd', + 'D', 'F', 'g', 'E', 'e', 'c', 'a', 'b', 'B', 'h', 'H', 'K', 'k', 'j', + 'J', 'C', 'm', 's', 'S', 'A', 'z', 'Z', 'O', 'v', 'V', 'X', 'x'}; + +// Checks if the string pattern used as a date format specifier is valid. +// A string pattern is valid if all the letters(a-z, A-Z) in it belong to the +// set of reserved characters. See: +// https://www.unicode.org/reports/tr35/tr35.html#Invalid_Patterns +bool isValidDatePattern(StringRef Pattern) { + for (auto &PatternChar : Pattern) { + if (isalpha(PatternChar)) { + if (std::find(std::begin(ValidDatePatternChars), + std::end(ValidDatePatternChars), + PatternChar) == std::end(ValidDatePatternChars)) { + return false; + } + } + } + return true; +} + +// Checks if the string pattern used as a date format specifier contains +// any incorrect pattern and reports it as a warning. +// See: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns +void NSDateFormatterCheck::check(const MatchFinder::MatchResult &Result) { + // Callback implementation. + const auto *StrExpr = Result.Nodes.getNodeAs<ObjCStringLiteral>("str_lit"); + const StringLiteral *SL = cast<ObjCStringLiteral>(StrExpr)->getString(); + StringRef SR = SL->getString(); + + if (!isValidDatePattern(SR)) { + diag(StrExpr->getExprLoc(), "invalid date format specifier"); + } + + if (SR.contains('y') && SR.contains('w') && !SR.contains('Y')) { + diag(StrExpr->getExprLoc(), + "use of calendar year (y) with week of the year (w); " + "did you mean to use week-year (Y) instead?"); + } + if (SR.contains('F')) { + if (!(SR.contains('e') || SR.contains('E'))) { + diag(StrExpr->getExprLoc(), + "day of week in month (F) used without day of the week (e or E); " + "did you forget e (or E) in the format string?"); + } + if (!SR.contains('M')) { + diag(StrExpr->getExprLoc(), + "day of week in month (F) used without the month (M); " + "did you forget M in the format string?"); + } + } + if (SR.contains('W') && !SR.contains('M')) { + diag(StrExpr->getExprLoc(), "Week of Month (W) used without the month (M); " + "did you forget M in the format string?"); + } + if (SR.contains('Y') && SR.contains('Q') && !SR.contains('y')) { + diag(StrExpr->getExprLoc(), + "use of week year (Y) with quarter number (Q); " + "did you mean to use calendar year (y) instead?"); + } + if (SR.contains('Y') && SR.contains('M') && !SR.contains('y')) { + diag(StrExpr->getExprLoc(), + "use of week year (Y) with month (M); " + "did you mean to use calendar year (y) instead?"); + } + if (SR.contains('Y') && SR.contains('D') && !SR.contains('y')) { + diag(StrExpr->getExprLoc(), + "use of week year (Y) with day of the year (D); " + "did you mean to use calendar year (y) instead?"); + } + if (SR.contains('Y') && SR.contains('W') && !SR.contains('y')) { + diag(StrExpr->getExprLoc(), + "use of week year (Y) with week of the month (W); " + "did you mean to use calendar year (y) instead?"); + } + if (SR.contains('Y') && SR.contains('F') && !SR.contains('y')) { + diag(StrExpr->getExprLoc(), + "use of week year (Y) with day of the week in month (F); " + "did you mean to use calendar year (y) instead?"); + } +} + +} // namespace objc +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.h b/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.h new file mode 100644 index 0000000..f2c6f5f --- /dev/null +++ b/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.h @@ -0,0 +1,38 @@ +//===--- NSDateFormatterCheck.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_OBJC_NSDATEFORMATTERCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_NSDATEFORMATTERCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace objc { + +/// Checks the string pattern used as a date format specifier and reports +/// warnings if it contains any incorrect sub-pattern. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/objc-NSDateFormatter.html +class NSDateFormatterCheck : public ClangTidyCheck { +public: + NSDateFormatterCheck(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 objc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_NSDATEFORMATTERCHECK_H diff --git a/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp b/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp index 3a5bf7d..0cfab1f 100644 --- a/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp @@ -14,6 +14,7 @@ #include "DeallocInCategoryCheck.h" #include "ForbiddenSubclassingCheck.h" #include "MissingHashCheck.h" +#include "NSDateFormatterCheck.h" #include "NSInvocationArgumentLifetimeCheck.h" #include "PropertyDeclarationCheck.h" #include "SuperSelfCheck.h" @@ -37,6 +38,7 @@ public: "objc-forbidden-subclassing"); CheckFactories.registerCheck<MissingHashCheck>( "objc-missing-hash"); + CheckFactories.registerCheck<NSDateFormatterCheck>("objc-nsdate-formatter"); CheckFactories.registerCheck<NSInvocationArgumentLifetimeCheck>( "objc-nsinvocation-argument-lifetime"); CheckFactories.registerCheck<PropertyDeclarationCheck>( |