diff --git a/resources/doc/documentation.md b/resources/doc/documentation.md index c6df1db..79d1f70 100644 --- a/resources/doc/documentation.md +++ b/resources/doc/documentation.md @@ -277,5 +277,18 @@ If methods present on traits are duplicated in a classe using the trait, Chanel - The class of the method needs to use at least on trait - The method should have another method in the trait composition with the same name and the same AST. +*Warnings:* +This cleaning should not have any counter indication. + +### Remove methods with equivalent in super classes. + +If a methods has an equivalent method of the same name in a super class, Chanel remove the method. + +*Conditions for the cleanings to by applied:* +- Work only in instances and class side of classes. Does not work on traits. +- The superclass of the method should not be nil. +- The method should override another method in the hierarchy. +- The overriden method as the same AST than the overriding method. + *Warnings:* This cleaning should not have any counter indication. \ No newline at end of file diff --git a/src/Chanel-Tests/ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest.class.st b/src/Chanel-Tests/ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest.class.st new file mode 100644 index 0000000..a813f7d --- /dev/null +++ b/src/Chanel-Tests/ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest.class.st @@ -0,0 +1,136 @@ +" +A ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest is a test class for testing the behavior of ChanelRemoveMethodsWithEquivalentInSuperClassCleaner +" +Class { + #name : #ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest, + #superclass : #ChanelAbstractCleanerTest, + #instVars : [ + 'superClass' + ], + #category : #'Chanel-Tests' +} + +{ #category : #running } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> setUp [ + super setUp. + superClass := self createDefaultClass. + class := self createSubclassOf: superClass named: #ChanelRemoveMethodssWithSuperEquavalentSubClassFake. +] + +{ #category : #tests } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> testClassRemoveMethodWithEquivalentInSuperClass [ + superClass class compile: 'methodTest + ^2'. + + class class compile: 'methodTest + ^2'. + + self runCleaner. + + self assert: (superClass class localSelectors includes: #methodTest). + self deny: (class class localSelectors includes: #methodTest) +] + +{ #category : #tests } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> testDoesNotRemoveMethodIfNotPresentInSuperClass [ + class compile: 'method + ^3'. + + self runCleaner. + + self deny: (superClass localSelectors includes: #method). + self assert: (class localSelectors includes: #method) +] + +{ #category : #tests } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> testDoesNotRemoveMethodsFromTrait [ + | trait | + trait := self createDefaultTrait. + + class setTraitComposition: trait. + + superClass compile: 'method + ^2'. + + trait compile: 'method + ^3'. + + self runCleaner. + + self assert: (superClass localSelectors includes: #method). + self deny: (class localSelectors includes: #method). + self assert: (trait localSelectors includes: #method) +] + +{ #category : #tests } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> testDoesNotRemoveNotEquivalentMethod [ + superClass compile: 'method + ^2'. + + class compile: 'method + ^3'. + + self runCleaner. + + self assert: (superClass localSelectors includes: #method). + self assert: (class localSelectors includes: #method) +] + +{ #category : #tests } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> testDoesNotRemoveNotEquivalentMethodWithPragma [ + superClass compile: 'method + ^2'. + + class compile: 'method + + ^2'. + + self runCleaner. + + self assert: (superClass localSelectors includes: #method). + self assert: (class localSelectors includes: #method) +] + +{ #category : #tests } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> testRemoveMethodWithEquivalentInSuperClass [ + superClass compile: 'method + ^2'. + + class compile: 'method + ^2'. + + self runCleaner. + + self assert: (superClass localSelectors includes: #method). + self deny: (class localSelectors includes: #method) +] + +{ #category : #tests } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> testRemoveMethodWithEquivalentInSuperClassWithComment [ + superClass compile: 'method + ^2'. + + class compile: 'method + "I don''t care about comments." + ^2'. + + self runCleaner. + + self assert: (superClass localSelectors includes: #method). + self deny: (class localSelectors includes: #method) +] + +{ #category : #tests } +ChanelRemoveMethodsWithEquivalentInSuperClassCleanerTest >> testRemoveMethodWithEquivalentInSuperClassWithJustCommentDifference [ + superClass compile: 'method + ^2'. + + class compile: 'method + "I don''t care about comments." + ^2'. + + self runCleaner. + + self assert: (superClass localSelectors includes: #method). + self deny: (class localSelectors includes: #method) +] diff --git a/src/Chanel/ChanelRemoveMethodsWithEquivalentInSuperClassCleaner.class.st b/src/Chanel/ChanelRemoveMethodsWithEquivalentInSuperClassCleaner.class.st new file mode 100644 index 0000000..09b965e --- /dev/null +++ b/src/Chanel/ChanelRemoveMethodsWithEquivalentInSuperClassCleaner.class.st @@ -0,0 +1,28 @@ +" +Description +-------------------- + +I am a cleaner removing methods overriding another method with exactly the same AST. +" +Class { + #name : #ChanelRemoveMethodsWithEquivalentInSuperClassCleaner, + #superclass : #ChanelAbstractCleaner, + #category : #Chanel +} + +{ #category : #accessing } +ChanelRemoveMethodsWithEquivalentInSuperClassCleaner class >> priority [ + ^ 1500 +] + +{ #category : #cleaning } +ChanelRemoveMethodsWithEquivalentInSuperClassCleaner >> clean [ + | overridenMethod | + self configuration definedClasses iterator + | #isTrait rejectIt + | [ :class | class localMethods, class class localMethods ] flatCollectIt + | [ :method | method methodClass superclass isNil ] rejectIt + | [ :method | (overridenMethod := (method methodClass superclass lookupSelector: method selector)) isNil ] rejectIt + | [ :method | method ast = overridenMethod ast ] selectIt + > #removeMethod doIt +]