/* Copyright (C) 2013 Raquel Pau and Albert Coroleu. Walkmod is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Walkmod is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Walkmod. If not, see <http://www.gnu.org/licenses/>.*/ package org.walkmod.javalang.actions; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.walkmod.javalang.ast.Comment; import org.walkmod.javalang.ast.Node; import org.walkmod.javalang.ast.body.BodyDeclaration; import org.walkmod.javalang.ast.body.JavadocComment; import org.walkmod.javalang.ast.expr.Expression; import org.walkmod.javalang.ast.stmt.BlockStmt; public class ReplaceAction extends Action { private String newCode; private int endLine; private int endColumn; private String oldCode; private char indentationChar = ' '; private int indentationLevel; private int indentationSize; private Node newNode; private Node oldNode; private List<Comment> acceptedComments = new LinkedList<Comment>(); public ReplaceAction(int beginLine, int beginPosition, Node oldNode, Node newNode, int indentation, int indentationSize, List<Comment> comments) { super(beginLine, beginPosition, ActionType.REPLACE); //we filter those comments that affects to the region of the replace to keep them available if (comments != null) { Iterator<Comment> it = comments.iterator(); while (it.hasNext()) { Comment next = it.next(); if (oldNode.contains(next) && !(next instanceof JavadocComment)) { acceptedComments.add(next); it.remove(); } } } this.oldNode = oldNode; this.indentationLevel = indentation; oldCode = oldNode.getPrettySource(indentationChar, indentationLevel, indentationSize, acceptedComments); this.indentationSize = indentationSize; this.newNode = newNode; getText("", indentationChar); //we infer the new ending line and columns for the new text String[] lines = newCode.split("\n"); endLine = getBeginLine() + lines.length - 1; endColumn = lines[lines.length - 1].length(); if (oldNode.getEndLine() >= endLine) { if (oldNode.getEndLine() == endLine) { if (oldNode.getEndColumn() > endColumn) { endLine = oldNode.getEndLine(); endColumn = oldNode.getEndColumn(); } } else { endLine = oldNode.getEndLine(); endColumn = oldNode.getEndColumn(); } } } /** * Returns the new text to insert with the appropriate indentation and comments * * @param indentation * the existing indentation at the file. It never should be null and it is needed for * files that mix tabs and spaces in the same line. * @param indentationChar * the used indentation char (' ', or '\t') * @return the new text that replaces the existing one */ public String getText(String indentation, char indentationChar) { newCode = FormatterHelper.indent( newNode.getPrettySource(indentationChar, indentationLevel, indentationSize, acceptedComments), indentation, indentationChar, indentationLevel, indentationSize, requiresExtraIndentationOnFirstLine(newNode)); return newCode; } @Override public int getEndLine() { return endLine; } public int getOldEndLine() { return oldNode.getEndLine(); } public int getOldEndColumn() { return oldNode.getEndColumn(); } @Override public int getEndColumn() { return endColumn; } public String getNewText() { return newCode; } public String getOldText() { return oldCode; } private boolean requiresExtraIndentationOnFirstLine(Node node) { return !((node instanceof Expression) || (node instanceof BlockStmt) || (node instanceof BodyDeclaration)); } }