Annotator to highlight unsupported features in Python2

This commit is contained in:
alexey.ivanov
2010-02-25 13:42:37 +03:00
parent a1db395f8a
commit 1b02b30eb3
25 changed files with 517 additions and 60 deletions

View File

@@ -57,6 +57,7 @@ INTN.Family.toggle.import.alias=Toggle import alias
INTN.Family.convert.except.part=Convert except part to supported form
INTN.Family.convert.set.literal=Convert set literal two supported forms
INTN.Family.convert.builtin=Convert builtin module import
INTN.Family.convert.dict.comp.expression=Convert dictionary comprehension expression
INTN.convert.to.from.$0.import.$1=Convert to ''from {0} import {1}''
INTN.convert.to.import.$0=Convert to ''import {0}''
@@ -71,6 +72,8 @@ INTN.convert.set.literal.to=Convert set literal to 'set' method call
INTN.convert.builtin.import=Convert builtin module import to supported form
INTN.convert.dict.comp.to=Convert dictionary comprehension to 'dict' method call
# Conflict checker
CONFLICT.name.$0.obscured=Name ''{0}'' obscured by local definitions
CONFLICT.name.$0.obscured.cannot.convert=Name ''{0}'' obscured. Cannot convert.

View File

@@ -35,6 +35,7 @@ public class PythonLanguage extends Language {
_annotators.add(ImportAnnotator.class);
_annotators.add(StringConstantAnnotator.class);
_annotators.add(PyBuiltinAnnotator.class);
_annotators.add(UnsupportedFeaturesIn2.class);
}

View File

@@ -0,0 +1,81 @@
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.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
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.*;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Alexey.Ivanov
* Date: 20.02.2010
* Time: 15:49:35
*/
public class ConvertDictCompIntention implements IntentionAction {
@NotNull
@Override
public String getText() {
return PyBundle.message("INTN.convert.dict.comp.to");
}
@NotNull
@Override
public String getFamilyName() {
return PyBundle.message("INTN.Family.convert.dict.comp.expression");
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && !LanguageLevel.forFile(virtualFile).isPy3K()) {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
PyDictCompExpression expression = PsiTreeUtil.getParentOfType(element, PyDictCompExpression.class);
if (expression == null) {
return false;
}
return expression.getResultExpression() instanceof PyKeyValueExpression;
}
return false;
}
// TODO: {k, v for k in range(4) for v in range(4)}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && !LanguageLevel.forFile(virtualFile).isPy3K()) {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
PyDictCompExpression expression = PsiTreeUtil.getParentOfType(element, PyDictCompExpression.class);
assert expression != null;
replaceComprehension(project, expression);
}
}
private static void replaceComprehension(Project project, PyDictCompExpression expression) {
List<ComprhForComponent> forComponents = expression.getForComponents();
if (expression.getResultExpression() instanceof PyKeyValueExpression) {
PyKeyValueExpression keyValueExpression = (PyKeyValueExpression)expression.getResultExpression();
PyElementGenerator elementGenerator = PythonLanguage.getInstance().getElementGenerator();
assert keyValueExpression.getValue() != null;
expression.replace(elementGenerator.createFromText(project, PyExpressionStatement.class,
"dict([(" + keyValueExpression.getKey().getText() + ", " +
keyValueExpression.getValue().getText() + ") for " +
forComponents.get(0).getIteratorVariable().getText() + " in " +
forComponents.get(0).getIteratedList().getText() + "])"));
}
}
@Override
public boolean startInWriteAction() {
return true;
}
}

View File

