diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java
index 9c17a9f75a7f..f5a46f1734a0 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java
@@ -17,9 +17,13 @@ package com.intellij.codeInspection.sameParameterValue;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInsight.daemon.GroupNames;
+import com.intellij.codeInsight.daemon.impl.UnusedSymbolUtil;
import com.intellij.codeInspection.*;
+import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase;
import com.intellij.codeInspection.reference.*;
-import com.intellij.psi.PsiReference;
+import com.intellij.openapi.progress.EmptyProgressIndicator;
+import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
+import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,11 +55,7 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT
if (value != null) {
if (!globalContext.shouldCheck(refParameter, this)) continue;
if (problems == null) problems = new ArrayList<>(1);
- final String paramName = refParameter.getName();
- problems.add(manager.createProblemDescriptor(refParameter.getElement(), InspectionsBundle.message(
- "inspection.same.parameter.problem.descriptor", "" + paramName + "", "" + value + ""),
- createFix(paramName, value),
- ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false));
+ problems.add(registerProblem(manager, refParameter.getElement(), value));
}
}
}
@@ -63,7 +63,6 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT
return problems == null ? null : problems.toArray(new CommonProblemDescriptor[problems.size()]);
}
-
@Override
protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext globalContext,
@NotNull final ProblemDescriptionsProcessor processor) {
@@ -118,7 +117,7 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT
}
protected LocalQuickFix createFix(String paramName, String value) {
- throw new UnsupportedOperationException();
+ return null;
}
@Override
@@ -127,4 +126,131 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT
return fix.toString();
}
+ @Nullable
+ @Override
+ public LocalInspectionTool getSharedLocalInspectionTool() {
+ return new LocalSameParameterValueInspection(this);
+ }
+
+ private class LocalSameParameterValueInspection extends BaseJavaLocalInspectionTool {
+ private static final String NOT_CONST = "_NOT_CONST";
+
+ private final SameParameterValueInspectionBase myGlobal;
+
+ private LocalSameParameterValueInspection(SameParameterValueInspectionBase global) {
+ myGlobal = global;
+ }
+
+ @Override
+ @NotNull
+ public String getGroupDisplayName() {
+ return myGlobal.getGroupDisplayName();
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return myGlobal.getDisplayName();
+ }
+
+ @Override
+ @NotNull
+ public String getShortName() {
+ return myGlobal.getShortName();
+ }
+
+ @NotNull
+ @Override
+ public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
+ boolean isOnTheFly,
+ @NotNull LocalInspectionToolSession session) {
+ return new JavaElementVisitor() {
+ private final UnusedDeclarationInspectionBase myDeadCodeTool;
+
+ {
+ InspectionProfile profile = InspectionProjectProfileManager.getInstance(holder.getProject()).getCurrentProfile();
+ UnusedDeclarationInspectionBase deadCodeTool = (UnusedDeclarationInspectionBase)profile.getUnwrappedTool(UnusedDeclarationInspectionBase.SHORT_NAME, holder.getFile());
+ myDeadCodeTool = deadCodeTool == null ? new UnusedDeclarationInspectionBase() : deadCodeTool;
+ }
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ if (method.isConstructor()) return;
+ PsiParameter[] parameters = method.getParameterList().getParameters();
+ if (parameters.length == 0) return;
+
+ if (myDeadCodeTool.isEntryPoint(method)) return;
+ if (!method.getHierarchicalMethodSignature().getSuperSignatures().isEmpty()) return;
+
+ PsiParameter lastParameter = parameters[parameters.length - 1];
+ final String[] paramValues;
+ final boolean hasVarArg = lastParameter.getType() instanceof PsiEllipsisType;
+ if (hasVarArg) {
+ if (parameters.length == 1) return;
+ paramValues = new String[parameters.length - 1];
+ } else {
+ paramValues = new String[parameters.length];
+ }
+
+ if (UnusedSymbolUtil.processUsages(holder.getProject(), method.getContainingFile(), method, new EmptyProgressIndicator(), null, info -> {
+ PsiElement element = info.getElement();
+
+ if (!(element instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ PsiElement parent = element.getParent();
+ if (!(parent instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ PsiMethodCallExpression methodCall = (PsiMethodCallExpression) parent;
+ PsiExpression[] arguments = methodCall.getArgumentList().getExpressions();
+ if (arguments.length < paramValues.length) return false;
+
+ boolean needFurtherProcess = false;
+ for (int i = 0; i < paramValues.length; i++) {
+ Object value = paramValues[i];
+ final String currentArg = getArgValue(arguments[i]);
+ if (value == null) {
+ paramValues[i] = currentArg;
+ if (currentArg != NOT_CONST) {
+ needFurtherProcess = true;
+ }
+ } else if (value != NOT_CONST) {
+ if (!paramValues[i].equals(currentArg)) {
+ paramValues[i] = NOT_CONST;
+ } else {
+ needFurtherProcess = true;
+ }
+ }
+ }
+
+ return needFurtherProcess;
+ })) {
+ for (int i = 0, length = paramValues.length; i < length; i++) {
+ String value = paramValues[i];
+ if (value != null && value != NOT_CONST) {
+ holder.registerProblem(registerProblem(holder.getManager(), parameters[i], value));
+ }
+ }
+ }
+ }
+ };
+ }
+
+ private String getArgValue(PsiExpression arg) {
+ return arg instanceof PsiLiteralExpression ? arg.getText() : NOT_CONST;
+ }
+ }
+
+ private ProblemDescriptor registerProblem(@NotNull InspectionManager manager,
+ PsiParameter parameter,
+ String value) {
+ final String name = parameter.getName();
+ return manager.createProblemDescriptor(parameter,
+ InspectionsBundle.message("inspection.same.parameter.problem.descriptor",
+ "" + name + "",
+ "" + value + ""),
+ createFix(name, value),
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false);
+ }
}
diff --git a/java/java-tests/testData/inspection/sameParameterValue/methodWithSuper/expected.xml b/java/java-tests/testData/inspection/sameParameterValue/methodWithSuper/expected.xml
new file mode 100644
index 000000000000..5b0b2c35f487
--- /dev/null
+++ b/java/java-tests/testData/inspection/sameParameterValue/methodWithSuper/expected.xml
@@ -0,0 +1,12 @@
+
+
+
+ Test.java
+ 4
+ testMethodWithSuper
+ Actual method parameter is the same constant
+ Actual value of parameter '<code>i</code>' is always '<code>10</code>'
+
+
+
+
diff --git a/java/java-tests/testData/inspection/sameParameterValue/methodWithSuper/src/Test.java b/java/java-tests/testData/inspection/sameParameterValue/methodWithSuper/src/Test.java
new file mode 100644
index 000000000000..bf50ae40be5b
--- /dev/null
+++ b/java/java-tests/testData/inspection/sameParameterValue/methodWithSuper/src/Test.java
@@ -0,0 +1,20 @@
+public class Test {
+
+ static class AAA {
+ public void mmm(int i) {
+ System.out.println(i + 10);
+ }
+ }
+
+ static class BBB extends AAA {
+ @Override
+ public void mmm(int i) {
+ System.out.println(i + 20);
+ }
+ }
+
+ public static void main(String[] args) {
+ new BBB().mmm(10);
+ new AAA().mmm(10);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueLocalTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueLocalTest.java
new file mode 100644
index 000000000000..61d5eb9954e5
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueLocalTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2016 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;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.codeInspection.sameParameterValue.SameParameterValueInspection;
+import com.intellij.testFramework.InspectionTestCase;
+
+public class SameParameterValueLocalTest extends InspectionTestCase {
+ private final LocalInspectionTool myTool = new SameParameterValueInspection().getSharedLocalInspectionTool();
+
+ @Override
+ protected String getTestDataPath() {
+ return JavaTestUtil.getJavaTestDataPath() + "/inspection";
+ }
+
+ private String getGlobalTestDir() {
+ return "sameParameterValue/" + getTestName(true);
+ }
+
+ public void testEntryPoint() {
+ doTest(getGlobalTestDir(), myTool);
+ }
+
+ public void testMethodWithSuper() {
+ doTest(getGlobalTestDir(), myTool);
+ }
+
+ public void testVarargs() {
+ doTest(getGlobalTestDir(), myTool);
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueTest.java
index 9f1890acbf0f..79a1be79e215 100644
--- a/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueTest.java
@@ -16,19 +16,23 @@ public class SameParameterValueTest extends InspectionTestCase {
return "sameParameterValue/" + getTestName(true);
}
- public void testEntryPoint() throws Exception {
+ public void testEntryPoint() {
doTest(getTestDir(), myTool, false, true);
}
- public void testWithoutDeadCode() throws Exception {
+ public void testWithoutDeadCode() {
doTest(getTestDir(), myTool, false, false);
}
- public void testVarargs() throws Exception {
+ public void testVarargs() {
doTest(getTestDir(), myTool, false, true);
}
- public void testSimpleVararg() throws Exception {
+ public void testSimpleVararg() {
+ doTest(getTestDir(), myTool, false, true);
+ }
+
+ public void testMethodWithSuper() {
doTest(getTestDir(), myTool, false, true);
}
}