diff --git a/clang-tools-extra/clang-tidy/objc/CMakeLists.txt b/clang-tools-extra/clang-tidy/objc/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/objc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/objc/CMakeLists.txt @@ -10,6 +10,7 @@ ForbiddenSubclassingCheck.cpp MissingHashCheck.cpp NSInvocationArgumentLifetimeCheck.cpp + NSDateFormatterCheck.cpp ObjCTidyModule.cpp PropertyDeclarationCheck.cpp SuperSelfCheck.cpp diff --git a/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.h b/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.h new file mode 100644 --- /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/NSDateFormatterCheck.cpp b/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp new file mode 100644 --- /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("str_lit"); + const StringLiteral *SL = cast(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/ObjCTidyModule.cpp b/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp --- 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 @@ "objc-forbidden-subclassing"); CheckFactories.registerCheck( "objc-missing-hash"); + CheckFactories.registerCheck("objc-nsdate-formatter"); CheckFactories.registerCheck( "objc-nsinvocation-argument-lifetime"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -239,7 +239,6 @@ `llvmlibc-implementation-in-namespace `_, `llvmlibc-restrict-system-libc-headers `_, "Yes" `misc-confusable-identifiers `_, - `misc-const-correctness `_, "Yes" `misc-definitions-in-headers `_, "Yes" `misc-misleading-bidirectional `_, `misc-misleading-identifier `_, @@ -295,6 +294,7 @@ `objc-dealloc-in-category `_, `objc-forbidden-subclassing `_, `objc-missing-hash `_, + `objc-nsdate-formatter `_, `objc-nsinvocation-argument-lifetime `_, "Yes" `objc-property-declaration `_, "Yes" `objc-super-self `_, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/objc/nsdate-formatter.rst b/clang-tools-extra/docs/clang-tidy/checks/objc/nsdate-formatter.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/objc/nsdate-formatter.rst @@ -0,0 +1,73 @@ +.. title:: clang-tidy - objc-nsdate-formatter + +objc-nsdate-formatter +===================== + +When ``NSDateFormatter`` is used to convert an ``NSDate`` type to a ``String`` type, the user +can specify a custom format string. Certain format specifiers are undesirable +despite being legal. See http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns for all legal date patterns. + +This checker reports as warnings the following string patterns in a date format specifier: + +#. yyyy + ww : Calendar year specified with week of a week year (unless YYYY is also specified). + + * | **Example 1:** Input Date: `29 December 2014` ; Format String: `yyyy-ww`; + | Output string: `2014-01` (Wrong because it’s not the first week of 2014) + + * | **Example 2:** Input Date: `29 December 2014` ; Format String: `dd-MM-yyyy (ww-YYYY)`; + | Output string: `29-12-2014 (01-2015)` (This is correct) + +#. F without ee/EE : Numeric day of week in a month without actual day. + + * | **Example:** Input Date: `29 December 2014` ; Format String: `F-MM`; + | Output string: `5-12` (Wrong because it reads as *5th ___ of Dec* in English) + +#. F without MM : Numeric day of week in a month without month. + + * | **Example:** Input Date: `29 December 2014` ; Format String: `F-EE` + | Output string: `5-Mon` (Wrong because it reads as *5th Mon of ___* in English) + +#. WW without MM : Week of the month without the month. + + * | **Example:** Input Date: `29 December 2014` ; Format String: `WW-yyyy` + | Output string: `05-2014` (Wrong because it reads as *5th Week of ___* in English) + +#. YYYY + QQ : Week year specified with quarter of normal year (unless yyyy is also specified). + + * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-QQ` + | Output string: `2015-04` (Wrong because it’s not the 4th quarter of 2015) + + * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (QQ-yyyy)` + | Output string: `01-2015 (04-2014)` (This is correct) + +#. YYYY + MM : Week year specified with Month of a calendar year (unless yyyy is also specified). + + * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-MM` + | Output string: `2015-12` (Wrong because it’s not the 12th month of 2015) + + * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (MM-yyyy)` + | Output string: `01-2015 (12-2014)` (This is correct) + +#. YYYY + DD : Week year with day of a calendar year (unless yyyy is also specified). + + * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-DD` + | Output string: `2015-363` (Wrong because it’s not the 363rd day of 2015) + + * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (DD-yyyy)` + | Output string: `01-2015 (363-2014)` (This is correct) + +#. YYYY + WW : Week year with week of a calendar year (unless yyyy is also specified). + + * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-WW` + | Output string: `2015-05` (Wrong because it’s not the 5th week of 2015) + + * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (WW-MM-yyyy)` + | Output string: `01-2015 (05-12-2014)` (This is correct) + +#. YYYY + F : Week year with day of week in a calendar month (unless yyyy is also specified). + + * | **Example 1:** Input Date: `29 December 2014` ; Format String: `YYYY-ww-F-EE` + | Output string: `2015-01-5-Mon` (Wrong because it’s not the 5th Monday of January in 2015) + + * | **Example 2:** Input Date: `29 December 2014` ; Format String: `ww-YYYY (F-EE-MM-yyyy)` + | Output string: `01-2015 (5-Mon-12-2014)` (This is correct) diff --git a/clang-tools-extra/test/clang-tidy/checkers/objc/nsdate-formatter.m b/clang-tools-extra/test/clang-tidy/checkers/objc/nsdate-formatter.m new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/objc/nsdate-formatter.m @@ -0,0 +1,313 @@ +// RUN: %check_clang_tidy %s objc-nsdate-formatter %t +@interface NSObject ++ (instancetype)alloc; +- (instancetype)init; +@end + +@interface TestClass : NSObject ++ (void)testMethod1; ++ (void)testMethod2; ++ (void)testMethod3; ++ (void)testAnotherClass; +@end + +@interface NSString : NSObject +@end + +void NSLog(NSString *format, ...); + +@interface NSDate : NSObject +@end + +@interface NSDateFormatter : NSObject +@property(copy) NSString *dateFormat; +- (NSString *)stringFromDate:(NSDate *)date; +@end + +@interface AnotherClass : NSObject +@property(copy) NSString *dateFormat; +@end + +@interface NSDateComponents : NSObject +@property long year; +@property long month; +@property long day; +@end + +@interface NSCalendar : NSObject +@property(class, readonly, copy) NSCalendar *currentCalendar; +- (nullable NSDate *)dateFromComponents:(NSDateComponents *)Comps; +@end + +@implementation TestClass ++ (void)testMethod1 { + // Reproducing incorrect behavior from Radar + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [formatter setDateFormat:@"YYYY_MM_dd_HH_mm_ss_SSS_ZZZ"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSDateComponents *comps = [[NSDateComponents alloc] init]; + [comps setDay:29]; + [comps setMonth:12]; + [comps setYear:2014]; + NSDate *date_radar = [[NSCalendar currentCalendar] dateFromComponents:comps]; + NSLog(@"YYYY_MM_dd_HH_mm_ss_SSS_ZZZ %@", [formatter stringFromDate:date_radar]); + + // Radar correct behavior + [formatter setDateFormat:@"yyyy_MM_dd_HH_mm_ss_SSS_ZZZ"]; + NSLog(@"yyyy_MM_dd_HH_mm_ss_SSS_ZZZ %@", [formatter stringFromDate:date_radar]); + + // Radar correct behavior - week year + [formatter setDateFormat:@"YYYY_ww_dd_HH_mm_ss_SSS_ZZZ"]; + NSLog(@"YYYY_ww_dd_HH_mm_ss_SSS_ZZZ %@", [formatter stringFromDate:date_radar]); + + // Radar incorrect behavior + [formatter setDateFormat:@"yyyy_ww_dd_HH_mm_ss_SSS_ZZZ"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_ww_dd_HH_mm_ss_SSS_ZZZ %@", [formatter stringFromDate:date_radar]); + + NSLog(@"=========================================="); + // Correct + [formatter setDateFormat:@"yyyy_MM"]; + NSLog(@"yyyy_MM %@", [formatter stringFromDate:date_radar]); + + // Correct + [formatter setDateFormat:@"yyyy_dd"]; + NSLog(@"yyyy_dd %@", [formatter stringFromDate:date_radar]); + + // Correct + [formatter setDateFormat:@"yyyy_DD"]; + NSLog(@"yyyy_DD %@", [formatter stringFromDate:date_radar]); + + // Incorrect + [formatter setDateFormat:@"yyyy_ww"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_ww %@", [formatter stringFromDate:date_radar]); + + // Incorrect + [formatter setDateFormat:@"yyyy_WW"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: Week of Month (W) used without the month (M); did you forget M in the format string? [objc-nsdate-formatter] + NSLog(@"yyyy_WW %@", [formatter stringFromDate:date_radar]); + + NSLog(@"=========================================="); + // Correct + [formatter setDateFormat:@"yyyy_MM_dd"]; + NSLog(@"yyyy_MM_dd %@", [formatter stringFromDate:date_radar]); + + // Potentially Incorrect + [formatter setDateFormat:@"yyyy_MM_DD"]; + NSLog(@"yyyy_MM_DD %@", [formatter stringFromDate:date_radar]); + + // Incorrect + [formatter setDateFormat:@"yyyy_MM_ww"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_MM_ww %@", [formatter stringFromDate:date_radar]); + + NSLog(@"=======WEEK YEAR=========="); + // Incorrect + [formatter setDateFormat:@"YYYY_MM"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_MM %@", [formatter stringFromDate:date_radar]); + + // Correct + [formatter setDateFormat:@"YYYY_ww"]; + NSLog(@"YYYY_ww %@", [formatter stringFromDate:date_radar]); + + // Incorrect + [formatter setDateFormat:@"YYYY_WW"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: Week of Month (W) used without the month (M); did you forget M in the format string? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with week of the month (W); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_WW %@", [formatter stringFromDate:date_radar]); + + // Correct + [formatter setDateFormat:@"YYYY_dd"]; + NSLog(@"YYYY_dd %@", [formatter stringFromDate:date_radar]); + + // Incorrect + [formatter setDateFormat:@"YYYY_DD"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the year (D); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_DD %@", [formatter stringFromDate:date_radar]); + + NSLog(@"=========================================="); + // Potentially Incorrect + [formatter setDateFormat:@"YYYY_ww_dd"]; + NSLog(@"YYYY ww dd %@", [formatter stringFromDate:date_radar]); + + // Incorrect + [formatter setDateFormat:@"YYYY_ww_DD"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the year (D); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_ww_DD %@", [formatter stringFromDate:date_radar]); +} + ++ (void)testMethod2 { + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + NSDateComponents *comps = [[NSDateComponents alloc] init]; + [comps setDay:29]; + [comps setMonth:12]; + [comps setYear:2014]; + NSDate *date_radar = [[NSCalendar currentCalendar] dateFromComponents:comps]; + + // Test 1 : incorrect + [formatter setDateFormat:@"yyyy_QQ_MM_ww_dd_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_QQ_MM_ww_dd_EE %@", [formatter stringFromDate:date_radar]); + + // Test 2 : incorrect + [formatter setDateFormat:@"yyyy_QQ_MM_ww_dd_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_QQ_MM_ww_dd_ee %@", [formatter stringFromDate:date_radar]); + + // Test 3 : incorrect + [formatter setDateFormat:@"yyyy_QQ_MM_ww_DD_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_QQ_MM_ww_DD_EE %@", [formatter stringFromDate:date_radar]); + + // Test 4 : incorrect + [formatter setDateFormat:@"yyyy_QQ_MM_ww_DD_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_QQ_MM_ww_DD_ee %@", [formatter stringFromDate:date_radar]); + + // Test 5 : incorrect + [formatter setDateFormat:@"yyyy_QQ_MM_ww_F_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_QQ_MM_ww_F_EE %@", [formatter stringFromDate:date_radar]); + + // Test 6 : incorrect + [formatter setDateFormat:@"yyyy_QQ_MM_ww_F_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of calendar year (y) with week of the year (w); did you mean to use week-year (Y) instead? [objc-nsdate-formatter] + NSLog(@"yyyy_QQ_MM_ww_F_ee %@", [formatter stringFromDate:date_radar]); + + // Test 7 : correct + [formatter setDateFormat:@"yyyy_QQ_MM_WW_dd_EE"]; + NSLog(@"yyyy_QQ_MM_WW_dd_EE %@", [formatter stringFromDate:date_radar]); + + // Test 8 : correct + [formatter setDateFormat:@"yyyy_QQ_MM_WW_dd_ee"]; + NSLog(@"yyyy_QQ_MM_WW_dd_ee %@", [formatter stringFromDate:date_radar]); + + // Test 9 : correct + [formatter setDateFormat:@"yyyy_QQ_MM_WW_DD_EE"]; + NSLog(@"yyyy_QQ_MM_WW_DD_EE %@", [formatter stringFromDate:date_radar]); + + // Test 10 : correct + [formatter setDateFormat:@"yyyy_QQ_MM_WW_DD_ee"]; + NSLog(@"yyyy_QQ_MM_WW_DD_ee %@", [formatter stringFromDate:date_radar]); + + // Test 11 : correct + [formatter setDateFormat:@"yyyy_QQ_MM_WW_F_EE"]; + NSLog(@"yyyy_QQ_MM_WW_F_EE %@", [formatter stringFromDate:date_radar]); + + // Test 12 : correct + [formatter setDateFormat:@"yyyy_QQ_MM_WW_F_ee"]; + NSLog(@"yyyy_QQ_MM_WW_F_ee %@", [formatter stringFromDate:date_radar]); + + // Test 13 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_ww_dd_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_ww_dd_EE %@", [formatter stringFromDate:date_radar]); + + // Test 14 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_ww_dd_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_ww_dd_ee %@", [formatter stringFromDate:date_radar]); + + // Test 15 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_ww_DD_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the year (D); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_ww_DD_EE %@", [formatter stringFromDate:date_radar]); + + // Test 16 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_ww_DD_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the year (D); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_ww_DD_ee %@", [formatter stringFromDate:date_radar]); + + // Test 17 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_ww_F_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the week in month (F); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_ww_F_EE %@", [formatter stringFromDate:date_radar]); + + // Test 18 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_ww_F_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the week in month (F); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_ww_F_ee %@", [formatter stringFromDate:date_radar]); + + // Test 19 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_WW_dd_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with week of the month (W); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_WW_dd_EE %@", [formatter stringFromDate:date_radar]); + + // Test 20 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_WW_dd_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with week of the month (W); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_WW_dd_ee %@", [formatter stringFromDate:date_radar]); + + // Test 21 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_WW_DD_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the year (D); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-4]]:28: warning: use of week year (Y) with week of the month (W); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_WW_DD_EE %@", [formatter stringFromDate:date_radar]); + + // Test 22 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_WW_DD_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the year (D); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-4]]:28: warning: use of week year (Y) with week of the month (W); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_WW_DD_ee %@", [formatter stringFromDate:date_radar]); + + // Test 23 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_WW_F_EE"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the week in month (F); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-4]]:28: warning: use of week year (Y) with week of the month (W); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_WW_F_EE %@", [formatter stringFromDate:date_radar]); + + // Test 24 : incorrect + [formatter setDateFormat:@"YYYY_QQ_MM_WW_F_ee"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use of week year (Y) with day of the week in month (F); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: use of week year (Y) with month (M); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: use of week year (Y) with quarter number (Q); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + // CHECK-MESSAGES: :[[@LINE-4]]:28: warning: use of week year (Y) with week of the month (W); did you mean to use calendar year (y) instead? [objc-nsdate-formatter] + NSLog(@"YYYY_QQ_MM_WW_F_ee %@", [formatter stringFromDate:date_radar]); +} + ++ (void)testMethod3 { + NSDateFormatter *Formatter = [[NSDateFormatter alloc] init]; + NSDateComponents *Comps = [[NSDateComponents alloc] init]; + [Comps setDay:29]; + [Comps setMonth:12]; + [Comps setYear:2014]; + NSDate *DateRadar = [[NSCalendar currentCalendar] dateFromComponents:Comps]; + + // Incorrect : has reserved and invalid chars + [Formatter setDateFormat:@"Rashmi"]; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: invalid date format specifier [objc-nsdate-formatter] + NSLog(@"Rashmi %@", [Formatter stringFromDate:DateRadar]); + + // Correct + [Formatter setDateFormat:@"AMy"]; + NSLog(@"AMy %@", [Formatter stringFromDate:DateRadar]); +} + ++ (void)testAnotherClass { + AnotherClass *Formatter = [[AnotherClass alloc] init]; + [Formatter setDateFormat:@"RandomString"]; + [Formatter setDateFormat:@"YYYY_QQ_MM_WW_dd_EE"]; +} +@end