summaryrefslogtreecommitdiff
path: root/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis')
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java177
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisResultsHighlightingTest.java67
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java209
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectContract.java30
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectLeaking.java26
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectNoPsiKey.java26
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectNotNull.java26
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/LeakingParametersData.java43
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test01.java78
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test02.java33
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test03.java34
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/TestAnnotation.java26
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/TestConverterData.java81
13 files changed, 856 insertions, 0 deletions
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java
new file mode 100644
index 000000000000..516b140cc0b1
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.codeInsight.ExternalAnnotationsManager;
+import com.intellij.codeInsight.InferredAnnotationsManager;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkModificator;
+import com.intellij.openapi.roots.AnnotationOrderRootType;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ModuleRootModificationUtil;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileVisitor;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiFormatUtil;
+import com.intellij.testFramework.PsiTestUtil;
+import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
+import com.intellij.util.AsynchConsumer;
+import org.jetbrains.annotations.Contract;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author lambdamix
+ */
+public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestCase {
+ public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
+
+ private InferredAnnotationsManager myInferredAnnotationsManager;
+ private ExternalAnnotationsManager myExternalAnnotationsManager;
+
+ private List<String> diffs = new ArrayList<String>();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ setUpLibraries();
+ setUpExternalUpAnnotations();
+
+ myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject());
+ myExternalAnnotationsManager = ExternalAnnotationsManager.getInstance(myModule.getProject());
+ }
+
+ private void setUpLibraries() {
+ VirtualFile lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/../../../lib");
+ assertNotNull(lib);
+ PsiTestUtil.addLibrary(myModule, "velocity", lib.getPath(), new String[]{"/velocity.jar!/"}, new String[]{});
+ }
+
+ private void setUpExternalUpAnnotations() {
+ String annotationsPath = PathManagerEx.getTestDataPath() + "/codeInspection/bytecodeAnalysis/annotations";
+ final VirtualFile annotationsDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(annotationsPath);
+ assertNotNull(annotationsDir);
+
+ ModuleRootModificationUtil.updateModel(myModule, new AsynchConsumer<ModifiableRootModel>() {
+ @Override
+ public void finished() {
+ }
+
+ @Override
+ public void consume(ModifiableRootModel modifiableRootModel) {
+ final LibraryTable libraryTable = modifiableRootModel.getModuleLibraryTable();
+ Library[] libs = libraryTable.getLibraries();
+ for (Library library : libs) {
+ final Library.ModifiableModel libraryModel = library.getModifiableModel();
+ libraryModel.addRoot(annotationsDir, AnnotationOrderRootType.getInstance());
+ libraryModel.commit();
+ }
+ Sdk sdk = modifiableRootModel.getSdk();
+ if (sdk != null) {
+ SdkModificator sdkModificator = sdk.getSdkModificator();
+ sdkModificator.addRoot(annotationsDir, AnnotationOrderRootType.getInstance());
+ sdkModificator.commitChanges();
+ }
+ }
+ });
+
+ VfsUtilCore.visitChildrenRecursively(annotationsDir, new VirtualFileVisitor() { });
+ annotationsDir.refresh(false, true);
+ }
+
+ public void testSdkAndLibAnnotations() {
+
+ final PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage("");
+ assert rootPackage != null;
+
+ final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
+ JavaRecursiveElementVisitor visitor = new JavaRecursiveElementVisitor() {
+ @Override
+ public void visitPackage(PsiPackage aPackage) {
+ for (PsiPackage subPackage : aPackage.getSubPackages(scope)) {
+ visitPackage(subPackage);
+ }
+ for (PsiClass aClass : aPackage.getClasses(scope)) {
+ for (PsiMethod method : aClass.getMethods()) {
+ checkMethodAnnotations(method);
+ }
+ }
+ }
+ };
+
+ rootPackage.accept(visitor);
+ assertEmpty(diffs);
+ }
+
+ private void checkMethodAnnotations(PsiMethod method) {
+ try {
+ if (ProjectBytecodeAnalysis.getKey(method) == -1) {
+ return;
+ }
+ }
+ catch (IOException e) {
+ fail();
+ }
+
+ // not null-result
+ String externalOutAnnotation =
+ myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
+ String inferredOutAnnotation =
+ myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
+ String methodKey = PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE);
+
+ if (!externalOutAnnotation.equals(inferredOutAnnotation)) {
+ diffs.add(methodKey + ": " + externalOutAnnotation + " != " + inferredOutAnnotation);
+ }
+
+ for (PsiParameter parameter : method.getParameterList().getParameters()) {
+ String parameterKey = PsiFormatUtil.getExternalName(parameter, false, Integer.MAX_VALUE);
+ String externalParameterAnnotation =
+ myExternalAnnotationsManager.findExternalAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
+ String inferredParameterAnnotation =
+ myInferredAnnotationsManager.findInferredAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
+ if (!externalParameterAnnotation.equals(inferredParameterAnnotation)) {
+ diffs.add(parameterKey + ": " + externalParameterAnnotation + " != " + inferredParameterAnnotation);
+ }
+ }
+
+ PsiAnnotation externalContractAnnotation =
+ myExternalAnnotationsManager.findExternalAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
+ PsiAnnotation inferredContractAnnotation =
+ myInferredAnnotationsManager.findInferredAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
+
+ String externalContractAnnotationString =
+ externalContractAnnotation == null ? "null" : "@Contract(" + AnnotationUtil.getStringAttributeValue(externalContractAnnotation, null) + ")";
+ String inferredContractAnnotationString =
+ inferredContractAnnotation == null ? "null" : "@Contract(" + AnnotationUtil.getStringAttributeValue(inferredContractAnnotation, null) + ")";
+
+ if (!externalContractAnnotationString.equals(inferredContractAnnotationString)) {
+ diffs.add(methodKey + ": " + externalContractAnnotationString + " != " + inferredContractAnnotationString);
+ }
+
+ }
+
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisResultsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisResultsHighlightingTest.java
new file mode 100644
index 000000000000..dc67871e6283
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisResultsHighlightingTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.codeInspection.dataFlow.DataFlowInspection;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.LightProjectDescriptor;
+import com.intellij.testFramework.PsiTestUtil;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author lambdamix
+ */
+public class BytecodeAnalysisResultsHighlightingTest extends LightCodeInsightFixtureTestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ setUpLibraries();
+ }
+
+ @NotNull
+ @Override
+ protected LightProjectDescriptor getProjectDescriptor() {
+ return JAVA_1_7;
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return JavaTestUtil.getJavaTestDataPath() + "/codeInspection/bytecodeAnalysis/src/";
+ }
+
+ private void doTest() {
+ final DataFlowInspection inspection = new DataFlowInspection();
+ inspection.SUGGEST_NULLABLE_ANNOTATIONS = true;
+ inspection.REPORT_CONSTANT_REFERENCE_VALUES = false;
+ myFixture.enableInspections(inspection);
+ myFixture.testHighlighting(true, false, true, getTestName(false) + ".java");
+ }
+
+ public void testExample() {
+ doTest();
+ }
+
+ private void setUpLibraries() {
+ VirtualFile lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/../../../lib");
+ assertNotNull(lib);
+ PsiTestUtil.addLibrary(myModule, "velocity", lib.getPath(), new String[]{"/velocity.jar!/"}, new String[]{});
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java
new file mode 100644
index 000000000000..09fa87fa95e9
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.codeInsight.InferredAnnotationsManager;
+import com.intellij.codeInspection.bytecodeAnalysis.data.*;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.testFramework.PsiTestUtil;
+import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.org.objectweb.asm.*;
+import org.jetbrains.org.objectweb.asm.tree.MethodNode;
+import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+
+/**
+ * @author lambdamix
+ */
+public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
+ public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
+ private final String myClassesProjectRelativePath = "/classes/" + Test01.class.getPackage().getName().replace('.', '/');
+ private JavaPsiFacade myJavaPsiFacade;
+ private InferredAnnotationsManager myInferredAnnotationsManager;
+ private BytecodeAnalysisConverter myBytecodeAnalysisConverter;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myJavaPsiFacade = JavaPsiFacade.getInstance(myModule.getProject());
+ myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject());
+ myBytecodeAnalysisConverter = BytecodeAnalysisConverter.getInstance();
+
+ setUpDataClasses();
+ }
+
+ public void testInference() throws IOException {
+ checkAnnotations(Test01.class);
+ checkAnnotations(Test02.class);
+ checkAnnotations(Test03.class);
+ }
+
+ public void testConverter() throws IOException {
+ checkCompoundIds(Test01.class);
+ checkCompoundIds(TestConverterData.class);
+ checkCompoundIds(TestConverterData.StaticNestedClass.class);
+ checkCompoundIds(TestConverterData.InnerClass.class);
+ checkCompoundIds(TestConverterData.GenericStaticNestedClass.class);
+ checkCompoundIds(TestAnnotation.class);
+ }
+
+ public void testLeakingParametersAnalysis() throws IOException {
+ checkLeakingParameters(LeakingParametersData.class);
+ }
+
+ private static void checkLeakingParameters(Class<?> jClass) throws IOException {
+ final HashMap<Method, boolean[]> map = new HashMap<Method, boolean[]>();
+
+ // collecting leakedParameters
+ final ClassReader classReader = new ClassReader(new FileInputStream(jClass.getResource("/" + jClass.getName().replace('.', '/') + ".class").getFile()));
+ classReader.accept(new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ final MethodNode node = new MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions);
+ final Method method = new Method(classReader.getClassName(), name, desc);
+ return new MethodVisitor(Opcodes.ASM5, node) {
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+ try {
+ map.put(method, cfg.leakingParameters(classReader.getClassName(), node));
+ }
+ catch (AnalyzerException ignore) {}
+ }
+ };
+ }
+ }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+
+ for (java.lang.reflect.Method jMethod : jClass.getDeclaredMethods()) {
+ Method method = new Method(Type.getType(jClass).getInternalName(), jMethod.getName(), Type.getMethodDescriptor(jMethod));
+ Annotation[][] annotations = jMethod.getParameterAnnotations();
+ for (int i = 0; i < annotations.length; i++) {
+ boolean isLeaking = false;
+ Annotation[] parameterAnnotations = annotations[i];
+ for (Annotation parameterAnnotation : parameterAnnotations) {
+ if (parameterAnnotation.annotationType() == ExpectLeaking.class) {
+ isLeaking = true;
+ }
+ }
+ assertEquals(method.toString() + " #" + i, isLeaking, map.get(method)[i]);
+ }
+ }
+ }
+
+ private void checkAnnotations(Class<?> javaClass) {
+ PsiClass psiClass = myJavaPsiFacade.findClass(javaClass.getName(), GlobalSearchScope.moduleWithLibrariesScope(myModule));
+ assertNotNull(psiClass);
+
+ for (java.lang.reflect.Method javaMethod : javaClass.getDeclaredMethods()) {
+ PsiMethod psiMethod = psiClass.findMethodsByName(javaMethod.getName(), false)[0];
+ Annotation[][] annotations = javaMethod.getParameterAnnotations();
+
+ // not-null parameters
+ params: for (int i = 0; i < annotations.length; i++) {
+ Annotation[] parameterAnnotations = annotations[i];
+ PsiParameter psiParameter = psiMethod.getParameterList().getParameters()[i];
+ PsiAnnotation inferredAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
+ for (Annotation parameterAnnotation : parameterAnnotations) {
+ if (parameterAnnotation.annotationType() == ExpectNotNull.class) {
+ assertNotNull(javaMethod.toString() + " " + i, inferredAnnotation);
+ continue params;
+ }
+ }
+ assertNull(javaMethod.toString() + " " + i, inferredAnnotation);
+ }
+
+ // not-null result
+ ExpectNotNull expectedAnnotation = javaMethod.getAnnotation(ExpectNotNull.class);
+ PsiAnnotation actualAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL);
+ assertEquals(javaMethod.toString(), expectedAnnotation == null, actualAnnotation == null);
+
+
+ // contracts
+ ExpectContract expectedContract = javaMethod.getAnnotation(ExpectContract.class);
+ PsiAnnotation actualContractAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
+
+ assertEquals(expectedContract == null, actualContractAnnotation == null);
+
+ if (expectedContract != null) {
+ String expectedContractValue = expectedContract.value();
+ String actualContractValue = AnnotationUtil.getStringAttributeValue(actualContractAnnotation, null);
+ assertEquals(javaMethod.toString(), expectedContractValue, actualContractValue);
+ }
+
+ }
+ }
+
+ private void checkCompoundIds(Class<?> javaClass) throws IOException {
+ String javaClassName = javaClass.getCanonicalName();
+ PsiClass psiClass = myJavaPsiFacade.findClass(javaClassName, GlobalSearchScope.moduleWithLibrariesScope(myModule));
+ assertNotNull(psiClass);
+
+ for (java.lang.reflect.Method javaMethod : javaClass.getDeclaredMethods()) {
+ Method method = new Method(Type.getType(javaClass).getInternalName(), javaMethod.getName(), Type.getMethodDescriptor(javaMethod));
+ boolean noKey = javaMethod.getAnnotation(ExpectNoPsiKey.class) != null;
+ PsiMethod psiMethod = psiClass.findMethodsByName(javaMethod.getName(), false)[0];
+ checkCompoundId(method, psiMethod, noKey);
+ }
+
+ for (Constructor<?> constructor : javaClass.getDeclaredConstructors()) {
+ Method method = new Method(Type.getType(javaClass).getInternalName(), "<init>", Type.getConstructorDescriptor(constructor));
+ boolean noKey = constructor.getAnnotation(ExpectNoPsiKey.class) != null;
+ PsiMethod[] constructors = psiClass.getConstructors();
+ PsiMethod psiMethod = constructors[0];
+ checkCompoundId(method, psiMethod, noKey);
+ }
+ }
+
+ private void checkCompoundId(Method method, PsiMethod psiMethod, boolean noKey) throws IOException {
+ Direction direction = new Out();
+ int psiKey = myBytecodeAnalysisConverter.mkPsiKey(psiMethod, direction);
+ if (noKey) {
+ assertTrue(-1 == psiKey);
+ return;
+ }
+ else {
+ assertFalse(-1 == psiKey);
+ }
+
+ int asmKey = myBytecodeAnalysisConverter.mkAsmKey(new Key(method, direction, true));
+
+ Assert.assertEquals(asmKey, psiKey);
+ }
+
+ private void setUpDataClasses() throws IOException {
+ File classesDir = new File(Test01.class.getResource("/" + Test01.class.getPackage().getName().replace('.', '/')).getFile());
+ File destDir = new File(myModule.getProject().getBaseDir().getPath() + myClassesProjectRelativePath);
+ FileUtil.copyDir(classesDir, destDir);
+ VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(destDir);
+ assertNotNull(vFile);
+ PsiTestUtil.addLibrary(myModule, "dataClasses", vFile.getPath(), new String[]{""}, ArrayUtil.EMPTY_STRING_ARRAY);
+ }
+
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectContract.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectContract.java
new file mode 100644
index 000000000000..9b78f742eb9c
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectContract.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.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 "";
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectLeaking.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectLeaking.java
new file mode 100644
index 000000000000..3c5ded3427ba
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectLeaking.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @author lambdamix
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExpectLeaking {
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectNoPsiKey.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectNoPsiKey.java
new file mode 100644
index 000000000000..dde06c0f153b
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectNoPsiKey.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @author lambdamix
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExpectNoPsiKey {
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectNotNull.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectNotNull.java
new file mode 100644
index 000000000000..39f1c6e7f363
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectNotNull.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @author lambdamix
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExpectNotNull {
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/LeakingParametersData.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/LeakingParametersData.java
new file mode 100644
index 000000000000..ff5887ff2dbb
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/LeakingParametersData.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.data;
+
+import com.intellij.codeInspection.bytecodeAnalysis.ExpectLeaking;
+
+/**
+ * @author lambdamix
+ */
+public class LeakingParametersData {
+ int z;
+
+ void test01(@ExpectLeaking Object o1, @ExpectLeaking Object o2, @ExpectLeaking Object o3) {
+ o1.toString();
+ o2.toString();
+ o3.toString();
+ }
+
+ void test02(@ExpectLeaking LeakingParametersData d) {
+ System.out.println(d.z);
+ }
+
+ void test03(int i, @ExpectLeaking LeakingParametersData d) {
+ System.out.println(d.z);
+ }
+
+ void test04(long i, @ExpectLeaking LeakingParametersData d) {
+ System.out.println(d.z);
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test01.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test01.java
new file mode 100644
index 000000000000..1b90bb640b39
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test01.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.data;
+
+import com.intellij.codeInspection.bytecodeAnalysis.ExpectContract;
+import com.intellij.codeInspection.bytecodeAnalysis.ExpectNotNull;
+
+/**
+ * @author lambdamix
+ */
+public class Test01 {
+ 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) {
+ o.toString();
+ }
+
+ static void v(Object o) {
+
+ }
+
+ @ExpectContract("null->null")
+ static String toString1(Object o) {
+ return o == null ? null : o.toString();
+ }
+
+ @ExpectContract("null->!null")
+ static String toString2(Object o) {
+ return o == null ? "null" : o.toString();
+ }
+
+ @ExpectNotNull
+ static String constantString() {
+ return "s";
+ }
+
+ @ExpectContract("!null->!null;null->null")
+ static String idString(String s) {
+ return s;
+ }
+
+ @ExpectNotNull
+ public Test01 getThis() {
+ return this;
+ }
+
+ @ExpectNotNull
+ protected Test01 createRoot() {
+ return new Test01();
+ }
+
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test02.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test02.java
new file mode 100644
index 000000000000..f794ff23009b
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test02.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.data;
+
+import com.intellij.codeInspection.bytecodeAnalysis.ExpectNotNull;
+
+/**
+ * @author lambdamix
+ */
+public final class Test02 {
+ @ExpectNotNull
+ public String notNullString() {
+ return "";
+ }
+
+ @ExpectNotNull
+ public String notNullStringDelegate() {
+ return notNullString();
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test03.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test03.java
new file mode 100644
index 000000000000..97903933190e
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test03.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.data;
+
+import com.intellij.codeInspection.bytecodeAnalysis.ExpectNotNull;
+
+/**
+ * @author lambdamix
+ */
+public class Test03 {
+
+ public String toString1() {
+ return toString();
+ }
+
+ @Override
+ @ExpectNotNull
+ public String toString() {
+ return "";
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/TestAnnotation.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/TestAnnotation.java
new file mode 100644
index 000000000000..cfe55ff5cd28
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/TestAnnotation.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.data;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @author lambdamix
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestAnnotation {
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/TestConverterData.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/TestConverterData.java
new file mode 100644
index 000000000000..254db418e55c
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/TestConverterData.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.data;
+
+import com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisConverter;
+import com.intellij.codeInspection.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) {}
+
+ // BytecodeAnalysisConverter class is not in the project path, so translation from PSI is impossible
+ @ExpectNoPsiKey
+ public BytecodeAnalysisConverter test01(BytecodeAnalysisConverter converter) {
+ return converter;
+ }
+
+ @TestAnnotation
+ public TestConverterData[] test02(@TestAnnotation TestConverterData[] tests) throws Exception {
+ return tests;
+ }
+
+ public boolean[] test03(boolean[] b) {
+ return b;
+ }
+}