Index: clang-tidy/objc/CMakeLists.txt =================================================================== --- clang-tidy/objc/CMakeLists.txt +++ clang-tidy/objc/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyObjCModule ForbiddenSubclassingCheck.cpp ObjCTidyModule.cpp + PropertyDeclarationCheck.cpp LINK_LIBS clangAST Index: clang-tidy/objc/ObjCTidyModule.cpp =================================================================== --- clang-tidy/objc/ObjCTidyModule.cpp +++ clang-tidy/objc/ObjCTidyModule.cpp @@ -11,6 +11,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "ForbiddenSubclassingCheck.h" +#include "PropertyDeclarationCheck.h" using namespace clang::ast_matchers; @@ -23,6 +24,8 @@ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck( "objc-forbidden-subclassing"); + CheckFactories.registerCheck( + "objc-property-declaration"); } }; Index: clang-tidy/objc/PropertyDeclarationCheck.h =================================================================== --- /dev/null +++ clang-tidy/objc/PropertyDeclarationCheck.h @@ -0,0 +1,39 @@ +//===--- PropertyDeclarationCheck.h - clang-tidy-----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_PROPERTY_DECLARATION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_PROPERTY_DECLARATION_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace objc { + +/// Finds Objective-C property declarations which +/// are not in Lower Camel Case. +/// +/// The format of property should look like: +/// @property(nonatomic) NSString *lowerCamelCase; +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/objc-property-declaration.html +class PropertyDeclarationCheck : public ClangTidyCheck { +public: + PropertyDeclarationCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + 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_PROPERTY_DECLARATION_H Index: clang-tidy/objc/PropertyDeclarationCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/objc/PropertyDeclarationCheck.cpp @@ -0,0 +1,59 @@ +//===--- PropertyDeclarationCheck.cpp - clang-tidy-------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PropertyDeclarationCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace objc { + +namespace { + +/// we will do best effort to generate a fix, however, if the +/// case can not be solved with a simple fix (e.g. CamelCase +/// is a simple fix), we will leave the fix to the user. +/// TODO: 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)); + } + return FixItHint(); +} +} // namespace + +void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + objcPropertyDecl( + // the property name should be in Lower Camel Case like + // 'lowerCamelCase' + unless(matchesName("::[a-z]+[a-z0-9]*([A-Z][a-z0-9]+)*$"))) + .bind("property"), + this); +} + +void PropertyDeclarationCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = + Result.Nodes.getNodeAs("property"); + diag(MatchedDecl->getLocation(), + "property '%0' is not in proper format according to property naming " + "convention") + << MatchedDecl->getName() << generateFixItHint(MatchedDecl); +} + +} // namespace objc +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,11 @@ Improvements to clang-tidy -------------------------- +- New `objc-property-declaration + `_ check + + FIXME: add release notes. + - New `google-objc-global-variable-declaration `_ check Index: docs/clang-tidy/checks/google-objc-global-variable-declaration.rst =================================================================== --- docs/clang-tidy/checks/google-objc-global-variable-declaration.rst +++ docs/clang-tidy/checks/google-objc-global-variable-declaration.rst @@ -3,7 +3,7 @@ google-objc-global-variable-declaration ======================================= -Finds global variable declarations in Objective-C files that are not follow the pattern +Finds global variable declarations in Objective-C files that do not follow the pattern of variable names in Google's Objective-C Style Guide. The corresponding style guide rule: @@ -16,26 +16,31 @@ For code: .. code-block:: objc + static NSString* myString = @"hello"; The fix will be: .. code-block:: objc + static NSString* gMyString = @"hello"; Another example of constant: .. code-block:: objc + static NSString* const myConstString = @"hello"; The fix will be: .. code-block:: objc + static NSString* const kMyConstString = @"hello"; However for code that prefixed with non-alphabetical characters like: .. code-block:: objc + static NSString* __anotherString = @"world"; The check will give a warning message but will not be able to suggest a fix. The user Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -173,6 +173,8 @@ modernize-use-using mpi-buffer-deref mpi-type-mismatch + objc-forbidden-subclassing + objc-property-declaration performance-faster-string-find performance-for-range-copy performance-implicit-conversion-in-loop @@ -181,7 +183,6 @@ performance-type-promotion-in-math-fn performance-unnecessary-copy-initialization performance-unnecessary-value-param - objc-forbidden-subclassing readability-avoid-const-params-in-decls readability-braces-around-statements readability-container-size-empty Index: docs/clang-tidy/checks/objc-property-declaration.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/objc-property-declaration.rst @@ -0,0 +1,26 @@ +.. title:: clang-tidy - objc-property-declaration + +objc-property-declaration +========================= + +Finds property declarations in Objective-C files that do not follow the pattern +of property names in Apple's programming guide. The property name should be +in the format of Lower Camel Case. + +For code: + +.. code-block:: objc + +@property(nonatomic, assign) int LowerCamelCase; + +The fix will be: + +.. code-block:: objc + +@property(nonatomic, assign) int lowerCamelCase; + +The check will do best effort to give a fix, however, in some cases it is +difficult to give a proper fix since the property name could be complicated. +Users will need to come up with a proper name by their own. + +The corresponding style rule: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html#//apple_ref/doc/uid/20001284-1001757 Index: test/clang-tidy/objc-property-declaration.m =================================================================== --- /dev/null +++ test/clang-tidy/objc-property-declaration.m @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s objc-property-declaration %t + +@interface Foo +@property(assign, nonatomic) int NotCamelCase; +// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property 'NotCamelCase' is not in proper format according to property naming convention [objc-property-declaration] +// CHECK-FIXES: @property(assign, nonatomic) int notCamelCase; +@property(assign, nonatomic) int camelCase; +// CHECK-MESSAGES-NOT: :[[@LINE-1]]:34: warning: property 'camelCase' is not in proper format according to property naming convention [objc-property-declaration] +@end