This document is intended for providers of participants for the rename
type, method, and field refactorings. The document describes the new
rename type feature "Update Similarly Named Elements" and the changes
required in rename type, method, and field refactoring participants
induced by this new feature.

Table of Contents:

Starting in Eclipse 3.2 M4, the rename type refactoring is able to
rename “similar declarations": methods, fields, and local
variables with names similar to the name of the renamed type. For
example, consider the following code:

Renaming the type Foo to Bar used to update only the type’s name and
all references to it, for example the return type of createFoo() or the
parameter type of setFoo(Foo foo). The new update similar declarations
feature allows the user to change all method, field, and variable
names corresponding to or containing the type name. For example, when
renaming Foo to Bar, the code may be changed in the following way
(depending on the users choices):

In contrast to the old type rename refactoring whose changes were
limited to the type itself and its references, the new rename type
refactoring creates much more changes which also affect arbitrary
fields, methods, and local variables inside and outside of the renamed
type. This raises the question of how to signal those changes to
interested parties by loading corresponding participants.

Signalling the new changes

The best solution would have been to simply reuse existing
participants, i.e. loading

a rename type participant for the type rename,

rename method participants for the method renames,

rename field participants for the field renames, and

rename local variable participants for the local variable
renames.

Unfortunately, this approach was not feasible as the changes created by
the new rename type refactoring are no longer simple renames – neither
the type rename nor the method, field and local variable renames:

Type rename: Considering the example above, the normal
rename
type refactoring would only have changed the type name and the
references to the type; for example, the type of the field foo and the
return type of method getBar(). Rename type participants could
therefore assume that all fields and methods inside the type would keep
their defining attributes:

same name for methods, fields, and local variables,
and

same parameter types for methods

In the new refactoring, this is now no longer the case: Each field,
method, or local variable inside the renamed type is potentially
affected by the refactoring. Consider the following method from the
example above:

public void setFoo(Foo foo) { }

Renaming the type Foo to Bar effectively changes this method to

public void setBar(Bar bar) { }

The changes to this method are:

the name changed

the parameter type changed

the parameter name changed

These changes are best described as a complete signature change
of the method, and not a simple rename. Similar problems exist when
changing fields and local variables. Because these changes were not
signaled to the participants, they break existing
participants with assumptions about these members. Those participants
cannot be reused as-is.

As a side note, signature changes to methods have already been a
problem when
renaming methods like the method setFoo(Foo foo): Even in the former
implementation, a signature change was performed on this method as the
parameter type Foo was changed to Bar which was not signaled to the
rename type participant; we also did not load a special participant for
it.

Method, field and local variable renames: Considering a
rename
of the method setFoo(Foo foo) from the example above, the normal rename
methodrefactoring would only have changed the name of the
method (and
possibly of overridden methods and references). Rename method
participants could therefore assume that only the name of the method
changed and everything else stayed the same.

In the new refactoring, this is now no longer the case. Consider the
method signature change of setFoo(Foo foo) from the example above. The
changes to this method are:

the name changed

the parameter type changed

the parameter name changed

the container of the method changed: it is now no longer
declared
in the class Foo, but in the class Bar.

Again, these changes are best described as a complete signature change
of the method and an additional change to the container of the method;
it is no longer a simple rename. Because these changes were not
signaled to the participants, they break existing
participants. Therefore, existing rename method, field, and local
variable participants cannot be reused as-is, and it is questionable
whether those participants should know about possible container changes.

Required Actions

As outlined in section II, some existing participants will not work
with the new refactoring. Because of the breaking nature of this
change, we provide

a product configuration flag to completely disable
the
“update similar names” feature

a participant descriptor flag to temporarily
disable
participants if the “update similar names” feature is turned on

a migration guide and helper methods for
implementing
support for the new feature.

Setting the product configuration flag: If set, the new
feature
will not be presented to the user at all and participant loading and
handling stays exactly the way it was before. Note that the feature is
enabled by default. To disable the feature, please add the following
code to the product extension definition:

Setting the participant descriptor flag: If set, the
participant
will be disabled in each concrete rename type refactoring if the new
option is enabled. To disable a participant in that case, please add
the following code to the participant extension definition:

<param name="handlesSimilarDeclarations" value="false"/>

Updating the participants (Migrating): To be able to
respond to
the additional changes of the new type rename refactoring, participants
will need to know about these changes. Our solution for this problem is
new API for the rename type participants, enabling them to handle
similarly named declarations. Participant writers will need to adapt or
replace their existing rename type participants to

be aware of changing fields, methods, or local variables
inside
the renamed type (signature change and container change)

