[clang-tidy] Extend IdentifierNamingCheck per file config

Add IgnoreMainLikeFunctions to the per file config. This can be extended for new options added to the check easily.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D90832
This commit is contained in:
Nathan James 2020-11-05 19:51:04 +00:00
parent 40140e122f
commit 3b9b90a191
No known key found for this signature in database
GPG Key ID: CC007AFCDA90AA5F
9 changed files with 92 additions and 63 deletions

View File

@ -122,9 +122,9 @@ static StringRef const StyleNames[] = {
#undef NAMING_KEYS #undef NAMING_KEYS
// clang-format on // clang-format on
static std::vector<llvm::Optional<IdentifierNamingCheck::NamingStyle>> static IdentifierNamingCheck::FileStyle
getNamingStyles(const ClangTidyCheck::OptionsView &Options) { getFileStyleFromOptions(const ClangTidyCheck::OptionsView &Options) {
std::vector<llvm::Optional<IdentifierNamingCheck::NamingStyle>> Styles( SmallVector<llvm::Optional<IdentifierNamingCheck::NamingStyle>, 0> Styles(
SK_Count); SK_Count);
SmallString<64> StyleString; SmallString<64> StyleString;
for (unsigned I = 0; I < SK_Count; ++I) { for (unsigned I = 0; I < SK_Count; ++I) {
@ -145,23 +145,23 @@ getNamingStyles(const ClangTidyCheck::OptionsView &Options) {
Styles[I].emplace(std::move(CaseOptional), std::move(Prefix), Styles[I].emplace(std::move(CaseOptional), std::move(Prefix),
std::move(Postfix)); std::move(Postfix));
} }
return Styles; bool IgnoreMainLike = Options.get("IgnoreMainLikeFunctions", false);
return {std::move(Styles), IgnoreMainLike};
} }
IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name, IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name,
ClangTidyContext *Context) ClangTidyContext *Context)
: RenamerClangTidyCheck(Name, Context), Context(Context), CheckName(Name), : RenamerClangTidyCheck(Name, Context), Context(Context), CheckName(Name),
GetConfigPerFile(Options.get("GetConfigPerFile", true)), GetConfigPerFile(Options.get("GetConfigPerFile", true)),
IgnoreFailedSplit(Options.get("IgnoreFailedSplit", false)), IgnoreFailedSplit(Options.get("IgnoreFailedSplit", false)) {
IgnoreMainLikeFunctions(Options.get("IgnoreMainLikeFunctions", false)) {
auto IterAndInserted = NamingStylesCache.try_emplace( auto IterAndInserted = NamingStylesCache.try_emplace(
llvm::sys::path::parent_path(Context->getCurrentFile()), llvm::sys::path::parent_path(Context->getCurrentFile()),
getNamingStyles(Options)); getFileStyleFromOptions(Options));
assert(IterAndInserted.second && "Couldn't insert Style"); assert(IterAndInserted.second && "Couldn't insert Style");
// Holding a reference to the data in the vector is safe as it should never // Holding a reference to the data in the vector is safe as it should never
// move. // move.
MainFileStyle = IterAndInserted.first->getValue(); MainFileStyle = &IterAndInserted.first->getValue();
} }
IdentifierNamingCheck::~IdentifierNamingCheck() = default; IdentifierNamingCheck::~IdentifierNamingCheck() = default;
@ -169,26 +169,28 @@ IdentifierNamingCheck::~IdentifierNamingCheck() = default;
void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
RenamerClangTidyCheck::storeOptions(Opts); RenamerClangTidyCheck::storeOptions(Opts);
SmallString<64> StyleString; SmallString<64> StyleString;
ArrayRef<llvm::Optional<NamingStyle>> Styles = MainFileStyle->getStyles();
for (size_t I = 0; I < SK_Count; ++I) { for (size_t I = 0; I < SK_Count; ++I) {
if (!MainFileStyle[I]) if (!Styles[I])
continue; continue;
StyleString = StyleNames[I]; StyleString = StyleNames[I];
size_t StyleSize = StyleString.size(); size_t StyleSize = StyleString.size();
StyleString.append("Prefix"); StyleString.append("Prefix");
Options.store(Opts, StyleString, MainFileStyle[I]->Prefix); Options.store(Opts, StyleString, Styles[I]->Prefix);
// Fast replacement of [Pre]fix -> [Suf]fix. // Fast replacement of [Pre]fix -> [Suf]fix.
memcpy(&StyleString[StyleSize], "Suf", 3); memcpy(&StyleString[StyleSize], "Suf", 3);
Options.store(Opts, StyleString, MainFileStyle[I]->Suffix); Options.store(Opts, StyleString, Styles[I]->Suffix);
if (MainFileStyle[I]->Case) { if (Styles[I]->Case) {
memcpy(&StyleString[StyleSize], "Case", 4); memcpy(&StyleString[StyleSize], "Case", 4);
StyleString.pop_back(); StyleString.pop_back();
StyleString.pop_back(); StyleString.pop_back();
Options.store(Opts, StyleString, *MainFileStyle[I]->Case); Options.store(Opts, StyleString, *Styles[I]->Case);
} }
} }
Options.store(Opts, "GetConfigPerFile", GetConfigPerFile); Options.store(Opts, "GetConfigPerFile", GetConfigPerFile);
Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit); Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);
Options.store(Opts, "IgnoreMainLikeFunctions", IgnoreMainLikeFunctions); Options.store(Opts, "IgnoreMainLikeFunctions",
MainFileStyle->isIgnoringMainLikeFunction());
} }
static bool matchesStyle(StringRef Name, static bool matchesStyle(StringRef Name,
@ -704,23 +706,27 @@ llvm::Optional<RenamerClangTidyCheck::FailureInfo>
IdentifierNamingCheck::GetDeclFailureInfo(const NamedDecl *Decl, IdentifierNamingCheck::GetDeclFailureInfo(const NamedDecl *Decl,
const SourceManager &SM) const { const SourceManager &SM) const {
SourceLocation Loc = Decl->getLocation(); SourceLocation Loc = Decl->getLocation();
ArrayRef<llvm::Optional<NamingStyle>> NamingStyles = const FileStyle &FileStyle = getStyleForFile(SM.getFilename(Loc));
getStyleForFile(SM.getFilename(Loc)); if (!FileStyle.isActive())
return llvm::None;
return getFailureInfo( return getFailureInfo(Decl->getName(), Loc, FileStyle.getStyles(),
Decl->getName(), Loc, NamingStyles, findStyleKind(Decl, FileStyle.getStyles(),
findStyleKind(Decl, NamingStyles, IgnoreMainLikeFunctions), SM, FileStyle.isIgnoringMainLikeFunction()),
IgnoreFailedSplit); SM, IgnoreFailedSplit);
} }
llvm::Optional<RenamerClangTidyCheck::FailureInfo> llvm::Optional<RenamerClangTidyCheck::FailureInfo>
IdentifierNamingCheck::GetMacroFailureInfo(const Token &MacroNameTok, IdentifierNamingCheck::GetMacroFailureInfo(const Token &MacroNameTok,
const SourceManager &SM) const { const SourceManager &SM) const {
SourceLocation Loc = MacroNameTok.getLocation(); SourceLocation Loc = MacroNameTok.getLocation();
const FileStyle &Style = getStyleForFile(SM.getFilename(Loc));
if (!Style.isActive())
return llvm::None;
return getFailureInfo(MacroNameTok.getIdentifierInfo()->getName(), Loc, return getFailureInfo(MacroNameTok.getIdentifierInfo()->getName(), Loc,
getStyleForFile(SM.getFilename(Loc)), Style.getStyles(), SK_MacroDefinition, SM,
SK_MacroDefinition, SM, IgnoreFailedSplit); IgnoreFailedSplit);
} }
RenamerClangTidyCheck::DiagInfo RenamerClangTidyCheck::DiagInfo
@ -732,19 +738,27 @@ IdentifierNamingCheck::GetDiagInfo(const NamingCheckId &ID,
}}; }};
} }
ArrayRef<llvm::Optional<IdentifierNamingCheck::NamingStyle>> const IdentifierNamingCheck::FileStyle &
IdentifierNamingCheck::getStyleForFile(StringRef FileName) const { IdentifierNamingCheck::getStyleForFile(StringRef FileName) const {
if (!GetConfigPerFile) if (!GetConfigPerFile)
return MainFileStyle; return *MainFileStyle;
auto &Styles = NamingStylesCache[llvm::sys::path::parent_path(FileName)]; StringRef Parent = llvm::sys::path::parent_path(FileName);
if (Styles.empty()) { auto Iter = NamingStylesCache.find(Parent);
if (Iter != NamingStylesCache.end())
return Iter->getValue();
ClangTidyOptions Options = Context->getOptionsForFile(FileName); ClangTidyOptions Options = Context->getOptionsForFile(FileName);
if (Options.Checks && GlobList(*Options.Checks).contains(CheckName)) if (Options.Checks && GlobList(*Options.Checks).contains(CheckName)) {
Styles = getNamingStyles({CheckName, Options.CheckOptions}); auto It = NamingStylesCache.try_emplace(
else Parent, getFileStyleFromOptions({CheckName, Options.CheckOptions}));
Styles.resize(SK_Count, None); assert(It.second);
return It.first->getValue();
} }
return Styles; assert(false);
// Default construction gives an empty style.
auto It = NamingStylesCache.try_emplace(Parent);
assert(It.second);
return It.first->getValue();
} }
} // namespace readability } // namespace readability

