/*
* Copyright 2009-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.eclipse.refactoring.core.convert;
import javax.swing.text.BadLocationException;
import org.codehaus.groovy.eclipse.core.GroovyCore;
import org.codehaus.jdt.groovy.model.GroovyCompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
/**
* Common class to process the convert to closure refactoring.
* Used by both the completion proposal and the refactor menu option.
*
* @author Geoff Denning
* @created Nov 15, 2011
*/
// FIXGWD: This class should be converted into a proper refactoring class which extends Refactoring.
public class ConvertToClosureRefactoring {
private final IMethod targetMethod;
public ConvertToClosureRefactoring(GroovyCompilationUnit unit, int offset) {
targetMethod = findMethod(unit, offset);
}
private IMethod findMethod(GroovyCompilationUnit unit, int offset) {
//if (unit.isOnBuildPath()) return null;
try {
IJavaElement maybeMethod = unit.getElementAt(offset);
if (!(maybeMethod instanceof IMethod)) {
return null;
}
ISourceRange nameRange = ((IMethod) maybeMethod).getNameRange();
if (nameRange.getLength() == maybeMethod.getElementName().length()) {
return ((IMethod) maybeMethod);
}
// For quoted method names, the name range will include the quotes,
// but
// the name itself will not include them
// check the text to see if the name start is at a quote
char[] contents = unit.getContents();
if (contents.length > nameRange.getOffset() && contents[nameRange.getOffset()] == '"') {
return ((IMethod) maybeMethod);
}
} catch (JavaModelException e) {
GroovyCore.logException("Error finding enclosing method for refactoring", e);
}
return null;
}
public void applyRefactoring(IDocument document) {
if (targetMethod != null) {
TextEdit thisEdit = findReplacement(document, targetMethod);
try {
if (thisEdit != null) {
thisEdit.apply(document);
}
} catch (Exception e) {
GroovyCore.logException("Oops.", e);
}
}
}
public boolean isApplicable() {
return targetMethod != null && targetMethod.exists();
}
private TextEdit findReplacement(IDocument doc, IMethod targetMethod) {
try {
ISourceRange nameRange = targetMethod.getSourceRange();
// find the opening parnn and the closing paren
int openingParen = findOpenParen(doc, targetMethod, nameRange);
int closingParen = findCloseParen(doc, openingParen);
int openingBracket = findOpenBracket(doc, closingParen);
return createEdit(doc, targetMethod, openingParen, closingParen, openingBracket);
} catch (Exception e) {
GroovyCore.logException("Exception during convert to closure.", e);
return null;
}
}
/**
* @return finds the first open paren after the name ends
* @throws BadLocationException
* @throws org.eclipse.jface.text.BadLocationException
*/
private int findOpenParen(IDocument doc, IMethod targetMethod, ISourceRange nameRange) throws BadLocationException, org.eclipse.jface.text.BadLocationException {
int offset = nameRange.getOffset() + targetMethod.getElementName().length();
while (offset < doc.getLength() && doc.getChar(offset) != '(') {
offset++;
}
return offset;
}
private int findOpenBracket(IDocument doc, int closingParen) throws BadLocationException, org.eclipse.jface.text.BadLocationException {
int offset = closingParen;
while (offset < doc.getLength() && doc.getChar(offset) != '{') {
offset++;
}
return offset;
}
private int findCloseParen(IDocument doc, int open) throws BadLocationException, org.eclipse.jface.text.BadLocationException {
int offset = open;
while (offset < doc.getLength() && doc.getChar(offset) != ')') {
offset++;
}
return offset;
}
private TextEdit createEdit(IDocument doc, IMethod targetMethod, int openingParen, int closingParen, int openingBracket)
throws BadLocationException, org.eclipse.jface.text.BadLocationException {
if (!(openingParen < doc.getLength() && doc.getChar(openingParen) == '(')) {
return null;
}
if (!(closingParen < doc.getLength() && doc.getChar(closingParen) == ')')) {
return null;
}
if (!(openingBracket < doc.getLength() && doc.getChar(openingBracket) == '{')) {
return null;
}
TextEdit edit = new MultiTextEdit();
if (targetMethod.getParameterTypes().length > 0) {
edit.addChild(new ReplaceEdit(openingParen, 1, " = { "));
edit.addChild(new ReplaceEdit(closingParen, openingBracket - closingParen + 1, " ->"));
} else {
edit.addChild(new ReplaceEdit(openingParen, 1, " = {"));
edit.addChild(new DeleteEdit(closingParen, openingBracket - closingParen + 1));
}
return edit;
}
}