/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jetbrains.python.validation; import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.sdk.PythonSdkType; import static com.jetbrains.python.PyBundle.message; /** * @author yole */ public class AssignTargetAnnotator extends PyAnnotator { private enum Operation { Assign, AugAssign, Delete, Except, For, With } @Override public void visitPyAssignmentStatement(final PyAssignmentStatement node) { for (PyExpression expression : node.getRawTargets()) { expression.accept(new ExprVisitor(Operation.Assign)); } } @Override public void visitPyAugAssignmentStatement(final PyAugAssignmentStatement node) { node.getTarget().accept(new ExprVisitor(Operation.AugAssign)); } @Override public void visitPyDelStatement(final PyDelStatement node) { ExprVisitor visitor = new ExprVisitor(Operation.Delete); for (PyExpression expr : node.getTargets()) { expr.accept(visitor); } } @Override public void visitPyExceptBlock(final PyExceptPart node) { PyExpression target = node.getTarget(); if (target != null) { target.accept(new ExprVisitor(Operation.Except)); } } @Override public void visitPyForStatement(final PyForStatement node) { PyExpression target = node.getForPart().getTarget(); if (target != null) { target.accept(new ExprVisitor(Operation.For)); } } @Override public void visitPyWithItem(PyWithItem node) { PyExpression target = node.getTarget(); if (target != null) { target.accept(new ExprVisitor(Operation.With)); } } private class ExprVisitor extends PyElementVisitor { private final Operation myOp; private final String DELETING_NONE = message("ANN.deleting.none"); private final String ASSIGNMENT_TO_NONE = message("ANN.assign.to.none"); private final String CANT_ASSIGN_TO_FUNCTION_CALL = message("ANN.cant.assign.to.call"); private final String CANT_DELETE_FUNCTION_CALL = message("ANN.cant.delete.call"); public ExprVisitor(Operation op) { myOp = op; } @Override public void visitPyReferenceExpression(final PyReferenceExpression node) { String referencedName = node.getReferencedName(); if (PyNames.NONE.equals(referencedName)) { getHolder().createErrorAnnotation(node, (myOp == Operation.Delete) ? DELETING_NONE : ASSIGNMENT_TO_NONE); } } @Override public void visitPyTargetExpression(final PyTargetExpression node) { String targetName = node.getName(); if (PyNames.NONE.equals(targetName)) { final VirtualFile vfile = node.getContainingFile().getVirtualFile(); if (vfile != null && !vfile.getUrl().contains("/" + PythonSdkType.SKELETON_DIR_NAME + "/")){ getHolder().createErrorAnnotation(node, (myOp == Operation.Delete) ? DELETING_NONE : ASSIGNMENT_TO_NONE); } } if (PyNames.DEBUG.equals(targetName)) { if (LanguageLevel.forElement(node).isPy3K()) { getHolder().createErrorAnnotation(node, "assignment to keyword"); } else { getHolder().createErrorAnnotation(node, "cannot assign to __debug__"); } } } @Override public void visitPyCallExpression(final PyCallExpression node) { getHolder().createErrorAnnotation(node, (myOp == Operation.Delete) ? CANT_DELETE_FUNCTION_CALL : CANT_ASSIGN_TO_FUNCTION_CALL); } @Override public void visitPyGeneratorExpression(final PyGeneratorExpression node) { getHolder().createErrorAnnotation(node, message( myOp == Operation.AugAssign ? "ANN.cant.aug.assign.to.generator" : "ANN.cant.assign.to.generator")); } @Override public void visitPyBinaryExpression(final PyBinaryExpression node) { getHolder().createErrorAnnotation(node, message("ANN.cant.assign.to.operator")); } @Override public void visitPyTupleExpression(final PyTupleExpression node) { if (node.isEmpty()) { getHolder().createErrorAnnotation(node, message("ANN.cant.assign.to.parens")); } else if (myOp == Operation.AugAssign) { getHolder().createErrorAnnotation(node, message("ANN.cant.aug.assign.to.tuple.or.generator")); } else { node.acceptChildren(this); } } @Override public void visitPyParenthesizedExpression(final PyParenthesizedExpression node) { if (myOp == Operation.AugAssign) { getHolder().createErrorAnnotation(node, message("ANN.cant.aug.assign.to.tuple.or.generator")); } else { node.acceptChildren(this); } } @Override public void visitPyListLiteralExpression(final PyListLiteralExpression node) { if (node.isEmpty()) { getHolder().createErrorAnnotation(node, message("ANN.cant.assign.to.brackets")); } else if (myOp == Operation.AugAssign) { getHolder().createErrorAnnotation(node, message("ANN.cant.aug.assign.to.list.or.comprh")); } else { node.acceptChildren(this); } } @Override public void visitPyListCompExpression(final PyListCompExpression node) { markError(node, message(myOp == Operation.AugAssign ? "ANN.cant.aug.assign.to.comprh" : "ANN.cant.assign.to.comprh")); } @Override public void visitPyDictCompExpression(PyDictCompExpression node) { markError(node, message(myOp == Operation.AugAssign ? "ANN.cant.aug.assign.to.dict.comprh" : "ANN.cant.assign.to.dict.comprh")); } @Override public void visitPySetCompExpression(PySetCompExpression node) { markError(node, message(myOp == Operation.AugAssign ? "ANN.cant.aug.assign.to.set.comprh" : "ANN.cant.assign.to.set.comprh")); } @Override public void visitPyStarExpression(PyStarExpression node) { super.visitPyStarExpression(node); if (!(node.getParent() instanceof PySequenceExpression)) { markError(node, "starred assignment target must be in a list or tuple"); } } @Override public void visitPyDictLiteralExpression(PyDictLiteralExpression node) { checkLiteral(node); } @Override public void visitPySetLiteralExpression(PySetLiteralExpression node) { checkLiteral(node); } public void visitPyNumericLiteralExpression(final PyNumericLiteralExpression node) { checkLiteral(node); } public void visitPyStringLiteralExpression(final PyStringLiteralExpression node) { checkLiteral(node); } private void checkLiteral(PyExpression node) { getHolder().createErrorAnnotation(node, message(myOp == Operation.Delete? "ANN.cant.delete.literal" : "ANN.cant.assign.to.literal")); } public void visitPyLambdaExpression(final PyLambdaExpression node) { getHolder().createErrorAnnotation(node, message("ANN.cant.assign.to.lambda")); } @Override public void visitPyNoneLiteralExpression(PyNoneLiteralExpression node) { getHolder().createErrorAnnotation(node, "assignment to keyword"); } @Override public void visitPyBoolLiteralExpression(PyBoolLiteralExpression node) { getHolder().createErrorAnnotation(node, "assignment to keyword"); } } }