View File

@ -60,6 +60,26 @@ public:
std::string Suffix; std::string Suffix;
}; };
struct FileStyle {
FileStyle() : IsActive(false), IgnoreMainLikeFunctions(false) {}
FileStyle(SmallVectorImpl<Optional<NamingStyle>> &&Styles,
bool IgnoreMainLike)
: Styles(std::move(Styles)), IsActive(true),
IgnoreMainLikeFunctions(IgnoreMainLike) {}
ArrayRef<Optional<NamingStyle>> getStyles() const {
assert(IsActive);
return Styles;
}
bool isActive() const { return IsActive; }
bool isIgnoringMainLikeFunction() const { return IgnoreMainLikeFunctions; }
private:
SmallVector<Optional<NamingStyle>, 0> Styles;
bool IsActive;
bool IgnoreMainLikeFunctions;
};
private: private:
llvm::Optional<FailureInfo> llvm::Optional<FailureInfo>
GetDeclFailureInfo(const NamedDecl *Decl, GetDeclFailureInfo(const NamedDecl *Decl,
@ -70,19 +90,16 @@ private:
DiagInfo GetDiagInfo(const NamingCheckId &ID, DiagInfo GetDiagInfo(const NamingCheckId &ID,
const NamingCheckFailure &Failure) const override; const NamingCheckFailure &Failure) const override;
ArrayRef<llvm::Optional<NamingStyle>> const FileStyle &getStyleForFile(StringRef FileName) const;
getStyleForFile(StringRef FileName) const;
/// Stores the style options as a vector, indexed by the specified \ref /// Stores the style options as a vector, indexed by the specified \ref
/// StyleKind, for a given directory. /// StyleKind, for a given directory.
mutable llvm::StringMap<std::vector<llvm::Optional<NamingStyle>>> mutable llvm::StringMap<FileStyle> NamingStylesCache;
NamingStylesCache; FileStyle *MainFileStyle;
ArrayRef<llvm::Optional<NamingStyle>> MainFileStyle;
ClangTidyContext *const Context; ClangTidyContext *const Context;
const std::string CheckName; const std::string CheckName;
const bool GetConfigPerFile; const bool GetConfigPerFile;
const bool IgnoreFailedSplit; const bool IgnoreFailedSplit;
const bool IgnoreMainLikeFunctions;
}; };
} // namespace readability } // namespace readability

