migraphx.py 10.8 KB
Newer Older
1
2
3
import cppcheck, itertools
from cppcheckdata import simpleMatch, match

Paul's avatar
Format  
Paul committed
4

5
6
7
8
9
10
def skipTokenMatches(tokens, skip=None):
    for tok in tokens:
        if match(tok, skip):
            continue
        yield tok

Paul's avatar
Format  
Paul committed
11

12
def isTokensEqual(xtokens, ytokens, skip=None):
Paul's avatar
Format  
Paul committed
13
14
    for x, y in itertools.zip_longest(skipTokenMatches(xtokens, skip),
                                      skipTokenMatches(ytokens, skip)):
15
16
17
18
19
20
21
22
        if not x:
            return False
        if not y:
            return False
        if x.str != y.str:
            return False
    return True

Paul's avatar
Format  
Paul committed
23

24
25
26
27
28
29
30
def getInnerLink(token):
    if not token:
        return []
    if not token.link:
        return []
    return token.next.forward(token.link)

Paul's avatar
Format  
Paul committed
31

32
33
34
35
36
37
38
39
def getVariableDecl(var):
    if not var:
        return []
    end = var.typeEndToken
    if end:
        end = end.next
    return var.typeStartToken.forward(end)

Paul's avatar
Format  
Paul committed
40

41
42
43
44
45
46
47
48
49
50
51
52
@cppcheck.checker
def AvoidBranchingStatementAsLastInLoop(cfg, data):
    for token in cfg.tokenlist:
        end = match(token, "for|while (*) {*}").end
        if not end:
            continue
        stmt = end.tokAt(-2)
        if not match(stmt, "%any% ; }"):
            continue
        if not match(stmt, "break|continue"):
            stmt = stmt.astTop()
        if match(stmt, "break|continue|return"):
Paul's avatar
Format  
Paul committed
53
54
55
56
57
            cppcheck.reportError(
                stmt, "style",
                "Branching statement as the last statement inside a loop is very confusing."
            )

58
59
60
61
62
63
64
65

# @cppcheck.checker
# def CollapsibleIfStatements(cfg, data):
#     for token in cfg.tokenlist:
#         if not match(token, "if (*) { if (*) {*} }"):
#             continue
#         cppcheck.reportError(token, "style", "These two if statements can be collapsed into one.")

Paul's avatar
Format  
Paul committed
66

67
68
69
70
71
@cppcheck.checker
def ConditionalAssert(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "if (*) { assert (*) ; }"):
            continue
Paul's avatar
Format  
Paul committed
72
73
74
        cppcheck.reportError(token, "style",
                             "The if condition should be included in assert.")

75
76
77
78
79
80
81
82

@cppcheck.checker
def EmptyCatchStatement(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "catch (*) { }"):
            continue
        cppcheck.reportError(token, "style", "An empty catch statement.")

Paul's avatar
Format  
Paul committed
83

84
85
86
87
88
89
90
@cppcheck.checker
def EmptyDoWhileStatement(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "do { } while ("):
            continue
        cppcheck.reportError(token, "style", "Empty do-while.")

Paul's avatar
Format  
Paul committed
91

92
93
94
95
96
@cppcheck.checker
def EmptyElseBlock(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "else { }"):
            continue
Paul's avatar
Format  
Paul committed
97
98
99
        cppcheck.reportError(token, "style",
                             "Empty else statement can be safely removed.")

100
101
102
103
104
105
106
107

@cppcheck.checker
def EmptyForStatement(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "for (*) { }"):
            continue
        cppcheck.reportError(token, "style", "Empty for statement.")

Paul's avatar
Format  
Paul committed
108

109
110
111
112
113
114
115
@cppcheck.checker
def EmptyIfStatement(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "if (*) { }"):
            continue
        cppcheck.reportError(token, "style", "Empty if statement.")

Paul's avatar
Format  
Paul committed
116

117
118
119
120
121
122
123
@cppcheck.checker
def EmptySwitchStatement(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "switch (*) { }"):
            continue
        cppcheck.reportError(token, "style", "Empty switch statement.")

Paul's avatar
Format  
Paul committed
124

125
126
127
128
129
130
131
@cppcheck.checker
def EmptyWhileStatement(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "while (*) { }"):
            continue
        cppcheck.reportError(token, "style", "Empty while statement.")

