cppcheck-py 2.19.0__py3-none-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cppcheck/__init__.py +55 -0
- cppcheck/cppcheck-2.19.0.tar.gz +0 -0
- cppcheck/data/addons/__init__.py +0 -0
- cppcheck/data/addons/cppcheck.py +41 -0
- cppcheck/data/addons/cppcheckdata.py +1727 -0
- cppcheck/data/addons/findcasts.py +32 -0
- cppcheck/data/addons/misc.py +163 -0
- cppcheck/data/addons/misra.py +5153 -0
- cppcheck/data/addons/misra_9.py +559 -0
- cppcheck/data/addons/naming.py +92 -0
- cppcheck/data/addons/namingng.py +420 -0
- cppcheck/data/addons/runaddon.py +16 -0
- cppcheck/data/addons/threadsafety.py +350 -0
- cppcheck/data/addons/y2038.py +602 -0
- cppcheck/data/cfg/avr.cfg +402 -0
- cppcheck/data/cfg/bento4.cfg +142 -0
- cppcheck/data/cfg/boost.cfg +1284 -0
- cppcheck/data/cfg/bsd.cfg +567 -0
- cppcheck/data/cfg/cairo.cfg +89 -0
- cppcheck/data/cfg/cppcheck-lib.cfg +72 -0
- cppcheck/data/cfg/cppunit.cfg +48 -0
- cppcheck/data/cfg/dpdk.cfg +11 -0
- cppcheck/data/cfg/embedded_sql.cfg +4 -0
- cppcheck/data/cfg/emscripten.cfg +108 -0
- cppcheck/data/cfg/ginac.cfg +12848 -0
- cppcheck/data/cfg/gnu.cfg +1738 -0
- cppcheck/data/cfg/googletest.cfg +62 -0
- cppcheck/data/cfg/gtk.cfg +23082 -0
- cppcheck/data/cfg/icu.cfg +221 -0
- cppcheck/data/cfg/kde.cfg +92 -0
- cppcheck/data/cfg/libcerror.cfg +203 -0
- cppcheck/data/cfg/libcurl.cfg +487 -0
- cppcheck/data/cfg/libsigc++.cfg +36 -0
- cppcheck/data/cfg/lua.cfg +316 -0
- cppcheck/data/cfg/mfc.cfg +271 -0
- cppcheck/data/cfg/microsoft_atl.cfg +40 -0
- cppcheck/data/cfg/microsoft_sal.cfg +490 -0
- cppcheck/data/cfg/microsoft_unittest.cfg +20 -0
- cppcheck/data/cfg/motif.cfg +318 -0
- cppcheck/data/cfg/nspr.cfg +38 -0
- cppcheck/data/cfg/ntl.cfg +6907 -0
- cppcheck/data/cfg/opencv2.cfg +132 -0
- cppcheck/data/cfg/opengl.cfg +581 -0
- cppcheck/data/cfg/openmp.cfg +157 -0
- cppcheck/data/cfg/openssl.cfg +174 -0
- cppcheck/data/cfg/pcre.cfg +165 -0
- cppcheck/data/cfg/posix.cfg +6445 -0
- cppcheck/data/cfg/protobuf.cfg +10 -0
- cppcheck/data/cfg/python.cfg +674 -0
- cppcheck/data/cfg/qt.cfg +5502 -0
- cppcheck/data/cfg/ruby.cfg +142 -0
- cppcheck/data/cfg/sdl.cfg +354 -0
- cppcheck/data/cfg/selinux.cfg +3621 -0
- cppcheck/data/cfg/sfml.cfg +301 -0
- cppcheck/data/cfg/sqlite3.cfg +1571 -0
- cppcheck/data/cfg/std.cfg +9205 -0
- cppcheck/data/cfg/tinyxml2.cfg +37 -0
- cppcheck/data/cfg/vcl.cfg +4 -0
- cppcheck/data/cfg/windows.cfg +17237 -0
- cppcheck/data/cfg/wxsqlite3.cfg +1955 -0
- cppcheck/data/cfg/wxsvg.cfg +16905 -0
- cppcheck/data/cfg/wxwidgets.cfg +17245 -0
- cppcheck/data/cfg/zephyr.cfg +113 -0
- cppcheck/data/cfg/zlib.cfg +1450 -0
- cppcheck/data/cppcheck-htmlreport +1157 -0
- cppcheck/data/cppcheck.exe +0 -0
- cppcheck/data/platforms/aix_ppc64.xml +18 -0
- cppcheck/data/platforms/arm32-wchar_t2.xml +18 -0
- cppcheck/data/platforms/arm32-wchar_t4.xml +18 -0
- cppcheck/data/platforms/arm64-wchar_t2.xml +18 -0
- cppcheck/data/platforms/arm64-wchar_t4.xml +18 -0
- cppcheck/data/platforms/avr8.xml +18 -0
- cppcheck/data/platforms/cray_sv1.xml +18 -0
- cppcheck/data/platforms/elbrus-e1cp.xml +18 -0
- cppcheck/data/platforms/mips32.xml +18 -0
- cppcheck/data/platforms/msp430_eabi_large_datamodel.xml +18 -0
- cppcheck/data/platforms/pic16.xml +18 -0
- cppcheck/data/platforms/pic8-enhanced.xml +18 -0
- cppcheck/data/platforms/pic8.xml +18 -0
- cppcheck_py-2.19.0.dist-info/METADATA +76 -0
- cppcheck_py-2.19.0.dist-info/RECORD +84 -0
- cppcheck_py-2.19.0.dist-info/WHEEL +5 -0
- cppcheck_py-2.19.0.dist-info/entry_points.txt +4 -0
- cppcheck_py-2.19.0.dist-info/licenses/LICENSE.md +191 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# cppcheck addon for naming conventions
|
|
4
|
+
# An enhanced version. Configuration is taken from a json file
|
|
5
|
+
# It supports to check for type-based prefixes in function or variable names.
|
|
6
|
+
# Aside from include guard naming, include guard presence can also be tested.
|
|
7
|
+
#
|
|
8
|
+
# Example usage (variable name must start with lowercase, function name must start with uppercase):
|
|
9
|
+
# $ cppcheck --dump path-to-src/
|
|
10
|
+
# $ python namingng.py test.c.dump
|
|
11
|
+
#
|
|
12
|
+
# JSON format:
|
|
13
|
+
#
|
|
14
|
+
# {
|
|
15
|
+
# "RE_VARNAME": ["[a-z]*[a-zA-Z0-9_]*\\Z"],
|
|
16
|
+
# "RE_PRIVATE_MEMBER_VARIABLE": null,
|
|
17
|
+
# "RE_FUNCTIONNAME": ["[a-z0-9A-Z]*\\Z"],
|
|
18
|
+
# "_comment": "comments can be added to the config with underscore-prefixed keys",
|
|
19
|
+
# "include_guard": {
|
|
20
|
+
# "input": "path",
|
|
21
|
+
# "prefix": "GUARD_",
|
|
22
|
+
# "case": "upper",
|
|
23
|
+
# "max_linenr": 5,
|
|
24
|
+
# "RE_HEADERFILE": "[^/].*\\.h\\Z",
|
|
25
|
+
# "required": true
|
|
26
|
+
# },
|
|
27
|
+
# "var_prefixes": {"uint32_t": "ui32"},
|
|
28
|
+
# "function_prefixes": {"uint16_t": "ui16",
|
|
29
|
+
# "uint32_t": "ui32"}
|
|
30
|
+
# }
|
|
31
|
+
#
|
|
32
|
+
# RE_VARNAME, RE_PRIVATE_MEMBER_VARIABLE and RE_FUNCTIONNAME are regular expressions to cover the basic names
|
|
33
|
+
# In var_prefixes and function_prefixes there are the variable-type/prefix pairs
|
|
34
|
+
|
|
35
|
+
import cppcheckdata
|
|
36
|
+
import sys
|
|
37
|
+
import os
|
|
38
|
+
import re
|
|
39
|
+
import json
|
|
40
|
+
|
|
41
|
+
# Auxiliary class
|
|
42
|
+
class DataStruct:
|
|
43
|
+
def __init__(self, file, linenr, string, column=0):
|
|
44
|
+
self.file = file
|
|
45
|
+
self.linenr = linenr
|
|
46
|
+
self.str = string
|
|
47
|
+
self.column = column
|
|
48
|
+
|
|
49
|
+
def reportNamingError(location,message,errorId='namingConvention',severity='style',extra='',column=None):
|
|
50
|
+
cppcheckdata.reportError(location,severity,message,'namingng',errorId,extra,columnOverride=column)
|
|
51
|
+
|
|
52
|
+
def configError(error,fatal=True):
|
|
53
|
+
print('config error: %s'%error)
|
|
54
|
+
if fatal:
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
|
|
57
|
+
def validateConfigREs(list_or_dict,json_key):
|
|
58
|
+
have_error = False
|
|
59
|
+
for item in list_or_dict:
|
|
60
|
+
try:
|
|
61
|
+
re.compile(item)
|
|
62
|
+
except re.error as err:
|
|
63
|
+
configError("item '%s' of '%s' is not a valid regular expression: %s"%(item,json_key,err),fatal=False)
|
|
64
|
+
have_error = True
|
|
65
|
+
continue
|
|
66
|
+
if not isinstance(list_or_dict,dict):
|
|
67
|
+
continue
|
|
68
|
+
# item is actually a dict key; check value
|
|
69
|
+
value = list_or_dict[item]
|
|
70
|
+
if (not isinstance(value,list) or len(value) != 2
|
|
71
|
+
or not isinstance(value[0],bool) or not isinstance(value[1],str)):
|
|
72
|
+
configError("item '%s' of '%s' must be an array [bool,string]"%(item,json_key),fatal=False)
|
|
73
|
+
have_error = True
|
|
74
|
+
|
|
75
|
+
return have_error
|
|
76
|
+
|
|
77
|
+
def loadConfig(configfile):
|
|
78
|
+
if not os.path.exists(configfile):
|
|
79
|
+
configError("cannot find config file '%s'"%configfile)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
with open(configfile) as fh:
|
|
83
|
+
data = json.load(fh)
|
|
84
|
+
except json.JSONDecodeError as e:
|
|
85
|
+
configError("error parsing config file as JSON at line %d: %s"%(e.lineno,e.msg))
|
|
86
|
+
except Exception as e:
|
|
87
|
+
configError("error opening config file '%s': %s"%(configfile,e))
|
|
88
|
+
|
|
89
|
+
if not isinstance(data, dict):
|
|
90
|
+
configError('config file must contain a JSON object at the top level')
|
|
91
|
+
|
|
92
|
+
# All errors are emitted before bailing out, to make the unit test more
|
|
93
|
+
# effective.
|
|
94
|
+
have_error = False
|
|
95
|
+
|
|
96
|
+
# Put config items in a class, so that settings can be accessed using
|
|
97
|
+
# config.feature
|
|
98
|
+
class Config:
|
|
99
|
+
pass
|
|
100
|
+
config = Config()
|
|
101
|
+
|
|
102
|
+
mapping = {
|
|
103
|
+
'file': ('RE_FILE', (list,)),
|
|
104
|
+
'namespace': ('RE_NAMESPACE', (list,dict)),
|
|
105
|
+
'include_guard': ('include_guard', (dict,)),
|
|
106
|
+
'variable': ('RE_VARNAME', (list,dict)),
|
|
107
|
+
'variable_prefixes': ('var_prefixes', (dict,), {}),
|
|
108
|
+
'private_member': ('RE_PRIVATE_MEMBER_VARIABLE', (list,dict)),
|
|
109
|
+
'public_member': ('RE_PUBLIC_MEMBER_VARIABLE', (list,dict)),
|
|
110
|
+
'global_variable': ('RE_GLOBAL_VARNAME', (list,dict)),
|
|
111
|
+
'function_name': ('RE_FUNCTIONNAME', (list,dict)),
|
|
112
|
+
'function_prefixes': ('function_prefixes', (dict,), {}),
|
|
113
|
+
'class_name': ('RE_CLASS_NAME', (list,dict)),
|
|
114
|
+
'skip_one_char_variables': ('skip_one_char_variables', (bool,)),
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# parse defined keys and store as members of config object
|
|
118
|
+
for key,opts in mapping.items():
|
|
119
|
+
json_key = opts[0]
|
|
120
|
+
req_type = opts[1]
|
|
121
|
+
default = None if len(opts)<3 else opts[2]
|
|
122
|
+
|
|
123
|
+
value = data.pop(json_key,default)
|
|
124
|
+
if value is not None and type(value) not in req_type:
|
|
125
|
+
req_typename = ' or '.join([tp.__name__ for tp in req_type])
|
|
126
|
+
got_typename = type(value).__name__
|
|
127
|
+
configError('%s must be %s (not %s), or not set'%(json_key,req_typename,got_typename),fatal=False)
|
|
128
|
+
have_error = True
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
# type list implies that this is either a list of REs or a dict with RE keys
|
|
132
|
+
if list in req_type and value is not None:
|
|
133
|
+
re_error = validateConfigREs(value,json_key)
|
|
134
|
+
if re_error:
|
|
135
|
+
have_error = True
|
|
136
|
+
|
|
137
|
+
setattr(config,key,value)
|
|
138
|
+
|
|
139
|
+
# check remaining keys, only accept underscore-prefixed comments
|
|
140
|
+
for key,value in data.items():
|
|
141
|
+
if key == '' or key[0] != '_':
|
|
142
|
+
configError("unknown config key '%s'"%key,fatal=False)
|
|
143
|
+
have_error = True
|
|
144
|
+
|
|
145
|
+
if have_error:
|
|
146
|
+
sys.exit(1)
|
|
147
|
+
|
|
148
|
+
# pylint: disable-next=no-member - TODO: fix this
|
|
149
|
+
if config.include_guard:
|
|
150
|
+
# pylint: disable-next=no-member - TODO: fix this
|
|
151
|
+
config.include_guard_header_re = config.include_guard.get('RE_HEADERFILE',"[^/].*\\.h\\Z")
|
|
152
|
+
|
|
153
|
+
return config
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def evalExpr(conf, exp, mockToken, msgType):
|
|
157
|
+
report_as_error = False
|
|
158
|
+
msg = msgType + ' ' + mockToken.str + ' violates naming convention'
|
|
159
|
+
|
|
160
|
+
if isinstance(conf, dict):
|
|
161
|
+
report_as_error = conf[exp][0]
|
|
162
|
+
msg += ': ' + conf[exp][1]
|
|
163
|
+
|
|
164
|
+
res = re.match(exp,mockToken.str)
|
|
165
|
+
if bool(res) == report_as_error:
|
|
166
|
+
reportNamingError(mockToken,msg)
|
|
167
|
+
|
|
168
|
+
def check_include_guard_name(conf,directive):
|
|
169
|
+
parts = directive.str.split()
|
|
170
|
+
if len(parts) != 2:
|
|
171
|
+
msg = 'syntax error'
|
|
172
|
+
reportNamingError(directive,msg,'syntax')
|
|
173
|
+
return None,None
|
|
174
|
+
guard_name = parts[1]
|
|
175
|
+
guard_column = 1+directive.str.find(guard_name)
|
|
176
|
+
|
|
177
|
+
filename = directive.file
|
|
178
|
+
if conf.include_guard.get('input','path') == 'basename':
|
|
179
|
+
filename = os.path.basename(filename)
|
|
180
|
+
use_case = conf.include_guard.get('case','upper')
|
|
181
|
+
if use_case == 'upper':
|
|
182
|
+
filename = filename.upper()
|
|
183
|
+
elif use_case == 'lower':
|
|
184
|
+
filename = filename.lower()
|
|
185
|
+
elif use_case == 'keep':
|
|
186
|
+
pass # keep filename case as-is
|
|
187
|
+
else:
|
|
188
|
+
print("invalid config value for 'case': '%s'"%use_case,file=sys.stderr)
|
|
189
|
+
sys.exit(1)
|
|
190
|
+
|
|
191
|
+
barename = re.sub('[^A-Za-z0-9]','_',filename).strip('_')
|
|
192
|
+
expect_guard_name = conf.include_guard.get('prefix','') + barename + conf.include_guard.get('suffix','')
|
|
193
|
+
if expect_guard_name != guard_name:
|
|
194
|
+
msg = 'include guard naming violation; %s != %s'%(guard_name,expect_guard_name)
|
|
195
|
+
reportNamingError(directive,msg,'includeGuardName',column=guard_column)
|
|
196
|
+
|
|
197
|
+
return guard_name,guard_column
|
|
198
|
+
|
|
199
|
+
def check_include_guards(conf,cfg,unguarded_include_files):
|
|
200
|
+
# Scan for '#ifndef FILE_H' as the first directive, in the first N lines.
|
|
201
|
+
# Then test whether the next directive #defines the found name.
|
|
202
|
+
# Various tests are done:
|
|
203
|
+
# - check include guards for their naming and consistency
|
|
204
|
+
# - test whether include guards are in place
|
|
205
|
+
max_linenr = conf.include_guard.get('max_linenr', 5)
|
|
206
|
+
|
|
207
|
+
def report(directive,msg,errorId,severity='style',column=0):
|
|
208
|
+
reportNamingError(directive,msg,errorId,severity=severity,column=column)
|
|
209
|
+
|
|
210
|
+
def report_pending_ifndef(directive,column):
|
|
211
|
+
report(directive,'include guard #ifndef is not followed by #define','includeGuardIncomplete',column=column)
|
|
212
|
+
|
|
213
|
+
last_fn = None
|
|
214
|
+
pending_ifndef = None
|
|
215
|
+
guard_column = None
|
|
216
|
+
phase = 0
|
|
217
|
+
for directive in cfg.directives:
|
|
218
|
+
if last_fn != directive.file:
|
|
219
|
+
if pending_ifndef:
|
|
220
|
+
report_pending_ifndef(pending_ifndef,guard_column)
|
|
221
|
+
pending_ifndef = None
|
|
222
|
+
last_fn = directive.file
|
|
223
|
+
phase = 0
|
|
224
|
+
if phase == -1:
|
|
225
|
+
# ignore (the remainder of) this file
|
|
226
|
+
continue
|
|
227
|
+
if not re.match(conf.include_guard_header_re,directive.file):
|
|
228
|
+
phase = -1
|
|
229
|
+
continue
|
|
230
|
+
|
|
231
|
+
if directive.linenr > max_linenr:
|
|
232
|
+
if phase == 0 and conf.include_guard.get('required',1):
|
|
233
|
+
report(directive,'include guard not found before line %d'%max_linenr,'includeGuardMissing')
|
|
234
|
+
phase = -1
|
|
235
|
+
continue
|
|
236
|
+
|
|
237
|
+
if phase == 0:
|
|
238
|
+
# looking for '#ifndef FILE_H'
|
|
239
|
+
if not directive.str.startswith('#ifndef'):
|
|
240
|
+
if conf.include_guard.get('required',1):
|
|
241
|
+
report(directive,'first preprocessor directive should be include guard #ifndef','includeGuardMissing')
|
|
242
|
+
phase = -1
|
|
243
|
+
continue
|
|
244
|
+
guard_name,guard_column = check_include_guard_name(conf,directive)
|
|
245
|
+
if guard_name is None:
|
|
246
|
+
phase = -1
|
|
247
|
+
continue
|
|
248
|
+
pending_ifndef = directive
|
|
249
|
+
phase = 1
|
|
250
|
+
elif phase == 1:
|
|
251
|
+
pending_ifndef = None
|
|
252
|
+
# looking for '#define FILE_H'
|
|
253
|
+
if not directive.str.startswith('#define'):
|
|
254
|
+
report(directive,'second preprocessor directive should be include guard #define','includeGuardIncomplete')
|
|
255
|
+
phase = -1
|
|
256
|
+
continue
|
|
257
|
+
parts = directive.str.split()
|
|
258
|
+
if len(parts) == 1:
|
|
259
|
+
report(directive,'syntax error','syntax')
|
|
260
|
+
phase = -1
|
|
261
|
+
continue
|
|
262
|
+
if guard_name != parts[1]:
|
|
263
|
+
report(directive,'include guard does not guard; %s != %s'%(guard_name,parts[1]),'includeGuardAwayFromDuty',severity='warning',column=guard_column)
|
|
264
|
+
|
|
265
|
+
unguarded_include_files.remove(directive.file)
|
|
266
|
+
|
|
267
|
+
phase = -1
|
|
268
|
+
if pending_ifndef:
|
|
269
|
+
report_pending_ifndef(pending_ifndef,guard_column)
|
|
270
|
+
|
|
271
|
+
def process(dumpfiles, configfile, cli, debugprint):
|
|
272
|
+
conf = loadConfig(configfile)
|
|
273
|
+
|
|
274
|
+
for afile in dumpfiles:
|
|
275
|
+
if not afile[-5:] == '.dump':
|
|
276
|
+
continue
|
|
277
|
+
if not cli:
|
|
278
|
+
print('Checking ' + afile + '...')
|
|
279
|
+
data = cppcheckdata.CppcheckData(afile)
|
|
280
|
+
process_data(conf,data,cli,debugprint)
|
|
281
|
+
|
|
282
|
+
def check_file_naming(conf,data):
|
|
283
|
+
for source_file in data.files:
|
|
284
|
+
basename = os.path.basename(source_file)
|
|
285
|
+
good = False
|
|
286
|
+
for exp in conf.file:
|
|
287
|
+
good |= bool(re.match(exp, source_file))
|
|
288
|
+
good |= bool(re.match(exp, basename))
|
|
289
|
+
if not good:
|
|
290
|
+
mockToken = DataStruct(source_file, 0, basename)
|
|
291
|
+
reportNamingError(mockToken, 'File name ' + basename + ' violates naming convention')
|
|
292
|
+
|
|
293
|
+
def check_namespace_naming(conf,data):
|
|
294
|
+
for tk in data.rawTokens:
|
|
295
|
+
if tk.str != 'namespace':
|
|
296
|
+
continue
|
|
297
|
+
mockToken = DataStruct(tk.next.file, tk.next.linenr, tk.next.str, tk.next.column)
|
|
298
|
+
for exp in conf.namespace:
|
|
299
|
+
evalExpr(conf.namespace, exp, mockToken, 'Namespace')
|
|
300
|
+
|
|
301
|
+
def check_variable_naming(conf,cfg,debugprint):
|
|
302
|
+
for var in cfg.variables:
|
|
303
|
+
if not var.nameToken:
|
|
304
|
+
continue
|
|
305
|
+
if var.access in ('Global','Public','Private'):
|
|
306
|
+
continue
|
|
307
|
+
prev = var.nameToken.previous
|
|
308
|
+
varType = prev.str
|
|
309
|
+
while "*" in varType and len(varType.replace("*", "")) == 0:
|
|
310
|
+
prev = prev.previous
|
|
311
|
+
varType = prev.str + varType
|
|
312
|
+
|
|
313
|
+
if debugprint:
|
|
314
|
+
print("Variable Name: " + str(var.nameToken.str))
|
|
315
|
+
print("original Type Name: " + str(var.nameToken.valueType.originalTypeName))
|
|
316
|
+
print("Type Name: " + var.nameToken.valueType.type)
|
|
317
|
+
print("Sign: " + str(var.nameToken.valueType.sign))
|
|
318
|
+
print("variable type: " + varType)
|
|
319
|
+
print("\n")
|
|
320
|
+
print("\t-- {} {}".format(varType, str(var.nameToken.str)))
|
|
321
|
+
|
|
322
|
+
if conf.skip_one_char_variables and len(var.nameToken.str) == 1:
|
|
323
|
+
continue
|
|
324
|
+
if varType in conf.variable_prefixes:
|
|
325
|
+
prefix = conf.variable_prefixes[varType]
|
|
326
|
+
if not var.nameToken.str.startswith(prefix):
|
|
327
|
+
reportNamingError(var.typeStartToken,
|
|
328
|
+
'Variable ' +
|
|
329
|
+
var.nameToken.str +
|
|
330
|
+
' violates naming convention',
|
|
331
|
+
column=var.nameToken.column)
|
|
332
|
+
|
|
333
|
+
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str, var.nameToken.column)
|
|
334
|
+
for exp in conf.variable:
|
|
335
|
+
evalExpr(conf.variable, exp, mockToken, 'Variable')
|
|
336
|
+
|
|
337
|
+
# Naming check for Global, Private and Public member variables
|
|
338
|
+
def check_gpp_naming(conf_list,cfg,access,message):
|
|
339
|
+
for var in cfg.variables:
|
|
340
|
+
if var.access != access:
|
|
341
|
+
continue
|
|
342
|
+
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str, var.nameToken.column)
|
|
343
|
+
for exp in conf_list:
|
|
344
|
+
evalExpr(conf_list, exp, mockToken, message)
|
|
345
|
+
|
|
346
|
+
def check_function_naming(conf,cfg,debugprint):
|
|
347
|
+
for token in cfg.tokenlist:
|
|
348
|
+
if not token.function:
|
|
349
|
+
continue
|
|
350
|
+
if token.function.type in ('Constructor', 'Destructor', 'CopyConstructor', 'MoveConstructor'):
|
|
351
|
+
continue
|
|
352
|
+
retval = token.previous.str
|
|
353
|
+
prev = token.previous
|
|
354
|
+
while "*" in retval and len(retval.replace("*", "")) == 0:
|
|
355
|
+
prev = prev.previous
|
|
356
|
+
retval = prev.str + retval
|
|
357
|
+
if debugprint:
|
|
358
|
+
print("\t:: {} {}".format(retval, token.function.name))
|
|
359
|
+
|
|
360
|
+
if retval and retval in conf.function_prefixes:
|
|
361
|
+
if not token.function.name.startswith(conf.function_prefixes[retval]):
|
|
362
|
+
reportNamingError(token, 'Function ' + token.function.name + ' violates naming convention', column=token.column)
|
|
363
|
+
mockToken = DataStruct(token.file, token.linenr, token.function.name, token.column)
|
|
364
|
+
msgType = 'Function'
|
|
365
|
+
for exp in conf.function_name:
|
|
366
|
+
evalExpr(conf.function_name, exp, mockToken, msgType)
|
|
367
|
+
|
|
368
|
+
def check_class_naming(conf,cfg):
|
|
369
|
+
for fnc in cfg.functions:
|
|
370
|
+
if fnc.type not in ('Constructor','Destructor'):
|
|
371
|
+
continue
|
|
372
|
+
mockToken = DataStruct(fnc.tokenDef.file, fnc.tokenDef.linenr, fnc.name, fnc.tokenDef.column)
|
|
373
|
+
msgType = 'Class ' + fnc.type
|
|
374
|
+
for exp in conf.class_name:
|
|
375
|
+
evalExpr(conf.class_name, exp, mockToken, msgType)
|
|
376
|
+
|
|
377
|
+
def process_data(conf,data,cli,debugprint):
|
|
378
|
+
if conf.file:
|
|
379
|
+
check_file_naming(conf,data)
|
|
380
|
+
|
|
381
|
+
if conf.namespace:
|
|
382
|
+
check_namespace_naming(conf,data)
|
|
383
|
+
|
|
384
|
+
unguarded_include_files = []
|
|
385
|
+
if conf.include_guard and conf.include_guard.get('required',1):
|
|
386
|
+
unguarded_include_files = [fn for fn in data.files if re.match(conf.include_guard_header_re,fn)]
|
|
387
|
+
|
|
388
|
+
for cfg in data.configurations:
|
|
389
|
+
if not cli:
|
|
390
|
+
print('Checking config %s...' % cfg.name)
|
|
391
|
+
if conf.variable:
|
|
392
|
+
check_variable_naming(conf,cfg,debugprint)
|
|
393
|
+
if conf.private_member:
|
|
394
|
+
check_gpp_naming(conf.private_member,cfg,'Private','Private member variable')
|
|
395
|
+
if conf.public_member:
|
|
396
|
+
check_gpp_naming(conf.public_member,cfg,'Public','Public member variable')
|
|
397
|
+
if conf.global_variable:
|
|
398
|
+
check_gpp_naming(conf.global_variable,cfg,'Global','Global variable')
|
|
399
|
+
if conf.function_name:
|
|
400
|
+
check_function_naming(conf,cfg,debugprint)
|
|
401
|
+
if conf.class_name:
|
|
402
|
+
check_class_naming(conf,cfg)
|
|
403
|
+
if conf.include_guard:
|
|
404
|
+
check_include_guards(conf,cfg,unguarded_include_files)
|
|
405
|
+
|
|
406
|
+
for fn in unguarded_include_files:
|
|
407
|
+
mockToken = DataStruct(fn,0,os.path.basename(fn))
|
|
408
|
+
reportNamingError(mockToken,'Missing include guard','includeGuardMissing')
|
|
409
|
+
|
|
410
|
+
if __name__ == "__main__":
|
|
411
|
+
parser = cppcheckdata.ArgumentParser()
|
|
412
|
+
parser.add_argument("--debugprint", action="store_true", default=False,
|
|
413
|
+
help="Add debug prints")
|
|
414
|
+
parser.add_argument("--configfile", type=str, default="namingng.config.json",
|
|
415
|
+
help="Naming check config file")
|
|
416
|
+
|
|
417
|
+
args = parser.parse_args()
|
|
418
|
+
process(args.dumpfile, args.configfile, args.cli, args.debugprint)
|
|
419
|
+
|
|
420
|
+
sys.exit(0)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import cppcheckdata
|
|
2
|
+
import cppcheck
|
|
3
|
+
import runpy
|
|
4
|
+
import sys
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
if __name__ == '__main__':
|
|
8
|
+
addon = sys.argv[1]
|
|
9
|
+
__addon_name__ = os.path.splitext(os.path.basename(addon))[0]
|
|
10
|
+
sys.argv.pop(0)
|
|
11
|
+
|
|
12
|
+
runpy.run_path(addon, run_name='__main__')
|
|
13
|
+
|
|
14
|
+
# Run registered checkers
|
|
15
|
+
cppcheck.runcheckers()
|
|
16
|
+
sys.exit(cppcheckdata.EXIT_CODE)
|