@@ -0,0 +1,67 @@
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.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
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.*;
import org.jetbrains.annotations.NotNull;
/**
* Created by IntelliJ IDEA.
* User: Alexey.Ivanov
* Date: 16.02.2010
* Time: 21:33:28
*/
public class ConvertSetLiteralIntention implements IntentionAction {
@NotNull
public String getText() {
return PyBundle.message("INTN.convert.set.literal.to");
}
@NotNull
public String getFamilyName() {
return PyBundle.message("INTN.Family.convert.set.literal");
}
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && !LanguageLevel.forFile(virtualFile).isPy3K()) {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
PySetLiteralExpression setLiteral = PsiTreeUtil.getParentOfType(element, PySetLiteralExpression.class);
return (setLiteral != null);
}
return false;
}
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && !LanguageLevel.forFile(virtualFile).isPy3K()) {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
PySetLiteralExpression setLiteral = PsiTreeUtil.getParentOfType(element, PySetLiteralExpression.class);
assert setLiteral != null;
PyExpression[] expressions = setLiteral.getElements();
if (expressions != null) {
PyElementGenerator elementGenerator = PythonLanguage.getInstance().getElementGenerator();
assert expressions.length != 0;
StringBuilder stringBuilder = new StringBuilder(expressions[0].getText());
for (int i = 1; i < expressions.length; ++i) {
stringBuilder.append(", ");
stringBuilder.append(expressions[i].getText());
}
PyStatement newElement = elementGenerator.createFromText(project, PyExpressionStatement.class, "set([" + stringBuilder.toString() + "])");
setLiteral.replace(newElement);
}
}
}
public boolean startInWriteAction() {
return true;
}
}

View File

@@ -0,0 +1,61 @@
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.PsiElement;
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.*;
import org.jetbrains.annotations.NotNull;
/**
* Created by IntelliJ IDEA.
* User: Alexey.Ivanov
* Date: 19.02.2010
* Time: 18:50:24
*/
public class ReplaceBuiltinsIntention implements IntentionAction {
@NotNull
public String getText() {
return PyBundle.message("INTN.convert.builtin.import");
}
@NotNull
public String getFamilyName() {
return PyBundle.message("INTN.Family.convert.builtin");
}
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
PyImportStatement importStatement = PsiTreeUtil.getParentOfType(element, PyImportStatement.class);
return (importStatement != null);
}
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
PyElementGenerator elementGenerator = PythonLanguage.getInstance().getElementGenerator();
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
PyImportStatement importStatement = PsiTreeUtil.getParentOfType(element, PyImportStatement.class);
for (PyImportElement importElement : importStatement.getImportElements()) {
PyReferenceExpression importReference = importElement.getImportReference();
if (importReference != null) {
if (LanguageLevel.forFile(file.getVirtualFile()).isPy3K()) {
if ("__builtin__".equals(importReference.getName())) {
importReference.replace(elementGenerator.createFromText(project, PyReferenceExpression.class, "builtins"));
}
} else {
if ("builtins".equals(importReference.getName())) {
importReference.replace(elementGenerator.createFromText(project, PyReferenceExpression.class, "__builtin__"));
}
}
}
}
}
public boolean startInWriteAction() {
return true;
}
}

View File

@@ -0,0 +1,63 @@
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.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
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.LanguageLevel;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyExceptPart;
import org.jetbrains.annotations.NotNull;
/**
* Created by IntelliJ IDEA.
* User: Alexey.Ivanov
* Date: 16.02.2010
* Time: 18:07:55
*/
public class ReplaceExceptPartIntention implements IntentionAction {
@NotNull
public String getText() {
return PyBundle.message("INTN.convert.except.to");
}
@NotNull
public String getFamilyName() {
return PyBundle.message("INTN.Family.convert.except.part");
}
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null && !LanguageLevel.forFile(virtualFile).isPy3K()) {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
PyExceptPart exceptPart = PsiTreeUtil.getParentOfType(element, PyExceptPart.class);
return (exceptPart != null);
}
return false;
}
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
PyExceptPart exceptPart = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyExceptPart.class);
PyElementGenerator elementGenerator = PythonLanguage.getInstance().getElementGenerator();
assert exceptPart != null;
PsiElement element = exceptPart.getExceptClass().getNextSibling();
while (element instanceof PsiWhiteSpace) {
element = element.getNextSibling();
}
assert element != null;
element = element.replace(elementGenerator.createComma(project).getPsi());
assert element.getPrevSibling() instanceof PsiWhiteSpace;
element.getPrevSibling().delete();
}
public boolean startInWriteAction() {
return true;
}
}