Paul's avatar
Format  
Paul committed
132

133
134
135
136
137
138
139
140
141
142
143
@cppcheck.checker
def ForLoopShouldBeWhileLoop(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "for ( ; !!;"):
            continue
        # Skip empty for loops
        if match(token, "for (*) { }"):
            continue
        end = token.next.link
        if not match(end.tokAt(-1), "; )"):
            continue
Paul's avatar
Format  
Paul committed
144
145
146
        cppcheck.reportError(token, "style",
                             "For loop should be written as a while loop.")

147
148
149
150
151
152
153
154

@cppcheck.checker
def GotoStatement(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "goto"):
            continue
        cppcheck.reportError(token, "style", "Goto considered harmful.")

Paul's avatar
Format  
Paul committed
155

156
157
158
159
160
161
162
163
164
165
166
167
# @cppcheck.checker
# def InvertedLogic(cfg, data):
#     for token in cfg.tokenlist:
#         cond = None
#         if match(token, "if (*) {*} else { !!if"):
#             cond = token.next.astOperand2
#         elif match(token, "?"):
#             cond = token.astOperand1
#         if not match(cond, "!|!="):
#             continue
#         cppcheck.reportError(cond, "style", "It is cleaner to invert the logic.")

Paul's avatar
Format  
Paul committed
168

169
170
171
172
173
@cppcheck.checker
def LambdaAttribute(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "] __device__|__host__ {|{}}"):
            continue
Paul's avatar
Format  
Paul committed
174
175
176
177
        cppcheck.reportError(
            token, "style",
            "Attributes to lambdas must come after parameter list.")

178
179
180
181
182
183
184
185
186
187
188
189

@cppcheck.checker
def MultipleUnaryOperator(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "+|-|~|!"):
            continue
        if not token.isUnaryOp(token.str):
            continue
        if not match(token.astOperand1, "+|-|~|!"):
            continue
        if not token.astOperand1.isUnaryOp(token.astOperand1.str):
            continue
Paul's avatar
Format  
Paul committed
190
191
192
        cppcheck.reportError(token, "style",
                             "Muliple unary operators used together.")

193
194
195
196
197
198

@cppcheck.checker
def MutableVariable(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "mutable %var%"):
            continue
Paul's avatar
Format  
Paul committed
199
200
201
        cppcheck.reportError(token, "style",
                             "Do not create mutable variables.")

202
203
204
205
206
207
208
209
210
211
212

@cppcheck.checker
def NestedBlocks(cfg, data):
    for token in cfg.tokenlist:
        block = match(token, "if|while|for|switch (*) { {*}@block }").block
        if not block:
            block = match(token, "; { {*}@block break ; }").block
        if not block:
            continue
        cppcheck.reportError(block, "style", "Block directly inside block.")

Paul's avatar
Format  
Paul committed
213

214
215
216
@cppcheck.checker
def RedundantCast(cfg, data):
    for token in cfg.tokenlist:
Paul's avatar
Format  
Paul committed
217
218
        m = match(token,
                  "%var%@decl ; %var%@assign = static_cast <*>@cast (*) ;")
219
220
221
222
223
        if not m:
            continue
        if m.decl.varId != m.assign.varId:
            continue
        if not match(token.previous, "auto"):
Paul's avatar
Format  
Paul committed
224
225
226
            if not isTokensEqual(getVariableDecl(m.decl.variable),
                                 getInnerLink(m.cast),
                                 skip='const|volatile|&|&&|*'):
227
                continue
Paul's avatar
Format  
Paul committed
228
229
        if not match(token,
                     "%var%@decl ; %var%@assign = static_cast <*>@cast (*) ;"):
230
231
232
            continue
        cppcheck.reportError(token, "style", "Static cast is redundant.")

Paul's avatar
Format  
Paul committed
233

234
235
236
237
238
@cppcheck.checker
def RedundantConditionalOperator(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "? true|false : true|false"):
            continue
Paul's avatar
Format  
Paul committed
239
240
241
        cppcheck.reportError(token, "style",
                             "Conditional operator is redundant.")

242
243
244
245

@cppcheck.checker
def RedundantIfStatement(cfg, data):
    for token in cfg.tokenlist:
Paul's avatar
Format  
Paul committed
246
247
248
        if not match(
                token,
                "if (*) { return true|false ; } else { return true|false ; }"):
