mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-03 03:37:58 +07:00
[tests] migrates bytecode analysis tests to light test case
... and moves test data out of source code
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
21
java/java-tests/testData/codeInspection/bytecodeAnalysis/data/compile.sh
Executable file
21
java/java-tests/testData/codeInspection/bytecodeAnalysis/data/compile.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
# use Java 9+
|
||||
JAVAC="$(which javac)"
|
||||
|
||||
if [ ! -x "$JAVAC" ]; then
|
||||
echo "Java compiler not defined"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf classes
|
||||
mkdir classes
|
||||
|
||||
"$JAVAC" -g --release 8 -d classes src/Expect*.java
|
||||
|
||||
"$JAVAC" -g --release 8 -d classes -cp classes src/data/*.java
|
||||
rm -rf classes/bytecodeAnalysis/data/ExtTestConverterData*
|
||||
|
||||
"$JAVAC" -g --release 9 -d classes -cp classes src/java9/*.java
|
||||
|
||||
"$JAVAC" -g --release 8 -cp classes conflict/*.java
|
||||
Binary file not shown.
@@ -0,0 +1,27 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
// A class to test the clash of the same class in different source paths
|
||||
// See also ../src/data/TestConflict.java
|
||||
public class TestConflict {
|
||||
static native int throwInDataNativeInConflict();
|
||||
|
||||
static int nativeInDataThrowInConflict() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
static int throwBoth() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
void pureInDataSideEffectInConflict() {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
void sideEffectInDataPureInConflict() { }
|
||||
|
||||
void pureBoth() { }
|
||||
|
||||
void sideEffectBoth() {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
package bytecodeAnalysis;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface ExpectContract {
|
||||
String value() default "";
|
||||
boolean pure() default false;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package bytecodeAnalysis;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExpectLeaking { }
|
||||
@@ -0,0 +1,10 @@
|
||||
package bytecodeAnalysis;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExpectNoPsiKey { }
|
||||
@@ -0,0 +1,10 @@
|
||||
package bytecodeAnalysis;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExpectNotNull { }
|
||||
@@ -0,0 +1,287 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@SuppressWarnings({"unused", "IOResourceOpenedButNotSafelyClosed"})
|
||||
public class Test01 {
|
||||
@ExpectNotNull
|
||||
@ExpectContract(pure = true)
|
||||
public static MySupplier methodReference(@ExpectNotNull String s) {
|
||||
return s::trim;
|
||||
}
|
||||
|
||||
boolean plainFlag;
|
||||
volatile boolean volatileFlag;
|
||||
|
||||
static void f(@ExpectNotNull Object o1, @ExpectNotNull Object o2) {
|
||||
if (o1 == null) throw new NullPointerException();
|
||||
else s(o2, o2);
|
||||
}
|
||||
|
||||
static void g(@ExpectNotNull Object o, boolean b) {
|
||||
if (b) f(o, o);
|
||||
else s(o, o);
|
||||
}
|
||||
|
||||
static void s(@ExpectNotNull Object o1, Object o2) {
|
||||
t(o1);
|
||||
v(o2);
|
||||
}
|
||||
|
||||
static void t(@ExpectNotNull Object o) {
|
||||
use(o);
|
||||
}
|
||||
|
||||
private static String use(@ExpectNotNull Object o) {
|
||||
System.out.println(o);
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
static void v(Object o) { }
|
||||
|
||||
@ExpectContract("null->null")
|
||||
static String toString1(Object o) {
|
||||
return o == null ? null : use(o);
|
||||
}
|
||||
|
||||
@ExpectContract("null->!null")
|
||||
static String toString2(Object o) {
|
||||
return o == null ? "null" : use(o);
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
static String constantString() {
|
||||
return "s";
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_->param1", pure = true)
|
||||
static String idString(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "->this", pure = true)
|
||||
@ExpectNotNull
|
||||
public Test01 getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "->new", pure = true)
|
||||
@ExpectNotNull
|
||||
protected Test01 createRoot() {
|
||||
return new Test01();
|
||||
}
|
||||
|
||||
@ExpectContract(value = "!null->false;null->true", pure = true)
|
||||
static boolean isNull(Object o) {
|
||||
return o == null;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "!null->true;null->false", pure = true)
|
||||
static boolean isNotNull(Object o) {
|
||||
return !isNull(o);
|
||||
}
|
||||
|
||||
interface MySupplier {
|
||||
String get();
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
@ExpectContract(pure = true)
|
||||
public static MySupplier lambda(@ExpectNotNull String s) {
|
||||
return () -> s.trim();
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
@ExpectContract(pure = true)
|
||||
public MySupplier lambdaNonStatic(@ExpectNotNull String s) {
|
||||
return () -> getThis().hashCode() + s.trim();
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
public MySupplier lambdaBranching(@ExpectNotNull String s, String t, boolean b) {
|
||||
if (b) {
|
||||
System.out.println(s);
|
||||
}
|
||||
else {
|
||||
System.out.println(t);
|
||||
}
|
||||
return () -> s.trim();
|
||||
}
|
||||
|
||||
@ExpectContract(value="null,_->fail", pure = true)
|
||||
public static void assertNotNull(@ExpectNotNull Object obj, String message) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectContract(value="false,_,_->fail;true,_,_->true", pure = true)
|
||||
public static boolean assertTrue(boolean val, String message, int data) {
|
||||
if (!val) {
|
||||
throw new IllegalArgumentException(message+":"+data);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@ExpectContract(value="true,_->fail;_,_->false", pure = true)
|
||||
public static boolean assertFalse(boolean val, String message) {
|
||||
if (val) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
@ExpectContract(value = "_,_,_->new", pure = true)
|
||||
public static long[] copyOfRange(@ExpectNotNull long[] arr, int from, int to) {
|
||||
int diff = to - from;
|
||||
if (diff < 0) {
|
||||
throw new IllegalArgumentException("Invalid arguments: " + from + '>' + to);
|
||||
}
|
||||
long[] copy = new long[diff];
|
||||
System.arraycopy(arr, from, copy, 0, Math.min(arr.length - from, diff));
|
||||
return copy;
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
@ExpectContract(value="_->new", pure = true)
|
||||
public static long[] copyAndModify(@ExpectNotNull long[] input) {
|
||||
long[] copy = copyOfRange(input, 0, input.length);
|
||||
copy[0] = 1;
|
||||
set(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static void set(@ExpectNotNull long[] copy) {
|
||||
copy[1] = 2;
|
||||
}
|
||||
|
||||
@ExpectContract(value="_,_,_,_->new", pure = true)
|
||||
public static <I, O> O[] copyOfRangeObject(@ExpectNotNull I[] arr, int from, int to, @ExpectNotNull Class<? extends O[]> newType) {
|
||||
int diff = to - from;
|
||||
if (diff < 0) {
|
||||
throw new IllegalArgumentException("Invalid arguments: " + from + '>' + to);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
O[] copy = (O[]) Array.newInstance(newType.getComponentType(), diff);
|
||||
//noinspection SuspiciousSystemArraycopy
|
||||
System.arraycopy(arr, from, copy, 0, Math.min(arr.length - from, diff));
|
||||
return copy;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_->fail", pure = true)
|
||||
public static void callAlwaysFail(int x) {
|
||||
alwaysFail();
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_->fail", pure = true)
|
||||
public static void callAlwaysFailRef(String x) {
|
||||
callAlwaysFailTwoRefs(x, null);
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_,_->fail", pure = true)
|
||||
public static void callAlwaysFailTwoRefs(String x, String y) {
|
||||
alwaysFail();
|
||||
}
|
||||
|
||||
@ExpectContract(value = "->fail", pure = true)
|
||||
private static void alwaysFail() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@ExpectContract(value = "!null->null;null->!null", pure = true)
|
||||
static String invert(String x) {
|
||||
return x == null ? "empty" : null;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "false->true;true->false", pure = true)
|
||||
static boolean invertBool(boolean x) {
|
||||
return !x;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_,true->true;null,_->true", pure=true)
|
||||
boolean checkTrueFail(Object a, boolean b) {
|
||||
if (a == null) return true;
|
||||
if (b) throw new RuntimeException();
|
||||
return b;
|
||||
}
|
||||
|
||||
@ExpectNotNull
|
||||
String getStringNoTry(@ExpectNotNull String s) throws IOException {
|
||||
return String.valueOf(new FileReader(s.trim()).read());
|
||||
}
|
||||
|
||||
String getStringTry(String s) {
|
||||
try {
|
||||
return String.valueOf(new FileReader(s.trim()).read());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectContract("null->null")
|
||||
String getStringTryNPECatched(String s) {
|
||||
try {
|
||||
return String.valueOf(new FileReader(s.trim()).read());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
void testThrow(@ExpectNotNull String s) {
|
||||
if (s.isEmpty()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectContract("_->param1")
|
||||
String testCatchReturn(String s) {
|
||||
try {
|
||||
Integer.parseInt(s);
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
System.out.println("exception!");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
boolean testCatchBool(File file) {
|
||||
try {
|
||||
Files.createDirectories(file.toPath());
|
||||
return true;
|
||||
}
|
||||
catch (IOException ignored) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
@ExpectContract("null->false")
|
||||
boolean testCatchBool2(File file) {
|
||||
try {
|
||||
Files.createDirectories(file.toPath());
|
||||
return true;
|
||||
}
|
||||
catch (Throwable ignored) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
@ExpectContract(value = "_->new", pure = true)
|
||||
String[] replaceFirstWithNull(@ExpectNotNull String[] arr) {
|
||||
String[] res = arr.clone();
|
||||
res[0] = null;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.*;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
public final class Test02 {
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
public String notNullString() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
public String notNullStringDelegate() {
|
||||
return notNullString();
|
||||
}
|
||||
|
||||
public boolean getFlagVolatile(@ExpectNotNull Test01 test01) {
|
||||
return test01.volatileFlag;
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
public boolean getFlagPlain(@ExpectNotNull Test01 test01) {
|
||||
return test01.plainFlag;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TestAnnotation { }
|
||||
@@ -0,0 +1,31 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.ExpectContract;
|
||||
|
||||
// A class to test the clash of the same class in different source paths
|
||||
// See also ../../conflict/TestConflict.java
|
||||
public class TestConflict {
|
||||
static int throwInDataNativeInConflict() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
static native int nativeInDataThrowInConflict();
|
||||
|
||||
@ExpectContract(value = "->fail", pure = true)
|
||||
static int throwBoth() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
void pureInDataSideEffectInConflict() { }
|
||||
|
||||
void sideEffectInDataPureInConflict() {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
void pureBoth() { }
|
||||
|
||||
void sideEffectBoth() {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.ExpectNoPsiKey;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
public class TestConverterData {
|
||||
public static class StaticNestedClass {
|
||||
public StaticNestedClass(Object o) { }
|
||||
|
||||
public StaticNestedClass[] test01(StaticNestedClass[] ns, StaticNestedClass... ellipsis) {
|
||||
return ns;
|
||||
}
|
||||
}
|
||||
|
||||
public class InnerClass {
|
||||
// a reference to outer class should be inserted when translating PSI -> ASM
|
||||
public InnerClass(Object o) { }
|
||||
|
||||
public InnerClass[] Inner2test01(InnerClass[] tests, InnerClass... ellipsis) {
|
||||
return tests;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenericStaticNestedClass<A> {
|
||||
public GenericStaticNestedClass(A a) { }
|
||||
|
||||
public GenericStaticNestedClass[] test01(GenericStaticNestedClass[] ns, GenericStaticNestedClass... ellipsis) {
|
||||
return ns;
|
||||
}
|
||||
|
||||
public GenericStaticNestedClass<A>[] test02(GenericStaticNestedClass<A>[] ns, GenericStaticNestedClass<A>... ellipsis) {
|
||||
return ns;
|
||||
}
|
||||
|
||||
public class GenericInnerClass<B> {
|
||||
public GenericInnerClass(B b) { }
|
||||
|
||||
public <C> GenericStaticNestedClass<A> test01(GenericInnerClass<C> c) {
|
||||
return GenericStaticNestedClass.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TestConverterData(int x) { }
|
||||
|
||||
// ExtConverterClass class is not in the class roots, so translation from PSI is impossible
|
||||
@ExpectNoPsiKey
|
||||
public ExtTestConverterData test01(ExtTestConverterData converter) {
|
||||
return converter;
|
||||
}
|
||||
|
||||
@TestAnnotation
|
||||
public TestConverterData[] test02(@TestAnnotation TestConverterData[] tests) {
|
||||
return tests;
|
||||
}
|
||||
|
||||
public boolean[] test03(boolean[] b) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
class ExtTestConverterData { }
|
||||
@@ -0,0 +1,22 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.ExpectContract;
|
||||
|
||||
public enum TestEnum {
|
||||
A, B, C;
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
public int getValue() {
|
||||
return ordinal()+1;
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
public boolean isA() {
|
||||
switch (this) {
|
||||
case A:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
public final class TestHashCollision {
|
||||
// signature hashes for these two methods collide: MD5("()V"+"test11044") and MD5("()V"+"test20917") have the same prefix: 3d802c48
|
||||
void test11044() {
|
||||
// Though purity can be inferred for this method, due to collision we erase inference result
|
||||
}
|
||||
|
||||
void test20917() {
|
||||
System.out.println("non-pure");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.ExpectLeaking;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
public class TestLeakingParametersData {
|
||||
int z;
|
||||
|
||||
void test01(@ExpectLeaking Object o1, @ExpectLeaking Object o2, @ExpectLeaking Object o3) {
|
||||
o1.toString();
|
||||
o2.toString();
|
||||
o3.toString();
|
||||
}
|
||||
|
||||
void test02(@ExpectLeaking TestLeakingParametersData d) {
|
||||
System.out.println(d.z);
|
||||
}
|
||||
|
||||
void test03(int i, @ExpectLeaking TestLeakingParametersData d) {
|
||||
System.out.println(d.z);
|
||||
}
|
||||
|
||||
void test04(long i, @ExpectLeaking TestLeakingParametersData d) {
|
||||
System.out.println(d.z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package bytecodeAnalysis.data;
|
||||
|
||||
import bytecodeAnalysis.*;
|
||||
|
||||
/**
|
||||
* @author lambdamix
|
||||
*/
|
||||
public class TestNonStable {
|
||||
public String asString1() {
|
||||
return asString();
|
||||
}
|
||||
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
public String asString() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package bytecodeAnalysis.java9;
|
||||
|
||||
import bytecodeAnalysis.*;
|
||||
|
||||
// Test that indified string concatenation is properly recognized
|
||||
// This file is precompiled via Java 9 compiler and class file is placed in the same directory
|
||||
public class TestStringConcat {
|
||||
@ExpectContract(pure = true)
|
||||
@ExpectNotNull
|
||||
String concat(String foo, String bar) {
|
||||
return foo+"!"+bar;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user