View File

@ -1,5 +0,0 @@
Checks: -readability-identifier-naming
CheckOptions:
- key: readability-identifier-naming.GlobalFunctionCase
value: lower_case

View File

@ -1,3 +0,0 @@
void disabled_style_1();
void disabledStyle2();
void DISABLED_STYLE_3();

View File

@ -2,4 +2,6 @@ Checks: readability-identifier-naming
CheckOptions: CheckOptions:
- key: readability-identifier-naming.GlobalFunctionCase - key: readability-identifier-naming.GlobalFunctionCase
value: lower_case value: lower_case
- key: readability-identifier-naming.IgnoreMainLikeFunctions
value: true

View File

@ -3,3 +3,5 @@
void style_first_good(); void style_first_good();
void styleFirstBad(); void styleFirstBad();
int thisIsMainLikeIgnored(int argc, const char *argv[]) {}

View File

@ -2,4 +2,6 @@ Checks: readability-identifier-naming
CheckOptions: CheckOptions:
- key: readability-identifier-naming.GlobalFunctionCase - key: readability-identifier-naming.GlobalFunctionCase
value: UPPER_CASE value: UPPER_CASE
- key: readability-identifier-naming.IgnoreMainLikeFunctions
value: false

View File

@ -3,3 +3,5 @@
void STYLE_SECOND_GOOD(); void STYLE_SECOND_GOOD();
void styleSecondBad(); void styleSecondBad();
int thisIsMainLikeNotIgnored(int argc, const char *argv[]) {}

