10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/ASTMatchers/ASTMatchers.h"
22 objcMessageExpr(hasSelector(
"setDateFormat:"),
23 hasReceiverType(asString(
"NSDateFormatter *")),
24 hasArgument(0, ignoringImpCasts(
25 objcStringLiteral().bind(
"str_lit")))),
30 'G',
'y',
'Y',
'u',
'U',
'r',
'Q',
'q',
'M',
'L',
'I',
'w',
'W',
'd',
31 'D',
'F',
'g',
'E',
'e',
'c',
'a',
'b',
'B',
'h',
'H',
'K',
'k',
'j',
32 'J',
'C',
'm',
's',
'S',
'A',
'z',
'Z',
'O',
'v',
'V',
'X',
'x'};
39 return llvm::all_of(Pattern, [](
const auto &PatternChar) {
40 return !isalpha(PatternChar) ||
50 const auto *StrExpr = Result.Nodes.getNodeAs<ObjCStringLiteral>(
"str_lit");
51 const StringLiteral *SL = cast<ObjCStringLiteral>(StrExpr)->getString();
52 StringRef SR = SL->getString();
55 diag(StrExpr->getExprLoc(),
"invalid date format specifier");
58 if (SR.contains(
'y') && SR.contains(
'w') && !SR.contains(
'Y')) {
59 diag(StrExpr->getExprLoc(),
60 "use of calendar year (y) with week of the year (w); "
61 "did you mean to use week-year (Y) instead?");
63 if (SR.contains(
'F')) {
64 if (!(SR.contains(
'e') || SR.contains(
'E'))) {
65 diag(StrExpr->getExprLoc(),
66 "day of week in month (F) used without day of the week (e or E); "
67 "did you forget e (or E) in the format string?");
69 if (!SR.contains(
'M')) {
70 diag(StrExpr->getExprLoc(),
71 "day of week in month (F) used without the month (M); "
72 "did you forget M in the format string?");
75 if (SR.contains(
'W') && !SR.contains(
'M')) {
76 diag(StrExpr->getExprLoc(),
"Week of Month (W) used without the month (M); "
77 "did you forget M in the format string?");
79 if (SR.contains(
'Y') && SR.contains(
'Q') && !SR.contains(
'y')) {
80 diag(StrExpr->getExprLoc(),
81 "use of week year (Y) with quarter number (Q); "
82 "did you mean to use calendar year (y) instead?");
84 if (SR.contains(
'Y') && SR.contains(
'M') && !SR.contains(
'y')) {
85 diag(StrExpr->getExprLoc(),
86 "use of week year (Y) with month (M); "
87 "did you mean to use calendar year (y) instead?");
89 if (SR.contains(
'Y') && SR.contains(
'D') && !SR.contains(
'y')) {
90 diag(StrExpr->getExprLoc(),
91 "use of week year (Y) with day of the year (D); "
92 "did you mean to use calendar year (y) instead?");
94 if (SR.contains(
'Y') && SR.contains(
'W') && !SR.contains(
'y')) {
95 diag(StrExpr->getExprLoc(),
96 "use of week year (Y) with week of the month (W); "
97 "did you mean to use calendar year (y) instead?");
99 if (SR.contains(
'Y') && SR.contains(
'F') && !SR.contains(
'y')) {
100 diag(StrExpr->getExprLoc(),
101 "use of week year (Y) with day of the week in month (F); "
102 "did you mean to use calendar year (y) instead?");
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
bool isValidDatePattern(StringRef Pattern)
static char ValidDatePatternChars[]