Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7f93db9
Driver improvement for temp to instance variable
AlexisCnockaert Oct 31, 2025
497bf9a
Merge branch 'Pharo14' into refactoring/newdriver
AlexisCnockaert Oct 31, 2025
3fa60b3
Merge branch 'Pharo14' into refactoring/newdriver
Ducasse Oct 31, 2025
5396e18
Almost done, missing 1 single action
AlexisCnockaert Nov 13, 2025
901503a
Merge 3fa60b3b000d6cf5ba6a0f388c51aa2268745d8c
AlexisCnockaert Nov 13, 2025
7e2d58c
AlexisCnockaert Nov 20, 2025
be757cd
remove accidental file
AlexisCnockaert Nov 20, 2025
c5fd2f3
?
AlexisCnockaert Nov 20, 2025
3c78684
Merge branch 'Pharo14' into refactoring/newdriver
AlexisCnockaert Nov 20, 2025
3f509b2
Last changes for driver implementation
AlexisCnockaert Nov 20, 2025
f2c41d1
Merge branch 'Pharo14' into refactoring/newdriver
AlexisCnockaert Nov 20, 2025
553b828
permission revert
AlexisCnockaert Nov 20, 2025
e341041
Merge branch 'refactoring/newdriver' of github.com:AlexisCnockaert/ph…
AlexisCnockaert Nov 20, 2025
66b978e
remove unwanted class
AlexisCnockaert Nov 20, 2025
2a425d4
Delete src/Refactoring-UI/RePushUpInstanceVariableAndRemoveTempChoice…
AlexisCnockaert Nov 20, 2025
1b216c9
Update expected size of refactoring changes to 3
AlexisCnockaert Nov 20, 2025
f53b5f1
Fix failing test and extra method display on driver!
Nov 24, 2025
7937ade
Merge 66b978ec8e15b0e99d36378705c07fd5f1c9a059
Nov 24, 2025
6875cf6
Merge branch 'Pharo14' into refactoring/newdriver
AlexisCnockaert Nov 24, 2025
5e01f0b
Merge branch 'Pharo14' into Refactoring/newdriver
AlexisCnockaert Nov 24, 2025
3f0daec
Merge 5e01f0b034a9b82d919dc6188b7735f58e8b1a6f
AlexisCnockaert Nov 27, 2025
e8d0d18
Renamed clas condition name and browse references action for driver
AlexisCnockaert Nov 27, 2025
d926372
Merge branch 'Pharo14' into Refactoring/newdriver
AlexisCnockaert Nov 27, 2025
b672d5c
last changes!!
AlexisCnockaert Nov 27, 2025
7b516e7
Merge d9263726c9d076884cff617f86073506ba3be759
AlexisCnockaert Nov 27, 2025
bd969c3
Merge branch 'Pharo14' into Refactoring/newdriver
AlexisCnockaert Nov 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 0 additions & 38 deletions src/Refactoring-Core/RBCondition.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,6 @@ RBCondition class >> checkInstanceVariableName: aName in: aClass [
^ OCScanner isVariable: string
]

