clang-tools 8.0.0

PropertyDeclarationCheck.cpp
Go to the documentation of this file.
1 //===--- PropertyDeclarationCheck.cpp - clang-tidy-------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "PropertyDeclarationCheck.h"
11 #include <algorithm>
12 #include "../utils/OptionsUtils.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/Basic/CharInfo.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/Support/Regex.h"
19
20 using namespace clang::ast_matchers;
21
22 namespace clang {
23 namespace tidy {
24 namespace objc {
25
26 namespace {
27
28 // For StandardProperty the naming style is 'lowerCamelCase'.
29 // For CategoryProperty especially in categories of system class,
30 // to avoid naming conflict, the suggested naming style is
31 // 'abc_lowerCamelCase' (adding lowercase prefix followed by '_').
32 // Regardless of the style, all acronyms and initialisms should be capitalized.
33 enum NamingStyle {
34 StandardProperty = 1,
35 CategoryProperty = 2,
36 };
37
38 /// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
39 /// 'camelCase' or 'abc_camelCase'. For other cases the users need to
40 /// come up with a proper name by their own.
41 /// FIXME: provide fix for snake_case to snakeCase
42 FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
43 auto Name = Decl->getName();
44 auto NewName = Decl->getName().str();
45 size_t Index = 0;
46 if (Style == CategoryProperty) {
47 Index = Name.find_first_of('_') + 1;
48 NewName.replace(0, Index - 1, Name.substr(0, Index - 1).lower());
49 }
50 if (Index < Name.size()) {
51 NewName[Index] = tolower(NewName[Index]);
52 if (NewName != Name) {
53 return FixItHint::CreateReplacement(
54 CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())),
55 llvm::StringRef(NewName));
56 }
57 }
58 return FixItHint();
59 }
60
61 std::string validPropertyNameRegex(bool UsedInMatcher) {
62 // Allow any of these names:
63 // foo
64 // fooBar
65 // url
66 // urlString
67 // ID
68 // IDs
69 // URL
70 // URLString
71 // bundleID
72 // CIColor
73 //
74 // Disallow names of this form:
75 // LongString
76 //
77 // aRbITRaRyCapS is allowed to avoid generating false positives for names
78 // like isVitaminBSupplement, CProgrammingLanguage, and isBeforeM.
79 std::string StartMatcher = UsedInMatcher ? "::" : "^";
80 return StartMatcher + "([a-z]|[A-Z][A-Z0-9])[a-z0-9A-Z]*$";
81 }
82
83 bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
84 auto RegexExp = llvm::Regex("^[a-zA-Z]+_[a-zA-Z0-9][a-zA-Z0-9_]+$");
85 return RegexExp.match(PropertyName);
86 }
87
88 bool prefixedPropertyNameValid(llvm::StringRef PropertyName) {
89 size_t Start = PropertyName.find_first_of('_');
90 assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
91 auto Prefix = PropertyName.substr(0, Start);
92 if (Prefix.lower() != Prefix) {
93 return false;
94 }
95 auto RegexExp =
96 llvm::Regex(llvm::StringRef(validPropertyNameRegex(false)));
97 return RegexExp.match(PropertyName.substr(Start + 1));
98 }
99 } // namespace
100
101 PropertyDeclarationCheck::PropertyDeclarationCheck(StringRef Name,
102 ClangTidyContext *Context)
103 : ClangTidyCheck(Name, Context),
104 SpecialAcronyms(
105 utils::options::parseStringList(Options.get("Acronyms", ""))),
106 IncludeDefaultAcronyms(Options.get("IncludeDefaultAcronyms", true)),
107 EscapedAcronyms() {}
108
109 void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
110 // this check should only be applied to ObjC sources.
111 if (!getLangOpts().ObjC) return;
112
113 Finder->addMatcher(
114 objcPropertyDecl(
115 // the property name should be in Lower Camel Case like
116 // 'lowerCamelCase'
117 unless(matchesName(validPropertyNameRegex(true))))
118 .bind("property"),
119 this);
120 }
121
122 void PropertyDeclarationCheck::check(const MatchFinder::MatchResult &Result) {
123 const auto *MatchedDecl =
124 Result.Nodes.getNodeAs<ObjCPropertyDecl>("property");
125 assert(MatchedDecl->getName().size() > 0);
126 auto *DeclContext = MatchedDecl->getDeclContext();
127 auto *CategoryDecl = llvm::dyn_cast<ObjCCategoryDecl>(DeclContext);
128
129 if (CategoryDecl != nullptr &&
130 hasCategoryPropertyPrefix(MatchedDecl->getName())) {
131 if (!prefixedPropertyNameValid(MatchedDecl->getName()) ||
132 CategoryDecl->IsClassExtension()) {
133 NamingStyle Style = CategoryDecl->IsClassExtension() ? StandardProperty
134 : CategoryProperty;
135 diag(MatchedDecl->getLocation(),
136 "property name '%0' not using lowerCamelCase style or not prefixed "
137 "in a category, according to the Apple Coding Guidelines")
138 << MatchedDecl->getName() << generateFixItHint(MatchedDecl, Style);
139 }
140 return;
141 }
142 diag(MatchedDecl->getLocation(),
143 "property name '%0' not using lowerCamelCase style or not prefixed in "
144 "a category, according to the Apple Coding Guidelines")
145 << MatchedDecl->getName()
146 << generateFixItHint(MatchedDecl, StandardProperty);
147 }
148
149 void PropertyDeclarationCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
150 Options.store(Opts, "Acronyms",
151 utils::options::serializeStringList(SpecialAcronyms));
152 Options.store(Opts, "IncludeDefaultAcronyms", IncludeDefaultAcronyms);
153 }
154
155 } // namespace objc
156 } // namespace tidy
157 } // namespace clang
clang::tidy::objc::@412::NamingStyle
NamingStyle
Definition: PropertyDeclarationCheck.cpp:33
clang::ast_matchers
Definition: AbseilMatcher.h:15
clang::tidy::OptionsView::store
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Definition: ClangTidy.cpp:473
clang::tidy::objc::PropertyDeclarationCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Options) override
Should store all options supported by this check with their current values or default values for opti...
Definition: PropertyDeclarationCheck.cpp:149
clang::tidy::utils::options::serializeStringList
std::string serializeStringList(ArrayRef< std::string > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
Definition: OptionsUtils.cpp:31
clang::tidy::ClangTidyCheck::getLangOpts
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:187
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidy.h:127
clang::tidy::utils::options::parseStringList
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
Definition: OptionsUtils.cpp:19
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidy.h:183
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:98
Result
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: ClangdServer.cpp:60
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:100
clang::tidy::objc::PropertyDeclarationCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: PropertyDeclarationCheck.cpp:122
clang::tidy::objc::PropertyDeclarationCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: PropertyDeclarationCheck.cpp:109
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidy.cpp:438
PropertyDeclarationCheck.h
Index
const SymbolIndex * Index
Definition: Dexp.cpp:85