brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.2 KiB · 31d098e Raw
107 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "NSDateFormatterCheck.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11#include "clang/ASTMatchers/ASTMatchers.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::objc {16 17void NSDateFormatterCheck::registerMatchers(MatchFinder *Finder) {18  // Adding matchers.19 20  Finder->addMatcher(21      objcMessageExpr(hasSelector("setDateFormat:"),22                      hasReceiverType(asString("NSDateFormatter *")),23                      hasArgument(0, ignoringImpCasts(24                                         objcStringLiteral().bind("str_lit")))),25      this);26}27 28static char ValidDatePatternChars[] = {29    'G', 'y', 'Y', 'u', 'U', 'r', 'Q', 'q', 'M', 'L', 'I', 'w', 'W', 'd',30    'D', 'F', 'g', 'E', 'e', 'c', 'a', 'b', 'B', 'h', 'H', 'K', 'k', 'j',31    'J', 'C', 'm', 's', 'S', 'A', 'z', 'Z', 'O', 'v', 'V', 'X', 'x'};32 33// Checks if the string pattern used as a date format specifier is valid.34// A string pattern is valid if all the letters(a-z, A-Z) in it belong to the35// set of reserved characters. See:36// https://www.unicode.org/reports/tr35/tr35.html#Invalid_Patterns37static bool isValidDatePattern(StringRef Pattern) {38  return llvm::all_of(Pattern, [](const auto &PatternChar) {39    return !isalpha(PatternChar) ||40           llvm::is_contained(ValidDatePatternChars, PatternChar);41  });42}43 44// Checks if the string pattern used as a date format specifier contains45// any incorrect pattern and reports it as a warning.46// See:47// https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns48void NSDateFormatterCheck::check(const MatchFinder::MatchResult &Result) {49  // Callback implementation.50  const auto *StrExpr = Result.Nodes.getNodeAs<ObjCStringLiteral>("str_lit");51  const StringLiteral *SL = cast<ObjCStringLiteral>(StrExpr)->getString();52  const StringRef SR = SL->getString();53 54  if (!isValidDatePattern(SR)) {55    diag(StrExpr->getExprLoc(), "invalid date format specifier");56  }57 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?");62  }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?");68    }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?");73    }74  }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?");78  }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?");83  }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?");88  }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?");93  }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?");98  }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?");103  }104}105 106} // namespace clang::tidy::objc107