Home | History | Annotate | Download | only in spechelper
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package spechelper;
     17 
     18 import org.eclipse.jdt.core.Flags;
     19 import org.eclipse.jdt.core.ICompilationUnit;
     20 import org.eclipse.jdt.core.IJavaProject;
     21 import org.eclipse.jdt.core.IMethod;
     22 import org.eclipse.jdt.core.IType;
     23 import org.eclipse.jdt.core.ITypeParameter;
     24 import org.eclipse.jdt.core.JavaModelException;
     25 import org.eclipse.jdt.core.Signature;
     26 import org.eclipse.jdt.core.dom.AST;
     27 import org.eclipse.jdt.core.dom.ASTParser;
     28 import org.eclipse.jdt.core.dom.ASTVisitor;
     29 import org.eclipse.jdt.core.dom.CompilationUnit;
     30 import org.eclipse.jdt.core.dom.Expression;
     31 import org.eclipse.jdt.core.dom.ITypeBinding;
     32 import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
     33 import org.eclipse.jdt.internal.ui.JavaPlugin;
     34 import org.eclipse.jdt.ui.JavaElementLabelProvider;
     35 import org.eclipse.jface.dialogs.IDialogConstants;
     36 import org.eclipse.jface.dialogs.MessageDialog;
     37 import org.eclipse.swt.widgets.Shell;
     38 import org.eclipse.ui.IEditorInput;
     39 import org.eclipse.ui.IEditorPart;
     40 import org.eclipse.ui.PlatformUI;
     41 import org.eclipse.ui.dialogs.ElementListSelectionDialog;
     42 
     43 import java.util.ArrayList;
     44 import java.util.List;
     45 
     46 /**
     47  *
     48  */
     49 public class MethodSelector {
     50 
     51     public String obtainReplacement(String buffer) {
     52         IMethod method = selectMethod();
     53         // if user did cancel the selection
     54         if (method == null) {
     55             return null;
     56         }
     57 
     58         // see if we are already in a annotation:
     59         // if yes -> only dump the testtarget annotation, not the complete
     60         // TestInfo
     61         // (could not easily find this out with CompilationUnit, since inserting
     62         // a :
     63         // broke the AST - maybe use WorkingCopy and so on,
     64         // but for now: do it with simple String analysis
     65         boolean shortOnly = false;
     66         int annotPos = buffer.lastIndexOf("@TestInfo");
     67         // the latest annotation - count "(" ")" pairs - if not the same count
     68         // we assume to be in the annotation (H: code compiles fine)
     69         if (annotPos != -1) {
     70             String sub = buffer.substring(annotPos);
     71             // only consider the latest 6 lines for the annotation to occur
     72             // (6 = range within which the annotation @TestTarget
     73             // must occur, but out of range to reach the annotation from the
     74             // previous method - ah i'd prefer working with compilationUnit...
     75             String[] lines = sub.split("\n");
     76             for (int i = lines.length - 6; i < lines.length; i++) {
     77                 String line = lines[i];
     78                 if (line.contains("@TestTarget")) {
     79                     shortOnly = true;
     80                 }
     81             }
     82         }
     83 
     84         return generateAnnotation(shortOnly, method);
     85     }
     86 
     87 
     88     private String generateAnnotation(boolean shortOnly, IMethod method) {
     89         String[] ptypes = method.getParameterTypes();
     90         String param = "";
     91         for (int i = 0; i < ptypes.length; i++) {
     92             String ptype = ptypes[i];
     93             String sig = Signature.toString(ptype);
     94             // kind of a hack: convert all Generic Type args to Object, or to
     95             // its bound Type
     96             if (sig.length() == 1) {
     97                 ITypeParameter tps = method.getTypeParameter(sig);
     98                 sig = "Object";
     99 
    100                 if (tps != null && tps.exists()) {
    101                     try {
    102                         String[] bounds = tps.getBounds();
    103                         if (bounds.length > 0) {
    104                             sig = bounds[0];
    105                         }
    106                     } catch (JavaModelException e) {
    107                         e.printStackTrace();
    108                     }
    109 
    110                 }
    111             }
    112             // omit type signature
    113             sig = sig.replaceAll("<.*>", "");
    114             param += (i > 0 ? ", " : "") + sig + ".class";
    115         }
    116         String IND = "    ";
    117 
    118         String targ = "@TestTarget(\n" + IND + "      methodName = \""
    119                 + method.getElementName() + "\",\n" + IND
    120                 + "      methodArgs = {" + param + "}\n" + IND + "    )\n";
    121 
    122         String s;
    123         if (shortOnly) {
    124             s = targ;
    125         } else {
    126 
    127             s = "@TestInfo(\n" + IND + "  status = TestStatus.TBR,\n" + IND
    128                     + "  notes = \"\",\n" + IND + "  targets = {\n" + IND
    129                     + "    " + targ + IND + "})";
    130         }
    131         return s;
    132     }
    133 
    134     private IMethod selectMethod() {
    135         IEditorPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
    136                 .getActivePage().getActiveEditor();
    137         Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
    138                 .getShell();
    139         IEditorInput ei = part.getEditorInput();
    140         final ICompilationUnit cu = JavaPlugin.getDefault()
    141                 .getWorkingCopyManager().getWorkingCopy(ei);
    142         // cu != null since we register only for java/javadoc completion
    143         // proposals
    144         ASTParser parser = ASTParser.newParser(AST.JLS3);
    145         parser.setSource(cu);
    146         parser.setResolveBindings(true);
    147         CompilationUnit unit = (CompilationUnit) parser.createAST(null);
    148 
    149         class MHolder {
    150             IMethod method;
    151         }
    152         final MHolder mholder = new MHolder();
    153 
    154         class FHolder {
    155             boolean foundClassAnnotation;
    156         }
    157         final FHolder fholder = new FHolder();
    158 
    159         unit.accept(new ASTVisitor() {
    160             public boolean visit(SingleMemberAnnotation node) {
    161                 String name = node.getTypeName().getFullyQualifiedName();
    162                 if (!name.equals("TestTargetClass")) {
    163                     return false;
    164                 }
    165                 fholder.foundClassAnnotation = true;
    166                 Expression targetClassE = node.getValue();
    167                 ITypeBinding ty = targetClassE.resolveTypeBinding();
    168                 if (ty == null) {
    169                     return false;
    170                 }
    171                 ITypeBinding[] classTypes = ty.getTypeArguments();
    172                 if (classTypes.length > 0) {
    173                     ITypeBinding tp = classTypes[0];
    174                     String qname = tp.getQualifiedName();
    175                     System.out.println("qname:" + qname);
    176                     IJavaProject myProject = cu.getJavaProject();
    177                     try {
    178                         IType myType = myProject.findType(qname);
    179                         if (myType != null) {
    180                             Shell parent = PlatformUI.getWorkbench()
    181                                     .getActiveWorkbenchWindow().getShell();
    182                             ElementListSelectionDialog dialog = new ElementListSelectionDialog(
    183                                     parent,
    184                                     new JavaElementLabelProvider(
    185                                             JavaElementLabelProvider.SHOW_PARAMETERS
    186                                                     | JavaElementLabelProvider.SHOW_OVERLAY_ICONS
    187                                                     | JavaElementLabelProvider.SHOW_RETURN_TYPE));
    188                             // restrict to public/protected methods only
    189                             IMethod[] allMeth = myType.getMethods();
    190                             List<IMethod> pubproMethods = new ArrayList<IMethod>();
    191                             for (int i = 0; i < allMeth.length; i++) {
    192                                 IMethod method = allMeth[i];
    193                                 if ((method.getFlags() & (Flags.AccPublic | Flags.AccProtected)) != 0) {
    194                                     pubproMethods.add(method);
    195                                 }
    196                             }
    197                             IMethod[] res = pubproMethods
    198                                     .toArray(new IMethod[pubproMethods.size()]);
    199                             dialog.setIgnoreCase(true);
    200                             dialog.setBlockOnOpen(true);
    201                             dialog.setElements(res);//
    202                             dialog.setFilter("");
    203                             dialog.setTitle(qname);
    204                             if (dialog.open() != IDialogConstants.CANCEL_ID) {
    205                                 Object[] types = dialog.getResult();
    206                                 System.out.println("selected:" + types[0]);
    207                                 IMethod method = (IMethod) types[0];
    208                                 mholder.method = method;
    209 
    210                             } else {
    211                                 // System.out.println("cancelled!!");
    212                             }
    213                         }
    214                     } catch (JavaModelException e) {
    215                         e.printStackTrace();
    216                     }
    217                 }
    218                 return true;
    219             }
    220         });
    221         if (!fholder.foundClassAnnotation) {
    222             MessageDialog.openInformation(shell, "Class Annotation missing",
    223                     "@TestTargetClass(...) is missing");
    224             return null;
    225         }
    226         return mholder.method;
    227     }
    228 }
    229