blob: 156d6c4ea2d27365b9a1c60f952e3999fc37d9a3 [file] [log] [blame]
/*
* 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");
}
}
}