11import python
2- private import LegacyPointsTo
2+ private import semmle.python.SelfAttribute
33
44/** The metrics for a function */
55class FunctionMetrics extends Function {
@@ -18,76 +18,6 @@ class FunctionMetrics extends Function {
1818 /** Gets the number of lines of docstring in the function */
1919 int getNumberOfLinesOfDocStrings ( ) { py_docstringlines ( this , result ) }
2020
21- /**
22- * Gets the cyclomatic complexity of the function:
23- * The number of linearly independent paths through the source code.
24- * Computed as E - N + 2P,
25- * where
26- * E = the number of edges of the graph.
27- * N = the number of nodes of the graph.
28- * P = the number of connected components, which for a single function is 1.
29- */
30- int getCyclomaticComplexity ( ) {
31- exists ( int e , int n |
32- n = count ( BasicBlockWithPointsTo b | b = this .getABasicBlock ( ) and b .likelyReachable ( ) ) and
33- e =
34- count ( BasicBlockWithPointsTo b1 , BasicBlockWithPointsTo b2 |
35- b1 = this .getABasicBlock ( ) and
36- b1 .likelyReachable ( ) and
37- b2 = this .getABasicBlock ( ) and
38- b2 .likelyReachable ( ) and
39- b2 = b1 .getASuccessor ( ) and
40- not b1 .unlikelySuccessor ( b2 )
41- )
42- |
43- result = e - n + 2
44- )
45- }
46-
47- private BasicBlock getABasicBlock ( ) {
48- result = this .getEntryNode ( ) .getBasicBlock ( )
49- or
50- exists ( BasicBlock mid | mid = this .getABasicBlock ( ) and result = mid .getASuccessor ( ) )
51- }
52-
53- /**
54- * Dependency of Callables
55- * One callable "this" depends on another callable "result"
56- * if "this" makes some call to a method that may end up being "result".
57- */
58- FunctionMetrics getADependency ( ) {
59- result != this and
60- not non_coupling_method ( result ) and
61- exists ( Call call | call .getScope ( ) = this |
62- exists ( FunctionObject callee | callee .getFunction ( ) = result |
63- call .getAFlowNode ( ) .getFunction ( ) .( ControlFlowNodeWithPointsTo ) .refersTo ( callee )
64- )
65- or
66- exists ( Attribute a | call .getFunc ( ) = a |
67- unique_root_method ( result , a .getName ( ) )
68- or
69- exists ( Name n | a .getObject ( ) = n and n .getId ( ) = "self" |
70- result .getScope ( ) = this .getScope ( ) and
71- result .getName ( ) = a .getName ( )
72- )
73- )
74- )
75- }
76-
77- /**
78- * Afferent Coupling
79- * the number of callables that depend on this method.
80- * This is sometimes called the "fan-in" of a method.
81- */
82- int getAfferentCoupling ( ) { result = count ( FunctionMetrics m | m .getADependency ( ) = this ) }
83-
84- /**
85- * Efferent Coupling
86- * the number of methods that this method depends on
87- * This is sometimes called the "fan-out" of a method.
88- */
89- int getEfferentCoupling ( ) { result = count ( FunctionMetrics m | this .getADependency ( ) = m ) }
90-
9121 int getNumberOfParametersWithoutDefault ( ) {
9222 result =
9323 this .getPositionalParameterCount ( ) -
@@ -116,36 +46,6 @@ class ClassMetrics extends Class {
11646 /** Gets the number of lines of docstrings in the class */
11747 int getNumberOfLinesOfDocStrings ( ) { py_docstringlines ( this , result ) }
11848
119- private predicate dependsOn ( Class other ) {
120- other != this and
121- (
122- exists ( FunctionMetrics f1 , FunctionMetrics f2 | f1 .getADependency ( ) = f2 |
123- f1 .getScope ( ) = this and f2 .getScope ( ) = other
124- )
125- or
126- exists ( Function f , Call c , ClassObject cls | c .getScope ( ) = f and f .getScope ( ) = this |
127- c .getFunc ( ) .( ExprWithPointsTo ) .refersTo ( cls ) and
128- cls .getPyClass ( ) = other
129- )
130- )
131- }
132-
133- /**
134- * Gets the afferent coupling of a class -- the number of classes that
135- * directly depend on it.
136- */
137- int getAfferentCoupling ( ) { result = count ( ClassMetrics t | t .dependsOn ( this ) ) }
138-
139- /**
140- * Gets the efferent coupling of a class -- the number of classes that
141- * it directly depends on.
142- */
143- int getEfferentCoupling ( ) { result = count ( ClassMetrics t | this .dependsOn ( t ) ) }
144-
145- int getInheritanceDepth ( ) {
146- exists ( ClassObject cls | cls .getPyClass ( ) = this | result = max ( classInheritanceDepth ( cls ) ) )
147- }
148-
14949 /* -------- CHIDAMBER AND KEMERER LACK OF COHESION IN METHODS ------------ */
15050 /*
15151 * The aim of this metric is to try and determine whether a class
@@ -245,21 +145,6 @@ class ClassMetrics extends Class {
245145 int getLackOfCohesionHM ( ) { result = count ( int line | this .unionSubgraph ( _, line ) ) }
246146}
247147
248- private int classInheritanceDepth ( ClassObject cls ) {
249- /* Prevent run-away recursion in case of circular inheritance */
250- not cls .getASuperType ( ) = cls and
251- (
252- exists ( ClassObject sup | cls .getABaseType ( ) = sup | result = classInheritanceDepth ( sup ) + 1 )
253- or
254- not exists ( cls .getABaseType ( ) ) and
255- (
256- major_version ( ) = 2 and result = 0
257- or
258- major_version ( ) > 2 and result = 1
259- )
260- )
261- }
262-
263148class ModuleMetrics extends Module {
264149 /** Gets the total number of lines (including blank lines) in the module */
265150 int getNumberOfLines ( ) { py_alllines ( this , result ) }
@@ -272,43 +157,6 @@ class ModuleMetrics extends Module {
272157
273158 /** Gets the number of lines of docstrings in the module */
274159 int getNumberOfLinesOfDocStrings ( ) { py_docstringlines ( this , result ) }
275-
276- /**
277- * Gets the afferent coupling of a class -- the number of classes that
278- * directly depend on it.
279- */
280- int getAfferentCoupling ( ) { result = count ( ModuleMetrics t | t .dependsOn ( this ) ) }
281-
282- /**
283- * Gets the efferent coupling of a class -- the number of classes that
284- * it directly depends on.
285- */
286- int getEfferentCoupling ( ) { result = count ( ModuleMetrics t | this .dependsOn ( t ) ) }
287-
288- private predicate dependsOn ( Module other ) {
289- other != this and
290- (
291- exists ( FunctionMetrics f1 , FunctionMetrics f2 | f1 .getADependency ( ) = f2 |
292- f1 .getEnclosingModule ( ) = this and f2 .getEnclosingModule ( ) = other
293- )
294- or
295- exists ( Function f , Call c , ClassObject cls | c .getScope ( ) = f and f .getScope ( ) = this |
296- c .getFunc ( ) .( ExprWithPointsTo ) .refersTo ( cls ) and
297- cls .getPyClass ( ) .getEnclosingModule ( ) = other
298- )
299- )
300- }
301- }
302-
303- /** Helpers for coupling */
304- predicate unique_root_method ( Function func , string name ) {
305- name = func .getName ( ) and
306- not exists ( FunctionObject f , FunctionObject other |
307- f .getFunction ( ) = func and
308- other .getName ( ) = name
309- |
310- not other .overrides ( f )
311- )
312160}
313161
314162predicate non_coupling_method ( Function f ) {
0 commit comments