{ #category : 'instance creation' }
RBCondition class >> checkNotMultipleTemporaryDefinitionsOf: aString in: aClass [

| condition |
condition := self new.
condition
block: [
| methods |
methods := self multipleMethodsDefiningTemporary: aString in: aClass ignore: [ :class :selector | false ].
methods size > 1
ifTrue: [
condition errorMacro:
'More than one method defines temporary variable ' , aString , ': ' , (methods collect: [ :m | m selector ]) asString.
false ]
ifFalse: [ true ] ]
errorString: aClass printString , ' <1?:does not >define<1?s:> temporary variable ' , aString.
^ condition
]

{ #category : 'instance creation' }
RBCondition class >> definesClassVariable: aString in: aClass [
^self new
Expand Down Expand Up @@ -374,25 +355,6 @@ RBCondition class >> methodDefiningTemporary: aString in: aClass ignore: aBlock
^ nil
]

{ #category : 'utilities' }
RBCondition class >> multipleMethodsDefiningTemporary: aString in: aClass ignore: aBlock [

| searcher methods method |
searcher := OCParseTreeSearcher new.
methods := Set new.
method := nil.

searcher matches: aString do: [ :aNode :answer | methods add: method ].
aClass withAllSubclasses do: [ :class |
class selectors do: [ :each |
(aBlock value: class value: each) ifFalse: [
| parseTree |
method := class methodFor: each.
parseTree := class parseTreeForSelector: each.
parseTree ifNotNil: [ searcher executeTree: parseTree ] ] ] ].
^ methods
]

{ #category : 'instance creation' }
RBCondition class >> referencesClassVariable: aString in: aClass [

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,9 @@ RBTemporaryToInstanceVariableRefactoring >> applicabilityPreconditions [
RBTemporaryToInstanceVariableRefactoring >> breakingChangePreconditions [

^ {
(RBCondition withBlock: [
(class allSubclasses anySatisfy: [ :cls | cls definesInstanceVariable: temporaryVariableName asString ]) ifTrue: [
self refactoringWarning:
('One or more subclasses of <1p> already defines an<n>instance variable with the same name. Proceed anyway?'
expandMacrosWith: class name) ].
true ]).
(RBCondition checkNotMultipleTemporaryDefinitionsOf: temporaryVariableName in: class).
(ReVariablesNotReadBeforeWrittenCondition new
subtree: parseTree;
variables: temporaryVariableName;
checkForTemporaryVariables: true) }
self preconditionNoSubclassDefinesVar.
self preconditionNoMultipleTempOccurences.
self preconditionNoReadBeforeWritten }
]

{ #category : 'initialization' }
Expand All @@ -143,6 +135,31 @@ RBTemporaryToInstanceVariableRefactoring >> isTemporaryVariableNameValid [
self refactoringError: temporaryVariableName , ' is a block parameter' ]
]

{ #category : 'preconditions' }
RBTemporaryToInstanceVariableRefactoring >> preconditionNoMultipleTempOccurences [

^ ReMultipleMethodsDontReferToTempVarCondition name: temporaryVariableName class: class selector: selector
]

{ #category : 'preconditions' }
RBTemporaryToInstanceVariableRefactoring >> preconditionNoReadBeforeWritten [

^ ReVariablesNotReadBeforeWrittenCondition new
subtree: parseTree;
variables: { temporaryVariableName };
checkForTemporaryVariables: true
]

{ #category : 'preconditions' }
RBTemporaryToInstanceVariableRefactoring >> preconditionNoSubclassDefinesVar [

^ RBCondition
withBlock: [ (class allSubclasses anySatisfy: [ :cls | cls definesInstanceVariable: temporaryVariableName asString ]) not ]
errorString:
('One or more subclasses of <1p> already defines an<n>instance variable with the same name.'
expandMacrosWith: class name)
]

{ #category : 'preconditions' }
RBTemporaryToInstanceVariableRefactoring >> preconditions [

Expand All @@ -159,10 +176,6 @@ RBTemporaryToInstanceVariableRefactoring >> prepareForExecution [
RBTemporaryToInstanceVariableRefactoring >> privateTransform [

self removeTemporaryOfClass: class.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not really undersyand what is removeTemporyOfClass: doing so it is difficult for me to get further.
Trying to understand the logic: I think that there were something we should keep.
If one of the subclass got the same instance variable that the temp we want to convert, then we remove it from that class and defines it in the root class.
So why removing this logic.
Because now if a subclass has the variable with the same name we force the guy to do a pullUp.
May be this is better this way the developer has to see it.

class allSubclasses do: [ :cls |
(cls definesInstanceVariable: temporaryVariableName)
ifTrue: [ cls removeInstanceVariable: temporaryVariableName ]
ifFalse: [ self removeTemporaryOfClass: cls ] ].
class addInstanceVariable: temporaryVariableName
]

Expand All @@ -178,8 +191,8 @@ RBTemporaryToInstanceVariableRefactoring >> removeTemporaryOfMethod: aSelector i
method := aClass methodFor: aSelector.
methodParseTree := method parseTree.
methodParseTree ifNil: [ self refactoringError: 'Could not parse method' ].
( matcher := self parseTreeRewriterClass removeTemporaryNamed: temporaryVariableName )
executeTree: methodParseTree.
(methodParseTree temporaryNames includes: temporaryVariableName) ifFalse: [ ^ self ].
(matcher := self parseTreeRewriterClass removeTemporaryNamed: temporaryVariableName) executeTree: methodParseTree.
method compileTree: matcher tree
]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"
I check if temporary variable name is used in other methods of the class.
"
Class {
#name : 'ReMultipleMethodsDontReferToTempVarCondition',
#superclass : 'ReVariableNameCondition',
#instVars : [
'class',
'selector'
],
#category : 'Refactoring-Core-Conditions',
#package : 'Refactoring-Core',
#tag : 'Conditions'
}

{ #category : 'instance creation' }
ReMultipleMethodsDontReferToTempVarCondition class >> name: aString class: aClass selector: aSelector [

^ (self name: aString)
class: aClass;
selector: aSelector yourself
]

{ #category : 'checking' }
ReMultipleMethodsDontReferToTempVarCondition >> check [

^ self violators isEmpty
]

{ #category : 'setter' }
ReMultipleMethodsDontReferToTempVarCondition >> class: aRBClass [

class := aRBClass.

]

{ #category : 'utilities' }
ReMultipleMethodsDontReferToTempVarCondition >> multipleMethodsDefiningTemporary: aString in: aClass ignore: aBlock [

| searcher methods method |
searcher := OCParseTreeSearcher new.
methods := Set new.
method := nil.

searcher matches: aString do: [ :aNode :answer | methods add: method ].
aClass withAllSubclasses do: [ :cls |
cls selectors do: [ :each |
(aBlock value: cls value: each) ifFalse: [
| parseTree |
method := cls methodFor: each.
parseTree := cls parseTreeForSelector: each.
parseTree ifNotNil: [ searcher executeTree: parseTree ] ] ] ].
^ methods
]

{ #category : 'accessing' }
ReMultipleMethodsDontReferToTempVarCondition >> selector: aSelector [

selector := aSelector
]

{ #category : 'displaying' }
ReMultipleMethodsDontReferToTempVarCondition >> violationMessageOn: aStream [

self violators ifEmpty: [ ^ self ].
^ aStream
nextPutAll: 'More than one method defines temporary variable ';
nextPutAll: name;
nextPutAll: ': ';
nextPutAll: (self violators collect: [ :m | m selector ]) asArray asString
]

{ #category : 'checking' }
ReMultipleMethodsDontReferToTempVarCondition >> violators [

| methods |
methods := self multipleMethodsDefiningTemporary: name in: class ignore: [ :cls :selectors | false ].
^ methods reject: [ :m | m selector = selector ]
]
3 changes: 2 additions & 1 deletion src/Refactoring-Core/ReRefactoring.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ ReRefactoring >> canReferenceVariable: aString in: aClass [
{ #category : 'scripting api - conditions' }
ReRefactoring >> checkBreakingChangePreconditions [
"Check a preconditions and raise an error on violations. This method is part of the scripting API since it raises an error."

| failedPreconditions |
failedPreconditions := self failedBreakingChangePreconditions.
failedPreconditions ifEmpty: [ ^ self ].

RBRefactoringWarning signalFor: failedPreconditions
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ ReVariablesNotReadBeforeWrittenCondition >> variables: aCollection [
{ #category : 'displaying' }
ReVariablesNotReadBeforeWrittenCondition >> violationMessageOn: aStream [

self check ifTrue: [ ^ self ].
aStream
nextPutAll: 'Cannot extract selected code because variables: ';
nextPutAll: variables asString;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Class {
#name : 'ReClassToConvertTemporaryToInstanceVariable',
#superclass : 'Object',
#instVars : [
'instVar'
],
#category : 'Refactoring-DataForTesting-ForConvertingVariables',
#package : 'Refactoring-DataForTesting',
#tag : 'ForConvertingVariables'
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add the scenario where a subclass has the same name as the temp that we want to convert.

{ #category : 'action' }
ReClassToConvertTemporaryToInstanceVariable >> doAction1 [

| temp |
temp := 35.

^ temp
]

{ #category : 'action' }
ReClassToConvertTemporaryToInstanceVariable >> doAction2 [

| instVar |
instVar := 3.
^ instVar
]

{ #category : 'initialization' }
ReClassToConvertTemporaryToInstanceVariable >> initialize [

<ignoreUnusedVariables: #( #instVar )>
super initialize
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Class {
#name : 'ReConvertTemporaryToInstanceVariableDriverTest',
#superclass : 'ReDriverTest',
#instVars : [
'testingEnvironment'
],
#category : 'Refactoring-UI-Tests-Driver',
#package : 'Refactoring-UI-Tests',
#tag : 'Driver'
}

{ #category : 'getter' }
ReConvertTemporaryToInstanceVariableDriverTest >> classToConvertTemporaryToInstanceVariable [

^ ReClassToConvertTemporaryToInstanceVariable
]

{ #category : 'running' }
ReConvertTemporaryToInstanceVariableDriverTest >> setUp [

super setUp.
testingEnvironment := RBClassEnvironment classes: self classToConvertTemporaryToInstanceVariable withAllSubclasses
]

{ #category : 'tests' }
ReConvertTemporaryToInstanceVariableDriverTest >> testConvertTempFailure [

| driver |
driver := ReConvertTemporaryToInstanceVariableDriver new.
self setUpDriver: driver.
driver class: self classToConvertTemporaryToInstanceVariable selector: #doAction2 variable: 'instVar'.

driver runRefactoring.

self assert: driver refactoring changes changes size equals: 0
]

{ #category : 'tests' }
ReConvertTemporaryToInstanceVariableDriverTest >> testConvertTempSuccessfully [

| driver |
driver := ReConvertTemporaryToInstanceVariableDriver new.
self setUpDriver: driver.
driver class: self classToConvertTemporaryToInstanceVariable selector: #doAction1 variable: 'temp'.

driver runRefactoring.

self assert: driver refactoring changes changes size equals: 2.

]
2 changes: 1 addition & 1 deletion src/Refactoring-UI/ReBrowseMethodChoice.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ ReBrowseMethodChoice >> action [
{ #category : 'accessing' }
ReBrowseMethodChoice >> description [

^ 'Browse the method(s)'
^ 'Browse the method'
]
19 changes: 19 additions & 0 deletions src/Refactoring-UI/ReBrowseMethodsChoice.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Class {
#name : 'ReBrowseMethodsChoice',
#superclass : 'ReMethodChoice',
#category : 'Refactoring-UI-Choices',
#package : 'Refactoring-UI',
#tag : 'Choices'
}

{ #category : 'accessing' }
ReBrowseMethodsChoice >> action [

driver browseMethods
]

{ #category : 'accessing' }
ReBrowseMethodsChoice >> description [

^ description ifNil: [ description := 'Browse the methods' ]
]
Loading