Skip to content

Commit 5cb3a0d

Browse files
Merge pull request #1567 from moosetechnology/java-dead-code-rule
Update/extend Java dead code rule (with tests)
2 parents 93e1bdc + 28f7dce commit 5cb3a0d

File tree

5 files changed

+141
-75
lines changed

5 files changed

+141
-75
lines changed

src/MooseIDE-DeadCode-Tests/MiDeadCodeBrowserModelTest.class.st

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ MiDeadCodeBrowserModelTest >> testIsNewDead [
200200

201201
{ #category : 'tests - heuristics' }
202202
MiDeadCodeBrowserModelTest >> testJavaAnnotationHeuristicDeadNoAnnotation [
203+
"Unused method with no annotation is dead"
203204

204205
| entity |
205206
entity := FamixJavaMethod new.
@@ -209,6 +210,7 @@ MiDeadCodeBrowserModelTest >> testJavaAnnotationHeuristicDeadNoAnnotation [
209210

210211
{ #category : 'tests - heuristics' }
211212
MiDeadCodeBrowserModelTest >> testJavaAnnotationHeuristicDeadWrongAnnotation [
213+
"Unused method with @Deprecated annotation is dead"
212214

213215
| entity |
214216
entity := self javaMethod: 'someFunctionality' annotatedWith: 'Deprecated'.
@@ -218,6 +220,7 @@ MiDeadCodeBrowserModelTest >> testJavaAnnotationHeuristicDeadWrongAnnotation [
218220

219221
{ #category : 'tests - heuristics' }
220222
MiDeadCodeBrowserModelTest >> testJavaAnnotationHeuristicNotDead [
223+
"Unused method with JUnit annotation is not dead"
221224

222225
| entity |
223226
entity := self javaMethod: 'someFunctionality' annotatedWith: 'BeforeClass'.
@@ -227,6 +230,7 @@ MiDeadCodeBrowserModelTest >> testJavaAnnotationHeuristicNotDead [
227230

228231
{ #category : 'tests - heuristics' }
229232
MiDeadCodeBrowserModelTest >> testJavaHasOverridingHeuristicDead [
233+
"Unused method (entity1.doSomething()) with sub-method declaring @Override is not dead"
230234

231235
| entity1 entity2 annotation |
232236
entity1 := self javaClassMethod: 'doSomething()'.
@@ -247,6 +251,8 @@ MiDeadCodeBrowserModelTest >> testJavaHasOverridingHeuristicDead [
247251

248252
{ #category : 'tests - heuristics' }
249253
MiDeadCodeBrowserModelTest >> testJavaHasOverridingHeuristicDeadNoAnnotation [
254+
"Unused method (entity1.doSomething()) with sub-method not declaring @Override is dead"
255+
250256
| entity1 entity2 |
251257
entity1 := self javaClassMethod: 'doSomething()'.
252258
entity2 := self javaClassMethod: 'doSomething()'.
@@ -257,6 +263,8 @@ MiDeadCodeBrowserModelTest >> testJavaHasOverridingHeuristicDeadNoAnnotation [
257263

258264
{ #category : 'tests - heuristics' }
259265
MiDeadCodeBrowserModelTest >> testJavaHasOverridingHeuristicDeadNoOverride [
266+
"Unused method (entity1.doSomething()) with sub-method not declaring @Override is dead"
267+
260268
| entity1 entity2 annotation |
261269

262270
entity1 := self javaClassMethod: 'doSomething()'.
@@ -279,6 +287,9 @@ MiDeadCodeBrowserModelTest >> testJavaHasOverridingHeuristicDeadNoOverride [
279287

280288
{ #category : 'tests - heuristics' }
281289
MiDeadCodeBrowserModelTest >> testJavaHasOverridingHeuristicDeadNoSubMethod [
290+
"Unused method (entity1.doSomething()) with sub-method declaring @Override is dead
291+
(note: entity1.doSomething() is not a sub method of entity1.doSomething()"
292+
282293
| entity1 entity2 annotation |
283294

284295
entity1 := self javaClassMethod: 'doSomething()'.
@@ -298,26 +309,55 @@ MiDeadCodeBrowserModelTest >> testJavaHasOverridingHeuristicDeadNoSubMethod [
298309

299310
{ #category : 'tests - heuristics' }
300311
MiDeadCodeBrowserModelTest >> testJavaImplementsHeuristicNoInterface [
312+
"Unused method (entity1.doSomething()) not implementing an abtract declaration is dead"
301313

302314
| entity1 |
303315
entity1 := self javaClassMethod: 'doSomething()'.
304316

305-
self assert: (MiDeadCodeJavaImplementsInterfaceHeuristic new isDead: entity1)
317+
self assert: (MiDeadCodeJavaImplementsAbstractHeuristic new isDead: entity1)
306318
]
307319

308320
{ #category : 'tests - heuristics' }
309321
MiDeadCodeBrowserModelTest >> testJavaImplementsHeuristicNoOverride [
322+
"Unused method (entity1.doSomething())) implementing an interface declaration is not dead
323+
(according to MiDeadCodeJavaImplementsAbstractHeuristic)"
310324

311325
| entity1 entity2 |
312326
entity1 := self javaClassMethod: 'doSomething()'.
313327
entity2 := self javaInterfaceMethod: 'doSomething()'.
314328
self javaClass: entity1 parentType implements: entity2 parentType.
315329

316-
self deny: (MiDeadCodeJavaImplementsInterfaceHeuristic new isDead: entity1)
330+
self deny: (MiDeadCodeJavaImplementsAbstractHeuristic new isDead: entity1)
331+
]
332+
333+
{ #category : 'tests - heuristics' }
334+
MiDeadCodeBrowserModelTest >> testJavaImplementsHeuristicNotAbstract [
335+
"Unused method (entity1.doSomething()) overriding a super-method is dead"
336+
337+
| entity1 entity2 |
338+
entity1 := self javaClassMethod: 'doSomething()'.
339+
entity2 := self javaClassMethod: 'doSomething()'.
340+
self javaClass: entity1 parentType inherits: entity2 parentType.
341+
342+
self assert: (MiDeadCodeJavaImplementsAbstractHeuristic new isDead: entity1)
343+
]
344+
345+
{ #category : 'tests - heuristics' }
346+
MiDeadCodeBrowserModelTest >> testJavaImplementsHeuristicWithAbstract [
347+
"Unused method (entity1.doSomething()) overriding an abstract super-method is not dead"
348+
349+
| entity1 entity2 |
350+
entity1 := self javaClassMethod: 'doSomething()'.
351+
entity2 := self javaClassMethod: 'doSomething()'.
352+
entity2 isAbstract: true.
353+
self javaClass: entity1 parentType inherits: entity2 parentType.
354+
355+
self deny: (MiDeadCodeJavaImplementsAbstractHeuristic new isDead: entity1)
317356
]
318357

319358
{ #category : 'tests - heuristics' }
320359
MiDeadCodeBrowserModelTest >> testJavaImplementsHeuristicWithOverride [
360+
"Unused method (entity1.doSomething()) implementing an interface declaration but overriding a concrete implementation is dead"
321361

322362
| entity1 entity2 entity3 |
323363
entity1 := self javaClassMethod: 'doSomething()'.
@@ -326,11 +366,14 @@ MiDeadCodeBrowserModelTest >> testJavaImplementsHeuristicWithOverride [
326366
self javaClass: entity1 parentType inherits: entity2 parentType.
327367
self javaClass: entity1 parentType implements: entity3 parentType.
328368

329-
self assert: (MiDeadCodeJavaImplementsInterfaceHeuristic new isDead: entity1)
369+
self assert: (MiDeadCodeJavaImplementsAbstractHeuristic new isDead: entity1)
330370
]
331371

332372
{ #category : 'tests - heuristics' }
333373
MiDeadCodeBrowserModelTest >> testJavaOverridesHeuristicDeadNoInterface [
374+
"Unused method (entity1.doSomething()) is dead
375+
note: no link between entity1 and entity2"
376+
334377
| entity1 entity2 |
335378
entity1 := self javaClassMethod: 'doSomething()'.
336379
entity2 := self javaInterfaceMethod: 'doSomething()'.
@@ -341,6 +384,8 @@ MiDeadCodeBrowserModelTest >> testJavaOverridesHeuristicDeadNoInterface [
341384

342385
{ #category : 'tests - heuristics' }
343386
MiDeadCodeBrowserModelTest >> testJavaOverridesHeuristicDeadNoInvocation [
387+
"Unused method implementing an interface declaration is dead
388+
(according to MiDeadCodeJavaOverridesInvokedHeuristic)"
344389

345390
| entity1 entity2 |
346391
entity1 := self javaClassMethod: 'doSomething()'.
@@ -352,6 +397,9 @@ MiDeadCodeBrowserModelTest >> testJavaOverridesHeuristicDeadNoInvocation [
352397

353398
{ #category : 'tests - heuristics' }
354399
MiDeadCodeBrowserModelTest >> testJavaOverridesHeuristicDeadNoMethod [
400+
"Unused method (entity1.doSomething()) with no implementing sub-method used is dead
401+
(according to MiDeadCodeJavaOverridesInvokedHeuristic)
402+
note: methods names are different"
355403

356404
| entity1 entity2 |
357405
entity1 := self javaClassMethod: 'doSomething()'.
@@ -364,6 +412,8 @@ MiDeadCodeBrowserModelTest >> testJavaOverridesHeuristicDeadNoMethod [
364412

365413
{ #category : 'tests - heuristics' }
366414
MiDeadCodeBrowserModelTest >> testJavaOverridesHeuristicNotDead [
415+
"Unused method (entity1.doSomething()) with implementing sub-method used is not dead
416+
(according to MiDeadCodeJavaOverridesInvokedHeuristic)"
367417

368418
| entity1 entity2 |
369419
entity1 := self javaClassMethod: 'doSomething()'.
@@ -572,11 +622,11 @@ MiDeadCodeBrowserModelTest >> testRecursionRoundNotAddingOutsideFollwedEntities
572622
MiDeadCodeBrowserModelTest >> testSortHeuristics [
573623

574624
model chooseHeuristics: {
575-
MiDeadCodeJavaImplementsInterfaceHeuristic new .
625+
MiDeadCodeJavaImplementsAbstractHeuristic new .
576626
MiDeadCodeJavaTestAnnotationHeuristic new }.
577627

578628
self assert: model chosenHeuristics size equals: 3.
579-
self assert: model chosenHeuristics first class equals: MiDeadCodeJavaImplementsInterfaceHeuristic.
629+
self assert: model chosenHeuristics first class equals: MiDeadCodeJavaImplementsAbstractHeuristic.
580630
self assert: model chosenHeuristics second class equals: MiDeadCodeJavaTestAnnotationHeuristic.
581631
self assert: model chosenHeuristics third class equals: MiDeadCodeNoIncomingInvocationHeuristic.
582632
]

src/MooseIDE-DeadCode/MiDeadCodeAbstractHeuristic.class.st

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Class {
2323
{ #category : 'testing' }
2424
MiDeadCodeAbstractHeuristic class >> isAbstract [
2525

26-
^self name includesSubstring: 'Abstract'
26+
^self name includesSubstring: 'MiDeadCodeAbstract'
2727
]
2828

2929
{ #category : 'accessing' }

src/MooseIDE-DeadCode/MiDeadCodeJavaHasOverridingHeuristic.class.st

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
"
2+
A method having an ""@Override"" sub-method (in a subclass) is assumed not-dead,
3+
because one cannot remove the overriden method
4+
(@Override makes it mandatory to have a super-method)
5+
"
16
Class {
27
#name : 'MiDeadCodeJavaHasOverridingHeuristic',
38
#superclass : 'MiDeadCodeAbstractJavaHeuristic',
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"
2+
A heuristic to recognize methods overriding another method that is called.
3+
4+
If a method in a super-class (or interface) is called, we assume any method implementing it in a concrete class can be called
5+
"
6+
Class {
7+
#name : 'MiDeadCodeJavaImplementsAbstractHeuristic',
8+
#superclass : 'MiDeadCodeAbstractJavaHeuristic',
9+
#category : 'MooseIDE-DeadCode-Rules',
10+
#package : 'MooseIDE-DeadCode',
11+
#tag : 'Rules'
12+
}
13+
14+
{ #category : 'testing' }
15+
MiDeadCodeJavaImplementsAbstractHeuristic >> any: tWithMethods declaresMethod: aTMethod [
16+
17+
tWithMethods do: [ :aTWithMethods |
18+
aTWithMethods methods
19+
detect: [ :mth | mth signature = aTMethod signature ]
20+
ifOne: [ :mth | ^true ]
21+
].
22+
23+
^false
24+
]
25+
26+
{ #category : 'testing' }
27+
MiDeadCodeJavaImplementsAbstractHeuristic >> collect: tWithMethods definedMethod: aTMethod [
28+
29+
^tWithMethods
30+
collect: [ :aTWithMethods |
31+
aTWithMethods methods
32+
detect: [ :mth | mth signature = aTMethod signature ]
33+
ifNone: [ nil ]
34+
]
35+
thenReject: #isNil
36+
37+
]
38+
39+
{ #category : 'accessing' }
40+
MiDeadCodeJavaImplementsAbstractHeuristic >> description [
41+
42+
^super description ,
43+
'A method implementing an abstract method, even dead, is needed for the implementation'
44+
]
45+
46+
{ #category : 'accessing' }
47+
MiDeadCodeJavaImplementsAbstractHeuristic >> name [
48+
49+
^super name , 'Implements abstract method'
50+
]
51+
52+
{ #category : 'testing' }
53+
MiDeadCodeJavaImplementsAbstractHeuristic >> notDead: aTMethod [
54+
"- Get all methods defined in super-classes
55+
- if any one is not abstract, then return false, the rule does not apply
56+
- if there is one, it must be abstract, return true (is not dead)
57+
- Look at all methods defined in implemented interface
58+
if any matches this method then return true (is not dead)"
59+
60+
| superclasses definedMethods implementedInterfaces |
61+
62+
superclasses := aTMethod parentType superclassHierarchy
63+
reject: #isNil. "protect against a bug in VerveineJ"
64+
65+
definedMethods := self collect: superclasses definedMethod: aTMethod.
66+
67+
definedMethods
68+
detect: [ :definedMethod | definedMethod isAbstract not ]
69+
ifOne: [ :definedMethod | ^false ].
70+
71+
definedMethods ifNotEmpty: [ ^true ].
72+
73+
implementedInterfaces := ({ aTMethod parentType } , superclasses)
74+
flatCollectAsSet: [ :c | self implementedInterfaceHierarchy: c ].
75+
76+
(self any: implementedInterfaces declaresMethod: aTMethod)
77+
ifTrue: [ ^true ].
78+
79+
^ false
80+
]

src/MooseIDE-DeadCode/MiDeadCodeJavaImplementsInterfaceHeuristic.class.st

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)