-
Notifications
You must be signed in to change notification settings - Fork 65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nitsmell : Add code smell detection #2445
Conversation
ok to test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although there's a base that could be merged, there is still some work to do to arrive at that point, could you fix all the issues in your code and re-submit? Thanks!
src/metrics/codesmells_metrics.nit
Outdated
module codesmells_metrics | ||
|
||
# We usualy need specific phases | ||
# NOTE: `frontend` is sufficent in most case (it is often too much) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment feels out of place, is it a copy/paste from an example phase?
src/metrics/codesmells_metrics.nit
Outdated
# 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. | ||
module codesmells_metrics |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The module header should be detached from the license, else nitdoc might consider it as part of the documentation
src/metrics/codesmells_metrics.nit
Outdated
class Antipatterns | ||
super BadConceptions | ||
# create all Antipatterns | ||
init do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This init could be removed if it is empty
src/metrics/codesmells_metrics.nit
Outdated
end | ||
|
||
#Collection | ||
fun collect(classe : AClassdef)do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A common way to avoid synatx errors when using class
is to use clazz
instead, but if it bothers no one, classe
is also OK, albeit a bit too french
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For AClassdef
, aclassdef
and n_classdef
(the latter for historical reasons) are the most common variable names used in the Nit compiler.
src/metrics/codesmells_metrics.nit
Outdated
|
||
class BadConceptions | ||
#Code smell list | ||
var badConceptionElement = new Array[BadConception] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally when declaring attributes or variables, the preferred Nit style is snake_case instead of camelCase
src/metrics/codesmells_metrics.nit
Outdated
var badConceptionElement = new Array[BadConception] | ||
|
||
# Print all element conception | ||
fun printAll do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel the print concerns should be handled by the nitmetrics command-line client instead of the library.
If it is the case, at some point we may add a dependance on console
to add some command-line eye-candy, which would make no sense in the library itself
src/metrics/codesmells_metrics.nit
Outdated
var visits = callvisiteMethodAnalyse(aclasse) | ||
|
||
for visit in visits do | ||
if visit.lineDetail.length > 30 then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard-coded magic number is hard-coded, could you move it to an attribute should we wish to change it at some point?
import mclasses_metrics | ||
import semantize | ||
|
||
fun callvisiteMethodAnalyse(aclasse : AClassdef) : Array[MethodAnalyse] do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fun analyze_methods
? Or analyse_methods
would be OK too, I'm not angry with en_GB.
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same newline issue here
src/nitsmells.nit
Outdated
|
||
# The body of the specific work. | ||
# The main entry point is provided by `test_phase`, | ||
# This function is then automatically (unless errors where found). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems out of place too, copy/paste issue?
There's a typo here as well
5a4540f
to
517a880
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of changes required. But aside from the code the real problem is the theory behind it.
In my opinion, you really need more tests on this. At least to find the edge cases (like the one shown in test_prog
.
src/metrics/codesmells_metrics.nit
Outdated
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
# Detect the code smells and antipatterns in the code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is the documentation of the module it should be attached to the module
declaration. Remove the blank line between them.
src/metrics/codesmells_metrics.nit
Outdated
|
||
|
||
redef class ToolContext | ||
var codesmells_metrics_phase: Phase = new CodeSmellsMetricsPhase(self, null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced that the static type is really required here.
src/metrics/codesmells_metrics.nit
Outdated
|
||
|
||
redef fun process_mainmodule(mainmodule, given_mmodules) | ||
do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of your do
s are inlined with the method declaration, keep it consistent.
src/metrics/codesmells_metrics.nit
Outdated
redef fun process_mainmodule(mainmodule, given_mmodules) | ||
do | ||
print toolcontext.format_h1("--- Code Smells Metrics ---") | ||
var mclazzs = mainmodule.flatten_mclass_hierarchy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean mclasses
?
src/metrics/codesmells_metrics.nit
Outdated
print toolcontext.format_h1("--- Code Smells Metrics ---") | ||
var mclazzs = mainmodule.flatten_mclass_hierarchy | ||
var model_builder = toolcontext.modelbuilder | ||
var model_view = model_builder.model.private_view |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really good question. Do we take private/generated things into account when running mertrics?
tests/sav/nitsmells_args1.res
Outdated
-quit | ||
Long method: Average 1 lines | ||
Affected method: | ||
-total_strengh has 2 lines |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the example itself shows how reliable this metric is... :/
I'm not convinced that a 2-lines method can really be viewed as large. Even if the average is 1 line.
tests/sav/nitsmells_args1.res
Outdated
*** CODE SMELLS METRICS *** | ||
--- Code Smells Metrics --- | ||
------------------- | ||
Class: Character |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should display the class full name (full_name
) or/and the class location.
tests/sav/nitsmells_args1.res
Outdated
Class: Character | ||
Feature envy : true | ||
Affected method: | ||
-quit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feature envy: A method accesses the data of another object more than its own data.
Here the quit
code:
fun quit do
career = null
end
I really don't understand the result.
tests/sav/nitsmells_args1.res
Outdated
-total_endurance has 2 lines | ||
-total_intelligence has 2 lines | ||
------------------- | ||
Class: Character |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it appears twice for the same program, you are not talking about Class
but Classdef
tests/sav/nitsmells_args1.res
Outdated
Class: Character | ||
Feature envy : true | ||
Affected method: | ||
-hit_points |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again:
redef fun hit_points do return health
Here health
is introduced by Character
but in another mclassdef.
src/metrics/codesmells_metrics.nit
Outdated
fun print_result is abstract | ||
end | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caca
src/metrics/codesmells_metrics.nit
Outdated
|
||
var number_method = 0 | ||
|
||
redef fun name do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inlining
src/metrics/codesmells_metrics.nit
Outdated
|
||
redef fun name do | ||
return "LONGPL" | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caca
src/metrics/codesmells_metrics.nit
Outdated
return result | ||
end | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caca
src/metrics/codesmells_metrics.nit
Outdated
end | ||
end | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caca
src/metrics/codesmells_metrics.nit
Outdated
number_attribut = mclassdef.collect_intro_and_redef_mattributes(model_builder.model.private_view).length | ||
# get the number of methods and subtract the get and set of attibutes (numberAtribut*2) | ||
number_method = mclassdef.collect_intro_and_redef_methods(model_builder.model.private_view).length - (number_attribut*2) | ||
if number_method.to_f > phase.average_number_of_method and number_attribut.to_f > phase.average_number_of_attribute then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return "the big ass condition"
src/metrics/codesmells_metrics.nit
Outdated
bad_methods.add(meth) | ||
result = true | ||
end | ||
return result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return bad_methods.not_empty
src/metrics/codesmells_metrics.nit
Outdated
result = true | ||
bad_methods.add(mmethoddef) | ||
end | ||
return result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return bad_methods.not_empty
src/metrics/codesmells_metrics.nit
Outdated
return "Long method" | ||
end | ||
|
||
redef fun collect(mclassdef, model_builder): Bool do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Factorize this method
src/metrics/codesmells_metrics.nit
Outdated
var result = false | ||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redefine this part from the factorization
tests/sav/nitsmells_args2.res
Outdated
@@ -0,0 +1,2 @@ | |||
Error: cannot find module `../TestNitsmells/LargeClass/`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL
tests/sav/nitsmells_args3.res
Outdated
@@ -0,0 +1,2 @@ | |||
Error: cannot find module `../TestNitsmells/LongMethod/`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL
tests/sav/nitsmells_args4.res
Outdated
@@ -0,0 +1,2 @@ | |||
Error: cannot find module `../TestNitsmells/LongParameterList/`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL
src/metrics/codesmells_metrics.nit
Outdated
return counter.avg + counter.std_dev | ||
end | ||
|
||
fun get_avg_LineNumber(model_builder: ModelBuilder): Float do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird case
bd529e7
to
52b86ca
Compare
tests are OK (modulo Java & race conditions). |
I just saw one last change. I need to replace the mclassdef.mpropdefs by mclassdef.collect ... |
Long class Long method parameter list Long size method Feature envy Adding a visitor to analyse the contents of the methods Signed-off-by: Florian Deljarry <deljarry.florian@gmail.com>
Good job, ok to merge! |
Adding code smell detection : - Long class - Long method parameter list - Long size method - Feature envy Adding a visitor to analyse the contents of the methods Pull-Request: #2445 Reviewed-by: Jean Privat <jean@pryen.org> Reviewed-by: Lucas Bajolet <r4pass@hotmail.com> Reviewed-by: Jean-Christophe Beaupré <jcbrinfo.public@gmail.com>
Adding code smell detection :
Adding a visitor to analyse the contents of the methods