From 44ea3071e9ed20920ad2266f22b2f56ad7d7b2c2 Mon Sep 17 00:00:00 2001 From: Ilya Klyuchnikov Date: Sun, 8 Jun 2014 18:24:26 +0400 Subject: [PATCH] testing contract annotations --- .../bytecodeAnalysis/ClassProcessor.java | 2 -- .../codeInspection/bytecodeAnalysis/Util.java | 7 +++-- .../BytecodeAnalysisTest.java | 15 +++++++++- .../bytecodeAnalysis/ExpectContract.java | 30 +++++++++++++++++++ .../bytecodeAnalysis/data/Test01.java | 12 ++++++++ 5 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/ExpectContract.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassProcessor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassProcessor.java index 680789cda86c..439566655e05 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassProcessor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassProcessor.java @@ -35,7 +35,6 @@ public class ClassProcessor extends VirtualFileVisitor { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis.ClassProcessor"); final static ELattice valueLattice = new ELattice(Value.Bot, Value.Top); - final Solver solver = new Solver(valueLattice); final IntIdSolver myIntIdSolver; @NotNull @@ -163,7 +162,6 @@ public class ClassProcessor extends VirtualFileVisitor { void addEquation(Equation equation) { try { - //solver.addEquation(equation); myIntIdSolver.addEquation(enumerate(equation)); } catch (IOException e) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Util.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Util.java index ad44535436fb..bd52c019cca4 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Util.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Util.java @@ -48,7 +48,7 @@ public class Util { if (value == Value.Top || value == Value.Bot) { continue; } - InternalKey key = null; + InternalKey key; try { String s = enumerators.internalKeyEnumerator.valueOf(inKey); key = readInternalKey(s); @@ -68,6 +68,7 @@ public class Util { else if (direction instanceof Out && value == Value.NotNull) { annotations.add(baseAnnKey, new AnnotationData("org.jetbrains.annotations.NotNull", "")); } + // TODO - sort (normalize) contract clauses else if (direction instanceof InOut) { StringBuilder sb = contracts.get(baseAnnKey); if (sb == null) { @@ -83,7 +84,9 @@ public class Util { } for (Map.Entry contract : contracts.entrySet()) { - annotations.add(contract.getKey(), new AnnotationData("org.jetbrains.annotations.Contract", contract.getValue().append('"').toString())); + if (!annotations.containsKey(contract.getKey())) { + annotations.add(contract.getKey(), new AnnotationData("org.jetbrains.annotations.Contract", contract.getValue().append('"').toString())); + } } return annotations; } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java index 4ea9e25145ff..a31eac7f7bf6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java @@ -26,6 +26,7 @@ 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 java.io.File; import java.io.IOException; @@ -35,7 +36,7 @@ import java.lang.annotation.Annotation; * @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; @@ -95,6 +96,18 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase { ExpectNotNull expectedAnnotation = javaMethod.getAnnotation(ExpectNotNull.class); PsiAnnotation actualAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL); assertEquals(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 (expectedAnnotation != null) { + String expectedContractValue = expectedContract.value(); + String actualContractValue = AnnotationUtil.getStringAttributeValue(actualContractAnnotation, null); + assertEquals(expectedContractValue, actualContractValue); + } } } 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/data/Test01.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test01.java index 727479ca6b19..fbc28186ec05 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test01.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/data/Test01.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection.bytecodeAnalysis.data; +import com.intellij.codeInspection.bytecodeAnalysis.ExpectContract; import com.intellij.codeInspection.bytecodeAnalysis.ExpectNotNull; /** @@ -43,4 +44,15 @@ public class Test01 { 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(); + } + }