Checker for non-standard member variable naming styles. Detects: - Google-style trailing underscore (state_, is_ready_) - m-underscore prefix (m_hybridNumDecim, m_isReady, m_some_var)
| 98 | |
| 99 | |
| 100 | class MemberStyleChecker(FileContentChecker): |
| 101 | """Checker for non-standard member variable naming styles. |
| 102 | |
| 103 | Detects: |
| 104 | - Google-style trailing underscore (state_, is_ready_) |
| 105 | - m-underscore prefix (m_hybridNumDecim, m_isReady, m_some_var) |
| 106 | """ |
| 107 | |
| 108 | # Pre-compiled regex for member variable declarations with trailing underscore. |
| 109 | # Matches: type_name var_name_; or type_name var_name_ = ...; |
| 110 | # Also matches: type_name* var_name_; or type_name& var_name_; |
| 111 | # Requires at least 2 characters before the trailing underscore. |
| 112 | _TRAILING_UNDERSCORE_PATTERN = re.compile( |
| 113 | r"\b" # Word boundary |
| 114 | r"(?:const\s+)?" # Optional const |
| 115 | r"(?:static\s+)?" # Optional static |
| 116 | r"(?:volatile\s+)?" # Optional volatile |
| 117 | r"(?:mutable\s+)?" # Optional mutable |
| 118 | r"[\w:]+(?:<[^>]+>)?" # Type name (with optional template args) |
| 119 | r"[\s*&]+" # Required separator (whitespace and/or pointer/reference) |
| 120 | r"\s*" # Optional trailing whitespace |
| 121 | r"(\w{2,}_)" # Variable name with trailing underscore (capture group 1) |
| 122 | r"\s*" # Optional whitespace |
| 123 | r"[;=,)]" # Followed by semicolon, equals, comma, or closing paren |
| 124 | ) |
| 125 | |
| 126 | # Pre-compiled regex for member variable declarations with m_ prefix. |
| 127 | # Matches: type_name m_varName; or type_name m_varName = ...; |
| 128 | _M_UNDERSCORE_PATTERN = re.compile( |
| 129 | r"\b" # Word boundary |
| 130 | r"(?:const\s+)?" # Optional const |
| 131 | r"(?:static\s+)?" # Optional static |
| 132 | r"(?:volatile\s+)?" # Optional volatile |
| 133 | r"(?:mutable\s+)?" # Optional mutable |
| 134 | r"[\w:]+(?:<[^>]+>)?" # Type name (with optional template args) |
| 135 | r"[\s*&]+" # Required separator (whitespace and/or pointer/reference) |
| 136 | r"\s*" # Optional trailing whitespace |
| 137 | r"(m_\w+)" # Variable name with m_ prefix (capture group 1) |
| 138 | r"\s*" # Optional whitespace |
| 139 | r"[;=,)]" # Followed by semicolon, equals, comma, or closing paren |
| 140 | ) |
| 141 | |
| 142 | # Pre-compiled regex for removing string literals before checking |
| 143 | _STRING_LITERAL_PATTERN = re.compile(r'"[^"]*"') |
| 144 | |
| 145 | # Pre-compiled set of excluded files for O(1) suffix lookups |
| 146 | _EXCLUDED_SET = frozenset(EXCLUDED_FILES) |
| 147 | |
| 148 | def __init__(self): |
| 149 | self.violations: dict[str, list[tuple[int, str]]] = {} |
| 150 | |
| 151 | def should_process_file(self, file_path: str) -> bool: |
| 152 | """Only process C++ source and header files.""" |
| 153 | # Check file extension |
| 154 | if not file_path.endswith((".h", ".hpp", ".cpp")): |
| 155 | return False |
| 156 | |
| 157 | # Check if file is in excluded list |