be aware of changing fields, methods, or local variables
outside
the renamed type (signature change, possibly container change if local
types are used)

Rename method, field, and local variable participants will not be
loaded for similarly named declarations; these elements must be handled
inside the rename type participant.

Migration Guide

Not all existing rename type participants will need code changes, and
the amount of changes will depend significantly on the existing
implementation. Particularly, rename type participants which only deal
with the type itself and not its members or other members (for example,
for updating a launch configuration) need not be changed at all.

For all participants which deal with the members of the type or which
need to add support for method, field, or local variable renames, the
code handling those elements must be changed. The biggest problem when
writing the new participant is mapping the renamed old methods, fields,
and local variables to the new, changed elements since a lot of things
can change (the complete signature and the direct or indirect container
of the elements).

To solve this problem, we provide API for relocating any java element
or resource in the workspace to reflect all performed changes.
Participants can use the relocated handle during change execution to
access the new elements.

Let’s look at a simple example. Consider the following old rename type
and rename method/field/local variable participants which keep a list
of all keys of types, methods, fields, and local variables
of all Java projects in an external database.

The rename participants are implemented something like this (this is
the rename type participant, which we will adapt – the code of the
method/field/local variable participants looks similar, but need not be
changed):

The code makes the assumption that all fields in the new type have the
same name as in the old type. We need to:

change this assumption

add code for handling field, method and local variable
changes in
other types

Let’s first look at how we can find out about similarly named
declarations. As a subclass of RenameParticipant, we have access to the
RenameArguments, which we already use in initialize(Object element):

fNewName= getArguments().getNewName();

The RenameArguments class has been subclassed for the Rename Type
Refactoring to contain additional information about similarly named
declarations. We can cast the class to RenameTypeArguments and check if
similarly named declarations are renamed:

Now we’d like to know which elements are renamed. Again, we ask the
RenameTypeArguments for this information:

IJavaElement[] similarDeclarations= args.getSimilarDeclarations();

All of the elements in this array are either of type IMethod, IField,
or ILocalVariable. These are the handles of the “old” elements before
all changes.

Now we know which elements have changed, but we still don’t know how
they will look after the refactoring. What we’d like to do is change
our existing code which resolves the new elements to handling complete
signature changes, i.e. we’d like to change the lines

To do this, we ask our refactoring processor for the new elements. The
processor is guaranteed to implement the interface IJavaElementMapper –
a mapper to map old pre-refactoring handles to post-refactoring
handles. We adapt the processor to the interface:

We can use this method to ask the refactoring to relocate any java
element in the workspace to reflect all performed changes. For
example, when asking the refactoring for an updated handle of the
method:

“setSomeClass(SomeClass someClass) in InnerType in SomeClass”,

It will return the handle:

“setAnotherClass(AnotherClass anotherClass) in InnerType in AnotherClass”

(Provided the class SomeClass was renamed to AnotherClass).

During change creation, the new handle will still point to a
non-existing element. However, during participant change execution, the
element will exist and can be used to retrieve resources etc.

Side Note: The Rename Type Refactoring may also affect
resources: If a top-level type was renamed, its enclosing file will be
renamed as well. To be able to re-map such resource elements as well,
we can adapt the RenameTypeProcessor to the IResourceMapper interface:

Again, this method can be used to map any IResource in the workspace to
a new element reflecting all changes.

With these helper methods, we change our code to the following to
respond to signature changes in members of the type itself and also to
changes to fields, methods, and local variables outside of the type:

We acquired an instance of the processor which we used
to
resolve refactored elements

We acquired a list of similarly named declarations

We used the java element mapper to acquire the type after
the
change

We used the java element mapper to acquire the type’s
members
after the change. Note that the resolving method works for all members
of the type, not only the similarly named ones. In fact, the method
works for any IJavaElement in the whole workspace (of course, most will
remain unaffected).

We used the similarly named declarations list and the java
element mapper to change all similarly named declarations outside the
type.

We didn’t use a resource element mapper in this example;
however
it works similar to the java element mapper.

Our code is now fully adapted to the similarly named declaration
updating feature.

To sum up, you need to be aware of the following issues when adapting
your old rename type participant code:

You may no longer make assumptions about how a java element
or
resource looks like during change execution, whether it resides inside
the renamed type or outside. Instead, always use the
getRefactoredJavaElement() or getRefactoredResource() methods to
acquire a new instance of the java element or resource.

You need to take care of methods, fields, and local
variables
renamed outside the type. You may acquire them by using the
getSimilarDeclarations() method.