1

コードを書いているときは、次のようにすべてのメソッドの先頭にトレース呼び出しを含めます。

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

メソッドの名前を変更すると、トレース メソッド呼び出しの文字列定数も更新されるように、Eclipse プラグインを作成しようとしています。これを実現するために、RenameParticipant を実装しています。

私が抱えている問題は、メソッド名の長さが変わらない場合にのみ、作成した変更が正しく機能することです。メソッド名の長さが変わると、私の変更は、変更されたファイル内の間違ったオフセットを編集してしまいます。

私は何を間違っていますか?メソッド rename が Trace 呼び出しのファイル内のオフセットを変更する可能性があるという事実をどのように説明できますか?


Change を計算するには、次のコードを使用します。

@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);
}

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;
  }
}

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 + "\""));
    }
  }
}
4

1 に答える 1

1

createPreChange(...)を使用して、コードを機能させることができました。これにより、メインのリファクタリングが実行される前にソースで実行された変更を返すことができます。これは、私のコードによって計算された変更が、実際に適用された時点でも正確であることを意味します。

http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fltk%2Fcore%2Frefactoring%2Fparticipants%2FRefactoringParticipant.html

編集:createPreChange(...)を使用することは、私の変更が別のPreChangeと競合する可能性があるため、実際には単なる回避策でした。createChange(...)の使用に戻り、getTextChange(...)を呼び出して既存のテキスト編集オブジェクトを取得し、このオブジェクトに編集内容を追加することで、より良い解決策を考え出しました。これにより、オフセットが正しく機能するようです。

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;
}
于 2012-04-07T11:31:11.077 に答える