/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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 spechelper;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
public class MethodSelector {
public String obtainReplacement(String buffer) {
IMethod method = selectMethod();
// if user did cancel the selection
if (method == null) {
return null;
}
// see if we are already in a annotation:
// if yes -> only dump the testtarget annotation, not the complete
// TestInfo
// (could not easily find this out with CompilationUnit, since inserting
// a :
// broke the AST - maybe use WorkingCopy and so on,
// but for now: do it with simple String analysis
boolean shortOnly = false;
int annotPos = buffer.lastIndexOf("@TestInfo");
// the latest annotation - count "(" ")" pairs - if not the same count
// we assume to be in the annotation (H: code compiles fine)
if (annotPos != -1) {
String sub = buffer.substring(annotPos);
// only consider the latest 6 lines for the annotation to occur
// (6 = range within which the annotation @TestTarget
// must occur, but out of range to reach the annotation from the
// previous method - ah i'd prefer working with compilationUnit...
String[] lines = sub.split("\n");
for (int i = lines.length - 6; i < lines.length; i++) {
String line = lines[i];
if (line.contains("@TestTarget")) {
shortOnly = true;
}
}
}
return generateAnnotation(shortOnly, method);
}
private String generateAnnotation(boolean shortOnly, IMethod method) {
String[] ptypes = method.getParameterTypes();
String param = "";
for (int i = 0; i < ptypes.length; i++) {
String ptype = ptypes[i];
String sig = Signature.toString(ptype);
// kind of a hack: convert all Generic Type args to Object, or to
// its bound Type
if (sig.length() == 1) {
ITypeParameter tps = method.getTypeParameter(sig);
sig = "Object";
if (tps != null && tps.exists()) {
try {
String[] bounds = tps.getBounds();
if (bounds.length > 0) {
sig = bounds[0];
}
} catch (JavaModelException e) {
e.printStackTrace();
}
}
}
// omit type signature
sig = sig.replaceAll("<.*>", "");
param += (i > 0 ? ", " : "") + sig + ".class";
}
String IND = " ";
String targ = "@TestTarget(\n" + IND + " methodName = \""
+ method.getElementName() + "\",\n" + IND
+ " methodArgs = {" + param + "}\n" + IND + " )\n";
String s;
if (shortOnly) {
s = targ;
} else {
s = "@TestInfo(\n" + IND + " status = TestStatus.TBR,\n" + IND
+ " notes = \"\",\n" + IND + " targets = {\n" + IND
+ " " + targ + IND + "})";
}
return s;
}
private IMethod selectMethod() {
IEditorPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().getActiveEditor();
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getShell();
IEditorInput ei = part.getEditorInput();
final ICompilationUnit cu = JavaPlugin.getDefault()
.getWorkingCopyManager().getWorkingCopy(ei);
// cu != null since we register only for java/javadoc completion
// proposals
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(cu);
parser.setResolveBindings(true);
CompilationUnit unit = (CompilationUnit) parser.createAST(null);
class MHolder {
IMethod method;
}
final MHolder mholder = new MHolder();
class FHolder {
boolean foundClassAnnotation;
}
final FHolder fholder = new FHolder();
unit.accept(new ASTVisitor() {
public boolean visit(SingleMemberAnnotation node) {
String name = node.getTypeName().getFullyQualifiedName();
if (!name.equals("TestTargetClass")) {
return false;
}
fholder.foundClassAnnotation = true;
Expression targetClassE = node.getValue();
ITypeBinding ty = targetClassE.resolveTypeBinding();
if (ty == null) {
return false;
}
ITypeBinding[] classTypes = ty.getTypeArguments();
if (classTypes.length > 0) {
ITypeBinding tp = classTypes[0];
String qname = tp.getQualifiedName();
System.out.println("qname:" + qname);
IJavaProject myProject = cu.getJavaProject();
try {
IType myType = myProject.findType(qname);
if (myType != null) {
Shell parent = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell();
ElementListSelectionDialog dialog = new ElementListSelectionDialog(
parent,
new JavaElementLabelProvider(
JavaElementLabelProvider.SHOW_PARAMETERS
| JavaElementLabelProvider.SHOW_OVERLAY_ICONS
| JavaElementLabelProvider.SHOW_RETURN_TYPE));
// restrict to public/protected methods only
IMethod[] allMeth = myType.getMethods();
List<IMethod> pubproMethods = new ArrayList<IMethod>();
for (int i = 0; i < allMeth.length; i++) {
IMethod method = allMeth[i];
if ((method.getFlags() & (Flags.AccPublic | Flags.AccProtected)) != 0) {
pubproMethods.add(method);
}
}
IMethod[] res = pubproMethods
.toArray(new IMethod[pubproMethods.size()]);
dialog.setIgnoreCase(true);
dialog.setBlockOnOpen(true);
dialog.setElements(res);//
dialog.setFilter("");
dialog.setTitle(qname);
if (dialog.open() != IDialogConstants.CANCEL_ID) {
Object[] types = dialog.getResult();
System.out.println("selected:" + types[0]);
IMethod method = (IMethod) types[0];
mholder.method = method;
} else {
// System.out.println("cancelled!!");
}
}
} catch (JavaModelException e) {
e.printStackTrace();
}
}
return true;
}
});
if (!fholder.foundClassAnnotation) {
MessageDialog.openInformation(shell, "Class Annotation missing",
"@TestTargetClass(...) is missing");
return null;
}
return mholder.method;
}
}