aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-tidy
diff options
context:
space:
mode:
authorRashmi Mudduluru <r_mudduluru@apple.com>2022-08-02 13:53:50 -0700
committerRashmi Mudduluru <r_mudduluru@apple.com>2022-08-02 13:57:44 -0700
commit95a92995d45fc6fada43ecd91eba3e7aea90487a (patch)
treecc390513c46c6641975727a76b6814e105f0045d /clang-tools-extra/clang-tidy
parent803386da2ff80f0a5e75d2baee6dfa79d9d8d26f (diff)
downloadllvm-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')
-rw-r--r--clang-tools-extra/clang-tidy/objc/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp116
-rw-r--r--clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.h38
-rw-r--r--clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp2
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>(