mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
UnsupportedFeatures and PyCompatiblityInspection refactored.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package com.jetbrains.python.actions;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.psi.PyElementGenerator;
|
||||
import com.jetbrains.python.psi.PyNumericLiteralExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* Author: Alexey.Ivanov
|
||||
* Date: 06.03.2010
|
||||
* Time: 16:50:53
|
||||
*/
|
||||
public class RemoveTrailingLQuickFix implements LocalQuickFix {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return PyBundle.message("INTN.remove.trailing.l");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return PyBundle.message("INTN.Family.migration.to.python3");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement numericLiteralExpression = descriptor.getPsiElement();
|
||||
if (numericLiteralExpression instanceof PyNumericLiteralExpression) {
|
||||
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
|
||||
String text = numericLiteralExpression.getText();
|
||||
numericLiteralExpression.replace(elementGenerator.createExpressionFromText(text.substring(0, text.length() - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,14 +34,11 @@ public class ReplaceBuiltinsQuickFix implements LocalQuickFix {
|
||||
for (PyImportElement importElement : ((PyImportStatement)importStatement).getImportElements()) {
|
||||
PyReferenceExpression importReference = importElement.getImportReference();
|
||||
if (importReference != null) {
|
||||
if (LanguageLevel.forFile(importStatement.getContainingFile().getVirtualFile()).isPy3K()) {
|
||||
if ("__builtin__".equals(importReference.getName())) {
|
||||
importReference.replace(elementGenerator.createFromText(LanguageLevel.getDefault(), PyReferenceExpression.class, "builtins"));
|
||||
}
|
||||
} else {
|
||||
if ("builtins".equals(importReference.getName())) {
|
||||
importReference.replace(elementGenerator.createFromText(LanguageLevel.getDefault(), PyReferenceExpression.class, "__builtin__"));
|
||||
}
|
||||
if ("__builtin__".equals(importReference.getName())) {
|
||||
importReference.replace(elementGenerator.createFromText(LanguageLevel.getDefault(), PyReferenceExpression.class, "builtins"));
|
||||
}
|
||||
if ("builtins".equals(importReference.getName())) {
|
||||
importReference.replace(elementGenerator.createFromText(LanguageLevel.getDefault(), PyReferenceExpression.class, "__builtin__"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.jetbrains.python.codeInsight.intentions;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.psi.PyElementGenerator;
|
||||
import com.jetbrains.python.psi.PyNumericLiteralExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* Author: Alexey.Ivanov
|
||||
* Date: 06.03.2010
|
||||
* Time: 16:50:53
|
||||
*/
|
||||
public class RemoveTrailingLIntention implements IntentionAction {
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return PyBundle.message("INTN.remove.trailing.l");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return PyBundle.message("INTN.Family.migration.to.python3");
|
||||
}
|
||||
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
PyNumericLiteralExpression numericLiteralExpression =
|
||||
PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyNumericLiteralExpression.class);
|
||||
if (numericLiteralExpression == null) {
|
||||
return;
|
||||
}
|
||||
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
|
||||
String text = numericLiteralExpression.getText();
|
||||
numericLiteralExpression.replace(elementGenerator.createExpressionFromText(text.substring(0, text.length() - 1)));
|
||||
}
|
||||
|
||||
public boolean startInWriteAction() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,17 @@
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.actions.*;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import com.jetbrains.python.validation.CompatibilityVisitor;
|
||||
import com.jetbrains.python.validation.UnsupportedFeaturesUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -22,8 +19,6 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* User: catherine
|
||||
@@ -111,521 +106,23 @@ public class PyCompatibilityInspection extends PyInspection {
|
||||
return new Visitor(holder, myVersionsToProcess);
|
||||
}
|
||||
|
||||
|
||||
private static class Visitor extends PyInspectionVisitor {
|
||||
List<LanguageLevel> myVersionsToProcess;
|
||||
private String myCommonMessage = "Python versions ";
|
||||
|
||||
public Visitor(final ProblemsHolder holder, List<LanguageLevel> versionsToProcess) {
|
||||
super(holder);
|
||||
myVersionsToProcess = versionsToProcess;
|
||||
private static class Visitor extends CompatibilityVisitor {
|
||||
private final ProblemsHolder myHolder;
|
||||
public Visitor(ProblemsHolder holder, List<LanguageLevel> versionsToProcess) {
|
||||
super(versionsToProcess);
|
||||
myHolder = holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyDictCompExpression(PyDictCompExpression node) {
|
||||
super.visitPyDictCompExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support dictionary comprehensions");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new ConvertDictCompQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPySetLiteralExpression(PySetLiteralExpression node) {
|
||||
super.visitPySetLiteralExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support set literal expressions");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new ConvertSetLiteralQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPySetCompExpression(PySetCompExpression node) {
|
||||
super.visitPySetCompExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support set comprehensions");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyExceptBlock(PyExceptPart node) {
|
||||
super.visitPyExceptBlock(node);
|
||||
PyExpression exceptClass = node.getExceptClass();
|
||||
if (exceptClass != null) {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24) || myVersionsToProcess.contains(LanguageLevel.PYTHON25)) {
|
||||
PsiElement element = exceptClass.getNextSibling();
|
||||
while (element instanceof PsiWhiteSpace) {
|
||||
element = element.getNextSibling();
|
||||
}
|
||||
if (element != null && "as".equals(element.getText())) {
|
||||
registerProblem(node, myCommonMessage + "2.4 2.5 " + " do not support this syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (languageLevel.isPy3K()) {
|
||||
PsiElement element = exceptClass.getNextSibling();
|
||||
while (element instanceof PsiWhiteSpace) {
|
||||
element = element.getNextSibling();
|
||||
}
|
||||
if (element != null && ",".equals(element.getText())) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
message.append(" do not this syntax.");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new ReplaceExceptPartQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyImportStatement(PyImportStatement node) {
|
||||
super.visitPyImportStatement(node);
|
||||
PyImportElement[] importElements = node.getImportElements();
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
for (PyImportElement importElement : importElements) {
|
||||
final PyQualifiedName qName = importElement.getImportedQName();
|
||||
if (qName != null) {
|
||||
if (!languageLevel.isPy3K()) {
|
||||
if (qName.matches("builtins")) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
message.append(" do not have module builtins.");
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (qName.matches("__builtin__")) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
message.append(" do not have module __builtin__.");
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new ReplaceBuiltinsQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyStarExpression(PyStarExpression node) {
|
||||
super.visitPyStarExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.isPy3K()) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support this syntax. Starred expressions are not allowed as assignment targets in Python 2");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyBinaryExpression(PyBinaryExpression node) {
|
||||
super.visitPyBinaryExpression(node);
|
||||
boolean hasProblem = false;
|
||||
if (node.isOperator("<>")) {
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel level = myVersionsToProcess.get(i);
|
||||
if (level.isPy3K()) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(level.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support <>, use != instead.");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new ReplaceNotEqOperatorQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyNumericLiteralExpression(final PyNumericLiteralExpression node) {
|
||||
super.visitPyNumericLiteralExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
|
||||
if (languageLevel.isPy3K()) {
|
||||
if (!node.isIntegerLiteral()) {
|
||||
continue;
|
||||
}
|
||||
final String text = node.getText();
|
||||
if (text.endsWith("l") || text.endsWith("L")) {
|
||||
message.append(languageLevel.toString()).append(" ");
|
||||
hasProblem = true;
|
||||
}
|
||||
if (text.length() > 1 && text.charAt(0) == '0') {
|
||||
final char c = Character.toLowerCase(text.charAt(1));
|
||||
if (c != 'o' && c != 'b' && c != 'x') {
|
||||
boolean isNull = true;
|
||||
for (char a : text.toCharArray()) {
|
||||
if ( a != '0') {
|
||||
isNull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isNull) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
message.append(" do not support a trailing \'l\' or \'L\'.");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new ReplaceOctalNumericLiteralQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyStringLiteralExpression(final PyStringLiteralExpression node) {
|
||||
super.visitPyStringLiteralExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
|
||||
if (languageLevel.isPy3K()) {
|
||||
final String text = node.getText();
|
||||
if (text.startsWith("u") || text.startsWith("U")) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
message.append(" do not a leading \'u\' or \'U\'.");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new RemoveLeadingUQuickFix());
|
||||
}
|
||||
|
||||
public void visitPyListCompExpression(final PyListCompExpression node) {
|
||||
super.visitPyListCompExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
boolean tmp = UnsupportedFeaturesUtil.visitPyListCompExpression(node, languageLevel);
|
||||
if (tmp) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel);
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support this syntax in list comprehensions.");
|
||||
for (ComprhForComponent forComponent : node.getForComponents()) {
|
||||
final PyExpression iteratedList = forComponent.getIteratedList();
|
||||
if (hasProblem)
|
||||
registerProblem(iteratedList, message.toString(), new ReplaceListComprehensionsQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyRaiseStatement(PyRaiseStatement node) {
|
||||
super.visitPyRaiseStatement(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
boolean hasNoArgs = UnsupportedFeaturesUtil.raiseHasNoArgs(node, languageLevel);
|
||||
if (hasNoArgs) {
|
||||
message.append(languageLevel).append(" ");
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support this syntax. Raise with no arguments can only be used in an except block");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString());
|
||||
|
||||
hasProblem = false;
|
||||
message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
boolean hasTwoArgs = UnsupportedFeaturesUtil.raiseHasMoreThenOneArg(node, languageLevel);
|
||||
if (hasTwoArgs) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel);
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support this syntax.");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new ReplaceRaiseStatementQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyReprExpression(PyReprExpression node) {
|
||||
super.visitPyReprExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (languageLevel.isPy3K()) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel);
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not support backquotes, use repr() instead");
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString(), new ReplaceBackquoteExpressionQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyWithStatement(PyWithStatement node) {
|
||||
super.visitPyWithStatement(node);
|
||||
Set<PyWithItem> problemItems = new HashSet<PyWithItem>();
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (languageLevel == LanguageLevel.PYTHON24) {
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax.");
|
||||
}
|
||||
else if (!languageLevel.supportsSetLiterals()) {
|
||||
final PyWithItem[] items = node.getWithItems();
|
||||
if (items.length > 1) {
|
||||
for (int j = 1; j < items.length; j++) {
|
||||
if (!problemItems.isEmpty())
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
problemItems.add(items [j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
message.append(" do not support multiple context managers");
|
||||
for (PyWithItem item : problemItems) {
|
||||
registerProblem(item, message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyCallExpression(PyCallExpression node) {
|
||||
super.visitPyCallExpression(node);
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.isPy3K()) {
|
||||
final PsiElement firstChild = node.getFirstChild();
|
||||
if (firstChild != null) {
|
||||
final String name = firstChild.getText();
|
||||
if (PyNames.SUPER.equals(name)) {
|
||||
final PyArgumentList argumentList = node.getArgumentList();
|
||||
if (argumentList != null && argumentList.getArguments().length == 0) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString());
|
||||
|
||||
hasProblem = false;
|
||||
message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
|
||||
PyExpression callee = node.getCallee();
|
||||
assert callee != null;
|
||||
PsiReference reference = callee.getReference();
|
||||
if (reference != null) {
|
||||
PsiElement resolved = reference.resolve();
|
||||
ProjectFileIndex ind = ProjectRootManager.getInstance(callee.getProject()).getFileIndex();
|
||||
if (resolved != null) {
|
||||
PsiFile file = resolved.getContainingFile();
|
||||
if (file != null && ind.isInLibraryClasses(file.getVirtualFile())) {
|
||||
final String name = callee.getText();
|
||||
if (!name.equals("print") && UnsupportedFeaturesUtil.BUILTINS.get(languageLevel).contains(name)) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
hasProblem = true;
|
||||
message.append(languageLevel.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasProblem) {
|
||||
message.append(" have no method ").append(node.getCallee().getText());
|
||||
registerProblem(node, message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyClass(PyClass node) { //PY-2719
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24)) {
|
||||
PyArgumentList list = node.getSuperClassExpressionList();
|
||||
if (list != null && list.getArguments().length == 0)
|
||||
registerProblem(list, "Python version 2.4 does not support this syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyPrintStatement(PyPrintStatement node) {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON30) || myVersionsToProcess.contains(LanguageLevel.PYTHON31)) {
|
||||
boolean hasProblem = false;
|
||||
PsiElement[] arguments = node.getChildren();
|
||||
for (PsiElement element : arguments) {
|
||||
if (!((element instanceof PyParenthesizedExpression) || (element instanceof PyTupleExpression))) {
|
||||
hasProblem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasProblem || arguments.length == 0)
|
||||
registerProblem(node, "Python versions >= 3.0 do not support this syntax. The print statement has been replaced with a print() function",
|
||||
new CompatibilityPrintCallQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyImportElement(PyImportElement node) {
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (UnsupportedFeaturesUtil.MODULES.get(languageLevel).contains(node.getText())) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not have module ").append(node.getText());
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyFromImportStatement(PyFromImportStatement node) {
|
||||
boolean hasProblem = false;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
PyReferenceExpression importSource = node.getImportSource();
|
||||
if (importSource != null) {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24)) { //PY-2793
|
||||
PsiElement prev = importSource.getPrevSibling();
|
||||
if (prev != null && prev.getNode().getElementType() == PyTokenTypes.DOT)
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax.");
|
||||
}
|
||||
|
||||
String name = importSource.getText();
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (UnsupportedFeaturesUtil.MODULES.get(languageLevel).contains(name)) {
|
||||
if (hasProblem)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
hasProblem = true;
|
||||
}
|
||||
}
|
||||
message.append(" do not have module ").append(name);
|
||||
if (hasProblem)
|
||||
registerProblem(node, message.toString());
|
||||
}
|
||||
else {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24))
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyAssignmentStatement(PyAssignmentStatement node) {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24)) {
|
||||
PyExpression assignedValue = node.getAssignedValue();
|
||||
if (assignedValue instanceof PyConditionalExpression) // PY-2792
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax.");
|
||||
|
||||
Stack<PsiElement> st = new Stack<PsiElement>(); // PY-2796
|
||||
if (assignedValue != null)
|
||||
st.push(assignedValue);
|
||||
while (!st.isEmpty()) {
|
||||
PsiElement el = st.pop();
|
||||
if (el instanceof PyYieldExpression)
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax. " +
|
||||
"In Python <= 2.4, yield was a statement; it didn't return any value.");
|
||||
else {
|
||||
for (PsiElement e : el.getChildren())
|
||||
st.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyTryExceptStatement(PyTryExceptStatement node) { // PY-2795
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24)) {
|
||||
PyExceptPart[] excepts = node.getExceptParts();
|
||||
PyFinallyPart finallyPart = node.getFinallyPart();
|
||||
if (excepts.length != 0 && finallyPart != null)
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax. You could use a finally block to ensure " +
|
||||
"that code is always executed, or one or more except blocks to catch specific exceptions.");
|
||||
protected final void registerProblem(@Nullable final PsiElement element,
|
||||
@NotNull final String message,
|
||||
final LocalQuickFix quickFix, boolean asError){
|
||||
if (element == null || element.getTextLength() == 0){
|
||||
return;
|
||||
}
|
||||
if (quickFix != null)
|
||||
myHolder.registerProblem(element, message, quickFix);
|
||||
else
|
||||
myHolder.registerProblem(element, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
package com.jetbrains.python.validation;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.actions.*;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* User : catherine
|
||||
*/
|
||||
public abstract class CompatibilityVisitor extends PyAnnotator {
|
||||
protected List<LanguageLevel> myVersionsToProcess;
|
||||
private String myCommonMessage = "Python version ";
|
||||
|
||||
public CompatibilityVisitor(List<LanguageLevel> versionsToProcess) {
|
||||
myVersionsToProcess = versionsToProcess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyDictCompExpression(PyDictCompExpression node) {
|
||||
super.visitPyDictCompExpression(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support dictionary comprehensions", len, node, new ConvertDictCompQuickFix(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPySetLiteralExpression(PySetLiteralExpression node) {
|
||||
super.visitPySetLiteralExpression(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support set literal expressions", len, node, new ConvertSetLiteralQuickFix(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPySetCompExpression(PySetCompExpression node) {
|
||||
super.visitPySetCompExpression(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support set comprehensions", len, node, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyExceptBlock(PyExceptPart node) {
|
||||
super.visitPyExceptBlock(node);
|
||||
PyExpression exceptClass = node.getExceptClass();
|
||||
if (exceptClass != null) {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24) || myVersionsToProcess.contains(LanguageLevel.PYTHON25)) {
|
||||
PsiElement element = exceptClass.getNextSibling();
|
||||
while (element instanceof PsiWhiteSpace) {
|
||||
element = element.getNextSibling();
|
||||
}
|
||||
if (element != null && "as".equals(element.getText())) {
|
||||
registerProblem(node, myCommonMessage + "2.4, 2.5 do not support this syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (languageLevel.isPy3K()) {
|
||||
PsiElement element = exceptClass.getNextSibling();
|
||||
while (element instanceof PsiWhiteSpace) {
|
||||
element = element.getNextSibling();
|
||||
}
|
||||
if (element != null && ",".equals(element.getText())) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support this syntax.", len, node, new ReplaceExceptPartQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyImportStatement(PyImportStatement node) {
|
||||
super.visitPyImportStatement(node);
|
||||
PyImportElement[] importElements = node.getImportElements();
|
||||
int len = 0;
|
||||
String moduleName = "";
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
for (PyImportElement importElement : importElements) {
|
||||
final PyQualifiedName qName = importElement.getImportedQName();
|
||||
if (qName != null) {
|
||||
if (!languageLevel.isPy3K()) {
|
||||
if (qName.matches("builtins")) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
moduleName = "builtins";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (qName.matches("__builtin__")) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
moduleName = "__builtin__";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not have module " + moduleName, len, node, new ReplaceBuiltinsQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyStarExpression(PyStarExpression node) {
|
||||
super.visitPyStarExpression(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.isPy3K()) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support this syntax. Starred expressions are not allowed as assignment targets in Python 2",
|
||||
len, node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyBinaryExpression(PyBinaryExpression node) {
|
||||
super.visitPyBinaryExpression(node);
|
||||
int len = 0;
|
||||
if (node.isOperator("<>")) {
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (languageLevel.isPy3K()) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support <>, use != instead.", len, node, new ReplaceNotEqOperatorQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyNumericLiteralExpression(final PyNumericLiteralExpression node) {
|
||||
super.visitPyNumericLiteralExpression(node);
|
||||
int len = 0;
|
||||
LocalQuickFix quickFix = null;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
String suffix = "";
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (languageLevel.isPy3K()) {
|
||||
if (!node.isIntegerLiteral()) {
|
||||
continue;
|
||||
}
|
||||
final String text = node.getText();
|
||||
if (text.endsWith("l") || text.endsWith("L")) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
suffix = " not support a trailing \'l\' or \'L\'.";
|
||||
quickFix = new RemoveTrailingLQuickFix();
|
||||
}
|
||||
if (text.length() > 1 && text.charAt(0) == '0') {
|
||||
final char c = Character.toLowerCase(text.charAt(1));
|
||||
if (c != 'o' && c != 'b' && c != 'x') {
|
||||
boolean isNull = true;
|
||||
for (char a : text.toCharArray()) {
|
||||
if ( a != '0') {
|
||||
isNull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isNull) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
quickFix = new ReplaceOctalNumericLiteralQuickFix();
|
||||
suffix = " not support this syntax. It requires '0o' prefix for octal literals";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, suffix, len, node, quickFix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyStringLiteralExpression(final PyStringLiteralExpression node) {
|
||||
super.visitPyStringLiteralExpression(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
|
||||
if (languageLevel.isPy3K()) {
|
||||
final String text = node.getText();
|
||||
if (text.startsWith("u") || text.startsWith("U")) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support a leading \'u\' or \'U\'.", len, node, new RemoveLeadingUQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyListCompExpression(final PyListCompExpression node) {
|
||||
super.visitPyListCompExpression(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
boolean tmp = UnsupportedFeaturesUtil.visitPyListCompExpression(node, languageLevel);
|
||||
if (tmp) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
for (ComprhForComponent forComponent : node.getForComponents()) {
|
||||
final PyExpression iteratedList = forComponent.getIteratedList();
|
||||
commonRegisterProblem(message, " not support this syntax in list comprehensions.", len, iteratedList,
|
||||
new ReplaceListComprehensionsQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyRaiseStatement(PyRaiseStatement node) {
|
||||
super.visitPyRaiseStatement(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
boolean hasNoArgs = UnsupportedFeaturesUtil.raiseHasNoArgs(node, languageLevel);
|
||||
if (hasNoArgs) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support this syntax. Raise with no arguments can only be used in an except block",
|
||||
len, node, null);
|
||||
|
||||
len = 0;
|
||||
message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
boolean hasTwoArgs = UnsupportedFeaturesUtil.raiseHasMoreThenOneArg(node, languageLevel);
|
||||
if (hasTwoArgs) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support this syntax.",
|
||||
len, node, new ReplaceRaiseStatementQuickFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyReprExpression(PyReprExpression node) {
|
||||
super.visitPyReprExpression(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (languageLevel.isPy3K()) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support backquotes, use repr() instead",
|
||||
len, node, new ReplaceBackquoteExpressionQuickFix());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitPyWithStatement(PyWithStatement node) {
|
||||
super.visitPyWithStatement(node);
|
||||
Set<PyWithItem> problemItems = new HashSet<PyWithItem>();
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (languageLevel == LanguageLevel.PYTHON24) {
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax.");
|
||||
}
|
||||
else if (!languageLevel.supportsSetLiterals()) {
|
||||
final PyWithItem[] items = node.getWithItems();
|
||||
if (items.length > 1) {
|
||||
for (int j = 1; j < items.length; j++) {
|
||||
if (!problemItems.isEmpty())
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
problemItems.add(items [j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
message.append(" do not support multiple context managers");
|
||||
for (PyWithItem item : problemItems) {
|
||||
registerProblem(item, message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyClass(PyClass node) { //PY-2719
|
||||
super.visitPyClass(node);
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24)) {
|
||||
PyArgumentList list = node.getSuperClassExpressionList();
|
||||
if (list != null && list.getArguments().length == 0)
|
||||
registerProblem(list, "Python version 2.4 does not support this syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyPrintStatement(PyPrintStatement node) {
|
||||
super.visitPyPrintStatement(node);
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON30) || myVersionsToProcess.contains(LanguageLevel.PYTHON31)) {
|
||||
boolean hasProblem = false;
|
||||
PsiElement[] arguments = node.getChildren();
|
||||
for (PsiElement element : arguments) {
|
||||
if (!((element instanceof PyParenthesizedExpression) || (element instanceof PyTupleExpression))) {
|
||||
hasProblem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasProblem || arguments.length == 0)
|
||||
registerProblem(node, "Python version >= 3.0 do not support this syntax. The print statement has been replaced with a print() function",
|
||||
new CompatibilityPrintCallQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyFromImportStatement(PyFromImportStatement node) {
|
||||
super.visitPyFromImportStatement(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
PyReferenceExpression importSource = node.getImportSource();
|
||||
if (importSource != null) {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24)) { //PY-2793
|
||||
PsiElement prev = importSource.getPrevSibling();
|
||||
if (prev != null && prev.getNode().getElementType() == PyTokenTypes.DOT)
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax.");
|
||||
}
|
||||
|
||||
String name = importSource.getText();
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (UnsupportedFeaturesUtil.MODULES.get(languageLevel).contains(name)) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not have module " + name,
|
||||
len, node, null, false);
|
||||
}
|
||||
else {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24))
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyAssignmentStatement(PyAssignmentStatement node) {
|
||||
super.visitPyAssignmentStatement(node);
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24)) {
|
||||
PyExpression assignedValue = node.getAssignedValue();
|
||||
if (assignedValue instanceof PyConditionalExpression) // PY-2792
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax.");
|
||||
|
||||
Stack<PsiElement> st = new Stack<PsiElement>(); // PY-2796
|
||||
if (assignedValue != null)
|
||||
st.push(assignedValue);
|
||||
while (!st.isEmpty()) {
|
||||
PsiElement el = st.pop();
|
||||
if (el instanceof PyYieldExpression)
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax. " +
|
||||
"In Python <= 2.4, yield was a statement; it didn't return any value.");
|
||||
else {
|
||||
for (PsiElement e : el.getChildren())
|
||||
st.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyTryExceptStatement(PyTryExceptStatement node) { // PY-2795
|
||||
super.visitPyTryExceptStatement(node);
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON24)) {
|
||||
PyExceptPart[] excepts = node.getExceptParts();
|
||||
PyFinallyPart finallyPart = node.getFinallyPart();
|
||||
if (excepts.length != 0 && finallyPart != null)
|
||||
registerProblem(node, "Python version 2.4 doesn't support this syntax. You could use a finally block to ensure " +
|
||||
"that code is always executed, or one or more except blocks to catch specific exceptions.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyCallExpression(PyCallExpression node) {
|
||||
super.visitPyCallExpression(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (!languageLevel.isPy3K()) {
|
||||
final PsiElement firstChild = node.getFirstChild();
|
||||
if (firstChild != null) {
|
||||
final String name = firstChild.getText();
|
||||
if (PyNames.SUPER.equals(name)) {
|
||||
final PyArgumentList argumentList = node.getArgumentList();
|
||||
if (argumentList != null && argumentList.getArguments().length == 0) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not support this syntax. super() should have arguments in Python 2",
|
||||
len, node, null);
|
||||
len = 0;
|
||||
message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
PyExpression callee = node.getCallee();
|
||||
assert callee != null;
|
||||
PsiReference reference = callee.getReference();
|
||||
if (reference != null) {
|
||||
PsiElement resolved = reference.resolve();
|
||||
ProjectFileIndex ind = ProjectRootManager.getInstance(callee.getProject()).getFileIndex();
|
||||
final String name = callee.getText();
|
||||
if (resolved != null) {
|
||||
PsiFile file = resolved.getContainingFile();
|
||||
if (file != null && ind.isInLibraryClasses(file.getVirtualFile())) {
|
||||
if (!name.equals("print") && UnsupportedFeaturesUtil.BUILTINS.get(languageLevel).contains(name)) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!name.equals("print") && UnsupportedFeaturesUtil.BUILTINS.get(languageLevel).contains(name)) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not have method " + node.getCallee().getText(),
|
||||
len, node, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyImportElement(PyImportElement node) {
|
||||
super.visitPyImportElement(node);
|
||||
int len = 0;
|
||||
StringBuilder message = new StringBuilder(myCommonMessage);
|
||||
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
|
||||
LanguageLevel languageLevel = myVersionsToProcess.get(i);
|
||||
if (UnsupportedFeaturesUtil.MODULES.get(languageLevel).contains(node.getText()) &&
|
||||
!node.getText().equals("__builtin__") && !node.getText().equals("builtins")) {
|
||||
len = appendLanguageLevel(message, len, languageLevel);
|
||||
}
|
||||
}
|
||||
commonRegisterProblem(message, " not have module " + node.getText(), len, node, null, false);
|
||||
}
|
||||
|
||||
|
||||
protected abstract void registerProblem(PsiElement node, String s, LocalQuickFix localQuickFix, boolean asError);
|
||||
|
||||
protected void registerProblem(PsiElement node, String s, LocalQuickFix localQuickFix) {
|
||||
registerProblem(node, s, localQuickFix, true);
|
||||
}
|
||||
|
||||
protected void registerProblem(PsiElement node, String s) {
|
||||
registerProblem(node, s, null);
|
||||
}
|
||||
|
||||
protected void setVersionsToProcess(List<LanguageLevel> versionsToProcess) {
|
||||
myVersionsToProcess = versionsToProcess;
|
||||
}
|
||||
|
||||
protected void commonRegisterProblem(StringBuilder initMessage, String suffix,
|
||||
int len, PyElement node, LocalQuickFix localQuickFix) {
|
||||
commonRegisterProblem(initMessage, suffix, len, node, localQuickFix, true);
|
||||
}
|
||||
|
||||
protected void commonRegisterProblem(StringBuilder initMessage, String suffix,
|
||||
int len, PyElement node, LocalQuickFix localQuickFix, boolean asError) {
|
||||
initMessage.append(" do");
|
||||
if (len == 1)
|
||||
initMessage.append("es");
|
||||
initMessage.append(suffix);
|
||||
if (len != 0)
|
||||
registerProblem(node, initMessage.toString(), localQuickFix, asError);
|
||||
}
|
||||
|
||||
private static int appendLanguageLevel(StringBuilder message, int len, LanguageLevel languageLevel) {
|
||||
if (len != 0)
|
||||
message.append(", ");
|
||||
message.append(languageLevel.toString());
|
||||
return ++len;
|
||||
}
|
||||
}
|
||||
@@ -9,24 +9,44 @@ import com.intellij.codeInspection.ex.ProblemDescriptorImpl;
|
||||
import com.intellij.codeInspection.ex.QuickFixWrapper;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.actions.*;
|
||||
import com.jetbrains.python.codeInsight.intentions.RemoveTrailingLIntention;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author Alexey.Ivanov
|
||||
*/
|
||||
public class UnsupportedFeatures extends PyAnnotator {
|
||||
public class UnsupportedFeatures extends CompatibilityVisitor {
|
||||
|
||||
public UnsupportedFeatures() {
|
||||
super(new ArrayList<LanguageLevel>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyElement(PyElement node) {
|
||||
setVersionsToProcess(Arrays.asList(getLanguageLevel(node)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerProblem(PsiElement node, String message, LocalQuickFix localQuickFix, boolean asError) {
|
||||
if (node == null || node.getTextLength() == 0){
|
||||
return;
|
||||
}
|
||||
if (localQuickFix != null)
|
||||
if (asError)
|
||||
getHolder().createErrorAnnotation(node, message).registerFix(createIntention(node, message, localQuickFix));
|
||||
else
|
||||
getHolder().createWarningAnnotation(node, message).registerFix(createIntention(node, message, localQuickFix));
|
||||
else
|
||||
if (asError)
|
||||
getHolder().createErrorAnnotation(node, message);
|
||||
else
|
||||
getHolder().createWarningAnnotation(node, message);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static LanguageLevel getLanguageLevel(PyElement node) {
|
||||
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
|
||||
@@ -36,321 +56,11 @@ public class UnsupportedFeatures extends PyAnnotator {
|
||||
return LanguageLevel.getDefault();
|
||||
}
|
||||
|
||||
private static boolean isPy2(PyElement node) {
|
||||
return !getLanguageLevel(node).isPy3K();
|
||||
}
|
||||
|
||||
private static boolean isPy3K(PyElement node) {
|
||||
return getLanguageLevel(node).isPy3K();
|
||||
}
|
||||
|
||||
private static IntentionAction createIntention(PyElement node, String message, LocalQuickFix fix) {
|
||||
private static IntentionAction createIntention(PsiElement node, String message, LocalQuickFix fix) {
|
||||
LocalQuickFix[] quickFixes = {fix};
|
||||
CommonProblemDescriptorImpl descr = new ProblemDescriptorImpl(node, node, message,
|
||||
quickFixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, true,
|
||||
node.getTextRange(), true);
|
||||
return QuickFixWrapper.wrap((ProblemDescriptor)descr, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyDictCompExpression(PyDictCompExpression node) {
|
||||
super.visitPyDictCompExpression(node);
|
||||
LanguageLevel languageLevel = getLanguageLevel(node);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
String message = "Python version " + languageLevel + " does not support dictionary comprehensions";
|
||||
getHolder()
|
||||
.createWarningAnnotation(node, message)
|
||||
.registerFix(createIntention(node, message, new ConvertDictCompQuickFix()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPySetLiteralExpression(PySetLiteralExpression node) {
|
||||
super.visitPySetLiteralExpression(node);
|
||||
LanguageLevel languageLevel = getLanguageLevel(node);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
String message = "Python version " + languageLevel + " does not support set literal expressions";
|
||||
getHolder()
|
||||
.createWarningAnnotation(node, message)
|
||||
.registerFix(createIntention(node, message, new ConvertSetLiteralQuickFix()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPySetCompExpression(PySetCompExpression node) {
|
||||
super.visitPySetCompExpression(node);
|
||||
final LanguageLevel languageLevel = getLanguageLevel(node);
|
||||
if (!languageLevel.supportsSetLiterals()) {
|
||||
getHolder().createWarningAnnotation(node, "Python version " + languageLevel + " does not support set comprehensions");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyExceptBlock(PyExceptPart node) {
|
||||
super.visitPyExceptBlock(node);
|
||||
PyExpression exceptClass = node.getExceptClass();
|
||||
if (exceptClass != null) {
|
||||
LanguageLevel languageLevel = getLanguageLevel(node);
|
||||
if (languageLevel == LanguageLevel.PYTHON24 || languageLevel == LanguageLevel.PYTHON25) {
|
||||
PsiElement element = exceptClass.getNextSibling();
|
||||
while (element instanceof PsiWhiteSpace) {
|
||||
element = element.getNextSibling();
|
||||
}
|
||||
if (element != null && "as".equals(element.getText())) {
|
||||
getHolder().createWarningAnnotation(node, "This Python version does not support this syntax");
|
||||
}
|
||||
}
|
||||
else if (isPy3K(node)) {
|
||||
PsiElement element = exceptClass.getNextSibling();
|
||||
while (element instanceof PsiWhiteSpace) {
|
||||
element = element.getNextSibling();
|
||||
}
|
||||
if (element != null && ",".equals(element.getText())) {
|
||||
String message = "Python 3 does not support this syntax";
|
||||
getHolder().createWarningAnnotation(node, message).registerFix(createIntention(node, message, new ReplaceExceptPartQuickFix()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyImportStatement(PyImportStatement node) {
|
||||
super.visitPyImportStatement(node);
|
||||
PyImportElement[] importElements = node.getImportElements();
|
||||
for (PyImportElement importElement : importElements) {
|
||||
final PyQualifiedName qName = importElement.getImportedQName();
|
||||
if (qName != null) {
|
||||
if (isPy2(node)) {
|
||||
if (qName.matches("builtins")) {
|
||||
String message = "There is no module builtins in Python 2";
|
||||
getHolder().createWarningAnnotation(node, message)
|
||||
.registerFix(createIntention(node, message, new ReplaceBuiltinsQuickFix()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (qName.matches("__builtin__")) {
|
||||
String message = "Module __builtin__ renamed to builtins";
|
||||
getHolder().createWarningAnnotation(node, "Module __builtin__ renamed to builtins")
|
||||
.registerFix(createIntention(node, message, new ReplaceBuiltinsQuickFix()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyCallExpression(PyCallExpression node) {
|
||||
super.visitPyCallExpression(node);
|
||||
if (isPy2(node)) {
|
||||
final PsiElement firstChild = node.getFirstChild();
|
||||
if (firstChild != null) {
|
||||
final String name = firstChild.getText();
|
||||
if (PyNames.SUPER.equals(name)) {
|
||||
final PyArgumentList argumentList = node.getArgumentList();
|
||||
if (argumentList != null && argumentList.getArguments().length == 0) {
|
||||
getHolder().createWarningAnnotation(node, "super() should have arguments in Python 2");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyExpression callee = node.getCallee();
|
||||
assert callee != null;
|
||||
PsiReference reference = callee.getReference();
|
||||
if (reference != null) {
|
||||
PsiElement resolved = reference.resolve();
|
||||
if (resolved == null) {
|
||||
final String name = callee.getText();
|
||||
if (!name.equals("print") && UnsupportedFeaturesUtil.BUILTINS.get(getLanguageLevel(callee)).contains(name)) {
|
||||
getHolder().createWarningAnnotation(callee, PyBundle.message("ANN.method.$0.removed", name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyStarExpression(PyStarExpression node) {
|
||||
super.visitPyStarExpression(node);
|
||||
if (isPy2(node)) {
|
||||
getHolder().createWarningAnnotation(node, "Starred expressions are not allowed as assignment targets in Python 2");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyBinaryExpression(PyBinaryExpression node) {
|
||||
super.visitPyBinaryExpression(node);
|
||||
if (isPy3K(node) && node.isOperator("<>")) {
|
||||
final String message = isPy3K(node) ? "<> is not supported in Python 3, use != instead" : "<> is deprecated, use != instead";
|
||||
getHolder().createWarningAnnotation(node, message).registerFix(createIntention(node, message, new ReplaceNotEqOperatorQuickFix()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyNumericLiteralExpression(final PyNumericLiteralExpression node) {
|
||||
super.visitPyNumericLiteralExpression(node);
|
||||
if (isPy3K(node)) {
|
||||
if (!node.isIntegerLiteral()) {
|
||||
return;
|
||||
}
|
||||
final String text = node.getText();
|
||||
if (text.endsWith("l") || text.endsWith("L")) {
|
||||
getHolder().createWarningAnnotation(node,
|
||||
"Integer literals do not support a trailing \'l\' or \'L\' in Python 3")
|
||||
.registerFix(new RemoveTrailingLIntention());
|
||||
}
|
||||
if (text.length() > 1 && text.charAt(0) == '0') {
|
||||
final char c = Character.toLowerCase(text.charAt(1));
|
||||
if (c != 'o' && c != 'b' && c != 'x') {
|
||||
boolean isNull = true;
|
||||
for (char a : text.toCharArray()) {
|
||||
if ( a != '0') {
|
||||
isNull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isNull) {
|
||||
final String message = "Python 3 requires '0o' prefix for octal literals";
|
||||
getHolder().createWarningAnnotation(node, message).registerFix(createIntention(node, message, new ReplaceOctalNumericLiteralQuickFix()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyStringLiteralExpression(final PyStringLiteralExpression node) {
|
||||
super.visitPyStringLiteralExpression(node);
|
||||
if (isPy3K(node)) {
|
||||
final String text = node.getText();
|
||||
if (text.startsWith("u") || text.startsWith("U")) {
|
||||
final String message = "String literals do not support a leading \'u\' or \'U\' in Python 3";
|
||||
getHolder().createWarningAnnotation(node, message).registerFix(createIntention(node, message, new RemoveLeadingUQuickFix()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyListCompExpression(final PyListCompExpression node) {
|
||||
super.visitPyListCompExpression(node);
|
||||
if (isPy3K(node)) {
|
||||
final List<ComprhForComponent> forComponents = node.getForComponents();
|
||||
for (ComprhForComponent forComponent : forComponents) {
|
||||
final PyExpression iteratedList = forComponent.getIteratedList();
|
||||
if (iteratedList instanceof PyTupleExpression) {
|
||||
final String message = "List comprehensions do not support this syntax in Python 3";
|
||||
getHolder().createWarningAnnotation(iteratedList, message).registerFix(createIntention(iteratedList, message, new ReplaceListComprehensionsQuickFix()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyRaiseStatement(PyRaiseStatement node) {
|
||||
super.visitPyRaiseStatement(node);
|
||||
boolean hasProblem = UnsupportedFeaturesUtil.raiseHasNoArgs(node, LanguageLevel.forElement(node));
|
||||
if (hasProblem) {
|
||||
getHolder().createErrorAnnotation(node, "raise with no arguments can only be used in an except block");
|
||||
}
|
||||
hasProblem = UnsupportedFeaturesUtil.raiseHasMoreThenOneArg(node, LanguageLevel.forElement(node));
|
||||
if (hasProblem) {
|
||||
final String message = "Python 3 does not support this syntax";
|
||||
getHolder().createWarningAnnotation(node, message).registerFix(createIntention(node, message, new ReplaceRaiseStatementQuickFix()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyReprExpression(PyReprExpression node) {
|
||||
super.visitPyReprExpression(node);
|
||||
if (isPy3K(node)) {
|
||||
final String message = "Backquote is not supported in Python 3, use repr() instead";
|
||||
getHolder().createWarningAnnotation(node, message).registerFix(createIntention(node, message, new ReplaceBackquoteExpressionQuickFix()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyWithStatement(PyWithStatement node) {
|
||||
super.visitPyWithStatement(node);
|
||||
final LanguageLevel languageLevel = getLanguageLevel(node);
|
||||
if (languageLevel == LanguageLevel.PYTHON24) {
|
||||
getHolder().createWarningAnnotation(node, "Python version 2.4 doesn't support this syntax.");
|
||||
}
|
||||
else if (!languageLevel.supportsSetLiterals()) {
|
||||
final PyWithItem[] items = node.getWithItems();
|
||||
if (items.length > 1) {
|
||||
for (int i = 1; i < items.length; i++) {
|
||||
getHolder().createWarningAnnotation(items [i], "Python version " + languageLevel + " does not support multiple context managers");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyClass(PyClass node) { //PY-2719
|
||||
if (getLanguageLevel(node) == LanguageLevel.PYTHON24) {
|
||||
PyArgumentList list = node.getSuperClassExpressionList();
|
||||
if (list != null && list.getArguments().length == 0)
|
||||
getHolder().createWarningAnnotation(list, "Python version 2.4 does not support this syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyPrintStatement(PyPrintStatement node) {
|
||||
PsiElement[] arguments = node.getChildren();
|
||||
if (getLanguageLevel(node).isPy3K()) {
|
||||
for (PsiElement element : arguments) {
|
||||
if (!((element instanceof PyParenthesizedExpression) || (element instanceof PyTupleExpression)))
|
||||
getHolder().createWarningAnnotation(element, "Python versions >= 3.0 do not support this syntax. The print statement has been replaced with a print() function");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyFromImportStatement(PyFromImportStatement node) {
|
||||
PyReferenceExpression importSource = node.getImportSource();
|
||||
if (getLanguageLevel(node) == LanguageLevel.PYTHON24) {
|
||||
if (importSource == null)
|
||||
getHolder().createWarningAnnotation(node, "Python version 2.4 doesn't support this syntax.");
|
||||
else {
|
||||
PsiElement prev = importSource.getPrevSibling();
|
||||
if (prev != null && prev.getNode().getElementType() == PyTokenTypes.DOT)
|
||||
getHolder().createWarningAnnotation(node, "Python version 2.4 doesn't support this syntax.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyAssignmentStatement(PyAssignmentStatement node) {
|
||||
if (getLanguageLevel(node) == LanguageLevel.PYTHON24) {
|
||||
PyExpression assignedValue = node.getAssignedValue();
|
||||
if (assignedValue instanceof PyConditionalExpression) // PY-2792
|
||||
getHolder().createWarningAnnotation(node, "Python version 2.4 doesn't support this syntax.");
|
||||
|
||||
Stack<PsiElement> st = new Stack<PsiElement>(); // PY-2796
|
||||
if (assignedValue != null)
|
||||
st.push(assignedValue);
|
||||
while (!st.isEmpty()) {
|
||||
PsiElement el = st.pop();
|
||||
if (el instanceof PyYieldExpression)
|
||||
getHolder().createWarningAnnotation(node, "Python version 2.4 doesn't support this syntax. " +
|
||||
"In Python <= 2.4, yield was a statement; it didn't return any value.");
|
||||
else {
|
||||
for (PsiElement e : el.getChildren())
|
||||
st.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyTryExceptStatement(PyTryExceptStatement node) { // PY-2795
|
||||
if (getLanguageLevel(node) == LanguageLevel.PYTHON24) {
|
||||
PyExceptPart[] excepts = node.getExceptParts();
|
||||
PyFinallyPart finallyPart = node.getFinallyPart();
|
||||
if (excepts.length != 0 && finallyPart != null)
|
||||
getHolder().createWarningAnnotation(node,
|
||||
"Python version 2.4 doesn't support this syntax. You could use a finally block to ensure " +
|
||||
"that code is always executed, or one or more except blocks to catch specific exceptions.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
print(<warning descr="<> is not supported in Python 3, use != instead">a <> 3</warning>)
|
||||
<warning descr="Backquote is not supported in Python 3, use repr() instead">`foo()`</warning>
|
||||
a = <warning descr="Integer literals do not support a trailing 'l' or 'L' in Python 3">123l</warning>
|
||||
a = <warning descr="Python 3 requires '0o' prefix for octal literals">043</warning>
|
||||
print(<error descr="Python version 3.0 does not support <>, use != instead.">a <> 3</error>)
|
||||
<error descr="Python version 3.0 does not support backquotes, use repr() instead">`foo()`</error>
|
||||
a = <error descr="Python version 3.0 does not support a trailing 'l' or 'L'.">123l</error>
|
||||
a = <error descr="Python version 3.0 does not support this syntax. It requires '0o' prefix for octal literals">043</error>
|
||||
a = 0X43
|
||||
a = 0b1
|
||||
a = 0.0
|
||||
s = <warning descr="String literals do not support a leading 'u' or 'U' in Python 3">u"text"</warning>
|
||||
<warning descr="Python 3 does not support this syntax">raise a, b, c</warning>
|
||||
<warning descr="Python 3 does not support this syntax">raise a, b</warning>
|
||||
s = <error descr="Python version 3.0 does not support a leading 'u' or 'U'.">u"text"</error>
|
||||
<error descr="Python version 3.0 does not support this syntax.">raise a, b, c</error>
|
||||
<error descr="Python version 3.0 does not support this syntax.">raise a, b</error>
|
||||
|
||||
try:
|
||||
pass
|
||||
<warning descr="Python 3 does not support this syntax">except a, name:
|
||||
pass</warning>
|
||||
<error descr="Python version 3.0 does not support this syntax.">except a, name:
|
||||
pass</error>
|
||||
|
||||
[x * 2 for x in <warning descr="List comprehensions do not support this syntax in Python 3">vec1, vec2</warning>]
|
||||
[x * 2 for x in <error descr="Python version 3.0 does not support this syntax in list comprehensions.">vec1, vec2</error>]
|
||||
|
||||
<warning descr="Module __builtin__ renamed to builtins">import __builtin__</warning>
|
||||
<error descr="Python version 3.0 does not have module __builtin__">import __builtin__</error>
|
||||
|
||||
<error descr="raise with no arguments can only be used in an except block">raise</error>
|
||||
<error descr="Python version 3.0 does not support this syntax. Raise with no arguments can only be used in an except block">raise</error>
|
||||
|
||||
try:
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# PY-2792
|
||||
<warning descr="Python version 2.4 doesn't support this syntax.">x = True if condition else False</warning>
|
||||
|
||||
def foo(): # PY-2796
|
||||
<warning descr="Python version 2.4 doesn't support this syntax. In Python <= 2.4, yield was a statement; it didn't return any value.">a = (yield 1)</warning>
|
||||
@@ -0,0 +1,4 @@
|
||||
print(<warning descr="Python version 3.0, 3.1 do not support <>, use != instead.">a <> b</warning>)
|
||||
|
||||
if <warning descr="Python version 3.0, 3.1 do not support <>, use != instead.">a <> 2</warning>:
|
||||
var = a
|
||||
@@ -0,0 +1,11 @@
|
||||
class A(B):
|
||||
def __init__(self):
|
||||
<warning descr="Python version 2.4, 2.5, 2.6, 2.7 do not support this syntax. super() should have arguments in Python 2">super()</warning>
|
||||
|
||||
<warning descr="Python version 3.1 does not have method cmp">cmp()</warning>
|
||||
<warning descr="Python version 3.0, 3.1 do not have method reduce"><warning descr="Python version 3.0 does not have method reduce">reduce()</warning></warning>
|
||||
<warning descr="Python version 2.4 does not have method all">all()</warning>
|
||||
|
||||
<warning descr="Python version 2.4, 2.5, 2.6, 2.7 do not have method bytearray">bytearray()</warning>
|
||||
<warning descr="Python version 2.4, 2.5 do not have method next">next()</warning>
|
||||
<warning descr="Python version 2.4, 2.5, 3.0, 3.1 do not have method buffer"><warning descr="Python version 3.0 does not have method buffer">buffer()</warning></warning>
|
||||
@@ -0,0 +1 @@
|
||||
var = <warning descr="Python version 2.4, 2.5, 2.6, 3.0 do not support dictionary comprehensions">{i : chr(65+i) for i in range(4)}</warning>
|
||||
@@ -0,0 +1,9 @@
|
||||
try:
|
||||
do_smth()
|
||||
<warning descr="Python version 2.4, 2.5 do not support this syntax.">except ImportError as e:
|
||||
do()</warning>
|
||||
|
||||
try:
|
||||
do_smth()
|
||||
<warning descr="Python version 3.0, 3.1 do not support this syntax.">except ImportError, ImportWarning:
|
||||
do()</warning>
|
||||
@@ -0,0 +1,4 @@
|
||||
<warning descr="Python version 2.4 doesn't support this syntax.">from . import smth</warning>
|
||||
<warning descr="Python version 2.4 doesn't support this syntax.">from .module import name1, name2</warning>
|
||||
|
||||
<warning descr="Python version 3.0, 3.1 do not have module Bastion">from Bastion import BastionClass</warning>
|
||||
@@ -0,0 +1 @@
|
||||
import <warning descr="Python version 3.0, 3.1 do not have module Bastion">Bastion</warning>
|
||||
@@ -0,0 +1,3 @@
|
||||
<error descr="Python version 2.7 does not have module builtins"><warning descr="Python version 2.4, 2.5, 2.6, 2.7 do not have module builtins">import builtins</warning></error>
|
||||
|
||||
<warning descr="Python version 3.0, 3.1 do not have module __builtin__">import __builtin__</warning>
|
||||
@@ -0,0 +1 @@
|
||||
var = [x for x in <warning descr="Python version 3.0, 3.1 do not support this syntax in list comprehensions.">1, 2, 3</warning>]
|
||||
@@ -0,0 +1,2 @@
|
||||
a = <warning descr="Python version 3.0, 3.1 do not support a trailing 'l' or 'L'.">12l</warning>
|
||||
v = <warning descr="Python version 3.0, 3.1 do not support this syntax. It requires '0o' prefix for octal literals">04</warning><error descr="end of statement expected">8</error>
|
||||
@@ -0,0 +1 @@
|
||||
<warning descr="Python version >= 3.0 do not support this syntax. The print statement has been replaced with a print() function">print "One value"</warning>
|
||||
@@ -0,0 +1,3 @@
|
||||
#PY-2719
|
||||
class BaseC<warning descr="Python version 2.4 does not support this syntax.">()</warning>:
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
try:
|
||||
a
|
||||
except :
|
||||
<warning descr="Python version 3.0, 3.1 do not support this syntax.">raise ImportError, ImportWarning</warning>
|
||||
|
||||
<warning descr="Python version 3.0, 3.1 do not support this syntax. Raise with no arguments can only be used in an except block">raise</warning>
|
||||
@@ -0,0 +1 @@
|
||||
a = <warning descr="Python version 3.0, 3.1 do not support backquotes, use repr() instead">`imp.acquire_lock()`</warning>
|
||||
@@ -0,0 +1 @@
|
||||
var = <warning descr="Python version 2.4, 2.5, 2.6, 3.0 do not support set comprehensions">{i for i in range(2)}</warning>
|
||||
@@ -0,0 +1 @@
|
||||
var = <warning descr="Python version 2.4, 2.5, 2.6, 3.0 do not support set literal expressions">{1, 2}</warning>
|
||||
@@ -0,0 +1,2 @@
|
||||
t = (1, 2, 3)
|
||||
a, <warning descr="Python version 2.4, 2.5, 2.6, 2.7 do not support this syntax. Starred expressions are not allowed as assignment targets in Python 2">*b</warning>, c = t
|
||||
@@ -0,0 +1 @@
|
||||
a = <warning descr="Python version 3.0, 3.1 do not support a leading 'u' or 'U'.">u"String"</warning>
|
||||
@@ -1,10 +1,10 @@
|
||||
print(<warning descr="Python versions 3.0, 3.1 do not support <>, use != instead.">a <> b</warning>)
|
||||
print(<warning descr="Python version 3.0, 3.1 do not support <>, use != instead.">a <> b</warning>)
|
||||
|
||||
if <warning descr="Python versions 3.0, 3.1 do not support <>, use != instead.">a <> 2</warning>:
|
||||
if <warning descr="Python version 3.0, 3.1 do not support <>, use != instead.">a <> 2</warning>:
|
||||
var = a
|
||||
########################
|
||||
|
||||
<warning descr="Python versions >= 3.0 do not support this syntax. The print statement has been replaced with a print() function">print "One value"</warning>
|
||||
<warning descr="Python version >= 3.0 do not support this syntax. The print statement has been replaced with a print() function">print "One value"</warning>
|
||||
|
||||
########################
|
||||
|
||||
@@ -14,14 +14,14 @@ class BaseC<warning descr="Python version 2.4 does not support this syntax.">()<
|
||||
|
||||
########################
|
||||
|
||||
<warning descr="Python version 2.4 doesn't support this syntax.">with A() as a, <warning descr="Python versions 2.5, 2.6, 3.0 do not support multiple context managers">B() as b</warning>:
|
||||
<warning descr="Python version 2.4 doesn't support this syntax.">with A() as a, <warning descr="Python version 2.5, 2.6, 3.0 do not support multiple context managers">B() as b</warning>:
|
||||
suite
|
||||
|
||||
</warning>########################
|
||||
a = <warning descr="Python versions 3.0, 3.1 do not support backquotes, use repr() instead">`imp.acquire_lock()`</warning>
|
||||
a = <warning descr="Python version 3.0, 3.1 do not support backquotes, use repr() instead">`imp.acquire_lock()`</warning>
|
||||
|
||||
########################
|
||||
var = [x for x in <warning descr="Python versions 3.0, 3.1 do not support this syntax in list comprehensions.">1, 2, 3</warning>]
|
||||
var = [x for x in <warning descr="Python version 3.0, 3.1 do not support this syntax in list comprehensions.">1, 2, 3</warning>]
|
||||
|
||||
########################
|
||||
class A:
|
||||
@@ -33,35 +33,35 @@ a.cmp()
|
||||
|
||||
########################
|
||||
|
||||
<warning descr="Python versions 3.1 have no method cmp">cmp()</warning>
|
||||
<warning descr="Python versions 3.0, 3.1 have no method reduce">reduce()</warning>
|
||||
<warning descr="Python versions 2.4 have no method all">all()</warning>
|
||||
<warning descr="Python version 3.1 does not have method cmp">cmp()</warning>
|
||||
<warning descr="Python version 3.0, 3.1 do not have method reduce">reduce()</warning>
|
||||
<warning descr="Python version 2.4 does not have method all">all()</warning>
|
||||
|
||||
bytearray()
|
||||
next()
|
||||
<warning descr="Python versions 2.4, 2.5, 3.0, 3.1 have no method buffer">buffer()</warning>
|
||||
<warning descr="Python version 2.4, 2.5, 3.0, 3.1 do not have method buffer">buffer()</warning>
|
||||
|
||||
########################
|
||||
try:
|
||||
a
|
||||
except :
|
||||
<warning descr="Python versions 3.0, 3.1 do not support this syntax.">raise ImportError, ImportWarning</warning>
|
||||
<warning descr="Python version 3.0, 3.1 do not support this syntax.">raise ImportError, ImportWarning</warning>
|
||||
|
||||
|
||||
try:
|
||||
a
|
||||
<warning descr="Python versions 3.0, 3.1 do not this syntax.">except ImportError, ImportWarning:
|
||||
<warning descr="Python version 3.0, 3.1 do not support this syntax.">except ImportError, ImportWarning:
|
||||
b
|
||||
|
||||
|
||||
|
||||
</warning>########################
|
||||
|
||||
var = <warning descr="Python versions 2.4, 2.5, 2.6, 3.0 do not support dictionary comprehensions">{i : chr(65+i) for i in range(4)}</warning>
|
||||
var = <warning descr="Python version 2.4, 2.5, 2.6, 3.0 do not support dictionary comprehensions">{i : chr(65+i) for i in range(4)}</warning>
|
||||
|
||||
########################
|
||||
|
||||
import <warning descr="Python versions 3.0, 3.1 do not have module Bastion">Bastion</warning>
|
||||
import <warning descr="Python version 3.0, 3.1 do not have module Bastion">Bastion</warning>
|
||||
var = Bastion.BastionClass()
|
||||
|
||||
########################
|
||||
@@ -70,7 +70,7 @@ def foo(): # PY-2796
|
||||
|
||||
########################
|
||||
|
||||
<warning descr="Python versions 3.0 3.1 do not support this syntax. Raise with no arguments can only be used in an except block">raise</warning>
|
||||
<warning descr="Python version 3.0, 3.1 do not support this syntax. re with no arguments can only be used in an except block">raise</warning>
|
||||
|
||||
########################
|
||||
# PY-2792
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<warning descr="Python version 2.4 doesn't support this syntax. You could use a finally block to ensure that code is always executed, or one or more except blocks to catch specific exceptions.">try:
|
||||
do_smth()
|
||||
except ImportError:
|
||||
do()
|
||||
except KeyError:
|
||||
do_1()
|
||||
finally:
|
||||
quit()</warning>
|
||||
@@ -0,0 +1,2 @@
|
||||
<warning descr="Python version 2.4 doesn't support this syntax.">with A() as a, <warning descr="Python version 2.5, 2.6, 3.0 do not support multiple context managers">B() as b</warning>:
|
||||
suite</warning>
|
||||
@@ -3,8 +3,8 @@ def foo():
|
||||
print x
|
||||
|
||||
def test_vlu():
|
||||
<warning descr="Starred expressions are not allowed as assignment targets in Python 2">*<warning descr="Local variable 'h' value is not used">h</warning></warning>, <warning descr="Local variable 't' value is not used">t</warning> = [1, 2, 3] # fail
|
||||
<error descr="Python version 2.6 does not support this syntax. Starred expressions are not allowed as assignment targets in Python 2">*<warning descr="Local variable 'h' value is not used">h</warning></error>, <warning descr="Local variable 't' value is not used">t</warning> = [1, 2, 3] # fail
|
||||
|
||||
def test_vlu():
|
||||
<warning descr="Starred expressions are not allowed as assignment targets in Python 2">*h</warning>, t = [1, 2, 3] # pass
|
||||
<error descr="Python version 2.6 does not support this syntax. Starred expressions are not allowed as assignment targets in Python 2">*h</error>, t = [1, 2, 3] # pass
|
||||
print(t)
|
||||
@@ -1 +1 @@
|
||||
print(<warning descr="Python versions 3.0, 3.1 do not support <>, use != instead.">a<caret> <> b</warning>)
|
||||
print(<warning descr="Python version 3.0, 3.1 do not support <>, use != instead.">a<caret> <> b</warning>)
|
||||
@@ -74,6 +74,7 @@ public class PythonHighlightingTest extends PyLightFixtureTestCase {
|
||||
}
|
||||
|
||||
public void testAssignmentTargets() {
|
||||
setLanguageLevel(LanguageLevel.PYTHON26);
|
||||
doTest(true, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.jetbrains.python.fixtures.PyLightFixtureTestCase;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
|
||||
/**
|
||||
* User : catherine
|
||||
*/
|
||||
public class PyCompatibilityInspectionTest extends PyLightFixtureTestCase {
|
||||
|
||||
public void testDictCompExpression() {
|
||||
setLanguageLevel(LanguageLevel.PYTHON27);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSetLiteralExpression() {
|
||||
setLanguageLevel(LanguageLevel.PYTHON27);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSetCompExpression() {
|
||||
setLanguageLevel(LanguageLevel.PYTHON27);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testExceptBlock() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testImportStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStarExpression() {
|
||||
setLanguageLevel(LanguageLevel.PYTHON30);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBinaryExpression() {
|
||||
setLanguageLevel(LanguageLevel.PYTHON27);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNumericLiteralExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testStringLiteralExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testListCompExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testRaiseStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReprExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testWithStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPyClass() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPrintStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testFromImportStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAssignmentStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTryExceptStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testImportElement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCallExpression() {
|
||||
setLanguageLevel(LanguageLevel.PYTHON30);
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile("inspections/PyCompatibilityInspection/" + getTestName(true) + ".py");
|
||||
myFixture.enableInspections(PyCompatibilityInspection.class);
|
||||
myFixture.checkHighlighting(true, false, false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user