From VisualWorks®, 7.6 of February 8, 2008 on March 3, 2008 at 9:43:21 pm (Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned. Choose terminate or close.'] <class> <name>Refactoring</name> <environment>Refactory.Browser</environment> <super>Core.Object</super> <private>false</private> none model options methodClass <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.Refactoring
Refactoring is the abstract superclass of all the refactorings in the system. A refactoring is a behavior-preserving source-to-source transformation. Every refactoring has a set of preconditions that must be met for the refactoring to be legally applied. Several refactorings require additional information from the user. The options dictionary allows this information to either be obtained from the user, or be client-specified, depending upon the block stored in a particular named option. Subclasses must implement the following messages: preconditions preconditions transforming transform Instance Variables: methodClass <RBAbstractClass> The class of the method currently being transformed. This is kind of ugly, but allows communication between the refactoring and the rewriter. model <RBRootNamespace> The model to perform the refactoring against. options <Dictionary key: Symbol value: BlockClosure> Dictinoary of named options. The value of each option is obtained at runtime by evaluating the corresponding block. Shared Variables: RefactoringsOptions <Dictionary key: Symbol value: BlockClosure> the default options for the options instance variable
</comment> <class> <name>MethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.Refactoring</super> <private>false</private> none class <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.MethodRefactoring
MethodRefactoring is the abstract superclass of all refactorings that operate on an entire method. Instance Variables: class <RBAbstractClass> The class that contains the method to refactor.
</comment> <class> <name>PushUpMethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none removeDuplicates selectors <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.PushUpMethodRefactoring
PushUpMethodRefactoring removes a set of methods from a class and defines them in the superclass. Instance Variables: removeDuplicates <Boolean> If true, we removed duplicated methods from the subclasses. selectors <(Collection of: Symbol)> Set of methods to push up.
</comment> <class> <name>VariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.Refactoring</super> <private>false</private> none class variableName <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.VariableRefactoring
VariableRefactoring is the abstract superclass of refactorings that manipulate variables. Instance Variables: class <RBAbstractClass> The class containing the variable to refactor. variableName <String> The name of the variable to refactor.
</comment> <class> <name>RenameInstanceVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.VariableRefactoring</super> <private>false</private> none newName <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RenameInstanceVariableRefactoring
RenameInstanceVariableRefactoring renames an instance variable and updates all references. Instance Variables: newName <String> The new name of the instance variable
</comment> <class> <name>RBProgramItem</name> <environment>Refactory.Browser</environment> <super>Core.Object</super> <private>false</private> none isPrivate name environment parcels binding <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBProgramItem
RBProgramItem is the abstract superclass of all of the classes in the RB's model of the system. This model is maniuplated by the Refactorings instead of the system. When this model is manipulated, it generates a CompositeChangeObject. When this ChangeObject is executed, it changes the system to match the model. Subclasses must implement the following messages: private basicRemove Instance Variables: category <Symbol> The category/protocol that this object resides in. environment <RBNamespace> The namespace that contains this object. isPrivate <Boolean> True if this object is private to its containing namespace. name <String> The name of the object. parcels <Collection of: Parcel> The parcels that contain this object. realItem <BlockClosure | DeferredBinding | VariableBinding | nil> The system object (if any) that this model object represents.
</comment> <class> <name>RBBasicNameSpace</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBProgramItem</super> <private>false</private> none removedItems items imports <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBBasicNameSpace
RBBasicNamespace is the abstract superclass of all of the Namespace-like entities in the RB's model of the system. Subclasses must implement the following messages: private recompileObject Instance Variables: imports <(Collection of: NameSpaceImport)> Namespaces imported by this namespace. items <Dictionary> Things added to the model that aren't in the real system. removedItems <Collection> Things removed from the model that are in the real system.
</comment> <class> <name>RBAbstractClass</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBBasicNameSpace</super> <private>false</private> none newMethods instanceVariableNames superclass subclasses removedMethods <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBAbstractClass
RBAbstractClass is an abstract class. It represents classes in the system. Refactorings operate on these objects, producing change objects. These change objects are then performed on the real code. Subclasses must implement the following messages: accessing metaclass nonMetaclass testing isAbstract isMeta Instance Variables: instanceVariableNames <SequenceableCollection of: String> instance variables that the class defines newMethods <Dictionary of: RBMethod> methods that have been added to the class removedMethods <Collection of: Symbol> method names that have been removed subclasses <Collection of: RBAbstractClass> my subclasses superclass <RBAbstractClass> the superclass (or LookupSuperclass if we haven't assigned it yet). Class Variables: LookupSuperclass <Object> a special object denoting that our superclass hasn't been assigned yet
</comment> <class> <name>ChangeMethodNameRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none newSelector oldSelector permutation implementors <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.ChangeMethodNameRefactoring
ChangeMethodNameRefactoring is the abstract superclass of all refactorings that change a method name somehow. Therefore, all references to the method must be updated. Note that since we can't distinguish between method sends, we must transform _all_ implementors of the method. Subclasses must implement the following messages: preconditions myConditions Returns the Condition object that must be satisfied for the refactoring to be valid. Instance Variables: implementors <(Collection of: RBAbstractClass)> All of the classes that implement this method. newSelector <Symbol> The selector to be changed to. oldSelector <Symbol> The original selector. permutation <(SequenceableCollection of: Integer)> The permutation of the original argument list to the new argument list.
</comment> <class> <name>RenameMethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.ChangeMethodNameRefactoring</super> <private>false</private> none hasPermutedArguments <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RenameMethodRefactoring
RenameMethodRefactoring renames a method and updates all selectors in the image. Note that this will rename ALL implementors of a selector, thus preserving behavior. Also note that this will rename all symbols in the image matching the selector. Instance Variables: hasPermutedArguments <Boolean> True if the arguments occur in a different order after the rename.
</comment> <class> <name>TemporaryToInstanceVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selector temporaryVariableName <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.TemporaryToInstanceVariableRefactoring
TemporaryToInstanceVariableRefactoring promotes a temporary of a method to an instance variable of the containing class. This is usually performed in the context of a Method Object refactoring to eliminate a large, complex method. Instance Variables: selector <Symbol> Name of the method containing the temporary variable. temporaryVariableName <String> The name of the variable to convert.
</comment> <class> <name>AbstractInstanceVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.VariableRefactoring</super> <private>false</private> none accessorsRefactoring <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.AbstractInstanceVariableRefactoring
AbstractInstanceVariableRefactoring is the refactoring that 1) creates accessors for the instance variable if they don't exist and 2) replaces all direct references to the instance variable will calls to either the setter or getter. It uses the CreateAccessorsForVariableRefactoring as a component. Instance Variables: accessorsRefactoring <CreateAccessorsForVariableRefactoring> The component refactoring that creates the accessors.
</comment> <class> <name>RefactoryTyper</name> <environment>Refactory.Browser</environment> <super>Core.Object</super> <private>false</private> none model class variableTypes bestGuesses variableMessages backpointers methodName selectorLookup <imports></imports> <category>Browser-Support</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RefactoryTyper
RefactoryTyper can figure of types of variables based on the set of messages sent to them. This is used to suggest classes in the move method refactoring and to generate the default comment for uncommented classes. Instance Variables: backpointers <Dictionary> a pointer from variables and methods to the methods that return them (e.g., if a method return a variable, then there will be a variable -> method link). bestGuesses <Dictionary> the best guesses for the variable types class <RBAbstractClass> the class we are performing the type analysis on methodName <Symbol> the name of the method we are currently looking at model <RBRootNamespace> the model we are performing type analysis on selectorLookup <Dictionary> map from selectors to classes that implement the selector variableMessages <Dictionary> the messages sent to each variable variableTypes <Dictionary> the possible variable types
</comment> <class> <name>InlineMethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none sourceInterval inlineParseTree sourceSelector sourceMessage inlineClass sourceTree <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.InlineMethodRefactoring
InlineMethodRefactoring replaces a call to a method by body of that method. This is often used to get rid of forwarding methods left behind from earlier refactorings. Instance Variables: inlineClass <RBAbstractClass> The class that contains the method to inline. inlineParseTree <RBMethodNode> The parse tree of the method to inline. sourceInterval <Interval> The interval into the original source of the call to inline. sourceMessage <RBProgramNode> The subtree of the call to inline. sourceTree <RBMethodNode> The parse tree of the method containing the call to inline. sourceSelector <Symbol> The selector of the method containing the call to inline.
</comment> <class> <name>InlineMethodFromComponentRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.InlineMethodRefactoring</super> <private>false</private> none <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.InlineMethodFromComponentRefactoring
InlineMethodFromComponentRefactoring inlines the body of a method of another class.
</comment> <class> <name>RBAbstractCondition</name> <environment>Refactory.Browser</environment> <super>Core.Object</super> <private>false</private> none errorMacro <imports></imports> <category>Browser-Conditions</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBAbstractCondition
RBAbstractCondition is an abstract class. It represents a precondition that is used whenever a Refactoring is performed. All preconditions must evaluate successfully in order for the Refactoring to be performed. Subclasses must implement the following messages: checking check Instance Variables: errorMacro <String> the error string that is used when the condition fails
</comment> <class> <name>ExpandNameSpaceReferencesRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.Refactoring</super> <private>false</private> none fromClass toClasses referencedVars parseTree <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.ExpandNameSpaceReferencesRefactoring
ExpandNamespaceReferenceRefactoring is a refactoring that expands a Namespaces's scope for a method that is being moved from one class to another. This refactoring is primarily used to support other, more complicated refactorings such as MoveMethod. Instance Variables: fromClass <RBClass> The class that the method is being moved from. parseTree <RBProgramNode> The method whose pool references need to be expanded. referencedVars <Collection of: Symbol> The collection of Namespace References in parseTree. toClasses <Collection of: RBClass> The classes into which the pools must be expanded.
</comment> <class> <name>AddInstanceVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.VariableRefactoring</super> <private>false</private> none <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.AddInstanceVariableRefactoring
AddInstanceVariableRefactoring adds an unreferenced instance variable to a class.
</comment> <class> <name>RemoveInstanceVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.VariableRefactoring</super> <private>false</private> none <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RemoveInstanceVariableRefactoring
RemoveInstanceVariableRefactoring removes an instance variable if it is unreferenced.
</comment> <class> <name>RemoveParameterRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.ChangeMethodNameRefactoring</super> <private>false</private> none parameterIndex argument <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RemoveParameterRefactoring
RemoveParameterRefactoring removes an unreferenced parameter from a method signature (and updates all calls). Instance Variables: argument <String> The name of the argument to remove. parameterIndex <Integer> The position of the parameter in the parameter list.
</comment> <class> <name>InlineParameterRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RemoveParameterRefactoring</super> <private>false</private> none expressions <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.InlineParameterRefactoring
InlineParameterRefactoring removes a parameter from a method and replaces it with a temporary in the body of the method and an assignment if every call to the method assigns the same, constant value to the parameter. Instance Variables: expressions <(SequenceableCollection of: RBProgramNode)> All expressions assigned to the parameter.
</comment> <class> <name>PullUpInstanceVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.VariableRefactoring</super> <private>false</private> none <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.PullUpInstanceVariableRefactoring
PullUpInstanceVariableRefactoring removes an instance variable from all subclasses that define it and defines it in the superclass.
</comment> <class> <name>AddParameterRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.ChangeMethodNameRefactoring</super> <private>false</private> none initializer <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.AddParameterRefactoring
AddParameterRefactoring adds a parameter to a method. All calls to the method are updated with the additional parameter with the value of initializer. Instance Variables: initializer <String> Default value of new parameter.
</comment> <class> <name>ClassRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.Refactoring</super> <private>false</private> none className <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.ClassRefactoring
ClassRefactoring is the abstract superclass of all refactorings that create new classes (or globals). Instance Variables: className <String> Name of the new class.
</comment> <class> <name>AddClassRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.ClassRefactoring</super> <private>false</private> none superclass subclasses <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.AddClassRefactoring
AddClassRefactoring adds an unreferenced class. This can be used to insert an empty class into the middle of the hierarchy. Instance Variables: category <Symbol> Category of the new class. subclasses <(Collection of: RBClass)> Existing classes that are to be subclasses of the new class. Note: These must be subclasses of superclass. superclass <RBClass> The (existing) superclass of the new class.
</comment> <class> <name>RBNameSpace</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBBasicNameSpace</super> <private>false</private> none <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBNameSpace
RBNamespace is the RB's models representation of a Namespace.
</comment> <class> <name>Condition</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBAbstractCondition</super> <private>false</private> none block type errorBlock <imports></imports> <category>Browser-Conditions</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.Condition
Condition represents a condition that must be true for a refactoring to be performed. Instance Variables: block <BlockClosure> this is the block that gets evaluated to check the condition errorBlock <BlockClosure | nil> if not nil, this is a block that if the condition fails, will produce some means of browsing the failure (such as opening a browser on the failures) type <Array> This array holds a symbol identifying the type of condition this is along with its parameters. Right now this is pretty useless, other than for printing, but in the future, we hope to be able to use this to assert postconditions of refactorings.
</comment> <class> <name>RBNegationCondition</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBAbstractCondition</super> <private>false</private> none condition <imports></imports> <category>Browser-Conditions</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBNegationCondition
NegationCondition represents negating another condition. Instance Variables: condition <RBAbstractCondition> the condition that is to be negated
</comment> <class> <name>ChildrenToSiblingsRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.ClassRefactoring</super> <private>false</private> none parent subclasses <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.ChildrenToSiblingsRefactoring
ChildrenToSiblingsRefactoring converts a concrete superclass with concrete subclasses into an abstract superclass with all concrete subclasses. This refactoring creates the new superclass, rearranges the hierarchy, and moves the formerly inherited methods and instance variables into the new abstract class. Instance Variables: parent <RBAbstractClass> Original concrete superclass subclasses <(Collection of: RBAbstractClass)> Subclasses of parent which are to become it's siblings.
</comment> <class> <name>RefactoringManager</name> <environment>Refactory.Browser</environment> <super>Core.Object</super> <private>false</private> none refactorings <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RefactoringManager
RefactoringManager is a singleton that keeps track of all refactoring performed. This currently doesn't do a whole lot. In the future, it could be used to implement non-linear undo. See Don Roberts Ph.D. thesis for details. Instance Variables: refactorings <OrderedCollection of: Refactorings> Refactorings performed in this system. Shared Variables: Instance <RefactoringManager> our sole instance
</comment> <class> <name>ExtractToTemporaryRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none sourceInterval selector newVariableName sourceTree <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.ExtractToTemporaryRefactoring
ExtractToTemporaryRefactoring extracts a portion of code and assigns it to a new temporary variable. Instance Variables: newVariableName <String> The name of the new temporary. sourceTree <RBProgramNode> Parse tree to modify. selector <Symbol> Selector of the method to modify. sourceInterval <Interval> Interval into the original source to extract.
</comment> <class> <name>CreateAccessorsForVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.VariableRefactoring</super> <private>false</private> none getterMethod setterMethod needsReturn <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.CreateAccessorsForVariableRefactoring
CreateAccessorsForVariableRefactoring creates simple accessors for an instance variable. If a simple accessor already exists (regardless of the name of the method), it does nothing. If a method name already exists that matches the instance variable name, a unique name is generated by appending a number. Instance Variables: getterMethod <Symbol> Selector of the getter method setterMethod <Symbol> Selector of the setter method needsReturn <Boolean> True if the generated setter needs a return (an assignment was used as an rvalue somewhere).
</comment> <class> <name>RBMethod</name> <environment>Refactory.Browser</environment> <super>Core.Object</super> <private>false</private> none class compiledMethod source selector parcels <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBMethod
RBMethod is the RB's model's representation of a method. Instance Variables: class <RBAbstractClass> The class containing this method compiledMethod <CompiledCode> The compiled form of this method. parcels <Collection of: Parcel> The parcels to which this method belongs. selector <Symbol> This method's selector. source <String> The source code of the method.
</comment> <class> <name>RBInitializerMethod</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBMethod</super> <private>false</private> none sharedVariable <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBInitializerMethod
RBInitializerMethod is the RB's model's representation of an initializer method for a Shared Variable. Instance Variables: sharedVariable <RBSharedVariable> The shared variable for which we are the initializer.
</comment> <class> <name>PushDownInstanceVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.VariableRefactoring</super> <private>false</private> none <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.PushDownInstanceVariableRefactoring
PushDownInstanceVariableRefactoring removes and instance variable from a class and defines in only those subclasses that reference it.
</comment> <class> <name>CompositeRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.Refactoring</super> <private>false</private> none refactorings <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.CompositeRefactoring
CompositeRefactoring is a refactoring that is composed of smaller refactorings. Since each step is supposed to be behavior-preserving, the composition is behavior-preserving. Instance Variables: refactorings <(SequenceableCollection of: Refactoring)> The refactorings that comprise this one.
</comment> <class> <name>RenameTemporaryRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selector interval oldName newName sourceTree <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RenameTemporaryRefactoring
RenameTemporaryRefactoring renames a temporary variable within a method. Instance Variables: interval <Interval> The selection within the code of the variable to rename. newName <String> New name for the variable. oldName <String> Original name for the variable. selector <Symbol> The selector of the method containing the variable to be renamed. sourceTree <ProgramNode> parse tree of method to rewrite
</comment> <class> <name>RBMetaclass</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBAbstractClass</super> <private>false</private> none nonMetaclass <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBMetaclass
RBMetaclass is the RB's model's representation of a metaclass. Instance Variables: nonMetaclass <RBClass> Our class
</comment> <class> <name>ExtractMethodToComponentRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selector extractionInterval extractedMethodSelector sourceTree <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.ExtractMethodToComponentRefactoring
ExtractMethodToComponentRefactoring is a composite refactoring that extracts a portion of code from a method and creates a method implementing that code on a class that the original class has a reference to either through an instance variable or a temporary variable. Instance Variables: extractedMethodSelector <Symbol> Name of the extracted method. extractionInterval <Interval> Interval within the original source to extract. selector <Symbol> Selector to extract code from. parseTree <ProgramNode> the parse tree of the method being worked on, may be preset by clients
</comment> <class> <name>ProtectInstanceVariableRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.VariableRefactoring</super> <private>false</private> none <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.ProtectInstanceVariableRefactoring
ProtectInstanceVariableRefactoring is the opposite of AbstractInstancVariableRefactoring. It replaces all self calls to accessors with direct references to the variable. If there are no more senders of the accessors, they are removed.
</comment> <class> <name>ExtractMethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selector extractionInterval extractedParseTree modifiedParseTree parameters needsReturn sourceTree <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.ExtractMethodRefactoring
ExtractMethodRefactoring extracts a portion of code as a new method. Don't try to understand it. John is afraid of it. It works for nearly all cases. Instance Variables: sourceTree <RBProgramNode> the source parse tree, can be set by clients, or will be lazily cached from class/selector extractedParseTree <RBProgramNode> The subtree of the parse tree to extract. extractionInterval <Interval> The interval within the original source code of the text to extract. modifiedParseTree <RBProgramNode> The resulting parse tree of the original method after the extraction. needsReturn <Boolean> True if the extracted method is used as an rvalue. parameters <Collection of: String> Parameters that must be passed to extracted method. selector <Symbol> Name of the extracted method.
</comment> <class> <name>MoveVariableDefinitionRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selector interval name sourceTree blockNodes definingNode <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.MoveVariableDefinitionRefactoring
MoveVariableDefinitionRefactoring moves the definition of a temporary within a method into the tightest-binding scope. Instance Variables: blockNodes <(Collection of: RBBlockNode)> The set of block nodes that will get the new definition. definingNode <RBSequenceNode> The node that currently defines the variable. interval <Interval> The interval into the source code of the original variable definition name <String> The name of the variable to move sourceTree <RBProgramNode> The parse tree of the method to transform. selector <Symbol> The name of the method to transform
</comment> <class> <name>RBSharedVariable</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBProgramItem</super> <private>false</private> none initializer constant category <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBSharedVariable
RBSharedVariable is the RB's model's representation of shared variables. Instance Variables: constant <Boolean> True if the shared variable is constant. initializer <RBInitializerMethod> The initialization code for the variable.
</comment> <class> <name>RBRootNameSpace</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBNameSpace</super> <private>false</private> none implementorsCache sendersCache changes rootClasses <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBRootNameSpace
RBRootNamespace is the RB's model's representation of the system's Root namespace. This also holds the changes that the model's manipulation has generated and the cached results of senders and implementors queries. Instance Variables: changes <RefactoryChange> The change that has been generated by the manipulation of the model. implementorsCache <Dictionary key: Symbol value: (Set of: RBAbstractClass)> Mapping from selectors to the classes that implement that selector. sendersCache <Dictionary key: Symbol value: (Set of: RBMethod) > Mapping from selectors to the methods that refer to that selector. rootClasses <Collection of: RBAbstractClass> Classes stored in the Root namespace.
</comment> <class> <name>RBClass</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBAbstractClass</super> <private>false</private> none metaclass indexedType <imports></imports> <category>Browser-Model</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBClass
RBClass is RB's model's representation of a class. Instance Variables: indexedType <ByteSymbol> Type of indexing for this class. metaclass <RBAbstractClass> The model's metaclass for this class.
</comment> <class> <name>MoveObjectRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.Refactoring</super> <private>false</private> none object targetScope originalScope referencesTo fromReferences <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.MoveObjectRefactoring
I move an object (class, namespace) from it's current scope to another. There are basically two parts to this refactoring, aside from the actual move. When the object is moved, we must look at all references to it and determine what changes need to be made to them. We call these "to" references. We also have to consider everything that the object itself references, and consider whether they need to be adjusted to accomodate the new home of the object. We call these "from" references. An additional term that shows up in this work is the term "outer referencing variable". This is basically what we used to call "globals". It is a reference to any namespace, class, or share. Or otherwords, any thing that is above the scope of an instance variable. Instance Variables: targetScope <RBProgramItem> the namespace we're moving to originalScope <RBProgramItem> the namespace we moved from, captured when the object is set object <RBProgramItem> The model object that is being relocated.
</comment> <class> <name>RemoveMethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selectors <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RemoveMethodRefactoring
RemoveMethodRefactoring removes a set of methods if they are not called. If there are any calls to any of the selectors, the refactoring fails. Instance Variables: selectors <(Collection of: Symbol)> The selectors of the methods to remove
</comment> <class> <name>RefactoringError</name> <environment>Refactory.Browser</environment> <super>Core.Error</super> <private>false</private> none <imports></imports> <category>Browser-Support</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RefactoringError
RefactoringError is signaled whenever a refactoring's precondition is violated.
</comment> <class> <name>PushDownMethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selectors <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.PushDownMethodRefactoring
PushDownMethodRefactoring moves a set of methods from a class into all of its subclasses. This can only be done if the original class is abstract and there are no self sends of the method in that class. This takes a set of selectors since sometimes a group should be in a subclass, but they all refer to each other. Instance Variables: selectors <(Collection of: Symbol)> Selectors to push down
</comment> <class> <name>AbstractVariablesRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.Refactoring</super> <private>false</private> none tree fromClass instVarReaders instVarWriters toClasses ignore sharedVariableReaders sharedVariableWriters <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.AbstractVariablesRefactoring
AbstractVariablesRefactoring modifies a parse tree to replace all references to variables that don't exist in the scope of toClasses but did exist in fromClass. This allows the parse tree to be moved into toClasses. Instance Variables: fromClass <RBAbstractClass> The class that the parseTree current resides in. ignore <String> The name of a variable to ignore during the transformation. instVarReaders <Set of: String> Instance variables read by parse tree. instVarWriters <Set of: String> Instance variables written parse tree. sharedVariableReaders <Set of: String> Shared Variables read by parse tree. sharedVariableWriters <Set of: String> Shared Variables written by parse tree. toClasses <Collection or: RBAbstractClass> Classes whose scopes the parse tree must be transformed to exist within. tree <RBProgramNode> ParseTree to transform
</comment> <class> <name>RBMethodName</name> <environment>Refactory.Browser</environment> <super>Core.Object</super> <private>false</private> none selector arguments <imports></imports> <category>Browser-Support</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBMethodName
RBMethodName is a first-class representation of the name of a method along with its arguments. Instance Variables: arguments <OrderedCollection of: RBProgramNode> The arguments to the method. selector <Symbol> The name of the method.
</comment> <class> <name>MoveMethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selector variable moveToClasses parseTree hasOnlySelfReturns selfVariableName <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.MoveMethodRefactoring
MoveMethodRefactoring moves a method from one class to another. The original class must have a reference to the new class. The original method is then replaced with a forwarding call to the new method. This maintains the interface of the original class. To eliminate the forwarder, you can use the inline method refactoring. Instance Variables: hasOnlySelfReturns <Boolean> True if the method to be moved only returns self. moveToClasses <(Collection of: RBAbstractClass)> The set of classes that method will be moved to. parseTree <RBMethodNode> The parse tree of the method being moved. selector <Symbol> The name of the method being moved. selfVariableName <String> The name of the parameter used to pass the original 'self' into the moved method. variable <String> The variable from the original method's scope that contains the reference to the class that we are moving the method to.
</comment> <class> <name>RBConjunctiveCondition</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.RBAbstractCondition</super> <private>false</private> none left right failed <imports></imports> <category>Browser-Conditions</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RBConjunctiveCondition
ConjunctiveCondition represents and-ing two AbstractConditions together. Instance Variables: failed <Symbol> which condition failed (#leftFailed, #rightFailed, or #unknownFailed) left <RBAbstractCondition> the condition on the left side of the and right <RBAbstractCondition> the condition on the right side of the and
</comment> <class> <name>AddMethodRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none protocols source <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.AddMethodRefactoring
AddMethodRefactoring adds a new method to a class Instance Variables: protocols <Collection of: SYmbol> Protocols to compile method into. source <String> Method source code
</comment> <class> <name>RenameObjectRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.ClassRefactoring</super> <private>false</private> none newName object <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RenameObjectRefactoring
RenameObjectRefactoring changes the name of a global object (class, shared var., etc.) and updates all references. It also updates all symbols that match the original name. Instance Variables: newName <String> Name to rename to. object <RBAbstractClass> The model object that is being renamed.
</comment> <class> <name>InlineAllSelfSendersRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none selector numberReplaced numberNotReplaced <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.InlineAllSelfSendersRefactoring
InlineAllSelfSendersRefactoring this composite refactoring inlines all self sends of a method. If, after the inlining, there are no references to the method, it is removed. Instance Variables: numberNotReplaced <ArithmeticValue> Number of sends not inlined. numberReplaced <ArithmeticValue> Number of send inlined. selector <Symbol> Selector of method to inline.
</comment> <class> <name>InlineTemporaryRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.MethodRefactoring</super> <private>false</private> none sourceInterval selector sourceTree assignmentNode definingNode <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.InlineTemporaryRefactoring
InlineTemporaryRefactoring replaces all references to a singly-assigned temporary with the right-hand side of that assignment. Instance Variables: assignmentNode <RBAssignmentNode> The assignment statement to inline. definingNode <RBSequenceNode> The sequence node that defines the variable that we are inlining away. selector <Symbol> The selector of the method to transform. sourceInterval <Interval> The interval into the original source of the code to inline. sourceTree <RBProgramNode> Parse tree of the method to transform.
</comment> <class> <name>RemoveObjectRefactoring</name> <environment>Refactory.Browser</environment> <super>Refactory.Browser.Refactoring</super> <private>false</private> none objectNames <imports></imports> <category>Browser-Refactorings</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RemoveObjectRefactoring
RemoveObjectRefactoring removes unreferenced global objects (classes, shared vars, etc.). It can also remove empty classes from the middle of hierarchies, reparenting all of its children. Instance Variables: objectNames <(Collection of: String)> Names of the objects to remove.
</comment> <class> <name>RefactoringWarning</name> <environment>Refactory.Browser</environment> <super>Core.Exception</super> <private>false</private> none <imports></imports> <category>Browser-Support</category> <attributes> <package>Browser-Refactorings</package> </attributes> </class> <comment> Refactory.Browser.RefactoringWarning
RefactoringWarning is a non-fatal warning that usually requires the user to validate. This is used in situations where either the behavior of the program will not be strictly preserved or the change may have a wider impact than the user may think.
</comment> <name>LookupSuperclass</name> <environment>Refactory.Browser.RBAbstractClass</environment> <private>false</private> <constant>false</constant> <category>private-statics</category> <initializer>Core.Object new</initializer> <attributes> <package>Browser-Refactorings</package> </attributes> <name>Instance</name> <environment>Refactory.Browser.RefactoringManager</environment> <private>false</private> <constant>false</constant> <category>As yet unclassified</category> <attributes> <package>Browser-Refactorings</package> </attributes> <name>RefactoringOptions</name> <environment>Refactory.Browser.Refactoring</environment> <private>false</private> <constant>false</constant> <category>As yet unclassified</category> <attributes> <package>Browser-Refactorings</package> </attributes> <methods> Refactory.Browser.Refactoring <category>testing</category>
canReferenceVariable: aString in: aClass ^(aClass referencedItem: aString) notNil or: [aClass definesInstanceVariable: aString]
</methods> <methods> Refactory.Browser.Refactoring <category>accessing</category>
changes ^self model changes
copyOptionsFrom: aDictionary | dict | dict := self options. dict == self class refactoringOptions ifTrue: [^self options: aDictionary copy]. dict keysAndValuesDo: [:key :value | value == (self class refactoringOptions at: key) ifTrue: [dict at: key put: (aDictionary at: key)]]. self options: dict
options ^options isNil ifTrue: [self class refactoringOptions] ifFalse: [options]
options: aDictionary options := aDictionary
setOption: aSymbol toUse: aBlock | dict | dict := self options. dict == self class refactoringOptions ifTrue: [dict := dict copy]. dict at: aSymbol put: aBlock. self options: dict
</methods> <methods> Refactory.Browser.Refactoring <category>support</category>
checkClass: aRBClass selector: aSelector using: aMatcher | parseTree | parseTree := aRBClass parseTreeFor: aSelector. parseTree notNil ifTrue: [aMatcher executeTree: parseTree]. ^aMatcher answer
convertAllReferencesTo: aSymbol using: searchReplacer self model allReferencesTo: aSymbol do: [:method | self convertMethod: method using: searchReplacer]
convertAllReferencesToObject: aRBProgramItem using: searchReplacer self model allReferencesToObject: aRBProgramItem do: [:method | self convertMethod: method using: searchReplacer]
convertClasses: classSet select: aBlock using: searchReplacer classSet do: [:aClass | (aBlock value: aClass) do: [:selector | self convertMethod: (aClass methodFor: selector) using: searchReplacer]]
convertMethod: aMethod using: searchReplacer "Convert the parse tree for selector using the searchReplacer. If a change is made then compile it into the changeBuilder." | parseTree | methodClass := aMethod modelClass. parseTree := aMethod parseTree. parseTree isNil ifTrue: [methodClass := nil. ^self]. (searchReplacer executeTree: parseTree) ifTrue: [aMethod compileTree: searchReplacer tree]. methodClass := nil
</methods> <methods> Refactory.Browser.Refactoring <category>preconditions</category>
checkPreconditions | conditions block | conditions := self preconditions. conditions check ifFalse: [block := conditions errorBlock. block notNil ifTrue: [self refactoringError: conditions errorString with: block] ifFalse: [self refactoringError: conditions errorString]]
preconditions self subclassResponsibility
</methods> <methods> Refactory.Browser.Refactoring <category>private</category>
classObjectFor: anObject anObject isBehavior ifTrue: [^self model classFor: anObject]. anObject isString ifTrue: [^self model classNamed: anObject]. ^anObject
methodClass ^methodClass
onError: aBlock do: errorBlock ^aBlock on: self class preconditionSignal do: [:ex | errorBlock value. ex return: nil]
primitiveExecute self checkPreconditions. self transform
refactoringError: aString RefactoringError raiseSignal: aString
refactoringError: aString with: aBlock RefactoringError raiseSignal: aString with: aBlock
refactoringWarning: aString RefactoringWarning raiseSignal: aString
uniqueMethodNameFor: anInteger | before after index name | before := 'a'. after := ''. anInteger timesRepeat: [after := after , 'z:']. index := 0. [name := before , index printString , after. (Symbol findInterned: name) notNil] whileTrue: [index := index + 1]. ^name asSymbol
</methods> <methods> Refactory.Browser.Refactoring <category>transforming</category>
execute self primitiveExecute. RefactoringManager instance addRefactoring: self
model ^model isNil ifTrue: [model := (RBRootNameSpace new) description: self printString; yourself] ifFalse: [model]
performComponentRefactoring: aRefactoring aRefactoring copyOptionsFrom: self options. aRefactoring primitiveExecute
transform self subclassResponsibility
</methods> <methods> Refactory.Browser.Refactoring <category>initialize-release</category>
initialize
model: aRBNameSpace model := aRBNameSpace
</methods> <methods> Refactory.Browser.Refactoring <category>requests</category>
methodForExpandingScopeOf: aVar ^(self options at: #sharedVariableScopeExpansion) value: self value: aVar
openBrowserOn: anEnvironment ^(self options at: #openBrowser) value: self value: anEnvironment
requestImplementorToInline: implementorsCollection ^(self options at: #implementorToInline) value: self value: implementorsCollection
requestMethodNameFor: aMethodName ^(self options at: #methodName) value: self value: aMethodName
requestSelfArgumentName ^(self options at: #selfArgumentName) value: self
selectVariableToMoveMethodTo: aSelector class: aClass ^(self options at: #selectVariableToMoveTo) value: self value: aClass value: aSelector
selectVariableTypesFrom: initialTypeCollection selected: selectedTypeCollection ^(self options at: #variableTypes) value: self value: initialTypeCollection value: selectedTypeCollection
shouldExtractAssignmentTo: aString ^(self options at: #extractAssignment) value: self value: aString
shouldInlineExpression: aString ^(self options at: #inlineExpression) value: self value: aString
shouldOverride: aSelector in: aClass ^(self options at: #alreadyDefined) value: self value: aClass value: aSelector
shouldUseExistingMethod: aSelector ^(self options at: #useExistingMethod) value: self value: aSelector
</methods> <methods> Refactory.Browser.Refactoring <category>printing</category>
printOn: aStream aStream nextPutAll: (self class name first isVowel ifTrue: ['an '] ifFalse: ['a ']); nextPutAll: self class name
</methods> <methods> Refactory.Browser.Refactoring <category>transforming-class/namespace names</category>
replaceFullReferenceTo: aRBProgramItem inVariable: aNode toBe: aString | path nameStream | path := self replaceReferenceTo: aRBProgramItem inPath: ((aNode name tokensBasedOn: $.) collect: [:each | each asSymbol]) toBe: aString. nameStream := WriteStream on: String new. path do: [:each | nameStream nextPutAll: each] separatedBy: [nameStream nextPut: $.]. ^RBVariableNode named: nameStream contents
replaceReferenceTo: aRBProgramItem inPath: path toBe: aString | newPath index nameStream | newPath := path copy. index := path size + 1. [index := path prevIndexOf: aRBProgramItem name from: index - 1 to: 1. index notNil] whileTrue: [nameStream := WriteStream on: String new. (1 to: index) do: [:i | nameStream nextPutAll: (path at: i)] separatedBy: [nameStream nextPut: $.]. (self methodClass referencedItem: nameStream contents) == aRBProgramItem ifTrue: [newPath at: index put: aString]]. ^newPath
</methods> <methods> Refactory.Browser.Refactoring <category>utilities</category>
checkInstanceVariableName: aName in: aClass ^Condition checkInstanceVariableName: aName in: aClass
checkMethodName: aName in: aClass ^Condition checkMethodName: aName in: aClass
safeMethodNameFor: aClass basedOn: aString "Creates an unused method name containing aString" | baseString newString hasParam i | baseString := aString copy. baseString at: 1 put: baseString first asLowercase. newString := baseString. hasParam := newString last = $:. hasParam ifTrue: [baseString := newString copyFrom: 1 to: newString size - 1]. i := 0. [aClass hierarchyDefinesMethod: newString asSymbol] whileTrue: [i := i + 1. newString := baseString , i printString , (hasParam ifTrue: [':'] ifFalse: [''])]. ^newString asSymbol
whichVariableNode: aParseTree inInterval: anInterval name: aName | matcher block | matcher := ParseTreeSearcher new. block := [:aNode :answer | (aNode intersectsInterval: anInterval) ifTrue: [aNode] ifFalse: [answer]]. matcher matches: aName do: block; matchesArgument: aName do: block. ^matcher executeTree: aParseTree initialAnswer: nil
</methods> <methods> Refactory.Browser.Refactoring class <category>instance creation</category>
new ^(super new) initialize; yourself
</methods> <methods> Refactory.Browser.Refactoring class <category>accessing signal</category>
preconditionSignal ^RefactoringError , RefactoringWarning
</methods> <methods> Refactory.Browser.Refactoring class <category>accessing</category>
refactoringOptions RefactoringOptions isNil ifTrue: [self initializeRefactoringOptions]. ^RefactoringOptions
setDefaultOption: aSymbol to: aBlock self refactoringOptions at: aSymbol put: aBlock
</methods> <methods> Refactory.Browser.MethodRefactoring <category>private</category>
buildSelectorString: aSelector aSelector numArgs = 0 ifTrue: [^aSelector]. ^self buildSelectorString: aSelector withPermuteMap: (1 to: aSelector numArgs)
buildSelectorString: aSelector withPermuteMap: anIntegerCollection | stream keywords | aSelector numArgs == 0 ifTrue: [^aSelector asString]. stream := WriteStream on: String new. keywords := aSelector keywords. keywords with: anIntegerCollection do: [:each :i | stream nextPutAll: each; nextPutAll: ' ``@arg'; nextPutAll: i printString; nextPut: $ ]. ^stream contents
</methods> <methods> Refactory.Browser.PushUpMethodRefactoring <category>preconditions</category>
checkBackReferencesTo: aSelector | definingClass pushUpParseTree | definingClass := class superclass whoDefinesMethod: aSelector. definingClass isNil ifTrue: [^self]. pushUpParseTree := class parseTreeFor: aSelector. class superclass allSubclasses do: [:each | each selectors do: [:sel | | parseTree | parseTree := each parseTreeFor: sel. (parseTree notNil and: [(parseTree superMessages includes: aSelector) and: [definingClass == (each whoDefinesMethod: aSelector)]]) ifTrue: [removeDuplicates := true. (aSelector == sel and: [parseTree equalTo: pushUpParseTree exceptForVariables: #()]) ifFalse: [self refactoringError: ((#CannotPushUpWouldOverride << #browser >> 'Cannot push up <1s> since it would override the method defined in <2p>') expandMacrosWith: aSelector with: definingClass)]]]]
checkInstVars selectors do: [:each | self checkInstVarsFor: each]
checkInstVarsFor: aSelector class instanceVariableNames do: [:each | ((class whichSelectorsReferToInstanceVariable: each) includes: aSelector) ifTrue: [self refactoringError: ((#x1sRefersTo2sDefinedIn3s << #browser >> '<1p> refers to <2s> which is defined in <3p>') expandMacrosWith: aSelector with: each with: class)]]
checkSiblingSuperSendsFrom: aRBClass selectors do: [:aSelector | (aRBClass whichMethodsReferToSymbol: aSelector) do: [:each | | tree | tree := each parseTree. tree notNil ifTrue: [(tree superMessages includes: aSelector) ifTrue: [| definer | definer := aRBClass superclass whoDefinesMethod: aSelector. (definer notNil and: [class includesClass: definer]) ifTrue: [self refactoringError: ((#CannotPushUp1sSuperSend << #browser >> 'Cannot push up <1s> since <2p>>><3s> sends a super message to it.') expandMacrosWith: aSelector with: aRBClass with: each selector)]]]]]. aRBClass allSubclasses do: [:each | self checkSiblingSuperSendsFrom: each]
checkSuperclass | overrideSelectors | overrideSelectors := selectors select: [:each | class superclass definesMethod: each]. overrideSelectors := overrideSelectors reject: [:each | | myTree superTree | myTree := class parseTreeFor: each. superTree := class superclass parseTreeFor: each. superTree equalTo: myTree exceptForVariables: #()]. overrideSelectors isEmpty ifTrue: [^self]. class superclass isAbstract ifFalse: [self refactoringError: ((#NonAbstract2pOrSuperDefine1p << #browser >> 'Non-abstract class <2p> or one of its superclasses already define <1p>') expandMacrosWith: overrideSelectors asArray first with: class superclass)]. overrideSelectors do: [:each | self checkBackReferencesTo: each]
checkSuperMessages self checkSuperSendsFromPushedUpMethods. self checkSuperSendsFromSiblings
checkSuperSendsFromPushedUpMethods selectors do: [:each | | parseTree | parseTree := class parseTreeFor: each. (parseTree superMessages anySatisfy: [:sup | class superclass directlyDefinesMethod: sup]) ifTrue: [self refactoringError: ((#CannotPushUp1sSuperSendInSuper << #browser >> 'Cannot push up <1s> since it sends a super message that is defined in the superclass.') expandMacrosWith: each)]]
checkSuperSendsFromSiblings | siblings | siblings := class superclass subclasses reject: [:each | each = class]. siblings do: [:each | self checkSiblingSuperSendsFrom: each]
preconditions ^(selectors inject: (Condition hasSuperclass: class) into: [:cond :each | cond & (Condition definesSelector: each in: class)]) & (Condition withBlock: [self checkInstVars. "self checkClassVars." self checkSuperclass. self checkSuperMessages. true])
</methods> <methods> Refactory.Browser.PushUpMethodRefactoring <category>transforming</category>
copyDownMethods selectors do: [:each | self copyDownMethod: each]
pushUp: aSelector | refactoring source | refactoring := ExpandNameSpaceReferencesRefactoring model: self model for: (class parseTreeFor: aSelector) fromClass: class toClasses: (Array with: class superclass). self performComponentRefactoring: refactoring. source := refactoring parseTree = (class parseTreeFor: aSelector) ifTrue: [class sourceCodeFor: aSelector] ifFalse: [refactoring parseTree printString]. class superclass compile: source withAttributesFrom: (class methodFor: aSelector)
pushUpMethods selectors do: [:each | self pushUp: each]
removeDuplicateMethods selectors do: [:each | self removeDuplicatesOf: each]
removeDuplicatesOf: aSelector | tree | tree := class superclass parseTreeFor: aSelector. class superclass allSubclasses do: [:each | ((each directlyDefinesMethod: aSelector) and: [(tree equalTo: (each parseTreeFor: aSelector) exceptForVariables: #()) and: [(each superclass whoDefinesMethod: aSelector) == class superclass]]) ifTrue: [removeDuplicates ifFalse: [removeDuplicates := true. self refactoringWarning: (#RemoveDuplicateSubclassMethodsQ << #browser >> 'Subclasses of the target class have duplicate copies of this method.<n>Pushing up the method will remove the copies. Proceed?') expandMacros]. each removeMethod: aSelector]]
removePushedUpMethods selectors do: [:each | class removeMethod: each]
transform self copyDownMethods; pushUpMethods; removePushedUpMethods; removeDuplicateMethods
</methods> <methods> Refactory.Browser.PushUpMethodRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Push up method refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' pushUp: '. selectors asArray storeOn: aStream. aStream nextPutAll: ' from: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.PushUpMethodRefactoring <category>initialize-release</category>
pushUp: selectorCollection from: aClass class := self classObjectFor: aClass. selectors := selectorCollection. removeDuplicates := false
</methods> <methods> Refactory.Browser.PushUpMethodRefactoring <category>private</category>
copyDownMethod: aSelector | oldSource superclassDefiner subclasses refactoring | superclassDefiner := class superclass whoDefinesMethod: aSelector. superclassDefiner isNil ifTrue: [^self]. oldSource := superclassDefiner sourceCodeFor: aSelector. oldSource isNil ifTrue: [self refactoringError: ((#SourceFor1sSuperNA << #browser >> 'Source code for <1s> superclass method not available') expandMacrosWith: aSelector)]. subclasses := class superclass subclasses reject: [:each | each directlyDefinesMethod: aSelector]. subclasses isEmpty ifTrue: [^self]. ((superclassDefiner parseTreeFor: aSelector) superMessages anySatisfy: [:each | superclassDefiner directlyDefinesMethod: each]) ifTrue: [self refactoringError: ((#CannotPushUp1sMustCopyDownAndSuperOverridden << #browser >> 'Cannot push up <1s> since we must copy down the superclass method in <2p><n>to the other subclasses, and the superclass method sends a super message which is overridden.') expandMacrosWith: aSelector with: superclassDefiner)]. self refactoringWarning: ((#CopyDownSuperMethod1s << #browser >> 'Do you want to copy down the superclass method to the classes that don''t define <1s>') expandMacrosWith: aSelector). refactoring := ExpandNameSpaceReferencesRefactoring model: self model for: (superclassDefiner parseTreeFor: aSelector) fromClass: superclassDefiner toClasses: subclasses. self performComponentRefactoring: refactoring. subclasses do: [:each | each compile: refactoring parseTree printString withAttributesFrom: (superclassDefiner methodFor: aSelector)]
</methods> <methods> Refactory.Browser.PushUpMethodRefactoring class <category>instance creation</category>
model: aRBNameSpace pushUp: selectorCollection from: aClass ^(self new) model: aRBNameSpace; pushUp: selectorCollection from: aClass; yourself
pushUp: selectorCollection from: aClass ^(self new) pushUp: selectorCollection from: aClass; yourself
</methods> <methods> Refactory.Browser.VariableRefactoring <category>printing</category>
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' variable: '. variableName storeOn: aStream. aStream nextPutAll: ' class: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.VariableRefactoring <category>initialize-release</category>
variable: aVarName class: aClass class := self classObjectFor: aClass. variableName := aVarName
</methods> <methods> Refactory.Browser.VariableRefactoring class <category>instance creation</category>
model: aRBNameSpace variable: aVarName class: aClass ^(self new) model: aRBNameSpace; variable: aVarName class: aClass; yourself
variable: aVarName class: aClass ^(self new) variable: aVarName class: aClass; yourself
</methods> <methods> Refactory.Browser.RenameInstanceVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Rename instance variable refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' rename: '''; nextPutAll: variableName; nextPutAll: ''' to: '''; nextPutAll: newName; nextPutAll: ''' in: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.RenameInstanceVariableRefactoring <category>initialize-release</category>
rename: aVarName to: aName in: aClass self variable: aVarName class: aClass. newName := aName
</methods> <methods> Refactory.Browser.RenameInstanceVariableRefactoring <category>transforming</category>
renameReferences | replacer | replacer := ParseTreeRewriter rename: variableName to: newName handler: [self refactoringError: ((#x1sAlreadyDefinedAsTemp << #browser >> '<1s> is already defined as a method or block temporary <n> variable in this class or one of its subclasses') expandMacrosWith: newName)]. self convertClasses: class withAllSubclasses select: [:aClass | aClass whichSelectorsReferToInstanceVariable: variableName] using: replacer
transform class renameInstanceVariable: variableName to: newName around: nil. self renameReferences
</methods> <methods> Refactory.Browser.RenameInstanceVariableRefactoring <category>preconditions</category>
preconditions ^(Condition isValidInstanceVariableName: newName for: class) & (Condition definesInstanceVariable: variableName in: class) & (Condition hierarchyOf: class definesVariable: newName) not & (Condition hierarchyOf: class canAccessVariableNamed: newName) not
</methods> <methods> Refactory.Browser.RenameInstanceVariableRefactoring class <category>instance creation</category>
model: aRBNameSpace rename: aVarName to: aName in: aClass ^(self new) model: aRBNameSpace; rename: aVarName to: aName in: aClass; yourself
rename: aVarName to: aName in: aClass ^(self new) rename: aVarName to: aName in: aClass; yourself
</methods> <methods> Refactory.Browser.RBProgramItem <category>comparing</category>
= aRBProgramItem ^self class = aRBProgramItem class and: [self name = aRBProgramItem name and: [self environment = aRBProgramItem environment]]
hash ^self name hash bitXor: self class hash
</methods> <methods> Refactory.Browser.RBProgramItem <category>accessing</category>
allNameSpacesDo: aBlock
binding ^binding
changes ^self rootNameSpace changes
fullName ^(self environment == self smalltalkNameSpace or: [self environment isNil]) ifTrue: [self name asString] ifFalse: [self environment fullName , '.' , self name]
name ^name
name: aSymbol name := aSymbol
parcels ^parcels isNil ifTrue: [parcels := self isDefined ifTrue: [Parcel parcelsDefiningBinding: self binding] ifFalse: [#()]] ifFalse: [parcels]
rootNameSpace environment isNil ifTrue: [^self]. ^environment rootNameSpace
smalltalkNameSpace | root | root := self rootNameSpace. ^root smalltalkNameSpace
unambiguousName | dottedName | dottedName := self fullName. (dottedName includes: $.) ifTrue: [^dottedName]. self == self smalltalkNameSpace ifTrue: [^dottedName]. ^'Smalltalk.' , dottedName
</methods> <methods> Refactory.Browser.RBProgramItem <category>initialize-release</category>
initialize isPrivate := false
isPrivate: aBoolean isPrivate := aBoolean
parcels: aCollection parcels := aCollection
parent: aNameSpace environment := aNameSpace
realBinding: aVariableBinding name := aVariableBinding key. binding := aVariableBinding. isPrivate := aVariableBinding isPrivate
</methods> <methods> Refactory.Browser.RBProgramItem <category>private</category>
basicRemove self subclassResponsibility
environment ^environment
flushCaches self rootNameSpace flushCaches
prepareForRemoval
realItem ^binding value
</methods> <methods> Refactory.Browser.RBProgramItem <category>testing</category>
isClassObject ^false
isDefined ^binding notNil
isNameSpace ^false
isPrivate ^isPrivate
isSharedVariable ^false
</methods> <methods> Refactory.Browser.RBProgramItem class <category>instance creation</category>
named: aSymbol model: aRBNameSpace ^(self new) name: aSymbol; parent: aRBNameSpace; yourself
new ^(super new) initialize; yourself
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>testing</category>
canAccess: aProgramItem ((self referencedItem: aProgramItem name) == aProgramItem and: [(self hasRemoved: aProgramItem name) not]) ifTrue: [^true]. ^false
canReference: aString ^(self referencedItem: aString) notNil
canReferenceObject: anObject ^(self referencedItem: anObject name) = anObject
checkLiteral: aLiteral references: aRBProgramItem aLiteral == aRBProgramItem name ifTrue: [^self canAccess: aRBProgramItem]. aLiteral isBindingReference ifTrue: [^self doesReference: aLiteral includeObject: aRBProgramItem]. aLiteral class == Array ifTrue: [^aLiteral anySatisfy: [:each | self checkLiteral: each references: aRBProgramItem]]. ^false
definesAnyItem (self privateItems notNil and: [self privateItems notEmpty]) ifTrue: [^true]. self realItem isNil ifTrue: [^false]. self realItem asNameSpace bindingsDo: [:each | (self hasRemoved: each key) ifFalse: [^true]]. ^false
doesName: aString includeObject: aRBProgramItem ^self doesPath: ((aString tokensBasedOn: $.) collect: [:each | each asSymbol]) includeObject: aRBProgramItem
doesPath: path includeObject: aRBProgramItem | index nameStream | index := 0. [index := path nextIndexOf: aRBProgramItem name from: index + 1 to: path size. index notNil] whileTrue: [nameStream := WriteStream on: String new. (1 to: index) do: [:i | nameStream nextPutAll: (path at: i)] separatedBy: [nameStream nextPut: $.]. (self referencedItem: nameStream contents) == aRBProgramItem ifTrue: [^true]]. ^false
doesReference: aReference includeObject: aRBClass ^self doesPath: aReference path includeObject: aRBClass
hasRemoved: aSymbol ^self privateRemovedItems notNil and: [self privateRemovedItems includes: aSymbol]
isNameSpace ^true
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>private-accessing</category>
createClassFor: aBinding | nonMeta | nonMeta := RBClass existing: aBinding model: self. ^self items at: nonMeta name put: nonMeta
createNameSpaceFor: aBinding | ns | ns := RBNameSpace onBinding: aBinding. ns parent: self. ^self items at: ns name put: ns
createProgramItemFrom: aVariableBinding aVariableBinding isForClass ifTrue: [^self createClassFor: aVariableBinding]. aVariableBinding isForNameSpace ifTrue: [^self createNameSpaceFor: aVariableBinding]. aVariableBinding isForGeneral ifTrue: [^self createSharedVariableFor: aVariableBinding]. ^nil
createSharedVariableFor: aVariableBinding | sharedVariable | sharedVariable := RBSharedVariable onBinding: aVariableBinding. sharedVariable parent: self. ^self items at: aVariableBinding key put: sharedVariable
generalImports ^self imports reject: [:each | each isSpecific]
itemFor: aSymbol (self includesItem: aSymbol) ifFalse: [^nil]. ^self items at: aSymbol ifAbsentPut: [| realBinding item | realBinding := self realItem asNameSpace bindingFor: aSymbol. realBinding notNil ifTrue: [item := self createProgramItemFrom: realBinding]. item isNil ifTrue: [^nil]. item]
items items isNil ifTrue: [items := IdentityDictionary new]. ^items
privateItems ^items
privateRemovedItems ^removedItems
removedItems removedItems isNil ifTrue: [removedItems := Set new]. ^removedItems
specificImports ^self imports select: [:each | each isSpecific]
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>accessing-imports</category>
addImport: aNameSpaceImport | newImports | newImports := OrderedCollection withAll: self imports. newImports add: aNameSpaceImport. self changeImportsTo: newImports
imports ^imports isNil ifTrue: [imports := self isDefined ifTrue: [self realItem importDefinitions] ifFalse: [#()]] ifFalse: [imports]
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>accessing</category>
allInitializersDo: aBlock | seen | seen := IdentitySet new. self items do: [:each | each allInitializersDo: aBlock. seen add: each name]. self isDefined ifFalse: [^self]. self realNameSpace bindingsDo: [:each | | variable | variable := each key. ((seen includes: variable) or: [self hasRemoved: variable]) ifFalse: [(self itemFor: variable) allInitializersDo: aBlock]]
allNameSpacesDo: aBlock aBlock value: self. self itemsDo: [:each | each isNameSpace ifTrue: [aBlock value: each. each allNameSpacesDo: aBlock]]
realNameSpace ^self realItem asNameSpace
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>accessing-objects</category>
localReferencedItem: aSymbol includePrivates: aBoolean alreadySearched: aCollection currentlyChecking: aSet | item | (aCollection includes: self) ifTrue: [^nil]. aCollection add: self. item := self itemFor: aSymbol. (item notNil and: [item isPrivate and: [aBoolean not]]) ifTrue: [item := nil]. item isNil ifTrue: [item := self searchImportsFor: aSymbol includePrivates: aBoolean alreadySearched: aCollection currentlyChecking: aSet]. ^item
lookupItemPath: aString currentlyChecking: aSet | index fullName item localName | fullName := aString. item := self. [item notNil & fullName notNil] whileTrue: [index := fullName indexOf: $.. index = 0 ifTrue: [localName := fullName. fullName := nil] ifFalse: [localName := fullName copyFrom: 1 to: index - 1. fullName := fullName copyFrom: index + 1 to: fullName size]. item := item localReferencedItem: localName asSymbol includePrivates: true alreadySearched: IdentitySet new currentlyChecking: aSet]. ^item
referencedItem: aString ^(aString includes: $.) ifTrue: [aString first == $_ ifTrue: [self lookupItemPath: (aString copyFrom: 3 to: aString size) currentlyChecking: Set new] ifFalse: [self rootNameSpace fullItemNamed: aString]] ifFalse: [self localReferencedItem: aString asSymbol includePrivates: true alreadySearched: IdentitySet new currentlyChecking: Set new]
searchImportsFor: aSymbol includePrivates: aBoolean alreadySearched: aCollection currentlyChecking: aSet self specificImports do: [:each | each isPrivate not | aBoolean ifTrue: [each simpleName = aSymbol ifTrue: [^self rootNameSpace fullItemNamed: each asString currentlyChecking: aSet]]]. self generalImports do: [:each | | item ns | each isPrivate not | aBoolean ifTrue: [ns := self rootNameSpace fullItemNamed: each asString currentlyChecking: aSet. ns notNil ifTrue: [item := ns localReferencedItem: aSymbol includePrivates: false alreadySearched: aCollection currentlyChecking: aSet]. item notNil ifTrue: [^item]]]. ^nil
sharedVariableNames | names | names := Set new. self itemsDo: [:each | each isSharedVariable ifTrue: [names add: each name]]. ^names
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>changes</category>
changeImportsTo: aCollection self imports: aCollection. self recompileObject
defineSharedVariable: aString | change | change := self changes defineSharedVariable: aString. ^(self rootNameSpace nameSpaceNamed: change nameSpaceName) addSharedVariableFrom: change
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>private</category>
addSharedVariableFrom: anAddSharedVariableChange | modelStatic sharedVariableName | sharedVariableName := anAddSharedVariableChange objectName. sharedVariableName := (sharedVariableName copyFrom: (sharedVariableName lastIndexOf: $.) + 1 to: sharedVariableName size) asSymbol. modelStatic := self itemFor: sharedVariableName. modelStatic isNil ifTrue: [self privateRemovedItems notNil ifTrue: [self privateRemovedItems remove: sharedVariableName ifAbsent: []]. modelStatic := RBSharedVariable named: sharedVariableName model: self. self items at: sharedVariableName put: modelStatic]. modelStatic isPrivate: anAddSharedVariableChange isPrivate; parcels: anAddSharedVariableChange parcels; category: anAddSharedVariableChange category; initializer: anAddSharedVariableChange initializer; constant: anAddSharedVariableChange isConstant. ^anAddSharedVariableChange
itemsDo: aBlock | seen | seen := IdentitySet new. self items copy do: [:each | aBlock value: each. seen add: each name]. self isDefined ifFalse: [^self]. self realNameSpace bindingsDo: [:each | | variable item | variable := each key. ((seen includes: variable) or: [(item := self itemFor: variable) isNil]) ifFalse: [aBlock value: item]]
prepareForRemoval self itemsDo: [:each | self removeLocalObject: each]
recompileObject self subclassResponsibility
removeLocalObject: aRBProgramItem aRBProgramItem prepareForRemoval. self removedItems add: aRBProgramItem name. self privateItems notNil ifTrue: [self privateItems removeKey: aRBProgramItem name ifAbsent: []]. self flushCaches. ^aRBProgramItem basicRemove
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>accessing-namespaces</category>
nameSpaceFor: aNameSpace | parent ns | aNameSpace isNil ifTrue: [^nil]. aNameSpace isBehavior ifTrue: [^self classFor: aNameSpace]. self realNameSpace == aNameSpace ifTrue: [^self]. parent := aNameSpace. [parent notNil] whileTrue: [parent environment == self realNameSpace ifTrue: [ns := self itemFor: parent name. ^ns notNil ifTrue: [ns nameSpaceFor: aNameSpace] ifFalse: [nil]]. parent := parent environment]. ^self rootNameSpace nameSpaceFor: aNameSpace
nameSpaceNamed: aSymbol | index var | aSymbol isNil ifTrue: [^nil]. (index := aSymbol indexOf: $.) = 0 ifFalse: [^(self nameSpaceNamed: (aSymbol copyFrom: 1 to: index - 1)) nameSpaceNamed: (aSymbol copyFrom: index + 1 to: aSymbol size)]. var := self itemFor: aSymbol asSymbol. (var isNil or: [var isNameSpace]) ifTrue: [^var]. var isSharedVariable ifTrue: [^var asNameSpace]. ^var
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>initialize-release</category>
imports: aCollection imports := aCollection
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>private-testing</category>
includesItem: aSymbol (self hasRemoved: aSymbol) ifTrue: [^false]. (self privateItems notNil and: [self privateItems includesKey: aSymbol]) ifTrue: [^true]. ^self isDefined and: [self realItem asNameSpace includesKey: aSymbol]
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>accessing-classes</category>
classFor: aBehavior | nonMetaclass ns class | aBehavior isNil ifTrue: [^nil]. aBehavior isBehavior ifFalse: [^aBehavior nonMetaclass]. nonMetaclass := aBehavior instanceBehavior. ns := self nameSpaceFor: aBehavior environment. class := ns itemFor: nonMetaclass name. class isNil ifTrue: [^nil]. class isClassObject ifFalse: [^nil]. ^aBehavior isMeta ifTrue: [class metaclass] ifFalse: [class]
</methods> <methods> Refactory.Browser.RBBasicNameSpace <category>method accessing</category>
outerReferencingMethodsDo: aBlock self itemsDo: [:each | each outerReferencingMethodsDo: aBlock]
</methods> <methods> Refactory.Browser.RBAbstractClass <category>variable accessing</category>
addInstanceVariable: aString self privateInstanceVariableNames add: aString. environment addInstanceVariable: aString to: self
removeInstanceVariable: aString self privateInstanceVariableNames remove: aString. environment removeInstanceVariable: aString from: self
renameInstanceVariable: oldName to: newName around: aBlock self privateInstanceVariableNames at: (self privateInstanceVariableNames indexOf: oldName asString) put: newName asString. environment renameInstanceVariable: oldName to: newName in: self
whoDefinesInstanceVariable: aString | sprClass | (self directlyDefinesInstanceVariable: aString) ifTrue: [^self]. sprClass := self superclass. ^sprClass isNil ifTrue: [nil] ifFalse: [sprClass whoDefinesInstanceVariable: aString]
</methods> <methods> Refactory.Browser.RBAbstractClass <category>private</category>
addMethod: aRBMethod self newMethods at: aRBMethod selector put: aRBMethod. removedMethods notNil ifTrue: [removedMethods remove: aRBMethod selector ifAbsent: []]
addSubclass: aRBClass self subclasses add: aRBClass
basicRemove ^self changes removeClassNamed: self unambiguousName
existingMethodsThatReferTo: aSymbol | existingMethods | existingMethods := self realClass whichSelectorsReferTo: aSymbol. (newMethods isNil and: [removedMethods isNil]) ifTrue: [^existingMethods]. ^existingMethods reject: [:each | (self hasRemovedMethod: each) or: [self newMethods includesKey: each]]
existingMethodsThatReferToInstanceVariable: aString ^(self realClass whichSelectorsAccess: aString) reject: [:each | (self hasRemovedMethod: each) or: [self newMethods includesKey: each]]
mirrorRealSubclasses | realClass | self isDefined ifTrue: [realClass := self realClass. realClass subclasses do: [:each | (environment rootNameSpace classFor: each) ifNotNil: [:anotherRBClass | subclasses addLast: anotherRBClass]]]
newMethods ^newMethods isNil ifTrue: [newMethods := IdentityDictionary new] ifFalse: [newMethods]
prepareForRemoval super prepareForRemoval. self superclass isNil ifTrue: [self rootNameSpace removeRootClass: self]. self subclasses copy do: [:each | each isMeta ifTrue: [each superclass: nil] ifFalse: [each environment removeLocalObject: each]]. self superclass notNil ifTrue: [self superclass removeSubclass: self]. self metaclass superclass notNil ifTrue: [self metaclass superclass removeSubclass: self metaclass]
privateInstanceVariableNames instanceVariableNames isNil ifTrue: [self isDefined ifTrue: [self instanceVariableNames: self realClass instVarNames] ifFalse: [instanceVariableNames := OrderedCollection new]]. ^instanceVariableNames
superclass: aRBClass self superclass notNil ifTrue: [self superclass removeSubclass: self]. superclass := aRBClass. superclass notNil ifTrue: [superclass addSubclass: self].
</methods> <methods> Refactory.Browser.RBAbstractClass <category>accessing</category>
allInstanceVariableNames | sprClass | sprClass := self superclass. ^sprClass isNil ifTrue: [self instanceVariableNames] ifFalse: [sprClass allInstanceVariableNames , self instanceVariableNames]
allSubclasses | allSubclasses index | index := 1. allSubclasses := OrderedCollection withAll: self subclasses. [index <= allSubclasses size] whileTrue: [allSubclasses addAll: (allSubclasses at: index) subclasses. index := index + 1]. ^allSubclasses
allSuperclasses | supers sprClass | supers := OrderedCollection new. sprClass := self superclass. [sprClass notNil] whileTrue: [supers add: sprClass. sprClass := sprClass superclass]. ^supers
instanceBehavior ^self nonMetaclass
instanceVariableNames ^self privateInstanceVariableNames copy
instanceVariableNames: aCollectionOfStrings instanceVariableNames := aCollectionOfStrings asOrderedCollection
metaclass ^self subclassResponsibility
nonMetaclass ^self subclassResponsibility
parcels ^self realClass isNil ifTrue: [#()] ifFalse: [Parcel parcels select: [:each | each definesClass: self realClass]]
primaryInstance ^self nonMetaclass
protocolsFor: aSelector | change | change := self isMeta ifTrue: [self changes changeForMetaclass: self nonMetaclass unambiguousName selector: aSelector] ifFalse: [self changes changeForClass: self unambiguousName selector: aSelector]. ^change isNil ifTrue: [self isDefined ifTrue: [Array with: (BrowserEnvironment new whichProtocolIncludes: aSelector in: self realClass)] ifFalse: [#(#accessing)]] ifFalse: [change protocols]
realClass ^self realItem
removedMethods ^removedMethods isNil ifTrue: [removedMethods := Set new] ifFalse: [removedMethods]
removeSubclass: aRBClass self subclasses remove: aRBClass ifAbsent: []
soleInstance ^self nonMetaclass
subclasses ^subclasses ifNil: [subclasses := OrderedCollection new. self mirrorRealSubclasses. subclasses]
superclass ^superclass == LookupSuperclass ifTrue: [superclass := environment classFor: self realClass superclass] ifFalse: [superclass]
withAllSubclasses ^(self allSubclasses) add: self; yourself
withAllSuperclasses ^(self allSuperclasses) add: self; yourself
</methods> <methods> Refactory.Browser.RBAbstractClass <category>method accessing</category>
allSelectors | class selectors | class := self. selectors := Set new. [class notNil] whileTrue: [selectors addAll: class selectors. class := class superclass]. ^selectors
compile: aString ^self compile: aString withAttributesFrom: (self methodFor: (RBParser parseMethodPattern: aString))
compile: aString classified: aSymbolCollection ^self compile: aString classified: aSymbolCollection parcels: self parcels
compile: aString classified: aSymbolCollection parcels: aCollection | change method | change := environment compile: aString in: self classified: aSymbolCollection. change parcels: aCollection. method := RBMethod for: self source: aString selector: change selector. self addMethod: method. ^change
compile: aString withAttributesFrom: aRBMethod | change method | change := environment compile: aString in: self classified: aRBMethod protocols. change copyAttributesFrom: aRBMethod selector in: aRBMethod modelClass realClass. method := RBMethod for: self source: aString selector: change selector. self addMethod: method. ^change
compileTree: aRBMethodNode ^(self methodFor: aRBMethodNode selector) compileTree: aRBMethodNode
methodFor: aSelector ^self newMethods at: aSelector ifAbsent: [| compiledMethod class | (self hasRemovedMethod: aSelector) ifTrue: [^nil]. class := self realClass. class isNil ifTrue: [^nil]. compiledMethod := class compiledMethodAt: aSelector ifAbsent: [nil]. compiledMethod isNil ifTrue: [nil] ifFalse: [RBMethod for: self fromMethod: compiledMethod andSelector: aSelector]]
outerReferencingMethodsDo: aBlock "Enumerate all methods that refer to variables beyond the scope of the instance." super outerReferencingMethodsDo: aBlock. self realClass outerReferencingMethodsDo: [:selector :method | (self hasRemovedMethod: selector) ifFalse: [aBlock value: selector value: (self methodFor: selector)]]. newMethods ifNotNil: [newMethods keysAndValuesDo: [:selector :method | method hasOuterVariables ifTrue: [aBlock value: selector value: method]]]
parseTreeFor: aSelector | class | class := self whoDefinesMethod: aSelector. class isNil ifTrue: [^nil]. ^(class methodFor: aSelector) parseTree
removeMethod: aSelector self newMethods removeKey: aSelector ifAbsent: []. environment removeMethod: aSelector from: self. self removedMethods add: aSelector
selectors | selectors | selectors := Set new. selectors addAll: self newMethods keys. self isDefined ifTrue: [selectors addAll: self realClass selectors. removedMethods notNil ifTrue: [removedMethods do: [:each | selectors remove: each ifAbsent: []]]]. ^selectors
sourceCodeFor: aSelector | class | class := self whoDefinesMethod: aSelector. class isNil ifTrue: [^nil]. ^(class methodFor: aSelector) source
whichMethodsReferToSymbol: aSymbol | selectors | selectors := Set new. self newMethods do: [:each | (each refersToSymbol: aSymbol) ifTrue: [selectors add: each selector]]. self isDefined ifTrue: [selectors addAll: (self existingMethodsThatReferTo: aSymbol)]. ^selectors collect: [:sel | self methodFor: sel]
whichSelectorsReferToInstanceVariable: aString | selectors | selectors := Set new. self newMethods do: [:each | (each refersToVariable: aString) ifTrue: [selectors add: each selector]]. self isDefined ifTrue: [selectors addAll: (self existingMethodsThatReferToInstanceVariable: aString)]. ^selectors
whichSelectorsReferToObject: aRBProgramItem | selectors | selectors := Set new. self newMethods do: [:each | (each refersToObject: aRBProgramItem) ifTrue: [selectors add: each selector]]. (self isDefined and: [aRBProgramItem isDefined]) ifTrue: [selectors addAll: (self existingMethodsThatReferTo: aRBProgramItem binding)]. ^selectors
whoDefinesMethod: aSelector | sprClass | (self directlyDefinesMethod: aSelector) ifTrue: [^self]. sprClass := self superclass. ^sprClass isNil ifTrue: [nil] ifFalse: [sprClass whoDefinesMethod: aSelector]
</methods> <methods> Refactory.Browser.RBAbstractClass <category>testing</category>
definesInstanceVariable: aString (self directlyDefinesInstanceVariable: aString) ifTrue: [^true]. ^self superclass notNil and: [self superclass definesInstanceVariable: aString]
definesMethod: aSelector (self directlyDefinesMethod: aSelector) ifTrue: [^true]. ^self superclass notNil and: [self superclass definesMethod: aSelector]
definesSharedVariable: aString (self directlyDefinesSharedVariable: aString) ifTrue: [^true]. ^self superclass notNil and: [self superclass definesSharedVariable: aString]
definesVariable: aVariableName ^(self definesInstanceVariable: aVariableName) or: [self definesSharedVariable: aVariableName]
directlyDefinesInstanceVariable: aString ^self instanceVariableNames includes: aString
directlyDefinesMethod: aSelector self isDefined ifTrue: [(self hasRemovedMethod: aSelector) ifTrue: [^false]. (self realClass includesSelector: aSelector) ifTrue: [^true]]. ^newMethods notNil and: [newMethods includesKey: aSelector]
directlyDefinesSharedVariable: aString ^self includesItem: aString asSymbol
directlyDefinesVariable: aVariableName ^(self directlyDefinesSharedVariable: aVariableName) or: [self directlyDefinesInstanceVariable: aVariableName]
hasRemovedMethod: aSelector ^removedMethods notNil and: [removedMethods includes: aSelector]
hierarchyCanAccessVariableNamed: aString (self canReference: aString) ifTrue: [^true]. ^self allSubclasses anySatisfy: [:each | each canReference: aString]
hierarchyDefinesInstanceVariable: aString (self definesInstanceVariable: aString) ifTrue: [^true]. ^self allSubclasses anySatisfy: [:each | each directlyDefinesInstanceVariable: aString]
hierarchyDefinesMethod: aSelector (self definesMethod: aSelector) ifTrue: [^true]. ^self subclassRedefines: aSelector
hierarchyDefinesVariable: aString (self definesVariable: aString) ifTrue: [^true]. ^self allSubclasses anySatisfy: [:each | each directlyDefinesVariable: aString]
includesClass: aRBClass | currentClass | currentClass := self. [currentClass notNil and: [currentClass ~= aRBClass]] whileTrue: [currentClass := currentClass superclass]. ^currentClass = aRBClass
isAbstract (self whichMethodsReferToSymbol: #subclassResponsibility) notEmpty ifTrue: [^true]. self rootNameSpace allReferencesToObject: self do: [:each | ^false]. ^true
isClassObject ^true
isMeta self subclassResponsibility
referencedItem: aString in: aNamespace "Search for the named item, giving access to both our local names (e.g. shared variables) but searching aNamespace rather than our namespace and imports. The simplest thing that could possibly work seems to be to copy ourselves, tweak the namespace, and hope." | copy | aNamespace isNil ifTrue: [^self referencedItem: aString]. copy := self copy. copy parent: aNamespace. ^copy referencedItem: aString
subclassRedefines: aSelector ^self allSubclasses anySatisfy: [:each | each directlyDefinesMethod: aSelector]
</methods> <methods> Refactory.Browser.RBAbstractClass <category>initialize-release</category>
initialize super initialize. name := #'Unknown Class'
realBinding: aBinding super realBinding: aBinding. superclass isNil ifTrue: [superclass := LookupSuperclass]
</methods> <methods> Refactory.Browser.RBAbstractClass <category>printing</category>
printOn: aStream aStream nextPutAll: self name
storeOn: aStream aStream nextPutAll: self unambiguousName
</methods> <methods> Refactory.Browser.RBAbstractClass <category>accessing-objects</category>
searchImportsFor: aSymbol includePrivates: aBoolean alreadySearched: aCollection currentlyChecking: aSet | sprClass item | sprClass := self superclass. sprClass notNil ifTrue: [item := sprClass localReferencedItem: aSymbol includePrivates: false alreadySearched: aCollection currentlyChecking: aSet. item notNil ifTrue: [^item]]. item := super searchImportsFor: aSymbol includePrivates: aBoolean alreadySearched: aCollection currentlyChecking: aSet. (aBoolean not or: [item notNil]) ifTrue: [^item]. ^self environment localReferencedItem: aSymbol includePrivates: aBoolean alreadySearched: aCollection currentlyChecking: aSet
</methods> <methods> Refactory.Browser.ChangeMethodNameRefactoring <category>testing</category>
hasPermutedArguments oldSelector numArgs = newSelector numArgs ifFalse: [^true]. 1 to: oldSelector numArgs do: [:i | (permutation at: i) = i ifFalse: [^true]]. ^false
implementorsCanBePrimitives ^false
</methods> <methods> Refactory.Browser.ChangeMethodNameRefactoring <category>private</category>
implementors implementors isNil ifTrue: [implementors := self model allImplementorsOf: oldSelector]. ^implementors
modifyImplementorParseTree: parseTree in: aClass | oldArgs | oldArgs := parseTree arguments. parseTree renameSelector: newSelector andArguments: (permutation collect: [:each | oldArgs at: each])
parseTreeRewriter | rewriteRule oldString newString | rewriteRule := ParseTreeRewriter new. oldString := self buildSelectorString: oldSelector. newString := self buildSelectorString: newSelector withPermuteMap: permutation. rewriteRule replace: '``@object ' , oldString with: '``@object ' , newString. ^rewriteRule
</methods> <methods> Refactory.Browser.ChangeMethodNameRefactoring <category>preconditions</category>
myConditions ^self subclassResponsibility
preconditions "This refactoring only preserves behavior if all implementors are renamed." | conditions | conditions := self myConditions & (Condition definesSelector: oldSelector in: class) & (Condition isValidMethodName: newSelector for: class). conditions := self implementors inject: conditions into: [:condition :each | condition & (Condition hierarchyOf: each canUnderstand: newSelector) not]. ^conditions & (Condition withBlock: [self implementors size > 1 ifTrue: [self refactoringWarning: ((#WillModify1pImplementors << #browser >> 'This will modify all <1p> implementors.') expandMacrosWith: self implementors size)]. true])
</methods> <methods> Refactory.Browser.ChangeMethodNameRefactoring <category>accessing</category>
newSelector ^newSelector
</methods> <methods> Refactory.Browser.ChangeMethodNameRefactoring <category>transforming</category>
removeRenamedImplementors oldSelector == newSelector ifTrue: [^self]. self implementors do: [:each | each removeMethod: oldSelector]
renameImplementors self implementors do: [:each | | parseTree | parseTree := each parseTreeFor: oldSelector. parseTree isNil ifTrue: [self refactoringError: (#CouldNotParseSourceCode << #browser >> 'Could not parse source code.')]. self implementorsCanBePrimitives ifFalse: [parseTree isPrimitive ifTrue: [self refactoringError: ((#x1p1sIsPrimitive << #browser >> '<1p>''s implementation of #<2s> is a primitive') expandMacrosWith: each with: oldSelector)]]. self modifyImplementorParseTree: parseTree in: each. (each methodFor: oldSelector) compileTree: parseTree]
renameMessageSends self convertAllReferencesTo: oldSelector using: self parseTreeRewriter
transform self renameImplementors. self renameMessageSends. self removeRenamedImplementors
</methods> <methods> Refactory.Browser.ChangeMethodNameRefactoring <category>initialize-release</category>
renameMethod: aSelector in: aClass to: newSel permutation: aMap oldSelector := aSelector asSymbol. newSelector := newSel asSymbol. class := self classObjectFor: aClass. permutation := aMap
</methods> <methods> Refactory.Browser.RenameMethodRefactoring <category>testing</category>
hasPermutedArguments ^hasPermutedArguments isNil ifTrue: [hasPermutedArguments := super hasPermutedArguments] ifFalse: [hasPermutedArguments]
implementorsCanBePrimitives ^self hasPermutedArguments not
</methods> <methods> Refactory.Browser.RenameMethodRefactoring <category>transforming</category>
parseTreeRewriter | rewriteRule oldString newString | oldString := self buildSelectorString: oldSelector. newString := self buildSelectorString: newSelector withPermuteMap: permutation. rewriteRule := self hasPermutedArguments ifTrue: [ParseTreeRewriter new] ifFalse: [ParseTreeRewriter replaceLiteral: oldSelector with: newSelector]. rewriteRule replace: '``@object ' , oldString with: '``@object ' , newString. ^rewriteRule
</methods> <methods> Refactory.Browser.RenameMethodRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Rename method refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' renameMethod: #'; nextPutAll: oldSelector; nextPutAll: ' in: '. class storeOn: aStream. aStream nextPutAll: ' to: #'; nextPutAll: newSelector; nextPutAll: ' permuation: '. permutation storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.RenameMethodRefactoring <category>preconditions</category>
myConditions ^Condition withBlock: [oldSelector numArgs = newSelector numArgs] errorString: ((#x1sDoesNotHaveCorrectArgNum << #browser >> '<1s> doesn''t have the correct number of arguments.') expandMacrosWith: newSelector printString)
preconditions | newCondition | newCondition := (Condition withBlock: [newSelector = oldSelector] errorString: (#Selectors1QEquivalent << #browser >> 'The selectors are <1?:not >equivalent') asString) & (Condition withBlock: [permutation asArray ~= (1 to: oldSelector numArgs) asArray] errorString: (#Arguments1QPermuted << #browser >> 'The arguments are <1?:not >permuted') asString). ^newCondition | super preconditions
</methods> <methods> Refactory.Browser.RenameMethodRefactoring class <category>instance creation</category>
model: aRBNameSpace renameMethod: aSelector in: aClass to: newSelector permutation: aMap ^(self new) model: aRBNameSpace; renameMethod: aSelector in: aClass to: newSelector permutation: aMap; yourself
renameMethod: aSelector in: aClass to: newSelector permutation: aMap ^(self new) renameMethod: aSelector in: aClass to: newSelector permutation: aMap; yourself
</methods> <methods> Refactory.Browser.TemporaryToInstanceVariableRefactoring <category>preconditions</category>
checkForValidTemporaryVariable | parseTree | parseTree := class parseTreeFor: selector. (parseTree allTemporaryVariables includes: temporaryVariableName) ifFalse: [self refactoringError: ((#x1sIsInvalidTempName << #browser >> '<1s> isn''t a valid temporary variable name') expandMacrosWith: temporaryVariableName)]. (parseTree allArgumentVariables includes: temporaryVariableName) ifTrue: [self refactoringError: ((#x1sIsABlockParameter << #browser >> '<1s> is a block parameter') expandMacrosWith: temporaryVariableName)]. (RBReadBeforeWrittenTester isVariable: temporaryVariableName readBeforeWrittenIn: parseTree) ifTrue: [self refactoringWarning: ((#x1sReadBeforeWrittenProceedQ << #browser >> '<1s> is read before it is written.<n>Proceed anyway?') expandMacrosWith: temporaryVariableName)]
preconditions ^(Condition definesSelector: selector in: class) & (Condition hierarchyOf: class definesVariable: temporaryVariableName asString) not & (Condition withBlock: [self checkForValidTemporaryVariable. true])
</methods> <methods> Refactory.Browser.TemporaryToInstanceVariableRefactoring <category>initialize-release</category>
class: aClass selector: aSelector variable: aVariableName class := self classObjectFor: aClass. selector := aSelector. temporaryVariableName := aVariableName
</methods> <methods> Refactory.Browser.TemporaryToInstanceVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Convert temporary to instance variable refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' class: '. class storeOn: aStream. aStream nextPutAll: ' selector: #'; nextPutAll: selector; nextPutAll: ' variable: '''; nextPutAll: temporaryVariableName; nextPut: $'. aStream nextPut: $)
</methods> <methods> Refactory.Browser.TemporaryToInstanceVariableRefactoring <category>transforming</category>
transform | parseTree matcher method | method := class methodFor: selector. parseTree := method parseTree. parseTree isNil ifTrue: [self refactoringError: (#CouldNotParseMethod << #browser >> 'Could not parse method')]. class removeMethod: selector. class addInstanceVariable: temporaryVariableName. (matcher := ParseTreeRewriter removeTemporaryNamed: temporaryVariableName) executeTree: parseTree. method compileTree: matcher tree
</methods> <methods> Refactory.Browser.TemporaryToInstanceVariableRefactoring class <category>instance creation</category>
class: aClass selector: aSelector variable: aVariableName ^(self new) class: aClass selector: aSelector variable: aVariableName; yourself
model: aRBNameSpace class: aClass selector: aSelector variable: aVariableName ^(self new) model: aRBNameSpace; class: aClass selector: aSelector variable: aVariableName; yourself
</methods> <methods> Refactory.Browser.AbstractInstanceVariableRefactoring <category>transforming</category>
abstractReferences | replacer | replacer := ParseTreeRewriter variable: variableName getter: self accessorsRefactoring getterMethod setter: self accessorsRefactoring setterMethod. self convertClasses: class withAllSubclasses select: [:aClass | (aClass whichSelectorsReferToInstanceVariable: variableName) reject: [:each | aClass == class and: [each == self accessorsRefactoring getterMethod or: [each == self accessorsRefactoring setterMethod]]]] using: replacer
createAccessors self performComponentRefactoring: self accessorsRefactoring
transform self createAccessors. self abstractReferences
</methods> <methods> Refactory.Browser.AbstractInstanceVariableRefactoring <category>private-accessing</category>
accessorsRefactoring ^accessorsRefactoring isNil ifTrue: [accessorsRefactoring := CreateAccessorsForVariableRefactoring model: self model variable: variableName class: class] ifFalse: [accessorsRefactoring]
</methods> <methods> Refactory.Browser.AbstractInstanceVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Abstract instance variable refactoring'
</methods> <methods> Refactory.Browser.AbstractInstanceVariableRefactoring <category>preconditions</category>
preconditions ^Condition directlyDefinesInstanceVariable: variableName in: class
</methods> <methods> Refactory.Browser.RefactoryTyper <category>printing</category>
collectionNameFor: aString ^'-<1s>-' expandMacrosWith: aString
printOn: aStream aStream nextPutAll: class fullName; cr. class instanceVariableNames do: [:each | aStream tab; nextPutAll: each; tab; nextPut: $<. self printTypeFor: each on: aStream. aStream nextPut: $>; cr]
printType: aClass for: aString on: aStream | name colTypes | colTypes := #(). name := self collectionNameFor: aString. (aClass includesClass: (model classFor: Collection)) ifTrue: [colTypes := self guessTypesFor: name]. colTypes notEmpty ifTrue: [aStream nextPut: $(]. aStream nextPutAll: aClass name. colTypes notEmpty ifTrue: [aStream nextPutAll: ' of: '. colTypes size > 1 ifTrue: [aStream nextPut: $(]. self printTypeFor: name on: aStream. colTypes size > 1 ifTrue: [aStream nextPut: $)]]. colTypes notEmpty ifTrue: [aStream nextPut: $)]
printTypeFor: aString on: aStream | types | types := (self guessTypesFor: aString) asSortedCollection: [:a :b | a name < b name]. 1 to: types size do: [:i | i == 1 ifFalse: [aStream nextPutAll: ' | ']. self printType: (types at: i) for: aString on: aStream]
</methods> <methods> Refactory.Browser.RefactoryTyper <category>selectors</category>
computeMessagesSentToVariables | searcher | variableMessages := Dictionary new. class instanceVariableNames do: [:each | variableMessages at: each put: Set new]. searcher := ParseTreeSearcher new. class instanceVariableNames do: [:each | | block | block := [:aNode :answer | (variableMessages at: each ifAbsentPut: [Set new]) add: aNode selector. self processCollectionMessagesFor: each in: aNode]. searcher matches: each , ' `@messageName: ``@args' do: block. (backpointers at: each) do: [:sel | sel isSymbol ifTrue: [searcher matches: ('(self <1s>) `@messageName: ``@args' expandMacrosWith: (ParseTreeSearcher buildSelectorString: sel)) asString do: block]]]. searcher answer: variableMessages. self executeSearch: searcher
</methods> <methods> Refactory.Browser.RefactoryTyper <category>computing types</category>
computeTypes variableMessages keysAndValuesDo: [:key :value | variableTypes at: key put: (self findTypeFor: value)]
findTypeFor: selectorCollection ^selectorCollection inject: model rootClasses into: [:classes :each | self refineTypes: classes with: (selectorLookup at: each ifAbsentPut: [self implementorsOf: each])]
implementorsOf: aSelector | classes | classes := OrderedCollection new. model rootClasses do: [:each | self implementorsOf: aSelector in: each storeIn: classes]. ^classes
implementorsOf: aSelector in: aClass storeIn: classes (aClass directlyDefinesMethod: aSelector) ifTrue: [classes add: aClass. ^self]. aClass subclasses do: [:each | self implementorsOf: aSelector in: each storeIn: classes]
refineTypes: aClassCollection with: anotherClassCollection | classSet | classSet := Set new. aClassCollection do: [:each | anotherClassCollection do: [:cls | (cls includesClass: each) ifTrue: [classSet add: cls] ifFalse: [(each includesClass: cls) ifTrue: [classSet add: each]]]]. ^classSet
</methods> <methods> Refactory.Browser.RefactoryTyper <category>private</category>
executeSearch: searcher class withAllSubclasses do: [:each | each selectors do: [:sel | | parseTree | methodName := sel. parseTree := each parseTreeFor: sel. parseTree notNil ifTrue: [searcher executeTree: parseTree]]]
model ^model
model: aRBNameSpace model := aRBNameSpace
</methods> <methods> Refactory.Browser.RefactoryTyper <category>assignments</category>
guessTypeFromAssignment: aNode | type set newType | type := nil. aNode value isAssignment ifTrue: [^self guessTypeFromAssignment: (RBAssignmentNode variable: aNode variable value: aNode value value)]. aNode value isBlock ifTrue: [type := model classFor: [] class]. aNode value isLiteralNode ifTrue: [aNode value value isNil ifTrue: [^self]. type := model classFor: (self typeFor: aNode value value)]. aNode value isMessage ifTrue: [aNode value receiver isVariable ifTrue: [type := model classNamed: aNode value receiver name asSymbol]. aNode value selector == #asValue ifTrue: [type := model classNamed: #ValueHolder]. (#(#and: #or: #= #== #~= #~~ #<= #< #~~ #> #>=) includes: aNode value selector) ifTrue: [type := model classFor: Boolean]]. type isNil ifTrue: [^self]. set := variableTypes at: aNode variable name. newType := set detect: [:each | type includesClass: each] ifNone: [nil]. newType isNil ifTrue: [^self]. newType = (model classFor: Object) ifTrue: [newType := type]. (bestGuesses at: aNode variable name ifAbsentPut: [Set new]) add: newType
refineTypesByLookingAtAssignments | searcher needsSearch | needsSearch := false. searcher := ParseTreeSearcher new. variableTypes keysAndValuesDo: [:key :value | key first == $- ifFalse: [needsSearch := true. searcher matches: key , ' := ``@object' do: [:aNode :answer | self guessTypeFromAssignment: aNode]]]. needsSearch ifTrue: [self executeSearch: searcher]
typeFor: anObject '' class == anObject class ifTrue: [^String]. ^(#(true false) includes: anObject) ifTrue: [Boolean] ifFalse: [anObject class]
</methods> <methods> Refactory.Browser.RefactoryTyper <category>accessing</category>
guessTypesFor: anInstVarName ^bestGuesses at: anInstVarName ifAbsent: [self typesFor: anInstVarName]
guessTypesFor: anInstVarName in: aClass class = aClass ifFalse: [self runOn: aClass]. ^bestGuesses at: anInstVarName ifAbsent: [self typesFor: anInstVarName in: aClass]
runOn: aClass variableTypes := Dictionary new. variableMessages := Dictionary new. bestGuesses := Dictionary new. class := model classFor: aClass. class instanceVariableNames isEmpty ifTrue: [^self]. self selectedClass: aClass; computeEquivalenceClassesForMethodsAndVars; computeMessagesSentToVariables; computeTypes; refineTypesByLookingAtAssignments
selectedClass: aClass class := model classFor: aClass
typesFor: anInstVarName ^variableTypes at: anInstVarName ifAbsent: [Set new]
typesFor: anInstVarName in: aClass class = aClass ifFalse: [self runOn: aClass]. ^variableTypes at: anInstVarName ifAbsent: [Set new]
</methods> <methods> Refactory.Browser.RefactoryTyper <category>initialize-release</category>
initialize model := RBRootNameSpace new. class := model classFor: Object. variableTypes := Dictionary new. variableMessages := Dictionary new. selectorLookup := IdentityDictionary new. bestGuesses := Dictionary new
</methods> <methods> Refactory.Browser.RefactoryTyper <category>selectors-collections</category>
processCollectionFor: key messagesTo: aName in: aBlock | searcher | searcher := ParseTreeSearcher new. searcher matches: aName , ' `@message: ``@args' do: [:aNode :answer | self processCollectionMessagesFor: key in: aNode. answer add: aNode selector; yourself]. searcher executeTree: aBlock initialAnswer: (variableMessages at: (self collectionNameFor: key) ifAbsentPut: [Set new])
processCollectionMessagesFor: variableName in: aParseTree | parent block | aParseTree isMessage ifFalse: [^self]. (#(#first #at: #last) includes: aParseTree selector) ifTrue: [parent := aParseTree parent. (parent notNil and: [parent isMessage]) ifFalse: [^self]. aParseTree == parent receiver ifFalse: [^self]. (variableMessages at: (self collectionNameFor: variableName) ifAbsentPut: [Set new]) add: parent selector. self processCollectionMessagesFor: (self collectionNameFor: variableName) in: parent]. (#(#do: #do:separatedBy: #collect: #reject: #select: #detect: #detect:ifNone:) includes: aParseTree selector) ifTrue: [block := aParseTree arguments first. block isBlock ifFalse: [^self]. self processCollectionFor: variableName messagesTo: block arguments first name in: block]. #inject:into: == aParseTree selector ifTrue: [block := aParseTree arguments last. block isBlock ifFalse: [^self]. self processCollectionFor: variableName messagesTo: block arguments last name in: block]
</methods> <methods> Refactory.Browser.RefactoryTyper <category>equivalence classes</category>
computeEquivalenceClassesForMethodsAndVars | searcher | backpointers := Dictionary new. class instanceVariableNames do: [:each | backpointers at: each put: (Set with: each)]. class withAllSubclasses do: [:sub | sub selectors do: [:each | backpointers at: each put: (Set with: each)]]. searcher := ParseTreeSearcher new. searcher matches: '^``@object' do: [:aNode :answer | self processNode: aNode value]. self executeSearch: searcher
merge: aName | set1 set2 | set1 := backpointers at: methodName ifAbsent: [nil]. set2 := backpointers at: aName ifAbsent: [nil]. (set1 isNil or: [set2 isNil or: [set1 == set2]]) ifTrue: [^self]. set1 addAll: set2. set2 do: [:each | backpointers at: each put: set1]
processNode: aNode (aNode isVariable and: [class instanceVariableNames includes: aNode name]) ifTrue: [^self merge: aNode name]. (aNode isMessage and: [aNode receiver isVariable and: [aNode receiver name = 'self']]) ifTrue: [^self merge: aNode selector]. aNode isAssignment ifTrue: [self processNode: aNode value; processNode: aNode variable]. (aNode isMessage and: [#(#ifTrue: #ifFalse: #ifTrue:ifFalse: #ifFalse:ifTrue:) includes: aNode selector]) ifTrue: [aNode arguments do: [:each | each isBlock ifTrue: [each body statements notEmpty ifTrue: [self processNode: each body statements last]]]]
</methods> <methods> Refactory.Browser.RefactoryTyper class <category>instance creation</category>
new ^(super new) initialize; yourself
newFor: aRBNameSpace ^(self new) model: aRBNameSpace; yourself
</methods> <methods> Refactory.Browser.RefactoryTyper class <category>accessing</category>
typesFor: variableName in: aParseTree model: aRBNameSpace | searcher messages | searcher := ParseTreeSearcher new. searcher matches: variableName , ' `@message: ``@args' do: [:aNode :answer | answer add: aNode selector; yourself]. messages := searcher executeTree: aParseTree initialAnswer: Set new. ^(self new) model: aRBNameSpace; findTypeFor: messages
</methods> <methods> Refactory.Browser.InlineMethodRefactoring <category>transforming</category>
addSelfReturn inlineParseTree addSelfReturn
addTemporary: sourceNode assignedTo: replacementNode | newName | newName := self renameConflictingTemporary: sourceNode name. (inlineParseTree body) addTemporaryNamed: newName; addNodeFirst: (RBAssignmentNode variable: (RBVariableNode named: newName) value: replacementNode)
checkSuperMessages self inlineClass = class ifTrue: [^self]. self inlineClass superclass isNil ifTrue: [^self]. inlineParseTree superMessages do: [:each | (self inlineClass superclass whoDefinesMethod: each) = (class superclass whoDefinesMethod: each) ifFalse: [self refactoringError: ((#CannotInline1sSuperMessageOverridden << #browser >> 'Cannot inline method since it sends a super message <1s> that is overridden') expandMacrosWith: each)]]
compileMethod class compileTree: self sourceTree
findSelectedMessage sourceMessage := self sourceTree whichNodeIsContainedBy: sourceInterval. sourceMessage isNil ifTrue: [self refactoringError: #SelectionNotMessageSend << #browser >> 'The selection doesn''t appear to be a message send']. sourceMessage isCascade ifTrue: [sourceMessage := sourceMessage messages last]. sourceMessage isMessage ifFalse: [self refactoringError: #SelectionNotMessageSend << #browser >> 'The selection doesn''t appear to be a message send']. (sourceMessage receiver isVariable and: [#('self' 'super') includes: sourceMessage receiver name]) ifFalse: [self refactoringError: #CannotInlineNonSelfMessage << #browser >> 'Cannot inline non-self messages']
inlineClass ^inlineClass isNil ifTrue: [inlineClass := (sourceMessage receiver name = 'super' ifTrue: [class superclass] ifFalse: [class]) whoDefinesMethod: self inlineSelector] ifFalse: [inlineClass]
inlineSelector sourceMessage isNil ifTrue: [self findSelectedMessage]. ^sourceMessage selector
inlineSourceReplacing: aParseTree | statements nodeUnderSequence | statements := inlineParseTree body statements. (statements size > 1 and: [aParseTree isEvaluatedFirst not]) ifTrue: [self refactoringWarning: (#OrderOfExecutionChangeWarning << #browser >> 'To inline this method, we need to move some of its statements before the original message send.<n>This could change the order of execution, which can change the behavior.<n>Do you want to proceed?') expandMacros]. nodeUnderSequence := aParseTree. [nodeUnderSequence parent isSequence] whileFalse: [nodeUnderSequence := nodeUnderSequence parent]. (nodeUnderSequence parent) addNodes: (statements copyFrom: 1 to: (statements size - 1 max: 0)) before: nodeUnderSequence; addTemporariesNamed: inlineParseTree body temporaryNames. aParseTree replaceWith: (statements isEmpty ifTrue: [RBVariableNode named: 'self'] ifFalse: [statements last])
insertInlinedMethod | node | node := sourceMessage. self moveComments. node parent isCascade ifTrue: [self rewriteCascadedMessage. node := node parent]. node parent isReturn ifTrue: [node := node parent] ifFalse: [self removeReturns]. self replaceArguments. self inlineSourceReplacing: node. self sourceTree removeDeadCode. self removeEmptyIfTrues. self removeImmediateBlocks
moveComments inlineParseTree nodesDo: [:each | each comments: (each comments collect: [:anInterval | | start stop source | source := self sourceTree source. start := source size + 1. source := source , (inlineParseTree source copyFrom: anInterval first to: anInterval last). stop := source size. self sourceTree source: source. start to: stop])]
normalizeIfTrues | rewriter | rewriter := ParseTreeRewriter new. rewriter replace: '| `@temps | ``@.s1. ``@boolean ifTrue: [| `@t1 | ``@.Stmts1. ^`@r1]. ``@.s2. ^``@r2' with: '| `@temps | ``@.s1. ``@boolean ifTrue: [| `@t1 | ``@.Stmts1. ^`@r1] ifFalse: [``@.s2. ^``@r2]'; replace: '| `@temps | ``@.s1. ``@boolean ifFalse: [| `@t1 | ``@.Stmts1. ^`@r1]. ``@.s2. ^``@r2' with: '| `@temps | ``@.s1. ``@boolean ifTrue: [``@.s2. ^``@r2] ifFalse: [| `@t1 | ``@.Stmts1. ^`@r1]'. [rewriter executeTree: inlineParseTree] whileTrue: [inlineParseTree := rewriter tree]
normalizeReturns | rewriter | rewriter := ParseTreeRewriter new. rewriter replace: '^``@boolean ifTrue: [| `@t1 | `@.Stmts1. ^``@r1] ifFalse: [| `@t2 | `@.Stmts2. ^``@r2]' with: '^``@boolean ifTrue: [| `@t1 | `@.Stmts1. ``@r1] ifFalse: [| `@t2 | `@.Stmts2. ``@r2]'; replace: '^``@boolean ifFalse: [| `@t1 | `@.Stmts1. ^``@r1] ifTrue: [| `@t2 | `@.Stmts2. ^``@r2]' with: '^``@boolean ifFalse: [| `@t1 | `@.Stmts1. ``@r1] ifTrue: [| `@t2 | `@.Stmts2. ``@r2]'; replace: '^``@boolean ifTrue: [| `@t1 | `@.Stmts1. ``@r1] ifFalse: [| `@t2 | `@.Stmts2. ^``@r2]' with: '^``@boolean ifTrue: [| `@t1 | `@.Stmts1. ``@r1] ifFalse: [| `@t2 | `@.Stmts2. ``@r2]'; replace: '^``@boolean ifFalse: [| `@t1 | `@.Stmts1. ``@r1] ifTrue: [| `@t2 | `@.Stmts2. ^``@r2]' with: '^``@boolean ifFalse: [| `@t1 | `@.Stmts1. ``@r1] ifTrue: [| `@t2 | `@.Stmts2. ``@r2]'; replace: '^``@boolean ifTrue: [| `@t1 | `@.Stmts1. ^``@r1] ifFalse: [| `@t2 | `@.Stmts2. ``@r2]' with: '^``@boolean ifTrue: [| `@t1 | `@.Stmts1. ``@r1] ifFalse: [| `@t2 | `@.Stmts2. ``@r2]'; replace: '^``@boolean ifFalse: [| `@t1 | `@.Stmts1. ^``@r1] ifTrue: [| `@t2 | `@.Stmts2. ``@r2]' with: '^``@boolean ifFalse: [| `@t1 | `@.Stmts1. ``@r1] ifTrue: [| `@t2 | `@.Stmts2. ``@r2]'; replace: '``@boolean ifTrue: [| `@t1 | `@.Stmts1. ^``@r1] ifFalse: [| `@t2 | `@.Stmts2. ^``@r2]' with: '^``@boolean ifTrue: [| `@t1 | `@.Stmts1. ``@r1] ifFalse: [| `@t2 | `@.Stmts2. ``@r2]'; replace: '``@boolean ifFalse: [| `@t1 | `@.Stmts1. ^``@r1] ifTrue: [| `@t2 | `@.Stmts2. ^``@r2]' with: '^``@boolean ifFalse: [| `@t1 | `@.Stmts1. ``@r1] ifTrue: [| `@t2 | `@.Stmts2. ``@r2]'. [rewriter executeTree: inlineParseTree] whileTrue: [inlineParseTree := rewriter tree]
parseInlineMethod self inlineClass isNil ifTrue: [self refactoringError: ((#x1pDoesNotContainMethod2s << #browser >> '<1p> or its superclasses don''t contain method <2s>') expandMacrosWith: class with: self inlineSelector)]. inlineParseTree := self inlineClass parseTreeFor: self inlineSelector. inlineParseTree isNil ifTrue: [self refactoringError: (#CouldNotParseSources << #browser >> 'Could not parse sources')]. inlineParseTree lastIsReturn ifFalse: [inlineParseTree addSelfReturn]
removeEmptyIfTrues | rewriter | rewriter := ParseTreeRewriter new. rewriter replace: '``@boolean ifTrue: [] ifFalse: [| `@temps | ``@.Stmts]' with: '``@boolean ifFalse: [|`@temps | ``@.Stmts]'; replace: '``@boolean ifFalse: [] ifTrue: [| `@temps | ``@.Stmts]' with: '``@boolean ifTrue: [|`@temps | ``@.Stmts]'; replace: '``@boolean ifTrue: [| `@temps | ``@.Stmts] ifFalse: []' with: '``@boolean ifTrue: [|`@temps | ``@.Stmts]'; replace: '``@boolean ifFalse: [| `@temps | ``@.Stmts] ifTrue: []' with: '``@boolean ifFalse: [|`@temps | ``@.Stmts]'. (rewriter executeTree: self sourceTree) ifTrue: [sourceTree := rewriter tree]
removeImmediateBlocks | rewriter | rewriter := ParseTreeRewriter new. rewriter replace: '[^``@object] value' with: '``.object' when: [:aNode | aNode parent isSequence]; replace: '[``.object `{:node | node isReturn not}] value' with: '``.object' when: [:aNode | aNode parent isCascade not]. rewriter replace: '| `@temps | ``@.Stmts1. [| `@bTemps | ``@.bStmts] value. ``@.Stmts2' with: '| `@temps `@bTemps | ``@.Stmts1. ``@.bStmts. ``@.Stmts2'. (rewriter executeTree: self sourceTree) ifTrue: [sourceTree := rewriter tree]
removeReturns | rewriter | rewriter := ParseTreeRewriter new. rewriter replace: '^``@object' with: '``@object'. (rewriter executeTree: inlineParseTree) ifTrue: [inlineParseTree := rewriter tree]
renameConflictingTemporaries inlineParseTree allDefinedVariables do: [:each | self renameConflictingTemporary: each]
renameConflictingTemporary: aName | allNames newName index seqNode | allNames := (Set new) addAll: inlineParseTree allDefinedVariables; yourself. allNames remove: aName ifAbsent: []. seqNode := sourceMessage. [seqNode isSequence] whileFalse: [seqNode := seqNode parent]. allNames addAll: seqNode allDefinedVariables. "Add those variables defined in blocks. This might cause a few variables to be renamed that don't need to be, but this should be safe." newName := aName. index := 0. [(sourceMessage whoDefines: newName) notNil or: [(class hierarchyDefinesVariable: newName) or: [allNames includes: newName]]] whileTrue: [index := index + 1. newName := aName , index printString]. newName = aName ifFalse: [self renameTemporary: aName to: newName]. ^newName
renameTemporary: oldName to: newName | rewriter | rewriter := ParseTreeRewriter new. rewriter replace: oldName with: newName; replaceArgument: oldName with: newName. (rewriter executeTree: inlineParseTree) ifTrue: [inlineParseTree := rewriter tree]
replaceArgument: sourceNode with: replacementNode | rewriter | rewriter := ParseTreeRewriter new. rewriter replaceTree: sourceNode withTree: replacementNode. (rewriter executeTree: inlineParseTree body) ifTrue: [inlineParseTree body: rewriter tree]
replaceArguments sourceMessage arguments reverse with: inlineParseTree arguments reverse do: [:replacement :source | (replacement isImmediateNode or: [self shouldInlineExpression: replacement newSource]) ifTrue: [self replaceArgument: source with: replacement] ifFalse: [self addTemporary: source assignedTo: replacement]]
rewriteCascadedMessage | index messages | messages := sourceMessage parent messages. index := (1 to: messages size) detect: [:i | sourceMessage == (messages at: i)] ifNone: [0]. inlineParseTree body addNodesFirst: (messages copyFrom: 1 to: index - 1). self removeReturns. inlineParseTree body addNodes: (messages copyFrom: index + 1 to: messages size). inlineParseTree addReturn
rewriteInlinedTree sourceMessage parent isReturn ifTrue: [(self sourceTree isLast: sourceMessage parent) ifFalse: [self addSelfReturn]] ifFalse: [self writeGuardClauses; normalizeIfTrues; normalizeReturns; addSelfReturn]
transform self renameConflictingTemporaries; insertInlinedMethod; compileMethod
writeGuardClauses | rewriter | rewriter := ParseTreeRewriter new. rewriter replaceMethod: '`@methodName: `@args | `@temps | `@.s1. `@boolean ifTrue: [| `@t1 | `@.Stmts1. ^`@r1]. `@.s2. ^`@r2' with: '`@methodName: `@args | `@temps | `@.s1. `@boolean ifTrue: [| `@t1 | `@.Stmts1. ^`@r1] ifFalse: [`@.s2. ^`@r2]'; replaceMethod: '`@methodName: `@args | `@temps | `@.s1. `@boolean ifFalse: [| `@t1 | `@.Stmts1. ^`@r1]. `@.s2. ^`@r2' with: '`@methodName: `@args | `@temps | `@.s1. `@boolean ifTrue: [`@.s2. ^`@r2] ifFalse: [| `@t1 | `@.Stmts1. ^`@r1]'; replaceMethod: '`@methodName: `@args | `@temps | `@.s1. `@boolean ifTrue: [| `@t1 | `@.Stmts1. ^`@r1]. `@.s2' with: '`@methodName: `@args | `@temps | `@.s1. `@boolean ifTrue: [| `@t1 | `@.Stmts1. ^`@r1] ifFalse: [`@.s2. ^self]'; replaceMethod: '`@methodName: `@args | `@temps | `@.s1. `@boolean ifFalse: [| `@t1 | `@.Stmts1. ^`@r1]. `@.s2' with: '`@methodName: `@args | `@temps | `@.s1. `@boolean ifTrue: [`@.s2. ^self] ifFalse: [| `@t1 | `@.Stmts1. ^`@r1]'. [rewriter executeTree: inlineParseTree] whileTrue: [inlineParseTree := rewriter tree]
</methods> <methods> Refactory.Browser.InlineMethodRefactoring <category>testing</category>
hasMultipleReturns "Do we have multiple returns? If the last statement isn't a return, then we have an implicit return of self." | searcher | searcher := ParseTreeSearcher new. searcher matches: '^``@object' do: [:aNode :hasAReturn | hasAReturn ifTrue: [^true]. true]. searcher executeTree: inlineParseTree initialAnswer: inlineParseTree lastIsReturn not. ^false
isOverridden ^class allSubclasses anySatisfy: [:each | each directlyDefinesMethod: self inlineSelector]
isPrimitive ^inlineParseTree isPrimitive
</methods> <methods> Refactory.Browser.InlineMethodRefactoring <category>initialize-release</category>
inline: anInterval inMethod: aSelector forClass: aClass sourceSelector := aSelector. class := self classObjectFor: aClass. sourceInterval := anInterval
</methods> <methods> Refactory.Browser.InlineMethodRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Inline method refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' inline: '. sourceInterval storeOn: aStream. aStream nextPutAll: ' inMethod: #'; nextPutAll: sourceSelector; nextPutAll: ' forClass: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.InlineMethodRefactoring <category>preconditions</category>
preconditions ^(Condition definesSelector: sourceSelector in: class) & (Condition withBlock: [self findSelectedMessage. self parseInlineMethod. self isOverridden ifTrue: [self refactoringWarning: ((#x1p2sOverriddenInlineQ << #browser >> '<1p>>><2s> is overridden. Do you want to inline it anyway?') expandMacrosWith: self inlineClass with: self inlineSelector)]. self isPrimitive ifTrue: [self refactoringError: (#CannotInlinePrimitives << #browser >> 'Cannot inline primitives')]. self checkSuperMessages. self rewriteInlinedTree. (sourceMessage parent isReturn or: [self hasMultipleReturns not]) ifFalse: [self refactoringError: (#CannotInlineWithMultipleReturns << #browser >> 'Cannot inline method since it contains multiple returns that cannot be rewritten')]. true])
</methods> <methods> Refactory.Browser.InlineMethodRefactoring <category>accessing</category>
sourceTree ^sourceTree ifNil: [sourceTree := class parseTreeFor: sourceSelector]
sourceTree: aParseTree sourceTree := aParseTree
</methods> <methods> Refactory.Browser.InlineMethodRefactoring class <category>instance creation</category>
inline: anInterval inMethod: aSelector forClass: aClass ^(self new) inline: anInterval inMethod: aSelector forClass: aClass; yourself
model: aRBNameSpace inline: anInterval inMethod: aSelector forClass: aClass ^(self new) model: aRBNameSpace; inline: anInterval inMethod: aSelector forClass: aClass; yourself
</methods> <methods> Refactory.Browser.InlineMethodFromComponentRefactoring <category>transforming</category>
abstractVariableReferences | refactoring | refactoring := AbstractVariablesRefactoring model: self model abstractVariablesIn: inlineParseTree from: inlineClass toAll: (Array with: class). self performComponentRefactoring: refactoring. inlineParseTree := refactoring parseTree
addArgumentToSelector: aSymbol ^aSymbol isInfix ifTrue: [#value:value:] ifFalse: [(aSymbol , 'value:') asSymbol]
addSelfReferenceToInlineParseTree | variableName rewriter newArguments | variableName := self newNameForSelf. rewriter := ParseTreeRewriter rename: 'self' to: variableName. (rewriter executeTree: inlineParseTree) ifTrue: [inlineParseTree := rewriter tree]. newArguments := OrderedCollection withAll: inlineParseTree arguments. newArguments addFirst: (RBVariableNode named: variableName). inlineParseTree renameSelector: (self addArgumentToSelector: inlineParseTree selector) andArguments: newArguments. sourceMessage receiver replaceWith: (RBVariableNode named: variableName)
addSelfReferenceToSourceMessage | newArguments | newArguments := OrderedCollection withAll: sourceMessage arguments. newArguments addFirst: sourceMessage receiver copy. sourceMessage renameSelector: (self addArgumentToSelector: sourceMessage selector) andArguments: newArguments
checkSuperMessages inlineParseTree superMessages notEmpty ifTrue: [self refactoringError: (#CannotInlineWithSuperSend << #browser >> 'Cannot inline method since it sends a super message')]
findSelectedMessage sourceMessage := self sourceTree whichNodeIsContainedBy: sourceInterval. sourceMessage isNil ifTrue: [self refactoringError: #SelectionNotMessageSend << #browser >> 'The selection doesn''t appear to be a message send']. sourceMessage isCascade ifTrue: [sourceMessage := sourceMessage messages last]. sourceMessage isMessage ifFalse: [self refactoringError: #SelectionNotMessageSend << #browser >> 'The selection doesn''t appear to be a message send']
inlineClass | imps | inlineClass notNil ifTrue: [^inlineClass]. imps := (self model allImplementorsOf: self inlineSelector) asOrderedCollection. imps size = 1 ifTrue: [^inlineClass := imps first]. imps isEmpty ifTrue: [self refactoringError: ((#NobodyDefinesMethod1s << #browser >> 'Nobody defines a method named <1s>') expandMacrosWith: self inlineSelector)]. inlineClass := self requestImplementorToInline: imps. inlineClass isNil ifTrue: [self refactoringError: (#NoImplementorSelected << #browser >> 'No implementor selected')]. ^inlineClass
newNameForSelf | variableName index originalName nonMetaClass | nonMetaClass := inlineClass nonMetaclass. variableName := originalName := ((nonMetaClass name first isVowel ifTrue: [(#an << #browser >> 'an')] ifFalse: [(#a << #browser >> 'a')])) asString, nonMetaClass name. index := 1. [variableName := self safeVariableNameBasedOn: variableName. inlineParseTree allDefinedVariables includes: variableName] whileTrue: [variableName := originalName , index printString. index := index + 1]. ^variableName
renameSelfReferences self addSelfReferenceToSourceMessage. self addSelfReferenceToInlineParseTree.
safeVariableNameBasedOn: aString "Creates an unused variable name containing aString" | baseString newString i allTempVars | allTempVars := inlineParseTree allTemporaryVariables. baseString := aString copy. baseString at: 1 put: baseString first asLowercase. newString := baseString. i := 0. [(allTempVars includes: newString) or: [class definesInstanceVariable: newString]] whileTrue: [i := i + 1. newString := baseString , i printString]. ^newString
transform self abstractVariableReferences. self renameSelfReferences. super transform
</methods> <methods> Refactory.Browser.InlineMethodFromComponentRefactoring <category>testing</category>
isOverridden ^self inlineClass allSubclasses anySatisfy: [:each | each directlyDefinesMethod: self inlineSelector]
</methods> <methods> Refactory.Browser.InlineMethodFromComponentRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Inline method from component refactoring'
</methods> <methods> Refactory.Browser.RBAbstractCondition <category>logical operations</category>
& aCondition ^RBConjunctiveCondition new left: self right: aCondition
not ^RBNegationCondition on: self
| aCondition "(A | B) = (A not & B not) not" ^(self not & aCondition not) not
</methods> <methods> Refactory.Browser.RBAbstractCondition <category>checking</category>
check self subclassResponsibility
</methods> <methods> Refactory.Browser.RBAbstractCondition <category>accessing</category>
errorBlock ^self errorBlockFor: false
errorString ^self errorStringFor: false
</methods> <methods> Refactory.Browser.RBAbstractCondition <category>private</category>
errorBlockFor: aBoolean ^nil
errorMacro ^errorMacro isNil ifTrue: ['unknown'] ifFalse: [errorMacro]
errorMacro: aString errorMacro := aString
errorStringFor: aBoolean ^self errorMacro expandMacrosWith: aBoolean
</methods> <methods> Refactory.Browser.ExpandNameSpaceReferencesRefactoring <category>initialize-release</category>
for: aParseTree fromClass: aClass toClasses: classCollection fromClass := self model classFor: aClass. parseTree := aParseTree. toClasses := classCollection collect: [:each | self model classFor: each]
</methods> <methods> Refactory.Browser.ExpandNameSpaceReferencesRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Expand scope of shared variables referenced by method to class refactoring'
storeOn: aStream "fill in later"
</methods> <methods> Refactory.Browser.ExpandNameSpaceReferencesRefactoring <category>transforming</category>
addImports referencedVars do: [:var | self expandScopeOf: var]
computeReferencedVars | searcher | referencedVars := Set new. searcher := ParseTreeSearcher new. searcher matches: '`var' do: [:aNode :answer | | varName | varName := aNode name. ((aNode whoDefines: varName) isNil and: [(fromClass allInstanceVariableNames includes: varName) not]) ifTrue: [referencedVars add: varName]]. searcher executeTree: parseTree
createAccessors: aString | refactoring rewriter | refactoring := CreateAccessorsForVariableRefactoring model: self model variable: aString class: fromClass. self performComponentRefactoring: refactoring. rewriter := ParseTreeRewriter new. rewriter replace: aString , ' := ``@object' with: ('self <1s> ``@object' expandMacrosWith: refactoring setterMethod); replace: aString with: 'self ' , refactoring getterMethod. rewriter executeTree: parseTree. parseTree := rewriter tree
expandScopeOf: aString | sel | sel := self methodForExpandingScopeOf: aString. sel isNil ifTrue: [self refactoringError: (#RefactoringAborted << #browser >> 'Refactoring aborted')]. self perform: sel with: aString
removeAccessibleVariables | result | result := Set new. toClasses do: [:cls | referencedVars do: [:each | | from to | from := fromClass referencedItem: each. to := cls referencedItem: each. from == to ifFalse: [result add: each]]]. referencedVars := result
specificImport: aString | item | item := fromClass referencedItem: aString. toClasses do: [:each | each nonMetaclass addImport: (SpecificNameSpaceImport pathString: item fullName)]
transform self computeReferencedVars. self removeAccessibleVariables. self mustAddImports ifTrue: [self refactoringWarning: (#InaccessibleVarRefWarning << #browser >> 'This method contains references to variables<n>which are inaccessible in the<n>name space of the destination.') expandMacros]. self addImports
</methods> <methods> Refactory.Browser.ExpandNameSpaceReferencesRefactoring <category>accessing</category>
parseTree ^parseTree
</methods> <methods> Refactory.Browser.ExpandNameSpaceReferencesRefactoring <category>testing</category>
mustAddImports ^referencedVars notEmpty
</methods> <methods> Refactory.Browser.ExpandNameSpaceReferencesRefactoring <category>preconditions</category>
preconditions ^Condition empty
</methods> <methods> Refactory.Browser.ExpandNameSpaceReferencesRefactoring class <category>instance creation</category>
for: aSelector fromClass: aClass toClasses: classCollection ^(self new) for: aSelector fromClass: aClass toClasses: classCollection; yourself
model: aRBNameSpace for: aSelector fromClass: aClass toClasses: classCollection ^(self new) model: aRBNameSpace; for: aSelector fromClass: aClass toClasses: classCollection; yourself
</methods> <methods> Refactory.Browser.AddInstanceVariableRefactoring <category>transforming</category>
transform class addInstanceVariable: variableName
</methods> <methods> Refactory.Browser.AddInstanceVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Add instance variable refactoring'
</methods> <methods> Refactory.Browser.AddInstanceVariableRefactoring <category>preconditions</category>
preconditions ^(Condition isValidInstanceVariableName: variableName for: class) & (Condition hierarchyOf: class definesVariable: variableName) not & (Condition hierarchyOf: class canAccessVariableNamed: variableName) not
</methods> <methods> Refactory.Browser.RemoveInstanceVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Remove instance variable refactoring'
</methods> <methods> Refactory.Browser.RemoveInstanceVariableRefactoring <category>transforming</category>
transform class removeInstanceVariable: variableName
</methods> <methods> Refactory.Browser.RemoveInstanceVariableRefactoring <category>preconditions</category>
preconditions | references | references := Condition hierarchyOf: class referencesInstanceVariable: variableName. class realClass isNil ifTrue: [references errorMacro: ((#x1sIsReferenced << #browser >> '<1s> is referenced.') expandMacrosWith: variableName)] ifFalse: [references errorMacro: ((#x1sIsReferencedBrowseQ << #browser >> '<1s> is referenced.<n>Browse references?') expandMacrosWith: variableName); errorBlock: [self openBrowserOn: (BrowserEnvironment new instVarRefsTo: variableName in: class realClass)]]. ^(Condition definesInstanceVariable: variableName asString in: class) & references not
</methods> <methods> Refactory.Browser.RemoveParameterRefactoring <category>private</category>
computeNewSelector | keywords stream | oldSelector numArgs == 0 ifTrue: [self refactoringError: (#MethodHasNoArgs << #browser >> 'This method contains no arguments')]. oldSelector isInfix ifTrue: [self refactoringError: (#CannotRemoveParamsOfInfix << #browser >> 'Cannot remove parameters of infix selectors')]. keywords := oldSelector keywords asOrderedCollection. keywords size = 1 ifTrue: [^(keywords first copyWithout: $:) asSymbol]. keywords removeAtIndex: parameterIndex. stream := WriteStream on: String new. keywords do: [:each | stream nextPutAll: each]. ^stream contents asSymbol
</methods> <methods> Refactory.Browser.RemoveParameterRefactoring <category>transforming</category>
getNewSelector | tree | (class directlyDefinesMethod: oldSelector) ifFalse: [self refactoringError: (#MethodDoesntExist << #browser >> 'Method doesn''t exist.')]. tree := class parseTreeFor: oldSelector. tree isNil ifTrue: [self refactoringError: (#CannotParseSources << #browser >> 'Cannot parse sources.')]. parameterIndex := tree argumentNames indexOf: argument ifAbsent: [self refactoringError: (#SelectAParameter << #browser >> 'Select a parameter!')]. permutation := (1 to: oldSelector numArgs) copyWithout: parameterIndex. newSelector := self computeNewSelector
hasReferencesToTemporaryIn: each | tree | tree := each parseTreeFor: oldSelector. tree isNil ifTrue: [self refactoringError: (#CannotParseSources << #browser >> 'Cannot parse sources.')]. ^tree references: (tree argumentNames at: parameterIndex)
</methods> <methods> Refactory.Browser.RemoveParameterRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Remove parameter refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' removeParameter: '''; nextPutAll: argument; nextPutAll: ''' in: '. class storeOn: aStream. aStream nextPutAll: ' selector: #'; nextPutAll: oldSelector. aStream nextPut: $)
</methods> <methods> Refactory.Browser.RemoveParameterRefactoring <category>initialize-release</category>
removeParameter: aString in: aClass selector: aSelector oldSelector := aSelector. class := self classObjectFor: aClass. argument := aString
</methods> <methods> Refactory.Browser.RemoveParameterRefactoring <category>preconditions</category>
myConditions | imps | imps := self model allImplementorsOf: oldSelector. self getNewSelector. ^imps inject: (Condition definesSelector: oldSelector in: class) into: [:cond :each | cond & (Condition withBlock: [(self hasReferencesToTemporaryIn: each) not] errorString: (#ArgumentStillReferenced << #browser >> 'This argument is still referenced in atleast one implementor!'))]
</methods> <methods> Refactory.Browser.RemoveParameterRefactoring class <category>instance creation</category>
model: aRBNameSpace removeParameter: aString in: aClass selector: aSelector ^(self new) model: aRBNameSpace; removeParameter: aString in: aClass selector: aSelector; yourself
removeParameter: aString in: aClass selector: aSelector ^(self new) removeParameter: aString in: aClass selector: aSelector; yourself
</methods> <methods> Refactory.Browser.InlineParameterRefactoring <category>private</category>
allExpressionsToInline | coll | coll := Set new. self model allReferencesTo: oldSelector do: [:each | | tree | tree := each parseTree. tree notNil ifTrue: [coll addAll: (self expressionsToInlineFrom: tree)]]. ^coll asOrderedCollection
expressionsToInlineFrom: aTree | searcher | searcher := ParseTreeSearcher new. searcher matches: '``@obj ' , (self buildSelectorString: oldSelector) do: [:aNode :answer | answer add: (aNode arguments at: parameterIndex); yourself]. ^searcher executeTree: aTree initialAnswer: OrderedCollection new
</methods> <methods> Refactory.Browser.InlineParameterRefactoring <category>initialize-release</category>
inlineParameter: aString in: aClass selector: aSelector oldSelector := aSelector. class := self classObjectFor: aClass. argument := aString
</methods> <methods> Refactory.Browser.InlineParameterRefactoring <category>transforming</category>
modifyImplementorParseTree: parseTree in: aClass | node assignment | node := (parseTree arguments at: parameterIndex) copy. parseTree body addTemporaryNamed: node name. assignment := RBAssignmentNode variable: node copy value: expressions first. parseTree body addNodeFirst: assignment. super modifyImplementorParseTree: parseTree in: aClass
</methods> <methods> Refactory.Browser.InlineParameterRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Inline parameter refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' inlineParameter: '''; nextPutAll: argument; nextPutAll: ''' in: '. class storeOn: aStream. aStream nextPutAll: ' selector: #'; nextPutAll: oldSelector; nextPut: $)
</methods> <methods> Refactory.Browser.InlineParameterRefactoring <category>preconditions</category>
myConditions self getNewSelector. expressions := self allExpressionsToInline. ^(Condition definesSelector: oldSelector in: class) & ((Condition withBlock: [expressions notEmpty]) errorMacro: (#NoCallersUseRemove << #browser >> 'No callers. Use Remove Method instead.') asString) & ((Condition withBlock: [expressions size = 1]) errorMacro: (#AllValuesMustBeIdentical << #browser >> 'All values passed as this argument must be identical.') asString) & ((Condition withBlock: [expressions first isLiteralNode]) errorMacro: (#AllValuesMustBeLiteral << #browser >> 'All values passed must be literal.') asString)
</methods> <methods> Refactory.Browser.InlineParameterRefactoring class <category>instance creation</category>
inlineParameter: aString in: aClass selector: aSelector ^(self new) inlineParameter: aString in: aClass selector: aSelector; yourself
model: aRBNameSpace inlineParameter: aString in: aClass selector: aSelector ^(self new) model: aRBNameSpace; inlineParameter: aString in: aClass selector: aSelector; yourself
</methods> <methods> Refactory.Browser.PullUpInstanceVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Push up instance variable refactoring'
</methods> <methods> Refactory.Browser.PullUpInstanceVariableRefactoring <category>transforming</category>
transform class allSubclasses do: [:each | (each directlyDefinesInstanceVariable: variableName) ifTrue: [each removeInstanceVariable: variableName]]. class addInstanceVariable: variableName
</methods> <methods> Refactory.Browser.PullUpInstanceVariableRefactoring <category>preconditions</category>
preconditions ^Condition withBlock: [(class hierarchyDefinesInstanceVariable: variableName) ifFalse: [self refactoringError: ((#NoSubclassDefines1s << #browser >> 'No subclass defines <1s>') expandMacrosWith: variableName)]. (class directlyDefinesInstanceVariable: variableName) ifTrue: [self refactoringError: (#VariableAlreadyDefined << #browser >> 'The variable is already defined by the class')]. (class subclasses allSatisfy: [:each | each directlyDefinesInstanceVariable: variableName]) ifFalse: [self refactoringWarning: ((#NotAllSubclassesHaveInstVar1s << #browser >> 'Not all subclasses have an instance variable named <1s>.') expandMacrosWith: variableName)]. true]
</methods> <methods> Refactory.Browser.AddParameterRefactoring <category>initialize-release</category>
addParameterToMethod: aSelector in: aClass newSelector: newSel initializer: init self renameMethod: aSelector in: aClass to: newSel permutation: (1 to: newSel numArgs). initializer := init
</methods> <methods> Refactory.Browser.AddParameterRefactoring <category>preconditions</category>
checkSendersAccessTo: name | searcher method | (#('self' 'super') includes: name) ifTrue: [^self]. searcher := ParseTreeSearcher new. searcher matches: ((#anObject1s << #browser >> '``@anObject <1s>') expandMacrosWith: (self buildSelectorString: oldSelector)) do: [:aNode :answer | (aNode whoDefines: name) isNil ifTrue: [self refactoringError: ((#x1sNotDefinedIn2p << #browser >> '<1s> doesn''t appear to be defined in <2p>') expandMacrosWith: name with: method)]]. self model allReferencesTo: oldSelector do: [:each | method := each. (self canReferenceVariable: name in: each modelClass) ifFalse: [searcher executeTree: each parseTree]]
checkVariableReferencesIn: aParseTree | searcher | searcher := ParseTreeSearcher new. searcher matches: '`var' do: [:aNode :answer | | name | name := aNode name. (aNode whoDefines: name) isNil ifTrue: [self checkSendersAccessTo: name]]. searcher executeTree: aParseTree
myConditions ^Condition withBlock: [oldSelector numArgs + 1 = newSelector numArgs ifFalse: [self refactoringError: ((#x1sDoesNotHaveProperArgNum << #browser >> '<1s> doesn''t have the proper number of arguments.') expandMacrosWith: newSelector printString)]. self verifyInitializationExpression. true]
verifyInitializationExpression | tree | tree := RBParser parseExpression: initializer onError: [:msg :index | self refactoringError: ((#IllegalInitCodeBecause1s << #browser >> 'Illegal initialization code because:.<1s>') expandMacrosWith: msg)]. tree isValue ifFalse: [self refactoringError: (#InitCodeCannotBeReturnOrList << #browser >> 'The initialization code cannot be a return node or a list of statements')]. self checkVariableReferencesIn: tree
</methods> <methods> Refactory.Browser.AddParameterRefactoring <category>private</category>
modifyImplementorParseTree: parseTree in: aClass | name newArg allTempVars | allTempVars := parseTree allDefinedVariables. name := self safeVariableNameFor: aClass temporaries: allTempVars. newArg := RBVariableNode named: name. parseTree arguments: parseTree arguments , (Array with: newArg). super modifyImplementorParseTree: parseTree in: aClass
newSelectorString | stream keywords | stream := WriteStream on: String new. keywords := newSelector keywords. 1 to: keywords size do: [:i | stream nextPutAll: (keywords at: i). i == keywords size ifTrue: [stream nextPut: $(; nextPutAll: initializer; nextPut: $)] ifFalse: [stream nextPutAll: ' ``@arg'; nextPutAll: i printString]. stream nextPut: $ ]. ^stream contents
parseTreeRewriter | rewriteRule oldString newString | rewriteRule := ParseTreeRewriter new. oldString := self buildSelectorString: oldSelector. newString := self newSelectorString. rewriteRule replace: '``@object ' , oldString with: '``@object ' , newString. ^rewriteRule
safeVariableNameFor: aClass temporaries: allTempVars | baseString i newString | newString := baseString := 'anObject'. i := 0. [(allTempVars includes: newString) or: [aClass definesInstanceVariable: newString]] whileTrue: [i := i + 1. newString := baseString , i printString]. ^newString
</methods> <methods> Refactory.Browser.AddParameterRefactoring <category>printing</category>
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' addParameterToMethod: #'; nextPutAll: oldSelector; nextPutAll: ' in: '. class storeOn: aStream. aStream nextPutAll: ' newSelector: #'; nextPutAll: newSelector; nextPutAll: ' initializer: '''; nextPutAll: initializer; nextPutAll: ''')'
</methods> <methods> Refactory.Browser.AddParameterRefactoring class <category>instance creation</category>
addParameterToMethod: aSelector in: aClass newSelector: newSelector initializer: init ^(self new) addParameterToMethod: aSelector in: aClass newSelector: newSelector initializer: init; yourself
model: aRBNameSpace addParameterToMethod: aSelector in: aClass newSelector: newSelector initializer: init ^(self new) model: aRBNameSpace; addParameterToMethod: aSelector in: aClass newSelector: newSelector initializer: init; yourself
</methods> <methods> Refactory.Browser.ClassRefactoring <category>initialize-release</category>
className: aName className := aName
</methods> <methods> Refactory.Browser.ClassRefactoring <category>private</category>
definitionName | index | index := className lastIndexOf: $.. ^className copyFrom: index + 1 to: className size
nameSpace ^self model nameSpaceNamed: self nameSpaceName
nameSpaceName | nameSpaceName index | index := className lastIndexOf: $.. nameSpaceName := index = 0 ifTrue: [''] ifFalse: [className copyFrom: 1 to: index - 1]. nameSpaceName isEmpty ifTrue: [nameSpaceName := 'Smalltalk']. ^nameSpaceName
unambiguousNameSpaceName | ns | ns := self nameSpaceName. ^(ns includes: $.) ifTrue: [ns] ifFalse: ['Smalltalk.', ns]
</methods> <methods> Refactory.Browser.ClassRefactoring class <category>instance creation</category>
className: aName ^(self new) className: aName; yourself
model: aRBNameSpace className: aName ^(self new) model: aRBNameSpace; className: aName; yourself
</methods> <methods> Refactory.Browser.AddClassRefactoring <category>initialize-release</category>
addClass: aName superclass: aClass subclasses: aCollection self className: aName. superclass := self classObjectFor: aClass. subclasses := aCollection collect: [:each | self classObjectFor: each]
</methods> <methods> Refactory.Browser.AddClassRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Add class, '; nextPutAll: className; nextPutAll: ', as subclass of '; nextPutAll: superclass printString; nextPutAll: ' refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' addClass: #'''; nextPutAll: className; nextPutAll: ''' superclass: '. superclass storeOn: aStream. aStream nextPutAll: ' subclasses: '. subclasses asArray storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.AddClassRefactoring <category>transforming</category>
transform | nameSpaceName definitionName args | nameSpaceName := self unambiguousNameSpaceName. definitionName := self definitionName. args := Array with: nameSpaceName with: definitionName with: superclass asReference makeUnambiguous with: superclass indexedType. (self model) defineClass: ('<1s> defineClass: #<2s> superclass: <3p> indexedType: #<4s> private: false instanceVariableNames: '''' classInstanceVariableNames: '''' imports: '''' category: ''''' expandMacrosWithArguments: args); reparentClasses: subclasses to: (self model classNamed: className asSymbol)
</methods> <methods> Refactory.Browser.AddClassRefactoring <category>preconditions</category>
preconditions | cond | cond := ((Condition isMetaclass: superclass) errorMacro: (#SuperMustNotBeMeta << #browser >> 'Superclass must not be a metaclass') asString) not. cond := subclasses inject: cond into: [:sub :each | sub & ((Condition isMetaclass: each) errorMacro: (#SubMust1QBeMeta << #browser >> 'Subclass must <1?not :>be a metaclass') asString) not & (Condition isImmediateSubclass: each of: superclass)]. ^cond & (Condition isValidClassName: self definitionName) & (Condition canReference: self definitionName in: self nameSpace) not
</methods> <methods> Refactory.Browser.AddClassRefactoring class <category>instance creation</category>
addClass: aName superclass: aClass subclasses: aCollection ^(self new) addClass: aName superclass: aClass subclasses: aCollection; yourself
model: aRBNameSpace addClass: aName superclass: aClass subclasses: aCollection category: aSymbol ^(self new) model: aRBNameSpace; addClass: aName superclass: aClass subclasses: aCollection; yourself
</methods> <methods> Refactory.Browser.RBNameSpace <category>private</category>
allNewClassesDo: aBlock self privateItems isNil ifTrue: [^self]. self privateItems do: [:each | each isClassObject ifTrue: [aBlock value: each nonMetaclass; value: each metaclass] ifFalse: [each isNameSpace ifTrue: [each allNewClassesDo: aBlock]]]
basicRemove ^self changes removeNameSpaceNamed: self unambiguousName
recompileObject self rootNameSpace defineNameSpace: self definitionString
</methods> <methods> Refactory.Browser.RBNameSpace <category>private-changes</category>
addClassFrom: aClassChange | newClass newClassName | newClassName := aClassChange objectName. (newClassName includes: $.) ifTrue: [newClassName := (newClassName copyFrom: (newClassName lastIndexOf: $.) + 1 to: newClassName size) asSymbol]. newClass := self itemFor: newClassName. newClass isNil ifTrue: [self privateRemovedItems notNil ifTrue: [self privateRemovedItems remove: newClassName ifAbsent: []]. newClass := RBClass named: newClassName model: self. self items at: newClassName put: newClass]. newClass superclass: (aClassChange superclassName isNil ifTrue: [nil] ifFalse: [self rootNameSpace classNamed: aClassChange superclassName]). newClass superclass isNil ifTrue: [self rootNameSpace rootClasses add: newClass. newClass metaclass superclass: (self classFor: Object class superclass)] ifFalse: [newClass metaclass superclass: newClass superclass metaclass]. newClass imports: aClassChange imports. newClass indexedType: aClassChange indexedType. newClass isPrivate: aClassChange isPrivate. newClass parcels: aClassChange parcels. newClass instanceVariableNames: aClassChange instanceVariableNames. newClass metaclass instanceVariableNames: aClassChange classInstanceVariableNames. ^aClassChange
addInstanceVariable: aString to: aRBClass ^self changes addInstanceVariable: aString to: aRBClass
addNameSpaceFrom: aNameSpaceChange | ns nameSpaceName | nameSpaceName := aNameSpaceChange newNameSpaceName. (nameSpaceName includes: $.) ifTrue: [nameSpaceName := (nameSpaceName copyFrom: (nameSpaceName lastIndexOf: $.) + 1 to: nameSpaceName size) asSymbol]. ns := self itemFor: nameSpaceName. ns isNil ifTrue: [self privateRemovedItems notNil ifTrue: [self privateRemovedItems remove: nameSpaceName ifAbsent: []]. ns := RBNameSpace named: nameSpaceName model: self. self items at: nameSpaceName put: ns]. ns imports: aNameSpaceChange imports. ns isPrivate: aNameSpaceChange isPrivate. ns parcels: aNameSpaceChange parcels. ^aNameSpaceChange
changeClass: aRBClass self flushCaches
compile: aString in: aRBClass classified: aSymbol | change | change := self changes compile: aString in: aRBClass classified: aSymbol. self flushCaches. ^change
performChange: aCompositeRefactoryChange around: aBlock | oldChanges | self changes addChange: aCompositeRefactoryChange. oldChanges := self changes. self rootNameSpace changes: aCompositeRefactoryChange. aBlock ensure: [self rootNameSpace changes: oldChanges]. ^aCompositeRefactoryChange
removeInstanceVariable: aString from: aRBClass ^self changes removeInstanceVariable: aString from: aRBClass
removeMethod: aSelector from: aRBClass self flushCaches. ^self changes removeMethod: aSelector from: aRBClass
renameInstanceVariable: oldName to: newName in: aRBClass ^self changes addChange: (RenameInstanceVariableChange rename: oldName to: newName in: aRBClass)
replaceClassNameIn: definitionString to: aReference | parseTree | parseTree := RBParser parseExpression: definitionString. parseTree arguments at: 2 put: (RBLiteralNode value: aReference). ^parseTree formattedCode
</methods> <methods> Refactory.Browser.RBNameSpace <category>changes</category>
defineClass: aString | change | change := self changes defineClass: aString. ^(self nameSpaceNamed: change nameSpaceName) addClassFrom: change
defineNameSpace: aString | change | change := self changes defineNameSpace: aString. ^(self nameSpaceNamed: change nameSpaceName) addNameSpaceFrom: change
moveObject: anRBProgramItem toScope: anRBNamespace self changes moveObjectNamed: anRBProgramItem unambiguousName to: anRBNamespace unambiguousName. anRBNamespace items at: anRBProgramItem name put: anRBProgramItem. anRBProgramItem environment removedItems add: anRBProgramItem name. anRBProgramItem parent: anRBNamespace
renameClass: aRBClass to: aSymbol around: aBlock | change | change := RenameObjectChange rename: aRBClass unambiguousName to: aSymbol. aRBClass environment items at: aSymbol put: aRBClass. self performChange: change around: aBlock. self flushCaches. aRBClass environment removedItems add: aRBClass name. aRBClass environment items at: aRBClass name. aRBClass environment items removeKey: aRBClass name. aRBClass name: aSymbol. aRBClass isClassObject ifTrue: [aRBClass subclasses do: [:each | each superclass: aRBClass]. aRBClass metaclass subclasses do: [:each | each superclass: aRBClass metaclass]]. ^change
reparentClasses: aRBClassCollection to: newClass aRBClassCollection do: [:aClass | self defineClass: (self replaceClassNameIn: aClass definitionString to: (newClass isNil ifTrue: [nil] ifFalse: [newClass asReference]))]
</methods> <methods> Refactory.Browser.RBNameSpace <category>accessing</category>
definitionString | definitionStream | definitionStream := WriteStream on: String new. definitionStream nextPutAll: self environment unambiguousName; nextPutAll: ' defineNameSpace: #'; nextPutAll: self name; cr; tab; nextPutAll: 'private: '; nextPutAll: isPrivate printString; cr; tab; nextPutAll: 'imports: '''. self imports do: [:each | each printDefinitionOn: definitionStream] separatedBy: [definitionStream cr; tab]. definitionStream nextPutAll: ''''; cr; tab; nextPutAll: 'category: '''''. ^definitionStream contents
</methods> <methods> Refactory.Browser.RBNameSpace <category>printing</category>
printOn: aStream aStream nextPutAll: '[RB]'; nextPutAll: self fullName
</methods> <methods> Refactory.Browser.RBNameSpace class <category>instance creation</category>
onBinding: aBinding ^(self new) realBinding: aBinding; yourself
</methods> <methods> Refactory.Browser.Condition <category>printing</category>
printOn: aStream type printOn: aStream
</methods> <methods> Refactory.Browser.Condition <category>initialize-release</category>
errorBlock: anObject errorBlock := anObject
type: aSymbol block: aBlock errorString: aString type := aSymbol. block := aBlock. self errorMacro: aString
withBlock: aBlock block := aBlock. type := #(#generic)
</methods> <methods> Refactory.Browser.Condition <category>checking</category>
check ^block value
</methods> <methods> Refactory.Browser.Condition <category>accessing</category>
errorBlockFor: aBoolean ^errorBlock
</methods> <methods> Refactory.Browser.Condition class <category>instance creation</category>
canReference: aString in: aRBNameSpace ^self new type: (Array with: #isGlobal with: aString) block: [aRBNameSpace notNil and: [aRBNameSpace canReference: aString]] errorString: ((#x1sExistsORdoesnotInNameSpace << #browser >> '<1s> %<1?already exists :does not exist %>in the name space') expandMacrosWith: aString)
canUnderstand: aSelector in: aClass ^(self new) type: (Array with: #understandsSelector with: aClass with: aSelector) block: [aClass definesMethod: aSelector] errorString: ((#x1sQundestandsQ2s << #browser >> '<1s> %<1?:does not %>understand%<1?s:%> <2s>') expandMacrosWith: aClass printString with: aSelector printString); yourself
definesInstanceVariable: aString in: aClass ^self new type: (Array with: #definesInstVar with: aClass with: aString) block: [aClass definesInstanceVariable: aString] errorString: ((#x1sQdefinesQInstVar2s << #browser >> '<1s> %<1?:does not %>define%<1?s:%> instance variable <2s>') expandMacrosWith: aClass printString with: aString)
definesSelector: aSelector in: aClass ^(self new) type: (Array with: #definesSelector with: aClass with: aSelector) block: [aClass directlyDefinesMethod: aSelector] errorString: ((#x1sQdoesnotdefineQ2s << #browser >> '<1s> %<1?:does not %>define%<1?s:%> <2s>') expandMacrosWith: aClass printString with: aSelector printString); yourself
definesVariable: aString in: aClass ^(self new) type: (Array with: #definesVar with: aClass with: aString) block: [aClass definesVariable: aString] errorString: ((#x1sQdoesnotdefineQVariable2s << #browser >> '<1s> %<1?:does not %>define%<1?s:%> variable <2s>') expandMacrosWith: aClass printString with: aString); yourself
directlyDefinesInstanceVariable: aString in: aClass ^(self new) type: (Array with: #directlyDefinesInstanceVariable with: aClass with: aString) block: [aClass directlyDefinesInstanceVariable: aString] errorString: ((#x1sQdoesnotdirectlydefineQinstVar2s << #browser >> '<1s> %<1?:does not %>directly define%<1?s:%> instance variable <2s>') expandMacrosWith: aClass printString with: aString); yourself
empty "Returns an empty condition" ^self new type: (Array with: #empty) block: [true] errorString: (#Empty << #browser >> 'Empty') asString
hasSuperclass: aClass ^self new type: (Array with: #hasSuperclass with: aClass) block: [aClass superclass isNil not] errorString: ((#x1sHasQnoQsuperclass << #browser >> '<1s> has %<1?a:no%> superclass') expandMacrosWith: aClass printString)
hierarchyOf: aClass canAccessVariableNamed: aString ^self new type: (Array with: #hierarchyCanAccessVariable with: aClass with: aString) block: [aClass hierarchyCanAccessVariableNamed: aString] errorString: ((#x1sOrSubclassDoesNotDefineVar2s << #browser >> '<1s> or one of its subclasses %<1?:does not %>define%<1?s:%> variable <2s>') expandMacrosWith: aClass printString with: aString)
hierarchyOf: aClass canUnderstand: aSelector ^(self new) type: (Array with: #hierarchyUnderstandsSelector with: aClass with: aSelector) block: [aClass hierarchyDefinesMethod: aSelector] errorString: ((#x1sQorsubclassORallsubclassesQdoNotUnderstand2s << #browser >> '<1s> %<1?or a subclass:and all subclasses do not%> understand%<1?s:%> <2s>') expandMacrosWith: aClass printString with: aSelector printString); yourself
hierarchyOf: aClass definesVariable: aString ^self new type: (Array with: #hierarchyDefinesInstVar with: aClass with: aString) block: [aClass hierarchyDefinesVariable: aString] errorString: ((#x1sOrSubclassDoesNotDefineVar2s << #browser >> '<1s> or one of its subclasses %<1?:does not %>define%<1?s:%> variable <2s>') expandMacrosWith: aClass printString with: aString)
hierarchyOf: aClass referencesInstanceVariable: aString ^self new type: (Array with: #hierarchyReferencesInstVar with: aClass with: aString) block: [aClass withAllSubclasses anySatisfy: [:each | (each whichSelectorsReferToInstanceVariable: aString) notEmpty]] errorString: ((#x1sOrSubclassQdoesnotQreferenceInstVar2s << #browser >> '<1s> or subclass %<1?:does not %>reference%<1?s:%> instance variable <2s>') expandMacrosWith: aClass printString with: aString)
isAbstractClass: aClass ^self new type: (Array with: #IsAbstractClass with: aClass) block: [aClass isAbstract] errorString: ((#x1sIsQnotQAbstract << #browser >> '<1s> is %<1?:not %>an abstract class') expandMacrosWith: aClass printString)
isImmediateSubclass: subclass of: superClass ^(self new) type: (Array with: #immediateSubclass with: superClass with: subclass) block: [subclass superclass = superClass] errorString: ((#x1sIsQnotQimmediateSubclassOf2s << #browser >> '<1s> is %<1?:not %>an immediate subclass of <2s>') expandMacrosWith: subclass printString with: superClass printString); yourself
isMetaclass: anObject ^(self new) type: (Array with: #IsMetaclass with: anObject) block: [anObject isMeta] errorString: ((#x1sIsQnotQAMetaclass << #browser >> '<1s> is %<1?:not %>a metaclass') expandMacrosWith: anObject printString); yourself
isSymbol: aString ^(self new) type: (Array with: #isSymbol with: aString) block: [aString isSymbol] errorString: ((#x1sIs1notASymbol << #browser >> '<1s> is %<1?:not %>a symbol') expandMacrosWith: aString); yourself
isValidClassName: aString ^(self new) type: (Array with: #validClassName with: aString) block: [self validClassName: aString] errorString: ((#x1sIs1notAValidClassName << #browser >> '<1s> is %<1?:not %>a valid class name') expandMacrosWith: aString); yourself
isValidInstanceVariableName: aString for: aClass ^self new type: (Array with: #validInstVarName with: aString with: aClass) block: [self checkInstanceVariableName: aString in: aClass] errorString: ((#x1sIs1notAValidInstVarName << #browser >> '<1s> is %<1?:not %>a valid instance variable name') expandMacrosWith: aString)
isValidMethodName: aString for: aClass ^(self new) type: (Array with: #validMethodName with: aString with: aClass) block: [self checkMethodName: aString in: aClass] errorString: ((#x1sIsNotValidMethodName << #browser >> '<1s> is %<1?:not %>a valid method name') expandMacrosWith: aString printString); yourself
referencesInstanceVariable: aString in: aClass ^(self new) type: (Array with: #referencesInstVar with: aClass with: aString) block: [(aClass whichSelectorsReferToInstanceVariable: aString) notEmpty] errorString: ((#x1s1doesNotReferenceInstVar2s << #browser >> '<1s> %<1?:does not %>reference%<1?s:%> instance variable <2s>') expandMacrosWith: aClass printString with: aString); yourself
subclassesOf: aClass referToSelector: aSelector ^self new type: (Array with: #subclassReferences with: aClass with: aSelector) block: [aClass subclasses anySatisfy: [:each | each selectors anySatisfy: [:sel | | tree | tree := each parseTreeFor: sel. tree notNil and: [tree superMessages includes: aSelector]]]] errorString: ((#x1noORaSubclassRefersTo2s << #browser >> '%<1?:no:a%> subclass of <1s> refers to <2s>') expandMacrosWith: aClass printString with: aSelector printString)
withBlock: aBlock ^(self new) withBlock: aBlock; yourself
withBlock: aBlock errorString: aString ^(self new) type: #unknown block: aBlock errorString: aString; yourself
</methods> <methods> Refactory.Browser.Condition class <category>utilities</category>
checkInstanceVariableName: aName in: aClass | string | aName isString ifFalse: [^false]. string := aName asString. string isEmpty ifTrue: [^false]. (self reservedNames includes: string) ifTrue: [^false]. string first isUppercase ifTrue: [^false]. ^RBScanner isVariable: string
checkMethodName: aName in: aClass ^aName isString and: [RBScanner isSelector: aName]
reservedNames ^#('self' 'true' 'false' 'nil' 'thisContext' 'super')
validClassName: aString "Class names and class variable names have the same restrictions" | string | aString isString ifFalse: [^false]. string := aString asString. (string includes: $.) ifTrue: [^false]. (self reservedNames includes: string) ifTrue: [^false]. string isEmpty ifTrue: [^false]. string first isLowercase ifTrue: [^false]. ^RBScanner isVariable: string
</methods> <methods> Refactory.Browser.RBNegationCondition <category>checking</category>
check ^condition check not
</methods> <methods> Refactory.Browser.RBNegationCondition <category>initialize-release</category>
condition: aCondition condition := aCondition. self errorMacro: condition errorMacro
</methods> <methods> Refactory.Browser.RBNegationCondition <category>private</category>
errorBlockFor: aBoolean ^condition errorBlockFor: aBoolean not
errorStringFor: aBoolean ^condition errorStringFor: aBoolean not
</methods> <methods> Refactory.Browser.RBNegationCondition <category>printing</category>
printOn: aStream aStream nextPutAll: 'NOT '; print: condition
</methods> <methods> Refactory.Browser.RBNegationCondition class <category>instance creation</category>
on: aCondition ^(self new) condition: aCondition; yourself
</methods> <methods> Refactory.Browser.ChildrenToSiblingsRefactoring <category>transforming</category>
addSuperclass | newClass | self performComponentRefactoring: (AddClassRefactoring model: self model addClass: className superclass: parent superclass subclasses: (Array with: parent) category: nil). newClass := self abstractSuperclass. parent imports do: [:each | newClass addImport: each]
changeIsKindOfReferences | replacer | replacer := (ParseTreeRewriter new) replace: '``@rcv isKindOf: ' , parent name with: '``@rcv isKindOf: ' , self definitionName when: [:node | self methodClass canAccess: parent]; replace: '``@rcv isKindOf: `var' withValueFrom: [:aNode | aNode arguments: (Array with: (self replaceFullReferenceTo: parent inVariable: aNode arguments first toBe: self definitionName)). aNode] when: [:node | (node arguments first name includes: $.) and: [self methodClass doesName: node arguments first name includeObject: parent]]; replaceArgument: self definitionName withValueFrom: [:aNode | self refactoringError: ((#x1sAlreadyExistsInScope << #browser >> '<1s> already exists within the reference scope') expandMacrosWith: self definitionName)]; yourself. self convertAllReferencesToObject: parent using: replacer
pushUpMethods self pushUpMethodsFrom: parent. self pushUpMethodsFrom: parent metaclass
pushUpVariables self pullUpInstanceVariables. self pullUpClassInstanceVariables. self pullUpSharedVariables
reparentSubclasses self model reparentClasses: subclasses to: self abstractSuperclass
transform self addSuperclass; pushUpVariables; pushUpMethods; changeIsKindOfReferences; reparentSubclasses
</methods> <methods> Refactory.Browser.ChildrenToSiblingsRefactoring <category>private-methods</category>
computeSubclassSupersOf: aClass | selectors | selectors := Set new. aClass subclasses do: [:each | each selectors do: [:sel | selectors addAll: (each parseTreeFor: sel) superMessages]]. ^selectors
createSubclassResponsibilityFor: aSelector in: aClass | source | (aClass superclass definesMethod: aSelector) ifTrue: [^self]. source := self subclassResponsibilityFor: aSelector in: aClass. source isNil ifTrue: [^self]. aClass superclass compile: source withAttributesFrom: (aClass methodFor: aSelector)
pushUp: aSelector in: aClass | source | source := aClass sourceCodeFor: aSelector. source isNil ifFalse: [aClass superclass compile: source withAttributesFrom: (aClass methodFor: aSelector)]
pushUpMethodsFrom: aClass | selectorsToPushUp | selectorsToPushUp := self selectorsToPushUpFrom: aClass. aClass selectors do: [:each | (selectorsToPushUp includes: each) ifTrue: [self pushUp: each in: aClass] ifFalse: [self createSubclassResponsibilityFor: each in: aClass]]. selectorsToPushUp do: [:each | aClass removeMethod: each]
selectorsToPushUpFrom: aClass | superSelectors | superSelectors := self computeSubclassSupersOf: aClass. ^aClass selectors select: [:each | (superSelectors includes: each) or: [self shouldPushUp: each from: aClass]]
shouldPushUp: aSelector from: aClass ^(aClass isMeta ifTrue: [subclasses collect: [:each | each metaclass]] ifFalse: [subclasses]) anySatisfy: [:each | (each directlyDefinesMethod: aSelector) not]
subclassResponsibilityFor: aSelector in: aClass | methodNode position source | source := aClass sourceCodeFor: aSelector. methodNode := RBParser parseMethod: source onError: [:err :pos | ^nil]. position := methodNode arguments isEmpty ifTrue: [methodNode selectorParts last stop] ifFalse: [methodNode arguments last stop]. ^'<1s><n><t>self subclassResponsibility' expandMacrosWith: (source copyFrom: 1 to: position)
</methods> <methods> Refactory.Browser.ChildrenToSiblingsRefactoring <category>initialize-release</category>
name: aClassName class: aClass subclasses: subclassCollection className := aClassName asSymbol. parent := self model classFor: aClass. subclasses := subclassCollection collect: [:each | self model classFor: each]
</methods> <methods> Refactory.Browser.ChildrenToSiblingsRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Convert children to siblings refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' name: #'''; nextPutAll: className; nextPutAll: ''' class: '. parent storeOn: aStream. aStream nextPutAll: ' subclasses: '. subclasses asArray storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.ChildrenToSiblingsRefactoring <category>private-variables</category>
pullUpClassInstanceVariables | newSuperclass | newSuperclass := self abstractSuperclass metaclass. parent metaclass instanceVariableNames do: [:each | self performComponentRefactoring: (PullUpInstanceVariableRefactoring model: self model variable: each class: newSuperclass)]
pullUpInstanceVariables | newSuperclass | newSuperclass := self abstractSuperclass. parent instanceVariableNames do: [:each | self performComponentRefactoring: (PullUpInstanceVariableRefactoring model: self model variable: each class: newSuperclass)]
pullUpSharedVariables | newSuperclass | newSuperclass := self abstractSuperclass. parent sharedVariableNames do: [:each | | sv definition | sv := parent referencedItem: each. definition := RBParser parseExpression: sv definitionString. self model removeObject: sv. definition receiver: (RBVariableNode named: newSuperclass unambiguousName). self model defineSharedVariable: definition formattedCode]
</methods> <methods> Refactory.Browser.ChildrenToSiblingsRefactoring <category>private-accessing</category>
abstractSuperclass ^self model classNamed: className
</methods> <methods> Refactory.Browser.ChildrenToSiblingsRefactoring <category>preconditions</category>
preconditions ^subclasses inject: ((Condition isMetaclass: parent) errorMacro: (#SuperMustNotBeMeta << #browser >> 'Superclass must not be a metaclass') asString) not into: [:sub :each | sub & ((Condition isMetaclass: each) errorMacro: (#SubMust1QBeMeta << #browser >> 'Subclass must <1?not :>be a metaclass') asString) not & (Condition isImmediateSubclass: each of: parent)]
</methods> <methods> Refactory.Browser.ChildrenToSiblingsRefactoring class <category>instance creation</category>
model: aRBNameSpace name: aClassName class: aClass subclasses: subclassCollection ^(self new) model: aRBNameSpace; name: aClassName class: aClass subclasses: subclassCollection; yourself
name: aClassName class: aClass subclasses: subclassCollection ^(self new) name: aClassName class: aClass subclasses: subclassCollection; yourself
</methods> <methods> Refactory.Browser.RefactoringManager <category>public access</category>
addRefactoring: aRefactoring RefactoryChangeManager instance performChange: aRefactoring changes. refactorings add: aRefactoring class name
</methods> <methods> Refactory.Browser.RefactoringManager <category>initialize-release</category>
initialize refactorings := Bag new
</methods> <methods> Refactory.Browser.RefactoringManager <category>printing</category>
printOn: aStream aStream nextPutAll: '# Refactoring'; cr; nextPutAll: '--- -----------------------------------------------'; cr. refactorings asSet asSortedCollection do: [:name | aStream nextPutAll: (refactorings occurrencesOf: name) printString; nextPutAll: ' '; nextPutAll: name; cr]
</methods> <methods> Refactory.Browser.RefactoringManager class <category>instance creation</category>
instance Instance isNil ifTrue: [Instance := self basicNew. Instance initialize]. ^Instance
new ^self shouldNotImplement
</methods> <methods> Refactory.Browser.RefactoringManager class <category>public access</category>
nuke Instance notNil ifTrue: [Instance release]. Instance := nil
</methods> <methods> Refactory.Browser.RefactoringManager class <category>parcel load/unload/save</category>
preUnloadActionFor: aParcel ^self nuke
</methods> <methods> Refactory.Browser.ExtractToTemporaryRefactoring <category>preconditions</category>
checkVariableName (class whoDefinesInstanceVariable: newVariableName) notNil ifTrue: [self refactoringError: (#x1pDefinesInstVar2s << #browser >> '<1p> defines an instance variable named <2s>' expandMacrosWith: class with: newVariableName)]. (self sourceTree allDefinedVariables includes: newVariableName) ifTrue: [self refactoringError: (#x1sIsAlreadyTempName << #browser >> '<1s> is already a temporary variable name' expandMacrosWith: newVariableName)]
preconditions ^(Condition definesSelector: selector in: class) & (Condition isValidInstanceVariableName: newVariableName for: class) & (Condition withBlock: [self verifySelectedInterval. self checkVariableName. true])
verifySelectedInterval | selectedParseTree selectedSources | selectedSources := self selectedSource. selectedParseTree := RBParser parseExpression: selectedSources onError: [:message :position | self refactoringError: (#InvalidSelection << #browser >> 'Invalid selection')]. selectedParseTree isSequence ifTrue: [self refactoringError: (#CannotAssignTempToMultiple << #browser >> 'Cannot assign temp to multiple statements')]
</methods> <methods> Refactory.Browser.ExtractToTemporaryRefactoring <category>transforming</category>
compileNewMethod class compileTree: self sourceTree
constructAssignmentFrom: aNode | valueNode | valueNode := RBVariableNode named: newVariableName. ^RBAssignmentNode variable: valueNode value: aNode
insertTemporary | node statementNode | node := self sourceTree whichNodeIsContainedBy: sourceInterval. (node notNil and: [node isValue]) ifFalse: [self refactoringError: #CannotAssignToNonValueNodes << #browser >> 'Cannot assign to non-value nodes']. statementNode := node statementNode. node replaceWith: (RBVariableNode named: newVariableName). (statementNode parent) addNode: (self constructAssignmentFrom: node) before: (node == statementNode ifTrue: [RBVariableNode named: newVariableName] ifFalse: [statementNode]); addTemporaryNamed: newVariableName
transform self insertTemporary; compileNewMethod
</methods> <methods> Refactory.Browser.ExtractToTemporaryRefactoring <category>initialize-release</category>
extract: anInterval to: aString from: aSelector in: aClass class := self classObjectFor: aClass. selector := aSelector. sourceInterval := anInterval. newVariableName := aString
</methods> <methods> Refactory.Browser.ExtractToTemporaryRefactoring <category>private-accessing</category>
selectedSource | source | source := self sourceTree source. source isNil ifTrue: [self refactoringError: #CouldntFindSources << #browser >> 'Couldn''t find sources']. ((sourceInterval first between: 1 and: source size) and: [sourceInterval last between: 1 and: source size]) ifFalse: [self refactoringError: #InvalidInterval << #browser >> 'Invalid interval']. ^source copyFrom: sourceInterval first to: sourceInterval last
sourceTree ^sourceTree ifNil: [sourceTree := class parseTreeFor: selector]
sourceTree: aParseTree sourceTree := aParseTree
</methods> <methods> Refactory.Browser.ExtractToTemporaryRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Extract to temporary refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' extract: '. sourceInterval storeOn: aStream. aStream nextPutAll: ' to: '''; nextPutAll: newVariableName; nextPutAll: ''' from: #'; nextPutAll: selector; nextPutAll: ' in: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.ExtractToTemporaryRefactoring class <category>instance creation</category>
extract: anInterval to: aString from: aSelector in: aClass ^(self new) extract: anInterval to: aString from: aSelector in: aClass; yourself
model: aRBNameSpace extract: anInterval to: aString from: aSelector in: aClass ^(self new) model: aRBNameSpace; extract: anInterval to: aString from: aSelector in: aClass; yourself
</methods> <methods> Refactory.Browser.CreateAccessorsForVariableRefactoring <category>transforming</category>
createGetterAccessor getterMethod := self findGetterMethod. getterMethod isNil ifTrue: [getterMethod := self defineGetterMethod]
createSetterAccessor setterMethod := self findSetterMethod. setterMethod isNil ifTrue: [setterMethod := self defineSetterMethod]
defineGetterMethod | selector definingClass | definingClass := self definingClass. selector := self safeMethodNameFor: definingClass basedOn: variableName asString. definingClass compile: ('<1s><n><t>^<2s>' expandMacrosWith: selector with: variableName) classified: #(#accessing). ^selector
defineSetterMethod | selector definingClass string | definingClass := self definingClass. string := self needsReturnForSetter ifTrue: ['<1s> anObject<n><t>^<2s> := anObject'] ifFalse: ['<1s> anObject<n><t><2s> := anObject']. selector := self safeMethodNameFor: definingClass basedOn: variableName asString , ':'. definingClass compile: (string expandMacrosWith: selector with: variableName) classified: #accessing. ^selector
transform self createGetterAccessor; createSetterAccessor
</methods> <methods> Refactory.Browser.CreateAccessorsForVariableRefactoring <category>private-accessing</category>
definingClass ^class
findGetterMethod | definingClass matcher | definingClass := self definingClass. matcher := ParseTreeSearcher getterMethod: variableName. ^self possibleGetterSelectors detect: [:each | (self checkClass: definingClass selector: each using: matcher) notNil and: [(definingClass subclassRedefines: each) not]] ifNone: [nil]
findSetterMethod | definingClass matcher | definingClass := self definingClass. matcher := self needsReturnForSetter ifTrue: [ParseTreeSearcher returnSetterMethod: variableName] ifFalse: [ParseTreeSearcher setterMethod: variableName]. ^self possibleSetterSelectors detect: [:each | (self checkClass: definingClass selector: each using: matcher) notNil and: [(definingClass subclassRedefines: each) not]] ifNone: [nil]
getterMethod ^getterMethod
methodsReferencingVariable ^self definingClass whichSelectorsReferToInstanceVariable: variableName
possibleGetterSelectors ^self methodsReferencingVariable select: [:each | each numArgs == 0]
possibleSetterSelectors ^self methodsReferencingVariable select: [:each | each numArgs == 1]
setterMethod ^setterMethod
</methods> <methods> Refactory.Browser.CreateAccessorsForVariableRefactoring <category>testing</category>
needsReturnForSetter needsReturn isNil ifTrue: [needsReturn := self usesAssignmentOf: variableName in: class]. ^needsReturn
usesAssignmentOf: aString in: aClass | matcher definingClass | matcher := ParseTreeSearcher new. matcher answer: false; matches: aString , ' := ``@object' do: [:aNode :answer | answer or: [aNode isUsed]]. definingClass := aClass. ^definingClass withAllSubclasses anySatisfy: [:each | (each whichSelectorsReferToInstanceVariable: aString) anySatisfy: [:sel | self checkClass: each selector: sel using: matcher]]
</methods> <methods> Refactory.Browser.CreateAccessorsForVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Create accessors refactoring'
</methods> <methods> Refactory.Browser.CreateAccessorsForVariableRefactoring <category>preconditions</category>
preconditions ^(Condition definesInstanceVariable: variableName in: class) | (Condition canReference: variableName in: class)
</methods> <methods> Refactory.Browser.RBMethod <category>accessing</category>
method ^compiledMethod
method: aCompiledMethod compiledMethod := aCompiledMethod
modelClass ^class
modelClass: aRBClass class := aRBClass
package ^Store.Registry containingPackageForSelector: selector class: self modelClass realItem
parcels ^parcels isNil ifTrue: [parcels := Parcel parcels select: [:each | each definesSelector: self selector forClass: self modelClass realClass]] ifFalse: [parcels]
parseTree ^RBParser parseMethod: self source onError: [:str :pos | ^nil]
protocols ^self modelClass protocolsFor: self selector
scope ^compiledMethod ifNil: [self modelClass environment] ifNotNil: [self modelClass rootNameSpace nameSpaceNamed: compiledMethod environment absoluteName]
selector ^selector
selector: aSymbol selector := aSymbol
source ^source isNil ifTrue: [source := compiledMethod getSource] ifFalse: [source]
source: aString source := aString
</methods> <methods> Refactory.Browser.RBMethod <category>printing</category>
printOn: aStream class printOn: aStream. aStream nextPutAll: '>>'; nextPutAll: self selector
</methods> <methods> Refactory.Browser.RBMethod <category>testing</category>
canReferenceObject: anRBProgramItem | searchScope | searchScope := self modelClass. self isPackageExtension ifTrue: [self package environment ifNotNil: [searchScope := self modelClass rootNameSpace nameSpaceNamed: compiledMethod environment absoluteName]]. ^searchScope canReferenceObject: anRBProgramItem
hasOuterVariables ^compiledMethod ifNil: [self searchSourceForOuterVariables] ifNotNil: [compiledMethod hasOuterVariables]
isPackageExtension ^self package ifNotNil: [:methodPackage | self modelClass ifNil: [false] ifNotNil: [:classPackage | classPackage == methodPackage]] ifNil: [false]
referencedItem: aString | searchScope | searchScope := self modelClass. self isPackageExtension ifTrue: [self package environment ifNotNil: [searchScope := self modelClass rootNameSpace nameSpaceNamed: compiledMethod environment absoluteName]]. ^searchScope referencedItem: aString
refersToClassReference: aRBClass | searcher | searcher := ParseTreeSearcher new. searcher matches: '`#literal' do: [:node :answer | answer or: [self modelClass checkLiteral: node value references: aRBClass]]. ^searcher executeTree: self parseTree initialAnswer: false
refersToObject: aRBProgramItem | searcher | searcher := ParseTreeSearcher new. searcher matches: '`var' do: [:node :answer | answer or: [self modelClass doesName: node name includeObject: aRBProgramItem]]. ^(searcher executeTree: self parseTree initialAnswer: false) or: [self refersToClassReference: aRBProgramItem]
refersToSymbol: aSymbol | searcher | searcher := ParseTreeSearcher new. searcher matches: aSymbol printString do: [:node :answer | true]; matches: '`#literal' do: [:node :answer | answer or: [self literal: node value containsReferenceTo: aSymbol]]. (RBScanner isSelector: aSymbol) ifTrue: [searcher matches: '`@object ' , (ParseTreeSearcher buildSelectorString: aSymbol) do: [:node :answer | true]]. ^searcher executeTree: self parseTree initialAnswer: false
refersToVariable: aString | searcher tree | tree := self parseTree. ((tree defines: aString) or: [tree body defines: aString]) ifTrue: [^false]. searcher := ParseTreeSearcher new. searcher matches: aString do: [:node :answer | true]; matches: '[:`@vars | | `@temps | `@.Stmts]' do: [:node :answer | answer or: [((node defines: aString) or: [node body defines: aString]) not and: [searcher executeTree: node body initialAnswer: false]]]. ^searcher executeTree: self parseTree initialAnswer: false
</methods> <methods> Refactory.Browser.RBMethod <category>private</category>
literal: anObject containsReferenceTo: aSymbol anObject = aSymbol ifTrue: [^true]. anObject class = Array ifFalse: [^false]. ^anObject anySatisfy: [:each | self literal: each containsReferenceTo: aSymbol]
searchSourceForOuterVariables | searcher | searcher := ParseTreeSearcher new. searcher matches: '`var' do: [:node :answer | answer or: [(node whoDefines: node name) isNil and: [(self modelClass definesInstanceVariable: node name) not]]]. ^searcher executeTree: self parseTree initialAnswer: false
</methods> <methods> Refactory.Browser.RBMethod <category>compiling</category>
compileTree: aBRMethodNode | method sourceCode change oldChange | oldChange := self modelClass isMeta ifTrue: [self modelClass rootNameSpace changes changeForMetaclass: self modelClass nonMetaclass fullName selector: self selector] ifFalse: [self modelClass rootNameSpace changes changeForClass: self modelClass fullName selector: self selector]. sourceCode := aBRMethodNode newSource. change := self modelClass environment compile: sourceCode in: self modelClass classified: self protocols. change copyAttributesFrom: self selector. oldChange notNil ifTrue: [change parcels: oldChange parcels. change package: oldChange package]. method := self class for: self modelClass source: sourceCode selector: aBRMethodNode selector. self modelClass addMethod: method. ^change
</methods> <methods> Refactory.Browser.RBMethod <category>compatibility</category>
environment ^compiledMethod ifNil: [self modelClass environment] ifNotNil: [self modelClass rootNameSpace nameSpaceNamed: compiledMethod environment absoluteName]
</methods> <methods> Refactory.Browser.RBMethod class <category>instance creation</category>
for: aRBClass fromMethod: aCompiledMethod andSelector: aSymbol ^(self new) modelClass: aRBClass; method: aCompiledMethod; selector: aSymbol; yourself
for: aRBClass source: aString selector: aSelector ^(self new) modelClass: aRBClass; selector: aSelector; source: aString; yourself
</methods> <methods> Refactory.Browser.RBInitializerMethod <category>compiling</category>
compileTree: aRBProgramNode sharedVariable initializer: aRBProgramNode formattedCode. ^self modelClass defineSharedVariable: sharedVariable definitionString
</methods> <methods> Refactory.Browser.RBInitializerMethod <category>accessing</category>
parseTree ^RBParser parseExpression: self source onError: [:str :pos | ^nil]
sharedVariable ^sharedVariable
sharedVariable: aRBSharedVariable sharedVariable := aRBSharedVariable
</methods> <methods> Refactory.Browser.RBInitializerMethod class <category>instance creation</category>
for: anRBStatic fromMethod: aCompiledMethod ^(self new) modelClass: anRBStatic environment; sharedVariable: anRBStatic; method: aCompiledMethod; selector: #'static Initializer Method for ' , anRBStatic name; yourself
for: anRBStatic source: aString ^(self new) modelClass: anRBStatic environment; sharedVariable: anRBStatic; source: aString; selector: #'static Initializer Method for ' , anRBStatic name; yourself
</methods> <methods> Refactory.Browser.PushDownInstanceVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Push down instance variable refactoring'
</methods> <methods> Refactory.Browser.PushDownInstanceVariableRefactoring <category>transforming</category>
transform | classesToPushInto | class removeInstanceVariable: variableName. classesToPushInto := class subclasses reject: [:each | each withAllSubclasses allSatisfy: [:aClass | (aClass whichSelectorsReferToInstanceVariable: variableName) isEmpty]]. classesToPushInto isEmpty ifTrue: [self refactoringWarning: (#PushingDownWillRemoveVariableProceedQ << #browser >> 'None of the subclasses use this variable.<n>Pushing down will remove it. Proceed?') expandMacros]. classesToPushInto do: [:each | each addInstanceVariable: variableName]
</methods> <methods> Refactory.Browser.PushDownInstanceVariableRefactoring <category>preconditions</category>
preconditions | references | references := Condition referencesInstanceVariable: variableName in: class. class realClass isNil ifTrue: [references errorMacro: ((#x1sIsReferenced << #browser >> '<1s> is referenced.') expandMacrosWith: variableName)] ifFalse: [references errorMacro: ((#x1sIsReferencedBrowseQ << #browser >> '<1s> is referenced.<n>Browse references?') expandMacrosWith: variableName); errorBlock: [self openBrowserOn: (BrowserEnvironment new instVarRefsTo: variableName in: class realClass)]]. ^(Condition definesInstanceVariable: variableName in: class) & references not
</methods> <methods> Refactory.Browser.CompositeRefactoring <category>transforming</category>
transform refactorings do: [:each | self performComponentRefactoring: each]
</methods> <methods> Refactory.Browser.CompositeRefactoring <category>preconditions</category>
preconditions "Preconditions are checked on the component refactorings." ^Condition empty
</methods> <methods> Refactory.Browser.CompositeRefactoring <category>initialize-release</category>
initialize super initialize. refactorings := #()
refactorings: aCollection | oldName | oldName := self printString. refactorings := aCollection. (model notNil and: [model description = oldName]) ifTrue: [model description: self printString]
</methods> <methods> Refactory.Browser.CompositeRefactoring <category>printing</category>
printOn: aStream refactorings isEmpty ifTrue: [^super printOn: aStream]. refactorings first printOn: aStream
</methods> <methods> Refactory.Browser.RenameTemporaryRefactoring <category>initialize-release</category>
class: aClass selector: aSelector interval: anInterval newName: aString class := self classObjectFor: aClass. selector := aSelector. interval := anInterval. newName := aString
</methods> <methods> Refactory.Browser.RenameTemporaryRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Rename temporary refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' renameTemporaryFrom: '. interval storeOn: aStream. aStream nextPutAll: ' to: '''; nextPutAll: newName; nextPutAll: ''' in: '. class storeOn: aStream. aStream nextPutAll: ' selector: #'; nextPutAll: selector. aStream nextPut: $)
</methods> <methods> Refactory.Browser.RenameTemporaryRefactoring <category>tranforming</category>
renameNode: aParseTree (aParseTree whoDefines: newName) notNil ifTrue: [self refactoringError: ((#x1sIsAlreadyDefined << #browser >> '<1s> is already defined') expandMacrosWith: newName)]. (aParseTree allDefinedVariables includes: newName) ifTrue: [self refactoringError: ((#x1sIsAlreadyDefined << #browser >> '<1s> is already defined') expandMacrosWith: newName)]. (ParseTreeRewriter rename: oldName to: newName) executeTree: aParseTree
</methods> <methods> Refactory.Browser.RenameTemporaryRefactoring <category>preconditions</category>
preconditions ^(Condition definesSelector: selector in: class) & (Condition isValidInstanceVariableName: newName for: class) & (Condition definesVariable: newName in: class) not & (Condition withBlock: [| methodSource | interval first > interval last ifTrue: [self refactoringError: #InvalidVariableName << #browser >> 'Invalid variable name']. methodSource := self sourceTree source. methodSource size >= interval last ifFalse: [self refactoringError: #InvalidRangeForVariable << #browser >> 'Invalid range for variable']. oldName := (methodSource copyFrom: interval first to: interval last) asString. true])
</methods> <methods> Refactory.Browser.RenameTemporaryRefactoring <category>accessing</category>
sourceTree ^sourceTree ifNil: [sourceTree := class parseTreeFor: selector]
sourceTree: aParseTree sourceTree := aParseTree
</methods> <methods> Refactory.Browser.RenameTemporaryRefactoring <category>transforming</category>
transform | definingNode variableNode | variableNode := self whichVariableNode: self sourceTree inInterval: interval name: oldName. (variableNode isNil or: [variableNode isVariable not]) ifTrue: [self refactoringError: (#x1sIsntAValidVariable << #browser >> '<1s> isn''t a valid variable' expandMacrosWith: oldName)]. variableNode name = oldName ifFalse: [self refactoringError: #InvalidSelection << #browser >> 'Invalid selection']. definingNode := variableNode whoDefines: oldName. definingNode isNil ifTrue: [self refactoringError: (#x1sIsNotDefinedByMethod << #browser >> '<1s> isn''t defined by the method' expandMacrosWith: oldName)]. self renameNode: definingNode. class compileTree: self sourceTree
</methods> <methods> Refactory.Browser.RenameTemporaryRefactoring class <category>instance creation</category>
model: aRBNameSpace renameTemporaryFrom: anInterval to: newName in: aClass selector: aSelector ^(self new) model: aRBNameSpace; class: aClass selector: aSelector interval: anInterval newName: newName; yourself
renameTemporaryFrom: anInterval to: newName in: aClass selector: aSelector ^(self new) class: aClass selector: aSelector interval: anInterval newName: newName; yourself
</methods> <methods> Refactory.Browser.RBMetaclass <category>accessing</category>
fullName ^super fullName , ' class'
imports ^nonMetaclass imports
metaclass ^self
nonMetaclass ^nonMetaclass
parcels ^nonMetaclass parcels
unambiguousName ^self nonMetaclass unambiguousName , ' class'
</methods> <methods> Refactory.Browser.RBMetaclass <category>testing</category>
isMeta ^true
</methods> <methods> Refactory.Browser.RBMetaclass <category>initialize-release</category>
nonMetaclass: aRBClass aRBClass metaclass: self. nonMetaclass := aRBClass. binding := aRBClass binding. (superclass isNil and: [self isDefined]) ifTrue: [superclass := LookupSuperclass]
</methods> <methods> Refactory.Browser.RBMetaclass <category>printing</category>
printOn: aStream super printOn: aStream. aStream nextPutAll: ' class'
storeOn: aStream super storeOn: aStream. aStream nextPutAll: ' class'
</methods> <methods> Refactory.Browser.RBMetaclass <category>private</category>
realItem | class | class := super realItem. ^class isNil ifTrue: [nil] ifFalse: [class class]
recompileObject self nonMetaclass recompileObject
</methods> <methods> Refactory.Browser.RBMetaclass <category>private-accessing</category>
items ^self nonMetaclass items
privateItems ^self nonMetaclass privateItems
privateRemovedItems ^self nonMetaclass privateRemovedItems
</methods> <methods> Refactory.Browser.RBMetaclass <category>accessing-objects</category>
referencedItem: aString ^self nonMetaclass referencedItem: aString
</methods> <methods> Refactory.Browser.RBMetaclass class <category>instance creation</category>
newOn: aRBClass model: aRBBasicNameSpace ^(self new) name: aRBClass name; parent: aRBBasicNameSpace; nonMetaclass: aRBClass; yourself
</methods> <methods> Refactory.Browser.ExtractMethodToComponentRefactoring <category>initialize-release</category>
extract: anInterval from: aSelector in: aClass class := self classObjectFor: aClass. selector := aSelector. extractionInterval := anInterval
</methods> <methods> Refactory.Browser.ExtractMethodToComponentRefactoring <category>transforming</category>
extractMethod | refactoring | refactoring := ExtractMethodRefactoring model: self model extract: extractionInterval from: selector in: class. refactoring sourceTree: sourceTree. refactoring setOption: #methodName toUse: [:ref :methodName | extractedMethodSelector := ref uniqueMethodNameFor: methodName arguments size. methodName selector: extractedMethodSelector; yourself]. self performComponentRefactoring: refactoring
inlineForwarder | refactoring | refactoring := InlineAllSelfSendersRefactoring model: self model sendersOf: extractedMethodSelector in: class. refactoring setOption: #inlineExpression toUse: [:ref :string | true]. self performComponentRefactoring: refactoring
moveMethod | variable refactoring | variable := self selectVariableToMoveMethodTo: extractedMethodSelector class: class. variable isNil ifTrue: [self refactoringError: (#DidNotExtractMethod << #browser >> 'Did not extract method')]. refactoring := MoveMethodRefactoring model: self model selector: extractedMethodSelector class: class variable: variable. self performComponentRefactoring: refactoring
transform self extractMethod; moveMethod; inlineForwarder
</methods> <methods> Refactory.Browser.ExtractMethodToComponentRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Extract method to component refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' extract: '. extractionInterval storeOn: aStream. aStream nextPutAll: ' from: #'; nextPutAll: selector; nextPutAll: ' in: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.ExtractMethodToComponentRefactoring <category>preconditions</category>
preconditions ^Condition empty
</methods> <methods> Refactory.Browser.ExtractMethodToComponentRefactoring <category>accessing</category>
sourceTree ^sourceTree ifNil: [sourceTree := class parseTreeFor: selector]
sourceTree: aParseTree sourceTree := aParseTree
</methods> <methods> Refactory.Browser.ExtractMethodToComponentRefactoring class <category>instance creation</category>
extract: anInterval from: aSelector in: aClass ^(self new) extract: anInterval from: aSelector in: aClass; yourself
model: aRBNameSpace extract: anInterval from: aSelector in: aClass ^(self new) model: aRBNameSpace; extract: anInterval from: aSelector in: aClass; yourself
</methods> <methods> Refactory.Browser.ProtectInstanceVariableRefactoring <category>private-accessing</category>
getterSetterMethods | matcher | matcher := ParseTreeSearcher new. matcher answer: Set new; matchesAnyMethodOf: (Array with: '`method ^' , variableName with: ('`method: `arg <1s> := `arg' expandMacrosWith: variableName) with: ('`method: `arg ^<1s> := `arg' expandMacrosWith: variableName)) do: [:aNode :answer | (class subclassRedefines: aNode selector) ifFalse: [answer add: aNode selector]. answer]. (class whichSelectorsReferToInstanceVariable: variableName) do: [:each | self checkClass: class selector: each using: matcher]. ^matcher answer
</methods> <methods> Refactory.Browser.ProtectInstanceVariableRefactoring <category>transforming</category>
inline: aSelector self onError: [self performComponentRefactoring: (InlineAllSelfSendersRefactoring model: self model sendersOf: aSelector in: class)] do: []
transform self setOption: #inlineExpression toUse: [:ref :string | true]. self getterSetterMethods do: [:each | self inline: each]
</methods> <methods> Refactory.Browser.ProtectInstanceVariableRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Protect instance variable refactoring'
</methods> <methods> Refactory.Browser.ProtectInstanceVariableRefactoring <category>preconditions</category>
preconditions ^Condition definesInstanceVariable: variableName in: class
</methods> <methods> Refactory.Browser.ExtractMethodRefactoring <category>transforming</category>
checkAssignments: variableNames | node outsideVars removeAssigned | removeAssigned := variableNames copy. node := self placeholderNode. outsideVars := variableNames select: [:each | (node whoDefines: each) references: each]. outsideVars size == 1 ifTrue: [self checkSingleAssignment: outsideVars asArray first]. outsideVars size > 1 ifTrue: [self refactoringError: (#CannotExtractAssignmentWithoutAllRefs << #browser >> 'Cannot extract assignment without all references.')]. removeAssigned removeAll: outsideVars. (RBReadBeforeWrittenTester readBeforeWritten: removeAssigned in: extractedParseTree) notEmpty ifTrue: [self refactoringError: (#CannotExtractAssignmentIfReadBeforeWritten << #browser >> 'Cannot extract assignment if read before written.')]. removeAssigned do: [:each | (node whoDefines: each) removeTemporaryNamed: each]. self createTemporariesInExtractedMethodFor: variableNames
checkReturn needsReturn := self placeholderNode isUsed. extractedParseTree containsReturn ifFalse: [^self]. extractedParseTree lastIsReturn ifTrue: [^self]. (modifiedParseTree isLast: self placeholderNode) ifFalse: [self refactoringError: (#CannotExtractReturn << #browser >> 'Couldn''t extract code since it contains a return.')]. self checkSelfReturns
checkSelfReturns | searcher | searcher := ParseTreeSearcher new. searcher matches: '^self' do: [:aNode :answer | answer]; matches: '^`@anything' do: [:aNode :answer | true]. (searcher executeTree: extractedParseTree initialAnswer: false) ifTrue: [self placeholderNode asReturn]
checkSingleAssignment: varName ((RBReadBeforeWrittenTester isVariable: varName readBeforeWrittenIn: extractedParseTree) or: [extractedParseTree containsReturn]) ifTrue: [self refactoringError: (#CannotExtractAssignmentsToTempsWithoutAllRefs << #browser >> 'Cannot extract assignments to temporaries without all references')]. extractedParseTree addNode: (RBReturnNode value: (RBVariableNode named: varName)). modifiedParseTree := ParseTreeRewriter replace: self methodDelimiter with: varName , ' := ' , self methodDelimiter in: modifiedParseTree
checkSpecialExtractions | node | node := self placeholderNode parent. node isNil ifTrue: [^self]. (node isAssignment and: [node variable = self placeholderNode]) ifTrue: [self refactoringError: (#CannotExtractLHS << #browser >> 'Cannot extract left hand side of an assignment')]. node isCascade ifTrue: [self refactoringError: (#CannotExtractFirstInCascade << #browser >> 'Cannot extract first message of a cascaded message')]
checkTemporaries | temps accesses assigned | temps := self remainingTemporaries. accesses := temps select: [:each | extractedParseTree references: each]. assigned := accesses select: [:each | extractedParseTree assigns: each]. assigned notEmpty ifTrue: [self checkAssignments: assigned]. ^parameters := (accesses asOrderedCollection) removeAll: assigned; yourself
createTemporariesInExtractedMethodFor: assigned assigned do: [:each | extractedParseTree body addTemporaryNamed: each]
existingSelector "Try to find an existing method instead of creating a new one" ^class allSelectors detect: [:each | (class subclassRedefines: each) not and: [self isMethodEquivalentTo: each]] ifNone: [nil]
extractMethod | isSequence extractCode subtree newCode | extractCode := self getExtractedSource. extractedParseTree := RBParser parseExpression: extractCode onError: [:string :pos | self refactoringError: #InvalidSourceToExtract << #browser >> 'Invalid source to extract']. extractedParseTree isNil ifTrue: [self refactoringError: #InvalidSourceToExtract << #browser >> 'Invalid source to extract']. (extractedParseTree isSequence and: [extractedParseTree statements isEmpty]) ifTrue: [self refactoringError: #SelectSomeCodeToExtract << #browser >> 'Select some code to extract']. isSequence := extractedParseTree isSequence or: [extractedParseTree isReturn]. extractedParseTree := RBMethodNode selector: #value arguments: #() body: (extractedParseTree isSequence ifTrue: [extractedParseTree] ifFalse: [RBSequenceNode temporaries: #() statements: (OrderedCollection with: extractedParseTree)]). extractedParseTree body temporaries notEmpty ifTrue: [extractedParseTree body temporaries: #()]. extractedParseTree source: extractCode. subtree := isSequence ifTrue: [ParseTreeSearcher treeMatchingStatements: extractedParseTree body formattedCode in: self sourceTree] ifFalse: [ParseTreeSearcher treeMatching: extractCode in: self sourceTree]. subtree isNil ifTrue: [self refactoringError: #CouldNotExtractSourceFromMethod << #browser >> 'Could not extract code from method']. newCode := self methodDelimiter. isSequence ifTrue: [| stmts | stmts := extractedParseTree body statements. stmts notEmpty ifTrue: [stmts last isAssignment ifTrue: [| name | name := stmts last variable name. (self shouldExtractAssignmentTo: name) ifFalse: [newCode := '<1s> := <2s>' expandMacrosWith: name with: newCode. stmts at: stmts size put: stmts last value]]]]. modifiedParseTree := isSequence ifTrue: [ParseTreeRewriter replaceStatements: subtree formattedCode with: newCode in: self sourceTree onInterval: extractionInterval] ifFalse: [ParseTreeRewriter replace: subtree formattedCode with: newCode in: self sourceTree onInterval: extractionInterval]
getExtractedSource | source | source := self sourceTree source. ((extractionInterval first between: 1 and: source size) and: [extractionInterval last between: 1 and: source size]) ifFalse: [self refactoringError: #InvalidInterval << #browser >> 'Invalid interval']. ^source copyFrom: extractionInterval first to: extractionInterval last
getNewMethodName | newSelector methodName newMethodName | methodName := RBMethodName new. methodName arguments: parameters. [newMethodName := self requestMethodNameFor: methodName. newMethodName isNil ifTrue: [self refactoringError: (#DidNotExtractCode << #browser >> 'Did not extract code')]. newSelector := newMethodName selector. (self checkMethodName: newSelector in: class) ifFalse: [self refactoringWarning: ((#x1sIsInvalidSelector << #browser >> '<1s> is not a valid selector name.') expandMacrosWith: newSelector). newSelector := nil]. (class hierarchyDefinesMethod: newSelector asSymbol) ifTrue: [(self shouldOverride: newSelector in: class) ifFalse: [newSelector := nil]]. newSelector isNil] whileTrue: []. parameters := newMethodName arguments asOrderedCollection. ^newSelector asSymbol
isMethodEquivalentTo: aSelector selector == aSelector ifTrue: [^false]. aSelector numArgs ~~ parameters size ifTrue: [^false]. (self isParseTreeEquivalentTo: aSelector) ifFalse: [^false]. self reorderParametersToMatch: aSelector. ^true
isParseTreeEquivalentTo: aSelector | tree definingClass | definingClass := class whoDefinesMethod: aSelector. tree := definingClass parseTreeFor: aSelector. tree isNil ifTrue: [^false]. tree isPrimitive ifTrue: [^false]. (tree body equalTo: extractedParseTree body exceptForVariables: (tree arguments collect: [:each | each name])) ifFalse: [^false]. (definingClass = class or: [(tree superMessages anySatisfy: [:each | (class superclass whichClassIncludesSelector: aSelector) ~= (definingClass superclass whichClassIncludesSelector: each)]) not]) ifFalse: [^false]. ^self shouldUseExistingMethod: aSelector
methodDelimiter ^'#''place.holder.for.method'''
nameNewMethod: aSymbol | args newSend | args := parameters collect: [:each | RBVariableNode named: each]. extractedParseTree renameSelector: aSymbol andArguments: args asArray. aSymbol numArgs = 0 ifTrue: [modifiedParseTree := ParseTreeRewriter replace: self methodDelimiter with: 'self ' , aSymbol asString in: modifiedParseTree. ^self]. newSend := WriteStream on: String new. aSymbol keywords with: parameters do: [:key :arg | newSend nextPutAll: key asString; nextPut: $ ; nextPutAll: arg asString; nextPut: $ ]. modifiedParseTree := ParseTreeRewriter replace: self methodDelimiter with: 'self ' , newSend contents in: modifiedParseTree
placeholderNode | node | node := ParseTreeSearcher treeMatching: self methodDelimiter in: modifiedParseTree. node isNil ifTrue: [self refactoringError: (#CannotExtractCode << #browser >> 'Cannot extract code')]. ^node
remainingTemporaries | temps | temps := modifiedParseTree allDefinedVariables asSet. extractedParseTree allDefinedVariables do: [:each | temps remove: each ifAbsent: []]. ^temps
reorderParametersToMatch: aSelector | tree dictionary | tree := class parseTreeFor: aSelector. dictionary := Dictionary new. tree body equalTo: extractedParseTree body withMapping: dictionary. parameters := tree arguments collect: [:each | dictionary at: each name ifAbsent: [self refactoringError: (#InternalErrorPleaseReport << #browser >> 'An internal error occured, please report this error.')]]
transform | existingSelector | existingSelector := self existingSelector. self nameNewMethod: (existingSelector isNil ifTrue: [self getNewMethodName] ifFalse: [existingSelector]). existingSelector isNil ifTrue: [class compile: extractedParseTree newSource withAttributesFrom: (class methodFor: selector)]. class compileTree: modifiedParseTree
</methods> <methods> Refactory.Browser.ExtractMethodRefactoring <category>initialize-release</category>
extract: anInterval from: aSelector in: aClass class := self classObjectFor: aClass. selector := aSelector. extractionInterval := anInterval
</methods> <methods> Refactory.Browser.ExtractMethodRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Extract method refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' extract: '. extractionInterval storeOn: aStream. aStream nextPutAll: ' from: #'; nextPutAll: selector; nextPutAll: ' in: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.ExtractMethodRefactoring <category>preconditions</category>
preconditions ^(Condition definesSelector: selector in: class) & (Condition withBlock: [self extractMethod. self checkSpecialExtractions. self checkReturn. needsReturn ifTrue: [extractedParseTree addReturn]. self checkTemporaries. true])
</methods> <methods> Refactory.Browser.ExtractMethodRefactoring <category>accessing</category>
sourceTree ^sourceTree ifNil: [sourceTree := class parseTreeFor: selector]
sourceTree: aParseTree sourceTree := aParseTree
</methods> <methods> Refactory.Browser.ExtractMethodRefactoring class <category>instance creation</category>
extract: anInterval from: aSelector in: aClass ^(self new) extract: anInterval from: aSelector in: aClass; yourself
model: aRBNameSpace extract: anInterval from: aSelector in: aClass ^(self new) model: aRBNameSpace; extract: anInterval from: aSelector in: aClass; yourself
</methods> <methods> Refactory.Browser.MoveVariableDefinitionRefactoring <category>transforming</category>
checkNodes: sequenceNodes (sequenceNodes anySatisfy: [:each | RBReadBeforeWrittenTester isVariable: name readBeforeWrittenIn: each]) ifTrue: [^false]. sequenceNodes do: [:each | (self usesDirectly: each body) ifTrue: [blockNodes add: each] ifFalse: [(self checkNodes: (self subblocksIn: each body)) ifFalse: [blockNodes add: each]]]. ^true
checkParseTree | node | blockNodes := OrderedCollection new. node := self whichVariableNode: self sourceTree inInterval: interval name: name. node isNil ifTrue: [self refactoringError: #UnableToLocateNode << #browser >> 'Unable to locate node in parse tree']. definingNode := node whoDefines: name. definingNode isNil ifTrue: [self refactoringError: #CannotLocateVarDef << #browser >> 'Cannot locate variable definition']. definingNode isSequence ifFalse: [self refactoringError: #VariableIsAnArgument << #browser >> 'Variable is an argument']. (self usesDirectly: definingNode) ifTrue: [self refactoringError: #VariableAlreadyTight << #browser >> 'Variable already bound as tightly as possible']. (self checkNodes: (self subblocksIn: definingNode)) ifFalse: [self refactoringError: #VariablePossiblyReadBeforeWrite << #browser >> 'Variable is possibly read before written']
subblocksIn: aParseTree | searcher | searcher := ParseTreeSearcher new. searcher matches: '[:`@blockTemps | | `@temps | `@.Statements]' do: [:aNode :answer | (aNode references: name) ifTrue: [answer add: aNode]. answer]. ^searcher executeTree: aParseTree initialAnswer: OrderedCollection new
transform definingNode removeTemporaryNamed: name. blockNodes do: [:each | each body addTemporaryNamed: name]. class compileTree: self sourceTree
usesDirectly: aParseTree | searcher | searcher := ParseTreeSearcher new. searcher matches: '[:`@args | | `@temps | `@.Statements]' do: [:aNode :answer | answer]; matches: name do: [:aNode :answer | true]. ^searcher executeTree: aParseTree initialAnswer: false
</methods> <methods> Refactory.Browser.MoveVariableDefinitionRefactoring <category>initialize-release</category>
class: aClass selector: aSelector interval: anInterval interval := anInterval. class := self classObjectFor: aClass. selector := aSelector
</methods> <methods> Refactory.Browser.MoveVariableDefinitionRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Move variable definition refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' bindTight: '. interval storeOn: aStream. aStream nextPutAll: ' in: '. class storeOn: aStream. aStream nextPutAll: ' selector: #'; nextPutAll: selector. aStream nextPut: $)
</methods> <methods> Refactory.Browser.MoveVariableDefinitionRefactoring <category>preconditions</category>
preconditions ^(Condition definesSelector: selector in: class) & (Condition withBlock: [| methodSource | interval first <= interval last ifFalse: [self refactoringError: #InvalidVariableName << #browser >> 'Invalid variable name']. methodSource := self sourceTree source asString. methodSource size >= interval last ifFalse: [self refactoringError: #InvalidRangeForVariable << #browser >> 'Invalid range for variable']. name := methodSource copyFrom: interval first to: interval last. (self checkInstanceVariableName: name in: class) ifFalse: [self refactoringError: (#x1sIsInvalidVariableName << #browser >> '<1s> does not seem to be a valid variable name.' expandMacrosWith: name)]. self checkParseTree. true])
</methods> <methods> Refactory.Browser.MoveVariableDefinitionRefactoring <category>accessing</category>
sourceTree ^sourceTree ifNil: [sourceTree := class parseTreeFor: selector]
sourceTree: aParseTree sourceTree := aParseTree
</methods> <methods> Refactory.Browser.MoveVariableDefinitionRefactoring class <category>instance creation</category>
bindTight: anInterval in: aClass selector: aSelector ^(self new) class: aClass selector: aSelector interval: anInterval; yourself
model: aRBNameSpace bindTight: anInterval in: aClass selector: aSelector ^(self new) model: aRBNameSpace; class: aClass selector: aSelector interval: anInterval; yourself
</methods> <methods> Refactory.Browser.RBSharedVariable <category>accessing</category>
allInitializersDo: aBlock aBlock value: (RBInitializerMethod for: self source: self initializer)
asNameSpace (self isDefined and: [self realItem isNameSpace or: [self realItem isBehavior]]) ifTrue: [^self rootNameSpace nameSpaceFor: self realItem]. ^nil
category ^category ifNil: [binding category]
category: anObject category := anObject
constant ^constant
constant: aBoolean constant := aBoolean
definitionString | definitionStream | definitionStream := WriteStream on: String new. definitionStream nextPutAll: self environment unambiguousName; nextPutAll: ' defineSharedVariable: #'; nextPutAll: self name; cr; tab; nextPutAll: 'private: '; nextPutAll: isPrivate printString; cr; tab; nextPutAll: 'constant: '; nextPutAll: constant printString; cr; tab; nextPutAll: 'category: '; nextPutAll: self category asString printString; cr; tab; nextPutAll: 'initializer: '. initializer isNil ifTrue: [definitionStream nextPutAll: 'nil'] ifFalse: [definitionStream nextPutAll: initializer asString printString]. ^definitionStream contents
initializer initializer isNil ifFalse: [^initializer]. initializer := self isDefined ifTrue: [| method | method := binding method. method isNil ifTrue: [''] ifFalse: [method getSource]] ifFalse: ['']. ^initializer
initializer: aStringOrNil initializer := aStringOrNil
outerReferencingMethodsDo: aBlock | method | method := RBInitializerMethod for: self source: self initializer. method hasOuterVariables ifTrue: [aBlock value: nil value: method]
</methods> <methods> Refactory.Browser.RBSharedVariable <category>testing</category>
isSharedVariable ^true
</methods> <methods> Refactory.Browser.RBSharedVariable <category>initialize-release</category>
realBinding: aVariableBinding super realBinding: aVariableBinding. constant := aVariableBinding isConstant
</methods> <methods> Refactory.Browser.RBSharedVariable <category>private</category>
basicRemove ^self changes removeSharedVariableNamed: self unambiguousName
</methods> <methods> Refactory.Browser.RBSharedVariable <category>accessing-objects</category>
localReferencedItem: aSymbol includePrivates: aBoolean alreadySearched: aCollection currentlyChecking: aSet | ns | ns := self asNameSpace. ns isNil ifTrue: [^nil]. ^ns localReferencedItem: aSymbol includePrivates: aBoolean alreadySearched: aCollection currentlyChecking: aSet
</methods> <methods> Refactory.Browser.RBSharedVariable class <category>instance creation</category>
onBinding: aVariableBinding ^(self new) realBinding: aVariableBinding; yourself
</methods> <methods> Refactory.Browser.RBRootNameSpace <category>accessing</category>
allClassesDo: aBlock | seen | seen := IdentitySet new. self allNewClassesDo: [:each | seen add: each. aBlock value: each]. self rootClasses do: [:each | each withAllSubclasses do: [:sub | (seen includes: sub) ifFalse: [aBlock value: sub]]]
allImplementorsOf: aSelector ^implementorsCache at: aSelector ifAbsentPut: [self privateImplementorsOf: aSelector]
allReferencesTo: aSymbol do: aBlock (sendersCache at: aSymbol ifAbsentPut: [| refs | refs := OrderedCollection new. self allClassesDo: [:each | refs addAll: (each whichMethodsReferToSymbol: aSymbol)]. self allInitializersDo: [:init | (init refersToSymbol: aSymbol) ifTrue: [refs add: init]]. refs]) do: aBlock
allReferencesToObject: aRBProgramItem do: aBlock self allClassesDo: [:each | (each whichSelectorsReferToObject: aRBProgramItem) do: [:sel | aBlock value: (each methodFor: sel)]]. self allInitializersDo: [:init | (init refersToObject: aRBProgramItem) ifTrue: [aBlock value: init]]
changes ^changes
description ^self changes name
description: aString ^self changes name: aString
rootClasses rootClasses isNil ifTrue: [rootClasses := OrderedCollection new. Class rootsOfTheWorld do: [:each | | class | class := self classFor: each. (class notNil and: [class superclass isNil]) ifTrue: [rootClasses add: class]]]. ^rootClasses
</methods> <methods> Refactory.Browser.RBRootNameSpace <category>private</category>
changes: aCompositeRefactoryChange changes := aCompositeRefactoryChange
flushCaches implementorsCache := IdentityDictionary new. sendersCache := IdentityDictionary new
privateImplementorsOf: aSelector | classes | classes := Set new. self allClassesDo: [:each | (each directlyDefinesMethod: aSelector) ifTrue: [classes add: each]]. ^classes
removeRootClass: aRBClass rootClasses notNil ifTrue: [rootClasses remove: aRBClass ifAbsent: []]
</methods> <methods> Refactory.Browser.RBRootNameSpace <category>accessing-objects</category>
fullItemNamed: aString ^self fullItemNamed: aString currentlyChecking: Set new
fullItemNamed: aString currentlyChecking: aSet | st item | (aSet includes: aString) ifTrue: [^nil]. st := self smalltalkNameSpace. st isNil ifTrue: [^nil]. st isNameSpace ifFalse: [^nil]. aSet add: aString. item := st lookupItemPath: aString currentlyChecking: aSet. aSet remove: aString. ^item
smalltalkNameSpace ^self itemFor: #Smalltalk
</methods> <methods> Refactory.Browser.RBRootNameSpace <category>changes</category>
removeObject: aRBProgramItem aRBProgramItem environment removeLocalObject: aRBProgramItem
removeObjectNamed: aSymbol | item | item := self fullItemNamed: aSymbol. item isNil ifTrue: [^self]. self removeObject: item
</methods> <methods> Refactory.Browser.RBRootNameSpace <category>testing</category>
includesClassNamed: aSymbol ^(self classNamed: aSymbol) notNil
</methods> <methods> Refactory.Browser.RBRootNameSpace <category>initialize-release</category>
initialize super initialize. changes := CompositeRefactoryChange new. self realBinding: (Smalltalk bindingFor: #Root). implementorsCache := IdentityDictionary new. sendersCache := IdentityDictionary new
</methods> <methods> Refactory.Browser.RBRootNameSpace <category>accessing-classes</category>
classNamed: aSymbol | class index meta className | className := aSymbol. index := aSymbol indexOfSubCollection: ' class' startingAt: 1. (meta := index > 0) ifTrue: [className := aSymbol copyFrom: 1 to: index - 1]. class := self fullItemNamed: className. (class notNil and: [class isClassObject]) ifTrue: [^meta ifTrue: [class metaclass] ifFalse: [class]]. ^nil
metaclassNamed: aSymbol | class | class := self classNamed: aSymbol. class isNil ifTrue: [^nil]. ^class metaclass
</methods> <methods> Refactory.Browser.RBRootNameSpace <category>accessing-namespaces</category>
nameSpaceNamed: nameSpaceName | item | nameSpaceName = 'Root' ifTrue: [^self]. item := super nameSpaceNamed: nameSpaceName. item isNil ifTrue: [^(self nameSpaceNamed: #Smalltalk) nameSpaceNamed: nameSpaceName]. ^item
</methods> <methods> Refactory.Browser.RBClass <category>accessing</category>
asReference ^self fullName asQualifiedReference
definitionString | definitionStream | definitionStream := WriteStream on: String new. definitionStream nextPutAll: self environment unambiguousName; nextPutAll: ' defineClass: #'; nextPutAll: self name; cr; tab; nextPutAll: 'superclass: '; print: (self superclass isNil ifTrue: [nil] ifFalse: [self superclass asReference makeUnambiguous]); cr; tab; nextPutAll: 'indexedType: #'; nextPutAll: indexedType; cr; tab; nextPutAll: 'private: '; nextPutAll: isPrivate printString; cr; tab; nextPutAll: 'instanceVariableNames: '''. self instanceVariableNames do: [:each | definitionStream nextPutAll: each; nextPut: $ ]. definitionStream nextPutAll: ''''; cr; tab; nextPutAll: 'classInstanceVariableNames: '''. self metaclass instanceVariableNames do: [:each | definitionStream nextPutAll: each; nextPut: $ ]. definitionStream nextPutAll: ''''; cr; tab; nextPutAll: 'imports: '''. self imports do: [:each | definitionStream cr; next: 3 put: Character tab. each printDefinitionOn: definitionStream]. definitionStream cr; next: 3 put: Character tab; nextPutAll: ''''; cr; tab; nextPutAll: 'category: '''''. ^definitionStream contents
indexedType ^indexedType
indexedType: aSymbol indexedType := aSymbol
metaclass ^metaclass
nonMetaclass ^self
package ^Store.Registry containingPackageForClass: self realItem
</methods> <methods> Refactory.Browser.RBClass <category>initialize-release</category>
initialize super initialize. indexedType := #none
metaclass: aRBMetaclass metaclass := aRBMetaclass
realBinding: aBinding super realBinding: aBinding. indexedType := aBinding value behaviorType
</methods> <methods> Refactory.Browser.RBClass <category>testing</category>
isMeta ^false
</methods> <methods> Refactory.Browser.RBClass <category>private</category>
recompileObject self rootNameSpace defineClass: self definitionString
</methods> <methods> Refactory.Browser.RBClass <category>method accessing</category>
outerReferencingMethodsDo: aBlock super outerReferencingMethodsDo: aBlock. self metaclass outerReferencingMethodsDo: aBlock
</methods> <methods> Refactory.Browser.RBClass class <category>instance creation</category>
existing: aBinding model: aRBBasicNameSpace | inst | inst := (self new) parent: aRBBasicNameSpace; realBinding: aBinding; yourself. RBMetaclass newOn: inst model: aRBBasicNameSpace. ^inst
named: aSymbol model: aRBBasicNameSpace | inst | inst := super named: aSymbol model: aRBBasicNameSpace. RBMetaclass newOn: inst model: aRBBasicNameSpace. ^inst
</methods> <methods> Refactory.Browser.MoveObjectRefactoring <category>transforming</category>
doLocalMove "Make the changes to the RB model. This does not change any actual classes yet, but makes the model look like we want it to. This allows the rewrites to see the soon to be view of the world." targetScope items at: object name put: object. object environment removedItems add: object name. object parent: targetScope
findReferencesFromObject fromReferences := Set new. object outerReferencingMethodsDo: [:selector :method | fromReferences add: method]
findReferencesToObject referencesTo := OrderedCollection new. self model allReferencesToObject: object do: [:method | method modelClass = object ifFalse: [referencesTo add: method]]
fixReferencesFromObject fromReferences do: [:method | self convertMethod: method using: (self referenceFromObjectRewriter: method)]
fixReferencesToObject referencesTo do: [:method | self convertMethod: method using: (self referenceToObjectRewriter: method)]
migrateObject self model changes addChange: (MigrateObjectChange move: object unambiguousName to: targetScope unambiguousName)
transform self findReferencesToObject. self findReferencesFromObject. self migrateObject. self doLocalMove. self fixReferencesToObject. self fixReferencesFromObject
</methods> <methods> Refactory.Browser.MoveObjectRefactoring <category>initialize-release</category>
move: anObjectName to: aTargetScopeName "AnObjectName and aTargetScopeName should be results of absoluteName, not fullName." object := self model fullItemNamed: anObjectName. originalScope := object environment. targetScope := self model fullItemNamed: aTargetScopeName
</methods> <methods> Refactory.Browser.MoveObjectRefactoring <category>preconditions</category>
preconditions ^(Condition withBlock: [object isClassObject not or: [object isMeta not]] errorString: (#x1sIsInvalidObjectName << #browser >> '<1s> is not a valid object name' expandMacrosWith: object name)) & (Condition withBlock: [targetScope isClassObject not] errorString: (#x1sIsInvalidTargetScope << #browser >> '<1s> is not a valid move target' expandMacrosWith: targetScope name))
</methods> <methods> Refactory.Browser.MoveObjectRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Move object'
storeOn: aStream aStream nextPutAll: ('(<1s> moveObjectNamed: <2p> to: <3p>)' expandMacrosWith: self class unambiguousName with: object name with: targetScope name)
</methods> <methods> Refactory.Browser.MoveObjectRefactoring <category>rewriter-references to</category>
initReferencesToRewriter: aParseTreeRewriter toAdjustDottedNamesIn: anRBMethod aParseTreeRewriter replace: '`var' withValueFrom: [:node | | restOfPath originalPath newPath | originalPath := node name tokensBasedOn: $.. restOfPath := originalPath allButFirst: (originalPath indexOf: object name asString). newPath := (object unambiguousName tokensBasedOn: $.) , restOfPath. (newPath size > 2 and: [newPath first asString = 'Smalltalk']) ifTrue: [newPath := newPath allButFirst: 1]. RBVariableNode named: (newPath fold: [:a :b | a , '.' , b])] when: [:node | (node name includes: $.) and: [((node name tokensBasedOn: $.) includes: object name asString) and: [((self model fullItemNamed: node name) ifNotNil: [:variable | anRBMethod canReferenceObject: variable] ifNil: [false]) not or: [(node name first: 2) = '_.']]]]
initReferencesToRewriter: aParseTreeRewriter toExpandSimpleNamesIn: anRBMethod aParseTreeRewriter replace: '`var' withValueFrom: [:node | RBVariableNode named: object unambiguousName] when: [:node | node name asString = object name asString and: [(anRBMethod canReferenceObject: object) not]]
initReferencesToRewriter: aParseTreeRewriter toReduceDottedNamesIn: anRBMethod aParseTreeRewriter replace: '`var' withValueFrom: [:node | RBVariableNode named: object name] when: [:node | (node name includes: $.) and: [(node name tokensBasedOn: $.) last = object name asString and: [anRBMethod canReferenceObject: object]]]
initReferencesToRewriterToFixBindingReferencesIn: aParseTreeRewriter aParseTreeRewriter replace: '`#literal' withValueFrom: [:node | RBLiteralNode value: (targetScope realNameSpace fullyQualifiedReferenceOf: node value path last) makeUnambiguous] when: [:node | node value isBindingReference and: [node value refersToLiteral: object binding]]
referenceToObjectRewriter: anRBMethod | rewriter | rewriter := ParseTreeRewriter new. self initReferencesToRewriter: rewriter toExpandSimpleNamesIn: anRBMethod. self initReferencesToRewriter: rewriter toReduceDottedNamesIn: anRBMethod. self initReferencesToRewriter: rewriter toAdjustDottedNamesIn: anRBMethod. self initReferencesToRewriterToFixBindingReferencesIn: rewriter. ^rewriter
</methods> <methods> Refactory.Browser.MoveObjectRefactoring <category>rewriter-references from</category>
initReferenceFromRewriter: aParseTreeRewriter toAdjustBindingReferencesIn: anRBMethod aParseTreeRewriter replace: '`#literal' withValueFrom: [:node | RBLiteralNode value: (originalScope realNameSpace fullyQualifiedReferenceOf: node value path last) makeUnambiguous] when: [:node | node value isBindingReference and: [node value path size = 1 and: [(anRBMethod modelClass canReference: node value path last) not]]]
initReferenceFromRewriter: aParseTreeRewriter toExpandSimpleNamesIn: anRBMethod aParseTreeRewriter replace: '`var' withValueFrom: [:node | RBVariableNode named: (originalScope realNameSpace fullyQualifiedReferenceOf: node name) makeUnambiguous asString] when: [:node | node isLocalVariable not and: [(node name includes: $.) not and: [(node name asString = object name asString) not and: [(anRBMethod modelClass definesInstanceVariable: node name) not and: [(anRBMethod modelClass canReference: node name) not]]]]]
initReferenceFromRewriter: aParseTreeRewriter toReducedDottedNamesIn: anRBMethod aParseTreeRewriter replace: '`var' withValueFrom: [:node | RBVariableNode named: (node name tokensBasedOn: $.) last] when: [:node | (node name includes: $.) and: [| item | (item := anRBMethod referencedItem: node name) notNil and: [item = (anRBMethod referencedItem: (node name tokensBasedOn: $.) last)]]]
initReferenceFromRewriterForRelativeNames: aParseTreeRewriter aParseTreeRewriter replace: '`var' withValueFrom: [:node | | newBinding | newBinding := BindingReference path: originalScope realItem fullyQualifiedReference path , ((node name tokensBasedOn: $.) allButFirst: 1). "Strip off redundant Smalltalk" (newBinding path size > 2 and: [newBinding path first asString = 'Smalltalk']) ifTrue: [newBinding := BindingReference path: (newBinding path allButFirst: 1)]. RBVariableNode named: newBinding asString] when: [:node | (node name first: 2) = '_.']
referenceFromObjectRewriter: anRBMethod | rewriter | rewriter := ParseTreeRewriter new. self initReferenceFromRewriter: rewriter toExpandSimpleNamesIn: anRBMethod "expand to dotted names if need be". self initReferenceFromRewriter: rewriter toReducedDottedNamesIn: anRBMethod "next is a rule that turns _. names into true references". self initReferenceFromRewriterForRelativeNames: rewriter "this is for reducing dotted names that don't need to be anymore". self initReferenceFromRewriter: rewriter toAdjustBindingReferencesIn: anRBMethod "This third condition is for doctoring up #{BindingReferences} that doen't have dots". ^rewriter
</methods> <methods> Refactory.Browser.MoveObjectRefactoring class <category>instance creation</category>
model: aRBNameSpace moveObjectNamed: anObjectName to: aTargetScopeName ^(self new) model: aRBNameSpace; move: anObjectName to: aTargetScopeName; yourself
moveObjectNamed: anObjectName to: aTargetScopeName ^(self new) move: anObjectName to: aTargetScopeName; yourself
</methods> <methods> Refactory.Browser.RemoveMethodRefactoring <category>preconditions</category>
checkReferencesToAnyOf: aSelectorCollection aSelectorCollection do: [:each | self model allReferencesTo: each do: [:aRBMethod | (aSelectorCollection includes: aRBMethod selector) ifFalse: [self refactoringError: ((#PossibleCallTo2sFrom1pBrowseQ << #browser >> 'Possible call to <2s> in <1p><n>Browse references?') expandMacrosWith: aRBMethod modelClass with: each) with: [self openBrowserOn: (BrowserEnvironment new referencesTo: each)]]]]
checkReferencesToSuperSendsToAnyOf: superMessages [superMessages isEmpty] whileFalse: [self refactoringWarning: ((#AlmostEqButHasSuperSend << #browser >> 'Although <1s> is equivalent to a superclass method,<n>it contains a super send so it might modify behavior.') expandMacrosWith: superMessages first). superMessages remove: superMessages first]
checkSuperMethods | superMessages nonSupers | nonSupers := OrderedCollection new. superMessages := OrderedCollection new. (selectors reject: [:each | self justSendsSuper: each]) do: [:each | (self superclassEquivalentlyDefines: each) ifTrue: [(class parseTreeFor: each) superMessages notEmpty ifTrue: [superMessages add: each]] ifFalse: [nonSupers add: each]]. nonSupers isEmpty & superMessages isEmpty ifTrue: [^self]. self checkReferencesToAnyOf: nonSupers. self checkReferencesToSuperSendsToAnyOf: superMessages
justSendsSuper: aSelector | matcher parseTree superclass | matcher := ParseTreeSearcher justSendsSuper. parseTree := class parseTreeFor: aSelector. (matcher executeTree: parseTree initialAnswer: false) ifFalse: [^false]. parseTree lastIsReturn ifTrue: [^true]. superclass := class superclass whoDefinesMethod: aSelector. superclass isNil ifTrue: [^true]. "Since there isn't a superclass that implements the message, we can delete it since it would be an error anyway." parseTree := superclass parseTreeFor: aSelector. matcher := ParseTreeSearcher new. matcher matches: '^``@object' do: [:aNode :answer | answer add: aNode value; yourself]. matcher executeTree: parseTree initialAnswer: Set new. ^matcher answer allSatisfy: [:each | each isVariable and: [each name = 'self']]
preconditions ^(selectors inject: Condition empty into: [:cond :each | cond & (Condition definesSelector: each in: class)]) & (Condition withBlock: [self checkSuperMethods. true])
superclassEquivalentlyDefines: aSelector | superTree myTree | class superclass isNil ifTrue: [^false]. superTree := class superclass parseTreeFor: aSelector. myTree := class parseTreeFor: aSelector. (superTree isNil or: [myTree isNil]) ifTrue: [^false]. ^superTree equalTo: myTree exceptForVariables: #()
</methods> <methods> Refactory.Browser.RemoveMethodRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Remove method refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' removeMethods: '. selectors asArray storeOn: aStream. aStream nextPutAll: ' from: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.RemoveMethodRefactoring <category>initialize-release</category>
removeMethods: selectorCollection from: aClass class := self classObjectFor: aClass. selectors := selectorCollection
</methods> <methods> Refactory.Browser.RemoveMethodRefactoring <category>transforming</category>
transform selectors do: [:each | class removeMethod: each]
</methods> <methods> Refactory.Browser.RemoveMethodRefactoring class <category>instance creation</category>
model: aRBNameSpace removeMethods: selectorCollection from: aClass ^(self new) model: aRBNameSpace; removeMethods: selectorCollection from: aClass; yourself
removeMethods: selectorCollection from: aClass ^(self new) removeMethods: selectorCollection from: aClass; yourself
</methods> <methods> Refactory.Browser.RefactoringError class <category>signalling</category>
raiseSignal: aString with: anObject ^(self new) searchFrom: thisContext sender; originator: thisContext sender homeReceiver; messageText: aString; parameter: anObject; raiseSignal
</methods> <methods> Refactory.Browser.PushDownMethodRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Push down method refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' pushDown: '. selectors asArray storeOn: aStream. aStream nextPutAll: ' from: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.PushDownMethodRefactoring <category>initialize-release</category>
pushDown: selectorCollection from: aClass class := self classObjectFor: aClass. selectors := selectorCollection
</methods> <methods> Refactory.Browser.PushDownMethodRefactoring <category>transforming</category>
pushDown: aSelector | code refactoring | refactoring := ExpandNameSpaceReferencesRefactoring model: self model for: (class parseTreeFor: aSelector) fromClass: class toClasses: class subclasses. self performComponentRefactoring: refactoring. code := refactoring parseTree printString. class subclasses do: [:each | (each directlyDefinesMethod: aSelector) ifFalse: [each compile: code withAttributesFrom: (class methodFor: aSelector)]]
transform selectors do: [:each | self pushDown: each]. selectors do: [:each | class removeMethod: each]
</methods> <methods> Refactory.Browser.PushDownMethodRefactoring <category>preconditions</category>
preconditions | condition | condition := selectors inject: Condition empty into: [:cond :each | cond & (Condition definesSelector: each in: class) & (Condition subclassesOf: class referToSelector: each) not & (Condition withBlock: [| tree | tree := class parseTreeFor: each. tree isNil or: [tree superMessages allSatisfy: [:superMessage | (class directlyDefinesMethod: superMessage) not]]] errorString: ((#x1sSendOverriddenSuperMessage << #browser >> '<1s> sends super message that is overridden.') expandMacrosWith: each))]. ^condition & (Condition isAbstractClass: class)
</methods> <methods> Refactory.Browser.PushDownMethodRefactoring class <category>instance creation</category>
model: aRBNameSpace pushDown: selectorCollection from: aClass ^(self new) model: aRBNameSpace; pushDown: selectorCollection from: aClass; yourself
pushDown: selectorCollection from: aClass ^(self new) pushDown: selectorCollection from: aClass; yourself
</methods> <methods> Refactory.Browser.AbstractVariablesRefactoring <category>transforming</category>
abstractInstanceVariable: aString | refactoring rewriter | refactoring := CreateAccessorsForVariableRefactoring model: self model variable: aString class: fromClass. self performComponentRefactoring: refactoring. rewriter := ParseTreeRewriter new. rewriter replace: aString , ' := ``@object' with: ('self <1s> ``@object' expandMacrosWith: refactoring setterMethod); replace: aString with: 'self ' , refactoring getterMethod. (rewriter executeTree: tree) ifTrue: [tree := rewriter tree]
abstractInstanceVariables | variables | variables := Set new. variables addAll: instVarReaders; addAll: instVarWriters. variables do: [:each | self abstractInstanceVariable: each]
computeVariablesToAbstract | searcher | instVarReaders := Set new. instVarWriters := Set new. sharedVariableReaders := Set new. sharedVariableWriters := Set new. searcher := ParseTreeSearcher new. searcher matches: '`var := ``@anything' do: [:aNode :answer | self processAssignmentNode: aNode]; matches: '`var' do: [:aNode :answer | self processReferenceNode: aNode]. searcher executeTree: tree. self removeImportedSharedVariables
instanceVariableNames ^fromClass allInstanceVariableNames asSet
processAssignmentNode: aNode | varName | varName := aNode variable name. ignore = varName ifTrue: [^self]. (aNode whoDefines: varName) notNil ifTrue: [^self]. ((self instanceVariableNames includes: varName) ifTrue: [instVarWriters] ifFalse: [sharedVariableWriters]) add: varName
processReferenceNode: aNode | varName | varName := aNode name. ignore = varName ifTrue: [^self]. (#('self' 'super' 'true' 'false' 'nil' 'thisContext') includes: varName) ifTrue: [^self]. (aNode whoDefines: varName) notNil ifTrue: [^self]. ((self instanceVariableNames includes: varName) ifTrue: [instVarReaders] ifFalse: [sharedVariableReaders]) add: varName
removeImportedSharedVariables | selectionBlock | selectionBlock := [:varName | | var | var := fromClass referencedItem: varName. toClasses anySatisfy: [:each | (each canAccess: var) not]]. sharedVariableReaders := sharedVariableReaders select: selectionBlock. sharedVariableWriters := sharedVariableWriters select: selectionBlock
transform self hasVariablesToAbstract ifTrue: [self refactoringWarning: (#MethodHasVarRefsToConvertToAccessors << #browser >> 'This method has direct variable references which<n>will need to be converted to getter/setters.') expandMacros]. self abstractInstanceVariables
</methods> <methods> Refactory.Browser.AbstractVariablesRefactoring <category>initialize-release</category>
abstractVariablesIn: aBRProgramNode from: fromBehavior toAll: behaviorCollection ignoring: aVariableName tree := aBRProgramNode. fromClass := self classObjectFor: fromBehavior. toClasses := behaviorCollection collect: [:each | self classObjectFor: each]. ignore := aVariableName. self computeVariablesToAbstract
</methods> <methods> Refactory.Browser.AbstractVariablesRefactoring <category>testing</category>
hasVariablesToAbstract ^(instVarReaders isEmpty & instVarWriters isEmpty & sharedVariableReaders isEmpty & sharedVariableWriters isEmpty) not
</methods> <methods> Refactory.Browser.AbstractVariablesRefactoring <category>accessing</category>
parseTree ^tree
</methods> <methods> Refactory.Browser.AbstractVariablesRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Abstract all variable references in method refactoring'
</methods> <methods> Refactory.Browser.AbstractVariablesRefactoring <category>preconditions</category>
preconditions ^Condition empty
</methods> <methods> Refactory.Browser.AbstractVariablesRefactoring class <category>instance creation</category>
model: aRBNameSpace abstractVariablesIn: aBRProgramNode from: fromBehavior toAll: behaviorCollection ^self model: aRBNameSpace abstractVariablesIn: aBRProgramNode from: fromBehavior toAll: behaviorCollection ignoring: nil
model: aRBNameSpace abstractVariablesIn: aBRProgramNode from: fromBehavior toAll: behaviorCollection ignoring: aVariableName ^(self new) model: aRBNameSpace; abstractVariablesIn: aBRProgramNode from: fromBehavior toAll: behaviorCollection ignoring: aVariableName; yourself
</methods> <methods> Refactory.Browser.RBMethodName <category>accessing</category>
arguments ^arguments
arguments: nameCollection arguments := nameCollection. self changed: #arguments
moveArgument: aName before: anotherName arguments remove: aName ifAbsent: [^self]. arguments add: aName before: anotherName. self changed: #arguments
selector ^selector
selector: aSymbol selector := aSymbol asSymbol. self changed: #selector
</methods> <methods> Refactory.Browser.RBMethodName <category>testing</category>
isValid ^(Condition checkMethodName: self selector in: self class) and: [self selector numArgs == self arguments size]
</methods> <methods> Refactory.Browser.RBMethodName class <category>instance creation</category>
selector: aSymbol arguments: stringCollection ^(self new) selector: aSymbol; arguments: stringCollection; yourself
</methods> <methods> Refactory.Browser.MoveMethodRefactoring <category>transforming</category>
abstractVariables self performComponentRefactoring: self abstractVariablesRefactoring. parseTree := self abstractVariablesRefactoring parseTree
abstractVariablesRefactoring ^AbstractVariablesRefactoring model: self model abstractVariablesIn: parseTree from: class toAll: moveToClasses ignoring: variable
addSelfReturn self hasOnlySelfReturns ifTrue: [^self]. parseTree addSelfReturn
compileDelagatorMethod | statementNode delegatorNode tree | delegatorNode := RBMessageNode receiver: (RBVariableNode named: variable) selectorParts: parseTree selectorParts arguments: (parseTree argumentNames collect: [:each | RBVariableNode named: (each = selfVariableName ifTrue: ['self'] ifFalse: [each])]). self hasOnlySelfReturns ifFalse: [delegatorNode := RBReturnNode value: delegatorNode]. statementNode := RBSequenceNode temporaries: #() statements: (Array with: delegatorNode). (tree := class parseTreeFor: selector) body: statementNode. class compileTree: tree
compileNewMethods moveToClasses do: [:each | each compile: parseTree newSource withAttributesFrom: (class methodFor: selector)]
expandScopes | refactoring | refactoring := ExpandNameSpaceReferencesRefactoring model: self model for: parseTree fromClass: class toClasses: moveToClasses. self performComponentRefactoring: refactoring. parseTree := refactoring parseTree
getArgumentNameForSelf self needsToReplaceSelfReferences ifFalse: [^self]. [selfVariableName := self requestSelfArgumentName. (self checkInstanceVariableName: selfVariableName in: class) ifTrue: [self verifyTemporaryVariableDoesNotOverride ifFalse: [self refactoringWarning: (#VarDefinedTryAnotherQ << #browser >> 'The variable is already defined in one of the classes you''re moving the method to.<n>Try another?') expandMacros. selfVariableName := nil]] ifFalse: [self refactoringWarning: (#VarNameInvalidTryAgainQ << #browser >> 'The variable name is not a valid Smalltalk temporary variable name<n>Try again?') expandMacros. selfVariableName := nil]. selfVariableName isNil] whileTrue: []
getNewMethodName | newSelector parameters alreadyDefined methodName newMethodName | parameters := OrderedCollection withAll: parseTree argumentNames. parameters remove: variable ifAbsent: []. self needsToReplaceSelfReferences ifTrue: [parameters add: selfVariableName]. methodName := RBMethodName selector: selector arguments: parameters. [newMethodName := self requestMethodNameFor: methodName. newMethodName isNil ifTrue: [self refactoringError: (#DidNotMoveMethod << #browser >> 'Did not move method')]. newMethodName isValid ifTrue: [newSelector := newMethodName selector] ifFalse: [self refactoringWarning: (#InvalidMethodName << #browser >> 'Invalid method name')]. parameters := newMethodName arguments. (self checkMethodName: newSelector in: class) ifFalse: [self refactoringWarning: ((#x1sIsInvalidSelector << #browser >> '<1s> is not a valid selector name.') expandMacrosWith: newMethodName selector). newSelector := nil]. alreadyDefined := moveToClasses detect: [:each | each hierarchyDefinesMethod: newSelector] ifNone: [nil]. alreadyDefined notNil ifTrue: [self refactoringWarning: ((#x1sDefinedBy2pTryAnotherQ << #browser >> '<1s> is already defined by <2p> or a super/subclass<n>Try another?') expandMacrosWith: newSelector with: alreadyDefined). newSelector := nil]. newSelector isNil] whileTrue: []. parseTree renameSelector: newSelector andArguments: (parameters collect: [:each | RBVariableNode named: each]) asArray
hasOnlySelfReturns ^hasOnlySelfReturns isNil ifTrue: [| searcher | searcher := ParseTreeSearcher new. searcher matches: '^self' do: [:aNode :answer | answer]; matches: '^`@object' do: [:aNode :answer | false]. hasOnlySelfReturns := searcher executeTree: parseTree initialAnswer: true] ifFalse: [hasOnlySelfReturns]
replaceSelfReferences | replacer | selfVariableName isNil ifTrue: [^self]. replacer := ParseTreeRewriter new. replacer replace: 'self' with: selfVariableName. self hasOnlySelfReturns ifTrue: [replacer replace: '^self' with: '^self']. replacer executeTree: parseTree. parseTree := replacer tree
replaceVariableReferences | replacer | replacer := ParseTreeRewriter new. replacer replace: variable with: 'self'. replacer executeTree: parseTree. parseTree := replacer tree
transform self abstractVariables; expandScopes; getNewMethodName; addSelfReturn; replaceSelfReferences; replaceVariableReferences; compileNewMethods; compileDelagatorMethod
verifyTemporaryVariableDoesNotOverride (parseTree allDefinedVariables includes: selfVariableName) ifTrue: [^false]. ^(moveToClasses anySatisfy: [:each | each definesVariable: selfVariableName]) not
</methods> <methods> Refactory.Browser.MoveMethodRefactoring <category>private</category>
buildParseTree parseTree := (class parseTreeFor: selector) copy. parseTree isNil ifTrue: [self refactoringError: (#CouldNotParseMethod << #browser >> 'Could not parse method')]
</methods> <methods> Refactory.Browser.MoveMethodRefactoring <category>preconditions</category>
checkAssignmentsToVariable | searcher | searcher := ParseTreeSearcher new. searcher matches: variable , ' := `@object' do: [:aNode :answer | true]. (searcher executeTree: parseTree initialAnswer: false) ifTrue: [self refactoringError: ((#CannotMoveMethodTo1sAssigned << #browser >> 'Cannot move the method into <1s> since it is assigned') expandMacrosWith: variable)]
checkForPrimitiveMethod parseTree isPrimitive ifTrue: [self refactoringError: (#CannotMovePrimitiveMethods << #browser >> 'Cannot move primitive methods')]
checkForSuperReferences | searcher | searcher := ParseTreeSearcher new. searcher matches: 'super `@message: `@args' do: [:aNode :answer | true]. (searcher executeTree: parseTree initialAnswer: false) ifTrue: [self refactoringError: (#CannotMoveMethodHasSuperSend << #browser >> 'Cannot move the method since it has a super message send.')]
checkTemporaryVariableNames | varNames | varNames := parseTree allDefinedVariables. selfVariableName notNil ifTrue: [varNames add: selfVariableName]. varNames do: [:name | moveToClasses do: [:each | (self canReferenceVariable: name in: each) ifTrue: [self refactoringError: ((#x1pAlreadyDefinesVar2s << #browser >> '<1p> already defines a variable called <2s>') expandMacrosWith: each with: name)]]]
preconditions ^(Condition definesSelector: selector in: class) & (Condition withBlock: [self buildParseTree. self checkForPrimitiveMethod. self checkForSuperReferences. self checkAssignmentsToVariable. self getClassesToMoveTo. self getArgumentNameForSelf. self checkTemporaryVariableNames. true])
</methods> <methods> Refactory.Browser.MoveMethodRefactoring <category>private-accessing</category>
getClassesForInstanceVariable | definingClass typer types | definingClass := class whoDefinesInstanceVariable: variable. typer := RefactoryTyper newFor: self model. typer runOn: definingClass. types := typer typesFor: variable. types isEmpty ifTrue: [types := OrderedCollection with: (self model classFor: Object)]. moveToClasses := self selectVariableTypesFrom: types selected: (typer guessTypesFor: variable). moveToClasses isNil ifTrue: [self refactoringError: (#MethodNotMoved << #browser >> 'Method not moved')]
getClassesForTemporaryVariable | types | types := RefactoryTyper typesFor: variable in: parseTree model: self model. types isEmpty ifTrue: [types := OrderedCollection with: (self model classFor: Object)]. moveToClasses := self selectVariableTypesFrom: types selected: types. moveToClasses isNil ifTrue: [self refactoringError: (#MethodNotMoved << #browser >> 'Method not moved')]
getClassesToMoveTo self isMovingToArgument ifTrue: [self getClassesForTemporaryVariable] ifFalse: [self isMovingToInstVar ifTrue: [self getClassesForInstanceVariable] ifFalse: [self getClassForGlobalOrClassVariable]]. moveToClasses isEmpty ifTrue: [self refactoringError: (#NoClassesSelectedMethodNotMoved << #browser >> 'No classes selected, method not moved.')]
getClassForGlobalOrClassVariable | object type | object := class referencedItem: variable. type := self model classFor: ((object notNil and: [object isDefined]) ifTrue: [(object isSharedVariable ifTrue: [object realItem value] ifFalse: [object realItem]) class] ifFalse: [Object]). moveToClasses := self selectVariableTypesFrom: (Array with: type) selected: (Array with: type). moveToClasses isNil ifTrue: [self refactoringError: (#MethodNotMoved << #browser >> 'Method not moved')]
</methods> <methods> Refactory.Browser.MoveMethodRefactoring <category>testing</category>
hasSelfReferences | searcher | searcher := ParseTreeSearcher new. searcher matches: 'self' do: [:aNode :answer | true]. self hasOnlySelfReturns ifTrue: [searcher matches: '^self' do: [:aNode :answer | answer]]. ^searcher executeTree: parseTree initialAnswer: false
isMovingToArgument ^(parseTree arguments collect: [:each | each name]) includes: variable
isMovingToInstVar ^self isMovingToArgument not and: [(class whoDefinesInstanceVariable: variable) notNil]
needsToReplaceSelfReferences ^self hasSelfReferences or: [self abstractVariablesRefactoring hasVariablesToAbstract]
</methods> <methods> Refactory.Browser.MoveMethodRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Move method to component refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' selector: #'; nextPutAll: selector; nextPutAll: ' class: '. class storeOn: aStream. aStream nextPutAll: ' variable: '''; nextPutAll: variable; nextPutAll: ''')'
</methods> <methods> Refactory.Browser.MoveMethodRefactoring <category>initialize-release</category>
selector: aSymbol class: aClass variable: aVariableName selector := aSymbol. class := self classObjectFor: aClass. variable := aVariableName
</methods> <methods> Refactory.Browser.MoveMethodRefactoring class <category>instance creation</category>
model: aRBNameSpace selector: aSymbol class: aClass variable: aVariableName ^(self new) model: aRBNameSpace; selector: aSymbol class: aClass variable: aVariableName; yourself
selector: aSymbol class: aClass variable: aVariableName ^(self new) selector: aSymbol class: aClass variable: aVariableName; yourself
</methods> <methods> Refactory.Browser.RBConjunctiveCondition <category>checking</category>
check left check ifFalse: [failed := #leftFailed. ^false]. right check ifFalse: [failed := #rightFailed. ^false]. ^true
</methods> <methods> Refactory.Browser.RBConjunctiveCondition <category>private</category>
errorBlockFor: aBoolean ^aBoolean ifTrue: [nil] ifFalse: [failed == #leftFailed ifTrue: [left errorBlock] ifFalse: [right errorBlock]]
errorMacro ^errorMacro isNil ifTrue: [self longMacro] ifFalse: [super errorMacro]
errorStringFor: aBoolean ^aBoolean ifTrue: [self neitherFailed] ifFalse: [self perform: failed]
leftFailed ^left errorStringFor: false
longMacro ^'(' , left errorMacro , ') <1?AND:OR> (' , right errorMacro , ')'
neitherFailed ^(left errorStringFor: true) , ' AND ' , (right errorStringFor: true)
rightFailed ^right errorStringFor: false
unknownFailed ^(left errorStringFor: false) , ' OR ' , (right errorStringFor: false)
</methods> <methods> Refactory.Browser.RBConjunctiveCondition <category>initialize-release</category>
left: aCondition right: aCondition2 left := aCondition. right := aCondition2. failed := #unknownFailed
</methods> <methods> Refactory.Browser.RBConjunctiveCondition <category>printing</category>
printOn: aStream aStream print: left; nextPutAll: ' & '; print: right
</methods> <methods> Refactory.Browser.AddMethodRefactoring <category>initialize-release</category>
addMethod: aString toClass: aClass inProtocols: protocolList class := self classObjectFor: aClass. source := aString. protocols := protocolList
</methods> <methods> Refactory.Browser.AddMethodRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Add method refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' addMethod: '''; nextPutAll: source; nextPutAll: ''' toClass: '. class storeOn: aStream. aStream nextPutAll: ' inProtocols: '. protocols storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.AddMethodRefactoring <category>transforming</category>
transform class compile: source classified: protocols
</methods> <methods> Refactory.Browser.AddMethodRefactoring <category>preconditions</category>
preconditions | selector method | method := RBParser parseMethod: source onError: [:string :position | ^Condition withBlock: [self refactoringError: (#SourcesCouldNotBeParsed << #browser >> 'The sources could not be parsed')]]. selector := method selector. selector isNil ifTrue: [self refactoringError: (#InvalidSource << #browser >> 'Invalid source.')]. ^(Condition canUnderstand: selector in: class) not
</methods> <methods> Refactory.Browser.AddMethodRefactoring class <category>instance creation</category>
addMethod: aString toClass: aClass inProtocols: protocolList ^(self new) addMethod: aString toClass: aClass inProtocols: protocolList; yourself
model: aRBNameSpace addMethod: aString toClass: aClass inProtocols: protocolList ^(self new) model: aRBNameSpace; addMethod: aString toClass: aClass inProtocols: protocolList; yourself
</methods> <methods> Refactory.Browser.RenameObjectRefactoring <category>initialize-release</category>
className: aName newName: aNewName className := aName. object := self model fullItemNamed: className. newName := aNewName asSymbol
</methods> <methods> Refactory.Browser.RenameObjectRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Rename object'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' renameObjectNamed: '''; nextPutAll: className; nextPutAll: ''' to: '''; nextPutAll: newName; nextPutAll: ''')'
</methods> <methods> Refactory.Browser.RenameObjectRefactoring <category>transforming</category>
parseTreeRewriter ^(ParseTreeRewriter new) replace: '`#literal' withValueFrom: [:aNode | self replaceLiteralNode: aNode] when: [:aNode | self methodClass checkLiteral: aNode value references: object]; replace: object name with: newName when: [:node | self methodClass canAccess: object]; replace: '`var' withValueFrom: [:aNode | self replaceFullReferenceTo: object inVariable: aNode toBe: newName] when: [:node | (node name includes: $.) and: [self methodClass doesName: node name includeObject: object]]; replaceArgument: newName withValueFrom: [:aNode | self refactoringError: ((#x1sAlreadyExistsInScope << #browser >> '<1s> already exists within the reference scope') expandMacrosWith: newName)]; yourself
renameImportReferences methodClass := model smalltalkNameSpace. model allNameSpacesDo: [:each | (each imports anySatisfy: [:lit | each doesPath: lit path includeObject: object]) ifTrue: [each changeImportsTo: (each imports collect: [:lit | (each doesPath: lit path includeObject: object) ifTrue: [self replaceBindingReference: lit] ifFalse: [lit]])]]. methodClass := nil
renameReferences self renameSourceCodeReferences; renameImportReferences
renameSourceCodeReferences | replacer | replacer := self parseTreeRewriter. self model allReferencesToObject: object do: [:method | (method modelClass isClassObject and: [(method modelClass hierarchyDefinesVariable: newName) and: [(object environment isClassObject and: [method modelClass nonMetaclass includesClass: object environment]) not]]) ifTrue: [self refactoringError: ((#x1sAlreadyDefinedInHierarchyOf2s << #browser >> '<1s> is already defined in hierarchy of <2s>') expandMacrosWith: newName with: method modelClass printString)]. self convertMethod: method using: replacer]
replaceBindingReference: aReference | path newPath | path := aReference path. newPath := self replaceReferenceTo: object inPath: path toBe: newName. ^(aReference copy) path: newPath; yourself
replaceLiteral: aLiteral (aLiteral == object name and: [self methodClass canAccess: object]) ifTrue: [^newName]. aLiteral isBindingReference ifTrue: [^self replaceBindingReference: aLiteral]. aLiteral class == Array ifTrue: [^aLiteral collect: [:each | self replaceLiteral: each]]. ^aLiteral
replaceLiteralNode: aNode ^RBLiteralNode value: (self replaceLiteral: aNode value)
transform self model renameClass: object to: newName around: [self renameReferences]
</methods> <methods> Refactory.Browser.RenameObjectRefactoring <category>preconditions</category>
preconditions object isNil ifTrue: [self refactoringError: ((#x1sIsInvalidObjectName << #browser >> '<1s> is not a valid object name') expandMacrosWith: className)]. ^(Condition withBlock: [object isClassObject not or: [object isMeta not]] errorString: ((#x1sIsInvalidObjectName << #browser >> '<1s> is not a valid object name') expandMacrosWith: className)) & (Condition isValidClassName: newName) & (Condition canReference: newName in: object environment) not
</methods> <methods> Refactory.Browser.RenameObjectRefactoring class <category>instance creation</category>
model: aRBNameSpace renameObjectNamed: aString to: aNewName ^(self new) model: aRBNameSpace; className: aString newName: aNewName; yourself
renameObjectNamed: aString to: aNewName ^(self new) className: aString newName: aNewName; yourself
</methods> <methods> Refactory.Browser.InlineAllSelfSendersRefactoring <category>transforming</category>
checkInlinedMethods numberReplaced = 0 ifTrue: [self refactoringError: (#CouldNotInlineAnySenders << #browser >> 'Could not inline any senders')]
inlineMessagesInClass: aClass andSelector: aSelector | messagesToInline previousCountOfMessages | previousCountOfMessages := 4294967295. "Some really large number > # of initial self sends." [| tree | tree := aClass parseTreeFor: aSelector. messagesToInline := tree isNil ifTrue: [0] ifFalse: [self numberOfSelfSendsIn: tree]. messagesToInline > 0 and: [previousCountOfMessages > messagesToInline]] whileTrue: [| node | previousCountOfMessages := messagesToInline. node := self selfSendIn: (aClass parseTreeFor: aSelector). self onError: [self performComponentRefactoring: (InlineMethodRefactoring model: self model inline: node sourceInterval inMethod: aSelector forClass: aClass). numberReplaced := numberReplaced + 1] do: []]. numberNotReplaced := numberNotReplaced + messagesToInline
inlineSelfSends class withAllSubclasses do: [:each | | selectors | selectors := (each whichMethodsReferToSymbol: selector) collect: [:method | method selector]. selectors remove: selector ifAbsent: []. selectors do: [:sel | self inlineMessagesInClass: each andSelector: sel]]
messagePattern ^'self ' , (self buildSelectorString: selector)
numberOfSelfSendsIn: aParseTree | search | search := ParseTreeSearcher new. search matches: self messagePattern do: [:aNode :answer | answer + 1]. ^search executeTree: aParseTree initialAnswer: 0
removeMethod self onError: [self performComponentRefactoring: (RemoveMethodRefactoring model: self model removeMethods: (Array with: selector) from: class)] do: []
selfSendIn: aTree | searcher | searcher := ParseTreeSearcher new. searcher matches: self messagePattern do: [:aNode :answer | ^aNode]. ^searcher executeTree: aTree initialAnswer: nil
transform self inlineSelfSends; removeMethod; checkInlinedMethods
</methods> <methods> Refactory.Browser.InlineAllSelfSendersRefactoring <category>accessing</category>
messagesNotReplaced ^numberNotReplaced
</methods> <methods> Refactory.Browser.InlineAllSelfSendersRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Inline all senders refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' sendersOf: #'; nextPutAll: selector; nextPutAll: ' in: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.InlineAllSelfSendersRefactoring <category>initialize-release</category>
sendersOf: aSelector in: aClass class := self classObjectFor: aClass. selector := aSelector. numberReplaced := numberNotReplaced := 0
</methods> <methods> Refactory.Browser.InlineAllSelfSendersRefactoring <category>preconditions</category>
preconditions ^Condition canUnderstand: selector in: class
</methods> <methods> Refactory.Browser.InlineAllSelfSendersRefactoring class <category>instance creation</category>
model: aRBNameSpace sendersOf: aSelector in: aClass ^(self new) model: aRBNameSpace; sendersOf: aSelector in: aClass; yourself
sendersOf: aSelector in: aClass ^(self new) sendersOf: aSelector in: aClass; yourself
</methods> <methods> Refactory.Browser.InlineTemporaryRefactoring <category>preconditions</category>
checkMultipleAssignments self hasOnlyOneAssignment ifFalse: [self refactoringError: (#MultipleAssignmentsExist << #browser >> 'There are multiple assignments to the variable')]
checkReadBeforeWritten (RBReadBeforeWrittenTester isVariable: assignmentNode variable name writtenBeforeReadIn: definingNode) ifFalse: [self refactoringError: (#VariableReadBeforeAssigned << #browser >> 'The variable is possible read before it is assigned')]
determineAssignmentNode assignmentNode := self sourceTree whichNodeIsContainedBy: sourceInterval. assignmentNode isNil ifTrue: [self refactoringError: #SelectionDoesNotLookLikeAssignment << #browser >> 'The selection does not appear to be an assignment']. assignmentNode isAssignment ifFalse: [self refactoringError: #SelectionIsNotAssignment << #browser >> 'The selected node is not an assignment statement']
determineVariableDefinition definingNode := assignmentNode whoDefines: assignmentNode variable name. definingNode isNil ifTrue: [self refactoringError: (#VariableDoesNotLookLikeTemp << #browser >> 'The variable does not appear to be a temporary variable.')]
preconditions ^(Condition definesSelector: selector in: class) & (Condition withBlock: [self verifySelectedInterval. true])
verifySelectedInterval self determineAssignmentNode. self determineVariableDefinition. self checkMultipleAssignments. self checkReadBeforeWritten
</methods> <methods> Refactory.Browser.InlineTemporaryRefactoring <category>transforming</category>
compileMethod class compileTree: self sourceTree
replaceAssignment assignmentNode isUsed ifTrue: [assignmentNode replaceWith: assignmentNode value] ifFalse: [assignmentNode parent removeNode: assignmentNode]
replaceReferences | rewriter | rewriter := ParseTreeRewriter new. rewriter replaceTree: assignmentNode variable withTree: assignmentNode value. definingNode removeTemporaryNamed: assignmentNode variable name. rewriter executeTree: definingNode
transform self replaceAssignment; replaceReferences; compileMethod
</methods> <methods> Refactory.Browser.InlineTemporaryRefactoring <category>testing</category>
hasOnlyOneAssignment | searcher | searcher := ParseTreeSearcher new. searcher matches: assignmentNode variable name , ' := ``@object' do: [:aNode :answer | answer + 1]. ^(searcher executeTree: definingNode initialAnswer: 0) == 1
</methods> <methods> Refactory.Browser.InlineTemporaryRefactoring <category>initialize-release</category>
inline: anInterval from: aSelector in: aClass class := self classObjectFor: aClass. selector := aSelector. sourceInterval := anInterval
</methods> <methods> Refactory.Browser.InlineTemporaryRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Inline temporary refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' inline: '. sourceInterval storeOn: aStream. aStream nextPutAll: ' from: #'; nextPutAll: selector; nextPutAll: ' in: '. class storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.InlineTemporaryRefactoring <category>accessing</category>
sourceTree ^sourceTree ifNil: [sourceTree := class parseTreeFor: selector]
sourceTree: aParseTree ^sourceTree := aParseTree
</methods> <methods> Refactory.Browser.InlineTemporaryRefactoring class <category>instance creation</category>
inline: anInterval from: aSelector in: aClass ^(self new) inline: anInterval from: aSelector in: aClass; yourself
model: aRBNameSpace inline: anInterval from: aSelector in: aClass ^(self new) model: aRBNameSpace; inline: anInterval from: aSelector in: aClass; yourself
</methods> <methods> Refactory.Browser.RemoveObjectRefactoring <category>preconditions</category>
hasReferencesTo: aRBProgramItem model allReferencesToObject: aRBProgramItem do: [:each | ^true]. ^false
preconditions ^objectNames inject: Condition empty into: [:sum :each | | item | item := self model fullItemNamed: each. item isNil ifTrue: [self refactoringError: (#NoSuchObject << #browser >> 'No such object')]. sum & (Condition withBlock: [(self hasReferencesTo: item) ifTrue: [self refactoringError: ((#x1IsReferencedBrowseQ << #browser >> '<1s> is referenced.%<n%>Browse references?') expandMacrosWith: each) expandMacros with: [self openBrowserOn: (BrowserEnvironment new referencesTo: item binding)]]. item isNameSpace ifTrue: [item definesAnyItem ifTrue: [self refactoringError: ((#x1sDefinesOtherObjects << #browser >> '<1s> is not empty. It defines other shared variables, name spaces, or classes') expandMacrosWith: each)]. item isClassObject ifTrue: [(item instanceVariableNames isEmpty and: [item selectors isEmpty and: [item metaclass instanceVariableNames isEmpty and: [item metaclass selectors isEmpty]]]) ifFalse: [item subclasses notEmpty ifTrue: [self refactoringError: (#CannotRemoveWithInstVarsAndSubclasses << #browser >> 'Cannot remove class that defines instance variables or methods when it has subclasses.')]]. (item subclasses isEmpty and: [item superclass isNil]) ifTrue: [self refactoringError: (#CannotRemoveTopWithSubclasses << #browser >> 'Cannot remove top level class when it has subclasses')]]]. true])]
</methods> <methods> Refactory.Browser.RemoveObjectRefactoring <category>initialize-release</category>
objectNames: aStringCollection objectNames := aStringCollection
</methods> <methods> Refactory.Browser.RemoveObjectRefactoring <category>transforming</category>
removeClasses objectNames do: [:each | self model removeObjectNamed: each]
reparentSubclasses objectNames do: [:each | | class | class := self model classNamed: each. class notNil ifTrue: [self model reparentClasses: class subclasses copy to: class superclass]]
transform self reparentSubclasses; removeClasses
</methods> <methods> Refactory.Browser.RemoveObjectRefactoring <category>printing</category>
printOn: aStream aStream nextPutAll: 'Remove object refactoring'
storeOn: aStream aStream nextPut: $(. self class storeOn: aStream. aStream nextPutAll: ' objectNames: '. objectNames asArray storeOn: aStream. aStream nextPut: $)
</methods> <methods> Refactory.Browser.RemoveObjectRefactoring class <category>instance creation</category>
model: aRBNameSpace objectNames: aStringCollection ^(self new) model: aRBNameSpace; objectNames: aStringCollection; yourself
objectNames: aStringCollection ^(self new) objectNames: aStringCollection; yourself
</methods> <methods> Refactory.Browser.RefactoringWarning <category>private - actions</category>
defaultAction "Proceed through warnings" ^nil
</methods> <methods> Kernel.CompiledCode <category>accessing-literals</category>
hasOuterVariables self allLiteralsDo: [:each | (each isVariableBinding or: [each isBindingReference]) ifTrue: [^true]]. ^false
</methods> <methods> Kernel.NameSpace <category>RefactoringBrowser</category>
whoDefinesBinding: aBinding self withAllNameSpacesDo: [:each | (each localBindingFor: aBinding key) == aBinding ifTrue: [^each]]. self allBehaviorsDo: [:each | each isMeta ifFalse: [(each localBindingFor: aBinding key) == aBinding ifTrue: [^each]]]. ^nil
withAllEnvironments | envs env | envs := OrderedCollection new. env := self. [env isNil] whileFalse: [envs add: env. env := env environment]. ^envs
</methods> <methods> Core.Behavior <category>RefactoringBrowser</category>
outerReferencingMethodsDo: aBlock "Enumerate all methods which contain variable bindings beyond the instance variable scope. aBlock takes the selector and method for which this is true." methodDict keysAndValuesDo: [:selector :method | method hasOuterVariables ifTrue: [aBlock value: selector value: method]]
whichClassDefinesInstVar: aString ^self whichClassSatisfies: [:aClass | aClass instVarNames includes: aString]
whichClassDefinesSharedVariable: aSymbol ^self whichClassSatisfies: [:aClass | aClass asNameSpace includesKey: aSymbol]
whichClassSatisfies: aBlock (aBlock value: self) ifTrue: [^self]. ^superclass isNil ifTrue: [nil] ifFalse: [superclass whichClassSatisfies: aBlock]
</methods> "Imported Classes:" self error: 'Attempting to file-in parcel imports. Choose terminate or close' <class> <name>Object</name> <environment>Core</environment> <super></super> <private>false</private> none <imports></imports> <category>Kernel-Objects</category> <attributes> <package>Kernel-Objects</package> </attributes> </class> <class> <name>CompiledCode</name> <environment>Kernel</environment> <super>Core.Object</super> <private>false</private> objects bytes <imports> private Kernel.OpcodePool.* </imports> <category>Kernel-Methods</category> <attributes> <package>Kernel-Methods</package> </attributes> </class> <class> <name>Exception</name> <environment>Core</environment> <super>Core.GenericException</super> <private>false</private> none <imports></imports> <category>Kernel-Exception Handling</category> <attributes> <package>Kernel-Exception Handling</package> </attributes> </class> <class> <name>Behavior</name> <environment>Core</environment> <super>Core.Object</super> <private>false</private> none superclass methodDict format subclasses <imports></imports> <category>Kernel-Classes</category> <attributes> <package>Kernel-Classes</package> </attributes> </class> <class> <name>Error</name> <environment>Core</environment> <super>Core.Exception</super> <private>false</private> none <imports></imports> <category>Kernel-Exception Handling</category> <attributes> <package>Kernel-Exception Handling</package> </attributes> </class> <class> <name>NameSpace</name> <environment>Kernel</environment> <super>Kernel.GeneralNameSpace</super> <private>false</private> none parent name <imports></imports> <category>System-Name Spaces</category> <attributes> <package>System-Name Spaces</package> </attributes> </class>