<?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>Clear violation</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    String [] arr;
    String [] getArr() {return arr;}
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Clear violation with this.</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    String [] arr;
    String [] getArr() {return this.arr;}
}
        ]]></code>
    </test-code>

    <test-code>
        <description>ok</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    String [] arr;
    String [] getArr() {String[] foo; return foo;}
}
        ]]></code>
    </test-code>

    <test-code>
        <description>tricky field hiding</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    String [] arr;
    String [] getArr() {String[] arr; return arr;}
}
        ]]></code>
    </test-code>

    <test-code>
        <description>really sick code</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    String [] arr;
    String [] getArr() {String[] arr; return this.arr;}
}
        ]]></code>
    </test-code>

    <test-code>
        <description>returning a local array is ok</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    int[] getArr() {
        int[] x = new int[] {1,2,3};
        return x;
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>returning a local array is ok part deux</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    Object[] getArr() {
        return new Object[] {foo,bar};
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>returning a cloned field</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    private Object[] x;
    Object[] getArr() {
        return this.x.clone();
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>returning a new array</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    private Object x;
    Object[] getArr() {
        return new Object[] {x};
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Doesn't return array</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    String [] arr;
    String getArr() {return arr[0];}
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Interface with array declaration</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public interface Foo {
    public String[] getArr();
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#962 MethodReturnsInternalArray: False positive using a ternary operator</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Test {
    byte[] content;
    public byte[] getContent() {
        return this.content == null ? null : content.clone();
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1299 MethodReturnsInternalArray false positive</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.Arrays;
public class WebServiceResponseMessage {
    private Object[] responseObjects;
    public Object[] getResponseObjects() {
        return responseObjects == null ? null : Arrays.copyOf(responseObjects, responseObjects.length);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1324 MethodReturnsInternalArray false positive with clone()</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Test {
    private Hit[] hits;
    public Hit[] getHits() {
        return hits == null ? null : hits.clone();
    }
    static class Hit {}
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1322 MethodReturnsInternalArray on private methods</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class A {
    private Object[] content;
    // This method should not be a violation of MethodReturnsInternalArray
    private Object[] getContent() {
        return content;
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1475 False positive of MethodReturnsInternalArray</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class MethodReturnsInternalArrayCase {
    private static final byte[] DATA = {};

    protected final byte[] getData()
    {
        return DATA;
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1475 False positive of MethodReturnsInternalArray - ArrayAllocation</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class MethodReturnsInternalArrayCase {
    private static final byte[] DATA = new byte[0];

    protected final byte[] getData()
    {
        return DATA;
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#3160 nonempty static final fields</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
            public class MyClass {
                private static final String[] FOO_BAR = new String[] { "foo", "bar" };
                public final String[] call() { return FOO_BAR; }
            }
            ]]></code>
    </test-code>

    <test-code>
        <description>#3160 empty non-final fields</description>
        <expected-problems>4</expected-problems>
        <code><![CDATA[
            public class MyClass {
                private String[] foobar1 = new String[0];
                private String[] foobar2 = {};
                private static String[] FOO_BAR_3 = new String[0];
                private static String[] FOO_BAR_4 = {};
                public final String[] call1() { return foobar1; }
                public final String[] call2() { return foobar2; }
                public final String[] call3() { return FOO_BAR_3; }
                public final String[] call4() { return FOO_BAR_4; }
            }
            ]]></code>
    </test-code>

    <test-code>
        <description>Unresolved array: assume public</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
            public class MethodReturnsInternalArrayCase {
                protected final byte[] getData() {
                    return SomeClass.UNRESOLVED;
                }
            }
            class SomeClass {
                // unresolved field, should assume public
            }
            ]]></code>
    </test-code>

    <test-code>
        <description>#1738 MethodReturnsInternalArray in inner classes</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Outer {
    public static class Inner {
        private int[] arr2;

        public int[] getArr2() {
            return arr2;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1845 Regression in MethodReturnsInternalArray not handling enums</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.Arrays;
public enum MethodReturnsInternalArrayCaseEnum {
    ONE("One"),
    TWO("Two", "Three");

    private String[] titles;

    MethodReturnsInternalArrayCaseEnum(String... titles) {
        this.titles = Arrays.copyOf(titles, titles.length);
    }

    public String[] getTitles() {
        return titles.clone();
    }

    @Override
    public String toString() {
        return titles[0];
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Inner interface</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public interface OuterInterface {
       interface InnerInterface {
            String[] method();
       }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Inner annotation</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
public final class I {
    private I() {
    }
    @Retention(RetentionPolicy.RUNTIME)
    public static @interface Inner {
        String[] value();
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Top-level annotation</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TopLevelAnnotation {

    String[] value();

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

    <test-code>
        <description>Enum that returns array instead of copy</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public enum MethodReturnsInternalArrayCaseEnum {
    ONE("One"),
    TWO("Two", "Three");

    private String[] titles;

    MethodReturnsInternalArrayCaseEnum(String... titles) {
        this.titles = titles;
    }

    public String[] getTitles() {
        return titles;
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Inner enum that returns array instead of copy</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class OuterClass {

    public enum InnerEnum {
        INNER_ENUM("first", "second");
        private String[] titles;

        InnerEnum(String... titles) {
            this.titles = titles;
        }

        public String[] getTitles() {
            return titles;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Inner enum that returns copy of array</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.Arrays;
public class OuterClass {

    public enum InnerEnum {
        INNER_ENUM("first", "second");
        private String[] titles;

        InnerEnum(String... titles) {
            this.titles = titles;
        }

        public String[] getTitles() {
            return Arrays.copyOf(titles, titles.length);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Nested methods and local class</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class OuterClass {
    public int[] arrayReturningMethod() {
        class LocalClass {
            private String s;
            public String getString() {
                return this.s;
            }
        }
        LocalClass c = new LocalClass();
        return new int[0];
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Detect returned static arrays</description>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>8,16</expected-linenumbers>
        <code><![CDATA[
import java.util.concurrent.Callable;

public class MyClass {
    private static final String[] FOO_BAR = new String[] { "foo", "bar" };
    private final Callable<String[]> returnsFooBar = new Callable<String[]>() {
        @Override
        public String[] call() {
            return FOO_BAR;
        }
    };

    private static String[] fooBarNonFinal = new String[] { "foo", "bar" };
    private final Callable<String[]> returnsFooBarNonFinal = new Callable<String[]>() {
        @Override
        public String[] call() {
            return fooBarNonFinal; // violation
        }
    };
}
        ]]></code>
    </test-code>

    <test-code>
        <description>nested class in interface</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>4</expected-linenumbers>
        <code><![CDATA[
public interface Outer {
    class Foo {
        String [] arr;
        String [] getArr() {return arr;}
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>[java] MethodReturnsInternalArray doesn't consider anonymous classes #3630</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>7</expected-linenumbers>
        <code><![CDATA[
public class Outer {
    private static final String[] names = new String[] {"a", "b"};
    public static Provider getProvider() {
        return new Provider() {
            @Override
            public String[] getNames() {
                return names;
            }
        };
    }
    public interface Provider {
        String[] getNames();
    }
}
        ]]></code>
    </test-code>
</test-data>
