New topic: Inspection options (#988)

This commit is contained in:
Karol Lewandowski 2023-02-27 15:36:02 +01:00 committed by GitHub
parent 148ce5b74f
commit 4d1b6e6789
26 changed files with 285 additions and 322 deletions

View File

@ -35,9 +35,9 @@ Please see [Code Samples][docs:code-samples] topic on how to import and run code
In the following table, you may find all available samples provided in the separated directories as stand-alone projects available for running with the Gradle [`runIde`](tools_gradle_intellij_plugin.md#tasks-runide) task. In the following table, you may find all available samples provided in the separated directories as stand-alone projects available for running with the Gradle [`runIde`](tools_gradle_intellij_plugin.md#tasks-runide) task.
| Code Sample | Description | | Code Sample | Description |
|------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| |-----------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Action Basics](./action_basics) | Action and Action Group patterns implementation, adds entries to the Tools menu. | | [Action Basics](./action_basics) | Action and Action Group patterns implementation, adds entries to the Tools menu. |
| [Comparing References Inspection](./comparing_references_inspection) | Local Inspection Tool, adds entries to **Settings | Editor | Inspections | Java | Probable Bugs**. | | [Comparing References Inspection](./comparing_string_references_inspection) | Local Inspection Tool, adds entries to **Settings | Editor | Inspections | Java | Probable Bugs**. |
| [Conditional Operator Intention](./conditional_operator_intention) | Intention action, suggests converting a ternary operator into an `if` block and adds entry to **Settings | Editor | Intentions | SDK Intentions**. | | [Conditional Operator Intention](./conditional_operator_intention) | Intention action, suggests converting a ternary operator into an `if` block and adds entry to **Settings | Editor | Intentions | SDK Intentions**. |
| [Editor Basics](./editor_basics) | Basic Editor APIs example with editor popup menu with extra actions. | | [Editor Basics](./editor_basics) | Basic Editor APIs example with editor popup menu with extra actions. |
| [Framework Basics](./framework_basics) | Basic *SDK Demo Framework* support added to the **File | New | Project | Java** wizard. | | [Framework Basics](./framework_basics) | Basic *SDK Demo Framework* support added to the **File | New | Project | Java** wizard. |

View File

@ -5,7 +5,7 @@
rootProject.name = "SDK Code Samples" rootProject.name = "SDK Code Samples"
includeBuild("../action_basics") includeBuild("../action_basics")
includeBuild("../comparing_references_inspection") includeBuild("../comparing_string_references_inspection")
includeBuild("../conditional_operator_intention") includeBuild("../conditional_operator_intention")
includeBuild("../editor_basics") includeBuild("../editor_basics")
includeBuild("../facet_basics") includeBuild("../facet_basics")

View File

@ -1,203 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.intellij.sdk.codeInspection;
import com.intellij.codeInspection.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.ui.DocumentAdapter;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.util.StringTokenizer;
import static com.siyeh.ig.psiutils.ExpressionUtils.isNullLiteral;
/**
* Implements an inspection to detect when object references are compared using 'a==b' or 'a!=b'.
* The quick fix converts these comparisons to 'a.equals(b) or '!a.equals(b)' respectively.
*/
public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspectionTool {
// Defines the text of the quick fix intention
public static final String QUICK_FIX_NAME = "SDK: " +
InspectionsBundle.message("inspection.comparing.references.use.quickfix");
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ComparingReferencesInspection");
private final CriQuickFix myQuickFix = new CriQuickFix();
// This string holds a list of classes relevant to this inspection.
@SuppressWarnings({"WeakerAccess"})
@NonNls
public String CHECKED_CLASSES = "java.lang.String;java.util.Date";
/**
* This method is called to get the panel describing the inspection.
* It is called every time the user selects the inspection in preferences.
* The user has the option to edit the list of {@link #CHECKED_CLASSES}.
*
* @return panel to display inspection information.
*/
@Override
public JComponent createOptionsPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
final JTextField checkedClasses = new JTextField(CHECKED_CLASSES);
checkedClasses.getDocument().addDocumentListener(new DocumentAdapter() {
public void textChanged(@NotNull DocumentEvent event) {
CHECKED_CLASSES = checkedClasses.getText();
}
});
panel.add(checkedClasses);
return panel;
}
/**
* This method is overridden to provide a custom visitor.
* that inspects expressions with relational operators '==' and '!='.
* The visitor must not be recursive and must be thread-safe.
*
* @param holder object for visitor to register problems found.
* @param isOnTheFly true if inspection was run in non-batch mode
* @return non-null visitor for this inspection.
* @see JavaElementVisitor
*/
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
/**
* This string defines the short message shown to a user signaling the inspection found a problem.
* It reuses a string from the inspections bundle.
*/
@NonNls
private final String DESCRIPTION_TEMPLATE = "SDK " +
InspectionsBundle.message("inspection.comparing.references.problem.descriptor");
/**
* Avoid defining visitors for both Reference and Binary expressions.
*
* @param psiReferenceExpression The expression to be evaluated.
*/
@Override
public void visitReferenceExpression(PsiReferenceExpression psiReferenceExpression) {
}
/**
* Evaluate binary psi expressions to see if they contain relational operators '==' and '!=', AND they contain
* classes contained in CHECKED_CLASSES. The evaluation ignores expressions comparing an object to null.
* IF this criteria is met, add the expression to the problems list.
*
* @param expression The binary expression to be evaluated.
*/
@Override
public void visitBinaryExpression(PsiBinaryExpression expression) {
super.visitBinaryExpression(expression);
IElementType opSign = expression.getOperationTokenType();
if (opSign == JavaTokenType.EQEQ || opSign == JavaTokenType.NE) {
// The binary expression is the correct type for this inspection
PsiExpression lOperand = expression.getLOperand();
PsiExpression rOperand = expression.getROperand();
if (rOperand == null || isNullLiteral(lOperand) || isNullLiteral(rOperand)) {
return;
}
// Nothing is compared to null, now check the types being compared
PsiType lType = lOperand.getType();
PsiType rType = rOperand.getType();
if (isCheckedType(lType) || isCheckedType(rType)) {
// Identified an expression with potential problems, add to list with fix object.
holder.registerProblem(expression,
DESCRIPTION_TEMPLATE, myQuickFix);
}
}
}
/**
* Verifies the input is the correct {@code PsiType} for this inspection.
*
* @param type The {@code PsiType} to be examined for a match
* @return {@code true} if input is {@code PsiClassType} and matches one of the classes
* in the {@link ComparingReferencesInspection#CHECKED_CLASSES} list.
*/
private boolean isCheckedType(PsiType type) {
if (!(type instanceof PsiClassType)) {
return false;
}
StringTokenizer tokenizer = new StringTokenizer(CHECKED_CLASSES, ";");
while (tokenizer.hasMoreTokens()) {
String className = tokenizer.nextToken();
if (type.equalsToText(className)) {
return true;
}
}
return false;
}
};
}
/**
* This class provides a solution to inspection problem expressions by manipulating the PSI tree to use 'a.equals(b)'
* instead of '==' or '!='.
*/
private static class CriQuickFix implements LocalQuickFix {
/**
* Returns a partially localized string for the quick fix intention.
* Used by the test code for this plugin.
*
* @return Quick fix short name.
*/
@NotNull
@Override
public String getName() {
return QUICK_FIX_NAME;
}
/**
* This method manipulates the PSI tree to replace 'a==b' with 'a.equals(b)' or 'a!=b' with '!a.equals(b)'.
*
* @param project The project that contains the file being edited.
* @param descriptor A problem found by this inspection.
*/
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
try {
PsiBinaryExpression binaryExpression = (PsiBinaryExpression) descriptor.getPsiElement();
IElementType opSign = binaryExpression.getOperationTokenType();
PsiExpression lExpr = binaryExpression.getLOperand();
PsiExpression rExpr = binaryExpression.getROperand();
if (rExpr == null) {
return;
}
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
PsiMethodCallExpression equalsCall =
(PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null);
equalsCall.getMethodExpression().getQualifierExpression().replace(lExpr);
equalsCall.getArgumentList().getExpressions()[0].replace(rExpr);
PsiExpression result = (PsiExpression) binaryExpression.replace(equalsCall);
if (opSign == JavaTokenType.NE) {
PsiPrefixExpression negation = (PsiPrefixExpression) factory.createExpressionFromText("!a", null);
negation.getOperand().replace(result);
result.replace(negation);
}
} catch (IncorrectOperationException e) {
LOG.error(e);
}
}
@NotNull
public String getFamilyName() {
return getName();
}
}
}

