<?xml version="1.0" encoding="UTF-8"?>
<test-data
    xmlns="http://pmd.sourceforge.net/rule-tests"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">

    <test-code>
        <description>1, Exception thrown without preserving stack</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            throw new Exception(e.getMessage());
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>2, Exception thrown, stack preserved</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            throw new Exception(e);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>3, Exception thrown, stack preserved</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            throw new Exception(e, e.getMessage());
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>fillInStackTrace returns this</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            throw e.fillInStackTrace();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>fillInStackTrace on another exception</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            throw new IllegalArgumentException().fillInStackTrace();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>5, No exception thrown, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>6, No exception thrown, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            e.printStackTrace();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>7, No exception thrown, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public String foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            throw new Exception(Foo.foo(e),e);
        }
        return "";
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>8, No exception thrown, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            throw (Error)e;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>9, Excetion is cast, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            throw (Error)e.fillInStackTrace();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>9.5, Throwing same exception, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public class Foo {
                public void foo(String a) {
                    try {
                        int i = Integer.parseInt(a);
                    } catch(Exception e){
                        ((Exception)e).fillInStackTrace();
                        throw e;
                    }
                }
            }
            ]]></code>
    </test-code>

    <test-code>
        <description>9.55, Throwing same exception, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public class Foo {
                public void foo(String a) {
                    try {
                        int i = Integer.parseInt(a);
                    } catch(Exception e){
                        throw e;
                    }
                }
            }
            ]]></code>
    </test-code>

    <test-code>
        <description>10, Throwing new Exception, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e10){
            Exception e1 = new Exception(e10);
            throw e1;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>11, Throwing new Exception, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch(Exception e){
            Exception e1 = (Exception)e.fillInStackTrace();
            throw e1;
        }
    }
}
        ]]></code>
    </test-code>
    <test-code>
        <description>12, Catch and throw RuntimeException</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class B {
    public void bla() {
        try {
            ;
        } catch (IllegalStateException e) {
            throw new RuntimeException(e);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>13, Catch and throw RuntimeException, fail</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class B {
    public void bla() {
        try {
            ;
        } catch (IllegalStateException e) {
            throw new RuntimeException();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>14, Nested with same name catch and throw, fail on inner</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>7</expected-linenumbers>
        <code><![CDATA[
public class B {
    public void bla() {
        try {
            try {
                ;
            } catch (IllegalStateException ex) {
                throw new RuntimeException("Oh no!");
            }
        } catch (IllegalStateException ex) {
            throw new RuntimeException(ex);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>15, IllegalStateException can take a cause exception in the constructor, too.</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar() {
        try {
        } catch (Exception excep) {
            throw new IllegalStateException();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>16, False -, No violations reported by PreserveStackTrace Rule</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar() {
        try {
        } catch (Exception notUsed) {
            RuntimeException ex = new RuntimeException();
            throw ex;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>17, PreserveStackTrace Rule should exclude this as initCause is used.</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar() {
        try {
        } catch (Exception e) {
            IllegalStateException ex = new IllegalStateException();
            ex.initCause(e);
            throw ex;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>18, side effects on rules</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar1() {
        try {
        } catch (Exception notUsed) {
            RuntimeException ex = new RuntimeException();
            throw ex;
        }
    }

    public void bar2() {
        try {
        } catch (Exception e) {
            IllegalStateException ex = new IllegalStateException();
            ex.initCause(e);
            throw ex;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>19, False positive</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;

public class Logger {
    static Logger logger;

    void fine(String s, String e) {}
    void debug(String s, Throwable e) {}

    private static boolean isInstanceOf(final String className) {
        PrivilegedExceptionAction<Boolean> act =
            new PrivilegedExceptionAction<Boolean>() {
                public Boolean run() throws InstantiationException {
                    throw new InstantiationException();
                }
            };
        try {
            return AccessController.doPrivileged(act);
        } catch (Exception e) {
            logger.fine("isInstanceOf", "failed: " + e);
            logger.debug("isInstanceOf", e);
            return false;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>20, False positive</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    java.util.List exception_vec;

    private CodeException[] getCodeExceptions(int cp) {
        int             size  = exception_vec.size();
        CodeException[] c_exc = new CodeException[size];

        try {
            for (int i=0; i < size; i++) {
                CodeException c = (CodeException)exception_vec.get(i);
                c_exc[i] = c.getCodeException(cp);
            }
        } catch(ArrayIndexOutOfBoundsException e) {}
        return c_exc;
    }

    static class CodeException extends Exception {
        CodeException getCodeException(int i) { return this; }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>21, Java 7's multi-catch, NOK</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
class MultiCatch {

    public static void main(String[] args) {
        try {
            Class.forName("org.example.Foo").newInstance();
        } catch (InstantiationException | ClassNotFoundException | IllegalAccessException eMultiCatch) {
            throw new UnsupportedOperationException(args[0]);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>22, Java 7's multi-catch, OK</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
class MultiCatch {

    public static void main(String[] args) {
        try {
            Class.forName("org.example.Foo").newInstance();
        } catch (InstantiationException | ClassNotFoundException | IllegalAccessException eMultiCatch) {
            throw new UnsupportedOperationException(eMultiCatch);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#943 PreserveStackTrace false positive if a StringBuffer exists</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Stuff {
    @SuppressWarnings("unused")
    public void doStuff() throws RuntimeException {
        try {
            doMoreStuff();
        } catch (Exception e) {
            StringBuffer irrelevantSB = new StringBuffer("Irrelevant").append(" string").append(" buffer");
            RuntimeException someException = new RuntimeException(e);
            throw someException;
        }
    }

    private void doMoreStuff() {
        // Stuff happens
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1087 PreserveStackTrace (still) ignores initCause()</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.NoSuchElementException;
public class Test {
    public void foo() {
        try {
            // do something
        } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) {
            NoSuchElementException noSuchElementException = new NoSuchElementException(
                    "Cannot return next element, because there is none!");
            noSuchElementException.initCause(arrayIndexOutOfBoundsException);
            throw noSuchElementException;
        }

        try {
            // do something
        } catch (ArrayIndexOutOfBoundsException e) {
            throw (IllegalStateException)new IllegalStateException().initCause(e);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1087 PreserveStackTrace (still) ignores initCause() - negative test case</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
import java.util.NoSuchElementException;
public class Test {
    public void foo() {
        try {
            // do something
        } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) {
            NoSuchElementException noSuchElementException = new NoSuchElementException(
                    "Cannot return next element, because there is none!");
            noSuchElementException.initCause(new RuntimeException("some other unrelated exception"));
            throw noSuchElementException;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#794 False positive on PreserveStackTrace with anonymous inner</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.io.IOException;

public class Bug {
    void test() throws IOException {
        try {
            // do something
        } catch (final IOException e) {
            throw new IOException("b") {
                {
                    initCause(e);
                }
            };
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#422 False positive when using builder pattern</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.io.IOException;

public class Bug {
    void test() throws IOException {
        try {
            // do something
        } catch (final IOException e) {
            throw uncheckedException("ErrorCodeCommon.DIRECTORY_NOT_FOUND")
                    .withField("dirname", dirname)
                    .causedBy(e)
                    .build();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#543 False negative with String concatenation</description>
        <expected-problems>3</expected-problems>
        <code><![CDATA[
public class Foo {
    public void foo(String a) throws Exception {
        try {
            int i = Integer.parseInt(a);
        } catch(java.io.FileNotFoundException e) {
            throw new Exception("file not found:" + e.toString());
        } catch(java.io.IOException e) {
            throw new Exception("I/O error:" + e);
        } catch(Exception e) {
            throw new Exception("something bad:" + (e));
        }
    }
}
        ]]></code>
    </test-code>
    <test-code>
        <description>Don't ignore effectively final parameters</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>8</expected-linenumbers>
        <code><![CDATA[
public class Foo {

    public static <T> T getBean(String name, Class<T> requiredType) throws Exception {
        try {
            return name != null ? doGetSingleton(name, requiredType) : lookup(name, requiredType);
        } catch (NameNotFoundException ex) {
            // this one
            throw new NoSuchBeanDefinitionException(name, "not found in JNDI environment");
        } catch (NamingException ex) {
            throw new NoSuchBeanDefinitionException("JNDI environment", name, "JNDI lookup failed", ex);
        }
    }

    private static <T> T doGetSingleton(String name, Class<T> requiredType) throws NamingException {return null;}
    private static <T> T lookup(String name, Class<T> requiredType) throws NameNotFoundException {return null;}

    static class NoSuchBeanDefinitionException extends Exception {
        public NoSuchBeanDefinitionException(String s, String name, String message, Exception ex) {}
        public NoSuchBeanDefinitionException(String s, String name) {}
    }
    static class NameNotFoundException extends Exception { }
    static class NamingException extends Exception { }
}
        ]]></code>
    </test-code>
    <test-code>
        <description>[java] PreserveStackTrace false-positive #1747</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.io.IOException;

public class SomeOtherUserDefinedException extends Exception {
    public static void foo(String a) throws Exception {
        try {
	          // xxx
        } catch (IOException exception) {
            if (exception.getMessage().contains("foobar")) {
                throw new SomeOtherUserDefinedException("Error", exception);
            }
            throw exception;
        }
    }
}
        ]]></code>
    </test-code>
    <test-code>
        <description>FN with method creating exception</description>
        <expected-problems>3</expected-problems>
        <expected-linenumbers>22,24,26</expected-linenumbers>
        <code><![CDATA[
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;

public class SomeOtherUserDefinedException extends Exception {

    SomeOtherUserDefinedException(String m, Throwable cause) { super(m, cause); }

    static Object getSomething() throws Throwable { }

    protected void doInvoke() throws Throwable {
        Object ejb = null;
        try {
            ejb = getSomething();
        } catch (IOException ex) {
            throw new IllegalArgumentException("xxx", ex); // ok
        } catch (IOException ex) {
            Throwable targetEx = ex.getCause();
            if (targetEx instanceof RemoteException) {
                RemoteException rex = (RemoteException) targetEx;
                throw convertRmiAccessException(rex, isConnectFailure(rex)); // not ok
            } else if (targetEx instanceof CreateException) {
                throw convertRmiAccessException(targetEx, "message"); // not ok
            }
            throw targetEx; // not ok
        } finally {
            if (ejb instanceof Closeable) {
                ((Closeable) ejb).close();
            }
        }
    }

    private Throwable convertRmiAccessException(Throwable rex, boolean connectFailure) {return this;}

    private Throwable convertRmiAccessException(Throwable rex, String m) {return this;}

    private static boolean isConnectFailure(RemoteException rex) {return rex != null;}

    static class CreateException extends InvocationTargetException {

    }
}
        ]]></code>
    </test-code>


    <test-code>
        <description>Getter called on exception</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
            public class Foo {
                public void foo(String a) {
                    try {
                    } catch(Exception e){
                        throw e.getSomething();
                    }
                }
            }
            ]]></code>
    </test-code>


    <test-code>
        <description>#2134 [java] PreserveStackTrace not handling Throwable.addSuppressed(...)</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            import java.io.IOException;

            public class Foo {

                public void foo(String a) {
                    try {
                        return;
                    } catch (Exception innerException) {
                        RuntimeException inner = new RuntimeException();
                        inner.addSuppressed(innerException);
                        throw inner;
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Consume exception into another</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public class Foo {
                public void foo(String a) {
                    try {
                        return;
                    } catch (Exception outerException) {
                        try {
                            return;
                        } catch (Exception innerException) {
                            innerException.addSuppressed(outerException);
                            throw new RuntimeException(innerException);
                        }
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code disabled="true">
        <!-- todo reaching definitions analysis -->
        <description>FP with reassigned exception</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
            public class Foo {
                public void foo(String a) {
                    try {
                        System.out.println(a);
                    } catch (Exception outerException) {
                        outerException = new Exception();
                        throw outerException;
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code disabled="true">
        <!-- todo reaching definitions analysis -->
        <description>FP with reassigned exception (branch)</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
            public class Foo {
                public void foo(String a) {
                    try {
                        System.out.println(a);
                    } catch (Exception outerException) {
                        if (a!=null) outerException = new Exception();
                        else outerException = new RuntimeException();

                        throw outerException;
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>FP with reassigned exception</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public class Foo {
                public void foo(String a) {
                    try {
                        System.out.println(a);
                    } catch (Exception outerException) {
                        Exception e = new Exception();
                        e = outerException;
                        throw e; // throws the outer exception here, so this is not a violation
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Ignore InvocationTargetException#getTargetException</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            import java.lang.reflect.InvocationTargetException;

            public class Foo {

                public void withCast(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (InvocationTargetException ex) {
                        if (ex.getTargetException() instanceof RuntimeException) {
                            throw (RuntimeException) ex.getTargetException();
                        }
                    }
                }
                public void throwRuntime(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (InvocationTargetException ex) {
                        Exception e = ex.getTargetException();
                        if (e instanceof RuntimeException) {
                            throw (RuntimeException) e;
                        }
                    }
                }
                public void directRethrow(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (InvocationTargetException ex) {
                        throw ex.getTargetException();
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Ignore InvocationTargetException#getCause</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            import java.lang.reflect.InvocationTargetException;

            public class Foo {

                public void withCast(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (InvocationTargetException ex) {
                        if (ex.getCause() instanceof RuntimeException) {
                            throw (RuntimeException) ex.getCause();
                        }
                    }
                }
                public void throwRuntime(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (InvocationTargetException ex) {
                        Exception e = ex.getCause();
                        if (e instanceof RuntimeException) {
                            throw (RuntimeException) e;
                        }
                    }
                }
                public void directRethrow(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (InvocationTargetException ex) {
                        throw ex.getCause();
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Ignore PrivilegedActionException#getCause</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            import java.lang.reflect.InvocationTargetException;
            import java.security.PrivilegedActionException;

            public class Foo {

                public void withCast(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (PrivilegedActionException ex) {
                        if (ex.getCause() instanceof RuntimeException) {
                            throw (RuntimeException) ex.getCause();
                        }
                    }
                }

                public void throwRuntime(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (PrivilegedActionException ex) {
                        Exception e = ex.getCause();
                        if (e instanceof RuntimeException) {
                            throw (RuntimeException) e;
                        }
                    }
                }

                public void directRethrow(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (PrivilegedActionException ex) {
                        throw ex.getCause();
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Ignore PrivilegedActionException#getException</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            import java.lang.reflect.InvocationTargetException;
            import java.security.PrivilegedActionException;

            public class Foo {

                public void withCast(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (PrivilegedActionException ex) {
                        if (ex.getException() instanceof RuntimeException) {
                            throw (RuntimeException) ex.getException();
                        }
                    }
                }

                public void throwRuntime(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (PrivilegedActionException ex) {
                        Exception e = ex.getException();
                        if (e instanceof RuntimeException) {
                            throw (RuntimeException) e;
                        }
                    }
                }

                public void directRethrow(String a) throws Exception {
                    try {
                        System.out.println(a);
                    } catch (PrivilegedActionException ex) {
                        throw ex.getException();
                    }
                }
            }
            ]]></code>
    </test-code>

    <test-code>
        <description>Arguments may consume exception recursively</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public class Foo {

                public void foo(String a) {
                    try {
                        System.out.println(a);
                    } catch (NumberFormatException ex) {
                        // the exception is consumed by a constructor, which is
                        // consumed by the thrown expression
                        throw new InternalParseException(new SpelParseException(ex, "SpelMessage.NOT_A_LONG", "numberToken"));
                    }
                }

                static class InternalParseException {}
                static class SpelParseException {}
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Arguments may consume exception recursively, even across variables</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public class Foo {

                public void foo(String a) {
                    try {
                        System.out.println(a);
                    } catch (NumberFormatException ex) {
                        // same as above with intermediary variable
                        SpelParseException other = new SpelParseException(ex, "SpelMessage.NOT_A_LONG", "numberToken");
                        throw new InternalParseException(other);
                    }
                }

                static class InternalParseException { }
                static class SpelParseException { }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>StackOverflow with variable RHS which refers to itself</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public abstract class TestCase {
                public final Object resolveArgument(String parameter) throws Exception {
                    Object arg = resolveName(parameter);
                    try {
                        arg = useArg(arg);
                    } catch (Exception ex) {
                        throw new Exception(arg, ex);
                    }
                    return arg;
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Avoid NPE for unresolved variable</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public abstract class AbstractNamedValueMethodArgumentResolver {
                public final Object resolveArgument() {
                    try { }
                    catch (Exception e) {
                        throw unresolved;
                    }
                }
            }
            ]]></code>
    </test-code>

    <test-code>
        <description>Ignored exception name</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public abstract class AbstractNamedValueMethodArgumentResolver {

                public final Object resolveArgument() throws Throwable {
                    try {
                    } catch (Throwable ignored) {
                        throw new Exception();
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Ternary with both branches ok</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public abstract class AbstractNamedValueMethodArgumentResolver {

                public final Object resolveArgument() throws Throwable {
                    try {
                    } catch (Throwable ex) {
                        Exception rae = transform(ex);
                        throw rae != null ? rae
                                          : ex;
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Ternary with only one branch ok</description>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>6,14</expected-linenumbers>
        <code><![CDATA[
            public abstract class AbstractNamedValueMethodArgumentResolver {

                public final Object resolveArgument() throws Throwable {
                    try {
                    } catch (Throwable ex) {
                        throw "".isEmpty() ? new IllegalArgumentException()
                                           : ex;
                    }

                    // equivalent with if
                    try {
                    } catch (Throwable ex) {
                        if ("".isEmpty()) {
                            throw new IllegalArgumentException();
                        } else {
                            throw ex;
                        }
                    }
                }
            }
            ]]></code>
    </test-code>

    <test-code disabled="true">
        <!-- TODO both should have equivalent behavior       -->
        <description>Branch in dataflow should be merged</description>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>14,21</expected-linenumbers>
        <code><![CDATA[
            public abstract class AbstractNamedValueMethodArgumentResolver {
                // both of those should be equivalent

                public final Object resolveArgument() throws Throwable {
                    // equivalent with if
                    try {
                    } catch (Throwable ex) {
                        Throwable v;
                        if ("".isEmpty()) {
                            v = new IllegalArgumentException();
                        } else {
                            v = ex;
                        }
                        throw v;
                    }

                    // equivalent without interm. var.
                    try {
                    } catch (Throwable ex) {
                        if ("".isEmpty()) {
                            throw new IllegalArgumentException();
                        } else {
                            throw ex;
                        }
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Test the message</description>
        <expected-problems>1</expected-problems>
        <expected-messages>
            <message>Thrown exception does not preserve the stack trace of exception 'ex' on all code paths</message>
        </expected-messages>
        <code><![CDATA[
            public abstract class AbstractNamedValueMethodArgumentResolver {
                protected void setThrowingNameNoCheck(String name) {
                    try {
                        // this.discoveredThrowingType = ClassUtils.forName(name, getAspectClassLoader());
                    } catch (Throwable ex) {
                        throw new IllegalArgumentException("Throwing name '" + name  +
                                                                   "' is neither a valid argument name nor the fully-qualified " +
                                                                   "name of a Java type on the classpath. Root cause: " + ex);
                    }
                }
            }
            ]]></code>
    </test-code>
    <test-code>
        <description>Avoid stackoverflow</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    Foo(Foo foo) {}
    Foo() {}

    public void inject(Object bean, String beanName) throws Throwable {
        Foo field = new Foo();
        Object value;
        Foo desc = new Foo(field);
        try {
            value = Foo.resolveDependency(desc, beanName);
        } catch (IllegalArgumentException ex) {
            throw new FooException(beanName, new Foo(field), ex);
        }
        if (value != null) {
            field.set(bean, value);
        }
    }

    static Object resolveDependency(Foo f, String n) { return null; }
    void set(Object b, Object v) { }

    static class FooException extends RuntimeException {

        FooException(String s, Foo f, Throwable e) {}
    }
}
            ]]></code>
    </test-code>

    <test-code>
        <description>#5318 [java] PreserveStackTraceRule: false-positive on Pattern Matching with instanceof</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.function.Consumer;

public class Foo {
    public void withPatternMatching(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch (RuntimeException e) {
            throw e instanceof NumberFormatException numberFormatException
                    ? formatExceptionHandler.accept(numberFormatException)
                    : e;
        }
    }

    public void withExplicitCast(String a) {
        try {
            int i = Integer.parseInt(a);
        } catch (RuntimeException e) {
            throw e instanceof NumberFormatException
                    ? formatExceptionHandler.accept((NumberFormatException) e)
                    : e;
        }
    }

    private Consumer<NumberFormatException> formatExceptionHandler = e -> { e.printStackTrace(); };
}
]]></code>
    </test-code>
</test-data>