249
250
251
            continue
        cppcheck.reportError(token, "style", "The if statement is redundant.")

Paul's avatar
Format  
Paul committed
252

253
254
255
@cppcheck.checker
def RedundantLocalVariable(cfg, data):
    for token in cfg.tokenlist:
Paul's avatar
Format  
Paul committed
256
257
        m = match(token,
                  "%var%@decl ; %var%@assign = **; return %var%@returned ;")
258
259
260
261
262
263
        if not m:
            continue
        if m.decl.varId != m.assign.varId:
            continue
        if m.decl.varId != m.returned.varId:
            continue
Paul's avatar
Format  
Paul committed
264
265
266
267
268
        cppcheck.reportError(
            m.returned, "style",
            "Variable is returned immediately after its declaration, can be simplified to just return expression."
        )

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

# @cppcheck.checker
# def UnnecessaryElseStatement(cfg, data):
#     for token in cfg.tokenlist:
#         m = match(token, "if (*) {*}@block else@else_statement {")
#         if not m:
#             continue
#         stmt = m.block.link.tokAt(-2)
#         if not match(stmt, "%any% ; }"):
#             continue
#         if not match(stmt, "break|continue"):
#             stmt = stmt.astTop()
#         if not match(stmt, "break|continue|return|throw"):
#             continue
#         cppcheck.reportError(m.else_statement, "style", "Else statement is not necessary.")

Paul's avatar
Format  
Paul committed
285

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
@cppcheck.checker
def UnnecessaryEmptyCondition(cfg, data):
    for token in cfg.tokenlist:
        m = match(token, "if (*)@if_cond { for (*)@for_cond {*} }")
        if not m:
            continue
        cond = m.if_cond.astOperand2
        if match(cond, "!"):
            cond = cond.astOperand1
        if not match(cond.tokAt(-2), ". empty ("):
            continue
        container = cond.tokAt(-2).astOperand1
        if not container.varId:
            continue
        if not match(m.for_cond.astOperand2, ":"):
            continue
        container_iter = m.for_cond.astOperand2.astOperand2
        if container_iter.varId != container.varId:
            continue
Paul's avatar
Format  
Paul committed
305
306
307
308
        cppcheck.reportError(
            container, "style",
            "Unnecessary check for empty before for range loop.")

309
310
311
312
313
314
315
316

@cppcheck.checker
def UseDeviceLaunch(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "hipLaunchKernelGGL ("):
            continue
        cppcheck.reportError(token, "style", "Use device::launch instead.")

Paul's avatar
Format  
Paul committed
317

318
319
320
@cppcheck.checker
def UseManagePointer(cfg, data):
    for token in cfg.tokenlist:
Paul's avatar
Format  
Paul committed
321
322
323
324
        if not match(
                token,
                "fclose|free|hipFree|hipHostFree|hipFreeArray|hipMemFree|hipStreamDestroy|hipEventDestroy|hipArrayDestroy|hipCtxDestroy|hipDestroyTextureObject|hipDestroySurfaceObject|miirDestroyHandle ("
        ):
325
            continue
Paul's avatar
Format  
Paul committed
326
327
328
        cppcheck.reportError(token, "style",
                             "Use manage pointer for resource management.")

329
330
331
332
333
334

@cppcheck.checker
def UseSmartPointer(cfg, data):
    for token in cfg.tokenlist:
        if not match(token, "new %name%"):
            continue
Paul's avatar
Format  
Paul committed
335
336
337
        cppcheck.reportError(token, "style",
                             "Use manage pointer for resource management.")

338
339
340
341
342
343
344
345
346

@cppcheck.checker
def useStlAlgorithms(cfg, data):
    for token in cfg.tokenlist:
        if match(token, "memcpy|strcpy|strncpy|strcat|strncat ("):
            cppcheck.reportError(token, "style", "Use std::copy instead.")
        elif match(token, "memset ("):
            cppcheck.reportError(token, "style", "Use std::fill instead.")
        elif match(token, "memcmp ("):
Paul's avatar
Format  
Paul committed
347
348
            cppcheck.reportError(token, "style",
                                 "Use std::equal_range instead.")
349
350
        elif match(token, "memchr ("):
            cppcheck.reportError(token, "style", "Use std::find instead.")