View File

@ -1,12 +0,0 @@
<!-- Copyright 2000-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<html>
<body>
Reports usages of <code>==</code> and <code>!=</code> when comparing instances of specified types.
<p>
Quick-fix replaces operator with <code>equals()</code> call.
</p>
<!-- tooltip end -->
<p>Configure the inspection:</p>
List classes to be inspected separated by semi-colon.
</body>
</html>

View File

@ -1,6 +0,0 @@
public class Eq {
public boolean compare2Strings(java.lang.String s1, java.lang.String s2) {
return (s1.equals(s2));
}
}

View File

@ -1,6 +0,0 @@
public class Eq {
public boolean compare2Strings(java.lang.String s1, java.lang.String s2) {
return (<caret>s1 == s2);
}
}

View File

@ -1,6 +0,0 @@
public class Neq {
public boolean compare2Dates(java.util.Date dt1, java.util.Date dt2){
return (!dt1.equals(dt2));
}
}

View File

@ -1,6 +0,0 @@
public class Neq {
public boolean compare2Dates(java.util.Date dt1, java.util.Date dt2){
return (dt1 <caret>!= dt2);
}
}

View File

@ -5,14 +5,14 @@
Comparing References Inspection Sample demonstrates the implementation of the [Code Inspections][docs:code_inspections] feature for Java classes. Comparing References Inspection Sample demonstrates the implementation of the [Code Inspections][docs:code_inspections] feature for Java classes.
The plugin inspects your Java code and highlights any fragments containing the comparison of two `String` or `Date` variables. The plugin inspects your Java code and highlights any fragments containing the comparison of two `String` variables.
If such a check finds a comparison using the `==` or !`=` operators instead of the `.equals()` method, the plugin proposes a *quick-fix* action. If such a check finds a comparison using the `==` or !`=` operators instead of the `.equals()` method, the plugin proposes a *quick-fix* action.
### Extension Points ### Extension Points
| Name | Implementation | Extension Point Class | | Name | Implementation | Extension Point Class |
|--------------------------------|---------------------------------------------------------------------|---------------------------------------| |--------------------------------|---------------------------------------------------------------------------------|---------------------------------------|
| `com.intellij.localInspection` | [ComparingReferencesInspection][file:ComparingReferencesInspection] | `AbstractBaseJavaLocalInspectionTool` | | `com.intellij.localInspection` | [ComparingStringReferencesInspection][file:ComparingStringReferencesInspection] | `AbstractBaseJavaLocalInspectionTool` |
*Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]* *Reference: [Plugin Extension Points in IntelliJ SDK Docs][docs:ep]*
@ -21,4 +21,4 @@ If such a check finds a comparison using the `==` or !`=` operators instead of t
[docs:code_inspections]: https://plugins.jetbrains.com/docs/intellij/code-inspections.html [docs:code_inspections]: https://plugins.jetbrains.com/docs/intellij/code-inspections.html
[docs:ep]: https://plugins.jetbrains.com/docs/intellij/plugin-extensions.html [docs:ep]: https://plugins.jetbrains.com/docs/intellij/plugin-extensions.html
[file:ComparingReferencesInspection]: ./src/main/java/org/intellij/sdk/codeInspection/ComparingReferencesInspection.java [file:ComparingStringReferencesInspection]: ./src/main/java/org/intellij/sdk/codeInspection/ComparingStringReferencesInspection.java

View File

@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
plugins { plugins {
id("java") id("java")
@ -36,10 +36,4 @@ tasks {
sinceBuild.set("221") sinceBuild.set("221")
untilBuild.set("223.*") untilBuild.set("223.*")
} }
test {
// Set idea.home.path to the absolute path to the intellij-community source
// on your local machine.
systemProperty("idea.home.path", "/Users/jhake/Documents/source/comm")
}
} }

View File

@ -1,3 +1,3 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
rootProject.name = "comparing_references_inspection" rootProject.name = "comparing_string_references_inspection"

View File

@ -0,0 +1,139 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.intellij.sdk.codeInspection;
import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import static com.siyeh.ig.psiutils.ExpressionUtils.isNullLiteral;
/**
* Implements an inspection to detect when String references are compared using 'a==b' or 'a!=b'.
* The quick fix converts these comparisons to 'a.equals(b) or '!a.equals(b)' respectively.
*/
public class ComparingStringReferencesInspection extends AbstractBaseJavaLocalInspectionTool {
private final ReplaceWithEqualsQuickFix myQuickFix = new ReplaceWithEqualsQuickFix();
/**
* This method is overridden to provide a custom visitor
* that inspects expressions with relational operators '==' and '!='.
* The visitor must not be recursive and must be thread-safe.
*
* @param holder object for the visitor to register problems found
* @param isOnTheFly true if inspection was run in non-batch mode
* @return non-null visitor for this inspection
* @see JavaElementVisitor
*/
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
/**
* Evaluate binary psi expressions to see if they contain relational operators '==' and '!=',
* AND they are of String type.
* The evaluation ignores expressions comparing an object to null.
* IF these criteria are met, register the problem in the ProblemsHolder.
*
* @param expression The binary expression to be evaluated.
*/
@Override
public void visitBinaryExpression(PsiBinaryExpression expression) {
super.visitBinaryExpression(expression);
IElementType opSign = expression.getOperationTokenType();
if (opSign == JavaTokenType.EQEQ || opSign == JavaTokenType.NE) {
// The binary expression is the correct type for this inspection
PsiExpression lOperand = expression.getLOperand();
PsiExpression rOperand = expression.getROperand();
if (rOperand == null || isNullLiteral(lOperand) || isNullLiteral(rOperand)) {
return;
}
// Nothing is compared to null, now check the types being compared
if (isStringType(lOperand) || isStringType(rOperand)) {
// Identified an expression with potential problems, register problem with the quick fix object
holder.registerProblem(expression,
InspectionBundle.message("inspection.comparing.string.references.problem.descriptor"),
myQuickFix);
}
}
}
private boolean isStringType(PsiExpression operand) {
PsiType type = operand.getType();
if (!(type instanceof PsiClassType)) {
return false;
}
PsiClass resolvedType = ((PsiClassType) type).resolve();
if (resolvedType == null) {
return false;
}
return "java.lang.String".equals(resolvedType.getQualifiedName());
}
};
}
/**
* This class provides a solution to inspection problem expressions by manipulating the PSI tree to use 'a.equals(b)'
* instead of '==' or '!='.
*/
private static class ReplaceWithEqualsQuickFix implements LocalQuickFix {
/**
* Returns a partially localized string for the quick fix intention.
* Used by the test code for this plugin.
*
* @return Quick fix short name.
*/
@NotNull
@Override
public String getName() {
return InspectionBundle.message("inspection.comparing.string.references.use.quickfix");
}
/**
* This method manipulates the PSI tree to replace 'a==b' with 'a.equals(b)' or 'a!=b' with '!a.equals(b)'.
*
* @param project The project that contains the file being edited.
* @param descriptor A problem found by this inspection.
*/
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiBinaryExpression binaryExpression = (PsiBinaryExpression) descriptor.getPsiElement();
IElementType opSign = binaryExpression.getOperationTokenType();
PsiExpression lExpr = binaryExpression.getLOperand();
PsiExpression rExpr = binaryExpression.getROperand();
if (rExpr == null) {
return;
}
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
PsiMethodCallExpression equalsCall =
(PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null);
equalsCall.getMethodExpression().getQualifierExpression().replace(lExpr);
equalsCall.getArgumentList().getExpressions()[0].replace(rExpr);
PsiExpression result = (PsiExpression) binaryExpression.replace(equalsCall);
if (opSign == JavaTokenType.NE) {
PsiPrefixExpression negation = (PsiPrefixExpression) factory.createExpressionFromText("!a", null);
negation.getOperand().replace(result);
result.replace(negation);
}
}
@NotNull
public String getFamilyName() {
return getName();
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.intellij.sdk.codeInspection;
import com.intellij.DynamicBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.PropertyKey;
public final class InspectionBundle extends DynamicBundle {
private static final InspectionBundle ourInstance = new InspectionBundle();
@NonNls
public static final String BUNDLE = "messages.InspectionBundle";
private InspectionBundle() {
super(BUNDLE);
}
public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key,
Object @NotNull ... params) {
return ourInstance.getMessage(key, params);
}
}

View File

@ -1,4 +1,4 @@
<!-- Copyright 2000-2022 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. --> <!-- Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html --> <!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html -->
<idea-plugin> <idea-plugin>
@ -35,37 +35,37 @@
<extensions defaultExtensionNs="com.intellij"> <extensions defaultExtensionNs="com.intellij">
<!-- <!--
Extend the IntelliJ Platform local inspection type, and connect it to the implementation class in this plugin. Extend the IntelliJ Platform local inspection type and connect it to the implementation class in this plugin.
<localInspection> type element is applied within the scope of a file under edit. <localInspection> type element is applied within the scope of a file under edit.
It is preferred over <inspectionToolProvider> It is preferred over <inspectionToolProvider>
@see intellij.platform.resources.LangExtensionPoints @see intellij.platform.resources.LangExtensionPoints
@see com.intellij.codeInspection.InspectionProfileEntry @see com.intellij.codeInspection.InspectionProfileEntry
Attributes: Attributes:
language= Language ID - language - inspection language ID
shortName= Not specified, will be computed by the underlying implementation classes. - shortName - not specified, will be computed by the underlying implementation classes
displayName= The string to be shown in the Preferences | Editor | Inspections panel - bundle - name of the message bundle for the "key" attribute
The displayName gets registered to identify this inspection. - key - the key of the message to be shown in the Preferences | Editor | Inspections panel
Can be localized using key= and bundle= attributes instead. - groupPath - defines the outermost grouping for this inspection in
groupPath= Defines the outermost grouping for this inspection in
the Preferences | Editor | Inspections panel. Not localized. the Preferences | Editor | Inspections panel. Not localized.
groupBundle= Name of *.bundle file to translate groupKey. - groupBundle - the name of a message bundle file to translate groupKey
In this case reuse an IntelliJ Platform bundle file from intellij.platform.resources.en In this case, reuse an IntelliJ Platform bundle file from intellij.platform.resources.en
groupKey= Key to use for translation subgroup name using groupBundle file. - groupKey - the key to use for translation subgroup name using groupBundle file.
In this case reuse the IntelliJ Platform subcategory "Probable bugs" In this case, reuse the IntelliJ Platform subcategory "Probable bugs"
enabledByDefault= Inspection state when Inspections panel is created. - enabledByDefault - inspection state when the Inspections panel is created.
level= The default level of error found by this inspection, e.g. INFO, ERROR, etc. - level - the default level of error found by this inspection, e.g. INFO, ERROR, etc.
@see com.intellij.codeHighlighting.HighlightDisplayLevel @see com.intellij.codeHighlighting.HighlightDisplayLevel
implementationClass= FQN of inspection implementation - implementationClass= the fully-qualified name of the inspection implementation class
--> -->
<localInspection language="JAVA" <localInspection language="JAVA"
displayName="SDK: '==' or '!=' used instead of 'equals()'" bundle="messages.InspectionBundle"
key="inspection.comparing.string.references.display.name"
groupPath="Java" groupPath="Java"
groupBundle="messages.InspectionsBundle" groupBundle="messages.InspectionsBundle"
groupKey="group.names.probable.bugs" groupKey="group.names.probable.bugs"
enabledByDefault="true" enabledByDefault="true"
level="WARNING" level="WARNING"
implementationClass="org.intellij.sdk.codeInspection.ComparingReferencesInspection"/> implementationClass="org.intellij.sdk.codeInspection.ComparingStringReferencesInspection"/>
</extensions> </extensions>
</idea-plugin> </idea-plugin>

View File

@ -0,0 +1,9 @@
<!-- Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
<html>
<body>
Reports usages of <code>==</code> and <code>!=</code> when comparing instances of String.
<p>
Quick-fix replaces operator with <code>equals()</code> call.
</p>
</body>
</html>

View File

@ -0,0 +1,5 @@
# Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
inspection.comparing.string.references.display.name=SDK: '==' or '!=' used instead of 'equals()'
inspection.comparing.string.references.problem.descriptor=SDK: String objects compared with equality operation
inspection.comparing.string.references.use.quickfix=SDK: Use equals()

View File

@ -1,23 +1,31 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.intellij.sdk.codeInspection; package org.intellij.sdk.codeInspection;
import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.testFramework.TestDataPath;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
/** @TestDataPath("$CONTENT_ROOT/testData")
* Class for testing ComparingReferencesInspection. public class ComparingStringReferencesInspectionTest extends LightJavaCodeInsightFixtureTestCase {
* Requires {@code idea.home.path} to be set in build.gradle.kts.
* doTest() does the work for individual test cases. private static final String QUICK_FIX_NAME =
*/ InspectionBundle.message("inspection.comparing.string.references.use.quickfix");
public class ComparingReferencesInspectionTest extends LightJavaCodeInsightFixtureTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
myFixture.enableInspections(new ComparingStringReferencesInspection());
// optimization: add a fake java.lang.String class to avoid loading all JDK classes for test
myFixture.addClass("package java.lang; public final class String {}");
}
/** /**
* Defines path to files used for running tests. * Defines the path to files used for running tests.
* *
* @return The path from this module's root directory ($MODULE_WORKING_DIR$) to the * @return The path from this module's root directory ($MODULE_WORKING_DIR$) to the
* directory containing files for these tests. * directory containing files for these tests.
@ -27,28 +35,6 @@ public class ComparingReferencesInspectionTest extends LightJavaCodeInsightFixtu
return "src/test/testData"; return "src/test/testData";
} }
/**
* Given the name of a test file, runs comparing references inspection quick fix and tests
* the results against a reference outcome file. File name pattern 'foo.java' and 'foo.after.java'
* are matching before and after files in the testData directory.
*
* @param testName The name of the test file before comparing references inspection.
*/
protected void doTest(@NotNull String testName) {
// Initialize the test based on the testData file
myFixture.configureByFile(testName + ".java");
// Initialize the inspection and get a list of highlighted
myFixture.enableInspections(new ComparingReferencesInspection());
List<HighlightInfo> highlightInfos = myFixture.doHighlighting();
assertFalse(highlightInfos.isEmpty());
// Get the quick fix action for comparing references inspection and apply it to the file
final IntentionAction action = myFixture.findSingleIntention(ComparingReferencesInspection.QUICK_FIX_NAME);
assertNotNull(action);
myFixture.launchAction(action);
// Verify the results
myFixture.checkResultByFile(testName + ".after.java");
}
/** /**
* Test the '==' case. * Test the '==' case.
*/ */
@ -63,4 +49,26 @@ public class ComparingReferencesInspectionTest extends LightJavaCodeInsightFixtu
doTest("Neq"); doTest("Neq");
} }
/**
* Given the name of a test file, runs comparing references inspection quick fix and tests
* the results against a reference outcome file.
* File name pattern 'foo.java' and 'foo.after.java' are matching before and after files
* in the testData directory.
*
* @param testName test file name base
*/
protected void doTest(@NotNull String testName) {
// Initialize the test based on the testData file
myFixture.configureByFile(testName + ".java");
// Initialize the inspection and get a list of highlighted
List<HighlightInfo> highlightInfos = myFixture.doHighlighting();
assertFalse(highlightInfos.isEmpty());
// Get the quick fix action for comparing references inspection and apply it to the file
final IntentionAction action = myFixture.findSingleIntention(QUICK_FIX_NAME);
assertNotNull(action);
myFixture.launchAction(action);
// Verify the results
myFixture.checkResultByFile(testName + ".after.java");
}
} }

View File

@ -0,0 +1,5 @@
public class Eq {
public boolean compareStrings(String s1, String s2) {
return (s1.equals(s2));
}
}

View File

@ -0,0 +1,5 @@
public class Eq {
public boolean compareStrings(String s1, String s2) {
return (<caret>s1 == s2);
}
}

View File

@ -0,0 +1,5 @@
public class Neq {
public boolean compareStrings(String s1, String s2) {
return (!s1.equals(s2));
}
}

View File

@ -0,0 +1,5 @@
public class Neq {
public boolean compareStrings(String s1, String s2) {
return (s1 <caret>!= s2);
}
}