From cc237c0a58a6a6390396cdcf3874ec730cf03c90 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 14 Feb 2017 10:01:45 +0100 Subject: [PATCH] make it explicit that nullity/contract inference from source works only with PsiMethodImpl inspired by https://github.com/JetBrains/intellij-community/pull/511 --- .../InferredAnnotationsManagerImpl.java | 17 +++++++++-------- .../dataFlow/ContractInference.java | 5 +++-- .../dataFlow/ContractInferenceIndex.kt | 7 +------ .../dataFlow/InferenceFromSourceUtil.java | 6 ++---- .../dataFlow/NullityInference.java | 8 ++++++-- .../dataFlow/PurityInference.java | 4 ++-- .../codeInspection/dataFlow/inferenceResults.kt | 5 +++-- .../ContractInferenceFromSourceTest.groovy | 9 +++++---- .../PurityInferenceFromSourceTest.groovy | 3 ++- 9 files changed, 33 insertions(+), 31 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java index b4eafcd7322b..545f2cf09db1 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java @@ -20,6 +20,7 @@ import com.intellij.codeInspection.dataFlow.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.impl.source.PsiMethodImpl; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -57,13 +58,13 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { return fromBytecode; } - if (listOwner instanceof PsiMethod) { + if (listOwner instanceof PsiMethodImpl) { if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN)) { - return getInferredContractAnnotation((PsiMethod)listOwner); + return getInferredContractAnnotation((PsiMethodImpl)listOwner); } if ((AnnotationUtil.NOT_NULL.equals(annotationFQN) || AnnotationUtil.NULLABLE.equals(annotationFQN))) { - PsiAnnotation anno = getInferredNullityAnnotation((PsiMethod)listOwner); + PsiAnnotation anno = getInferredNullityAnnotation((PsiMethodImpl)listOwner); return anno == null ? null : annotationFQN.equals(anno.getQualifiedName()) ? anno : null; } } @@ -97,7 +98,7 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { } @Nullable - private PsiAnnotation getInferredContractAnnotation(PsiMethod method) { + private PsiAnnotation getInferredContractAnnotation(PsiMethodImpl method) { if (method.getModifierList().findAnnotation(ORG_JETBRAINS_ANNOTATIONS_CONTRACT) != null) { return null; } @@ -106,7 +107,7 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { } @Nullable - private PsiAnnotation getInferredNullityAnnotation(PsiMethod method) { + private PsiAnnotation getInferredNullityAnnotation(PsiMethodImpl method) { NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject); if (AnnotationUtil.findAnnotation(method, manager.getNotNulls(), true) != null || AnnotationUtil.findAnnotation(method, manager.getNullables(), true) != null) { return null; @@ -159,16 +160,16 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { } } - if (listOwner instanceof PsiMethod) { + if (listOwner instanceof PsiMethodImpl) { PsiAnnotation hardcoded = getHardcodedContractAnnotation((PsiMethod)listOwner); if (hardcoded != null) { result.add(hardcoded); } else if (!ignoreInference(listOwner, ORG_JETBRAINS_ANNOTATIONS_CONTRACT)) { - ContainerUtil.addIfNotNull(result, getInferredContractAnnotation((PsiMethod)listOwner)); + ContainerUtil.addIfNotNull(result, getInferredContractAnnotation((PsiMethodImpl)listOwner)); } if (!ignoreInference(listOwner, AnnotationUtil.NOT_NULL) || !ignoreInference(listOwner, AnnotationUtil.NULLABLE)) { - PsiAnnotation annotation = getInferredNullityAnnotation((PsiMethod)listOwner); + PsiAnnotation annotation = getInferredNullityAnnotation((PsiMethodImpl)listOwner); if (annotation != null && !ignoreInference(listOwner, annotation.getQualifiedName())) { result.add(annotation); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java index c0a49d110139..24f8357459fb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiPrimitiveType; import com.intellij.psi.PsiType; +import com.intellij.psi.impl.source.PsiMethodImpl; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; @@ -42,7 +43,7 @@ public class ContractInference { public static final int MAX_CONTRACT_COUNT = 10; @NotNull - public static List inferContracts(@NotNull final PsiMethod method) { + public static List inferContracts(@NotNull PsiMethodImpl method) { if (!InferenceFromSourceUtil.shouldInferFromSource(method)) { return Collections.emptyList(); } @@ -57,7 +58,7 @@ public class ContractInference { } @NotNull - private static List postProcessContracts(@NotNull PsiMethod method, MethodData data, List rawContracts) { + private static List postProcessContracts(@NotNull PsiMethodImpl method, MethodData data, List rawContracts) { List contracts = ContainerUtil.concat(rawContracts, c -> c.toContracts(method, data.methodBody(method))); if (contracts.isEmpty()) return Collections.emptyList(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceIndex.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceIndex.kt index 8e7bcedcda50..6956c06e5881 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceIndex.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceIndex.kt @@ -17,7 +17,6 @@ package com.intellij.codeInspection.dataFlow import com.intellij.lang.LighterAST import com.intellij.lang.LighterASTNode -import com.intellij.psi.PsiMethod import com.intellij.psi.impl.source.JavaLightStubBuilder import com.intellij.psi.impl.source.PsiFileImpl import com.intellij.psi.impl.source.PsiMethodImpl @@ -93,11 +92,7 @@ private fun createData(body: LighterASTNode, return MethodData(nullity, purity, contracts, body.startOffset, body.endOffset) } -fun getIndexedData(method: PsiMethod): MethodData? { - if (method !is PsiMethodImpl || !InferenceFromSourceUtil.shouldInferFromSource(method)) return null - - return gist.getFileData(method.containingFile)?.get(methodIndex(method)) -} +fun getIndexedData(method: PsiMethodImpl): MethodData? = gist.getFileData(method.containingFile)?.get(methodIndex(method)) private fun methodIndex(method: PsiMethodImpl): Int { val file = method.containingFile as PsiFileImpl diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InferenceFromSourceUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InferenceFromSourceUtil.java index aa1cf0896eb6..b76aa964ec22 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InferenceFromSourceUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InferenceFromSourceUtil.java @@ -18,7 +18,7 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.impl.light.LightElement; +import com.intellij.psi.impl.source.PsiMethodImpl; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.util.*; @@ -29,9 +29,7 @@ import org.jetbrains.annotations.Nullable; * @author peter */ public class InferenceFromSourceUtil { - static boolean shouldInferFromSource(@NotNull final PsiMethod method) { - if (method instanceof SyntheticElement || method instanceof LightElement) return false; - + static boolean shouldInferFromSource(@NotNull PsiMethodImpl method) { return CachedValuesManager.getCachedValue(method, () -> CachedValueProvider.Result .create(calcShouldInferFromSource(method), method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT)); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java index ef3a58c5e526..c1e59d04aab5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java @@ -18,8 +18,12 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.lang.LighterAST; import com.intellij.lang.LighterASTNode; import com.intellij.openapi.util.RecursionManager; -import com.intellij.psi.*; +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiPrimitiveType; +import com.intellij.psi.PsiType; +import com.intellij.psi.TokenType; import com.intellij.psi.impl.source.JavaLightTreeUtil; +import com.intellij.psi.impl.source.PsiMethodImpl; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; @@ -38,7 +42,7 @@ import static com.intellij.psi.impl.source.tree.JavaElementType.*; */ public class NullityInference { - public static Nullness inferNullity(final PsiMethod method) { + public static Nullness inferNullity(PsiMethodImpl method) { if (!InferenceFromSourceUtil.shouldInferFromSource(method)) { return Nullness.UNKNOWN; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java index 232400fa9bc4..3cffb4271b11 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java @@ -19,9 +19,9 @@ import com.intellij.lang.LighterAST; import com.intellij.lang.LighterASTNode; import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.JavaTokenType; -import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiType; import com.intellij.psi.impl.source.JavaLightTreeUtil; +import com.intellij.psi.impl.source.PsiMethodImpl; import com.intellij.psi.impl.source.tree.LightTreeUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.CachedValueProvider; @@ -40,7 +40,7 @@ import static com.intellij.psi.impl.source.tree.JavaElementType.*; */ public class PurityInference { - public static boolean inferPurity(@NotNull final PsiMethod method) { + public static boolean inferPurity(@NotNull PsiMethodImpl method) { if (!InferenceFromSourceUtil.shouldInferFromSource(method) || PsiType.VOID.equals(method.getReturnType()) || method.isConstructor()) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inferenceResults.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inferenceResults.kt index 72691488393b..87f9eab94147 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inferenceResults.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inferenceResults.kt @@ -18,6 +18,7 @@ package com.intellij.codeInspection.dataFlow import com.intellij.codeInsight.NullableNotNullManager import com.intellij.lang.LighterASTNode import com.intellij.psi.* +import com.intellij.psi.impl.source.PsiMethodImpl import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.psi.util.CachedValueProvider @@ -122,8 +123,8 @@ data class MethodData( internal val bodyStart: Int, internal val bodyEnd: Int ) { - fun methodBody(method: PsiMethod): () -> PsiCodeBlock = { - if ((method as StubBasedPsiElement<*>?)?.stub != null) + fun methodBody(method: PsiMethodImpl): () -> PsiCodeBlock = { + if (method.stub != null) CachedValuesManager.getCachedValue(method) { CachedValueProvider.Result(getDetachedBody(method), method) } else method.body!! diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy b/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy index 93a9e3ec077c..140ebd9f2315 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy @@ -18,6 +18,7 @@ package com.intellij.codeInspection import com.intellij.codeInspection.dataFlow.ContractInference import com.intellij.psi.PsiAnonymousClass import com.intellij.psi.impl.source.PsiFileImpl +import com.intellij.psi.impl.source.PsiMethodImpl import com.intellij.psi.util.PsiTreeUtil import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase /** @@ -525,7 +526,7 @@ class Foo {{ Object foo() { return null;} }; }}"""), PsiAnonymousClass).methods[0] - assert ContractInference.inferContracts(method).collect { it as String } == [] + assert ContractInference.inferContracts(method as PsiMethodImpl).collect { it as String } == [] } void "test inference for used anonymous class methods"() { @@ -536,7 +537,7 @@ class Foo {{ Object bar(boolean b) { return foo(b);} }; }}"""), PsiAnonymousClass).methods[0] - assert ContractInference.inferContracts(method).collect { it as String } == ['true -> null', 'false -> !null'] + assert ContractInference.inferContracts(method as PsiMethodImpl).collect { it as String } == ['true -> null', 'false -> !null'] } void "test anonymous class methods potentially used from outside"() { @@ -548,7 +549,7 @@ class Foo {{ } }; }}"""), PsiAnonymousClass).methods[0] - assert ContractInference.inferContracts(method).collect { it as String } == [' -> fail'] + assert ContractInference.inferContracts(method as PsiMethodImpl).collect { it as String } == [' -> fail'] } void "test vararg delegation"() { @@ -584,7 +585,7 @@ class Foo {{ private List inferContracts(String method) { def clazz = myFixture.addClass("final class Foo { $method }") assert !((PsiFileImpl) clazz.containingFile).contentsLoaded - def contracts = ContractInference.inferContracts(clazz.methods[0]) + def contracts = ContractInference.inferContracts(clazz.methods[0] as PsiMethodImpl) assert !((PsiFileImpl) clazz.containingFile).contentsLoaded return contracts.collect { it as String } } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/PurityInferenceFromSourceTest.groovy b/java/java-tests/testSrc/com/intellij/codeInspection/PurityInferenceFromSourceTest.groovy index 6c56a5b59ba1..0eaa45b0e811 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/PurityInferenceFromSourceTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInspection/PurityInferenceFromSourceTest.groovy @@ -17,6 +17,7 @@ package com.intellij.codeInspection import com.intellij.codeInspection.dataFlow.PurityInference import com.intellij.psi.impl.source.PsiFileImpl +import com.intellij.psi.impl.source.PsiMethodImpl import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase /** * @author peter @@ -215,7 +216,7 @@ public Foo() { private void assertPure(boolean expected, String classBody) { def clazz = myFixture.addClass("final class Foo { $classBody }") assert !((PsiFileImpl) clazz.containingFile).contentsLoaded - def purity = PurityInference.inferPurity(clazz.methods[0]) + def purity = PurityInference.inferPurity((PsiMethodImpl)clazz.methods[0]) assert !((PsiFileImpl) clazz.containingFile).contentsLoaded assert expected == purity }