@Override public void visitCode(Code obj) { Method m = getMethod(); if (m.getReturnType() == Type.VOID) { return; } stack.resetForMethodEntry(this); ifBlocks.clear(); activeUnconditional = null; CodeException[] ces = obj.getExceptionTable(); if (CollectionUtils.isEmpty(ces)) { catchPCs = null; } else { catchPCs = new BitSet(); for (CodeException ce : ces) { catchPCs.set(ce.getHandlerPC()); } } gotoBranchPCs.clear(); casePositions.clear(); lookingForResetOp = false; try { super.visitCode(obj); } catch (StopOpcodeParsingException e) { // reported an issue, so get out } }
@Override public void visitClassContext(ClassContext classContext) { JavaClass javaClass = classContext.getJavaClass(); // The class extends WebChromeClient boolean isWebChromeClient = InterfaceUtils.isSubtype(javaClass, "android.webkit.WebChromeClient"); // Not the target of this detector if (!isWebChromeClient) return; Method[] methodList = javaClass.getMethods(); for (Method m : methodList) { MethodGen methodGen = classContext.getMethodGen(m); if (DEBUG) System.out.println(">>> Method: " + m.getName()); // The presence of onGeolocationPermissionsShowPrompt is not enforce for the moment if (!m.getName().equals("onGeolocationPermissionsShowPrompt")) { continue; } // Since the logic implemented need to be analyze by a human, all implementation will be // flagged. bugReporter.reportBug( new BugInstance(this, ANDROID_GEOLOCATION_TYPE, Priorities.NORMAL_PRIORITY) // .addClassAndMethod(javaClass, m)); } }
/** Loads the code of the method. */ protected Instruction[] loadCode(Method m) { Code c = m.getCode(); if (c == null) { return null; } InstructionList il = new InstructionList(c.getCode()); InstructionHandle[] hs = il.getInstructionHandles(); int length = hs.length; Instruction[] is = new Instruction[length]; for (int i = 0; i < length; i++) { is[i] = insnFactory.createAndInitialize(this, hs[i], i, m.getConstantPool()); if (c.getLineNumberTable() != null) { // annoying bug when BCEL don't seem to find linenumber - pos match // also sometimes linenumber tables are not available is[i].setContext( ci.getName(), name, c.getLineNumberTable().getSourceLine(is[i].getPosition()), is[i].getPosition()); } } return is; }
/** * @param classContext * @param method */ private void analyzeMethod(ClassContext classContext, Method method) throws MethodUnprofitableException, CFGBuilderException, DataflowAnalysisException { if (method.isSynthetic() || (method.getAccessFlags() & Constants.ACC_BRIDGE) == Constants.ACC_BRIDGE) return; CFG cfg = classContext.getCFG(method); TypeDataflow typeDataflow = classContext.getTypeDataflow(method); ConstantPoolGen constantPoolGen = classContext.getConstantPoolGen(); locationLoop: for (Iterator<Location> iter = cfg.locationIterator(); iter.hasNext(); ) { Location location = iter.next(); InstructionHandle handle = location.getHandle(); Instruction ins = handle.getInstruction(); // Only consider invoke instructions if (!(ins instanceof InvokeInstruction)) continue; if (ins instanceof INVOKEINTERFACE) continue; InvokeInstruction inv = (InvokeInstruction) ins; TypeFrame frame = typeDataflow.getFactAtLocation(location); String methodName = inv.getMethodName(constantPoolGen); if (methodName.toLowerCase().indexOf("unsupported") >= 0) continue; String methodSig = inv.getSignature(constantPoolGen); if (methodSig.equals("()Ljava/lang/UnsupportedOperationException;")) continue; Set<XMethod> targets; try { targets = Hierarchy2.resolveMethodCallTargets(inv, frame, constantPoolGen); } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); continue locationLoop; } if (targets.isEmpty()) continue locationLoop; int priority = targets.size() == 1 ? Priorities.HIGH_PRIORITY : Priorities.NORMAL_PRIORITY; for (XMethod m : targets) { if (!m.isUnsupported()) continue locationLoop; XClass xc = AnalysisContext.currentXFactory().getXClass(m.getClassDescriptor()); if (!(inv instanceof INVOKESTATIC) && !(m.isFinal() || xc.isFinal())) priority = Priorities.NORMAL_PRIORITY; if (xc == null || xc.isAbstract()) { try { if (!AnalysisContext.currentAnalysisContext() .getSubtypes2() .hasSubtypes(m.getClassDescriptor())) continue locationLoop; } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); continue locationLoop; } } } BugInstance bug = new BugInstance(this, "DMI_UNSUPPORTED_METHOD", priority) .addClassAndMethod(classContext.getJavaClass(), method) .addCalledMethod(constantPoolGen, inv) .addSourceLine(classContext, method, location); bugReporter.reportBug(bug); } }
/** Returns the exceptions of the method. */ protected ExceptionHandler[] loadExceptions(Method m) { Code c = m.getCode(); if (c == null) { return null; } CodeException[] ce = c.getExceptionTable(); if (ce.length == 0) { return null; } int length = ce.length; ExceptionHandler[] eh = new ExceptionHandler[length]; ConstantPool cp = m.getConstantPool(); for (int i = 0; i < length; i++) { int ct = ce[i].getCatchType(); eh[i] = new ExceptionHandler( ((ct == 0) ? null : cp.getConstantString(ct, Constants.CONSTANT_Class).replace('/', '.')), ce[i].getStartPC(), ce[i].getEndPC(), ce[i].getHandlerPC()); } return eh; }
public SearchResult run(RSClient data, HashMap<String, ClassGen> classes) { for (ClassGen c : classes.values()) { ConstantPoolGen cpg = c.getConstantPool(); if (cpg.lookupFloat(16384.0000f) != -1) { for (Method m : c.getMethods()) { if (m.isStatic()) { MethodGen gen = new MethodGen(m, c.getClassName(), cpg); InstructionList il = gen.getInstructionList(); if (il == null) continue; InstructionFinder f = new InstructionFinder(il); Iterator e = f.search("GETSTATIC LDC FSUB PUTSTATIC"); if (e.hasNext()) { InstructionHandle[] handles = (InstructionHandle[]) e.next(); data.addField( "MapAngle", ((GETSTATIC) handles[0].getInstruction()).getClassName(cpg) + "." + ((GETSTATIC) handles[0].getInstruction()).getFieldName(cpg)); return SearchResult.Success; } } } } } return SearchResult.Failure; }
/* (non-Javadoc) * @see edu.umd.cs.findbugs.classfile.IAnalysisEngine#analyze(edu.umd.cs.findbugs.classfile.IAnalysisCache, java.lang.Object) */ public Method analyze(IAnalysisCache analysisCache, MethodDescriptor descriptor) throws CheckedAnalysisException { JavaClass jclass = analysisCache.getClassAnalysis(JavaClass.class, descriptor.getClassDescriptor()); Method[] methodList = jclass.getMethods(); Method result = null; // As a side-effect, cache all of the Methods for this JavaClass for (Method method : methodList) { MethodDescriptor methodDescriptor = DescriptorFactory.instance() .getMethodDescriptor( descriptor.getSlashedClassName(), method.getName(), method.getSignature(), method.isStatic()); // Put in cache eagerly analysisCache.eagerlyPutMethodAnalysis(Method.class, methodDescriptor, method); if (methodDescriptor.equals(descriptor)) { result = method; } } return result; }
@Override public void visitClassContext(ClassContext classContext) { if (!testingEnabled) { return; } analysisContext = AnalysisContext.currentAnalysisContext(); Method[] methodList = classContext.getJavaClass().getMethods(); for (Method method : methodList) { if (method.getCode() == null) { continue; } try { analyzeMethod(classContext, method); } catch (CFGBuilderException e) { bugReporter.logError( "Error checking for infinite recursive loop in " + SignatureConverter.convertMethodSignature(classContext.getJavaClass(), method), e); } catch (DataflowAnalysisException e) { bugReporter.logError( "Error checking for infinite recursive loop in " + SignatureConverter.convertMethodSignature(classContext.getJavaClass(), method), e); } } }
public static LocalVariableAnnotation getLocalVariableAnnotation( Method method, int local, int position1, int position2) { LocalVariableTable localVariableTable = method.getLocalVariableTable(); String localName = "?"; if (localVariableTable != null) { LocalVariable lv1 = localVariableTable.getLocalVariable(local, position1); if (lv1 == null) { lv1 = localVariableTable.getLocalVariable(local, position2); position1 = position2; } if (lv1 != null) localName = lv1.getName(); else for (LocalVariable lv : localVariableTable.getLocalVariableTable()) { if (lv.getIndex() == local) { if (!localName.equals("?") && !localName.equals(lv.getName())) { // not a single consistent name localName = "?"; break; } localName = lv.getName(); } } } LineNumberTable lineNumbers = method.getLineNumberTable(); if (lineNumbers == null) return new LocalVariableAnnotation(localName, local, position1); int line = lineNumbers.getSourceLine(position1); return new LocalVariableAnnotation(localName, local, position1, line); }
public static @CheckForNull LocalVariableAnnotation findUniqueBestMatchingParameter( ClassContext classContext, Method method, String name, String signature) { LocalVariableAnnotation match = null; int localsThatAreParameters = PreorderVisitor.getNumberArguments(method.getSignature()); int startIndex = 0; if (!method.isStatic()) startIndex = 1; SignatureParser parser = new SignatureParser(method.getSignature()); Iterator<String> signatureIterator = parser.parameterSignatureIterator(); int lowestCost = Integer.MAX_VALUE; for (int i = startIndex; i < localsThatAreParameters + startIndex; i++) { String sig = signatureIterator.next(); if (signature.equals(sig)) { LocalVariableAnnotation potentialMatch = LocalVariableAnnotation.getLocalVariableAnnotation(method, i, 0, 0); if (!potentialMatch.isNamed()) continue; int distance = EditDistance.editDistance(name, potentialMatch.getName()); if (distance < lowestCost) { match = potentialMatch; match.setDescription(DID_YOU_MEAN_ROLE); lowestCost = distance; } else if (distance == lowestCost) { // not unique best match match = null; } // signatures match } } if (lowestCost < 5) return match; return null; }
/** new style encoding is targetClassName ('!' | '?') methodName '.' methodSign */ boolean decode(String encodedBinding, ClassGen cg) { int sepPos = encodedBinding.indexOf('!'); if (sepPos != -1) { // static method: invokeKind = INVOKESTATIC; } else { sepPos = encodedBinding.indexOf('?'); if (sepPos != -1) { invokeKind = INVOKEVIRTUAL; } else { return false; // old style } } targetClass = encodedBinding.substring(0, sepPos); int sigPos = encodedBinding.indexOf('(', sepPos); methodName = encodedBinding.substring(sepPos + 1, sigPos); methodSign = encodedBinding.substring(sigPos); returnType = Type.getReturnType(methodSign); args = Type.getArgumentTypes(methodSign); accessorName = "_OT$decaps$" + methodName; existsAlready = cg.containsMethod(accessorName, methodSign) != null; if (invokeKind == INVOKEVIRTUAL) { Method existing = cg.containsMethod(methodName, methodSign); if (existing != null && existing.isPrivate()) invokeKind = INVOKESPECIAL; // accessing private } return true; }
/** * implements the visitor to reset the stack and proceed for private methods * * @param obj the context object of the currently parsed code block */ @Override public void visitCode(Code obj) { Method m = getMethod(); int aFlags = m.getAccessFlags(); if ((((aFlags & Constants.ACC_PRIVATE) != 0) || ((aFlags & Constants.ACC_STATIC) != 0)) && ((aFlags & Constants.ACC_SYNTHETIC) == 0) && (!m.getSignature().endsWith(")Z"))) { stack.resetForMethodEntry(this); returnRegister = -1; returnConstant = null; registerConstants.clear(); methodSuspect = true; returnPC = -1; super.visitCode(obj); if (methodSuspect && (returnConstant != null)) { BugInstance bi = new BugInstance( this, BugType.MRC_METHOD_RETURNS_CONSTANT.name(), ((aFlags & Constants.ACC_PRIVATE) != 0) ? NORMAL_PRIORITY : LOW_PRIORITY) .addClass(this) .addMethod(this); if (returnPC >= 0) { bi.addSourceLine(this, returnPC); } bi.addString(returnConstant.toString()); bugReporter.reportBug(bi); } } }
/** * Construct a MethodDescriptor from JavaClass and method. * * @param jclass a JavaClass * @param method a Method belonging to the JavaClass * @return a MethodDescriptor identifying the method */ public static MethodDescriptor getMethodDescriptor(JavaClass jclass, Method method) { return DescriptorFactory.instance() .getMethodDescriptor( jclass.getClassName().replace('.', '/'), method.getName(), method.getSignature(), method.isStatic()); }
/** Methods marked with the "Synthetic" attribute do not appear in the source code */ private boolean isSynthetic(Method m) { if ((m.getAccessFlags() & Constants.ACC_SYNTHETIC) != 0) return true; Attribute[] attrs = m.getAttributes(); for (Attribute attr : attrs) { if (attr instanceof Synthetic) return true; } return false; }
/** * overrides the visitor to find abstract methods that override concrete ones * * @param obj the context object of the currently parsed method */ @Override public void visitMethod(Method obj) { if (!obj.isAbstract()) return; String methodName = obj.getName(); String methodSig = obj.getSignature(); outer: for (JavaClass cls : superClasses) { Method[] methods = cls.getMethods(); for (Method m : methods) { if (m.isPrivate() || m.isAbstract()) continue; if (methodName.equals(m.getName()) && methodSig.equals(m.getSignature())) { BugInstance bug = new BugInstance(this, BugType.AOM_ABSTRACT_OVERRIDDEN_METHOD.name(), NORMAL_PRIORITY) .addClass(this) .addMethod(this); Code code = obj.getCode(); if (code != null) bug.addSourceLineRange(clsContext, this, 0, code.getLength() - 1); bugReporter.reportBug(bug); break outer; } } } }
@Override public String toString() { StringBuilder s = new StringBuilder(); String n = String.format("%n"); s.append("Equivalent methods:" + n); for (Method bzm : manifest.getBaseMethods()) { s.append(" " + bzm.getName() + " -> { "); for (Method zm : ELM.get(bzm)) s.append(zm.getReturnType() + ":" + zm.getName() + " "); // TODO fix this info s.append("}" + n); } s.append("Equivalent types:" + n); for (JavaClass bzt : manifest.getBaseTypes()) { s.append(" " + bzt.getClassName() + " -> { "); for (JavaClass zt : ET.get(bzt)) s.append(zt.getClassName() + " "); s.append("}" + n); } s.append("Method costs:" + n); for (Method zm : CLM.keySet()) s.append(" " + zm.getName() + " -> " + CLM.get(zm).getName() + n); s.append("Transformation costs:" + n); for (Method zs : CLS.keySet()) s.append(" " + zs.getName() + " -> " + CLS.get(zs).getName() + n); return s.toString(); }
/** * Returns a string describing a method declaration. It contains the access flags (public, * private, static, etc), the return type, the method name, and the types of each of its * arguments. */ public static String get_method_declaration(Method m) { StringBuilder sb = new StringBuilder(); Formatter f = new Formatter(sb); f.format("%s %s %s (", get_access_flags(m), m.getReturnType(), m.getName()); for (Type at : m.getArgumentTypes()) { f.format("%s, ", at); } f.format(")"); return (sb.toString().replace(", )", ")")); }
/** * Constructor. * * @param method an XMethod specifying a specific method in a specific class * @throws ClassNotFoundException */ public JavaClassAndMethod(XMethod method) throws ClassNotFoundException { this.javaClass = Repository.lookupClass(method.getClassName()); for (Method m : javaClass.getMethods()) if (m.getName().equals(method.getName()) && m.getSignature().equals(method.getSignature()) && m.isStatic() == method.isStatic()) { this.method = m; return; } throw new IllegalArgumentException("Can't find " + method); }
public void visitMethod(Method method) { super.visitMethod(method); // now get the MethodInfo back from the ClassInfo for // additional work. String methodId = method.getName() + method.getSignature(); OldMethodInfo mi = getITMethodInfo(methodId); if (JOPizer.dumpMgci) { // GCRT new GCRTMethodInfo(mi, method); } }
/** * checks to see if it this class has unit test related annotations attached to methods * * @param cls the class to check * @return if a unit test annotation was found */ private static boolean isTestClass(JavaClass cls) { for (Method m : cls.getMethods()) { for (AnnotationEntry entry : m.getAnnotationEntries()) { String type = entry.getAnnotationType(); if (type.startsWith("Lorg/junit/") || type.startsWith("Lorg/testng/")) { return true; } } } return false; }
@Override public void visitClassContext(ClassContext classContext) { JavaClass javaClass = classContext.getJavaClass(); Method[] methodList = javaClass.getMethods(); for (Method m : methodList) { MethodGen methodGen = classContext.getMethodGen(m); if (DEBUG) { System.out.println(">>> Method: " + m.getName()); } // To suspect that an invalid String representation is being build, // we identify the construction of a MessageDigest and // the use of a function that trim leading 0. boolean invokeMessageDigest = false; boolean invokeToHexString = false; ConstantPoolGen cpg = classContext.getConstantPoolGen(); if (methodGen == null || methodGen.getInstructionList() == null) { continue; // No instruction .. nothing to do } for (Iterator itIns = methodGen.getInstructionList().iterator(); itIns.hasNext(); ) { Instruction inst = ((InstructionHandle) itIns.next()).getInstruction(); if (DEBUG) { ByteCode.printOpCode(inst, cpg); } if (inst instanceof INVOKEVIRTUAL) { // MessageDigest.digest is called INVOKEVIRTUAL invoke = (INVOKEVIRTUAL) inst; if ("java.security.MessageDigest".equals(invoke.getClassName(cpg)) && "digest".equals(invoke.getMethodName(cpg))) { invokeMessageDigest = true; } } else if (inst instanceof INVOKESTATIC && invokeMessageDigest) { // The conversion must occurs after the digest was created INVOKESTATIC invoke = (INVOKESTATIC) inst; if ("java.lang.Integer".equals(invoke.getClassName(cpg)) && "toHexString".equals(invoke.getMethodName(cpg))) { invokeToHexString = true; } } } if (invokeMessageDigest && invokeToHexString) { bugReporter.reportBug( new BugInstance(this, BAD_HEXA_CONVERSION_TYPE, Priorities.NORMAL_PRIORITY) // .addClassAndMethod(javaClass, m)); } } }
/** is there a JUnit3TestSuite */ private boolean hasSuite(Method[] methods) { for (Method m : methods) { if (m.getName().equals("suite") && m.isPublic() && m.isStatic() // && m.getReturnType().equals(junit.framework.Test.class) // && m.getArgumentTypes().length == 0 && m.getSignature().equals("()Ljunit/framework/Test;")) { return true; } } return false; }
/** Main entry for this transformer. */ public void doTransformInterface(ClassEnhancer ce, ClassGen cg) { String class_name = cg.getClassName(); ConstantPoolGen cpg = cg.getConstantPool(); checkReadClassAttributes(ce, cg, class_name, cpg); generateFieldAccessForCallout(ce, cg, class_name, cpg); generateSuperAccessors(ce, cg, class_name, cpg); HashSet<String> calloutBindings = CallinBindingManager.getCalloutBindings(class_name); if (calloutBindings == null) { if (logging) printLogMessage("\nClass " + class_name + " requires no callout adjustment."); return; } if (logging) printLogMessage("\nCallout bindings might be changing class " + class_name + ":"); HashSet<String> oldStyleBinding = new HashSet<String>(); // try new style decapsulation first (since 1.2.8): for (String calloutBinding : calloutBindings) { DecapsulationDescriptor desc = new DecapsulationDescriptor(); if (!desc.decode(calloutBinding, cg)) oldStyleBinding.add(calloutBinding); // old style attribute else if (!desc.existsAlready) ce.addMethod(desc.generate(class_name, cpg), cg); } if (oldStyleBinding.isEmpty()) return; // --> follows: old style decapsulation for remaining bindings: int pos = class_name.lastIndexOf('.'); String package_name = "NO_PACKAGE"; if (pos != -1) package_name = class_name.substring(0, pos); Method[] methods = cg.getMethods(); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; String method_name = m.getName(); boolean requiresAdjustment = CallinBindingManager.requiresCalloutAdjustment( oldStyleBinding, method_name, m.getSignature()); if (requiresAdjustment) { ce.decapsulateMethod(m, cg, package_name, cpg); } } }
public void addAllDefinitions(JavaClass obj) { String className2 = obj.getClassName(); defined.add(className2); for (Method m : obj.getMethods()) if (!m.isPrivate()) { String name = getMemberName(obj, className2, m.getNameIndex(), m.getSignatureIndex()); defined.add(name); } for (Field f : obj.getFields()) if (!f.isPrivate()) { String name = getMemberName(obj, className2, f.getNameIndex(), f.getSignatureIndex()); defined.add(name); } }
protected void loadParameterAnnotations(Method m) { for (Attribute a : m.getAttributes()) { if (a instanceof ParameterAnnotations) { ParameterAnnotationEntry[] paEntries = ((ParameterAnnotations) a).getParameterAnnotationEntries(); AnnotationInfo[][] paramAnnos = new AnnotationInfo[paEntries.length][]; for (int i = 0; i < paEntries.length; i++) { AnnotationEntry[] ae = paEntries[i].getAnnotationEntries(); if (ae.length > 0) { AnnotationInfo[] annos = new AnnotationInfo[ae.length]; for (int j = 0; j < ae.length; j++) { annos[j] = new AnnotationInfo(ae[j]); } paramAnnos[i] = annos; } else { // this paramter doesn't have an AnnotationInfo } } parameterAnnotations = paramAnnos; } } }
/** Loads the line numbers for the method. */ protected int[] loadLineNumbers(Method m) { Code c = m.getCode(); if (c == null) { return null; } LineNumberTable lnt = c.getLineNumberTable(); int length = code.length; int[] ln = new int[length]; if (lnt == null) { // no line information return null; } else { for (int i = 0; i < length; i++) { try { // annoying bug when BCEL don't seem to find linenumber - pos match ln[i] = lnt.getSourceLine(code[i].getPosition()); } catch (RuntimeException e) { System.out.print("^"); } } } return ln; }
/** * Dumps the contents of the specified class to the specified directory. The file is named * dump_dir/[class].bcel. It contains a synopsis of the fields and methods followed by the jvm * code for each method. * * @param jc javaclass to dump * @param dump_dir directory in which to write the file */ public static void dump(JavaClass jc, File dump_dir) { try { dump_dir.mkdir(); File path = new File(dump_dir, jc.getClassName() + ".bcel"); PrintStream p = new PrintStream(path); // Print the class, super class and interfaces p.printf("class %s extends %s\n", jc.getClassName(), jc.getSuperclassName()); String[] inames = jc.getInterfaceNames(); if ((inames != null) && (inames.length > 0)) { p.printf(" "); for (String iname : inames) p.printf("implements %s ", iname); p.printf("\n"); } // Print each field p.printf("\nFields\n"); for (Field f : jc.getFields()) p.printf(" %s\n", f); // Print the signature of each method p.printf("\nMethods\n"); for (Method m : jc.getMethods()) p.printf(" %s\n", m); // If this is not an interface, print the code for each method if (!jc.isInterface()) { for (Method m : jc.getMethods()) { p.printf("\nMethod %s\n", m); Code code = m.getCode(); if (code != null) p.printf(" %s\n", code.toString().replace("\n", "\n ")); } } // Print the details of the constant pool. p.printf("Constant Pool:\n"); ConstantPool cp = jc.getConstantPool(); Constant[] constants = cp.getConstantPool(); for (int ii = 0; ii < constants.length; ii++) { p.printf(" %d %s\n", ii, constants[ii]); } p.close(); } catch (Exception e) { throw new Error("Unexpected error dumping javaclass", e); } }
/** * Returns the name of the join point. * * @param method the method * @param methodSequence the method sequence * @return the name of the join point */ private static String getJoinPointName(final Method method, final int methodSequence) { final StringBuffer joinPoint = new StringBuffer(); joinPoint.append(TransformationUtil.MEMBER_METHOD_JOIN_POINT_PREFIX); joinPoint.append(method.getName()); joinPoint.append(TransformationUtil.DELIMITER); joinPoint.append(methodSequence); return joinPoint.toString(); }
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((clazz == null) ? 0 : clazz.hashCode()); result = prime * result + ((method == null) ? 0 : method.hashCode()); return result; }
/** Returns the classnames of checked exceptions thrown by the method. */ protected String[] loadThrownExceptionClassNames(Method m) { ExceptionTable et = m.getExceptionTable(); if (et != null) { return et.getExceptionNames(); } else { return null; } }