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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mcpp
3
- Version: 1.1.0
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.22.3
37
- Requires-Dist: tree-sitter-c>=0.21.4
38
- Requires-Dist: tree-sitter-cpp>=0.22.3
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
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mcpp"
3
- version = "1.1.0"
3
+ version = "1.2.0"
4
4
  description = "McCabe++ (mcpp): cyclomatic complexity and other vulnerability-related code metrics"
5
5
  readme = "README.md"
6
6
  authors = [{name = "Lukas Pirch", email="lukas.pirch@tu-berlin.de"}]
@@ -0,0 +1,6 @@
1
+ hydra-core>=1.3.2
2
+ tree-sitter>=0.23.0
3
+ tree-sitter-c>=0.23.0
4
+ tree-sitter-cpp>=0.23.0
5
+ tqdm>=4.66.4
6
+ loguru>=0.7.2
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from importlib import resources
3
3
 
4
- from mcpp.__main__ import extract, extract_single, METRICS
4
+ from mcpp.__main__ import extract, extract_single, extract_code, METRICS
5
5
 
6
6
 
7
7
  with resources.path("mcpp", "__init__.py") as root_path:
@@ -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
- conditions = sitter.captures("Q_CONDITION", root, lang)
24
- for condition, tag in conditions:
25
- if tag == "condition":
26
- bin_expr = sitter.captures("Q_BINARY_EXPR", condition, lang)
27
- for expr, _ in bin_expr:
28
- if len(expr.children) != 3:
29
- continue
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, _ in sitter.captures(query, root, lang):
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, tag in sitter.captures("Q_CALL_NAME", root, lang):
67
- if tag == "name":
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, _ in sitter.captures("Q_IDENTIFIER", root, lang):
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) @for_stmt
6
+ (for_statement) @stmt
7
7
  """
8
8
 
9
9
  Q_DO_STMT = """
10
- (do_statement) @do_stmt
10
+ (do_statement) @stmt
11
11
  """
12
12
 
13
13
  Q_WHILE_STMT = """
14
- (while_statement) @while_stmt
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) @switch_stmt
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) @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) @assignment
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
- ) @if_stmt
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
- arg_lists = [m for m, tag in sitter.captures("Q_ARGLIST", root, lang) if tag == "args"]
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, _ in sitter.captures("Q_POINTER_EXPR", root, lang):
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, _ in candidates:
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, _ in sitter.captures(q, root, lang):
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
- max_nesting_level = max(max_nesting_level, nesting_level)
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
- for node, _ in sitter.captures(query, root, lang):
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, tag in conditions:
230
- if tag == "condition":
231
- bin_expr = sitter.captures("Q_BINARY_EXPR", condition, lang)
232
- for expr, _ in bin_expr:
233
- if len(expr.children) != 3:
234
- continue
235
- left, op, right = expr.children
236
- if op.text.decode() in logical_ops:
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, _ in conditions:
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.1.0
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.22.3
37
- Requires-Dist: tree-sitter-c>=0.21.4
38
- Requires-Dist: tree-sitter-cpp>=0.22.3
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
 
@@ -0,0 +1,6 @@
1
+ hydra-core>=1.3.2
2
+ tree-sitter>=0.23.0
3
+ tree-sitter-c>=0.23.0
4
+ tree-sitter-cpp>=0.23.0
5
+ tqdm>=4.66.4
6
+ loguru>=0.7.2
@@ -1,6 +0,0 @@
1
- hydra-core>=1.3.2
2
- tree-sitter>=0.22.3
3
- tree-sitter-c>=0.21.4
4
- tree-sitter-cpp>=0.22.3
5
- tqdm>=4.66.4
6
- loguru>=0.7.2
@@ -1,6 +0,0 @@
1
- hydra-core>=1.3.2
2
- tree-sitter>=0.22.3
3
- tree-sitter-c>=0.21.4
4
- tree-sitter-cpp>=0.22.3
5
- tqdm>=4.66.4
6
- loguru>=0.7.2
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes