mirror of
https://github.com/JetBrains/intellij-sdk-code-samples.git
synced 2025-07-29 09:47:50 +08:00
Merge pull request #162 from JohnHake/ijsdk-573
IJSDK-573 fixed comparing_references_inspection test failures
This commit is contained in:
commit
2755936ac1
@ -1,11 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="PLUGIN_MODULE" version="4">
|
<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">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/source" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/source" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/testSource" isTestSource="true" />
|
<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>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
<!-- 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="faux-email@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= Language ID
|
||||||
|
shortName= Not specified, will be computed by the underlying implementation classes.
|
||||||
|
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= FQN of inspection implementation
|
||||||
|
-->
|
||||||
|
<localInspection language="JAVA"
|
||||||
|
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;
|
package com.intellij.codeInspection;
|
||||||
|
|
||||||
import com.intellij.codeInsight.daemon.GroupNames;
|
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import com.intellij.ui.DocumentAdapter;
|
import com.intellij.ui.DocumentAdapter;
|
||||||
import com.intellij.util.IncorrectOperationException;
|
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.*;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import static com.siyeh.ig.psiutils.ExpressionUtils.isNullLiteral;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author max
|
* @author max
|
||||||
|
* @author jhake
|
||||||
*/
|
*/
|
||||||
public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspectionTool {
|
public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ComparingReferencesInspection");
|
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ComparingReferencesInspection");
|
||||||
|
private final CriQuickFix myQuickFix = new CriQuickFix();
|
||||||
private final LocalQuickFix myQuickFix = new MyQuickFix();
|
|
||||||
|
// 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"})
|
@SuppressWarnings({"WeakerAccess"})
|
||||||
@NonNls
|
@NonNls
|
||||||
public String CHECKED_CLASSES = "java.lang.String;java.util.Date";
|
public String CHECKED_CLASSES = "java.lang.String;java.util.Date";
|
||||||
@NonNls
|
|
||||||
private static final String DESCRIPTION_TEMPLATE =
|
/**
|
||||||
InspectionsBundle.message("inspection.comparing.references.problem.descriptor");
|
* This method is called to get the panel describing the inspection.
|
||||||
|
* It is called every time the user selects the inspection in preferences.
|
||||||
@NotNull
|
* The user has the option to edit the list of CHECKED_CLASSES.
|
||||||
public String getDisplayName() {
|
* Adds a document listener to see if
|
||||||
|
*
|
||||||
return "'==' or '!=' instead of 'equals()'";
|
* @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() {
|
* This method is overridden to provide a custom visitor
|
||||||
return GroupNames.BUGS_GROUP_NAME;
|
* that inspects expressions with relational operators '==' and '!='
|
||||||
}
|
* The visitor must not be recursive and must be thread-safe.
|
||||||
|
*
|
||||||
@NotNull
|
* @param holder object for visitor to register problems found.
|
||||||
public String getShortName() {
|
* @param isOnTheFly true if inspection was run in non-batch mode
|
||||||
return "ComparingReferences";
|
* @return non-null visitor for this inspection.
|
||||||
}
|
* @see JavaElementVisitor
|
||||||
|
*/
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||||
return new JavaElementVisitor() {
|
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
|
@Override
|
||||||
public void visitReferenceExpression(PsiReferenceExpression psiReferenceExpression) {
|
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
|
@Override
|
||||||
public void visitBinaryExpression(PsiBinaryExpression expression) {
|
public void visitBinaryExpression(PsiBinaryExpression expression) {
|
||||||
super.visitBinaryExpression(expression);
|
super.visitBinaryExpression(expression);
|
||||||
IElementType opSign = expression.getOperationTokenType();
|
IElementType opSign = expression.getOperationTokenType();
|
||||||
if (opSign == JavaTokenType.EQEQ || opSign == JavaTokenType.NE) {
|
if (opSign == JavaTokenType.EQEQ || opSign == JavaTokenType.NE) {
|
||||||
|
// The binary expression is the correct type for this inspection
|
||||||
PsiExpression lOperand = expression.getLOperand();
|
PsiExpression lOperand = expression.getLOperand();
|
||||||
PsiExpression rOperand = expression.getROperand();
|
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 lType = lOperand.getType();
|
||||||
PsiType rType = rOperand.getType();
|
PsiType rType = rOperand.getType();
|
||||||
|
|
||||||
if (isCheckedType(lType) || isCheckedType(rType)) {
|
if (isCheckedType(lType) || isCheckedType(rType)) {
|
||||||
|
// Identified an expression with potential problems, add to list with fix object.
|
||||||
holder.registerProblem(expression,
|
holder.registerProblem(expression,
|
||||||
DESCRIPTION_TEMPLATE, myQuickFix);
|
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());
|
* 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 MyQuickFix implements LocalQuickFix {
|
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
|
@NotNull
|
||||||
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
// The test (see the TestThisPlugin class) uses this string to identify the quick fix action.
|
return QUICK_FIX_NAME;
|
||||||
return InspectionsBundle.message("inspection.comparing.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) {
|
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||||
try {
|
try {
|
||||||
PsiBinaryExpression binaryExpression = (PsiBinaryExpression) descriptor.getPsiElement();
|
PsiBinaryExpression binaryExpression = (PsiBinaryExpression) descriptor.getPsiElement();
|
||||||
@ -108,16 +170,16 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
|
|||||||
PsiExpression rExpr = binaryExpression.getROperand();
|
PsiExpression rExpr = binaryExpression.getROperand();
|
||||||
if (rExpr == null)
|
if (rExpr == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||||
PsiMethodCallExpression equalsCall =
|
PsiMethodCallExpression equalsCall =
|
||||||
(PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null);
|
(PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null);
|
||||||
|
|
||||||
equalsCall.getMethodExpression().getQualifierExpression().replace(lExpr);
|
equalsCall.getMethodExpression().getQualifierExpression().replace(lExpr);
|
||||||
equalsCall.getArgumentList().getExpressions()[0].replace(rExpr);
|
equalsCall.getArgumentList().getExpressions()[0].replace(rExpr);
|
||||||
|
|
||||||
PsiExpression result = (PsiExpression) binaryExpression.replace(equalsCall);
|
PsiExpression result = (PsiExpression) binaryExpression.replace(equalsCall);
|
||||||
|
|
||||||
if (opSign == JavaTokenType.NE) {
|
if (opSign == JavaTokenType.NE) {
|
||||||
PsiPrefixExpression negation = (PsiPrefixExpression) factory.createExpressionFromText("!a", null);
|
PsiPrefixExpression negation = (PsiPrefixExpression) factory.createExpressionFromText("!a", null);
|
||||||
negation.getOperand().replace(result);
|
negation.getOperand().replace(result);
|
||||||
@ -127,27 +189,11 @@ public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspecti
|
|||||||
LOG.error(e);
|
LOG.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getFamilyName() {
|
public String getFamilyName() {
|
||||||
return getName();
|
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,10 +0,0 @@
|
|||||||
package com.intellij.codeInspection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author max
|
|
||||||
*/
|
|
||||||
public class ComparingReferencesProvider implements InspectionToolProvider {
|
|
||||||
public Class[] getInspectionClasses() {
|
|
||||||
return new Class[]{ComparingReferencesInspection.class};
|
|
||||||
}
|
|
||||||
}
|
|
@ -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.daemon.impl.HighlightInfo;
|
||||||
import com.intellij.codeInsight.intention.IntentionAction;
|
import com.intellij.codeInsight.intention.IntentionAction;
|
||||||
import com.intellij.codeInspection.ComparingReferencesInspection;
|
import com.intellij.codeInspection.ComparingReferencesInspection;
|
||||||
import com.intellij.codeInspection.InspectionToolProvider;
|
import com.intellij.openapi.application.PathManager;
|
||||||
import com.intellij.testFramework.TestDataPath;
|
|
||||||
import com.intellij.testFramework.UsefulTestCase;
|
import com.intellij.testFramework.UsefulTestCase;
|
||||||
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
||||||
import com.intellij.testFramework.fixtures.*;
|
import com.intellij.testFramework.fixtures.*;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see JavaCodeInsightFixtureTestCase
|
* @see JavaCodeInsightFixtureTestCase
|
||||||
* @see LightCodeInsightFixtureTestCase
|
* @see LightCodeInsightFixtureTestCase
|
||||||
*/
|
*/
|
||||||
@TestDataPath("$CONTENT_ROOT/../testData")
|
|
||||||
public class TestThisPlugin extends UsefulTestCase {
|
public class TestThisPlugin extends UsefulTestCase {
|
||||||
|
|
||||||
protected CodeInsightTestFixture myFixture;
|
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 {
|
public void setUp() throws Exception {
|
||||||
|
|
||||||
final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
|
final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
|
||||||
final TestFixtureBuilder<IdeaProjectTestFixture> testFixtureBuilder =
|
final TestFixtureBuilder<IdeaProjectTestFixture> testFixtureBuilder =
|
||||||
fixtureFactory.createFixtureBuilder(getName());
|
fixtureFactory.createFixtureBuilder(getName());
|
||||||
myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(testFixtureBuilder.getFixture());
|
myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(testFixtureBuilder.getFixture());
|
||||||
myFixture.setTestDataPath(dataPath);
|
myFixture.setTestDataPath(dataPath);
|
||||||
final JavaModuleFixtureBuilder builder = testFixtureBuilder.addModule(JavaModuleFixtureBuilder.class);
|
final JavaModuleFixtureBuilder builder = testFixtureBuilder.addModule(JavaModuleFixtureBuilder.class);
|
||||||
|
|
||||||
builder.addContentRoot(myFixture.getTempDirPath()).addSourceRoot("");
|
builder.addContentRoot(myFixture.getTempDirPath()).addSourceRoot("");
|
||||||
builder.setMockJdkLevel(JavaModuleFixtureBuilder.MockJdkLevel.jdk15);
|
builder.setMockJdkLevel(JavaModuleFixtureBuilder.MockJdkLevel.jdk15);
|
||||||
myFixture.setUp();
|
myFixture.setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
myFixture.tearDown();
|
myFixture.tearDown();
|
||||||
myFixture = null;
|
myFixture = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doTest(String testName, String hint) throws Throwable {
|
protected void doTest(String testName, String hint) throws Throwable {
|
||||||
myFixture.configureByFile(testName + ".java");
|
myFixture.configureByFile(testName + ".java");
|
||||||
|
|
||||||
myFixture.enableInspections(ComparingReferencesInspection.class);
|
myFixture.enableInspections(ComparingReferencesInspection.class);
|
||||||
List<HighlightInfo> highlightInfos = myFixture.doHighlighting();
|
List<HighlightInfo> highlightInfos = myFixture.doHighlighting();
|
||||||
Assert.assertTrue(!highlightInfos.isEmpty());
|
Assert.assertTrue(!highlightInfos.isEmpty());
|
||||||
|
|
||||||
final IntentionAction action = myFixture.findSingleIntention(hint);
|
final IntentionAction action = myFixture.findSingleIntention(hint);
|
||||||
|
|
||||||
Assert.assertNotNull(action);
|
Assert.assertNotNull(action);
|
||||||
myFixture.launchAction(action);
|
myFixture.launchAction(action);
|
||||||
myFixture.checkResultByFile(testName + ".after.java");
|
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 {
|
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 {
|
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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="PLUGIN_MODULE" version="4">
|
<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">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/source" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/source" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/testSource" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/testSource" isTestSource="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/testData" type="java-test-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/testData" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
46
conditional_operator_intention/resources/META-INF/plugin.xml
Normal file
46
conditional_operator_intention/resources/META-INF/plugin.xml
Normal file
@ -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="faux-email@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;
|
package com.intellij.codeInsight.intention;
|
||||||
|
|
||||||
@ -26,21 +25,21 @@ public class ConditionalOperatorConvertor extends PsiElementBaseIntentionAction
|
|||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getText() {
|
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
|
* 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,
|
* "auto-show" state of intentions.
|
||||||
* so the family name is the same text as the intention action list entry.
|
* It is also the directory name for the descriptions.
|
||||||
*
|
*
|
||||||
* @return the intention family name.
|
* @see com.intellij.codeInsight.intention.IntentionManager#registerIntentionAndMetaData(IntentionAction, String...)
|
||||||
* @see ConditionalOperatorConvertor#getText()
|
* @return the intention family name.
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getFamilyName() {
|
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;
|
package testPlugin;
|
||||||
|
|
||||||
import com.intellij.codeInsight.intention.IntentionAction;
|
import com.intellij.codeInsight.intention.IntentionAction;
|
||||||
@ -52,7 +54,7 @@ public class YourTest extends UsefulTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void 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,65 @@
|
|||||||
|
<!-- 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>
|
<idea-plugin>
|
||||||
|
<!-- Unique id for this plugin. Must stay constant for the life of the plugin. -->
|
||||||
<id>com.intellij.tutorials.inspection</id>
|
<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="faux-email@jetbrains.com" url="https://plugins.jetbrains.com">IntelliJ Platform SDK</vendor>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<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= Language ID
|
||||||
|
shortName= Not specified, will be computed by the underlying implementation classes.
|
||||||
|
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= FQN of inspection implementation
|
||||||
|
-->
|
||||||
|
<localInspection language="JAVA"
|
||||||
|
displayName="Demo Inspection"
|
||||||
|
groupName="Example Inspections"
|
||||||
|
groupPath="SDK"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="WARNING"
|
||||||
|
implementationClass="com.intellij.tutorials.inspection.DemoCodeInspection"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
</idea-plugin>
|
</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;
|
package com.intellij.tutorials.inspection;
|
||||||
|
|
||||||
import com.intellij.codeInspection.*;
|
import com.intellij.codeInspection.LocalInspectionTool;
|
||||||
import org.jetbrains.annotations.*;
|
import com.intellij.codeInspection.ProblemsHolder;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Anna Bulenkova
|
* @author Anna Bulenkova
|
||||||
*/
|
*/
|
||||||
public class DemoCodeInspection extends LocalInspectionTool {
|
public class DemoCodeInspection extends LocalInspectionTool {
|
||||||
@Nls
|
|
||||||
@NotNull
|
/**
|
||||||
@Override
|
* This method is overridden to provide a custom visitor
|
||||||
public String getDisplayName() {
|
* The visitor must not be recursive and must be thread-safe.
|
||||||
return "Demo Inspection";
|
*
|
||||||
}
|
* @param holder object for visitor to register problems found.
|
||||||
|
* @param isOnTheFly true if inspection was run in non-batch mode
|
||||||
|
* @return DemoInspectionVisitor.
|
||||||
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public DemoInspectionVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
public DemoInspectionVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package com.intellij.tutorials.inspection;
|
|
||||||
|
|
||||||
import com.intellij.codeInspection.InspectionToolProvider;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Anna Bulenkova
|
|
||||||
*/
|
|
||||||
public class DemoInspectionToolProvider implements InspectionToolProvider {
|
|
||||||
public Class[] getInspectionClasses() {
|
|
||||||
return new Class[]{DemoCodeInspection.class};
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
package com.intellij.tutorials.inspection;
|
||||||
|
|
||||||
import com.intellij.psi.*;
|
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>
|
|
Loading…
x
Reference in New Issue
Block a user