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