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 ( ) -
@@ -97,6 +27,8 @@ class FunctionMetrics extends Function {
9727 int getStatementNestingDepth ( ) { result = max ( Stmt s | s .getScope ( ) = this | getNestingDepth ( s ) ) }
9828
9929 int getNumberOfCalls ( ) { result = count ( Call c | c .getScope ( ) = this ) }
30+
31+ override string getAQlClass ( ) { result = "FunctionMetrics" }
10032}
10133
10234/** The metrics for a class */
@@ -116,36 +48,6 @@ class ClassMetrics extends Class {
11648 /** Gets the number of lines of docstrings in the class */
11749 int getNumberOfLinesOfDocStrings ( ) { py_docstringlines ( this , result ) }
11850
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-
14951 /* -------- CHIDAMBER AND KEMERER LACK OF COHESION IN METHODS ------------ */
15052 /*
15153 * The aim of this metric is to try and determine whether a class
@@ -243,21 +145,8 @@ class ClassMetrics extends Class {
243145
244146 /** return Hitz and Montazeri Lack of Cohesion */
245147 int getLackOfCohesionHM ( ) { result = count ( int line | this .unionSubgraph ( _, line ) ) }
246- }
247148
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- )
149+ override string getAQlClass ( ) { result = "ClassMetrics" }
261150}
262151
263152class ModuleMetrics extends Module {
@@ -273,42 +162,7 @@ class ModuleMetrics extends Module {
273162 /** Gets the number of lines of docstrings in the module */
274163 int getNumberOfLinesOfDocStrings ( ) { py_docstringlines ( this , result ) }
275164
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- )
165+ override string getAQlClass ( ) { result = "ModuleMetrics" }
312166}
313167
314168predicate non_coupling_method ( Function f ) {
0 commit comments