mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
correctly parse default values for tuple parameters (PY-350)
This commit is contained in:
@@ -102,6 +102,7 @@ public class FunctionParsing extends Parsing {
|
||||
}
|
||||
else if (myBuilder.getTokenType() == PyTokenTypes.LPAR) {
|
||||
parseParameterSubList();
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
myBuilder.error(message("PARSE.expected.comma.lpar.rpar"));
|
||||
@@ -168,6 +169,10 @@ public class FunctionParsing extends Parsing {
|
||||
}
|
||||
myBuilder.advanceLexer();
|
||||
}
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.EQ) {
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
}
|
||||
tuple.done(PyElementTypes.TUPLE_PARAMETER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class PyFileElementType extends IStubFileElementType {
|
||||
|
||||
@Override
|
||||
public int getStubVersion() {
|
||||
return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,26 +1,9 @@
|
||||
/*
|
||||
* Copyright 2005 Pythonid Project
|
||||
*
|
||||
* 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.psi;
|
||||
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.StubBasedPsiElement;
|
||||
import com.jetbrains.python.psi.stubs.PyNamedParameterStub;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a named parameter, as opposed to a tuple parameter.
|
||||
@@ -30,9 +13,6 @@ public interface PyNamedParameter extends PyParameter, PyElement, PsiNamedElemen
|
||||
|
||||
boolean isKeywordContainer();
|
||||
|
||||
@Nullable
|
||||
PyExpression getDefaultValue();
|
||||
|
||||
/**
|
||||
* @param includeDefaultValue if true, include the default value after an " = ".
|
||||
* @return Canonical representation of parameter. Includes asterisks for *param and **param, and name.
|
||||
|
||||
@@ -21,4 +21,7 @@ public interface PyParameter extends PyElement {
|
||||
*/
|
||||
@Nullable
|
||||
PyTupleParameter getAsTuple();
|
||||
|
||||
@Nullable
|
||||
PyExpression getDefaultValue();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyNamedParameter;
|
||||
import com.jetbrains.python.psi.PySingleStarParameter;
|
||||
import com.jetbrains.python.psi.PyTupleParameter;
|
||||
@@ -34,4 +35,8 @@ public class PySingleStarParameterImpl extends PyPresentableElementImpl<PySingle
|
||||
public PyTupleParameter getAsTuple() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PyExpression getDefaultValue() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,7 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.stubs.IStubElementType;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyNamedParameter;
|
||||
import com.jetbrains.python.psi.PyParameter;
|
||||
import com.jetbrains.python.psi.PyTupleParameter;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.stubs.PyTupleParameterStub;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -38,6 +35,14 @@ public class PyTupleParameterImpl extends PyPresentableElementImpl<PyTupleParame
|
||||
return this;
|
||||
}
|
||||
|
||||
public PyExpression getDefaultValue() {
|
||||
ASTNode[] nodes = getNode().getChildren(PyElementTypes.EXPRESSIONS);
|
||||
if (nodes.length > 0) {
|
||||
return (PyExpression)nodes[0].getPsi();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
|
||||
throw new IncorrectOperationException("Can't rename a tuple parameter to '" + name +"'");
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public class ParameterListAnnotator extends PyAnnotator {
|
||||
boolean hadDefaultValue = false;
|
||||
boolean hadSingleStar = false;
|
||||
boolean hadParamsAfterSingleStar = false;
|
||||
int inTuple = 0;
|
||||
@Override
|
||||
public void visitNamedParameter(PyNamedParameter parameter, boolean first, boolean last) {
|
||||
if (parameterNames.contains(parameter.getName())) {
|
||||
@@ -55,7 +56,7 @@ public class ParameterListAnnotator extends PyAnnotator {
|
||||
hadDefaultValue = true;
|
||||
}
|
||||
else {
|
||||
if (hadDefaultValue && !hadSingleStar && (!languageLevel.isPy3K() || !hadPositionalContainer)) {
|
||||
if (hadDefaultValue && !hadSingleStar && (!languageLevel.isPy3K() || !hadPositionalContainer) && inTuple == 0) {
|
||||
markError(parameter, PyBundle.message("ANN.non.default.param.after.default"));
|
||||
}
|
||||
}
|
||||
@@ -64,10 +65,18 @@ public class ParameterListAnnotator extends PyAnnotator {
|
||||
|
||||
@Override
|
||||
public void enterTupleParameter(PyTupleParameter param, boolean first, boolean last) {
|
||||
super.enterTupleParameter(param, first, last);
|
||||
inTuple++;
|
||||
if (languageLevel.isPy3K()) {
|
||||
markError(param, PyBundle.message("ANN.tuple.py3"));
|
||||
}
|
||||
else if (param.getDefaultValue() == null && hadDefaultValue) {
|
||||
markError(param, PyBundle.message("ANN.non.default.param.after.default"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveTupleParameter(PyTupleParameter param, boolean first, boolean last) {
|
||||
inTuple--;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
def comp_args(a=2, (b, c)=(3, 4)):
|
||||
return a, b, c
|
||||
@@ -0,0 +1,2 @@
|
||||
def comp_args((a, b)=(3, 4)):
|
||||
return a, b
|
||||
@@ -0,0 +1,41 @@
|
||||
PyFile:DefaultTupleArguments.py
|
||||
PyFunction('comp_args')
|
||||
PsiElement(Py:DEF_KEYWORD)('def')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('comp_args')
|
||||
PyParameterList
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyTupleParameter
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyNamedParameter('a')
|
||||
PsiElement(Py:IDENTIFIER)('a')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNamedParameter('b')
|
||||
PsiElement(Py:IDENTIFIER)('b')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PyParenthesizedExpression
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyTupleExpression
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('3')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('4')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyReturnStatement
|
||||
PsiElement(Py:RETURN_KEYWORD)('return')
|
||||
PsiWhiteSpace(' ')
|
||||
PyTupleExpression
|
||||
PyReferenceExpression: a
|
||||
PsiElement(Py:IDENTIFIER)('a')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: b
|
||||
PsiElement(Py:IDENTIFIER)('b')
|
||||
@@ -0,0 +1 @@
|
||||
def foo((a, b), (c, d)): pass
|
||||
@@ -0,0 +1,33 @@
|
||||
PyFile:TupleArguments.py
|
||||
PyFunction('foo')
|
||||
PsiElement(Py:DEF_KEYWORD)('def')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('foo')
|
||||
PyParameterList
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyTupleParameter
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyNamedParameter('a')
|
||||
PsiElement(Py:IDENTIFIER)('a')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNamedParameter('b')
|
||||
PsiElement(Py:IDENTIFIER)('b')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyTupleParameter
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyNamedParameter('c')
|
||||
PsiElement(Py:IDENTIFIER)('c')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNamedParameter('d')
|
||||
PsiElement(Py:IDENTIFIER)('d')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
@@ -91,6 +91,10 @@ public class PythonHighlightingTest extends PyLightFixtureTestCase {
|
||||
doTest(LanguageLevel.PYTHON26, true, true);
|
||||
}
|
||||
|
||||
public void testArgumentList() throws Exception {
|
||||
doTest(true, false);
|
||||
}
|
||||
|
||||
public void testRegularAfterVarArgs() throws Exception {
|
||||
doTest(LanguageLevel.PYTHON30, true, false);
|
||||
}
|
||||
|
||||
@@ -162,6 +162,15 @@ public class PythonParsingTest extends ParsingTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTupleArguments() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
public void testDefaultTupleArguments() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void doTest() throws Exception {
|
||||
doTest(LanguageLevel.PYTHON25);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user