View File

@@ -62,14 +62,18 @@ public class PyUnsupportedFeaturesInspection extends LocalInspectionTool {
REMOVED_METHODS.add("reload");
}
private static boolean isPy3K(PyElement node) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
return virtualFile != null && LanguageLevel.forFile(virtualFile).isPy3K();
}
public Visitor(final ProblemsHolder holder) {
super(holder);
}
@Override
public void visitPyBinaryExpression(PyBinaryExpression node) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
if (virtualFile != null && LanguageLevel.forFile(virtualFile).isPy3K()) {
if (isPy3K(node)) {
if (node.isOperator("<>")) {
registerProblem(node, "<> is not supported in Python 3, use != instead", new ReplaceNotEqOperatorQuickFix());
}
@@ -78,8 +82,7 @@ public class PyUnsupportedFeaturesInspection extends LocalInspectionTool {
@Override
public void visitPyNumericLiteralExpression(PyNumericLiteralExpression node) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
if (virtualFile != null && LanguageLevel.forFile(virtualFile).isPy3K()) {
if (isPy3K(node)) {
String text = node.getText();
if (text.endsWith("l") || text.endsWith("L")) {
registerProblem(node, "Integer literals do not support a trailing \'l\' or \'L\' in Python 3", new RemoveTrailingLQuickFix());
@@ -92,8 +95,7 @@ public class PyUnsupportedFeaturesInspection extends LocalInspectionTool {
@Override
public void visitPyStringLiteralExpression(PyStringLiteralExpression node) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
if (virtualFile != null && LanguageLevel.forFile(virtualFile).isPy3K()) {
if (isPy3K(node)) {
String text = node.getText();
if (text.startsWith("u") || text.startsWith("U")) {
registerProblem(node, "String literals do not support a leading \'u\' or \'U\' in Python 3", new ReamoveLeadingUQuickFix());
@@ -101,13 +103,14 @@ public class PyUnsupportedFeaturesInspection extends LocalInspectionTool {
}
}
@Override
public void visitPyListCompExpression(PyListCompExpression node) {
List<ComprhForComponent> forComponents = node.getForComponents();
for (ComprhForComponent forComponent: forComponents) {
PyExpression iteratedList = forComponent.getIteratedList();
if (iteratedList instanceof PyTupleExpression) {
registerProblem(iteratedList, "List comprehensions do not support this syntax in Python 3", new ReplaceListComprehensionsQuickFix());
registerProblem(iteratedList, "List comprehensions do not support such syntax in Python 3", new ReplaceListComprehensionsQuickFix());
}
}
}
@@ -116,16 +119,13 @@ public class PyUnsupportedFeaturesInspection extends LocalInspectionTool {
public void visitPyExceptBlock(PyExceptPart node) {
PyExpression exceptClass = node.getExceptClass();
if (exceptClass != null && node.getTarget() != null) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
if (virtualFile != null) {
if (LanguageLevel.forFile(virtualFile).isPy3K()) {
PsiElement element = exceptClass.getNextSibling();
while (element instanceof PsiWhiteSpace) {
element = element.getNextSibling();
}
if (element != null && ",".equals(element.getText())) {
registerProblem(node, "Python 3 does not support this syntax", new ReplaceExceptPartQuickFix(true));
}
if (isPy3K(node)) {
PsiElement element = exceptClass.getNextSibling();
while (element instanceof PsiWhiteSpace) {
element = element.getNextSibling();
}
if (element != null && ",".equals(element.getText())) {
registerProblem(node, "Python 3 does not support this syntax", new ReplaceExceptPartQuickFix(true));
}
}
}
@@ -134,68 +134,60 @@ public class PyUnsupportedFeaturesInspection extends LocalInspectionTool {
@Override
public void visitPyRaiseStatement(PyRaiseStatement node) {
PyExpression[] expressions = node.getExpressions();
assert(expressions != null);
assert (expressions != null);
if (expressions.length < 2) {
return;
}
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
if (virtualFile != null) {
if (LanguageLevel.forFile(virtualFile).isPy3K()) {
if (expressions.length == 3) {
registerProblem(node, "Python 3 does not support this syntax", new ReplaceRaiseStatementQuickFix());
return;
}
PsiElement element = expressions[0].getNextSibling();
while (element instanceof PsiWhiteSpace) {
element = element.getNextSibling();
}
if (element != null && ",".equals(element.getText())) {
registerProblem(node, "Python 3 does not support this syntax", new ReplaceRaiseStatementQuickFix());
}
} else {
if (expressions.length == 2) {
PsiElement element = expressions[0].getNextSibling();
while (element instanceof PsiWhiteSpace) {
element = element.getNextSibling();
}
if (element != null && "from".equals(element.getText())) {
registerProblem(node, "Python 2 does not support raise ... from syntax");
}
}
if (isPy3K(node)) {
if (expressions.length == 3) {
registerProblem(node, "Python 3 does not support this syntax", new ReplaceRaiseStatementQuickFix());
return;
}
PsiElement element = expressions[0].getNextSibling();
while (element instanceof PsiWhiteSpace) {
element = element.getNextSibling();
}
if (element != null && ",".equals(element.getText())) {
registerProblem(node, "Python 3 does not support this syntax", new ReplaceRaiseStatementQuickFix());
}
}
}
@Override
public void visitPyReprExpression(PyReprExpression node) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
if (virtualFile != null && LanguageLevel.forFile(virtualFile).isPy3K()) {
if (isPy3K(node)) {
registerProblem(node, "Backquote is not supported in Python 3, use repr() instead", new ReplaceBackquoteExpressionQuickFix());
}
}
@Override
public void visitPyCallExpression(PyCallExpression node) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
if (virtualFile != null) {
String name = node.getCallee().getName();
if (LanguageLevel.forFile(virtualFile).isPy3K()) {
if ("raw_input".equals(name)) {
registerProblem(node.getCallee(), PyBundle.message("INSP.method.$0.removed.use.$1", name, "input"),
new ReplaceMethodQuickFix("input"));
} else if (REMOVED_METHODS.contains(name)) {
registerProblem(node.getCallee(), PyBundle.message("INSP.method.$0.removed", name));
}
} else {
if ("super".equals(name)) {
PyArgumentList argumentList = node.getArgumentList();
if (argumentList != null && argumentList.getArguments().length == 0) {
registerProblem(node, "super() should have arguments in current language version");
public void visitPyImportStatement(PyImportStatement node) {
if (isPy3K(node)) {
PyImportElement[] importElements = node.getImportElements();
for (PyImportElement importElement : importElements) {
PyReferenceExpression importReference = importElement.getImportReference();
if (importReference != null) {
String name = importReference.getName();
if ("__builtin__".equals(name)) {
registerProblem(node, "Module __builtin__ renamed to builtins");
}
}
}
}
}
@Override
public void visitPyCallExpression(PyCallExpression node) {
if (isPy3K(node)) {
String name = node.getCallee().getName();
if ("raw_input".equals(name)) {
registerProblem(node.getCallee(), PyBundle.message("INSP.method.$0.removed.use.$1", name, "input"),
new ReplaceMethodQuickFix("input"));
} else if (REMOVED_METHODS.contains(name)) {
registerProblem(node.getCallee(), PyBundle.message("INSP.method.$0.removed", name));
}
}
}
}
}

View File

@@ -1,9 +1,14 @@
package com.jetbrains.python.psi;
import java.util.List;
/**
* Dict comprehension: {x:x+1 for x in range(10)}
*
* @author yole
*/
public interface PyDictCompExpression extends PyExpression, NameDefiner {
PyExpression getResultExpression();
List<ComprhForComponent> getForComponents();
List<ComprhIfComponent> getIfComponents();
}

View File

@@ -217,4 +217,8 @@ public class PyElementVisitor extends PsiElementVisitor {
public void visitPyReprExpression(PyReprExpression node) {
visitPyExpression(node);
}
public void visitPyNonlocalStatement(PyNonlocalStatement node) {
visitPyStatement(node);
}
}

View File

@@ -4,4 +4,5 @@ package com.jetbrains.python.psi;
* @author yole
*/
public interface PyNonlocalStatement extends PyStatement {
void accept(PyElementVisitor visitor);
}

View File

@@ -1,9 +1,13 @@
package com.jetbrains.python.psi;
import org.jetbrains.annotations.Nullable;
/**
* Represents a Python 3 set literal expression, for example, <tt>{1, 2, 3}</tt>
*
* @author yole
*/
public interface PySetLiteralExpression extends PyExpression {
@Nullable
PyExpression[] getElements();
}

View File

@@ -1,6 +1,7 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
import com.jetbrains.python.psi.PyElementVisitor;
import com.jetbrains.python.psi.PyNonlocalStatement;
/**
@@ -10,4 +11,8 @@ public class PyNonlocalStatementImpl extends PyElementImpl implements PyNonlocal
public PyNonlocalStatementImpl(ASTNode astNode) {
super(astNode);
}
public void accept(PyElementVisitor visitor) {
visitor.visitPyNonlocalStatement(this);
}
}

View File

@@ -1,9 +1,12 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.PyElementVisitor;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PySetLiteralExpression;
import com.jetbrains.python.psi.types.PyType;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
@@ -21,4 +24,9 @@ public class PySetLiteralExpressionImpl extends PyElementImpl implements PySetLi
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
pyVisitor.visitPySetLiteralExpression(this);
}
@Nullable
public PyExpression[] getElements() {
return PsiTreeUtil.getChildrenOfType(this, PyExpression.class);
}
}

View File

@@ -0,0 +1,91 @@
package com.jetbrains.python.validation;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.jetbrains.python.codeInsight.intentions.ConvertDictCompIntention;
import com.jetbrains.python.codeInsight.intentions.ConvertSetLiteralIntention;
import com.jetbrains.python.codeInsight.intentions.ReplaceBuiltinsIntention;
import com.jetbrains.python.codeInsight.intentions.ReplaceExceptPartIntention;
import com.jetbrains.python.psi.*;
/**
* Created by IntelliJ IDEA.
* User: Alexey.Ivanov
* Date: 16.02.2010
* Time: 16:16:45
*/
public class UnsupportedFeaturesIn2 extends PyAnnotator {
private static boolean isPy2(PyElement node) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
return virtualFile != null && !LanguageLevel.forFile(virtualFile).isPy3K();
}
private static boolean isPy3K(PyElement node) {
VirtualFile virtualFile = node.getContainingFile().getVirtualFile();
return virtualFile != null && LanguageLevel.forFile(virtualFile).isPy3K();
}
@Override
public void visitPyDictCompExpression(PyDictCompExpression node) {
if (isPy2(node)) {
getHolder().createWarningAnnotation(node, "Dictionary comprehension not supported in Python2").registerFix(new ConvertDictCompIntention());
}
}
@Override
public void visitPySetLiteralExpression(PySetLiteralExpression node) {
if (isPy2(node)) {
getHolder().createWarningAnnotation(node, "Python2 not supported set literal expressions").registerFix(new ConvertSetLiteralIntention());
}
}
@Override
public void visitPyExceptBlock(PyExceptPart node) {
if (isPy2(node)) {
PyExpression exceptClass = node.getExceptClass();
if (exceptClass != null) {
PsiElement element = exceptClass.getNextSibling();
while (element instanceof PsiWhiteSpace) {
element = element.getNextSibling();
}
if (element != null && "as".equals(element.getText())) {
getHolder().createWarningAnnotation(node, "Python2 not supported such syntax").registerFix(new ReplaceExceptPartIntention());
}
}
}
}
@Override
public void visitPyImportStatement(PyImportStatement node) {
if (isPy2(node)) {
PyImportElement[] importElements = node.getImportElements();
for (PyImportElement importElement : importElements) {
PyReferenceExpression importReference = importElement.getImportReference();
if (importReference != null) {
String name = importReference.getName();
if ("builtins".equals(name)) {
getHolder().createWarningAnnotation(node, "There is no module builtins in Python2").registerFix(new ReplaceBuiltinsIntention());
}
}
}
}
}
@Override
public void visitPyCallExpression(PyCallExpression node) {
if (isPy2(node)) {
PsiElement firstChild = node.getFirstChild();
if (firstChild != null) {
String name = firstChild.getText();
if ("super".equals(name)) {
PyArgumentList argumentList = node.getArgumentList();
if (argumentList != null && argumentList.getArguments().length == 0) {
getHolder().createWarningAnnotation(node, "super() should have arguments in Python2");
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
<warning descr="Dictionary comprehension not supported in Python2">{k: v for k, v in stuff}</warning>
try:
pass
<warning descr="Python2 not supported such syntax">except a as name:
pass</warning>
class A(B):
def foo(self):
<warning descr="super() should have arguments in Python2">super()</warning>
<warning descr="Python2 not supported set literal expressions">{1, 2}</warning>

View File

@@ -0,0 +1 @@
import __builtin__

View File

@@ -0,0 +1 @@
dict([(k, chr(k + 65)) for k in range(10)])

View File

@@ -0,0 +1 @@
set([1, 2, 3, 5, 34])

View File

@@ -0,0 +1,4 @@
try:
pass
except e, name:
pass

View File

@@ -0,0 +1 @@
import <caret>builtins

View File

@@ -0,0 +1 @@
{k: chr(k + 65)<caret> for k in range(10)}

View File

@@ -0,0 +1 @@
{1, 2, 3,<caret> 5, 34}

View File

@@ -0,0 +1,4 @@
try:
pass
except e as<caret> name:
pass

View File

@@ -0,0 +1,41 @@
package com.jetbrains.python;
import com.intellij.codeInsight.intention.IntentionAction;
import com.jetbrains.python.fixtures.PyLightFixtureTestCase;
/**
* Created by IntelliJ IDEA.
* User: Alexey.Ivanov
* Date: 25.02.2010
* Time: 12:45:53
*/
public class PyIntentionTest extends PyLightFixtureTestCase {
private void doTest(String hint) throws Exception {
myFixture.configureByFile("before" + getTestName(false) + ".py");
final IntentionAction action = myFixture.findSingleIntention(hint);
myFixture.launchAction(action);
myFixture.checkResultByFile("after" + getTestName(false) + ".py");
}
protected String getTestDataPath() {
return PythonTestUtil.getTestDataPath() + "/intentions/";
}
public void testConvertDictComp() throws Exception {
doTest(PyBundle.message("INTN.convert.dict.comp.to"));
}
public void testConvertSetLiteral() throws Exception {
doTest(PyBundle.message("INTN.convert.set.literal.to"));
}
public void testReplaceExceptPart() throws Exception {
doTest(PyBundle.message("INTN.convert.except.to"));
}
public void testConvertBuiltins() throws Exception {
doTest(PyBundle.message("INTN.convert.builtin.import"));
}
}

View File

@@ -107,6 +107,10 @@ public class PythonHighlightingTest extends PyLightFixtureTestCase {
doTest();
}
public void testUnsupportedFeaturesInPython2() throws Exception {
doTest(LanguageLevel.PYTHON26, true, false);
}
public void testYieldInNestedFunction() throws Exception {
// highlight func declaration first, lest we get an "Extra fragment highlighted" error.
EditorColorsManager manager = EditorColorsManager.getInstance();