package com.mountainminds.eclemma.internal.core.analysis; import java.util.Arrays; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import com.mountainminds.eclemma.internal.core.EclEmmaCorePlugin; import com.vladium.emma.data.MethodDescriptor; public class MethodMatcher { private final IType type; private final IJavaElement[] children; private final boolean[][] covered; private final MethodDescriptor[] methods; private final int staticInitInd; private int childInd = 0; private int methodInd = 0; private boolean matched = false; private boolean matchedStatic = false; public MethodMatcher(IType type, boolean[][] covered, MethodDescriptor[] methods) throws JavaModelException { this.type = type; this.children = type.getChildren(); this.covered = covered; this.methods = methods; // ArrayList mdlist = new ArrayList(); // for (int ii = 0; ii < methods.length; ii++) // { // MethodDescriptor methodEle = methods[ii]; // if (methodEle.getName().startsWith("access$")) // { // // Ignore // } // else // { // mdlist.add(methodEle.getName() + ":" + methodEle.getDescriptor()); // } // } // ArrayList jelist = new ArrayList(); // for (int ii = 0; ii < children.length; ii++) // { // IJavaElement childEle = children[ii]; // if ((childEle.getElementType() == IJavaElement.METHOD) || // (childEle.getElementType() == IJavaElement.INITIALIZER)) // { // jelist.add(childEle.toString()); // } // } // // System.out.println(jelist.get(0)); // System.out.println(); // // for (int ii = 0; ii < Math.max(jelist.size(), mdlist.size()); ii++) // { // if (ii < mdlist.size()) // { // System.out.println(mdlist.get(ii)); // } // if ((ii + 1) < jelist.size()) // { // System.out.println(jelist.get(ii + 1)); // } // System.out.println(); // } // Extract the static init descriptor if there is one int staticInit = -1; for (int i = 0; i < methods.length; i++) { if ("<clinit>".equals(methods[i].getName())) //$NON-NLS-1$ { staticInit = i; break; } } staticInitInd = staticInit; } public boolean methodMatched() { if (matchedStatic) { childInd++; matchedStatic = false; } if (matched) { childInd++; methodInd++; matched = false; } if (methodInd == staticInitInd) { methodInd++; } // Iterate over methods to skip generated access methods while ((methodInd < methods.length) && methods[methodInd].getName().startsWith("access$")) //$NON-NLS-1$ { methodInd++; } // Guard against reaching the end of the array if ((methodInd >= methods.length)) { matched = false; return false; } for (; childInd < children.length; childInd++) { IJavaElement childEle = children[childInd]; MethodDescriptor methodDesc = methods[methodInd]; // children[] includes more than just methods // methods[] contains descriptors for all the methods and // initializer code within the Class // We can match up these elements by skipping over elements // of children[] which are not methods or initializers. // This logic relies on the fact that these two arrays // hold the methods in the same order. if ((childEle.getElementType() == IJavaElement.METHOD) || (childEle.getElementType() == IJavaElement.INITIALIZER)) { if (methodInd >= methods.length) { logNotEnoughMethodDescriptors(); return false; } // Special case for static init blocks. These all map to a single // static method descriptor if (childEle.toString().startsWith("<static initializer ")) //$NON-NLS-1$ { matchedStatic = true; return true; } if ("<init>".equals(methodDesc.getName()))//$NON-NLS-1$ { // If the child ele is an initializer we just keep searching as we should // find a constructor soon if (childEle.getElementType() == IJavaElement.INITIALIZER) { continue; } // Special case where we have a method descriptor for the // implicit no-args constructor but no corresponding java // element. else if(!type.getElementName().equals(childEle.getElementName())) { // Skip over this descriptor methodInd++; } } if (methodInd >= methods.length) { logNotEnoughMethodDescriptors(); return false; } matched = true; return true; } } return false; } private void logNotEnoughMethodDescriptors() { IStatus status = new Status(IStatus.WARNING, EclEmmaCorePlugin.ID, IStatus.ERROR, "Fewer coverage descriptors than expected when examining type: " + type + "\n" + //$NON-NLS-1$//$NON-NLS-2$ "Method Descriptors: " + toStringDescriptors(methods) + "\n" + //$NON-NLS-1$ //$NON-NLS-2$ "Java Elements: " + Arrays.asList(children) + "\n", //$NON-NLS-1$ //$NON-NLS-2$ new Exception()); EclEmmaCorePlugin.getInstance().getLog().log(status); } private String toStringDescriptors(MethodDescriptor[] methods) { String ret = "["; //$NON-NLS-1$ for (int ii = 0; ii < methods.length; ii++) { MethodDescriptor method = methods[ii]; ret += method.getName() + method.getDescriptor(); if (ii < methods.length - 1) { ret += ","; //$NON-NLS-1$ } } ret += "]"; //$NON-NLS-1$ return ret; } public IJavaElement getMatchedElement() { return children[childInd]; } public MethodDescriptor getMatchedDescriptor() { return matchedStatic ? methods[staticInitInd] : methods[methodInd]; } public boolean[] getMatchedCoverageData() { return ((covered == null) ? null : (matchedStatic ? covered[staticInitInd] : covered[methodInd])); } }