mirror of
https://github.com/JetBrains/intellij-sdk-code-samples.git
synced 2025-07-30 18:27:49 +08:00
Rewrite comparing references inspection
Rewrite inspections tutorial doc
This commit is contained in:
parent
c71d177720
commit
2914811e6b
@ -1,11 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PLUGIN_MODULE" version="4">
|
||||
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/source/META-INF/plugin.xml" />
|
||||
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/resources/META-INF/plugin.xml" />
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/source" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSource" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testData" type="java-test-resource" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
@ -0,0 +1,72 @@
|
||||
<!-- Copyright 2000-2019 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. -->
|
||||
|
||||
<idea-plugin>
|
||||
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
|
||||
<id>org.intelliJ.sdk.codeInspection</id>
|
||||
|
||||
<!-- Text to display as name on Preferences/Settings | Plugin page -->
|
||||
<name>SDK Comparing References Inspection Sample</name>
|
||||
|
||||
<!-- The version of this plugin -->
|
||||
<version>1.1.0</version>
|
||||
|
||||
<!-- Compatible with the following versions of IntelliJ Platform -->
|
||||
<idea-version since-build="173"/>
|
||||
|
||||
<!-- Text to display as description on Preferences/Settings | Plugin page -->
|
||||
<description>
|
||||
<![CDATA[
|
||||
Demonstrates implementing a Local Inspection Tool.<br> Adds entries to <b>Preferences | Editor | Inspections | Java | Probable Bugs</b>.
|
||||
]]>
|
||||
</description>
|
||||
<change-notes>
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li><b>1.1.0</b> Refactor resources, register this inspection.</li>
|
||||
<li><b>1.0.0</b> Release 2018.3 and earlier.</li>
|
||||
</ul>
|
||||
]]>
|
||||
</change-notes>
|
||||
|
||||
<!-- Text to display as company information on Preferences/Settings | Plugin page -->
|
||||
<vendor email="sdk-example@jetbrains.com" url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
|
||||
<!-- 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.
|
||||
It is preferred over <inspectionToolProvider>
|
||||
@see intellij.platform.resources.LangExtensionPoints
|
||||
@see com.intellij.codeInspection.InspectionProfileEntry
|
||||
Attributes:
|
||||
language= Defines the type of file (in this case java source) for this inspection. Not localized
|
||||
shortName= The default name for the inspection, e.g. the default
|
||||
for name for the description file "ComparingReferences.html". Not localized.
|
||||
displayName= The string to be shown in the Preferences | Editor | Inspections panel
|
||||
The displayName gets registered to identify this inspection.
|
||||
Can be localized using key= and bundle= attributes instead.
|
||||
groupPath= Defines the outermost grouping for this inspection in
|
||||
the Preferences | Editor | Inspections panel. Not localized.
|
||||
groupBundle= Name of *.bundle file to translate groupKey.
|
||||
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.
|
||||
In this case reuse the IntelliJ Platform subcategory "Probable bugs"
|
||||
enabledByDefault= Inspection state when Inspections panel is created.
|
||||
level= The default level of error found by this inspection, e.g. INFO, ERROR, etc.
|
||||
@see com.intellij.codeHighlighting.HighlightDisplayLevel
|
||||
inplementationClass= package.className of implementation
|
||||
-->
|
||||
<localInspection language="JAVA"
|
||||
shortName="ComparingReferences"
|
||||
displayName="SDK: '==' or '!=' used instead of 'equals()'"
|
||||
groupPath="Java"
|
||||
groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.probable.bugs"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.ComparingReferencesInspection"/>
|
||||
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<b>SDK:</b> This inspection reports when the '==' or '!=' operator was used between expressions of
|
||||
reference types. <br>
|
||||
Classes to be inspected are controlled by a semi-colon separated <i>Options</i> list in the preferences panel for this inspection.
|
||||
</body>
|
||||
</html>
|
@ -1,14 +0,0 @@
|
||||
<idea-plugin>
|
||||
<name>Comparing References Inspection</name>
|
||||
<description>Inspection for (probably) inappropriate use of equality relation operation.</description>
|
||||
<version>1.0</version>
|
||||
<vendor>JetBrains</vendor>
|
||||
<!--
|
||||
<idea-version since-build="3000"/>
|
||||
-->
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<inspectionToolProvider implementation="com.intellij.codeInspection.ComparingReferencesProvider"/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
@ -1,105 +1,167 @@
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
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.*;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
* @author jhake
|
||||
*/
|
||||
public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ComparingReferencesInspection");
|
||||
|
||||
private final LocalQuickFix myQuickFix = new MyQuickFix();
|
||||
|
||||
private final CriQuickFix myQuickFix = new CriQuickFix();
|
||||
|
||||
// Defines the text of the quick fix intention
|
||||
public static final String QUICK_FIX_NAME = "SDK: " + InspectionsBundle.message("inspection.comparing.references.use.quickfix");
|
||||
|
||||
// This string holds a list of classes relevant to this inspection.
|
||||
@SuppressWarnings({"WeakerAccess"})
|
||||
@NonNls
|
||||
public String CHECKED_CLASSES = "java.lang.String;java.util.Date";
|
||||
@NonNls
|
||||
private static final String DESCRIPTION_TEMPLATE =
|
||||
InspectionsBundle.message("inspection.comparing.references.problem.descriptor");
|
||||
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
|
||||
return "'==' or '!=' instead of 'equals()'";
|
||||
|
||||
/**
|
||||
* 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 CHECKED_CLASSES.
|
||||
* Adds a document listener to see if
|
||||
*
|
||||
* @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(DocumentEvent event) {
|
||||
CHECKED_CLASSES = checkedClasses.getText();
|
||||
}
|
||||
});
|
||||
panel.add(checkedClasses);
|
||||
return panel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getGroupDisplayName() {
|
||||
return GroupNames.BUGS_GROUP_NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getShortName() {
|
||||
return "ComparingReferences";
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isNullLiteral(PsiExpression expr) {
|
||||
return expr instanceof PsiLiteralExpression && "null".equals(expr.getText());
|
||||
}
|
||||
|
||||
private static class MyQuickFix implements LocalQuickFix {
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
// The test (see the TestThisPlugin class) uses this string to identify the quick fix action.
|
||||
return InspectionsBundle.message("inspection.comparing.references.use.quickfix");
|
||||
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();
|
||||
@ -108,16 +170,16 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
|
||||
PsiExpression rExpr = binaryExpression.getROperand();
|
||||
if (rExpr == null)
|
||||
return;
|
||||
|
||||
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
PsiMethodCallExpression equalsCall =
|
||||
(PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null);
|
||||
|
||||
(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);
|
||||
@ -127,27 +189,11 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
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(DocumentEvent event) {
|
||||
CHECKED_CLASSES = checkedClasses.getText();
|
||||
}
|
||||
});
|
||||
|
||||
panel.add(checkedClasses);
|
||||
return panel;
|
||||
}
|
||||
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
/**
|
||||
* This class provides a list of inspections (classes) for this plugin.
|
||||
* Each inspection class should have a corresponding entry in plugin.xml
|
||||
* @author max
|
||||
*/
|
||||
public class ComparingReferencesProvider implements InspectionToolProvider {
|
||||
|
@ -1,7 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports when the '==' or '!=' operator was used between expressions of
|
||||
reference types. <br>
|
||||
In the text field below, specify the semicolon separated list of classes to be considered as suspicious.
|
||||
</body>
|
||||
</html>
|
@ -4,73 +4,84 @@ package testPlugin;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInspection.ComparingReferencesInspection;
|
||||
import com.intellij.codeInspection.InspectionToolProvider;
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.testFramework.UsefulTestCase;
|
||||
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
||||
import com.intellij.testFramework.fixtures.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @see JavaCodeInsightFixtureTestCase
|
||||
* @see LightCodeInsightFixtureTestCase
|
||||
*/
|
||||
@TestDataPath("$CONTENT_ROOT/../testData")
|
||||
public class TestThisPlugin extends UsefulTestCase {
|
||||
|
||||
|
||||
protected CodeInsightTestFixture myFixture;
|
||||
|
||||
// TODO: Get path to module root, then add path to testData
|
||||
// Specify path to your test data directory
|
||||
// e.g. final String dataPath = "c:\\users\\john.doe\\idea\\community\\samples\\ComparingReferences/testData";
|
||||
final String dataPath = "c:\\users\\John.Doe\\idea\\community\\samples\\comparingReferences/testData";
|
||||
|
||||
|
||||
// Specify the path to the test data directory
|
||||
final String dataPath = PathManager.getResourceRoot(TestThisPlugin.class, "/testPlugin/TestThisPlugin.class");
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
|
||||
final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
|
||||
final TestFixtureBuilder<IdeaProjectTestFixture> testFixtureBuilder =
|
||||
fixtureFactory.createFixtureBuilder(getName());
|
||||
fixtureFactory.createFixtureBuilder(getName());
|
||||
myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(testFixtureBuilder.getFixture());
|
||||
myFixture.setTestDataPath(dataPath);
|
||||
final JavaModuleFixtureBuilder builder = testFixtureBuilder.addModule(JavaModuleFixtureBuilder.class);
|
||||
|
||||
|
||||
builder.addContentRoot(myFixture.getTempDirPath()).addSourceRoot("");
|
||||
builder.setMockJdkLevel(JavaModuleFixtureBuilder.MockJdkLevel.jdk15);
|
||||
myFixture.setUp();
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
myFixture.tearDown();
|
||||
myFixture = null;
|
||||
}
|
||||
|
||||
|
||||
protected void doTest(String testName, String hint) throws Throwable {
|
||||
myFixture.configureByFile(testName + ".java");
|
||||
|
||||
|
||||
myFixture.enableInspections(ComparingReferencesInspection.class);
|
||||
List<HighlightInfo> highlightInfos = myFixture.doHighlighting();
|
||||
Assert.assertTrue(!highlightInfos.isEmpty());
|
||||
|
||||
|
||||
final IntentionAction action = myFixture.findSingleIntention(hint);
|
||||
|
||||
|
||||
Assert.assertNotNull(action);
|
||||
myFixture.launchAction(action);
|
||||
myFixture.checkResultByFile(testName + ".after.java");
|
||||
}
|
||||
|
||||
// Test the "==" case
|
||||
|
||||
/**
|
||||
* Test the "==" case
|
||||
* Note the hint must match CriQuickFix#getName
|
||||
*
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Test
|
||||
public void test() throws Throwable {
|
||||
doTest("before", "Use equals()");
|
||||
// doTest("before", "Use equals()");
|
||||
doTest("before", ComparingReferencesInspection.QUICK_FIX_NAME);
|
||||
}
|
||||
|
||||
// Test the "!=" case
|
||||
|
||||
/**
|
||||
* Test the "!=" case
|
||||
* Note the hint must match CriQuickFix#getName
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Test
|
||||
public void test1() throws Throwable {
|
||||
doTest("before1", "Use equals()");
|
||||
doTest("before1", ComparingReferencesInspection.QUICK_FIX_NAME);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
<idea-plugin>
|
||||
<name>Conditional Operator Converter</name>
|
||||
<id>ConditionalOperatorConverter</id>
|
||||
<description>Intention action that suggests to convert a conditional operator into
|
||||
'if' block.
|
||||
</description>
|
||||
<version>1.3</version>
|
||||
<vendor>JetBrains</vendor>
|
||||
<!--
|
||||
<idea-version since-build="2000"/>
|
||||
-->
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.ConditionalOperatorConvertor</className>
|
||||
<category>Conditional Operator</category>
|
||||
<descriptionDirectoryName>ConditionalOperatorConvertor</descriptionDirectoryName>
|
||||
|
||||
</intentionAction>
|
||||
</extensions>
|
||||
|
||||
<project-components>
|
||||
<component>
|
||||
<implementation-class>com.intellij.codeInsight.intention.ConditionalOperatorConvertor</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
</idea-plugin>
|
@ -1,12 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PLUGIN_MODULE" version="4">
|
||||
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/META-INF/plugin.xml" />
|
||||
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/resources/META-INF/plugin.xml" />
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/source" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSource" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testData" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
@ -0,0 +1,46 @@
|
||||
<!-- Copyright 2000-2019 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. -->
|
||||
|
||||
<idea-plugin>
|
||||
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
|
||||
<id>ConditionalOperatorConverter</id>
|
||||
|
||||
<!-- Text to display as name on Preferences/Settings | Plugin page -->
|
||||
<name>SDK Conditional Operator Converter</name>
|
||||
|
||||
<!-- The version of this plugin -->
|
||||
<version>1.4.0</version>
|
||||
|
||||
<!-- Compatible with the following versions of IntelliJ Platform -->
|
||||
<idea-version since-build="191"/>
|
||||
|
||||
<!-- Text to display as description on Preferences/Settings | Plugin page -->
|
||||
<description>
|
||||
<![CDATA[
|
||||
Intention action that suggests converting a ternary operator into an 'if' block.<br>Adds entry to <b>Preferences | Editor | Intentions | SDK Intentions<b>.
|
||||
]]>
|
||||
</description>
|
||||
<change-notes>
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li><b>1.4.0</b> Refactor resources, general cleanup.</li>
|
||||
<li><b>1.3.0</b> Release 2018.3 and earlier.</li>
|
||||
</ul>
|
||||
]]>
|
||||
</change-notes>
|
||||
|
||||
<!-- Text to display as company information on Preferences/Settings | Plugin page -->
|
||||
<vendor email="sdk-example@jetbrains.com" url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.ConditionalOperatorConvertor</className>
|
||||
<category>SDK Intentions</category>
|
||||
</intentionAction>
|
||||
</extensions>
|
||||
|
||||
<project-components>
|
||||
<component>
|
||||
<implementation-class>com.intellij.codeInsight.intention.ConditionalOperatorConvertor</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
</idea-plugin>
|
@ -0,0 +1,7 @@
|
||||
<!-- Copyright 2000-2019 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>
|
||||
<b>SDK:</b> This intention converts a ternary operator to a corresponding if statement. <br>
|
||||
</body>
|
||||
</html>
|
@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2018 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.
|
||||
*/
|
||||
|
||||
// Copyright 2000-2019 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.
|
||||
|
||||
package com.intellij.codeInsight.intention;
|
||||
|
||||
@ -26,21 +25,21 @@ public class ConditionalOperatorConvertor extends PsiElementBaseIntentionAction
|
||||
*/
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return "Convert ternary operator to if statement";
|
||||
return "SDK Convert ternary operator to if statement";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns text for name of this family of intentions. It is used to externalize
|
||||
* "auto-show" state of intentions. Only one intention action is being provided,
|
||||
* so the family name is the same text as the intention action list entry.
|
||||
* "auto-show" state of intentions.
|
||||
* It is also the directory name for the descriptions.
|
||||
*
|
||||
* @return the intention family name.
|
||||
* @see ConditionalOperatorConvertor#getText()
|
||||
* @see com.intellij.codeInsight.intention.IntentionManager#registerIntentionAndMetaData(IntentionAction, String...)
|
||||
* @return the intention family name.
|
||||
*/
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getText();
|
||||
return "ConditionalOperatorIntention";
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention converts a ternary operator to a corresponding if statement. <br>
|
||||
</body>
|
||||
</html>
|
@ -1,3 +1,5 @@
|
||||
// Copyright 2000-2019 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.
|
||||
|
||||
package testPlugin;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
@ -52,7 +54,7 @@ public class YourTest extends UsefulTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doTest("before.template", "Convert ternary operator to if statement");
|
||||
doTest("before.template", "SDK Convert ternary operator to if statement");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,67 @@
|
||||
<!-- Copyright 2000-2019 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. -->
|
||||
|
||||
<idea-plugin>
|
||||
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
|
||||
<id>com.intellij.tutorials.inspection</id>
|
||||
<name>Inspection Demo</name>
|
||||
<version>1.0</version>
|
||||
<vendor>JetBrains</vendor>
|
||||
|
||||
<description>Basic example of working with code inspections</description>
|
||||
<!-- Text to display as name on Preferences/Settings | Plugin page -->
|
||||
<name>SDK Inspection Demo</name>
|
||||
|
||||
<idea-version since-build="131"/>
|
||||
<!-- The version of this plugin -->
|
||||
<version>1.1.0</version>
|
||||
|
||||
<!-- Compatible with the following versions of IntelliJ Platform -->
|
||||
<idea-version since-build="191"/>
|
||||
|
||||
<!-- Text to display as description on Preferences/Settings | Plugin page -->
|
||||
<description>
|
||||
<![CDATA[
|
||||
Basic example of working with code inspections. Adds entry to <b>Preferences | Editor | Inspections | SDK | Example Tools</b>.
|
||||
]]>
|
||||
</description>
|
||||
<change-notes>
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li><b>1.1.0</b> Refactor resources, add "SDK" to description.</li>
|
||||
<li><b>1.0.0</b> Release 2018.3 and earlier.</li>
|
||||
</ul>
|
||||
]]>
|
||||
</change-notes>
|
||||
|
||||
<!-- Text to display as company information on Preferences/Settings | Plugin page -->
|
||||
<vendor email="sdk-example@jetbrains.com" url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<inspectionToolProvider implementation="com.intellij.tutorials.inspection.DemoInspectionToolProvider"/>
|
||||
|
||||
<!-- 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.
|
||||
It is preferred over <inspectionToolProvider>
|
||||
@see intellij.platform.resources.LangExtensionPoints
|
||||
@see com.intellij.codeInspection.InspectionProfileEntry
|
||||
Attributes:
|
||||
language= Defines the type of file (in this case java source) for this inspection. Not localized
|
||||
shortName= The default name for the inspection, e.g. the default
|
||||
for name for the description file "DemoCode.html". Not localized.
|
||||
displayName= The string to be shown in the Preferences | Editor | Inspections panel
|
||||
The displayName gets registered to identify this inspection.
|
||||
Can be localized using key= and bundle= attributes instead.
|
||||
groupPath= Defines the outermost grouping for this inspection in
|
||||
the Preferences | Editor | Inspections panel. Not localized.
|
||||
groupName= The subgroup containing this inspection. Not localized.
|
||||
enabledByDefault= Inspection state when Inspections panel is created.
|
||||
level= The default level of error found by this inspection, e.g. INFO, ERROR, etc.
|
||||
@see com.intellij.codeHighlighting.HighlightDisplayLevel
|
||||
inplementationClass= package.className of inspection implementation
|
||||
-->
|
||||
<localInspection language="JAVA"
|
||||
shortName="DemoCode"
|
||||
displayName="Demo Inspection"
|
||||
groupName="Example Inspections"
|
||||
groupPath="SDK"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
implementationClass="com.intellij.tutorials.inspection.DemoCodeInspection"/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
@ -0,0 +1,9 @@
|
||||
<!-- Copyright 2000-2019 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>
|
||||
<b>SDK:</b> Write your description here.<br>
|
||||
<!-- tooltip end -->
|
||||
Text after this comment will not be shown in tooltips.
|
||||
</body>
|
||||
</html>
|
@ -1,19 +1,24 @@
|
||||
// Copyright 2000-2019 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.
|
||||
|
||||
package com.intellij.tutorials.inspection;
|
||||
|
||||
import com.intellij.codeInspection.*;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Anna Bulenkova
|
||||
*/
|
||||
public class DemoCodeInspection extends LocalInspectionTool {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Demo Inspection";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is overridden to provide a custom visitor
|
||||
* 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 DemoInspectionVisitor.
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public DemoInspectionVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
|
@ -1,3 +1,5 @@
|
||||
// Copyright 2000-2019 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.
|
||||
|
||||
package com.intellij.tutorials.inspection;
|
||||
|
||||
import com.intellij.codeInspection.InspectionToolProvider;
|
||||
|
@ -1,3 +1,5 @@
|
||||
// Copyright 2000-2019 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.
|
||||
|
||||
package com.intellij.tutorials.inspection;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
|
@ -1,7 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Write your description here.
|
||||
<!-- tooltip end -->
|
||||
Text after this comment will not be shown in tooltips.
|
||||
</body>
|
||||
</html>
|
@ -2,71 +2,188 @@
|
||||
title: Code Inspections
|
||||
---
|
||||
|
||||
This topic describes the [comparing_references_inspection](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection), a sample plugin that creates a custom [inspection](https://www.jetbrains.com/idea/webhelp/code-inspection.html) for Java code. In addition, the sample plugin contains a JUnit-based test.
|
||||
The IntelliJ Platform provides tools designed for static code analysis called _code inspections_, which help the user maintain and clean up code without actually executing it.
|
||||
Custom code inspections can be implemented as IntelliJ Platform plugins.
|
||||
Examples of the plugin approach are the IntelliJ Platform SDK code samples [inspection](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/inspection) and [comparing_references_inspection](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection).
|
||||
In addition, the comparing_references_inspection code sample demonstrates implementing a unit test.
|
||||
|
||||
## About Code Inspections
|
||||
You can also create custom inspections through the IntelliJ IDEA user interface.
|
||||
See [Code Inspection](https://www.jetbrains.com/idea/webhelp/code-inspection.html) and [Creating Custom Inspections](https://www.jetbrains.com/idea/help/creating-custom-inspections.html) for more information.
|
||||
|
||||
The **IntelliJ Platform** provides tools designed for static code analysis (so called _code inspections_) that help you maintain and clean up your code without actually executing it. For more information, refer to [Code Inspection](https://www.jetbrains.com/idea/webhelp/code-inspection.html) in the **IntelliJ IDEA** Web Help. In **IntelliJ IDEA** you will find a set of built-in inspections that are grouped by their goals and sense.
|
||||
## Creating an Inspection Plugin
|
||||
|
||||
You can create custom inspections through the **IntelliJ IDEA** interface (see [Creating Custom Inspections](https://www.jetbrains.com/idea/help/creating-custom-inspections.html)). Alternatively, you can develop a plugin to implement a custom inspection.
|
||||
The [comparing_references_inspection](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection) code sample adds a new inspection to the **Java | Probable Bugs** group in the [Inspections list](https://www.jetbrains.com/help/idea/inspections-settings.html).
|
||||
The inspection reports when the `==` or `!=` operator is used between Java expressions of reference types.
|
||||
It illustrates the components for a custom inspection plugin:
|
||||
* Describing an [inspection](#plugin-configuration-file) in the plugin configuration file.
|
||||
* Implementing a [local inspection class](#inspection-implementation-java-class) to inspect Java code in the IntelliJ Platform-based IDE editor.
|
||||
* Creating a [visitor](#visitor-implementation-class) to traverse the `PsiTree` of the Java file being edited, inspecting for problematic syntax.
|
||||
* Implementing a [quick fix](#quick-fix-implementation) class to correct syntax problems by altering the `PsiTree` as needed.
|
||||
Quick fixes are displayed to the user like [intentions](code_intentions.md).
|
||||
* Implementing an [inspection preferences panel](#inspection-preferences-panel) to display information about the inspection.
|
||||
* Writing an HTML [description](#inspection-description) of the inspection for display in the inspection preferences panel.
|
||||
* Optionally, create a [unit test](#inspection-unit-test) for the plugin.
|
||||
|
||||
## Techniques Used
|
||||
Although the IntelliJ Platform SDK code samples illustrate implementations of these components, it is often useful to see examples of inspections implemented in the _intellij_community_ code base.
|
||||
This process can help find inspection descriptions and implementations based on what is visible in the IDE UI.
|
||||
The overall approach works for inspections aimed at other languages as well.
|
||||
* Find an existing inspection that is similar to the one you want to implement in the **Preferences | Editor | Inspections** panel.
|
||||
Note the display name of the inspection.
|
||||
For example, the Java/Probable Bugs inspection "Object comparison using '==', instead of 'equals()'" is very similar to `comparing_references_inspection`.
|
||||
* Use the display name text as the [target for a search](https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html) within the _intellij_community_ project.
|
||||
This will identify a bundle file if the display name is localized.
|
||||
If it is not localized, the search finds either the plugin configuration (`plugin.xml`) file where it is an attribute in the inspection description, or the Java implementation file where it provided by an overridden method.
|
||||
* In the case of localization, copy the key from the bundle file identified by the search.
|
||||
* Use the key text as the target for a search within the _intellij_community_ project.
|
||||
This search locates the plugin configuration file that describes the inspection.
|
||||
* From the inspection description entry find the `implementationClass` attribute value.
|
||||
* Use the `implementationClass` text as the [target of a class search](https://www.jetbrains.com/help/idea/searching-everywhere.html#Searching_Everywhere.xml) in the _intellij_community_ codebase to find the Java implementation file.
|
||||
|
||||
The [comparing_references_inspection](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection) sample plugin illustrates the use of the following techniques:
|
||||
## Creating an Inspection
|
||||
The [comparing_references_inspection](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection) code sample reports when the `==` or `!=` operators are used between Java expressions of reference types.
|
||||
The user can apply a quick fix to change `a==b` to `a.equals(b)`, or `a!=b` to `!a.equals(b)`.
|
||||
|
||||
The details of the `comparing_references_inspection` implementation illustrate the components of an inspection plugin.
|
||||
|
||||
- How to analyze a [PSI tree](/basics/architectural_overview/psi_files.md).
|
||||
- How to find a Java token of interest in the PSI tree.
|
||||
- How to inspect Java code in the **IntelliJ IDEA** editor using the [BaseJavaLocalInspectionTool](upsource:///java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java) class.
|
||||
- How to create a JUnit test for this plugin using the [IdeaTestFixtureFactory](upsource:///platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java) class.
|
||||
### Plugin Configuration File
|
||||
The `comparing_references_inspection` is described as a `<localInspection>` type within the `<extensions>` elements in the `comparing_references_inspection` plugin configuration ([plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection/resources/META-INF/plugin.xml)) file.
|
||||
Under the hood, inspection types are described as an `<extensionPoint>` in [LangExtensionPoints.xml](upsource:///platform/platform-resources/src/META-INF/LangExtensionPoints.xml):
|
||||
* The `localInspection` type is used for inspections that operate on one file at a time, and also operate as the user edits the file.
|
||||
* The `globalInspection` type is used for inspections that operate across multiple files, and the associated fix might, for example, refactor code between files.
|
||||
* The `inspectionToolProvider` type is not deprecated but `localInspection` is preferred.
|
||||
|
||||
## Sample Plugin
|
||||
The minimum inspection description must contain the `implementationClass` attribute.
|
||||
As shown in the `comparing_references_inspection` plugin configuration file, other attributes can be defined in the `localInspection` element, either with or without localization.
|
||||
In most cases, it is simplest to define the attributes in the plugin configuration file because the underlying parent classes handle most of the class responsibilities based on the configuration file description.
|
||||
Note that some attributes are not displayed to the user, so they are never localized.
|
||||
|
||||
The **comparingReferences** sample plugin is available in the `<%IntelliJ SDK Docs project%>/code_samples/comparing_references_inspection` directory. When launched, this plugin adds the **'==' or '!=' instead of 'equals()'** item to the **Probable bugs** node in the [Inspections list](https://www.jetbrains.com/help/idea/inspections-settings.html).
|
||||
As an alternative, inspections can define all of the attribute information (except `implementationClass`) by overriding methods in the inspection implementation class.
|
||||
|
||||
#### Running the Plugin
|
||||
### Inspection Implementation Java Class
|
||||
Inspection implementations for Java files, like [`ComparingReferencesInspection`](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection/source/com/intellij/codeinspection/ComparingReferencesInspection.java), are often based on the Java class [AbstractBaseJavaLocalInspectionTool](upsource:///java/java-analysis-api/src/com/intellij/codeInspection/AbstractBaseJavaLocalInspectionTool.java).
|
||||
The `AbstractBaseJavaLocalInspectionTool` implementation class offers methods to inspect Java classes, fields, and methods.
|
||||
|
||||
**To run the sample plugin**
|
||||
More generally, `localInspection` types are based on the class [`LocalInspectionTool`](upsource:///platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java).
|
||||
Examining the class hierarchy for `LocalInspectionTool` shows that the IntelliJ Platform provides many child inspection classes for a variety of languages and frameworks.
|
||||
One of these classes is a good basis for a new inspection implementation, but a bespoke implementation can also be based directly on `LocalInspectionTool`.
|
||||
|
||||
1. Start **IntelliJ IDEA** and open the **comparingReferences** plugin project saved into the `<%IntelliJ SDK Docs project%>/code_samples/comparing_references_inspection` directory.
|
||||
2. Open the [Project Structure](https://www.jetbrains.com/help/idea/project-structure-dialog.html) dialog and ensure that the project settings are valid for your environment.
|
||||
3. If necessary, modify the [Run/Debug Configurations](https://www.jetbrains.com/idea/webhelp/run-debug-configuration-plugin.html) and Run the plugin by choosing the **Run | Run** on the main menu.
|
||||
The primary responsibilities of the inspection implementation class are to provide:
|
||||
* A `PsiElementVisitor` object to traverse the `PsiTree` of the file being inspected.
|
||||
* A `LocalQuickFix` class to change the syntax of an identified problem.
|
||||
* A `JPanel` to be displayed in the _Inspections_ dialog.
|
||||
|
||||
#### Configuring the Plugin
|
||||
Note that if an inspection's description in the plugin configuration file defines only the implementation class, then the other attribute information has to be supplied by overriding methods in the Java implementation.
|
||||
|
||||
Once the plugin is launched, you can set the plugin options. You can specify the Java classes to be participated in the code inspection and the severity level of the found probable bugs.
|
||||
The `ComparingReferencesInspection` class defines two `String` fields:
|
||||
* `QUICK_FIX_NAME` defines the string users see when prompted to apply the quick fix.
|
||||
* `CHECKED_CLASSES` holds a list of class names of interest to the inspection.
|
||||
|
||||
**To configure the sample plugin**
|
||||
The overridden `ComparingReferencesInspection` methods are discussed in the sections below.
|
||||
|
||||
1. On the IDEA main menu, choose **File | Settings**, and then under **Project Settings**, click **Inspections**.
|
||||
2. In the list of the IntelliJ IDEA inspections, expand the **Probable bugs** node, and then click **'==' or '!=' instead of 'equals()'**.
|
||||
### Visitor Implementation Class
|
||||
The visitor class evaluates whether elements of the file's `PsiTree` are of interest to an inspection.
|
||||
|
||||
The `ComparingReferencesInspection.createOptionsPanel()` method creates an anonymous visitor class based on [`JavaElementVisitor`](upsource:///java/java-psi-api/src/com/intellij/psi/JavaElementVisitor.java) to traverse the `PsiTree` of the Java file being edited, inspecting for suspect syntax.
|
||||
The anonymous class overrides three methods in particular.
|
||||
* `visitReferenceExpression()` to prevent any duplicate visitation of reference-type expressions.
|
||||
* `visitBinaryExpression()`, which does all the heavy lifting.
|
||||
It is called to evaluate a `PsiBinaryExpression`, and it checks to see if the operands are `==` or `!=`, and if the operands are classes relevant to this inspection.
|
||||
* `isCheckedType()` evaluates the `PsiType` of the operands to determine if they are of interest to this inspection.
|
||||
|
||||
### Quick Fix Implementation
|
||||
The quick fix class acts much like an intention, allowing the user to change the portion of `PsiTree` highlighted by the inspection.
|
||||
A quick fix is invoked when the inspection highlights a `PsiElement` of interest and the user elects to make a change.
|
||||
|
||||
The `ComparingReferencesInspection` implementation uses the nested class `CriQuickFix` to implement a quick fix based on [`LocalQuickFix`](upsource:///platform/analysis-api/src/com/intellij/codeInspection/LocalQuickFix.java).
|
||||
The `CriQuickFix` class gives a user the option to change the use of `a == b` and `a != b` expression to `a.equals(b)` and `!a.equals(b)` respectively.
|
||||
|
||||
The heavy lifting is done in `CriQuickFix.applyFix()`, which manipulates the `PsiTree` to convert the expressions.
|
||||
The change to the `PsiTree` is accomplished by the usual approach to modification:
|
||||
* Getting a `PsiElementFactory`.
|
||||
* Creating a new `PsiMethodCallExpression`.
|
||||
* Substituting the original left and right operands into the new `PsiMethodCallExpression`.
|
||||
* Replacing the original binary expression with the `PsiMethodCallExpression`.
|
||||
|
||||
### Inspection Preferences Panel
|
||||
The inspection preferences panel is used to display information about the inspection.
|
||||
|
||||
The panel created by `ComparingReferencesInspection.createOptionsPanel()` just defines a single `JTextField` to display in a `JPanel`.
|
||||
This `JPanel` gets added to the default IntelliJ Platform _Inspections Preferences_ dialog when the `comparing_references_inspection` short name is selected.
|
||||
The `JTextField` allows editing of the `CHECKED_CLASSES` field while displayed in the panel.
|
||||
|
||||
Note that the IntelliJ Platform provides most of the UI displayed in the _Inspections Preferences_ panel.
|
||||
As long as the inspection attributes and inspection description are defined correctly, the IntelliJ Platform displays the information in the _Inspections Preferences_ UI.
|
||||
|
||||
### Inspection Description
|
||||
The inspection description is an HTML file.
|
||||
The description is displayed in the upper right panel of the _Inspections Preferences_ dialog when an inspection is selected from the list.
|
||||
|
||||
Implicit in using [`LocalInspectionTool`](upsource:///platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java) in the class hierarchy of the inspection implementation means following some conventions.
|
||||
* The inspection description file is expected to be located under `<plugin root dir>/resources/inspectionDescriptions/`.
|
||||
If the inspection description file is to be located elsewhere, override `getDescriptionUrl()` in the inspection implementation class.
|
||||
* The name of the description file is expected to be the inspection `<short name>.html` as provided by the inspection description or the inspection implementation class.
|
||||
If a short name is not provided by the plugin, the IntelliJ Platform creates one by attempting to truncate the implementation class name.
|
||||
|
||||
### Inspection Unit Test
|
||||
The `comparing_references_inspection` code sample provides a unit test for the inspection.
|
||||
See the [Testing Plugins](/basics/testing_plugins.md) section for general information about plugin testing.
|
||||
|
||||
The `comparing_references_inspection` test is based on the [`UsefulTestCase`](upsource:///platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java) class, part of the JUnit framework APIs.
|
||||
This class handles much of the underlying boilerplate for tests.
|
||||
|
||||
By convention, the folder `<project root>/testSource/testPlugin/` contains the test source code and must be marked as a "Tests" folder.
|
||||
If it is not, a DevKit project cannot find the source code.
|
||||
|
||||
By convention, the folder `<project root>/testData/` contains the test files and must be marked as a "Test Resources" folder.
|
||||
The folder contains pairs of files for each test using the name convention `*.java` and `*.after.java`.
|
||||
|
||||
In the case of `comparing_references_inspection` the test files are `before.java` and `before.after.java`, and `before1.java` and `before1.after.java`.
|
||||
The choice of `before` and `before1` is arbitrary.
|
||||
|
||||
The `comparing_references_inspection` tests run the inspection on the `*.java files`, implement the quick fix, and compare the results with the respective `*.after.java` files.
|
||||
|
||||
|
||||
## Running the Comparing References Inspection Code Sample
|
||||
The [comparing_references_inspection](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection) code sample adds a new inspection to the **Java | Probable Bugs** group in the [Inspections list](https://www.jetbrains.com/help/idea/inspections-settings.html).
|
||||
The inspection reports when the `==` or `!=` operator is used between Java expressions of reference types.
|
||||
|
||||
To run the sample plugin:
|
||||
* Start **IntelliJ IDEA**, open the `intellij-sdk-docs` project, and highlight the [comparing_references_inspection](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/comparing_references_inspection) module.
|
||||
* Open the [Project Structure](https://www.jetbrains.com/help/idea/project-structure-dialog.html) dialog and ensure that the project settings are valid for your environment.
|
||||
* If necessary, modify the [Run/Debug Configurations](https://www.jetbrains.com/idea/webhelp/run-debug-configuration-plugin.html) for the `comparing_references_inspection` module.
|
||||
* Run the plugin by choosing **Run** on the main menu.
|
||||
|
||||
### Configuring the Plugin
|
||||
|
||||
Once the plugin is launched, you can set the plugin options.
|
||||
You can specify the Java classes to participate in the code inspection and the severity level of the found probable bugs.
|
||||
|
||||
On the IDEA main menu, open the **Preferences | Editor | Inspections** dialog.
|
||||
In the list of the IntelliJ IDEA _Java_ inspections, expand the _Probable bugs_ node, and then click _SDK: '==' or '!=' instead of 'equals()'_.
|
||||
|
||||

|
||||
|
||||
3. Under **Options**, you can specify the following plugin settings:
|
||||
- From the **Severity** list, select the severity level of probable bugs the plugin will find (such as Warning, Info, etc.)
|
||||
- In the text box under **Severity**, specify the semicolon separated list of Java classes to be participated in this code inspection.
|
||||
4. When finished, click **OK**.
|
||||
Under **Options**, you can specify the following plugin settings:
|
||||
* From the **Severity** list, select the severity level of probable bugs the plugin finds such as Warning, Info, etc.
|
||||
* In the text box under **Severity**, specify the semicolon separated list of Java classes to participate in this code inspection.
|
||||
* When finished, click **OK**.
|
||||
|
||||
#### How does it work?
|
||||
### How does it work?
|
||||
|
||||
The plugin inspects your code opened in the **IntelliJ IDEA** editor or the code you are typing. The plugin highlights the code fragments where two variables of the reference type are separated by **==** or **!=** and proposes to replace this code fragment with **.equals()**:
|
||||
The plugin inspects your code opened in the IntelliJ IDEA editor or the code you are typing.
|
||||
The plugin highlights the code fragments where two variables of the reference type are separated by `==` or `!=` and proposes to replace this code fragment with `.equals()`:
|
||||
|
||||

|
||||
|
||||
In this example, the **s1** and **s2** are variables of the String type. Clicking **Use equals()** replaces
|
||||
In this example, the `str1` and `str2` are variables of the String type.
|
||||
Clicking _SDK: Use equals()_ replaces:
|
||||
|
||||
```java
|
||||
return (s1==s2);
|
||||
return (str1==str2);
|
||||
```
|
||||
|
||||
with the code:
|
||||
|
||||
```java
|
||||
return (s1.equals(s2));
|
||||
return (str1.equals(str2));
|
||||
```
|
||||
|
||||
#### Testing the Plugin
|
||||
|
||||
The sample plugin contains the `TestThisPlugin` Java class in the `testSource/testPlugin` package and the test data in the `testData` directory. This test adds two test cases to this plugin project. To run test cases, run the `YourTest.test()` or `YourTest.test1()` method, respectively.
|
||||
|
||||
For detailed information about testing and all related procedures, refer to [Testing](https://www.jetbrains.com/help/idea/performing-tests.html) in the **IntelliJ IDEA** Web Help.
|
||||
|
@ -2,11 +2,14 @@
|
||||
title: Code Intentions
|
||||
---
|
||||
|
||||
This topic describes the [conditional_operator_intention](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/conditional_operator_intention), a sample plugin that adds a new [intention action](https://www.jetbrains.com/help/idea/intention-actions.html) to the IntelliJ Platform Intentions list. In addition, the sample plugin contains a JUnit-based test.
|
||||
This topic describes the [conditional_operator_intention](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/conditional_operator_intention), a sample plugin that adds a new [intention action](https://www.jetbrains.com/help/idea/intention-actions.html) to the IntelliJ Platform Intentions list.
|
||||
In addition, the sample plugin contains a JUnit-based test.
|
||||
|
||||
## About Intention Actions
|
||||
|
||||
The **IntelliJ Platform** analyzes your code and helps handle situations that may result in errors. When a possible problem is suspected, the IDE suggests an appropriate intention action, denoted with special icons. For more information, refer to [Intention Actions](https://www.jetbrains.com/help/idea/intention-actions.html) in the **IntelliJ IDEA** Web Help.
|
||||
The **IntelliJ Platform** analyzes your code and helps handle situations that may result in errors.
|
||||
When a possible problem is suspected, the IDE suggests an appropriate intention action, denoted with special icons.
|
||||
For more information, refer to [Intention Actions](https://www.jetbrains.com/help/idea/intention-actions.html) in the **IntelliJ IDEA** Web Help.
|
||||
|
||||
You can view a list of all available intention actions using the [Intention List](https://www.jetbrains.com/help/idea/intention-actions.html#intention-settings) provided by the IDE.
|
||||
|
||||
@ -28,7 +31,8 @@ The [conditional_operator_intention](https://github.com/JetBrains/intellij-sdk-
|
||||
|
||||
## Sample Plugin
|
||||
|
||||
The **ConditionalOperatorConverter** sample plugin is available in the `<%IntelliJ SDK Docs project%>/code_samples/conditional_operator_intention` directory. When launched, this plugin adds the **Convert ternary operator if statement** item to the **Conditional Operator** node in the IDEA Intentions list:
|
||||
The **ConditionalOperatorConverter** sample plugin is available in the `<%IntelliJ SDK Docs project%>/code_samples/conditional_operator_intention` directory.
|
||||
When launched, this plugin adds the **Convert ternary operator if statement** item to the **Conditional Operator** node in the IDEA Intentions list:
|
||||
|
||||

|
||||
|
||||
@ -42,7 +46,8 @@ The **ConditionalOperatorConverter** sample plugin is available in the `<%Inte
|
||||
|
||||
#### How does it work?
|
||||
|
||||
The plugin analyzes symbols under the cursor in your code opened in the IDEA editor. If the cursor is positioned on the "?" conditional operator, **IntelliJ IDEA** proposes to replace this conditional (ternary) operator with the "if-then-else" statement:
|
||||
The plugin analyzes symbols under the cursor in your code opened in the IDEA editor.
|
||||
If the cursor is positioned on the "?" conditional operator, **IntelliJ IDEA** proposes to replace this conditional (ternary) operator with the "if-then-else" statement:
|
||||
|
||||

|
||||
|
||||
@ -64,6 +69,7 @@ if ((n>=0)) {
|
||||
|
||||
##### Testing the Plugin
|
||||
|
||||
The sample plugin contains the `YourTest` Java class in the `testSource/testPlugin/` package and the test data in the `testData/` directory. To perform the plugin test, run the `YourTest.test()` method.
|
||||
The sample plugin contains the `YourTest` Java class in the `testSource/testPlugin/` package and the test data in the `testData/` directory.
|
||||
To perform the plugin test, run the `YourTest.test()` method.
|
||||
|
||||
For detailed information about testing and all related procedures, refer to [Testing](https://www.jetbrains.com/help/idea/performing-tests.html) in the **IntelliJ IDEA** Web Help.
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 55 KiB |
Loading…
x
Reference in New Issue
Block a user