mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -136,7 +136,8 @@ class PyDBCommandThread(PyDBDaemonThread):
|
||||
if self.killReceived:
|
||||
return
|
||||
|
||||
threading.settrace(None) # no debugging on this thread
|
||||
|
||||
self.pyDb.SetTrace(None) # no debugging on this thread
|
||||
|
||||
try:
|
||||
while not self.killReceived:
|
||||
@@ -164,7 +165,7 @@ class PyDBCheckAliveThread(PyDBDaemonThread):
|
||||
self.setName('pydevd.CheckAliveThread')
|
||||
|
||||
def OnRun(self):
|
||||
pydevd_tracing.SetTrace(None) # no debugging on this thread
|
||||
self.pyDb.SetTrace(None) # no debugging on this thread
|
||||
while True:
|
||||
if not self.pyDb.haveAliveThreads():
|
||||
pydev_log.debug("No alive threads, finishing debug session")
|
||||
@@ -203,7 +204,7 @@ class NewThreadStartup:
|
||||
|
||||
def __call__(self):
|
||||
global_debugger = GetGlobalDebugger()
|
||||
pydevd_tracing.SetTrace(global_debugger.trace_dispatch)
|
||||
global_debugger.SetTrace(global_debugger.trace_dispatch)
|
||||
self.original_func(*self.args, **self.kwargs)
|
||||
|
||||
thread.NewThreadStartup = NewThreadStartup
|
||||
@@ -277,6 +278,7 @@ class PyDB:
|
||||
self._finishDebuggingSession = False
|
||||
self.force_post_mortem_stop = 0
|
||||
self.signature_factory = None
|
||||
self.SetTrace = pydevd_tracing.SetTrace
|
||||
|
||||
#this is a dict of thread ids pointing to thread ids. Whenever a command is passed to the java end that
|
||||
#acknowledges that a thread was created, the thread id should be passed here -- and if at some time we do not
|
||||
|
||||
@@ -6,4 +6,5 @@ package com.jetbrains.python.psi;
|
||||
* @author yole
|
||||
*/
|
||||
public interface PyNoneLiteralExpression extends PyLiteralExpression {
|
||||
boolean isEllipsis();
|
||||
}
|
||||
|
||||
@@ -81,6 +81,8 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
myMainDebugger.waitForConnect();
|
||||
|
||||
|
||||
disposeAcceptor();
|
||||
|
||||
myDebugProcessAcceptor = new DebuggerProcessAcceptor(this, myServerSocket);
|
||||
ApplicationManager.getApplication().executeOnPooledThread(myDebugProcessAcceptor);
|
||||
}
|
||||
@@ -109,15 +111,34 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for (ProcessDebugger d : allDebuggers()) {
|
||||
d.close();
|
||||
}
|
||||
disposeAcceptor();
|
||||
}
|
||||
|
||||
private List<RemoteDebugger> allDebuggers() {
|
||||
List<RemoteDebugger> result = Lists.newArrayList(myMainDebugger);
|
||||
synchronized (myOtherDebuggers) {
|
||||
result.addAll(myOtherDebuggers);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
myMainDebugger.disconnect();
|
||||
for (ProcessDebugger d : Lists.newArrayList(myOtherDebuggers)) {
|
||||
for (ProcessDebugger d : allDebuggers()) {
|
||||
d.disconnect();
|
||||
}
|
||||
disposeAcceptor();
|
||||
}
|
||||
|
||||
private void disposeAcceptor() {
|
||||
if (myDebugProcessAcceptor != null) {
|
||||
myDebugProcessAcceptor.disconnect();
|
||||
myDebugProcessAcceptor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +251,7 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
|
||||
private void cleanOtherDebuggers() {
|
||||
synchronized (myOtherDebuggers) {
|
||||
removeDisconnected(Lists.newArrayList(myOtherDebuggers));
|
||||
removeDisconnected(getOtherDebuggers());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,13 +270,15 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
}
|
||||
}
|
||||
|
||||
myOtherDebuggers.clear();
|
||||
myOtherDebuggers.addAll(newList);
|
||||
synchronized (myOtherDebuggers) {
|
||||
myOtherDebuggers.clear();
|
||||
myOtherDebuggers.addAll(newList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectAndRegisterOtherDebuggersThreads(List<PyThreadInfo> threads) {
|
||||
for (RemoteDebugger d : Lists.newArrayList(myOtherDebuggers)) {
|
||||
for (RemoteDebugger d : getOtherDebuggers()) {
|
||||
threads.addAll(d.getThreads());
|
||||
for (PyThreadInfo t : d.getThreads()) {
|
||||
myThreadRegistry.register(t.getId(), d);
|
||||
@@ -263,19 +286,23 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<RemoteDebugger> getOtherDebuggers() {
|
||||
synchronized (myOtherDebuggers) {
|
||||
return Lists.newArrayList(myOtherDebuggers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull AbstractCommand command) {
|
||||
myMainDebugger.execute(command);
|
||||
for (ProcessDebugger d : Lists.newArrayList(myOtherDebuggers)) {
|
||||
for (ProcessDebugger d : allDebuggers()) {
|
||||
d.execute(command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suspendAllThreads() {
|
||||
myMainDebugger.suspendAllThreads();
|
||||
for (ProcessDebugger d : myOtherDebuggers) {
|
||||
for (ProcessDebugger d : allDebuggers()) {
|
||||
d.suspendAllThreads();
|
||||
}
|
||||
}
|
||||
@@ -285,14 +312,6 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
debugger(threadId).suspendThread(threadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
myMainDebugger.close();
|
||||
for (ProcessDebugger d : Lists.newArrayList(myOtherDebuggers)) {
|
||||
d.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() throws PyDebuggerException {
|
||||
myMainDebugger.run();
|
||||
@@ -310,32 +329,28 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
|
||||
@Override
|
||||
public void setTempBreakpoint(String type, String file, int line) {
|
||||
myMainDebugger.setTempBreakpoint(type, file, line);
|
||||
for (ProcessDebugger d : myOtherDebuggers) {
|
||||
for (ProcessDebugger d : allDebuggers()) {
|
||||
d.setTempBreakpoint(type, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTempBreakpoint(String file, int line) {
|
||||
myMainDebugger.removeTempBreakpoint(file, line);
|
||||
for (ProcessDebugger d : myOtherDebuggers) {
|
||||
for (ProcessDebugger d : allDebuggers()) {
|
||||
d.removeTempBreakpoint(file, line);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBreakpoint(String typeId, String file, int line, String condition, String logExpression) {
|
||||
myMainDebugger.setBreakpoint(typeId, file, line, condition, logExpression);
|
||||
for (ProcessDebugger d : myOtherDebuggers) {
|
||||
for (ProcessDebugger d : allDebuggers()) {
|
||||
d.setBreakpoint(typeId, file, line, condition, logExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBreakpoint(String typeId, String file, int line) {
|
||||
myMainDebugger.removeBreakpoint(typeId, file, line);
|
||||
for (ProcessDebugger d : Lists.newArrayList(myOtherDebuggers)) {
|
||||
for (ProcessDebugger d : allDebuggers()) {
|
||||
d.removeBreakpoint(typeId, file, line);
|
||||
}
|
||||
}
|
||||
@@ -428,8 +443,9 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
myServerSocket = null;
|
||||
myShouldAccept = false;
|
||||
}
|
||||
myShouldAccept = false;
|
||||
myMultiProcessDebugger = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,18 +466,14 @@ public class MultiProcessDebugger implements ProcessDebugger {
|
||||
|
||||
@Override
|
||||
public void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory) {
|
||||
myMainDebugger.execute(factory.createAddCommand(myMainDebugger));
|
||||
|
||||
for (RemoteDebugger d : Lists.newArrayList(myOtherDebuggers)) {
|
||||
for (RemoteDebugger d : allDebuggers()) {
|
||||
d.execute(factory.createAddCommand(d));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeExceptionBreakpoint(ExceptionBreakpointCommandFactory factory) {
|
||||
myMainDebugger.execute(factory.createRemoveCommand(myMainDebugger));
|
||||
|
||||
for (RemoteDebugger d : Lists.newArrayList(myOtherDebuggers)) {
|
||||
for (RemoteDebugger d : allDebuggers()) {
|
||||
d.execute(factory.createRemoveCommand(d));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,6 @@ import java.util.List;
|
||||
* @author traff
|
||||
*/
|
||||
public interface ProcessDebugger {
|
||||
boolean isConnected();
|
||||
|
||||
void waitForConnect() throws Exception;
|
||||
|
||||
void disconnect();
|
||||
|
||||
String handshake() throws PyDebuggerException;
|
||||
|
||||
PyDebugValue evaluate(String threadId,
|
||||
@@ -55,8 +49,20 @@ public interface ProcessDebugger {
|
||||
|
||||
void suspendThread(String threadId);
|
||||
|
||||
/**
|
||||
* Disconnects current debug process. Closes all resources.
|
||||
*/
|
||||
void close();
|
||||
|
||||
boolean isConnected();
|
||||
|
||||
void waitForConnect() throws Exception;
|
||||
|
||||
/**
|
||||
* Disconnects currently connected process. After that it can wait for the next.
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
void run() throws PyDebuggerException;
|
||||
|
||||
void smartStepInto(String threadId, String functionName);
|
||||
|
||||
@@ -96,23 +96,6 @@ public class RemoteDebugger implements ProcessDebugger {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
synchronized (mySocketObject) {
|
||||
myConnected = false;
|
||||
|
||||
if (mySocket != null && !mySocket.isClosed()) {
|
||||
try {
|
||||
mySocket.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handshake() throws PyDebuggerException {
|
||||
final VersionCommand command = new VersionCommand(this, LOCAL_VERSION, SystemInfo.isUnix ? "UNIX" : "WIN");
|
||||
@@ -366,6 +349,23 @@ public class RemoteDebugger implements ProcessDebugger {
|
||||
fireCloseEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
synchronized (mySocketObject) {
|
||||
myConnected = false;
|
||||
|
||||
if (mySocket != null && !mySocket.isClosed()) {
|
||||
try {
|
||||
mySocket.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() throws PyDebuggerException {
|
||||
new RunCommand(this).execute();
|
||||
|
||||
+2
-3
@@ -3,7 +3,6 @@ package com.jetbrains.python.codeInsight.stdlib;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.codeInsight.PyDynamicMember;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
@@ -24,10 +23,10 @@ public class PyStdlibModuleMembersProvider extends PyModuleMembersProvider {
|
||||
if (qName.equals("os")) {
|
||||
final List<PyDynamicMember> results = new ArrayList<PyDynamicMember>();
|
||||
PsiElement path = null;
|
||||
PyClass osError = null;
|
||||
PsiElement osError = null;
|
||||
if (module != null) {
|
||||
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(module);
|
||||
osError = builtinCache.getClass("OSError");
|
||||
osError = builtinCache.getByName("OSError");
|
||||
|
||||
final String pathModuleName = SystemInfo.isWindows ? "ntpath" : "posixpath";
|
||||
path = ResolveImportUtil.resolveModuleInRoots(PyQualifiedName.fromDottedString(pathModuleName), module);
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import icons.PythonIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -53,6 +54,9 @@ public class PythonDebugLanguageConsoleView extends JPanel implements ConsoleVie
|
||||
add(myPydevConsoleView.getComponent(), PYDEV_CONSOLE_PANEL);
|
||||
|
||||
showDebugConsole(PyConsoleOptionsProvider.getInstance(project).isShowDebugConsoleByDefault());
|
||||
|
||||
Disposer.register(this, myPydevConsoleView);
|
||||
Disposer.register(this, myTextConsole);
|
||||
}
|
||||
|
||||
public PythonDebugLanguageConsoleView(final Project project, Sdk sdk) {
|
||||
@@ -249,4 +253,6 @@ public class PythonDebugLanguageConsoleView extends JPanel implements ConsoleVie
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
/**
|
||||
* User: catherine
|
||||
*
|
||||
* Inspection to detect assignment that can be replaced with augmented assignment.
|
||||
* Inspection to detect assignments that can be replaced with augmented assignments.
|
||||
*/
|
||||
public class PyAugmentAssignmentInspection extends PyInspection {
|
||||
@Nls
|
||||
@@ -43,15 +43,18 @@ public class PyAugmentAssignmentInspection extends PyInspection {
|
||||
|
||||
@Override
|
||||
public void visitPyAssignmentStatement(final PyAssignmentStatement node) {
|
||||
if (node.getAssignedValue() instanceof PyBinaryExpression) {
|
||||
final PyExpression value = node.getAssignedValue();
|
||||
if (value instanceof PyBinaryExpression) {
|
||||
final PyExpression target = node.getLeftHandSideExpression();
|
||||
final PyBinaryExpression expression = (PyBinaryExpression)node.getAssignedValue();
|
||||
if (expression == null) return;
|
||||
final PyBinaryExpression expression = (PyBinaryExpression)value;
|
||||
PyExpression leftExpression = expression.getLeftExpression();
|
||||
PyExpression rightExpression = expression.getRightExpression();
|
||||
if (rightExpression instanceof PyParenthesizedExpression)
|
||||
if (rightExpression instanceof PyParenthesizedExpression) {
|
||||
rightExpression = ((PyParenthesizedExpression)rightExpression).getContainedExpression();
|
||||
if (rightExpression == null || target == null) return;
|
||||
}
|
||||
if (rightExpression == null || target == null) {
|
||||
return;
|
||||
}
|
||||
boolean changedParts = false;
|
||||
final String targetText = target.getText();
|
||||
final String rightText = rightExpression.getText();
|
||||
@@ -64,31 +67,31 @@ public class PyAugmentAssignmentInspection extends PyInspection {
|
||||
|
||||
final PyElementType op = expression.getOperator();
|
||||
final TokenSet operations = TokenSet.create(PyTokenTypes.PLUS, PyTokenTypes.MINUS, PyTokenTypes.MULT,
|
||||
PyTokenTypes.FLOORDIV, PyTokenTypes.DIV, PyTokenTypes.PERC, PyTokenTypes.AND, PyTokenTypes.OR,
|
||||
PyTokenTypes.XOR, PyTokenTypes.LTLT, PyTokenTypes.GTGT, PyTokenTypes.EXP);
|
||||
PyTokenTypes.FLOORDIV, PyTokenTypes.DIV, PyTokenTypes.PERC, PyTokenTypes.AND,
|
||||
PyTokenTypes.OR, PyTokenTypes.XOR, PyTokenTypes.LTLT, PyTokenTypes.GTGT,
|
||||
PyTokenTypes.EXP);
|
||||
final TokenSet commutativeOperations = TokenSet.create(PyTokenTypes.PLUS, PyTokenTypes.MULT);
|
||||
if ((operations.contains(op) && !changedParts) || (changedParts && commutativeOperations.contains(op))) {
|
||||
if ((leftExpression instanceof PyReferenceExpression || leftExpression instanceof PySubscriptionExpression)) {
|
||||
if (leftExpression.getText().equals(targetText)) {
|
||||
if (rightExpression instanceof PyNumericLiteralExpression) {
|
||||
final AugmentedAssignmentQuickFix quickFix = new AugmentedAssignmentQuickFix();
|
||||
registerProblem(node, "Assignment can be replaced with augmented assignment", quickFix);
|
||||
}
|
||||
else {
|
||||
final PyType type = myTypeEvalContext.getType(rightExpression);
|
||||
if (type != null) {
|
||||
final PyBuiltinCache cache = PyBuiltinCache.getInstance(rightExpression);
|
||||
if (PyTypeChecker.match(cache.getComplexType(), type, myTypeEvalContext) ||
|
||||
(PyTypeChecker.match(cache.getStringType(LanguageLevel.forElement(rightExpression)), type,
|
||||
myTypeEvalContext) && !changedParts)) {
|
||||
registerProblem(node, "Assignment can be replaced with augmented assignment", new AugmentedAssignmentQuickFix());
|
||||
}
|
||||
}
|
||||
if (leftExpression instanceof PyReferenceExpression || leftExpression instanceof PySubscriptionExpression) {
|
||||
final PyType type = myTypeEvalContext.getType(rightExpression);
|
||||
if (type != null && !PyTypeChecker.isUnknown(type)) {
|
||||
final PyBuiltinCache cache = PyBuiltinCache.getInstance(rightExpression);
|
||||
final LanguageLevel languageLevel = LanguageLevel.forElement(rightExpression);
|
||||
if (isNumeric(type, cache) || (isString(type, cache, languageLevel) && !changedParts)) {
|
||||
registerProblem(node, "Assignment can be replaced with augmented assignment", new AugmentedAssignmentQuickFix());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isString(PyType type, PyBuiltinCache cache, LanguageLevel level) {
|
||||
return PyTypeChecker.match(cache.getStringType(level), type, myTypeEvalContext);
|
||||
}
|
||||
|
||||
private boolean isNumeric(PyType type, PyBuiltinCache cache) {
|
||||
return PyTypeChecker.match(cache.getComplexType(), type, myTypeEvalContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ public class PyCompatibilityInspection extends PyInspection {
|
||||
}
|
||||
final String errorMessage = "This syntax available only since py3";
|
||||
final boolean isPy3 = LanguageLevel.forElement(node).isPy3K();
|
||||
if (compatibleWithPy2() || !isPy3) {
|
||||
if (shouldBeCompatibleWithPy2() || !isPy3) {
|
||||
for (final PyElement problemElement : problemElements)
|
||||
myHolder.registerProblem(problemElement, errorMessage, isPy3? ProblemHighlightType.GENERIC_ERROR_OR_WARNING :
|
||||
ProblemHighlightType.GENERIC_ERROR);
|
||||
|
||||
@@ -72,6 +72,9 @@ public class ExpressionParsing extends Parsing {
|
||||
parseReprExpression(myBuilder);
|
||||
return true;
|
||||
}
|
||||
else if (parseEllipsis()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -97,7 +100,7 @@ public class ExpressionParsing extends Parsing {
|
||||
expr.done(PyElementTypes.LIST_LITERAL_EXPRESSION);
|
||||
return;
|
||||
}
|
||||
if (!parseSingleExpression(isTargetExpression, false)) {
|
||||
if (!parseSingleExpression(isTargetExpression)) {
|
||||
builder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
if (builder.getTokenType() == PyTokenTypes.FOR_KEYWORD) {
|
||||
@@ -111,7 +114,7 @@ public class ExpressionParsing extends Parsing {
|
||||
if (atToken(PyTokenTypes.RBRACKET)) {
|
||||
break;
|
||||
}
|
||||
if (!parseSingleExpression(isTargetExpression, false)) {
|
||||
if (!parseSingleExpression(isTargetExpression)) {
|
||||
builder.error(message("PARSE.expected.expr.or.comma.or.bracket"));
|
||||
break;
|
||||
}
|
||||
@@ -154,7 +157,7 @@ public class ExpressionParsing extends Parsing {
|
||||
result = parseORTestExpression(false, false);
|
||||
}
|
||||
else {
|
||||
result = parseTupleExpression(false, false, true, false);
|
||||
result = parseTupleExpression(false, false, true);
|
||||
}
|
||||
if (!result) {
|
||||
myBuilder.error("expression expected");
|
||||
@@ -172,7 +175,7 @@ public class ExpressionParsing extends Parsing {
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker firstExprMarker = myBuilder.mark();
|
||||
if (!parseSingleExpression(false, false)) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
myBuilder.error("expression expected");
|
||||
firstExprMarker.drop();
|
||||
expr.done(PyElementTypes.DICT_LITERAL_EXPRESSION);
|
||||
@@ -198,7 +201,7 @@ public class ExpressionParsing extends Parsing {
|
||||
}
|
||||
|
||||
private void parseDictLiteralTail(PsiBuilder.Marker startMarker, PsiBuilder.Marker firstKeyValueMarker) {
|
||||
if (!parseSingleExpression(false, false)) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
myBuilder.error("expression expected");
|
||||
firstKeyValueMarker.done(PyElementTypes.KEY_VALUE_EXPRESSION);
|
||||
if (atToken(PyTokenTypes.RBRACE)) {
|
||||
@@ -225,12 +228,12 @@ public class ExpressionParsing extends Parsing {
|
||||
|
||||
private boolean parseKeyValueExpression() {
|
||||
final PsiBuilder.Marker marker = myBuilder.mark();
|
||||
if (!parseSingleExpression(false, false)) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
checkMatches(PyTokenTypes.COLON, message("PARSE.expected.colon"));
|
||||
if (!parseSingleExpression(false, false)) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
myBuilder.error("value expression expected");
|
||||
marker.drop();
|
||||
return false;
|
||||
@@ -242,7 +245,7 @@ public class ExpressionParsing extends Parsing {
|
||||
private void parseSetLiteralTail(PsiBuilder.Marker startMarker) {
|
||||
while (myBuilder.getTokenType() != PyTokenTypes.RBRACE) {
|
||||
checkMatches(PyTokenTypes.COMMA, message("PARSE.expected.comma"));
|
||||
if (!parseSingleExpression(false, false)) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -325,7 +328,7 @@ public class ExpressionParsing extends Parsing {
|
||||
parseSliceEnd(expr, sliceItemStart);
|
||||
}
|
||||
else {
|
||||
boolean hadExpression = parseSingleExpression(false, true);
|
||||
boolean hadExpression = parseSingleExpression(false);
|
||||
if (atToken(PyTokenTypes.COLON)) {
|
||||
sliceOrTupleStart.drop();
|
||||
parseSliceEnd(expr, sliceItemStart);
|
||||
@@ -334,7 +337,7 @@ public class ExpressionParsing extends Parsing {
|
||||
sliceItemStart.done(PyElementTypes.SLICE_ITEM);
|
||||
if (!parseSliceListTail(expr, sliceOrTupleStart)) {
|
||||
sliceOrTupleStart.rollbackTo();
|
||||
if (!parseTupleExpression(false, false, false, true)) {
|
||||
if (!parseTupleExpression(false, false, false)) {
|
||||
myBuilder.error("tuple expression expected");
|
||||
}
|
||||
checkMatches(PyTokenTypes.RBRACKET, message("PARSE.expected.rbracket"));
|
||||
@@ -404,13 +407,13 @@ public class ExpressionParsing extends Parsing {
|
||||
sliceMarker.done(PyElementTypes.EMPTY_EXPRESSION);
|
||||
}
|
||||
else {
|
||||
parseSingleExpression(false, true);
|
||||
parseSingleExpression(false);
|
||||
}
|
||||
if (!BRACKET_COLON_COMMA.contains(myBuilder.getTokenType())) {
|
||||
myBuilder.error(message("PARSE.expected.colon.or.rbracket"));
|
||||
}
|
||||
if (matchToken(PyTokenTypes.COLON)) {
|
||||
parseSingleExpression(false, true);
|
||||
parseSingleExpression(false);
|
||||
}
|
||||
|
||||
sliceItemStart.done(PyElementTypes.SLICE_ITEM);
|
||||
@@ -427,12 +430,12 @@ public class ExpressionParsing extends Parsing {
|
||||
while (atToken(PyTokenTypes.COMMA)) {
|
||||
nextToken();
|
||||
PsiBuilder.Marker sliceItemStart = myBuilder.mark();
|
||||
parseTestExpression(false, false, true);
|
||||
parseTestExpression(false, false);
|
||||
if (matchToken(PyTokenTypes.COLON)) {
|
||||
inSlice = true;
|
||||
parseTestExpression(false, false, true);
|
||||
parseTestExpression(false, false);
|
||||
if (matchToken(PyTokenTypes.COLON)) {
|
||||
parseTestExpression(false, false, true);
|
||||
parseTestExpression(false, false);
|
||||
}
|
||||
}
|
||||
sliceItemStart.done(PyElementTypes.SLICE_ITEM);
|
||||
@@ -479,7 +482,7 @@ public class ExpressionParsing extends Parsing {
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.MULT || myBuilder.getTokenType() == PyTokenTypes.EXP) {
|
||||
final PsiBuilder.Marker starArgMarker = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
if (!parseSingleExpression(false, false)) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
starArgMarker.done(PyElementTypes.STAR_ARGUMENT_EXPRESSION);
|
||||
@@ -490,7 +493,7 @@ public class ExpressionParsing extends Parsing {
|
||||
myBuilder.advanceLexer();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.EQ) {
|
||||
myBuilder.advanceLexer();
|
||||
if (!parseSingleExpression(false, false)) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
keywordArgMarker.done(PyElementTypes.KEYWORD_ARGUMENT_EXPRESSION);
|
||||
@@ -498,7 +501,7 @@ public class ExpressionParsing extends Parsing {
|
||||
}
|
||||
keywordArgMarker.rollbackTo();
|
||||
}
|
||||
if (!parseSingleExpression(false, false)) {
|
||||
if (!parseSingleExpression(false)) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
break;
|
||||
}
|
||||
@@ -513,11 +516,11 @@ public class ExpressionParsing extends Parsing {
|
||||
}
|
||||
|
||||
public boolean parseExpressionOptional() {
|
||||
return parseTupleExpression(false, false, false, false);
|
||||
return parseTupleExpression(false, false, false);
|
||||
}
|
||||
|
||||
public boolean parseExpressionOptional(boolean isTargetExpression) {
|
||||
return parseTupleExpression(false, isTargetExpression, false, false);
|
||||
return parseTupleExpression(false, isTargetExpression, false);
|
||||
}
|
||||
|
||||
public void parseExpression() {
|
||||
@@ -527,7 +530,7 @@ public class ExpressionParsing extends Parsing {
|
||||
}
|
||||
|
||||
public void parseExpression(boolean stopOnIn, boolean isTargetExpression) {
|
||||
if (!parseTupleExpression(stopOnIn, isTargetExpression, false, false)) {
|
||||
if (!parseTupleExpression(stopOnIn, isTargetExpression, false)) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
}
|
||||
@@ -538,7 +541,7 @@ public class ExpressionParsing extends Parsing {
|
||||
myBuilder.advanceLexer();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.FROM_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
final boolean parsed = parseTupleExpression(false, isTargetExpression, false, false);
|
||||
final boolean parsed = parseTupleExpression(false, isTargetExpression, false);
|
||||
if (!parsed) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
@@ -546,19 +549,19 @@ public class ExpressionParsing extends Parsing {
|
||||
return parsed;
|
||||
}
|
||||
else {
|
||||
parseTupleExpression(false, isTargetExpression, false, false);
|
||||
parseTupleExpression(false, isTargetExpression, false);
|
||||
yieldExpr.done(PyElementTypes.YIELD_EXPRESSION);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return parseTupleExpression(false, isTargetExpression, false, false);
|
||||
return parseTupleExpression(false, isTargetExpression, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean parseTupleExpression(boolean stopOnIn, boolean isTargetExpression, final boolean oldTest, boolean allowEllipsis) {
|
||||
protected boolean parseTupleExpression(boolean stopOnIn, boolean isTargetExpression, final boolean oldTest) {
|
||||
PsiBuilder.Marker expr = myBuilder.mark();
|
||||
boolean exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression, allowEllipsis);
|
||||
boolean exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression);
|
||||
if (!exprParseResult) {
|
||||
expr.drop();
|
||||
return false;
|
||||
@@ -567,7 +570,7 @@ public class ExpressionParsing extends Parsing {
|
||||
while (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
|
||||
myBuilder.advanceLexer();
|
||||
PsiBuilder.Marker expr2 = myBuilder.mark();
|
||||
exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression, allowEllipsis);
|
||||
exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression);
|
||||
if (!exprParseResult) {
|
||||
expr2.rollbackTo();
|
||||
break;
|
||||
@@ -582,8 +585,8 @@ public class ExpressionParsing extends Parsing {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean parseSingleExpression(boolean isTargetExpression, boolean allowEllipsis) {
|
||||
return parseTestExpression(false, isTargetExpression, allowEllipsis);
|
||||
public boolean parseSingleExpression(boolean isTargetExpression) {
|
||||
return parseTestExpression(false, isTargetExpression);
|
||||
}
|
||||
|
||||
public boolean parseOldExpression() {
|
||||
@@ -593,13 +596,10 @@ public class ExpressionParsing extends Parsing {
|
||||
return parseORTestExpression(false, false);
|
||||
}
|
||||
|
||||
private boolean parseTestExpression(boolean stopOnIn, boolean isTargetExpression, boolean allowEllipsis) {
|
||||
private boolean parseTestExpression(boolean stopOnIn, boolean isTargetExpression) {
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.LAMBDA_KEYWORD) {
|
||||
return parseLambdaExpression(false);
|
||||
}
|
||||
if (allowEllipsis && parseEllipsis()) {
|
||||
return true;
|
||||
}
|
||||
PsiBuilder.Marker condExpr = myBuilder.mark();
|
||||
if (!parseORTestExpression( stopOnIn, isTargetExpression)) {
|
||||
condExpr.drop();
|
||||
@@ -616,7 +616,7 @@ public class ExpressionParsing extends Parsing {
|
||||
}
|
||||
else {
|
||||
myBuilder.advanceLexer();
|
||||
if (!parseTestExpression(stopOnIn, isTargetExpression, allowEllipsis)) {
|
||||
if (!parseTestExpression(stopOnIn, isTargetExpression)) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
}
|
||||
@@ -640,7 +640,7 @@ public class ExpressionParsing extends Parsing {
|
||||
PsiBuilder.Marker expr = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
getFunctionParser().parseParameterListContents(PyTokenTypes.COLON, false, true);
|
||||
boolean parseExpressionResult = oldTest ? parseOldTestExpression() : parseSingleExpression(false, false);
|
||||
boolean parseExpressionResult = oldTest ? parseOldTestExpression() : parseSingleExpression(false);
|
||||
if (!parseExpressionResult) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class FunctionParsing extends Parsing {
|
||||
PsiBuilder.Marker maybeReturnAnnotation = myBuilder.mark();
|
||||
nextToken();
|
||||
if (matchToken(PyTokenTypes.GT)) {
|
||||
if (!myContext.getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!myContext.getExpressionParser().parseSingleExpression(false)) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
maybeReturnAnnotation.done(PyElementTypes.ANNOTATION);
|
||||
@@ -195,13 +195,13 @@ public class FunctionParsing extends Parsing {
|
||||
if (!isLambda && myContext.getLanguageLevel().isPy3K() && atToken(PyTokenTypes.COLON)) {
|
||||
PsiBuilder.Marker annotationMarker = myBuilder.mark();
|
||||
nextToken();
|
||||
if (!getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false)) {
|
||||
myBuilder.error(message("PARSE.expected.expression"));
|
||||
}
|
||||
annotationMarker.done(PyElementTypes.ANNOTATION);
|
||||
}
|
||||
if (!isStarParameter && matchToken(PyTokenTypes.EQ)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false)) {
|
||||
PsiBuilder.Marker invalidElements = myBuilder.mark();
|
||||
while(!atAnyOfTokens(endToken, PyTokenTypes.LINE_BREAK, PyTokenTypes.COMMA, null)) {
|
||||
nextToken();
|
||||
@@ -251,7 +251,7 @@ public class FunctionParsing extends Parsing {
|
||||
}
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.EQ) {
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
}
|
||||
tuple.done(PyElementTypes.TUPLE_PARAMETER);
|
||||
}
|
||||
|
||||
@@ -278,18 +278,18 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
if (builder.getTokenType() == PyTokenTypes.GTGT) {
|
||||
final PsiBuilder.Marker target = builder.mark();
|
||||
builder.advanceLexer();
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
target.done(PyElementTypes.PRINT_TARGET);
|
||||
}
|
||||
else {
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
}
|
||||
while (builder.getTokenType() == PyTokenTypes.COMMA) {
|
||||
builder.advanceLexer();
|
||||
if (getEndOfStatementsTokens().contains(builder.getTokenType())) {
|
||||
break;
|
||||
}
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
}
|
||||
checkEndOfStatement(scope);
|
||||
statement.done(PyElementTypes.PRINT_STATEMENT);
|
||||
@@ -317,13 +317,13 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
assertCurrentToken(PyTokenTypes.DEL_KEYWORD);
|
||||
final PsiBuilder.Marker delStatement = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
if (!getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false)) {
|
||||
myBuilder.error("Expression expected");
|
||||
}
|
||||
while (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
|
||||
myBuilder.advanceLexer();
|
||||
if (!getEndOfStatementsTokens().contains(myBuilder.getTokenType())) {
|
||||
if (!getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false)) {
|
||||
myBuilder.error("Expression expected");
|
||||
}
|
||||
}
|
||||
@@ -338,18 +338,18 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
final PsiBuilder.Marker raiseStatement = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
if (!getEndOfStatementsTokens().contains(myBuilder.getTokenType())) {
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
}
|
||||
}
|
||||
else if (myBuilder.getTokenType() == PyTokenTypes.FROM_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
if (!getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false)) {
|
||||
myBuilder.error("Expression expected");
|
||||
}
|
||||
}
|
||||
@@ -362,10 +362,10 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
assertCurrentToken(PyTokenTypes.ASSERT_KEYWORD);
|
||||
final PsiBuilder.Marker assertStatement = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
if (getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (getExpressionParser().parseSingleExpression(false)) {
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
|
||||
myBuilder.advanceLexer();
|
||||
if (!getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false)) {
|
||||
myContext.getBuilder().error(EXPRESSION_EXPECTED);
|
||||
}
|
||||
}
|
||||
@@ -562,10 +562,10 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
getExpressionParser().parseExpression(true, false);
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.IN_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseSingleExpression(false, false);
|
||||
getExpressionParser().parseSingleExpression(false);
|
||||
}
|
||||
}
|
||||
checkEndOfStatement(inSuite);
|
||||
@@ -646,7 +646,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
final PsiBuilder.Marker statement = myBuilder.mark();
|
||||
final PsiBuilder.Marker whilePart = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
if (!getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false)) {
|
||||
myBuilder.error(EXPRESSION_EXPECTED);
|
||||
}
|
||||
parseColonAndSuite(scope);
|
||||
@@ -677,13 +677,13 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
final PsiBuilder.Marker exceptBlock = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
if (myBuilder.getTokenType() != PyTokenTypes.COLON) {
|
||||
if (!getExpressionParser().parseSingleExpression(false, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(false)) {
|
||||
myBuilder.error(EXPRESSION_EXPECTED);
|
||||
}
|
||||
setExpectAsKeyword(true);
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.COMMA || myBuilder.getTokenType() == PyTokenTypes.AS_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
if (!getExpressionParser().parseSingleExpression(true, false)) {
|
||||
if (!getExpressionParser().parseSingleExpression(true)) {
|
||||
myBuilder.error(EXPRESSION_EXPECTED);
|
||||
}
|
||||
}
|
||||
@@ -738,7 +738,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
setExpectAsKeyword(true);
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.AS_KEYWORD) {
|
||||
myBuilder.advanceLexer();
|
||||
getExpressionParser().parseSingleExpression(true, false); // 'as' is followed by a target
|
||||
getExpressionParser().parseSingleExpression(true); // 'as' is followed by a target
|
||||
}
|
||||
withItem.done(PyElementTypes.WITH_ITEM);
|
||||
if (!matchToken(PyTokenTypes.COMMA)) {
|
||||
|
||||
@@ -624,6 +624,23 @@ public class PyUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static AccessDirection getPropertyAccessDirection(@NotNull PyFunction function) {
|
||||
final Property property = function.getProperty();
|
||||
if (property != null) {
|
||||
if (property.getGetter().valueOrNull() == function) {
|
||||
return AccessDirection.READ;
|
||||
}
|
||||
if (property.getSetter().valueOrNull() == function) {
|
||||
return AccessDirection.WRITE;
|
||||
}
|
||||
else if (property.getDeleter().valueOrNull() == function) {
|
||||
return AccessDirection.DELETE;
|
||||
}
|
||||
}
|
||||
return AccessDirection.READ;
|
||||
}
|
||||
|
||||
public static class KnownDecoratorProviderHolder {
|
||||
public static PyKnownDecoratorProvider[] KNOWN_DECORATOR_PROVIDERS = Extensions.getExtensions(PyKnownDecoratorProvider.EP_NAME);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyNoneLiteralExpression;
|
||||
import com.jetbrains.python.psi.types.PyNoneType;
|
||||
@@ -24,4 +25,9 @@ public class PyNoneLiteralExpressionImpl extends PyElementImpl implements PyNone
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyNoneLiteralExpression(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEllipsis() {
|
||||
return getNode().findChildByType(PyTokenTypes.DOT) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.QueryExecutor;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -21,6 +20,15 @@ public class PyOverridingMethodsSearchExecutor implements QueryExecutor<PyFuncti
|
||||
PyFunction overridingMethod;
|
||||
try {
|
||||
overridingMethod = pyClass.findMethodByName(baseMethod.getName(), false);
|
||||
if (overridingMethod != null) {
|
||||
final Property baseProperty = baseMethod.getProperty();
|
||||
final Property overridingProperty = overridingMethod.getProperty();
|
||||
if (baseProperty != null && overridingProperty != null) {
|
||||
final AccessDirection direction = PyUtil.getPropertyAccessDirection(baseMethod);
|
||||
final Callable callable = overridingProperty.getByDirection(direction).valueOrNull();
|
||||
overridingMethod = (callable instanceof PyFunction) ? (PyFunction)callable : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
accessToken.finish();
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.jetbrains.python.psi.search;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.QueryExecutor;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -33,9 +32,20 @@ public class PySuperMethodsSearchExecutor implements QueryExecutor<PsiElement, P
|
||||
}
|
||||
}
|
||||
PyFunction superMethod = superClass.findMethodByName(name, false);
|
||||
if (superMethod != null) {
|
||||
final Property property = func.getProperty();
|
||||
final Property superProperty = superMethod.getProperty();
|
||||
if (property != null && superProperty != null) {
|
||||
final AccessDirection direction = PyUtil.getPropertyAccessDirection(func);
|
||||
final Callable callable = superProperty.getByDirection(direction).valueOrNull();
|
||||
superMethod = (callable instanceof PyFunction) ? (PyFunction)callable : null;
|
||||
}
|
||||
}
|
||||
if (superMethod != null) {
|
||||
foundMethodContainingClasses.add(superClass);
|
||||
if (!consumer.process(superMethod)) return false;
|
||||
if (!consumer.process(superMethod)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,6 +511,20 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyNoneLiteralExpression(PyNoneLiteralExpression node) {
|
||||
if (shouldBeCompatibleWithPy2() && node.isEllipsis()) {
|
||||
final PySubscriptionExpression subscription = PsiTreeUtil.getParentOfType(node, PySubscriptionExpression.class);
|
||||
if (subscription != null && PsiTreeUtil.isAncestor(subscription.getIndexExpression(), node, false)) {
|
||||
return;
|
||||
}
|
||||
final PySliceItem sliceItem = PsiTreeUtil.getParentOfType(node, PySliceItem.class);
|
||||
if (sliceItem != null) {
|
||||
return;
|
||||
}
|
||||
registerProblem(node, "Python versions < 3.0 do not support '...' outside of sequence slicings.");
|
||||
}
|
||||
}
|
||||
|
||||
private static class YieldVisitor extends PyElementVisitor {
|
||||
private boolean _haveYield = false;
|
||||
@@ -536,12 +550,6 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
|
||||
// do not go to nested functions
|
||||
}
|
||||
}
|
||||
private boolean shouldBeCompatibleWithPy3() {
|
||||
if (myVersionsToProcess.contains(LanguageLevel.PYTHON30) || myVersionsToProcess.contains(LanguageLevel.PYTHON31)
|
||||
|| myVersionsToProcess.contains(LanguageLevel.PYTHON32))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract void registerProblem(PsiElement node, String s, @Nullable LocalQuickFix localQuickFix, boolean asError);
|
||||
|
||||
@@ -581,13 +589,26 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
|
||||
|
||||
@Override
|
||||
public void visitPyNonlocalStatement(final PyNonlocalStatement node) {
|
||||
if (compatibleWithPy2()) {
|
||||
if (shouldBeCompatibleWithPy2()) {
|
||||
registerProblem(node, "nonlocal keyword available only since py3", null, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean compatibleWithPy2() {
|
||||
return myVersionsToProcess.contains(LanguageLevel.PYTHON24) || myVersionsToProcess.contains(LanguageLevel.PYTHON25) ||
|
||||
myVersionsToProcess.contains(LanguageLevel.PYTHON26) || myVersionsToProcess.contains(LanguageLevel.PYTHON27);
|
||||
protected boolean shouldBeCompatibleWithPy2() {
|
||||
for (LanguageLevel level : myVersionsToProcess) {
|
||||
if (level.isOlderThan(LanguageLevel.PYTHON30)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shouldBeCompatibleWithPy3() {
|
||||
for (LanguageLevel level : myVersionsToProcess) {
|
||||
if (level.isPy3K()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(c, x, y):
|
||||
if c:
|
||||
z = x
|
||||
else:
|
||||
z = ''
|
||||
y = z + y # pass
|
||||
return y
|
||||
@@ -0,0 +1,2 @@
|
||||
def foo():
|
||||
<warning descr="Python versions < 3.0 do not support '...' outside of sequence slicings.">...</warning>
|
||||
@@ -0,0 +1,5 @@
|
||||
import numpy
|
||||
|
||||
x = numpy.zeros((3, 4, 5))
|
||||
y = x[..., 0] # pass
|
||||
y = x[..., 0, :] # pass
|
||||
@@ -0,0 +1,8 @@
|
||||
class B:
|
||||
def foo(self, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
def foo(self, arg1=None, **kwargs): # pass
|
||||
pass
|
||||
@@ -0,0 +1,28 @@
|
||||
class B1:
|
||||
def foo(self, a, b):
|
||||
pass
|
||||
|
||||
|
||||
class C1(B1):
|
||||
def foo(self, *b):
|
||||
pass
|
||||
|
||||
|
||||
class B2:
|
||||
def foo(self, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class C2(B2):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
|
||||
class B3:
|
||||
def foo(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
class C3(B3):
|
||||
def foo(self):
|
||||
pass
|
||||
@@ -0,0 +1,23 @@
|
||||
class B:
|
||||
def foo(self, a):
|
||||
pass
|
||||
|
||||
|
||||
class C1(B):
|
||||
def foo(self, *a):
|
||||
pass
|
||||
|
||||
|
||||
class C2(B):
|
||||
def foo<warning descr="Signature of method 'C2.foo()' does not match signature of base method in class 'B'">(self)</warning>:
|
||||
pass
|
||||
|
||||
|
||||
class C3(B):
|
||||
def foo(self, **a):
|
||||
pass
|
||||
|
||||
|
||||
class C4(B):
|
||||
def foo(self, a):
|
||||
pass
|
||||
@@ -0,0 +1,23 @@
|
||||
class B1:
|
||||
def foo(self, *args, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class C1(B1):
|
||||
def foo(self): # pass
|
||||
pass
|
||||
|
||||
|
||||
class C2(B1):
|
||||
def foo(self, arg1): # pass
|
||||
pass
|
||||
|
||||
|
||||
class B3:
|
||||
def foo(self, arg1, *args, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class C3(B3):
|
||||
def foo<warning descr="Signature of method 'C3.foo()' does not match signature of base method in class 'B3'">(self, arg1, arg2=None)</warning>: # fail
|
||||
pass
|
||||
@@ -0,0 +1,8 @@
|
||||
class B:
|
||||
def foo(self, arg1):
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
def foo(self, arg1, arg2=None): #pass
|
||||
pass
|
||||
@@ -0,0 +1,8 @@
|
||||
class B:
|
||||
def foo(self, x=1):
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
def foo(self, **kwargs):
|
||||
pass
|
||||
@@ -0,0 +1,20 @@
|
||||
class B:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __new__(self):
|
||||
pass
|
||||
|
||||
def foo(self, a):
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
def __init__(self, a): # different but ok because __init__ is special
|
||||
pass
|
||||
|
||||
def __new__(self, p, q): # different but ok because __new__ is special
|
||||
pass
|
||||
|
||||
def foo<warning descr="Signature of method 'C.foo()' does not match signature of base method in class 'B'">(self, s, t)</warning>:
|
||||
pass
|
||||
@@ -0,0 +1,8 @@
|
||||
class B:
|
||||
def foo(self, arg1, arg2=None):
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
def foo<warning descr="Signature of method 'C.foo()' does not match signature of base method in class 'B'">(self, arg1=None)</warning>: #fail
|
||||
pass
|
||||
@@ -0,0 +1,8 @@
|
||||
class B:
|
||||
def foo(self, arg1, arg2=None, arg3=None, arg4=None):
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
def foo(self, arg1, arg2=None, arg3=None, **kwargs): #pass
|
||||
pass
|
||||
@@ -0,0 +1,7 @@
|
||||
class B:
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
def foo(self):
|
||||
pass
|
||||
@@ -0,0 +1,18 @@
|
||||
class B(object):
|
||||
@property
|
||||
def foo(self):
|
||||
return 'foo'
|
||||
|
||||
@foo.setter
|
||||
def foo(self, value):
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
@property
|
||||
def foo(self):
|
||||
return 'bar'
|
||||
|
||||
@foo.setter
|
||||
def foo(self, value): # pass
|
||||
pass
|
||||
@@ -0,0 +1,9 @@
|
||||
class B:
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
|
||||
class C(B):
|
||||
def foo<warning descr="Signature of method 'C.foo()' does not match signature of base method in class 'B'">(self, p1, **kwargs)</warning>: #fail
|
||||
pass
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
class c1:
|
||||
def foo(self, a):
|
||||
pass
|
||||
|
||||
class c2(c1):
|
||||
def foo(self, *a):
|
||||
pass
|
||||
|
||||
class c3(c1):
|
||||
def foo<warning descr="Signature of method 'c3.foo()' does not match signature of base method in class 'c1'">(self)</warning>:
|
||||
pass
|
||||
|
||||
class c4(c1):
|
||||
def foo(self, **a):
|
||||
pass
|
||||
|
||||
class c5(c1):
|
||||
def foo(self, a):
|
||||
pass
|
||||
|
||||
class c6:
|
||||
pass
|
||||
|
||||
class c7(c6):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class c8:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __new__(self):
|
||||
pass
|
||||
|
||||
def foo(self, a):
|
||||
pass
|
||||
|
||||
|
||||
class c9(c8):
|
||||
def __init__(self, a): # different but ok because __init__ is special
|
||||
pass
|
||||
|
||||
def __new__(self, p, q): # different but ok because __new__ is special
|
||||
pass
|
||||
|
||||
def foo<warning descr="Signature of method 'c9.foo()' does not match signature of base method in class 'c8'">(self, s, t)</warning>:
|
||||
pass
|
||||
|
||||
class c10:
|
||||
def foo(self, a, b):
|
||||
pass
|
||||
|
||||
class c11(c10):
|
||||
def foo(self, *b):
|
||||
pass
|
||||
|
||||
class c12(c4):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class c13:
|
||||
def foo(self, *args):
|
||||
pass
|
||||
|
||||
class c14(c13):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class c15: # PY-1083
|
||||
def foo(self, x = 1):
|
||||
pass
|
||||
|
||||
class c16:
|
||||
def foo(self, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
# PY-6700
|
||||
class c17:
|
||||
def foo(self, **kwargs):
|
||||
pass
|
||||
|
||||
class c18(c17):
|
||||
def foo(self, arg1=None, **kwargs): # pass
|
||||
pass
|
||||
|
||||
class c19:
|
||||
def foo(self, *args, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
class c20(c19):
|
||||
def foo(self): # pass
|
||||
pass
|
||||
|
||||
class c21(c19):
|
||||
def foo(self, arg1): # pass
|
||||
pass
|
||||
|
||||
class c22:
|
||||
def foo(self, arg1, *args, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
class c23(c22):
|
||||
def foo<warning descr="Signature of method 'c23.foo()' does not match signature of base method in class 'c22'">(self, arg1, arg2=None)</warning>: # fail
|
||||
pass
|
||||
|
||||
|
||||
# PY-7157
|
||||
class c24:
|
||||
def foo(self, arg1):
|
||||
pass
|
||||
|
||||
class c25(c24):
|
||||
def foo(self, arg1, arg2=None): #pass
|
||||
pass
|
||||
|
||||
|
||||
# PY-7162
|
||||
class c26:
|
||||
def foo(self, arg1, arg2=None):
|
||||
pass
|
||||
|
||||
class c27(c26):
|
||||
def foo<warning descr="Signature of method 'c27.foo()' does not match signature of base method in class 'c26'">(self, arg1=None)</warning>: #fail
|
||||
pass
|
||||
|
||||
|
||||
# PY-7159
|
||||
class c28:
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class c29(c28):
|
||||
def foo<warning descr="Signature of method 'c29.foo()' does not match signature of base method in class 'c28'">(self, p1, **kwargs)</warning>: #fail
|
||||
pass
|
||||
|
||||
|
||||
class c30:
|
||||
def foo(self, arg1, arg2=None, arg3=None, arg4=None):
|
||||
pass
|
||||
|
||||
class c31(c30):
|
||||
def foo(self, arg1, arg2=None, arg3=None, **kwargs): #pass
|
||||
pass
|
||||
@@ -1,5 +0,0 @@
|
||||
def a():
|
||||
... # <- highlighted as "Statement seems to have no effect"
|
||||
pass
|
||||
|
||||
a()
|
||||
@@ -1,33 +0,0 @@
|
||||
PyFile:EllipsisAsStatement.py
|
||||
PyFunction('a')
|
||||
PsiElement(Py:DEF_KEYWORD)('def')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('a')
|
||||
PyParameterList
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiErrorElement:Statement expected, found Py:DOT
|
||||
<empty list>
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiErrorElement:Statement expected, found Py:DOT
|
||||
<empty list>
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiErrorElement:Statement expected, found Py:DOT
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiComment(Py:END_OF_LINE_COMMENT)('# <- highlighted as "Statement seems to have no effect"')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
PsiWhiteSpace('\n\n')
|
||||
PyExpressionStatement
|
||||
PyCallExpression: a
|
||||
PyReferenceExpression: a
|
||||
PsiElement(Py:IDENTIFIER)('a')
|
||||
PyArgumentList
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
@@ -0,0 +1,5 @@
|
||||
...
|
||||
x = ...
|
||||
[1, 2, ...]
|
||||
def f():
|
||||
...
|
||||
@@ -0,0 +1,50 @@
|
||||
PyFile:EllipsisPython3.py
|
||||
PyExpressionStatement
|
||||
PyNoneLiteralExpression
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiWhiteSpace('\n')
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: x
|
||||
PsiElement(Py:IDENTIFIER)('x')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNoneLiteralExpression
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiWhiteSpace('\n')
|
||||
PyExpressionStatement
|
||||
PyListLiteralExpression
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('1')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNoneLiteralExpression
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace('\n')
|
||||
PyFunction('f')
|
||||
PsiElement(Py:DEF_KEYWORD)('def')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('f')
|
||||
PyParameterList
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace('\n ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyNoneLiteralExpression
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.inspections.PyMethodOverridingInspection;
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
*/
|
||||
public class PyMethodOverridingInspectionTest extends PyTestCase {
|
||||
private static final String TEST_DIRECTORY = "inspections/PyMethodOverridingInspection/";
|
||||
|
||||
public void testArgsKwargsOverrideArg() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNotOverridingMethod() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testInitNew() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testArgsKwargsAsAllowAnything() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-1083
|
||||
public void testExtraKwargs() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-6700
|
||||
public void testBothArgsKwargs() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-6700
|
||||
public void testArgAndKwargs() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7157
|
||||
public void testDefaultArgument() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7162
|
||||
public void testLessArgumentsPlusDefaults() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testLessParametersAndKwargs() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7159
|
||||
public void testRequiredParameterAndKwargs() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7725
|
||||
public void testPropertySetter() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile(TEST_DIRECTORY + getTestName(false) + ".py");
|
||||
myFixture.enableInspections(PyMethodOverridingInspection.class);
|
||||
myFixture.checkHighlighting(true, false, false);
|
||||
}
|
||||
}
|
||||
@@ -95,6 +95,7 @@ public class PythonAllTestsSuite {
|
||||
PyUnresolvedReferencesInspectionTest.class,
|
||||
PyCallingNonCallableInspectionTest.class,
|
||||
PyUnboundLocalVariableInspectionTest.class,
|
||||
PyMethodOverridingInspectionTest.class,
|
||||
PyUnusedImportTest.class,
|
||||
PyDeprecationTest.class,
|
||||
PythonHighlightingLexerTest.class,
|
||||
|
||||
@@ -62,11 +62,6 @@ public class PythonInspectionsTest extends PyTestCase {
|
||||
doTest(getTestName(false), inspection);
|
||||
}
|
||||
|
||||
public void testPyMethodOverridingInspection() {
|
||||
LocalInspectionTool inspection = new PyMethodOverridingInspection();
|
||||
doHighlightingTest(inspection);
|
||||
}
|
||||
|
||||
public void testPyTrailingSemicolonInspection() {
|
||||
LocalInspectionTool inspection = new PyTrailingSemicolonInspection();
|
||||
doTest(getTestName(false), inspection);
|
||||
|
||||
@@ -356,10 +356,6 @@ public class PythonParsingTest extends ParsingTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testEllipsisAsStatement() { // PY-7763
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-8606
|
||||
public void testEllipsisInSliceList() {
|
||||
doTest();
|
||||
@@ -374,6 +370,11 @@ public class PythonParsingTest extends ParsingTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-8752
|
||||
public void testEllipsisPython3() {
|
||||
doTest(LanguageLevel.PYTHON33);
|
||||
}
|
||||
|
||||
public void doTest(LanguageLevel languageLevel) {
|
||||
LanguageLevel prev = myLanguageLevel;
|
||||
myLanguageLevel = languageLevel;
|
||||
|
||||
@@ -47,6 +47,11 @@ public class PyAugmentAssignmentInspectionTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7605
|
||||
public void testStrOrUnknownFirstArg() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile("inspections/PyAugmentAssignmentInspection/" + getTestName(true) + ".py");
|
||||
myFixture.enableInspections(PyAugmentAssignmentInspection.class);
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.jetbrains.python.inspections;
|
||||
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : catherine
|
||||
@@ -119,6 +120,25 @@ public class PyCompatibilityInspectionTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7763
|
||||
public void testEllipsisAsStatementPy2() {
|
||||
doTest(LanguageLevel.PYTHON33);
|
||||
}
|
||||
|
||||
// PY-8606
|
||||
public void testEllipsisInSubscriptionPy2() {
|
||||
doTest(LanguageLevel.PYTHON33);
|
||||
}
|
||||
|
||||
private void doTest(@NotNull LanguageLevel level) {
|
||||
runWithLanguageLevel(level, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doTest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile("inspections/PyCompatibilityInspection/" + getTestName(true) + ".py");
|
||||
myFixture.enableInspections(PyCompatibilityInspection.class);
|
||||
|
||||
Reference in New Issue
Block a user