diff options
Diffstat (limited to 'java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis')
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; + } +} |