CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
135 lines
4.7 KiB
C++
135 lines
4.7 KiB
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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "PropertyDeclarationCheck.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
#include "llvm/Support/Regex.h"
|
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
namespace clang::tidy::objc {
|
|
|
|
namespace {
|
|
|
|
// For StandardProperty the naming style is 'lowerCamelCase'.
|
|
// For CategoryProperty especially in categories of system class,
|
|
// to avoid naming conflict, the suggested naming style is
|
|
// 'abc_lowerCamelCase' (adding lowercase prefix followed by '_').
|
|
// Regardless of the style, all acronyms and initialisms should be capitalized.
|
|
enum NamingStyle {
|
|
StandardProperty = 1,
|
|
CategoryProperty = 2,
|
|
};
|
|
|
|
} // namespace
|
|
|
|
/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
|
|
/// 'camelCase' or 'abc_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
|
|
static FixItHint generateFixItHint(const ObjCPropertyDecl *Decl,
|
|
NamingStyle Style) {
|
|
auto Name = Decl->getName();
|
|
auto NewName = Decl->getName().str();
|
|
size_t Index = 0;
|
|
if (Style == CategoryProperty) {
|
|
const size_t UnderScorePos = Name.find_first_of('_');
|
|
if (UnderScorePos != StringRef::npos) {
|
|
Index = UnderScorePos + 1;
|
|
NewName.replace(0, Index - 1, Name.substr(0, Index - 1).lower());
|
|
}
|
|
}
|
|
if (Index < Name.size()) {
|
|
NewName[Index] = tolower(NewName[Index]);
|
|
if (NewName != Name) {
|
|
return FixItHint::CreateReplacement(
|
|
CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())),
|
|
StringRef(NewName));
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
static std::string validPropertyNameRegex(bool UsedInMatcher) {
|
|
// Allow any of these names:
|
|
// foo
|
|
// fooBar
|
|
// url
|
|
// urlString
|
|
// ID
|
|
// IDs
|
|
// URL
|
|
// URLString
|
|
// bundleID
|
|
// CIColor
|
|
//
|
|
// Disallow names of this form:
|
|
// LongString
|
|
//
|
|
// aRbITRaRyCapS is allowed to avoid generating false positives for names
|
|
// like isVitaminBSupplement, CProgrammingLanguage, and isBeforeM.
|
|
const std::string StartMatcher = UsedInMatcher ? "::" : "^";
|
|
return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
|
|
}
|
|
|
|
static bool hasCategoryPropertyPrefix(StringRef PropertyName) {
|
|
auto RegexExp =
|
|
llvm::Regex("^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9][a-zA-Z0-9_]+$");
|
|
return RegexExp.match(PropertyName);
|
|
}
|
|
|
|
static bool prefixedPropertyNameValid(StringRef PropertyName) {
|
|
const size_t Start = PropertyName.find_first_of('_');
|
|
assert(Start != StringRef::npos && Start + 1 < PropertyName.size());
|
|
auto Prefix = PropertyName.substr(0, Start);
|
|
if (Prefix.lower() != Prefix)
|
|
return false;
|
|
auto RegexExp = llvm::Regex(StringRef(validPropertyNameRegex(false)));
|
|
return RegexExp.match(PropertyName.substr(Start + 1));
|
|
}
|
|
|
|
void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
|
|
Finder->addMatcher(objcPropertyDecl(
|
|
// the property name should be in Lower Camel Case like
|
|
// 'lowerCamelCase'
|
|
unless(matchesName(validPropertyNameRegex(true))))
|
|
.bind("property"),
|
|
this);
|
|
}
|
|
|
|
void PropertyDeclarationCheck::check(const MatchFinder::MatchResult &Result) {
|
|
const auto *MatchedDecl =
|
|
Result.Nodes.getNodeAs<ObjCPropertyDecl>("property");
|
|
assert(!MatchedDecl->getName().empty());
|
|
auto *DeclContext = MatchedDecl->getDeclContext();
|
|
auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(DeclContext);
|
|
|
|
if (CategoryDecl != nullptr &&
|
|
hasCategoryPropertyPrefix(MatchedDecl->getName())) {
|
|
if (!prefixedPropertyNameValid(MatchedDecl->getName()) ||
|
|
CategoryDecl->IsClassExtension()) {
|
|
const NamingStyle Style = CategoryDecl->IsClassExtension()
|
|
? StandardProperty
|
|
: CategoryProperty;
|
|
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, Style);
|
|
}
|
|
return;
|
|
}
|
|
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, StandardProperty);
|
|
}
|
|
|
|
} // namespace clang::tidy::objc
|