View File

@ -13,6 +13,7 @@
// RUN: readability-identifier-naming %t -- \ // RUN: readability-identifier-naming %t -- \
// RUN: -config='{ InheritParentConfig: true, CheckOptions: [ \ // RUN: -config='{ InheritParentConfig: true, CheckOptions: [ \
// RUN: {key: readability-identifier-naming.FunctionCase, value: camelBack}, \ // RUN: {key: readability-identifier-naming.FunctionCase, value: camelBack}, \
// RUN: {key: readability-identifier-naming.ParameterCase, value: CamelCase}, \
// RUN: {key: readability-identifier-naming.GetConfigPerFile, value: true} \ // RUN: {key: readability-identifier-naming.GetConfigPerFile, value: true} \
// RUN: ]}' -header-filter='.*' -- -I%theaders // RUN: ]}' -header-filter='.*' -- -I%theaders
@ -21,20 +22,14 @@
// RUN: cp -R %S/Inputs/readability-identifier-naming/. %theaders // RUN: cp -R %S/Inputs/readability-identifier-naming/. %theaders
// RUN: %check_clang_tidy -check-suffixes=DISABLED,SHARED -std=c++11 %s \ // RUN: %check_clang_tidy -check-suffixes=DISABLED,SHARED -std=c++11 %s \
// RUN: readability-identifier-naming %t -- \ // RUN: readability-identifier-naming %t -- \
// RUN: -config='{ InheritParentConfig: true, CheckOptions: [ \ // RUN: -config='{ InheritParentConfig: false, CheckOptions: [ \
// RUN: {key: readability-identifier-naming.FunctionCase, value: camelBack}, \ // RUN: {key: readability-identifier-naming.FunctionCase, value: camelBack}, \
// RUN: {key: readability-identifier-naming.ParameterCase, value: CamelCase}, \
// RUN: {key: readability-identifier-naming.GetConfigPerFile, value: false} \ // RUN: {key: readability-identifier-naming.GetConfigPerFile, value: false} \
// RUN: ]}' -header-filter='.*' -- -I%theaders // RUN: ]}' -header-filter='.*' -- -I%theaders
#include "global-style-disabled/header.h"
#include "global-style1/header.h" #include "global-style1/header.h"
#include "global-style2/header.h" #include "global-style2/header.h"
// CHECK-MESSAGES-ENABLED-DAG: global-style1/header.h:5:6: warning: invalid case style for global function 'styleFirstBad'
// CHECK-MESSAGES-ENABLED-DAG: global-style2/header.h:5:6: warning: invalid case style for global function 'styleSecondBad'
// CHECK-MESSAGES-DISABLED-DAG: global-style1/header.h:3:6: warning: invalid case style for function 'style_first_good'
// CHECK-MESSAGES-DISABLED-DAG: global-style2/header.h:3:6: warning: invalid case style for function 'STYLE_SECOND_GOOD'
// CHECK-MESSAGES-DISABLED-DAG: global-style-disabled/header.h:1:6: warning: invalid case style for function 'disabled_style_1'
// CHECK-MESSAGES-DISABLED-DAG: global-style-disabled/header.h:3:6: warning: invalid case style for function 'DISABLED_STYLE_3'
void goodStyle() { void goodStyle() {
style_first_good(); style_first_good();
@ -42,7 +37,7 @@ void goodStyle() {
// CHECK-FIXES-DISABLED: styleFirstGood(); // CHECK-FIXES-DISABLED: styleFirstGood();
// CHECK-FIXES-DISABLED-NEXT: styleSecondGood(); // CHECK-FIXES-DISABLED-NEXT: styleSecondGood();
} }
// CHECK-MESSAGES-SHARED-DAG: :[[@LINE+1]]:6: warning: invalid case style for function 'bad_style' // CHECK-MESSAGES-SHARED: :[[@LINE+1]]:6: warning: invalid case style for function 'bad_style'
void bad_style() { void bad_style() {
styleFirstBad(); styleFirstBad();
styleSecondBad(); styleSecondBad();
@ -54,11 +49,14 @@ void bad_style() {
// CHECK-FIXES-ENABLED-NEXT: STYLE_SECOND_BAD(); // CHECK-FIXES-ENABLED-NEXT: STYLE_SECOND_BAD();
// CHECK-FIXES-SHARED-NEXT: } // CHECK-FIXES-SHARED-NEXT: }
void expectNoStyle() { // CHECK-MESSAGES-DISABLED: global-style1/header.h:3:6: warning: invalid case style for function 'style_first_good'
disabled_style_1(); // CHECK-MESSAGES-ENABLED: global-style1/header.h:5:6: warning: invalid case style for global function 'styleFirstBad'
disabledStyle2(); // CHECK-MESSAGES-ENABLED: global-style1/header.h:7:5: warning: invalid case style for global function 'thisIsMainLikeIgnored'
DISABLED_STYLE_3(); // CHECK-MESSAGES-DISABLED: global-style1/header.h:7:31: warning: invalid case style for parameter 'argc'
// CHECK-FIXES-DISABLED: disabledStyle1(); // CHECK-MESSAGES-DISABLED: global-style1/header.h:7:49: warning: invalid case style for parameter 'argv'
// CHECK-FIXES-DISABLED-NEXT: disabledStyle2();
// CHECK-FIXES-DISABLED-NEXT: disabledStyle3(); // CHECK-MESSAGES-DISABLED: global-style2/header.h:3:6: warning: invalid case style for function 'STYLE_SECOND_GOOD'
} // CHECK-MESSAGES-ENABLED: global-style2/header.h:5:6: warning: invalid case style for global function 'styleSecondBad'
// CHECK-MESSAGES-ENABLED: global-style2/header.h:7:5: warning: invalid case style for global function 'thisIsMainLikeNotIgnored'
// CHECK-MESSAGES-SHARED: global-style2/header.h:7:34: warning: invalid case style for parameter 'argc'
// CHECK-MESSAGES-SHARED: global-style2/header.h:7:52: warning: invalid case style for parameter 'argv'