--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# Detect the code smells and antipatterns in the code.
+
+module codesmells_metrics
+
+import frontend
+import metrics_base
+import mclasses_metrics
+import semantize
+import method_analyze_metrics
+import mclassdef_collect
+
+redef class ToolContext
+ var codesmells_metrics_phase = new CodeSmellsMetricsPhase(self, null)
+end
+
+class CodeSmellsMetricsPhase
+ super Phase
+ var average_number_of_lines = 0.0
+ var average_number_of_parameter = 0.0
+ var average_number_of_method = 0.0
+ var average_number_of_attribute = 0.0
+
+ redef fun process_mainmodule(mainmodule, given_mmodules) do
+ print toolcontext.format_h1("--- Code Smells Metrics ---")
+ self.set_all_average_metrics
+ var mclass_codesmell = new BadConceptonController
+ var collect = new Counter[MClassDef]
+ var mclassdefs = new Array[MClassDef]
+
+ for mclass in mainmodule.flatten_mclass_hierarchy do
+ mclass_codesmell.collect(mclass.mclassdefs,self)
+ end
+ mclass_codesmell.print_top(10)
+ end
+
+ fun set_all_average_metrics do
+ var model_builder = toolcontext.modelbuilder
+ var model_view = model_builder.model.private_view
+ self.average_number_of_lines = model_view.get_avg_linenumber(model_builder)
+ self.average_number_of_parameter = model_view.get_avg_parameter
+ self.average_number_of_method = model_view.get_avg_method
+ self.average_number_of_attribute = model_view.get_avg_attribut
+ end
+end
+
+class BadConceptonController
+ # Code smell list
+ var bad_conception_elements = new Array[BadConceptionFinder]
+
+ # Print all element conception
+ fun print_all do
+ for bad_conception in bad_conception_elements do
+ bad_conception.print_all
+ end
+ end
+
+ # Print number of top element conception
+ fun print_top(number: Int) do
+ var test = self.get_numbers_of_elements(number)
+ for bad_conception in test do
+ bad_conception.print_all
+ end
+ end
+
+ # Collection
+ fun collect(mclassdefs: Array[MClassDef],phase: CodeSmellsMetricsPhase) do
+ for mclassdef in mclassdefs do
+ var bad_conception_class = new BadConceptionFinder(mclassdef,phase)
+ bad_conception_class.collect
+ bad_conception_elements.add(bad_conception_class)
+ end
+ end
+
+ fun sort: Array[BadConceptionFinder]
+ do
+ var res = bad_conception_elements
+ var sorter = new BadConceptionComparator
+ sorter.sort(res)
+ return res
+ end
+
+ fun get_numbers_of_elements(number : Int) : Array[BadConceptionFinder]do
+ var return_values = new Array[BadConceptionFinder]
+ var list = self.sort
+ var min = number
+ if list.length <= number*2 then min = list.length
+ for i in [0..min[ do
+ var t = list[list.length-i-1]
+ return_values.add(t)
+ end
+ return return_values
+ end
+end
+
+class BadConceptionFinder
+ var mclassdef: MClassDef
+ var array_badconception = new Array[BadConception]
+ var phase: CodeSmellsMetricsPhase
+
+ fun collect do
+ var bad_conception_elements = new Array[BadConception]
+ bad_conception_elements.add(new LargeClass(phase))
+ bad_conception_elements.add(new LongParameterList(phase))
+ bad_conception_elements.add(new FeatureEnvy(phase))
+ bad_conception_elements.add(new LongMethod(phase))
+ for bad_conception_element in bad_conception_elements do
+ if bad_conception_element.collect(self.mclassdef,phase.toolcontext.modelbuilder) == true then array_badconception.add(bad_conception_element)
+ end
+ end
+
+ fun print_all do
+ if array_badconception.length != 0 then
+ print "-----------"
+ print "{mclassdef.full_name}"
+ for bad_conception in array_badconception do
+ bad_conception.print_result
+ end
+ end
+ end
+end
+
+class BadConception
+ var phase: CodeSmellsMetricsPhase
+
+ # Name
+ fun name: String is abstract
+
+ # Description
+ fun desc: String is abstract
+
+ # Collection method
+ fun collect(mclassdef: MClassDef, model_builder: ModelBuilder): Bool is abstract
+
+ # Show results in console
+ fun print_result is abstract
+end
+
+class LargeClass
+ super BadConception
+ var number_attribut = 0
+
+ var number_method = 0
+
+ redef fun name do return "LARGC"
+
+ redef fun desc do return "Large class"
+
+ redef fun collect(mclassdef, model_builder): Bool do
+ number_attribut = mclassdef.collect_intro_and_redef_mattributes(model_builder.model.private_view).length
+ # get the number of methods (subtract the get and set of attibutes with (numberAtribut*2))
+ number_method = mclassdef.collect_intro_and_redef_methods(model_builder.model.private_view).length
+ return number_method.to_f > phase.average_number_of_method and number_attribut.to_f > phase.average_number_of_attribute
+ end
+
+ redef fun print_result do
+ print phase.toolcontext.format_h2("{desc}: {number_attribut} attributes and {number_method} methods ({phase.average_number_of_attribute}A {phase.average_number_of_method}M Average)")
+ end
+end
+
+class LongParameterList
+ super BadConception
+ var bad_methods = new Array[MMethodDef]
+
+ redef fun name do return "LONGPL"
+
+ redef fun desc do return "Long parameter list"
+
+ redef fun collect(mclassdef, model_builder): Bool do
+ for meth in mclassdef.collect_intro_and_redef_mpropdefs(model_builder.model.private_view) do
+ # check if the property is a method definition
+ if not meth isa MMethodDef then continue
+ # Check if method has a signature
+ if meth.msignature == null then continue
+ if meth.msignature.mparameters.length <= 4 then continue
+ bad_methods.add(meth)
+ end
+ return bad_methods.not_empty
+ end
+
+
+ redef fun print_result do
+ print "{desc}:"
+ if bad_methods.length >= 1 then
+ print " Affected method(s):"
+ for method in bad_methods do
+ print " -{method.name} has {method.msignature.mparameters.length} parameters"
+ end
+ end
+ end
+end
+
+class FeatureEnvy
+ super BadConception
+ var bad_methods = new Array[MMethodDef]
+
+ redef fun name do return "FEM"
+
+ redef fun desc do return "Feature envy"
+
+ redef fun collect(mclassdef, model_builder): Bool do
+ var mmethoddefs = call_analyze_methods(mclassdef,model_builder)
+ for mmethoddef in mmethoddefs do
+ if mmethoddef.total_extern_call <= mmethoddef.total_self_call then continue
+ bad_methods.add(mmethoddef)
+ end
+ return bad_methods.not_empty
+ end
+
+ redef fun print_result do
+ print "{desc}:"
+ if bad_methods.length >= 1 then
+ print " Affected method(s):"
+ for method in bad_methods do
+ print " -{method.name} {method.total_self_call}/{method.total_call}"
+ end
+ end
+ end
+end
+
+class LongMethod
+ super BadConception
+ var bad_methods = new Array[MMethodDef]
+
+ redef fun name do return "LONGMETH"
+
+ redef fun desc do return "Long method"
+
+ redef fun collect(mclassdef, model_builder): Bool do
+ var mmethoddefs = call_analyze_methods(mclassdef,model_builder)
+ for mmethoddef in mmethoddefs do
+ if mmethoddef.line_number <= phase.average_number_of_lines.to_i then continue
+ bad_methods.add(mmethoddef)
+ end
+ return bad_methods.not_empty
+ end
+
+ redef fun print_result do
+ print "{desc}: Average {phase.average_number_of_lines.to_i} lines"
+ if bad_methods.length >= 1 then
+ print " Affected method(s):"
+ for method in bad_methods do
+ print " -{method.name} has {method.line_number} lines"
+ end
+ end
+ end
+end
+
+redef class ModelView
+ fun get_avg_parameter: Float do
+ var counter = new Counter[MMethodDef]
+ for mclassdef in mclassdefs do
+ for method in mclassdef.collect_intro_and_redef_mpropdefs(self) do
+ # check if the property is a method definition
+ if not method isa MMethodDef then continue
+ #Check if method has a signature
+ if method.msignature == null then continue
+ if method.msignature.mparameters.length == 0 then continue
+ counter[method] = method.msignature.mparameters.length
+ end
+ end
+ return counter.avg + counter.std_dev
+ end
+
+ fun get_avg_attribut: Float do
+ var counter = new Counter[MClassDef]
+ for mclassdef in mclassdefs do
+ var number_attributs = mclassdef.collect_intro_and_redef_mattributes(self).length
+ if number_attributs != 0 then counter[mclassdef] = number_attributs
+ end
+ return counter.avg + counter.std_dev
+ end
+
+ fun get_avg_method: Float do
+ var counter = new Counter[MClassDef]
+ for mclassdef in mclassdefs do
+ var number_methodes = mclassdef.collect_intro_and_redef_methods(self).length
+ if number_methodes != 0 then counter[mclassdef] = number_methodes
+ end
+ return counter.avg + counter.std_dev
+ end
+
+ fun get_avg_linenumber(model_builder: ModelBuilder): Float do
+ var methods_analyse_metrics = new Counter[MClassDef]
+ for mclassdef in mclassdefs do
+ var result = 0
+ var count = 0
+ for mmethoddef in call_analyze_methods(mclassdef,model_builder) do
+ result += mmethoddef.line_number
+ if mmethoddef.line_number == 0 then continue
+ count += 1
+ end
+ if not mclassdef.collect_local_mproperties(self).length != 0 then continue
+ if count == 0 then continue
+ methods_analyse_metrics[mclassdef] = (result/count).to_i
+ end
+ return methods_analyse_metrics.avg + methods_analyse_metrics.std_dev
+ end
+end
+
+class BadConceptionComparator
+ super Comparator
+ redef type COMPARED: BadConceptionFinder
+ redef fun compare(a,b) do return a.array_badconception.length <=> b.array_badconception.length
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# This module redef Mclassdef to add new collect methods.
+
+module mclassdef_collect
+
+# We usualy need specific phases
+# NOTE: `frontend` is sufficent in most case (it is often too much)
+import frontend
+import model_views
+import model_collect
+
+redef class MClassDef
+ # Collect all mproperties introduced in 'self' with `visibility >= min_visibility`.
+ fun collect_intro_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ for mprop in self.intro_mproperties do
+ if not view.accept_mentity(mprop) then continue
+ set.add(mprop)
+ end
+ return set
+ end
+
+ # Collect mmethods introduced in 'self' with `visibility >= min_visibility`.
+ fun collect_intro_mmethods(view: ModelView): Set[MMethod] do
+ var res = new HashSet[MMethod]
+ for mproperty in collect_intro_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MMethod then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect mmethods redefined in 'self' with `visibility >= min_visibility`.
+ fun collect_redef_mmethods(view: ModelView): Set[MMethod] do
+ var res = new HashSet[MMethod]
+ for mproperty in collect_redef_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MMethod then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect mattributes redefined in 'self' with `visibility >= min_visibility`.
+ fun collect_redef_mattributes(view: ModelView): Set[MAttribute] do
+ var res = new HashSet[MAttribute]
+ for mproperty in collect_redef_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MAttribute then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect mattributes introduced in 'self' with `visibility >= min_visibility`.
+ fun collect_intro_mattributes(view: ModelView): Set[MAttribute] do
+ var res = new HashSet[MAttribute]
+ for mproperty in collect_intro_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MAttribute then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect all mproperties redefined in 'self' with `visibility >= min_visibility`.
+ fun collect_redef_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ for mpropdef in self.mpropdefs do
+ if not view.accept_mentity(mpropdef) then continue
+ if mpropdef.mproperty.intro_mclassdef.mclass == self then continue
+ set.add(mpropdef.mproperty)
+ end
+ return set
+ end
+
+ # Collect mmethods inherited by 'self' if accepted by `view`.
+ fun collect_inherited_mmethods(view: ModelView): Set[MMethod] do
+ var res = new HashSet[MMethod]
+ for mproperty in collect_inherited_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MMethod then res.add(mproperty)
+ end
+ return res
+ end
+
+ # Collect mproperties introduced and redefined in 'self' with `visibility >= min_visibility`.
+ fun collect_local_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ set.add_all collect_intro_mproperties(view)
+ set.add_all collect_redef_mproperties(view)
+ return set
+ end
+
+ # Collect all mproperties inehrited by 'self' with `visibility >= min_visibility`.
+ fun collect_inherited_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ for parent in collect_parents(view) do
+ set.add_all(parent.collect_intro_mproperties(view))
+ set.add_all(parent.collect_inherited_mproperties(view))
+ end
+ return set
+ end
+
+ # Collect mattributes inherited by 'self' with `visibility >= min_visibility`.
+ fun collect_inherited_mattributes(view: ModelView): Set[MAttribute] do
+ var res = new HashSet[MAttribute]
+ for mproperty in collect_inherited_mproperties(view) do
+ if not view.accept_mentity(mproperty) then continue
+ if mproperty isa MAttribute then res.add(mproperty)
+ end
+ return res
+ end
+
+ fun collect_all_methods(view: ModelView): Set[MMethod] do
+ var set = new HashSet[MMethod]
+ set.add_all collect_intro_mmethods(view)
+ set.add_all collect_redef_mmethods(view)
+ set.add_all collect_inherited_mmethods(view)
+ return set
+ end
+
+ fun collect_all_mattributes(view: ModelView): Set[MAttribute] do
+ var set = new HashSet[MAttribute]
+ set.add_all collect_redef_mattributes(view)
+ set.add_all collect_intro_mattributes(view)
+ set.add_all collect_inherited_mattributes(view)
+ return set
+ end
+
+ fun collect_intro_and_redef_methods(view: ModelView): Set[MMethod] do
+ var set = new HashSet[MMethod]
+ set.add_all collect_intro_mmethods(view)
+ set.add_all collect_redef_mmethods(view)
+ return set
+ end
+
+ fun collect_intro_and_redef_mattributes(view: ModelView): Set[MAttribute] do
+ var set = new HashSet[MAttribute]
+ set.add_all collect_redef_mattributes(view)
+ set.add_all collect_intro_mattributes(view)
+ return set
+ end
+
+ fun collect_intro_and_redef_mproperties(view: ModelView): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ set.add_all collect_redef_mproperties(view)
+ set.add_all collect_intro_mproperties(view)
+ return set
+ end
+
+ fun collect_intro_and_redef_mpropdefs(view: ModelView): Set[MPropDef] do
+ var set = new HashSet[MPropDef]
+ set.add_all collect_intro_mpropdefs(view)
+ set.add_all collect_redef_mpropdefs(view)
+ return set
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# This module call visitor for get number of line, total attributs call and total of self attributes call
+
+module method_analyze_metrics
+
+# We usualy need specific phases
+# NOTE: `frontend` is sufficent in most case (it is often too much)
+import metrics_base
+import mclasses_metrics
+import semantize
+import mclassdef_collect
+
+
+fun call_analyze_methods(mclassdef: MClassDef, model_builder: ModelBuilder): Array[MMethodDef] do
+ var mmethoddefs = new Array[MMethodDef]
+ for m_prop in mclassdef.collect_intro_and_redef_mpropdefs(model_builder.model.private_view) do
+ var n_prop = model_builder.mpropdef2node(m_prop)
+ #Check if the property is a method definition
+ if n_prop isa AMethPropdef and m_prop isa MMethodDef then
+ if n_prop.n_methid isa AIdMethid then
+ #Call visitor to analyse the method
+ var visitor = new MethodAnalyzeMetrics(n_prop)
+ visitor.enter_visit(n_prop)
+ mmethoddefs.add(set_analyse_result_methoddef(m_prop,visitor))
+ end
+ end
+ end
+ return mmethoddefs
+end
+
+fun set_analyse_result_methoddef(mmethoddef: MMethodDef, visitor: MethodAnalyzeMetrics): MMethodDef do
+ mmethoddef.total_call = visitor.total_call
+ mmethoddef.line_number = visitor.line_number.length
+ mmethoddef.total_self_call = visitor.total_self_call
+ mmethoddef.total_extern_call = visitor.total_call - visitor.total_self_call
+ return mmethoddef
+end
+
+public class MethodAnalyzeMetrics
+ super Visitor
+ var ameth_prop_def: AMethPropdef
+ var total_call = 0
+ var line_number = new Counter[nullable Int]
+ var total_self_call = 0
+
+ redef fun visit(n) do
+ n.visit_all(self)
+ if n isa AExpr then
+ if not n isa ABlockExpr then
+ if n.first_location != null then
+ line_number.inc(n.first_location.line_start)
+ end
+ end
+ end
+
+ if n isa ASendExpr then
+ var callsite = n.callsite
+ if callsite != null then
+ self.total_call += 1
+ if callsite.recv_is_self == true then self.total_self_call += 1
+ end
+ end
+ end
+end
+
+redef class MMethodDef
+ var total_call = 0
+ var line_number = 0
+ var total_self_call = 0
+ var total_extern_call = 0
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import metrics_base
+import mclasses_metrics
+import semantize
+
+import codesmells_metrics
+
+# Create a tool context to handle options and paths
+var toolcontext = new ToolContext
+toolcontext.tooldescription = "Usage: nitsmells [OPTION]... <file.nit>...\n Computes code smells on Nit programs."
+# We do not add other options, so process them now!
+toolcontext.process_options(args)
+# Get arguments
+var arguments = toolcontext.option_context.rest
+# We need a model to collect stufs
+var model = new Model
+# An a model builder to parse files
+var modelbuilder = new ModelBuilder(model, toolcontext)
+# Here we load an process all modules passed on the command line
+var mmodules = modelbuilder.parse_full(arguments)
+modelbuilder.run_phases
+print "*** CODE SMELLS METRICS ***"
+toolcontext.run_global_phases(mmodules)
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A test program with a fake model to check model tools.
+module featureenvy
+
+import platform
+
+class Starter
+ var attribute = 0
+ var attribute1 = 0
+ var attribute2 = 0
+ fun start do
+ self.attribute1 = 10
+ self.attribute = 2
+ end
+
+ fun ended do end
+end
+
+class FeatureEnvy
+ var testVariable = 0
+
+ fun feature_envy_method do
+ var starter = new Starter
+ testVariable = starter.attribute
+ if starter.attribute == self.testVariable then
+ starter.attribute = 10
+ end
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A test program with a fake model to check model tools.
+module largeclass
+
+import platform
+
+class LargeClass
+ var attribute = 0
+ var attribute1 = 0
+ var attribute2 = 0
+ var attribute3 = 0
+ var attribute4 = 0
+ var attribute5 = 0
+ var attribut6 = 0
+ var attribute7 = 0
+ var attribute8 = 0
+ var attribute9 = 0
+ var attribute10 = 0
+ var attribute11 = 0
+ var attribute12 = 0
+ var attribute13 = 0
+ var attribute14 = 0
+ var attribute15 = 0
+ var attribute16 = 0
+ var attribute17 = 0
+
+ fun start do
+ self.attribute16 = 10
+ end
+
+ fun ended do end
+ fun replay do end
+ fun restart do end
+ fun start1 do end
+ fun ended1 do end
+ fun replay1 do end
+ fun restart1 do end
+ fun start2 do end
+ fun ended2 do end
+ fun replay2 do end
+ fun restart2 do end
+end
+
+class NoLargeclass
+ var testVariable = 0
+
+ fun test do end
+end
\ No newline at end of file
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A test program with a fake model to check model tools.
+module longmethod
+
+import platform
+
+class Starter
+ var attribute = 0
+ var attribute1 = 0
+ var attribute2 = 0
+ fun start do
+ self.attribute1 = 10
+ end
+
+ fun ended do end
+end
+
+class LongMethodClass
+ var test_variable = 0
+
+ fun long_method do
+ var starter = new Starter
+ test_variable = 3
+ end
+end
\ No newline at end of file
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A test program with a fake model to check model tools.
+module longparameterlist
+
+import platform
+
+class Starter
+ fun no_para do end
+
+ fun no_para2() do end
+end
+
+class Test
+ fun short_list_parameter(numbers : Int, para1 : Bool, para2 : Float, para3 : Int) do
+ var starter = new Starter
+ end
+
+ fun long_list_parameter(numbers : Int, para1 : Bool, para2 : Float, para3 : Int, para4 : Starter) do
+ var starter = new Starter
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Declares base types allowed on the platform.
+module platform
+
+import end
+
+# Root of everything.
+interface Object
+ # Used for comparisons.
+ type OTHER: nullable Object
+
+ # Is `other` equqls to `self`?
+ fun ==(other: OTHER): Bool is intern
+
+ # Is `other` different from `self`?
+ fun !=(other: OTHER): Bool do return not self == other
+end
+
+# Some services about Integers.
+class Int
+ fun -: Int is intern
+ fun +(i: Int): Int is intern
+ fun -(i: Int): Int is intern
+ fun *(i: Int): Int is intern
+ fun /(i: Int): Int is intern
+ fun >(i: Int): Bool is intern
+ fun to_f: Float is intern
+end
+
+# Some services about Floats.
+class Float
+ fun +(f: Float): Float is intern
+ fun -(f: Float): Float is intern
+ fun *(f: Float): Float is intern
+ fun /(f: Float): Float is intern
+ fun >(f: Float): Bool is intern
+end
+
+# Booleans, `true` or `false`.
+class Bool end
+
+# Strings (there is no chars...).
+class String end
+
+# List of things.
+class List[E] end
--- /dev/null
+--no-colors test_prog/
+--no-colors TestNitsmells/FeatureEnvy/
+--no-colors TestNitsmells/LargeClass/
+--no-colors TestNitsmells/LongMethod/
+--no-colors TestNitsmells/LongParameterList/
\ No newline at end of file
--- /dev/null
+Usage: nitsmells [OPTION]... <file.nit>...
+ Computes code smells on Nit programs.
+Use --help for help
--- /dev/null
+*** CODE SMELLS METRICS ***
+--- Code Smells Metrics ---
+-----------
+test_prog$Character
+Large class: 6 attributes and 18 methods (5.414A 7.161M Average)
+Feature envy:
+ Affected method(s):
+ -total_strengh 4/9
+ -total_endurance 4/9
+ -total_intelligence 4/9
+Long method: Average 1 lines
+ Affected method(s):
+ -total_strengh has 2 lines
+ -total_endurance has 2 lines
+ -total_intelligence has 2 lines
+-----------
+test_prog::combat$Dwarf
+Feature envy:
+ Affected method(s):
+ -dps 1/3
--- /dev/null
+*** CODE SMELLS METRICS ***
+--- Code Smells Metrics ---
+-----------
+TestNitsmells$FeatureEnvy
+Feature envy:
+ Affected method(s):
+ -feature_envy_method 2/6
--- /dev/null
+*** CODE SMELLS METRICS ***
+--- Code Smells Metrics ---
+-----------
+TestNitsmells$LargeClass
+Large class: 18 attributes and 48 methods (17.515A 30.464M Average)
--- /dev/null
+*** CODE SMELLS METRICS ***
+--- Code Smells Metrics ---
+-----------
+TestNitsmells$LongMethodClass
+Long method: Average 1 lines
+ Affected method(s):
+ -long_method has 2 lines