dougpuob updated this revision to Diff 291371.
dougpuob added a comment.
Fixed crash on Windows when run regression test (llvm-lit for
`readability-identifier-naming.cpp` file).
This is because over range parameter made ctor of std::string copying out of
range memory from source. The over range parameter came from
SourceManager::getCharacterData() function with the SourceLocation returning
value of ValDecl->getLocation().
Find the terminated char insteads of calling `ValDecl->getLocation()` function.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D86671/new/
https://reviews.llvm.org/D86671
Files:
clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst
clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming-hungarian-notation.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming-hungarian-notation.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming-hungarian-notation.cpp
@@ -0,0 +1,263 @@
+typedef signed char int8_t; // NOLINT
+typedef short int16_t; // NOLINT
+typedef long int32_t; // NOLINT
+typedef long long int64_t; // NOLINT
+typedef unsigned char uint8_t; // NOLINT
+typedef unsigned short uint16_t; // NOLINT
+typedef unsigned long uint32_t; // NOLINT
+typedef unsigned long long uint64_t; // NOLINT
+#ifndef _WIN32
+typedef unsigned long long size_t; // NOLINT
+#endif
+typedef long intptr_t; // NOLINT
+typedef unsigned long uintptr_t; // NOLINT
+typedef long int ptrdiff_t; // NOLINT
+typedef unsigned char BYTE; // NOLINT
+typedef unsigned short WORD; // NOLINT
+typedef unsigned long DWORD; // NOLINT
+typedef int BOOL; // NOLINT
+typedef BYTE BOOLEAN; // NOLINT
+#define NULL (0) // NOLINT
+
+// RUN: clang-tidy %s -checks=readability-identifier-naming \
+// RUN: -config="{CheckOptions: [\
+// RUN: {key: readability-identifier-naming.FunctionCase , value: CamelCase }, \
+// RUN: {key: readability-identifier-naming.ClassCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.TypedefCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.MemberCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.ClassMemberCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.ConstantMemberCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.VariableCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.ParameterCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.GlobalPointerCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.GlobalVariableCase , value: szHungarianNotation }, \
+// RUN: {key: readability-identifier-naming.GlobalFunctionCase , value: CamelCase } \
+// RUN: ]}"
+
+class UnlistedClass { public: mutable int ValInt; };
+// CHECK-MESSAGES: :[[@LINE-1]]:43: warning: invalid case style for member 'ValInt' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}class UnlistedClass { public: mutable int iValInt; };
+
+UnlistedClass cUnlisted2;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for global variable 'cUnlisted2' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}UnlistedClass Unlisted2;
+
+UnlistedClass objUnlistedClass3;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for global variable 'objUnlistedClass3' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}UnlistedClass UnlistedClass3;
+
+typedef int INDEX;
+INDEX iIndex = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'iIndex' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}INDEX Index = 0;
+
+struct DataBuffer {
+ mutable size_t Size;
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: invalid case style for member 'Size' [readability-identifier-naming]
+// CHECK-FIXES: {{^}} mutable size_t nSize;
+
+int &RefValueIndex = iIndex;
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'RefValueIndex' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int &iRefValueIndex = Index;
+
+typedef void (*FUNC_PTR_HELLO)();
+FUNC_PTR_HELLO Hello = NULL;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for global pointer 'Hello' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}FUNC_PTR_HELLO fnHello = NULL;
+
+void *ValueVoidPtr = NULL;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global pointer 'ValueVoidPtr' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}void *pValueVoidPtr = NULL;
+
+ptrdiff_t PtrDiff = NULL;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: invalid case style for global variable 'PtrDiff' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}ptrdiff_t pPtrDiff = NULL;
+
+const char *NamePtr = "Name";
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for global pointer 'NamePtr' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}const char *szNamePtr = "Name";
+
+const char NameArray[] = "Name";
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for global variable 'NameArray' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}const char szNameArray[] = "Name";
+
+const char *NamePtrArray[] = {"AA", "BB"};
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for global variable 'NamePtrArray' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}const char *pszNamePtrArray[] = {"AA", "BB"};
+
+int DataInt[1] = {0};
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for global variable 'DataInt' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int aDataInt[1] = {0};
+
+int *DataIntPtr[1] = {0};
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'DataIntPtr' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int *paDataIntPtr[1] = {0};
+
+void *BufferPtr1;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global pointer 'BufferPtr1' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}void *pBufferPtr1;
+
+void **BufferPtr2;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global pointer 'BufferPtr2' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}void **ppBufferPtr2;
+
+void **pBufferPtr3;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global pointer 'pBufferPtr3' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}void **ppBufferPtr3;
+
+int *pBufferPtr4;
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global pointer 'pBufferPtr4' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int *piBufferPtr4;
+
+int DataArray[2] = {0};
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for global variable 'DataArray' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int aDataArray[2] = {0};
+
+int8_t *ValueI8Ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for global pointer 'ValueI8Ptr' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int8_t *pi8ValueI8Ptr;
+
+uint8_t *ValueU8Ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for global pointer 'ValueU8Ptr' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}uint8_t *pu8ValueU8Ptr;
+
+int8_t ValueI8;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global variable 'ValueI8' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int8_t i8ValueI8;
+
+int16_t ValueI16 = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for global variable 'ValueI16' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int16_t i16ValueI16 = 0;
+
+int32_t ValueI32 = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for global variable 'ValueI32' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int32_t i32ValueI32 = 0;
+
+int64_t ValueI64 = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for global variable 'ValueI64' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int64_t i64ValueI64 = 0;
+
+uint8_t ValueU8 = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for global variable 'ValueU8' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}uint8_t u8ValueU8 = 0;
+
+uint16_t ValueU16 = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for global variable 'ValueU16' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}uint16_t u16ValueU16 = 0;
+
+uint32_t ValueU32 = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for global variable 'ValueU32' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}uint32_t u32ValueU32 = 0;
+
+uint64_t ValueU64 = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for global variable 'ValueU64' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}uint64_t u64ValueU64 = 0;
+
+float ValueFloat = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'ValueFloat' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}float fValueFloat = 0;
+
+double ValueDouble = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global variable 'ValueDouble' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}double dValueDouble = 0;
+
+char ValueChar = 'c';
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'ValueChar' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}char cValueChar = 'c';
+
+bool ValueBool = true;
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'ValueBool' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}bool bValueBool = true;
+
+int ValueInt = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for global variable 'ValueInt' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int iValueInt = 0;
+
+int &RefValueInt = ValueInt;
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'RefValueInt' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}int &iRefValueInt = iValueInt;
+
+size_t ValueSize = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global variable 'ValueSize' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}size_t nValueSize = 0;
+
+wchar_t ValueWchar = 'w';
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for global variable 'ValueWchar' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}wchar_t wcValueWchar = 'w';
+
+short ValueShort = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'ValueShort' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}short sValueShort = 0;
+
+unsigned ValueUnsigned = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for global variable 'ValueUnsigned' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}unsigned uValueUnsigned = 0;
+
+signed ValueSigned = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global variable 'ValueSigned' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}signed iValueSigned = 0;
+
+long ValueLong = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'ValueLong' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}long lValueLong = 0;
+
+long long ValueLongLong = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: invalid case style for global variable 'ValueLongLong' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}long long llValueLongLong = 0;
+
+long long &RefValueLongLong = ValueLongLong;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for global variable 'RefValueLongLong' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}long long &llRefValueLongLong = llValueLongLong;
+
+long double ValueLongDouble = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for global variable 'ValueLongDouble' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}long double ldValueLongDouble = 0;
+
+volatile int VolatileInt = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global variable 'VolatileInt' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}volatile int iVolatileInt = 0;
+
+const int &ConstRefValue = ValueInt;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for global variable 'ConstRefValue' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}const int &iConstRefValue = iValueInt;
+
+thread_local int ThreadLocalValueInt = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: invalid case style for global variable 'ThreadLocalValueInt' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}thread_local int iThreadLocalValueInt = 0;
+
+extern int ExternValueInt;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for global variable 'ExternValueInt' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}extern int iExternValueInt;
+
+void MyFunc1(int Val){}
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: invalid case style for parameter 'Val' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}void MyFunc1(int iVal){}
+
+void MyFunc2(void* Val){}
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: invalid case style for parameter 'Val' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}void MyFunc2(void* pVal){}
+
+static constexpr int const &ConstExprInt = 42;
+// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: invalid case style for global variable 'ConstExprInt' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}static constexpr int const &iConstExprInt = 42;
+
+DWORD MsDword = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'MsDword' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}DWORD dwMsDword = 0;
+
+BYTE MsByte = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'MsByte' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}BYTE byMsByte = 0;
+
+WORD MsWord = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'MsWord' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}WORD wMsWord = 0;
+
+BOOL MsBool = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global variable 'MsBool' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}BOOL bMsBool = 0;
+
+BOOLEAN MsBoolean = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for global variable 'MsBoolean' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}BOOLEAN bMsBoolean = 0;
Index: clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst
@@ -17,7 +17,8 @@
- ``CamelCase``,
- ``camel_Snake_Back``,
- ``Camel_Snake_Case``,
- - ``aNy_CasE``.
+ - ``aNy_CasE``,
+ - ``szHungarianNotation``.
It also supports a fixed prefix and suffix that will be prepended or appended
to the identifiers, regardless of the casing.
@@ -30,6 +31,67 @@
but not where they are overridden, as it can't be fixed locally there.
This also applies for pseudo-override patterns like CRTP.
+Hungarian Notation casing type
+------------------------------
+
+In Hungarian notation, a variable name starts with a group of lower-case
+letters which are mnemonics for the type or purpose of that variable, followed
+by whatever name the programmer has chosen; this last part is sometimes
+distinguished as the given name. The first character of the given name can be
+capitalized to separate it from the type indicators (see also CamelCase).
+Otherwise the case of this character denotes scope.
+
+============ ============= ================ ============= =========== ==============
+Primitive Types Microsoft data types
+--------------------------------------------------------- --------------------------
+ Type Prefix Type Prefix Type Prefix
+============ ============= ================ ============= =========== ==============
+int8_t i8 short s BOOL b
+int16_t i16 signed i BOOLEAN b
+int32_t i32 unsigned u BYTE by
+int64_t i64 long l WORD w
+uint8_t u8 long long ll DWORD dw
+uint16_t u16 unsigned long ul
+uint32_t u32 long double ld
+uint64_t u64 ptrdiff_t p
+char8_t c8
+char16_t c16
+char32_t c32
+float f
+double d
+char c
+bool b
+_Bool b
+int i
+size_t n
+============ ============= ================ ============= =========== ==============
+
+
+
+- **Pointer type starts with `p`,**
+
+ .. code-block:: c++
+
+ void *pData = NULL;
+ void **ppData = NULL;
+ uint8_t *pu8Data = NULL;
+
+- **Array type start with `a`,**
+
+ .. code-block:: c++
+
+ int aDataInt[1] = {0};
+ int* paDataIntPtr[1] = {0};
+
+- **Null terminated string starts with `sz`**
+
+ .. code-block:: c++
+
+ char szNameArray[] = {"Text"};
+ char *szNamePtr = {"Text"};
+ char **pszNamePtr = {"Text"};
+
+
Options
-------
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -88,6 +88,13 @@
Added an option `GetConfigPerFile` to support including files which use
different naming styles.
+- Improved :doc:`readability-identifier-naming
+ <clang-tidy/checks/readability-identifier-naming>` check.
+
+ Added a casing types `szHungarianNotation` to support variables could be
+ checked with Hungarian Notation which the prefix encodes the actual data type
+ of the variable.
+
Improvements to include-fixer
-----------------------------
Index: clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
+++ clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
@@ -36,6 +36,7 @@
IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context);
~IdentifierNamingCheck();
+ std::string getDeclTypeName(const clang::NamedDecl *Decl) const;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
enum CaseType {
@@ -45,7 +46,8 @@
CT_UpperCase,
CT_CamelCase,
CT_CamelSnakeCase,
- CT_CamelSnakeBack
+ CT_CamelSnakeBack,
+ CT_HungarianNotation
};
struct NamingStyle {
Index: clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -44,7 +44,9 @@
{readability::IdentifierNamingCheck::CT_CamelSnakeCase,
"Camel_Snake_Case"},
{readability::IdentifierNamingCheck::CT_CamelSnakeBack,
- "camel_Snake_Back"}};
+ "camel_Snake_Back"},
+ {readability::IdentifierNamingCheck::CT_HungarianNotation,
+ "szHungarianNotation"}};
return llvm::makeArrayRef(Mapping);
}
@@ -178,8 +180,245 @@
Options.store(Opts, "IgnoreMainLikeFunctions", IgnoreMainLikeFunctions);
}
-static bool matchesStyle(StringRef Name,
- IdentifierNamingCheck::NamingStyle Style) {
+static const std::string
+getHungarianNotationTypePrefix(const std::string &TypeName,
+ const NamedDecl *InputDecl) {
+ if (!InputDecl || TypeName.empty()) {
+ return TypeName;
+ }
+
+ // clang-format off
+ const static llvm::StringMap<StringRef> HungarianNotationTable = {
+ // Primitive types
+ {"int8_t", "i8"},
+ {"int16_t", "i16"},
+ {"int32_t", "i32"},
+ {"int64_t", "i64"},
+ {"uint8_t", "u8"},
+ {"uint16_t", "u16"},
+ {"uint32_t", "u32"},
+ {"uint64_t", "u64"},
+ {"char8_t", "c8"},
+ {"char16_t", "c16"},
+ {"char32_t", "c32"},
+ {"float", "f"},
+ {"double", "d"},
+ {"char", "c"},
+ {"bool", "b"},
+ {"_Bool", "b"},
+ {"int", "i"},
+ {"size_t", "n"},
+ {"wchar_t", "wc"},
+ {"short", "s"},
+ {"signed", "i"},
+ {"unsigned", "u"},
+ {"long", "l"},
+ {"long long", "ll"},
+ {"unsigned long", "ul"},
+ {"long double", "ld"},
+ {"ptrdiff_t", "p"},
+ // Windows data types
+ {"BOOL", "b"},
+ {"BOOLEAN", "b"},
+ {"BYTE", "by"},
+ {"WORD", "w"},
+ {"DWORD", "dw"}};
+ // clang-format on
+
+ std::string ClonedTypeName = TypeName;
+
+ // Handle null string
+ std::string PrefixStr;
+ if (const auto *TD = dyn_cast<ValueDecl>(InputDecl)) {
+ auto QT = TD->getType();
+ if (QT->isFunctionPointerType()) {
+ PrefixStr = "fn"; // Function Pointer
+ } else if (QT->isPointerType()) {
+ // clang-format off
+ const static llvm::StringMap<StringRef> NullString = {
+ {"char*", "sz"},
+ {"wchar_t*", "wsz"}};
+ // clang-format on
+ for (const auto &Type : NullString) {
+ const auto &Key = Type.getKey();
+ if (ClonedTypeName.find(Key.str()) == 0) {
+ PrefixStr = Type.getValue().str();
+ ClonedTypeName = ClonedTypeName.substr(
+ Key.size(), ClonedTypeName.size() - Key.size());
+ break;
+ }
+ }
+ } else if (QT->isArrayType()) {
+ // clang-format off
+ const static llvm::StringMap<StringRef> NullString = {
+ {"char", "sz"},
+ {"wchar_t", "wsz"}};
+ // clang-format on
+ for (const auto &Type : NullString) {
+ const auto &Key = Type.getKey();
+ if (ClonedTypeName.find(Key.str()) == 0) {
+ PrefixStr = Type.getValue().str();
+ ClonedTypeName = ClonedTypeName.substr(
+ Key.size(), ClonedTypeName.size() - Key.size());
+ break;
+ }
+ }
+ if (PrefixStr.empty()) {
+ PrefixStr = 'a'; // Array
+ }
+ } else if (QT->isReferenceType()) {
+ size_t Pos = ClonedTypeName.find_last_of("&");
+ if (Pos != std::string::npos) {
+ ClonedTypeName = ClonedTypeName.substr(0, Pos);
+ }
+ }
+ }
+
+ // Handle pointers
+ size_t PtrCount = [&](std::string TypeName) -> size_t {
+ size_t Pos = TypeName.find('*');
+ size_t Count = 0;
+ for (; Pos < TypeName.length(); Pos++, Count++) {
+ if ('*' != TypeName[Pos])
+ break;
+ }
+ return Count;
+ }(ClonedTypeName);
+ if (PtrCount > 0) {
+ ClonedTypeName = [&](std::string Str, const std::string &From,
+ const std::string &To) {
+ size_t StartPos = 0;
+ while ((StartPos = Str.find(From, StartPos)) != std::string::npos) {
+ Str.replace(StartPos, From.length(), To);
+ StartPos += To.length();
+ }
+ return Str;
+ }(ClonedTypeName, "*", "");
+ }
+
+ if (PrefixStr.empty()) {
+ for (const auto &Type : HungarianNotationTable) {
+ const auto &Key = Type.getKey();
+ if (ClonedTypeName == Key) {
+ PrefixStr = Type.getValue().str();
+ break;
+ }
+ }
+ }
+
+ if (PtrCount > 0) {
+ for (size_t Idx = 0; Idx < PtrCount; Idx++) {
+ PrefixStr.insert(PrefixStr.begin(), 'p');
+ }
+ }
+
+ return PrefixStr;
+}
+
+std::string
+IdentifierNamingCheck::getDeclTypeName(const clang::NamedDecl *Decl) const {
+ const ValueDecl *ValDecl = dyn_cast<ValueDecl>(Decl);
+ if (!ValDecl) {
+ return "";
+ }
+
+ if (clang::Decl::Kind::EnumConstant == Decl->getKind() ||
+ clang::Decl::Kind::CXXMethod == Decl->getKind() ||
+ clang::Decl::Kind::Function == Decl->getKind()) {
+ return "";
+ }
+
+ // Get type text of variable declarations.
+ auto &SM = ValDecl->getASTContext().getSourceManager();
+ const char *Begin = SM.getCharacterData(ValDecl->getBeginLoc());
+ const char *End = SM.getCharacterData(ValDecl->getEndLoc());
+ intptr_t StrLen = End - Begin;
+
+ // FIXME: Sometimes the value that returns from ValDecl->getEndLoc()
+ // is wrong(out of location of Decl). This causes `StrLen` will be assigned
+ // an unexpected large value. Current workaround to find the terminated
+ // character instead of the `getEndLoc()` function.
+ char *EOL = const_cast<char *>(strchr(Begin, '\n'));
+ if (!EOL) {
+ EOL = const_cast<char *>(Begin) + strlen(Begin);
+ }
+ std::vector<const char *> PosList = {strchr(Begin, '='), strchr(Begin, ';'),
+ strchr(Begin, ','), strchr(Begin, ')'),
+ EOL};
+ for (auto &Pos : PosList) {
+ if (Pos > Begin) {
+ EOL = std::min(EOL, const_cast<char *>(Pos));
+ }
+ }
+
+ StrLen = EOL - Begin;
+ std::string TypeName;
+ if (StrLen > 0) {
+ std::string Type(Begin, StrLen);
+
+ const static std::list<std::string> Keywords = {
+ // Constexpr specifiers
+ "constexpr", "constinit", "consteval",
+ // Qualifier
+ "const", "volatile", "restrict", "mutable",
+ // Storage class specifiers
+ "register", "static", "extern", "thread_local",
+ // Other keywords
+ "virtual"};
+
+ // Remove keywords
+ for (const std::string &Kw : Keywords) {
+ for (size_t Pos = 0; (Pos = Type.find(Kw, Pos)) != std::string::npos;) {
+ Type.replace(Pos, Kw.length(), "");
+ }
+ }
+
+ // Replace spaces with single space.
+ for (size_t Pos = 0; (Pos = Type.find(" ", Pos)) != std::string::npos;
+ Pos += strlen(" ")) {
+ Type.replace(Pos, strlen(" "), " ");
+ }
+
+ // Replace " &" with "&".
+ for (size_t Pos = 0; (Pos = Type.find(" &", Pos)) != std::string::npos;
+ Pos += strlen("&")) {
+ Type.replace(Pos, strlen(" &"), "&");
+ }
+
+ // Replace " *" with "* ".
+ for (size_t Pos = 0; (Pos = Type.find(" *", Pos)) != std::string::npos;
+ Pos += strlen("*")) {
+ Type.replace(Pos, strlen(" *"), "* ");
+ }
+
+ // Remove redundant tailing.
+ const static std::list<std::string> TailsOfMultiWordType = {
+ " int", " char", " double", " long"};
+ bool RedundantRemoved = false;
+ for (const std::string &Kw : TailsOfMultiWordType) {
+ for (size_t Pos = 0; (Pos = Type.find(Kw, Pos)) != std::string::npos;) {
+ Type = Type.substr(0, Pos + Kw.length());
+ RedundantRemoved = true;
+ break;
+ }
+ }
+ TypeName = Type.erase(0, Type.find_first_not_of(" "));
+ if (!RedundantRemoved) {
+ std::size_t FoundSpace = Type.find(" ");
+ if (FoundSpace != std::string::npos) {
+ Type = Type.substr(0, FoundSpace);
+ }
+ }
+
+ TypeName = Type.erase(0, Type.find_first_not_of(" "));
+ }
+
+ return TypeName;
+}
+
+static bool matchesStyle(StringRef Type, StringRef Name,
+ IdentifierNamingCheck::NamingStyle Style,
+ const NamedDecl *Decl) {
static llvm::Regex Matchers[] = {
llvm::Regex("^.*$"),
llvm::Regex("^[a-z][a-z0-9_]*$"),
@@ -188,6 +427,7 @@
llvm::Regex("^[A-Z][a-zA-Z0-9]*$"),
llvm::Regex("^[A-Z]([a-z0-9]*(_[A-Z])?)*"),
llvm::Regex("^[a-z]([a-z0-9]*(_[A-Z])?)*"),
+ llvm::Regex("^[A-Z][a-zA-Z0-9]*$"),
};
if (!Name.consume_front(Style.Prefix))
@@ -200,13 +440,24 @@
if (Name.startswith("_") || Name.endswith("_"))
return false;
+ if (Style.Case == IdentifierNamingCheck::CaseType::CT_HungarianNotation) {
+ const std::string TypePrefix =
+ getHungarianNotationTypePrefix(Type.str(), Decl);
+ if (TypePrefix.length() > 0) {
+ if (!Name.startswith(TypePrefix))
+ return false;
+ Name = Name.drop_front(TypePrefix.size());
+ }
+ }
+
if (Style.Case && !Matchers[static_cast<size_t>(*Style.Case)].match(Name))
return false;
return true;
}
-static std::string fixupWithCase(StringRef Name,
+static std::string fixupWithCase(const StringRef &Type, const StringRef &Name,
+ const Decl *InputDecl,
IdentifierNamingCheck::CaseType Case) {
static llvm::Regex Splitter(
"([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
@@ -298,8 +549,26 @@
Fixup += Word.substr(1).lower();
}
break;
- }
+ case IdentifierNamingCheck::CT_HungarianNotation: {
+ const NamedDecl *ND = dyn_cast<NamedDecl>(InputDecl);
+ const std::string TypePrefix =
+ getHungarianNotationTypePrefix(Type.str(), ND);
+ Fixup = TypePrefix;
+ for (size_t Idx = 0; Idx < Words.size(); Idx++) {
+ // Skip first part if it's a lowercase string.
+ if (Idx == 0) {
+ bool LowerAlnum =
+ std::all_of(Words[Idx].begin(), Words[Idx].end(),
+ [](const char C) { return isdigit(C) || islower(C); });
+ if (LowerAlnum)
+ continue;
+ }
+ Fixup += Words[Idx];
+ }
+ break;
+ }
+ }
return Fixup.str().str();
}
@@ -365,10 +634,12 @@
}
static std::string
-fixupWithStyle(StringRef Name,
- const IdentifierNamingCheck::NamingStyle &Style) {
+fixupWithStyle(const StringRef &Type, const StringRef &Name,
+ const IdentifierNamingCheck::NamingStyle &Style,
+ const Decl *InputDecl) {
const std::string Fixed = fixupWithCase(
- Name, Style.Case.getValueOr(IdentifierNamingCheck::CaseType::CT_AnyCase));
+ Type, Name, InputDecl,
+ Style.Case.getValueOr(IdentifierNamingCheck::CaseType::CT_AnyCase));
StringRef Mid = StringRef(Fixed).trim("_");
if (Mid.empty())
Mid = "_";
@@ -384,7 +655,7 @@
if (isa<ObjCIvarDecl>(D) && NamingStyles[SK_ObjcIvar])
return SK_ObjcIvar;
-
+
if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef])
return SK_Typedef;
@@ -547,7 +818,7 @@
if (Decl->isStaticLocal() && NamingStyles[SK_StaticVariable])
return SK_StaticVariable;
-
+
if (Decl->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() && NamingStyles[SK_LocalPointer])
return SK_LocalPointer;
@@ -655,21 +926,22 @@
}
static llvm::Optional<RenamerClangTidyCheck::FailureInfo> getFailureInfo(
- StringRef Name, SourceLocation Location,
+ const StringRef &Type, const StringRef &Name, const NamedDecl *Decl,
+ SourceLocation Location,
ArrayRef<llvm::Optional<IdentifierNamingCheck::NamingStyle>> NamingStyles,
StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit) {
if (SK == SK_Invalid || !NamingStyles[SK])
return None;
const IdentifierNamingCheck::NamingStyle &Style = *NamingStyles[SK];
- if (matchesStyle(Name, Style))
+ if (matchesStyle(Type, Name, Style, Decl))
return None;
- std::string KindName =
- fixupWithCase(StyleNames[SK], IdentifierNamingCheck::CT_LowerCase);
+ std::string KindName = fixupWithCase(Type, StyleNames[SK], Decl,
+ IdentifierNamingCheck::CT_LowerCase);
std::replace(KindName.begin(), KindName.end(), '_', ' ');
- std::string Fixup = fixupWithStyle(Name, Style);
+ std::string Fixup = fixupWithStyle(Type, Name, Style, Decl);
if (StringRef(Fixup).equals(Name)) {
if (!IgnoreFailedSplit) {
LLVM_DEBUG(Location.print(llvm::dbgs(), SM);
@@ -690,8 +962,9 @@
ArrayRef<llvm::Optional<NamingStyle>> NamingStyles =
getStyleForFile(SM.getFilename(Loc));
+ std::string TypeName = getDeclTypeName(Decl);
return getFailureInfo(
- Decl->getName(), Loc, NamingStyles,
+ TypeName, Decl->getName(), Decl, Loc, NamingStyles,
findStyleKind(Decl, NamingStyles, IgnoreMainLikeFunctions), SM,
IgnoreFailedSplit);
}
@@ -701,8 +974,8 @@
const SourceManager &SM) const {
SourceLocation Loc = MacroNameTok.getLocation();
- return getFailureInfo(MacroNameTok.getIdentifierInfo()->getName(), Loc,
- getStyleForFile(SM.getFilename(Loc)),
+ return getFailureInfo("", MacroNameTok.getIdentifierInfo()->getName(), NULL,
+ Loc, getStyleForFile(SM.getFilename(Loc)),
SK_MacroDefinition, SM, IgnoreFailedSplit);
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits