mcpp 1.1.0__tar.gz → 1.2.0__tar.gz
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.
- {mcpp-1.1.0/src/mcpp.egg-info → mcpp-1.2.0}/PKG-INFO +4 -4
- {mcpp-1.1.0 → mcpp-1.2.0}/pyproject.toml +1 -1
- mcpp-1.2.0/requirements.txt +6 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/__init__.py +1 -1
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/complexity.py +9 -12
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/parse.py +4 -6
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/queries.py +7 -7
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/vulnerability.py +21 -23
- {mcpp-1.1.0 → mcpp-1.2.0/src/mcpp.egg-info}/PKG-INFO +4 -4
- mcpp-1.2.0/src/mcpp.egg-info/requires.txt +6 -0
- mcpp-1.1.0/requirements.txt +0 -6
- mcpp-1.1.0/src/mcpp.egg-info/requires.txt +0 -6
- {mcpp-1.1.0 → mcpp-1.2.0}/LICENSE +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/README.md +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/setup.cfg +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/__main__.py +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/assets/__init__.py +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/assets/config.yaml +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp/config.py +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp.egg-info/SOURCES.txt +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp.egg-info/dependency_links.txt +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp.egg-info/entry_points.txt +0 -0
- {mcpp-1.1.0 → mcpp-1.2.0}/src/mcpp.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mcpp
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: McCabe++ (mcpp): cyclomatic complexity and other vulnerability-related code metrics
|
|
5
5
|
Author-email: Lukas Pirch <lukas.pirch@tu-berlin.de>
|
|
6
6
|
License: MIT License
|
|
@@ -33,9 +33,9 @@ Requires-Python: >=3.9
|
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
License-File: LICENSE
|
|
35
35
|
Requires-Dist: hydra-core>=1.3.2
|
|
36
|
-
Requires-Dist: tree-sitter>=0.
|
|
37
|
-
Requires-Dist: tree-sitter-c>=0.
|
|
38
|
-
Requires-Dist: tree-sitter-cpp>=0.
|
|
36
|
+
Requires-Dist: tree-sitter>=0.23.0
|
|
37
|
+
Requires-Dist: tree-sitter-c>=0.23.0
|
|
38
|
+
Requires-Dist: tree-sitter-cpp>=0.23.0
|
|
39
39
|
Requires-Dist: tqdm>=4.66.4
|
|
40
40
|
Requires-Dist: loguru>=0.7.2
|
|
41
41
|
|
|
@@ -20,16 +20,13 @@ def c1(root, sitter, lang, calls=None):
|
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
complexity = c2(root, sitter, lang, calls)["C2"]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
left, op, right = expr.children
|
|
31
|
-
if op.text.decode() in logical_ops:
|
|
32
|
-
complexity += 1
|
|
23
|
+
for condition in sitter.captures("Q_CONDITION", root, lang).get("condition", []):
|
|
24
|
+
for expr in sitter.captures("Q_BINARY_EXPR", condition, lang).get("expr", []):
|
|
25
|
+
if len(expr.children) != 3:
|
|
26
|
+
continue
|
|
27
|
+
left, op, right = expr.children
|
|
28
|
+
if op.text.decode() in logical_ops:
|
|
29
|
+
complexity += 1
|
|
33
30
|
complexity += 1
|
|
34
31
|
return {
|
|
35
32
|
"C1": complexity
|
|
@@ -44,7 +41,7 @@ def c2(root, sitter, lang, calls=None):
|
|
|
44
41
|
})
|
|
45
42
|
complexity = 0
|
|
46
43
|
for query in ("Q_FOR_STMT", "Q_WHILE_STMT"):
|
|
47
|
-
complexity += len(sitter.captures(query, root, lang))
|
|
44
|
+
complexity += len(sitter.captures(query, root, lang).get("stmt", []))
|
|
48
45
|
return {
|
|
49
46
|
"C2": complexity
|
|
50
47
|
}
|
|
@@ -66,7 +63,7 @@ def c3_c4(root, sitter, lang, calls=None):
|
|
|
66
63
|
c3_val = 0
|
|
67
64
|
c4_val = 0
|
|
68
65
|
for query in ("Q_FOR_STMT", "Q_DO_STMT", "Q_WHILE_STMT"):
|
|
69
|
-
for loop_node
|
|
66
|
+
for loop_node in sitter.captures(query, root, lang).get("stmt", []):
|
|
70
67
|
nesting_level = _loop_nesting_level(loop_node)
|
|
71
68
|
if nesting_level > 0:
|
|
72
69
|
c3_val += 1
|
|
@@ -23,8 +23,7 @@ class Sitter(object):
|
|
|
23
23
|
self.queries = {"Q_ERROR_NODE": Q_ERROR_NODE}
|
|
24
24
|
|
|
25
25
|
def _init_parser(self, language: str):
|
|
26
|
-
parser = Parser()
|
|
27
|
-
parser.set_language(self.langs[language])
|
|
26
|
+
parser = Parser(self.langs[language])
|
|
28
27
|
return parser
|
|
29
28
|
|
|
30
29
|
def parse_lang(self, source: str, lang: str):
|
|
@@ -63,9 +62,8 @@ def get_call_names(sitter, root, lang):
|
|
|
63
62
|
""" Return all function call names. """
|
|
64
63
|
call_names = []
|
|
65
64
|
sitter.add_queries({"Q_CALL_NAME": Q_CALL_NAME})
|
|
66
|
-
for node
|
|
67
|
-
|
|
68
|
-
call_names.append(node.text.decode())
|
|
65
|
+
for node in sitter.captures("Q_CALL_NAME", root, lang).get("name", []):
|
|
66
|
+
call_names.append(node.text.decode())
|
|
69
67
|
return call_names
|
|
70
68
|
|
|
71
69
|
|
|
@@ -73,7 +71,7 @@ def get_identifiers(sitter, root, lang, filter=None):
|
|
|
73
71
|
""" Return all identifier names, optionally filtered by list of known function names. """
|
|
74
72
|
identifiers = []
|
|
75
73
|
sitter.add_queries({"Q_IDENTIFIER": Q_IDENTIFIER})
|
|
76
|
-
for node
|
|
74
|
+
for node in sitter.captures("Q_IDENTIFIER", root, lang).get("variable", []):
|
|
77
75
|
identifier = node.text.decode()
|
|
78
76
|
if filter is None or identifier not in filter:
|
|
79
77
|
identifiers.append(identifier)
|
|
@@ -3,15 +3,15 @@ Q_ERROR_NODE = """
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
Q_FOR_STMT = """
|
|
6
|
-
(for_statement) @
|
|
6
|
+
(for_statement) @stmt
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
Q_DO_STMT = """
|
|
10
|
-
(do_statement) @
|
|
10
|
+
(do_statement) @stmt
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
Q_WHILE_STMT = """
|
|
14
|
-
(while_statement) @
|
|
14
|
+
(while_statement) @stmt
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
Q_IF_STMT = """
|
|
@@ -19,7 +19,7 @@ Q_IF_STMT = """
|
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
Q_SWITCH_STMT = """
|
|
22
|
-
(switch_statement) @
|
|
22
|
+
(switch_statement) @stmt
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
|
|
@@ -30,7 +30,7 @@ Q_CONDITION = """
|
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
Q_BINARY_EXPR = """
|
|
33
|
-
(binary_expression) @
|
|
33
|
+
(binary_expression) @expr
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
36
|
Q_CALL_NAME = """
|
|
@@ -58,7 +58,7 @@ Q_POINTER_EXPR = """
|
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
60
|
Q_ASSIGNMENT_EXPR = """
|
|
61
|
-
(assignment_expression) @
|
|
61
|
+
(assignment_expression) @expr
|
|
62
62
|
"""
|
|
63
63
|
|
|
64
64
|
Q_IF_WITHOUT_ELSE = """
|
|
@@ -66,5 +66,5 @@ Q_IF_WITHOUT_ELSE = """
|
|
|
66
66
|
condition: ((_) @if)
|
|
67
67
|
consequence: ((_) @then)
|
|
68
68
|
!alternative
|
|
69
|
-
) @
|
|
69
|
+
) @stmt
|
|
70
70
|
"""
|
|
@@ -17,8 +17,7 @@ def v1(root, sitter, lang, calls=None):
|
|
|
17
17
|
})
|
|
18
18
|
|
|
19
19
|
vars_in_calls = []
|
|
20
|
-
|
|
21
|
-
for arg_list in arg_lists:
|
|
20
|
+
for arg_list in sitter.captures("Q_ARGLIST", root, lang).get("args", []):
|
|
22
21
|
variables = get_identifiers(sitter, arg_list, lang, filter=calls)
|
|
23
22
|
vars_in_calls.extend(variables)
|
|
24
23
|
|
|
@@ -34,8 +33,7 @@ def v2(root, sitter, lang, calls=None):
|
|
|
34
33
|
sitter.add_queries({
|
|
35
34
|
"Q_FUNCTION_PARAMETER": Q_FUNCTION_PARAMETER
|
|
36
35
|
})
|
|
37
|
-
|
|
38
|
-
params = sitter.captures("Q_FUNCTION_PARAMETER", root, lang)
|
|
36
|
+
params = sitter.captures("Q_FUNCTION_PARAMETER", root, lang).get("param", [])
|
|
39
37
|
return {
|
|
40
38
|
"V2": len(params)
|
|
41
39
|
}
|
|
@@ -61,7 +59,7 @@ def v3_v4(root, sitter, lang, calls=None):
|
|
|
61
59
|
|
|
62
60
|
pointer_arith = []
|
|
63
61
|
pointer_arith_vars = []
|
|
64
|
-
for pointer
|
|
62
|
+
for pointer in sitter.captures("Q_POINTER_EXPR", root, lang).get("pointer", []):
|
|
65
63
|
if any(arith in pointer.parent.text.decode() for arith in arith_ops):
|
|
66
64
|
pointer_arith.append(pointer)
|
|
67
65
|
variables = get_identifiers(sitter, pointer.parent, lang, filter=calls)
|
|
@@ -90,8 +88,8 @@ def v5(root, sitter, lang, calls=None):
|
|
|
90
88
|
]
|
|
91
89
|
|
|
92
90
|
var_count = Counter()
|
|
93
|
-
candidates = sitter.captures("Q_BINARY_EXPR", root, lang) + sitter.captures("Q_ASSIGNMENT_EXPR", root, lang)
|
|
94
|
-
for node
|
|
91
|
+
candidates = sitter.captures("Q_BINARY_EXPR", root, lang).get("expr", []) + sitter.captures("Q_ASSIGNMENT_EXPR", root, lang).get("expr", [])
|
|
92
|
+
for node in candidates:
|
|
95
93
|
if len(node.children) != 3:
|
|
96
94
|
continue
|
|
97
95
|
op_text = node.children[1].text.decode()
|
|
@@ -124,11 +122,11 @@ def v6_v7(root, sitter, lang, calls=None):
|
|
|
124
122
|
nested_controls = []
|
|
125
123
|
max_nesting_level = 0
|
|
126
124
|
for q in queries.keys():
|
|
127
|
-
for node
|
|
125
|
+
for node in sitter.captures(q, root, lang).get("stmt", []):
|
|
128
126
|
nesting_level = _control_nesting_level(node)
|
|
129
127
|
if nesting_level > 0:
|
|
130
128
|
nested_controls.append(node)
|
|
131
|
-
|
|
129
|
+
max_nesting_level = max(max_nesting_level, nesting_level)
|
|
132
130
|
|
|
133
131
|
return {
|
|
134
132
|
"V6": len(nested_controls),
|
|
@@ -186,7 +184,8 @@ def v8(root, sitter, lang, calls=None):
|
|
|
186
184
|
|
|
187
185
|
|
|
188
186
|
def _v8_single_query(root, sitter, lang, calls, query, control_dependent_controls, thread_lock):
|
|
189
|
-
|
|
187
|
+
tag = "condition" if "Q_CONDITION" in query else "stmt"
|
|
188
|
+
for node in sitter.captures(query, root, lang).get(tag, []):
|
|
190
189
|
parents = _traverse_parent_controls(node)
|
|
191
190
|
if len(parents) > 0:
|
|
192
191
|
with thread_lock:
|
|
@@ -224,17 +223,16 @@ def v9(root, sitter, lang, calls=None):
|
|
|
224
223
|
"|", "||"
|
|
225
224
|
]
|
|
226
225
|
|
|
227
|
-
conditions = sitter.captures("Q_CONDITION", root, lang)
|
|
226
|
+
conditions = sitter.captures("Q_CONDITION", root, lang).get("condition", [])
|
|
228
227
|
var_count = Counter()
|
|
229
|
-
for condition
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
var_count.update(get_identifiers(sitter, expr, lang, filter=calls))
|
|
228
|
+
for condition in conditions:
|
|
229
|
+
bin_expr = sitter.captures("Q_BINARY_EXPR", condition, lang).get("expr", [])
|
|
230
|
+
for expr in bin_expr:
|
|
231
|
+
if len(expr.children) != 3:
|
|
232
|
+
continue
|
|
233
|
+
left, op, right = expr.children
|
|
234
|
+
if op.text.decode() in logical_ops:
|
|
235
|
+
var_count.update(get_identifiers(sitter, expr, lang, filter=calls))
|
|
238
236
|
|
|
239
237
|
return {
|
|
240
238
|
"V9": max([0] + list(var_count.values()))
|
|
@@ -249,7 +247,7 @@ def v10(root, sitter, lang, calls=None):
|
|
|
249
247
|
"Q_IF_WITHOUT_ELSE": Q_IF_WITHOUT_ELSE
|
|
250
248
|
})
|
|
251
249
|
|
|
252
|
-
if_without_else = sitter.captures("Q_IF_WITHOUT_ELSE", root, lang)
|
|
250
|
+
if_without_else = sitter.captures("Q_IF_WITHOUT_ELSE", root, lang).get("stmt", [])
|
|
253
251
|
return {
|
|
254
252
|
"V10": len(if_without_else)
|
|
255
253
|
}
|
|
@@ -264,8 +262,8 @@ def v11(root, sitter, lang, calls=None):
|
|
|
264
262
|
})
|
|
265
263
|
|
|
266
264
|
num_controlled_vars = 0
|
|
267
|
-
conditions = sitter.captures("Q_CONDITION", root, lang)
|
|
268
|
-
for condition
|
|
265
|
+
conditions = sitter.captures("Q_CONDITION", root, lang).get("condition", [])
|
|
266
|
+
for condition in conditions:
|
|
269
267
|
num_controlled_vars += len(get_identifiers(sitter, condition, lang, filter=calls))
|
|
270
268
|
return {
|
|
271
269
|
"V11": num_controlled_vars
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mcpp
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: McCabe++ (mcpp): cyclomatic complexity and other vulnerability-related code metrics
|
|
5
5
|
Author-email: Lukas Pirch <lukas.pirch@tu-berlin.de>
|
|
6
6
|
License: MIT License
|
|
@@ -33,9 +33,9 @@ Requires-Python: >=3.9
|
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
License-File: LICENSE
|
|
35
35
|
Requires-Dist: hydra-core>=1.3.2
|
|
36
|
-
Requires-Dist: tree-sitter>=0.
|
|
37
|
-
Requires-Dist: tree-sitter-c>=0.
|
|
38
|
-
Requires-Dist: tree-sitter-cpp>=0.
|
|
36
|
+
Requires-Dist: tree-sitter>=0.23.0
|
|
37
|
+
Requires-Dist: tree-sitter-c>=0.23.0
|
|
38
|
+
Requires-Dist: tree-sitter-cpp>=0.23.0
|
|
39
39
|
Requires-Dist: tqdm>=4.66.4
|
|
40
40
|
Requires-Dist: loguru>=0.7.2
|
|
41
41
|
|
mcpp-1.1.0/requirements.txt
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|