| /* |
| * Copyright 2000-2013 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.getElements().length == 0) { |
| 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.getElements().length == 0) { |
| 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"); |
| } |
| } |
| } |