Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Language IDEs » Java Development Tools (JDT) » Eclipse RenameParticipant offset handling
Eclipse RenameParticipant offset handling [message #838355] Fri, 06 April 2012 20:11 Go to next message
Martin Robertson is currently offline Martin Robertson
Messages: 3
Registered: July 2011
Junior Member
When I am writing code I include trace calls at the start of every method which looks like this:

public void doOperation()
{
  Trace tr = new Trace("doOperation");
  ... method body ...
}

I am trying to write an Eclipse plugin so that when I rename a method the string constant in the trace method call is also updated. To achieve this I am implementing a RenameParticipant.

The issue I have is that the Change I produce only works correctly when the method name doesn't change length. If the method name changes length then my change ends up editing the wrong offset within the changed file.

What am I doing wrong? How can I account for the fact that the method rename may alter the offset within the file of my Trace call?

-----

To compute the Change I use the following code:

@Override
public Change createChange(IProgressMonitor pm)
  throws CoreException,
         OperationCanceledException
{
  ICompilationUnit unit = element.getCompilationUnit();
  CompilationUnit astCompUnit = parse(unit, pm);
  ASTNode astElement = NodeFinder.perform(astCompUnit, element.getNameRange());
  MethodDeclaration astMethod = (MethodDeclaration)getParent(astElement, MethodDeclaration.class);

  String newName = getArguments().getNewName();
  List<TraceFnFixOperation> ops = new ArrayList<TraceFnFixOperation>(1);
  TraceFnCtorFinder finder = new TraceFnCtorFinder(newName, ops);
  astMethod.accept(finder);

  if (ops.size() == 0)
    return null;

  return new TraceChange("Fix Trace", unit, ops);
}

The body of the TraceFnCtorFinder:

public static class TraceFnCtorFinder extends ASTVisitor
{
  private final String methodName;
  private final List<TraceFnFixOperation> workingops;

  public TraceFnCtorFinder(String methodName, List<TraceFnFixOperation> workingops)
  {
    this.methodName = methodName;
    this.workingops = workingops;
  }

  @Override
  public boolean visit(ClassInstanceCreation ctorClass)
  {
    Type type = ctorClass.getType();

    // Only examine simple types
    if (type.isSimpleType())
    {
      SimpleType simpleType = (SimpleType)type;
      String typeName = simpleType.getName().getFullyQualifiedName();

      // Check type has correct name
      if ("Trace".equals(typeName))
      {
        List<?> arguments = ctorClass.arguments();

        // Only check a single argument
        if ((arguments != null) &&
            (arguments.size() == 1))
        {
          Object arg = arguments.get(0);

          // Only check a string literal argument
          if (arg instanceof StringLiteral)
          {
            StringLiteral literal = (StringLiteral) arg;
            String currentArg = literal.getLiteralValue();

            // Check whether argument value is valid
            if (!methodName.equals(currentArg))
            {
              workingops.add(new TraceFnFixOperation(literal.getStartPosition(),
                                                     literal.getLength(),
                                                     methodName));
            }
          }
        }
      }
    }
    return false;
  }
}

The body of TraceChange:

public static class TraceChange extends CompilationUnitChange
{
  public TraceChange(String name,
                     ICompilationUnit cunit,
                     List<TraceFnFixOperation> ops)
  {
    super(name, cunit);

    MultiTextEdit multiTextEdit= new MultiTextEdit();
    setEdit(multiTextEdit);
    for (TraceFnFixOperation op : ops)
    {
      addEdit(new ReplaceEdit(op.startPosition,
                              op.length,
                              "\"" + op.methodName + "\""));
    }
  }
}

-----

I have also posted this question on StackOverflow with the same title (I can't post a link as I am new to this forum).
Re: Eclipse RenameParticipant offset handling [message #838660 is a reply to message #838355] Sat, 07 April 2012 08:04 Go to previous message
Martin Robertson is currently offline Martin Robertson
Messages: 3
Registered: July 2011
Junior Member
I have come up with a solution by calling getTextChange(...) to get the existing text edits object and adding my edits to this object. This seems to make the offsets work correctly.

public Change createChange(IProgressMonitor pm)
  throws CoreException,
         OperationCanceledException
{
  ICompilationUnit unit = element.getCompilationUnit();
  TextChange change = getTextChange(unit);

  // Failed to find existing change to add our changes to
  if (change == null)
    return null;

  // Find the AST version of the method being changed
  CompilationUnit astCompUnit = parse(unit, pm);
  ASTNode astElement = NodeFinder.perform(astCompUnit, element.getNameRange());
  MethodDeclaration astMethod = (MethodDeclaration)getParent(astElement, MethodDeclaration.class);

  // Visit the contents of the method to find changes to make
  String newName = getArguments().getNewName();
  List<TraceFnFixOperation> ops = new ArrayList<TraceFnFixOperation>(1);
  TraceFnCtorFinder finder = new TraceFnCtorFinder(newName, ops);
  astMethod.accept(finder);

  // Add identified edits to the overall change
  for (TraceFnFixOperation op : ops)
  {
    change.addEdit(new ReplaceEdit(op.startPosition,
                                   op.length,
                                   "\"" + op.methodName + "\""));
  }

  // Don't return a dedicated change
  return null;
}
Previous Topic:University of Illinois Survey on Refactoring Tools
Next Topic:Exception while generating AST in a non-eclipse environment
Goto Forum:
  


Current Time: Fri Jul 25 09:59:22 EDT 2014

Powered by FUDForum. Page generated in 0.01913 seconds