diff --git a/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml b/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml index 1abafbc51bc4..ad25558b9ea3 100644 --- a/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml +++ b/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml @@ -188,8 +188,9 @@ - - + + + diff --git a/python/python-psi-impl/src/com/jetbrains/python/PythonUiService.java b/python/python-psi-impl/src/com/jetbrains/python/PythonUiService.java index 7c47e77030ab..33bec9e0e6a0 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/PythonUiService.java +++ b/python/python-psi-impl/src/com/jetbrains/python/PythonUiService.java @@ -42,7 +42,11 @@ public class PythonUiService { return null; } - public void runRenameProcessor(Project project, PsiElement element, String newName, boolean searchInComments, boolean searchTextOccurrences) {} + public void runRenameProcessor(Project project, + PsiElement element, + String newName, + boolean searchInComments, + boolean searchTextOccurrences) {} public LocalQuickFix createPyChangeSignatureQuickFixForMismatchingMethods(PyFunction function, PyFunction method) { return null; @@ -66,11 +70,11 @@ public class PythonUiService { @NotNull public JComponent createEncodingsOptionsPanel(String[] possibleEncodings, - String defaultEncoding, - String[] possibleFormats, - int formatIndex, - Consumer encodingChanged, - Consumer formatIndexChanged) { + String defaultEncoding, + String[] possibleFormats, + int formatIndex, + Consumer encodingChanged, + Consumer formatIndexChanged) { return null; } @@ -90,6 +94,10 @@ public class PythonUiService { return null; } + public JComponent onePixelSplitter(boolean b, JComponent first, JComponent second) { + return null; + } + public static PythonUiService getInstance() { return ServiceManager.getService(PythonUiService.class); } @@ -106,4 +114,7 @@ public class PythonUiService { Consumer selectedItemChanged) { return null; } + + public void showPopup(Project project, List items, String title, Consumer callback) { + } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiChainedComparisonsInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyChainedComparisonsInspection.java similarity index 86% rename from python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiChainedComparisonsInspection.java rename to python/python-psi-impl/src/com/jetbrains/python/inspections/PyChainedComparisonsInspection.java index 35f7c579f798..d1878bdf3050 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiChainedComparisonsInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyChainedComparisonsInspection.java @@ -1,4 +1,18 @@ -// Copyright 2000-2020 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-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jetbrains.python.inspections; import com.intellij.codeInspection.LocalInspectionToolSession; @@ -10,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiFile; import com.jetbrains.python.PyTokenTypes; +import com.jetbrains.python.PythonUiService; import com.jetbrains.python.inspections.quickfix.ChainedComparisonsQuickFix; import com.jetbrains.python.psi.PyBinaryExpression; import com.jetbrains.python.psi.PyElementType; @@ -19,13 +34,35 @@ import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.awt.*; + import static com.jetbrains.python.psi.PyUtil.as; -public class PyPsiChainedComparisonsInspection extends PyInspection { +/** + * User: catherine + * + * Inspection to detect chained comparisons which can be simplified + * For instance, a < b and b < c --> a < b < c + */ +public class PyChainedComparisonsInspection extends PyInspection { + protected static final String ourIgnoreConstantOptionText = "Ignore statements with a constant in the middle"; private static final String INSPECTION_SHORT_NAME = "PyChainedComparisonsInspection"; public boolean ignoreConstantInTheMiddle = false; + @Nullable + @Override + public JComponent createOptionsPanel() { + JCheckBox checkBox = PythonUiService.getInstance().createInspectionCheckBox(ourIgnoreConstantOptionText, this, "ignoreConstantInTheMiddle"); + final JPanel rootPanel = new JPanel(new BorderLayout()); + if (checkBox != null) { + rootPanel.add(checkBox, + BorderLayout.PAGE_START); + } + return rootPanel; + } + @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, @@ -210,7 +247,7 @@ public class PyPsiChainedComparisonsInspection extends PyInspection { public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { final PsiFile file = descriptor.getStartElement().getContainingFile(); InspectionProfileModifiableModelKt.modifyAndCommitProjectProfile(project, it -> - ((PyPsiChainedComparisonsInspection)it.getUnwrappedTool(INSPECTION_SHORT_NAME, file)).ignoreConstantInTheMiddle = true); + ((PyChainedComparisonsInspection)it.getUnwrappedTool(INSPECTION_SHORT_NAME, file)).ignoreConstantInTheMiddle = true); } } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java index 75cecdb13648..2c349096645f 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyMandatoryEncodingInspection.java @@ -62,11 +62,12 @@ public class PyMandatoryEncodingInspection extends PyInspection { final String charsetString = PythonFileType.getCharsetFromEncodingDeclaration(node); if (charsetString == null) { - TextRange tr = new TextRange(0,0); + TextRange tr = new TextRange(0, 0); ProblemsHolder holder = getHolder(); - if (holder != null) + if (holder != null) { holder.registerProblem(node, tr, PyPsiBundle.message("INSP.mandatory.encoding.no.encoding.specified.for.file"), new AddEncodingQuickFix(myDefaultEncoding, myEncodingFormatIndex)); + } } } } @@ -119,7 +120,11 @@ public class PyMandatoryEncodingInspection extends PyInspection { @NotNull private JPanel onlyPython2Box() { final JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - panel.add(PythonUiService.getInstance().createInspectionCheckBox(PyPsiBundle.message("enable.in.python.3"), this, "myAllPythons")); + JCheckBox checkBox = + PythonUiService.getInstance().createInspectionCheckBox(PyPsiBundle.message("enable.in.python.3"), this, "myAllPythons"); + if (checkBox != null) { + panel.add(checkBox); + } return panel; } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiPep8NamingInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java similarity index 73% rename from python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiPep8NamingInspection.java rename to python/python-psi-impl/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java index 527b328e820c..e52f307b088a 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiPep8NamingInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java @@ -17,7 +17,10 @@ import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyNames; +import com.jetbrains.python.PyPsiBundle; +import com.jetbrains.python.PythonUiService; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.codeInsight.dataflow.scope.Scope; import com.jetbrains.python.psi.*; @@ -28,13 +31,19 @@ import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.awt.*; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; -public class PyPsiPep8NamingInspection extends PyInspection { +/** + * User : ktisha + */ +public class PyPep8NamingInspection extends PyInspection { + protected static final String INSPECTION_SHORT_NAME = "PyPep8NamingInspection"; private static final Pattern LOWERCASE_REGEX = Pattern.compile("[_\\p{javaLowerCase}][_\\p{javaLowerCase}0-9]*"); private static final Pattern UPPERCASE_REGEX = Pattern.compile("[_\\p{javaUpperCase}][_\\p{javaUpperCase}0-9]*"); @@ -54,6 +63,59 @@ public class PyPsiPep8NamingInspection extends PyInspection { public boolean ignoreOverriddenFunctions = true; public final List ignoredBaseClasses = Lists.newArrayList("unittest.TestCase", "unittest.case.TestCase"); + @Nullable + @Override + public JComponent createOptionsPanel() { + final JPanel rootPanel = new JPanel(new BorderLayout()); + JCheckBox checkBox = PythonUiService.getInstance() + .createInspectionCheckBox(PyPsiBundle.message("ignore.overridden.functions"), this, "ignoreOverriddenFunctions"); + if (checkBox != null) { + rootPanel.add(checkBox, BorderLayout.NORTH); + } + + JComponent classes = PythonUiService.getInstance().createListEditForm("Excluded base classes", ignoredBaseClasses); + JComponent errors = PythonUiService.getInstance().createListEditForm("Ignored errors", ignoredErrors); + + if (classes != null && errors != null) { + JComponent splitter = PythonUiService.getInstance().onePixelSplitter(false, classes, errors); + + if (splitter != null) { + rootPanel.add(splitter, BorderLayout.CENTER); + } + } + + return rootPanel; + } + + protected void addFunctionQuickFixes(ProblemsHolder holder, + PyClass containingClass, + ASTNode nameNode, + List quickFixes, TypeEvalContext typeEvalContext) { + if (holder != null && holder.isOnTheFly()) { + LocalQuickFix qf = PythonUiService.getInstance().createPyRenameElementQuickFix(nameNode.getPsi()); + if (qf != null) { + quickFixes.add(qf); + } + } + + if (containingClass != null) { + quickFixes.add(new PyPep8NamingInspection.IgnoreBaseClassQuickFix(containingClass, typeEvalContext)); + } + } + + protected LocalQuickFix[] createRenameAndIngoreErrorQuickFixes(@Nullable PsiElement node, + String errorCode) { + List fixes = Lists.newArrayList(); + if (node != null) { + LocalQuickFix qf = PythonUiService.getInstance().createPyRenameElementQuickFix(node); + if (qf != null) { + fixes.add(qf); + } + fixes.add(new IgnoreErrorFix(errorCode)); + } + return fixes.toArray(new LocalQuickFix[fixes.size()]); + } + @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, @@ -62,6 +124,68 @@ public class PyPsiPep8NamingInspection extends PyInspection { return new Visitor(holder, session); } + private static class IgnoreBaseClassQuickFix implements LocalQuickFix { + private final List myBaseClassNames; + + IgnoreBaseClassQuickFix(@NotNull PyClass baseClass, @NotNull TypeEvalContext context) { + myBaseClassNames = new ArrayList<>(); + ContainerUtil.addIfNotNull(getBaseClassNames(), baseClass.getQualifiedName()); + for (PyClass ancestor : baseClass.getAncestorClasses(context)) { + ContainerUtil.addIfNotNull(getBaseClassNames(), ancestor.getQualifiedName()); + } + } + + @NotNull + @Override + public String getFamilyName() { + return PyPsiBundle.message("INSP.pep8.ignore.method.names.for.descendants.of.class"); + } + + @Override + public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + PythonUiService.getInstance().showPopup(project, getBaseClassNames(), PyPsiBundle.message("INSP.pep8.ignore.base.class"), + (selectedValue) -> InspectionProfileModifiableModelKt + .modifyAndCommitProjectProfile(project, it -> { + PyPep8NamingInspection inspection = + (PyPep8NamingInspection)it + .getUnwrappedTool(PyPep8NamingInspection.class.getSimpleName(), + descriptor.getPsiElement()); + ContainerUtil.addIfNotNull(inspection.ignoredBaseClasses, selectedValue); + })); + } + + public List getBaseClassNames() { + return myBaseClassNames; + } + } + + protected static class IgnoreErrorFix implements LocalQuickFix { + private final String myCode; + private static final String myText = "Ignore errors like this"; + + IgnoreErrorFix(String code) { + myCode = code; + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return myText; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiFile file = descriptor.getStartElement().getContainingFile(); + InspectionProfileModifiableModelKt.modifyAndCommitProjectProfile(project, model -> { + PyPep8NamingInspection tool = (PyPep8NamingInspection)model.getUnwrappedTool(INSPECTION_SHORT_NAME, file); + if (!tool.ignoredErrors.contains(myCode)) { + tool.ignoredErrors.add(myCode); + } + }); + } + } + public class Visitor extends PyInspectionVisitor { public Visitor(ProblemsHolder holder, LocalInspectionToolSession session) { super(holder, session); @@ -175,7 +299,7 @@ public class PyPsiPep8NamingInspection extends PyInspection { private boolean isContextManager(PyClass node) { final String[] contextManagerFunctionNames = {PyNames.ENTER, PyNames.EXIT}; - for (String name: contextManagerFunctionNames) { + for (String name : contextManagerFunctionNames) { if (node.findMethodByName(name, false, myTypeEvalContext) == null) { return false; } @@ -217,44 +341,4 @@ public class PyPsiPep8NamingInspection extends PyInspection { } } } - - protected LocalQuickFix[] createRenameAndIngoreErrorQuickFixes(@Nullable PsiElement node, - String errorCode) { - //TODO: extract PyRenameElementQuickFix - return new LocalQuickFix[]{new IgnoreErrorFix(errorCode)}; - } - - protected static class IgnoreErrorFix implements LocalQuickFix { - private final String myCode; - private static final String myText = "Ignore errors like this"; - - IgnoreErrorFix(String code) { - myCode = code; - } - - @Nls - @NotNull - @Override - public String getFamilyName() { - return myText; - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - final PsiFile file = descriptor.getStartElement().getContainingFile(); - InspectionProfileModifiableModelKt.modifyAndCommitProjectProfile(project, model -> { - PyPsiPep8NamingInspection tool = (PyPsiPep8NamingInspection)model.getUnwrappedTool(INSPECTION_SHORT_NAME, file); - if (!tool.ignoredErrors.contains(myCode)) { - tool.ignoredErrors.add(myCode); - } - }); - } - } - - - protected void addFunctionQuickFixes(ProblemsHolder holder, - PyClass containingClass, - ASTNode nameNode, - List quickFixes, TypeEvalContext typeEvalContext) { - } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiShadowingBuiltinsInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiShadowingBuiltinsInspection.java deleted file mode 100644 index c6e8fb4d85ff..000000000000 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPsiShadowingBuiltinsInspection.java +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2000-2020 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.jetbrains.python.inspections; - -import com.google.common.collect.ImmutableSet; -import com.intellij.codeInspection.LocalInspectionToolSession; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemHighlightType; -import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiNameIdentifierOwner; -import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; -import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; -import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.PyBuiltinCache; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; - -public class PyPsiShadowingBuiltinsInspection extends PyInspection { - // Persistent settings - public List ignoredNames = new ArrayList<>(); - - @NotNull - @Override - public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, - boolean isOnTheFly, - @NotNull LocalInspectionToolSession session) { - return new Visitor(holder, session, ignoredNames); - } - - @NotNull - protected LocalQuickFix[] createQuickFixes(String name, PsiElement problemElement) { - return LocalQuickFix.EMPTY_ARRAY; - } - - private class Visitor extends PyInspectionVisitor { - private final Set myIgnoredNames; - - Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session, @NotNull Collection ignoredNames) { - super(holder, session); - myIgnoredNames = ImmutableSet.copyOf(ignoredNames); - } - - @Override - public void visitPyClass(@NotNull PyClass node) { - processElement(node); - } - - @Override - public void visitPyFunction(@NotNull PyFunction node) { - processElement(node); - } - - @Override - public void visitPyNamedParameter(@NotNull PyNamedParameter node) { - processElement(node); - } - - @Override - public void visitPyTargetExpression(@NotNull PyTargetExpression node) { - if (!node.isQualified()) { - processElement(node); - } - } - - private void processElement(@NotNull PsiNameIdentifierOwner element) { - final ScopeOwner owner = ScopeUtil.getScopeOwner(element); - if (owner instanceof PyClass) { - return; - } - final String name = element.getName(); - if (name != null && !myIgnoredNames.contains(name)) { - final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element); - final PsiElement builtin = builtinCache.getByName(name); - if (builtin != null && !PyUtil.inSameFile(builtin, element)) { - final PsiElement identifier = element.getNameIdentifier(); - final PsiElement problemElement = identifier != null ? identifier : element; - registerProblem(problemElement, String.format("Shadows built-in name '%s'", name), - ProblemHighlightType.WEAK_WARNING, null, createQuickFixes(name, problemElement)); - } - } - } - } -} diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java index ccd3f91a44ca..0c393831251b 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java @@ -15,29 +15,41 @@ */ package com.jetbrains.python.inspections; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.intellij.codeInsight.intention.LowPriorityAction; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.InspectionProfileModifiableModelKt; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.PsiNameIdentifierOwner; import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.PythonUiService; +import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; +import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; +import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyBuiltinCache; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Set; /** * Warns about shadowing built-in names. * * @author vlan */ -public class PyShadowingBuiltinsInspection extends PyPsiShadowingBuiltinsInspection { +public class PyShadowingBuiltinsInspection extends PyInspection { + + // Persistent settings + public List ignoredNames = new ArrayList<>(); @NotNull - @Override protected LocalQuickFix[] createQuickFixes(String name, PsiElement problemElement) { List fixes = Lists.newArrayList(); LocalQuickFix qf = PythonUiService.getInstance().createPyRenameElementQuickFix(problemElement); @@ -53,6 +65,14 @@ public class PyShadowingBuiltinsInspection extends PyPsiShadowingBuiltinsInspect return PythonUiService.getInstance().createListEditForm("Ignore built-ins", ignoredNames); } + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, + boolean isOnTheFly, + @NotNull LocalInspectionToolSession session) { + return new Visitor(holder, session, ignoredNames); + } + private static class PyIgnoreBuiltinQuickFix implements LocalQuickFix, LowPriorityAction { @NotNull private final String myName; @@ -93,5 +113,54 @@ public class PyShadowingBuiltinsInspection extends PyPsiShadowingBuiltinsInspect } } } + + private class Visitor extends PyInspectionVisitor { + private final Set myIgnoredNames; + + Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session, @NotNull Collection ignoredNames) { + super(holder, session); + myIgnoredNames = ImmutableSet.copyOf(ignoredNames); + } + + @Override + public void visitPyClass(@NotNull PyClass node) { + processElement(node); + } + + @Override + public void visitPyFunction(@NotNull PyFunction node) { + processElement(node); + } + + @Override + public void visitPyNamedParameter(@NotNull PyNamedParameter node) { + processElement(node); + } + + @Override + public void visitPyTargetExpression(@NotNull PyTargetExpression node) { + if (!node.isQualified()) { + processElement(node); + } + } + + private void processElement(@NotNull PsiNameIdentifierOwner element) { + final ScopeOwner owner = ScopeUtil.getScopeOwner(element); + if (owner instanceof PyClass) { + return; + } + final String name = element.getName(); + if (name != null && !myIgnoredNames.contains(name)) { + final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element); + final PsiElement builtin = builtinCache.getByName(name); + if (builtin != null && !PyUtil.inSameFile(builtin, element)) { + final PsiElement identifier = element.getNameIdentifier(); + final PsiElement problemElement = identifier != null ? identifier : element; + registerProblem(problemElement, String.format("Shadows built-in name '%s'", name), + ProblemHighlightType.WEAK_WARNING, null, createQuickFixes(name, problemElement)); + } + } + } + } } diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml index a37f189f33f5..60e2b21b276e 100644 --- a/python/src/META-INF/python-core-common.xml +++ b/python/src/META-INF/python-core-common.xml @@ -328,9 +328,6 @@ - - - diff --git a/python/src/com/jetbrains/python/PythonUiServiceImpl.java b/python/src/com/jetbrains/python/PythonUiServiceImpl.java index 18c04d7f9b2f..fef4ef570689 100644 --- a/python/src/com/jetbrains/python/PythonUiServiceImpl.java +++ b/python/src/com/jetbrains/python/PythonUiServiceImpl.java @@ -3,9 +3,12 @@ package com.jetbrains.python; import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ex.InspectionProfileModifiableModelKt; import com.intellij.codeInspection.ui.ListEditForm; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; +import com.intellij.ide.DataManager; import com.intellij.ide.util.ElementsChooser; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; @@ -13,15 +16,18 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.refactoring.rename.RenameProcessor; +import com.intellij.ui.OnePixelSplitter; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.CheckBox; import com.jetbrains.python.codeInsight.intentions.PyAnnotateTypesIntention; import com.jetbrains.python.inspections.PyMandatoryEncodingInspection; +import com.jetbrains.python.inspections.PyPep8NamingInspection; import com.jetbrains.python.inspections.quickfix.PyChangeSignatureQuickFix; import com.jetbrains.python.inspections.quickfix.PyImplementMethodsQuickFix; import com.jetbrains.python.inspections.quickfix.PyRenameElementQuickFix; @@ -231,4 +237,24 @@ public class PythonUiServiceImpl extends PythonUiService { root.add(option, BorderLayout.PAGE_START); return root; } + + @Override + public JComponent onePixelSplitter(boolean vertical, JComponent first, JComponent second) { + final OnePixelSplitter splitter = new OnePixelSplitter(vertical); + + splitter.setFirstComponent(first); + splitter.setSecondComponent(second); + + return splitter; + } + + public void showPopup(Project project, List items, String title, Consumer callback) { + DataManager.getInstance().getDataContextFromFocus().doWhenDone((Consumer)dataContext -> + JBPopupFactory.getInstance().createPopupChooserBuilder(items) + .setTitle(title) + .setItemChosenCallback(callback) + .setNamerForFiltering(o -> o) + .createPopup() + .showInBestPositionFor(dataContext)); + } } diff --git a/python/src/com/jetbrains/python/inspections/PyChainedComparisonsInspection.java b/python/src/com/jetbrains/python/inspections/PyChainedComparisonsInspection.java deleted file mode 100644 index 56c05dc661d2..000000000000 --- a/python/src/com/jetbrains/python/inspections/PyChainedComparisonsInspection.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jetbrains.python.inspections; - -import com.intellij.util.ui.CheckBox; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; - -/** - * User: catherine - * - * Inspection to detect chained comparisons which can be simplified - * For instance, a < b and b < c --> a < b < c - */ -public class PyChainedComparisonsInspection extends PyPsiChainedComparisonsInspection { - - @Nullable - @Override - public JComponent createOptionsPanel() { - final JPanel rootPanel = new JPanel(new BorderLayout()); - rootPanel.add(new CheckBox(ourIgnoreConstantOptionText, this, "ignoreConstantInTheMiddle"), - BorderLayout.PAGE_START); - - return rootPanel; - } -} diff --git a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java deleted file mode 100644 index 36bedad4abce..000000000000 --- a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2000-2020 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.jetbrains.python.inspections; - -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.codeInspection.ex.InspectionProfileModifiableModelKt; -import com.intellij.codeInspection.ui.ListEditForm; -import com.intellij.ide.DataManager; -import com.intellij.lang.ASTNode; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.psi.PsiElement; -import com.intellij.ui.OnePixelSplitter; -import com.intellij.util.Consumer; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.CheckBox; -import com.jetbrains.python.PyPsiBundle; -import com.jetbrains.python.inspections.quickfix.PyRenameElementQuickFix; -import com.jetbrains.python.psi.PyClass; -import com.jetbrains.python.psi.types.TypeEvalContext; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -/** - * User : ktisha - */ -public class PyPep8NamingInspection extends PyPsiPep8NamingInspection { - - @Nullable - @Override - public JComponent createOptionsPanel() { - final JPanel rootPanel = new JPanel(new BorderLayout()); - rootPanel.add(new CheckBox(PyPsiBundle.message("ignore.overridden.functions"), this, "ignoreOverriddenFunctions"), BorderLayout.NORTH); - - final OnePixelSplitter splitter = new OnePixelSplitter(false); - splitter.setFirstComponent(new ListEditForm("Excluded base classes", ignoredBaseClasses).getContentPanel()); - splitter.setSecondComponent(new ListEditForm("Ignored errors", ignoredErrors).getContentPanel()); - rootPanel.add(splitter, BorderLayout.CENTER); - - return rootPanel; - } - - @Override - protected void addFunctionQuickFixes(ProblemsHolder holder, - PyClass containingClass, - ASTNode nameNode, - List quickFixes, TypeEvalContext typeEvalContext) { - if (holder != null && holder.isOnTheFly()) { - quickFixes.add(new PyRenameElementQuickFix(nameNode.getPsi())); - } - - if (containingClass != null) { - quickFixes.add(new PyPep8NamingInspection.IgnoreBaseClassQuickFix(containingClass, typeEvalContext)); - } - } - - protected LocalQuickFix[] createRenameAndIngoreErrorQuickFixes(@Nullable PsiElement node, - String errorCode) { - return new LocalQuickFix[]{new PyRenameElementQuickFix(node), new IgnoreErrorFix(errorCode)}; - } - - private static class IgnoreBaseClassQuickFix implements LocalQuickFix { - private final List myBaseClassNames; - - IgnoreBaseClassQuickFix(@NotNull PyClass baseClass, @NotNull TypeEvalContext context) { - myBaseClassNames = new ArrayList<>(); - ContainerUtil.addIfNotNull(getBaseClassNames(), baseClass.getQualifiedName()); - for (PyClass ancestor : baseClass.getAncestorClasses(context)) { - ContainerUtil.addIfNotNull(getBaseClassNames(), ancestor.getQualifiedName()); - } - } - - @NotNull - @Override - public String getFamilyName() { - return PyPsiBundle.message("INSP.pep8.ignore.method.names.for.descendants.of.class"); - } - - @Override - public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { - DataManager.getInstance().getDataContextFromFocus().doWhenDone((Consumer)dataContext -> - JBPopupFactory.getInstance().createPopupChooserBuilder(getBaseClassNames()) - .setTitle(PyPsiBundle.message("INSP.pep8.ignore.base.class")) - .setItemChosenCallback((selectedValue) -> InspectionProfileModifiableModelKt.modifyAndCommitProjectProfile(project, it -> { - PyPep8NamingInspection inspection = - (PyPep8NamingInspection)it.getUnwrappedTool(PyPep8NamingInspection.class.getSimpleName(), descriptor.getPsiElement()); - ContainerUtil.addIfNotNull(inspection.ignoredBaseClasses, selectedValue); - })) - .setNamerForFiltering(o -> o) - .createPopup() - .showInBestPositionFor(dataContext)); - } - - public List getBaseClassNames() { - return myBaseClassNames; - } - } -}