Merge remote-tracking branch 'origin/master'

This commit is contained in:
Yaroslav Pankratyev
2017-08-29 16:32:42 +07:00
11 changed files with 232 additions and 30 deletions
@@ -17,7 +17,7 @@ package com.siyeh.ig;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScopeUtil;
@@ -74,4 +74,17 @@ public class JavaOverridingMethodUtil {
return methods.stream().filter(candidate -> PsiSuperMethodUtil.isSuperMethod(candidate, method));
}
public static boolean containsAnnotationWithName(@NotNull PsiModifierListOwner modifierListOwner, @NotNull String shortAnnotationName) {
PsiModifierList list = modifierListOwner.getModifierList();
if (list != null) {
for (PsiAnnotation annotation : list.getAnnotations()) {
PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
if (ref != null && shortAnnotationName.equals(ref.getReferenceName())) {
return true;
}
}
}
return false;
}
}
@@ -40,6 +40,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class MissingOverrideAnnotationInspection extends BaseJavaBatchLocalInspectionTool implements CleanupLocalInspectionTool{
@@ -134,16 +135,8 @@ public class MissingOverrideAnnotationInspection extends BaseJavaBatchLocalInspe
GlobalSearchScope scope = getLanguageLevelScope(minimal, project);
if (scope == null) return;
Stream<PsiMethod> overridingMethods = JavaOverridingMethodUtil
.getOverridingMethodsIfCheapEnough(method, scope, m -> {
for (PsiAnnotation annotation : m.getModifierList().getAnnotations()) {
PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
if (ref != null && OVERRIDE_SHORT_NAME.equals(ref.getReferenceName())) {
return false;
}
}
return true;
});
Predicate<PsiMethod> preFilter = m -> !JavaOverridingMethodUtil.containsAnnotationWithName(m, OVERRIDE_SHORT_NAME);
Stream<PsiMethod> overridingMethods = JavaOverridingMethodUtil.getOverridingMethodsIfCheapEnough(method, scope, preFilter);
if (overridingMethods == null) return;
result.hierarchyAnnotated = ThreeState.fromBoolean(!overridingMethods.findAny().isPresent());
}
@@ -16,15 +16,16 @@
package com.siyeh.ipp.annotation;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.siyeh.ig.psiutils.DeclarationSearchUtils;
import com.siyeh.ig.JavaOverridingMethodUtil;
import com.siyeh.ipp.base.PsiElementPredicate;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Predicate;
import java.util.stream.Stream;
class AnnotateOverriddenMethodsPredicate implements PsiElementPredicate {
@Override
public boolean satisfiedBy(PsiElement element) {
if (!(element instanceof PsiAnnotation)) {
@@ -65,20 +66,27 @@ class AnnotateOverriddenMethodsPredicate implements PsiElementPredicate {
parameterIndex = -1;
method = (PsiMethod)grandParent;
}
if (DeclarationSearchUtils.isTooExpensiveToSearch(method, true)) {
// skip expensive check and just offer the intention when it might not be needed
return true;
}
final Collection<PsiMethod> overridingMethods =
OverridingMethodsSearch.search(method).findAll();
if (overridingMethods.isEmpty()) {
return false;
}
for (PsiMethod overridingMethod : overridingMethods) {
String annotationShortName = StringUtil.getShortName(annotationName);
Predicate<PsiMethod> preFilter = m -> {
if (parameterIndex == -1) {
return !JavaOverridingMethodUtil.containsAnnotationWithName(m, annotationShortName);
}
else {
PsiModifierListOwner parameter = (PsiModifierListOwner)m.getParameters()[parameterIndex];
return !JavaOverridingMethodUtil.containsAnnotationWithName(parameter, annotationShortName);
}
};
Stream<PsiMethod> overridenMethods = JavaOverridingMethodUtil.getOverridingMethodsIfCheapEnough(method, null, preFilter);
// skip expensive check and just offer the intention when it might not be needed
if (overridenMethods == null) return true;
Iterator<PsiMethod> it = overridenMethods.iterator();
while (it.hasNext()) {
PsiMethod overridingMethod = it.next();
if (parameterIndex == -1) {
final PsiAnnotation foundAnnotation =
AnnotationUtil.findAnnotation(overridingMethod,
annotationName);
AnnotationUtil.findAnnotation(overridingMethod, annotationName);
if (foundAnnotation == null) {
return true;
}
@@ -89,8 +97,7 @@ class AnnotateOverriddenMethodsPredicate implements PsiElementPredicate {
final PsiParameter[] parameters = parameterList.getParameters();
final PsiParameter parameter = parameters[parameterIndex];
final PsiAnnotation foundAnnotation =
AnnotationUtil.findAnnotation(parameter,
annotationName);
AnnotationUtil.findAnnotation(parameter, annotationName);
if (foundAnnotation == null) {
return true;
}
@@ -0,0 +1,29 @@
/*
* Copyright 2000-2017 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.
*/
@interface SomeAnnotation {}
public class X {
@SomeAnnotat<caret>ion
public void method() {
}
}
public class Y extends X {
public void method() {
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2017 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.
*/
@interface SomeAnnotation {}
public class X {
@SomeAnnotation
public void method() {
}
}
public class Y extends X {
@SomeAnnotation
public void method() {
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2017 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.
*/
@interface SomeAnnotation {}
public class X {
@SomeAn<caret>notation
public void method() {
}
}
public class Y extends X {
@SomeAnnotation
public void method() {
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2000-2017 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.
*/
@interface SomeAnnotation {}
public class X {
public void method(@Som<caret>eAnnotation String x) {
}
}
public class Y extends X {
public void method(String x) {
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2000-2017 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.
*/
@interface SomeAnnotation {}
public class X {
public void method(@SomeAnnotation String x) {
}
}
public class Y extends X {
public void method(@SomeAnnotation String x) {
}
}
@@ -0,0 +1,43 @@
/*
* Copyright 2000-2017 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.siyeh.ipp.annotation;
import com.siyeh.IntentionPowerPackBundle;
import com.siyeh.ipp.IPPTestCase;
public class AnnotateOverriddenMethodsIntentionTest extends IPPTestCase {
public void testMethod() {
doTest();
}
public void testParameter() {
doTest(IntentionPowerPackBundle.message("annotate.overridden.methods.intention.parameters.name", "@SomeAnnotation"));
}
public void testNotAvailable() {
assertIntentionNotAvailable();
}
@Override
protected String getRelativePath() {
return "annotation/AnnotateOverriddenMethods";
}
@Override
protected String getIntentionName() {
return IntentionPowerPackBundle.message("annotate.overridden.methods.intention.method.name", "@SomeAnnotation");
}
}
Binary file not shown.
@@ -37,7 +37,8 @@ public class Utils {
public static String configValueForKey(List<OutPair> outPairs, String key) {
for (OutPair outPair : outPairs) {
if (outPair.getKey().equals(key)) {
return outPair.getVal();
String val = outPair.getVal();
return "none".equals(val) ? "" : val;
}
}
return "";