don't infer annotations in anonymous classes unless they'll be useful

This commit is contained in:
peter
2014-12-22 13:55:31 +01:00
parent d751ddd81c
commit 52a2de3b56
5 changed files with 86 additions and 16 deletions
@@ -17,17 +17,12 @@ package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.psi.util.*;
import com.intellij.util.Function;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
@@ -47,10 +42,10 @@ public class ContractInference {
@NotNull
public static List<MethodContract> inferContracts(@NotNull final PsiMethod method) {
if (isLibraryCode(method)) {
if (!InferenceFromSourceUtil.shouldInferFromSource(method)) {
return Collections.emptyList();
}
return CachedValuesManager.getCachedValue(method, new CachedValueProvider<List<MethodContract>>() {
@Nullable
@Override
@@ -66,12 +61,6 @@ public class ContractInference {
}
});
}
static boolean isLibraryCode(@NotNull PsiMethod method) {
if (method instanceof PsiCompiledElement) return true;
VirtualFile virtualFile = PsiUtilCore.getVirtualFile(method);
return virtualFile != null && FileIndexFacade.getInstance(method.getProject()).isInLibrarySource(virtualFile);
}
}
class ContractInferenceInterpreter {
@@ -0,0 +1,55 @@
/*
* 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.dataFlow;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
/**
* @author peter
*/
public class InferenceFromSourceUtil {
static boolean shouldInferFromSource(@NotNull PsiMethod method) {
if (isLibraryCode(method) ||
method.hasModifierProperty(PsiModifier.ABSTRACT) ||
PsiUtil.canBeOverriden(method) ||
method.getBody() == null) {
return false;
}
if (method.hasModifierProperty(PsiModifier.STATIC)) return true;
return !isUnusedInAnonymousClass(method);
}
private static boolean isUnusedInAnonymousClass(@NotNull PsiMethod method) {
PsiClass containingClass = method.getContainingClass();
return containingClass instanceof PsiAnonymousClass &&
MethodReferencesSearch.search(method, new LocalSearchScope(containingClass), false).findFirst() == null;
}
private static boolean isLibraryCode(@NotNull PsiMethod method) {
if (method instanceof PsiCompiledElement) return true;
VirtualFile virtualFile = PsiUtilCore.getVirtualFile(method);
return virtualFile != null && FileIndexFacade.getInstance(method.getProject()).isInLibrarySource(virtualFile);
}
}
@@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class NullityInference {
public static Nullness inferNullity(final PsiMethod method) {
if (ContractInference.isLibraryCode(method)) {
if (!InferenceFromSourceUtil.shouldInferFromSource(method)) {
return Nullness.UNKNOWN;
}
@@ -34,7 +34,10 @@ import java.util.List;
public class PurityInference {
public static boolean inferPurity(@NotNull final PsiMethod method) {
if (ContractInference.isLibraryCode(method) || method.getReturnType() == PsiType.VOID || method.getBody() == null || method.isConstructor()) {
if (!InferenceFromSourceUtil.shouldInferFromSource(method) ||
method.getReturnType() == PsiType.VOID ||
method.getBody() == null ||
method.isConstructor()) {
return false;
}
@@ -16,6 +16,8 @@
package com.intellij.codeInspection
import com.intellij.codeInspection.dataFlow.ContractInference
import com.intellij.psi.PsiAnonymousClass
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
/**
@@ -448,6 +450,27 @@ public static boolean isBlank(String s) {
assert c == ['null -> true']
}
public void "test no inference for unused anonymous class methods where annotations won't be used anyway"() {
def method = PsiTreeUtil.findChildOfType(myFixture.addClass("""
class Foo {{
new Object() {
Object foo() { return null;}
};
}}"""), PsiAnonymousClass).methods[0]
assert ContractInference.inferContracts(method).collect { it as String } == []
}
public void "test inference for used anonymous class methods"() {
def method = PsiTreeUtil.findChildOfType(myFixture.addClass("""
class Foo {{
new Object() {
Object foo() { return null;}
Object bar() { return foo();}
};
}}"""), PsiAnonymousClass).methods[0]
assert ContractInference.inferContracts(method).collect { it as String } == [' -> null']
}
private String inferContract(String method) {
return assertOneElement(inferContracts(method))
}