mclasses.add_all(mod_mclasses)
cmetrics.collect(new HashSet[MClass].from(mod_mclasses), mainmodule)
for name, metric in cmetrics.metrics do
- print toolcontext.format_h4("\t{name}: {metric.desc}")
- print toolcontext.format_p("\t avg: {metric.avg}")
- var max = metric.max
- print toolcontext.format_p("\t max: {max.first} ({max.second})")
- var min = metric.min
- print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ if metric isa IntMetric then
+ print toolcontext.format_h4("\t{name}: {metric.desc}")
+ print toolcontext.format_p("\t avg: {metric.avg}")
+ var max = metric.max
+ print toolcontext.format_p("\t max: {max.first} ({max.second})")
+ var min = metric.min
+ print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ end
end
hmetrics.collect(new HashSet[MModule].from(mgroup.mmodules), mainmodule)
for name, metric in hmetrics.metrics do
- print toolcontext.format_h4("\t{name}: {metric.desc}")
- print toolcontext.format_p("\t avg: {metric.avg}")
- var max = metric.max
- print toolcontext.format_p("\t max: {max.first} ({max.second})")
- var min = metric.min
- print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ if metric isa FloatMetric then
+ print toolcontext.format_h4("\t{name}: {metric.desc}")
+ print toolcontext.format_p("\t avg: {metric.avg}")
+ var max = metric.max
+ print toolcontext.format_p("\t max: {max.first} ({max.second})")
+ var min = metric.min
+ print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ end
end
end
end
print toolcontext.format_h2("\n ## global metrics")
cmetrics.collect(mclasses, mainmodule)
for name, metric in cmetrics.metrics do
- print toolcontext.format_h4("\t{name}: {metric.desc}")
- print toolcontext.format_p("\t avg: {metric.avg}")
- var max = metric.max
- print toolcontext.format_p("\t max: {max.first} ({max.second})")
- var min = metric.min
- print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ if metric isa IntMetric then
+ print toolcontext.format_h4("\t{name}: {metric.desc}")
+ print toolcontext.format_p("\t avg: {metric.avg}")
+ var max = metric.max
+ print toolcontext.format_p("\t max: {max.first} ({max.second})")
+ var min = metric.min
+ print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ end
end
hmetrics.collect(mmodules, mainmodule)
for name, metric in hmetrics.metrics do
- print toolcontext.format_h4("\t{name}: {metric.desc}")
- print toolcontext.format_p("\t avg: {metric.avg}")
- var max = metric.max
- print toolcontext.format_p("\t max: {max.first} ({max.second})")
- var min = metric.min
- print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ if metric isa FloatMetric then
+ print toolcontext.format_h4("\t{name}: {metric.desc}")
+ print toolcontext.format_p("\t avg: {metric.avg}")
+ var max = metric.max
+ print toolcontext.format_p("\t max: {max.first} ({max.second})")
+ var min = metric.min
+ print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ end
end
end
end
# Metric Set used to collect data about inheritance in each module
class InheritanceMetricSet
super MetricSet
- redef type METRIC: InheritanceMetric
+ redef type METRIC: MModuleMetric
fun collect(mmodules: Set[MModule], mainmodule: MModule) do
clear
for metric in metrics.values do
end
end
-# An abstract metric used to collect data about inheritance usage
-#
-# The metric is based on a module
-abstract class InheritanceMetric
- super FloatMetric[MModule]
- fun collect(mmodule: MModule, mainmodule: MModule) is abstract
-end
-
# Module metric: proportion of MClasses Defined Using Inheritance
#
# Count MClasses that have another parents than Object
class MDUI
- super InheritanceMetric
+ super MModuleMetric
+ super FloatMetric
redef fun name do return "mdui"
redef fun desc do return "proportion of mclass defined using inheritance (has other parent than Object)"
#
# Count classes that have another parents than Object
class MDUIC
- super InheritanceMetric
+ super MModuleMetric
+ super FloatMetric
redef fun name do return "mduic"
redef fun desc do return "proportion of class_kind defined using inheritance"
#
# Count interface that have another parents than Object
class MDUII
- super InheritanceMetric
+ super MModuleMetric
+ super FloatMetric
redef fun name do return "mduii"
redef fun desc do return "proportion of interface_kind defined using inheritance"
#
# Count classes that have at least a child
class MIF
- super InheritanceMetric
+ super MModuleMetric
+ super FloatMetric
redef fun name do return "mif"
redef fun desc do return "proportion of mclass inherited from"
#
# Count classes that have at least a child
class MIFC
- super InheritanceMetric
+ super MModuleMetric
+ super FloatMetric
redef fun name do return "mifc"
redef fun desc do return "proportion of class_kind inherited from"
#
# Count interfaces that have at least a child
class MIFI
- super InheritanceMetric
+ super MModuleMetric
+ super FloatMetric
redef fun name do return "mifi"
redef fun desc do return "proportion of interface_kind inherited from"
# Count only absrtract, concrete and extern classes
class CNOAC
super MClassMetric
+ super IntMetric
redef fun name do return "cnoac"
redef fun desc do return "number of class_kind ancestor"
# Count only absrtract, concrete and extern classes
class CNOPC
super MClassMetric
+ super IntMetric
redef fun name do return "cnopc"
redef fun desc do return "number of class_kind parent"
# Count only absrtract, concrete and extern classes
class CNOCC
super MClassMetric
+ super IntMetric
redef fun name do return "cnocc"
redef fun desc do return "number of class_kind children"
# Count only absrtract, concrete and extern classes
class CNODC
super MClassMetric
+ super IntMetric
redef fun name do return "cnodc"
redef fun desc do return "number of class_kind descendants"
# Count only interfaces
class CNOAI
super MClassMetric
+ super IntMetric
redef fun name do return "cnoai"
redef fun desc do return "number of interface_kind ancestor"
# Count only interfaces
class CNOPI
super MClassMetric
+ super IntMetric
redef fun name do return "cnopi"
redef fun desc do return "number of interface_kind parent"
# Count only interfaces
class CNOCI
super MClassMetric
+ super IntMetric
redef fun name do return "cnoci"
redef fun desc do return "number of interface_kind children"
# Count only interfaces
class CNODI
super MClassMetric
+ super IntMetric
redef fun name do return "cnodi"
redef fun desc do return "number of interface_kind descendants"
# Following the longest path composed only of extends edges from self to Object
class CDITC
super MClassMetric
+ super IntMetric
redef fun name do return "cditc"
redef fun desc do return "depth in class tree following only class, abstract, extern kind"
# Following the longest path composed only of implements edges from self to Object
class CDITI
super MClassMetric
+ super IntMetric
redef fun name do return "cditi"
redef fun desc do return "depth in class tree following only interface_kind"
mclasses.add_all(mod_mclasses)
metrics.collect(new HashSet[MClass].from(mod_mclasses), mainmodule)
for name, metric in metrics.metrics do
- print toolcontext.format_h4("\t{name}: {metric.desc}")
- print toolcontext.format_p("\t avg: {metric.avg}")
- var max = metric.max
- print toolcontext.format_p("\t max: {max.first} ({max.second})")
- var min = metric.min
- print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ if metric isa IntMetric then
+ print toolcontext.format_h4("\t{name}: {metric.desc}")
+ print toolcontext.format_p("\t avg: {metric.avg}")
+ var max = metric.max
+ print toolcontext.format_p("\t max: {max.first} ({max.second})")
+ var min = metric.min
+ print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ end
end
end
end
metrics.collect(mclasses, mainmodule)
for name, metric in metrics.metrics do
- print toolcontext.format_h4("\t{name}: {metric.desc}")
- print toolcontext.format_p("\t avg: {metric.avg}")
- var max = metric.max
- print toolcontext.format_p("\t max: {max.first} ({max.second})")
- var min = metric.min
- print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ if metric isa IntMetric then
+ print toolcontext.format_h4("\t{name}: {metric.desc}")
+ print toolcontext.format_p("\t avg: {metric.avg}")
+ var max = metric.max
+ print toolcontext.format_p("\t max: {max.first} ({max.second})")
+ var min = metric.min
+ print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ end
end
end
end
end
end
-# An abstract metric about MClass
-abstract class MClassMetric
- super IntMetric[MClass]
+# A metric about MClass
+interface MClassMetric
+ super Metric
+ redef type ELM: MClass
+
# Collect the metric value for this mclass
fun collect(mclass: MClass, mainmodule: MModule) is abstract
end
# Class Metric: Number of Ancestors
class CNOA
super MClassMetric
+ super IntMetric
redef fun name do return "cnoa"
redef fun desc do return "number of ancestor classes"
# Class Metric: Number of Parents
class CNOP
super MClassMetric
+ super IntMetric
redef fun name do return "cnop"
redef fun desc do return "number of parent classes"
# Class Metric: Number of Children
class CNOC
super MClassMetric
+ super IntMetric
redef fun name do return "cnoc"
redef fun desc do return "number of child classes"
# Class Metric: Number of Descendants
class CNOD
super MClassMetric
+ super IntMetric
redef fun name do return "cnod"
redef fun desc do return "number of descendant classes"
# Class Metric: Depth in Inheritance Tree
class CDIT
super MClassMetric
+ super IntMetric
redef fun name do return "cdit"
redef fun desc do return "depth in class tree"
# Class Metric: Number of Introduced MProperties
class CNBIP
super MClassMetric
+ super IntMetric
redef fun name do return "cnbip"
redef fun desc do return "number of introduced properties"
# Class Metric: Number of Refined MProperties
class CNBRP
super MClassMetric
+ super IntMetric
redef fun name do return "cnbrp"
redef fun desc do return "number of redefined properties"
# Class Metric: Number of Inherited MProperties
class CNBHP
super MClassMetric
+ super IntMetric
redef fun name do return "cnbhp"
redef fun desc do return "number of inherited properties"
#
# The concept is reified here for a better organization and documentation
interface Metric
+ type ELM: Object
+ type VAL: Object
+ type RES: Map[ELM, VAL]
+
fun name: String is abstract
fun desc: String is abstract
- # clear all results for this metric
+
+ # Clear all results for this metric
fun clear is abstract
+
+ # Values for each element
+ fun values: RES is abstract
+
+
+ # The value calculated for the element
+ fun [](element: ELM): VAL do return values[element]
+
+ # Does the element have a value for this metric?
+ fun has_element(element: ELM): Bool do return values.has_key(element)
+
+ # The values average
+ fun avg: Float is abstract
end
# A Metric that collects integer data
#
# Used to count things
-class IntMetric[E: Object]
+class IntMetric
super Metric
- var values = new Counter[E]
+ redef type VAL: Int
+ redef type RES: Counter[ELM]
+
+ protected var values_cache = new Counter[ELM]
+ redef fun values do return values_cache
- redef fun clear do values.clear
+ redef fun clear do values_cache.clear
# Return the couple with the highest value
- fun max: Couple[E, Int] do
- assert not values.is_empty
- var elem = values.max.as(not null)
- var value = values[elem]
- return new Couple[E, Int](elem, value)
+ fun max: Couple[ELM, Int] do
+ assert not values_cache.is_empty
+ var elem = values_cache.max.as(not null)
+ var value = values_cache[elem]
+ return new Couple[ELM, Int](elem, value)
end
# Return the couple with the lowest value
- fun min: Couple[E, Int] do
- assert not values.is_empty
- var elem = values.min.as(not null)
- var value = values[elem]
- return new Couple[E, Int](elem, value)
+ fun min: Couple[ELM, Int] do
+ assert not values_cache.is_empty
+ var elem = values_cache.min.as(not null)
+ var value = values_cache[elem]
+ return new Couple[ELM, Int](elem, value)
end
# Values average
- fun avg: Float do return values.avg
+ redef fun avg: Float do return values_cache.avg
end
# A Metric that collects float datas
#
# Used sor summarization
-class FloatMetric[E: Object]
+class FloatMetric
super Metric
- var values: Map[E, Float] = new HashMap[E, Float]
+ redef type VAL: Float
+
+ protected var values_cache = new HashMap[ELM, VAL]
+ redef fun values do return values_cache
- redef fun clear do values.clear
+ redef fun clear do values_cache.clear
# Return the couple with the highest value
- fun max: Couple[E, Float] do
+ fun max: Couple[ELM, Float] do
assert not values.is_empty
var max: nullable Float = null
- var elem: nullable E = null
+ var elem: nullable ELM = null
for e, v in values do
if max == null or v > max then
max = v
elem = e
end
end
- return new Couple[E, Float](elem.as(not null), max.as(not null))
+ return new Couple[ELM, Float](elem.as(not null), max.as(not null))
end
# Return the couple with the lowest value
- fun min: Couple[E, Float] do
+ fun min: Couple[ELM, Float] do
assert not values.is_empty
var min: nullable Float = null
- var elem: nullable E = null
+ var elem: nullable ELM = null
for e, v in values do
if min == null or v < min then
min = v
elem = e
end
end
- return new Couple[E, Float](elem.as(not null), min.as(not null))
+ return new Couple[ELM, Float](elem.as(not null), min.as(not null))
end
- # Values average
- fun avg: Float do
+ redef fun avg do
if values.is_empty then return 0.0
var sum = 0.0
for value in values.values do
mmodules.add_all(mgroup.mmodules)
metrics.collect(new HashSet[MModule].from(mgroup.mmodules), mainmodule)
for name, metric in metrics.metrics do
- print toolcontext.format_h4("\t{name}: {metric.desc}")
- print toolcontext.format_p("\t avg: {metric.avg}")
- var max = metric.max
- print toolcontext.format_p("\t max: {max.first} ({max.second})")
- var min = metric.min
- print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ if metric isa IntMetric then
+ print toolcontext.format_h4("\t{name}: {metric.desc}")
+ print toolcontext.format_p("\t avg: {metric.avg}")
+ var max = metric.max
+ print toolcontext.format_p("\t max: {max.first} ({max.second})")
+ var min = metric.min
+ print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ end
end
end
end
metrics.collect(mmodules, mainmodule)
for name, metric in metrics.metrics do
- print toolcontext.format_h4( "\t{name}: {metric.desc}")
- print toolcontext.format_p("\t avg: {metric.avg}")
- var max = metric.max
- print toolcontext.format_p("\t max: {max.first} ({max.second})")
- var min = metric.min
- print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ if metric isa IntMetric then
+ print toolcontext.format_h4( "\t{name}: {metric.desc}")
+ print toolcontext.format_p("\t avg: {metric.avg}")
+ var max = metric.max
+ print toolcontext.format_p("\t max: {max.first} ({max.second})")
+ var min = metric.min
+ print toolcontext.format_p("\t min: {min.first} ({min.second})")
+ end
end
end
end
# An abstract Metric on MModules
abstract class MModuleMetric
- super IntMetric[MModule]
+ super Metric
+ redef type ELM: MModule
# Collect the metric on the MModule
#
# Results are stored in the property `values`
# Module Metric: Number of Ancestors
class MNOA
super MModuleMetric
+ super IntMetric
redef fun name do return "mnoa"
redef fun desc do return "number of ancestor modules"
# Module Metric: Number of Parents
class MNOP
super MModuleMetric
+ super IntMetric
redef fun name do return "mnop"
redef fun desc do return "number of parent modules"
# Module Metric: Number of Children
class MNOC
super MModuleMetric
+ super IntMetric
redef fun name do return "mnoc"
redef fun desc do return "number of child modules"
# Module Metric: Number of Descendants
class MNOD
super MModuleMetric
+ super IntMetric
redef fun name do return "mnod"
redef fun desc do return "number of descendant modules"
# Module Metric: Depth in Tree
class MDIT
super MModuleMetric
+ super IntMetric
redef fun name do return "mdit"
redef fun desc do return "depth in module tree"
# count all mclasses introduced by the module
class MNBI
super MModuleMetric
+ super IntMetric
redef fun name do return "mnbi"
redef fun desc do return "number of introduction in module"
# count all mclasses refined in the module
class MNBR
super MModuleMetric
+ super IntMetric
redef fun name do return "mnbr"
redef fun desc do return "number of refinement in module"
redef fun collect(mmodule, main) do
- values[mmodule] = 0
+ var value = 0
for mclassdef in mmodule.mclassdefs do
- if not mclassdef.is_intro then values.inc(mmodule)
+ if not mclassdef.is_intro then value += 1
end
+ values[mmodule] = value
end
end
# Module Metric: Number of Concrete Class in module (intro + redef)
class MNBCC
super MModuleMetric
+ super IntMetric
redef fun name do return "mnbcc"
redef fun desc do return "number of concrete class in module (intro + redef)"
redef fun collect(mmodule, main) do
- values[mmodule] = 0
+ var value = 0
for mclassdef in mmodule.mclassdefs do
- if mclassdef.mclass.kind == concrete_kind then values.inc(mmodule)
+ if mclassdef.mclass.kind == concrete_kind then value += 1
end
+ values[mmodule] = value
end
end
# Module Metric: Number of Abstract Class in module (intro + redef)
class MNBAC
super MModuleMetric
+ super IntMetric
redef fun name do return "mnbac"
redef fun desc do return "number of abstract class in module (intro + redef)"
redef fun collect(mmodule, main) do
- values[mmodule] = 0
+ var value = 0
for mclassdef in mmodule.mclassdefs do
- if mclassdef.mclass.kind == abstract_kind then values.inc(mmodule)
+ if mclassdef.mclass.kind == abstract_kind then value += 1
end
+ values[mmodule] = value
end
end
# Module Metric: Number of Interface in module (intro + redef)
class MNBIC
super MModuleMetric
+ super IntMetric
redef fun name do return "mnbic"
redef fun desc do return "number of interface in module (intro + redef)"
redef fun collect(mmodule, main) do
- values[mmodule] = 0
+ var value = 0
for mclassdef in mmodule.mclassdefs do
- if mclassdef.mclass.kind == interface_kind then values.inc(mmodule)
+ if mclassdef.mclass.kind == interface_kind then value += 1
end
+ values[mmodule] = value
end
end
# Module Metric: Number of Enum in module (intro + redef)
class MNBEC
super MModuleMetric
+ super IntMetric
redef fun name do return "mnbec"
redef fun desc do return "number of enum in module (intro + redef)"
redef fun collect(mmodule, main) do
- values[mmodule] = 0
+ var value = 0
for mclassdef in mmodule.mclassdefs do
- if mclassdef.mclass.kind == enum_kind then values.inc(mmodule)
+ if mclassdef.mclass.kind == enum_kind then value += 1
end
+ values[mmodule] = value
end
end