Wizard created this revision. Herald added subscribers: cfe-commits, klimek.
Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D42464 Files: clang-tidy/objc/PropertyDeclarationCheck.cpp docs/clang-tidy/checks/objc-property-declaration.rst test/clang-tidy/objc-property-declaration.m
Index: test/clang-tidy/objc-property-declaration.m =================================================================== --- test/clang-tidy/objc-property-declaration.m +++ test/clang-tidy/objc-property-declaration.m @@ -11,3 +11,9 @@ @property(strong, nonatomic) NSString *URL_string; // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: property name 'URL_string' should use lowerCamelCase style, according to the Apple Coding Guidelines [objc-property-declaration] @end + +@interface Foo (Bar) +@property(assign, nonatomic) int abc_NotCamelCase; +// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'abc_NotCamelCase' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration] +@property(assign, nonatomic) int abc_camelCase; +@end \ No newline at end of file Index: docs/clang-tidy/checks/objc-property-declaration.rst =================================================================== --- docs/clang-tidy/checks/objc-property-declaration.rst +++ docs/clang-tidy/checks/objc-property-declaration.rst @@ -32,6 +32,15 @@ The corresponding style rule: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html#//apple_ref/doc/uid/20001284-1001757 +The check will also accept property declared in category with a prefix of +lowercase letters followed by a '_' to avoid naming conflict. For example: + +.. code-block:: objc +@property(nonatomic, assign) int abc_lowerCamelCase; + +The corresponding style rule: https://developer.apple.com/library/content/qa/qa1908/_index.html + + Options ------- Index: clang-tidy/objc/PropertyDeclarationCheck.cpp =================================================================== --- clang-tidy/objc/PropertyDeclarationCheck.cpp +++ clang-tidy/objc/PropertyDeclarationCheck.cpp @@ -8,12 +8,13 @@ //===----------------------------------------------------------------------===// #include "PropertyDeclarationCheck.h" +#include <algorithm> #include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/CharInfo.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Regex.h" -#include <algorithm> using namespace clang::ast_matchers; @@ -48,13 +49,28 @@ /// 'camelCase'. For other cases the users need to /// come up with a proper name by their own. /// FIXME: provide fix for snake_case to snakeCase -FixItHint generateFixItHint(const ObjCPropertyDecl *Decl) { - if (isupper(Decl->getName()[0])) { - auto NewName = Decl->getName().str(); - NewName[0] = tolower(NewName[0]); - return FixItHint::CreateReplacement( - CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())), - llvm::StringRef(NewName)); +FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, bool isCategory) { + auto Name = Decl->getName(); + auto NewName = Decl->getName().str(); + size_t Index = 0; + if (isCategory) { + for (size_t i = 0; i < Name.size(); ++i) { + if (Name[i] == '_') { + Index = i + 1; + break; + } + if (isUppercase(Name[i])) { + NewName[i] = tolower(Name[i]); + } + } + } + if (Index < Name.size()) { + NewName[Index] = tolower(NewName[Index]); + if (NewName != Name) { + return FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())), + llvm::StringRef(NewName)); + } } return FixItHint(); } @@ -65,8 +81,8 @@ // In case someone defines a custom prefix which includes a regex // special character, escape all the prefixes. std::transform(Acronyms.begin(), Acronyms.end(), - std::back_inserter(EscapedAcronyms), [](const std::string& s) { - return llvm::Regex::escape(s); }); + std::back_inserter(EscapedAcronyms), + [](const std::string &s) { return llvm::Regex::escape(s); }); // Allow any of these names: // foo // fooBar @@ -76,9 +92,33 @@ // URLString // bundleID return std::string("::((") + - llvm::join(EscapedAcronyms.begin(), EscapedAcronyms.end(), "|") + - ")[A-Z]?)?[a-z]+[a-z0-9]*([A-Z][a-z0-9]+)*" + "(" + - llvm::join(EscapedAcronyms.begin(), EscapedAcronyms.end(), "|") + ")?$"; + llvm::join(EscapedAcronyms.begin(), EscapedAcronyms.end(), "|") + + ")[A-Z]?)?[a-z]+[a-z0-9]*([A-Z][a-z0-9]+)*" + "(" + + llvm::join(EscapedAcronyms.begin(), EscapedAcronyms.end(), "|") + + ")?$"; +} + +bool hasCategoryPropertyPrefix(const llvm::StringRef &PropertyName) { + for (size_t i = 0; i < PropertyName.size() - 1; ++i) { + if (PropertyName[i] == '_') { + return true; + } + if (!llvm::isAlpha(PropertyName[i])) { + return false; + } + } + return false; +} + +bool prefixedPropertyNameMatches(const llvm::StringRef &PropertyName, + const std::vector<std::string> &Acronyms) { + size_t Start = 0; + while (PropertyName[Start] != '_') { + Start++; + } + auto RegexExp = llvm::Regex( + llvm::StringRef(validPropertyNameRegex(Acronyms).replace(0, 2, "^"))); + return RegexExp.match(llvm::StringRef(PropertyName.substr(Start + 1))); } } // namespace @@ -102,10 +142,24 @@ const auto *MatchedDecl = Result.Nodes.getNodeAs<ObjCPropertyDecl>("property"); assert(MatchedDecl->getName().size() > 0); + const auto *ParentContext = MatchedDecl->getDeclContext(); + auto NodeKind = std::string(ParentContext->getDeclKindName()); + if (NodeKind == "ObjCCategory" && + hasCategoryPropertyPrefix(MatchedDecl->getName())) { + if (!prefixedPropertyNameMatches(MatchedDecl->getName(), SpecialAcronyms)) { + diag(MatchedDecl->getLocation(), + "property name '%0' not using lowerCamelCase style or not prefixed " + "in " + "a category, according to " + "the Apple Coding Guidelines") + << MatchedDecl->getName() << generateFixItHint(MatchedDecl, true); + } + return; + } diag(MatchedDecl->getLocation(), "property name '%0' should use lowerCamelCase style, according to " "the Apple Coding Guidelines") - << MatchedDecl->getName() << generateFixItHint(MatchedDecl); + << MatchedDecl->getName() << generateFixItHint(MatchedDecl, false); } void PropertyDeclarationCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits