From 760dc144566a5807c469c32a8a23481c17f98ba7 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 2 Oct 2015 16:00:33 +0300 Subject: [PATCH 01/14] Fixed test data --- python/testSrc/com/jetbrains/python/PyTypingTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 7409f24faeb3..1e90b72a0cac 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -346,7 +346,7 @@ public class PyTypingTest extends PyTestCase { "from typing import Iterable\n" + "\n" + "def foo() -> Iterable[int]:\n" + - " passs\n" + + " pass\n" + "\n" + "for expr in foo():\n" + " pass\n"); From f533f0212656f3771f21cb860f12c1cf633086e6 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 2 Oct 2015 19:04:08 +0300 Subject: [PATCH 02/14] Fixed type inference for typing aliases (PY-16353) Now we resolve references in annotations first and then analyze them as typing constructs. Previously we analyzed only PyExpressions located in annotations. --- .../codeInsight/PyTypingTypeProvider.java | 157 +++++++++--------- .../com/jetbrains/python/PyTypingTest.java | 13 ++ 2 files changed, 95 insertions(+), 75 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java index 9528ff5df6b8..c1d524bb8f77 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java @@ -23,7 +23,6 @@ import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyExpressionCodeFragmentImpl; @@ -221,7 +220,8 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { if (expr instanceof PySubscriptionExpression) { final PyExpression indexExpr = ((PySubscriptionExpression)expr).getIndexExpression(); if (indexExpr != null) { - final PyGenericType genericType = getGenericType(indexExpr, context); + final PsiElement resolved = tryResolving(indexExpr, context); + final PyGenericType genericType = getGenericType(resolved, context); if (genericType != null) { results.add(genericType); } @@ -235,35 +235,36 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { @Nullable private static PyType getType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - final PyType unionType = getUnionType(expression, context); + final PsiElement resolved = tryResolving(expression, context); + final PyType unionType = getUnionType(resolved, context); if (unionType != null) { return unionType; } - final Ref optionalType = getOptionalTypeFromDefaultNone(expression, context); + final Ref optionalType = getOptionalTypeFromDefaultNone(resolved, context); if (optionalType != null) { return optionalType.get(); } - final PyType callableType = getCallableType(expression, context); + final PyType callableType = getCallableType(resolved, context); if (callableType != null) { return callableType; } - final PyType parameterizedType = getParameterizedType(expression, context); + final PyType parameterizedType = getParameterizedType(resolved, context); if (parameterizedType != null) { return parameterizedType; } - final PyType builtinCollection = getBuiltinCollection(expression, context); + final PyType builtinCollection = getBuiltinCollection(resolved); if (builtinCollection != null) { return builtinCollection; } - final PyType genericType = getGenericType(expression, context); + final PyType genericType = getGenericType(resolved, context); if (genericType != null) { return genericType; } - final Ref classType = getClassType(expression, context); + final Ref classType = getClassType(resolved, context); if (classType != null) { return classType.get(); } - final PyType stringBasedType = getStringBasedType(expression, context); + final PyType stringBasedType = getStringBasedType(resolved, context); if (stringBasedType != null) { return stringBasedType; } @@ -271,28 +272,30 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static Ref getClassType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - final PyType type = context.getType(expression); - if (type != null && isAny(type)) { - return Ref.create(); - } - if (type instanceof PyClassLikeType) { - final PyClassLikeType classType = (PyClassLikeType)type; - if (classType.isDefinition()) { - final PyType instanceType = classType.toInstance(); - return Ref.create(instanceType); + private static Ref getClassType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + if (element instanceof PyTypedElement) { + final PyType type = context.getType((PyTypedElement)element); + if (type != null && isAny(type)) { + return Ref.create(); + } + if (type instanceof PyClassLikeType) { + final PyClassLikeType classType = (PyClassLikeType)type; + if (classType.isDefinition()) { + final PyType instanceType = classType.toInstance(); + return Ref.create(instanceType); + } + } + else if (type instanceof PyNoneType) { + return Ref.create(type); } - } - else if (type instanceof PyNoneType) { - return Ref.create(type); } return null; } @Nullable - private static Ref getOptionalTypeFromDefaultNone(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - if (expression instanceof PySubscriptionExpression) { - final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression; + private static Ref getOptionalTypeFromDefaultNone(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + if (element instanceof PySubscriptionExpression) { + final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element; final PyExpression operand = subscriptionExpr.getOperand(); final String operandName = resolveToQualifiedName(operand, context); if ("typing.Optional".equals(operandName)) { @@ -310,11 +313,11 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getStringBasedType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - if (expression instanceof PyStringLiteralExpression) { + private static PyType getStringBasedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + if (element instanceof PyStringLiteralExpression) { // XXX: Requires switching from stub to AST - final String contents = ((PyStringLiteralExpression)expression).getStringValue(); - return getStringBasedType(contents, expression, context); + final String contents = ((PyStringLiteralExpression)element).getStringValue(); + return getStringBasedType(contents, element, context); } return null; } @@ -341,9 +344,9 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getCallableType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - if (expression instanceof PySubscriptionExpression) { - final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression; + private static PyType getCallableType(@NotNull PsiElement resolved, @NotNull TypeEvalContext context) { + if (resolved instanceof PySubscriptionExpression) { + final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)resolved; final PyExpression operand = subscriptionExpr.getOperand(); final String operandName = resolveToQualifiedName(operand, context); if ("typing.Callable".equals(operandName)) { @@ -371,9 +374,9 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getUnionType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - if (expression instanceof PySubscriptionExpression) { - final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression; + private static PyType getUnionType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + if (element instanceof PySubscriptionExpression) { + final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element; final PyExpression operand = subscriptionExpr.getOperand(); final String operandName = resolveToQualifiedName(operand, context); if ("typing.Union".equals(operandName)) { @@ -384,32 +387,22 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyGenericType getGenericType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - final PsiElement resolved = resolve(expression, context); - if (resolved instanceof PyTargetExpression) { - final PyTargetExpression targetExpr = (PyTargetExpression)resolved; - final QualifiedName calleeName = targetExpr.getCalleeName(); - if (calleeName != null && "TypeVar".equals(calleeName.toString())) { - // XXX: Requires switching from stub to AST - final PyExpression assigned = targetExpr.findAssignedValue(); - if (assigned instanceof PyCallExpression) { - final PyCallExpression assignedCall = (PyCallExpression)assigned; - final PyExpression callee = assignedCall.getCallee(); - if (callee != null) { - final String calleeQName = resolveToQualifiedName(callee, context); - if ("typing.TypeVar".equals(calleeQName)) { - final PyExpression[] arguments = assignedCall.getArguments(); - if (arguments.length > 0) { - final PyExpression firstArgument = arguments[0]; - if (firstArgument instanceof PyStringLiteralExpression) { - final String name = ((PyStringLiteralExpression)firstArgument).getStringValue(); - if (name != null) { - return new PyGenericType(name, getGenericTypeBound(arguments, context)); - } - } + private static PyGenericType getGenericType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + if (element instanceof PyCallExpression) { + final PyCallExpression assignedCall = (PyCallExpression)element; + final PyExpression callee = assignedCall.getCallee(); + if (callee != null) { + final String calleeQName = resolveToQualifiedName(callee, context); + if ("typing.TypeVar".equals(calleeQName)) { + final PyExpression[] arguments = assignedCall.getArguments(); + if (arguments.length > 0) { + final PyExpression firstArgument = arguments[0]; + if (firstArgument instanceof PyStringLiteralExpression) { + final String name = ((PyStringLiteralExpression)firstArgument).getStringValue(); + if (name != null) { + return new PyGenericType(name, getGenericTypeBound(arguments, context)); } } - } } } @@ -443,9 +436,9 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getParameterizedType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - if (expression instanceof PySubscriptionExpression) { - final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression; + private static PyType getParameterizedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + if (element instanceof PySubscriptionExpression) { + final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element; final PyExpression operand = subscriptionExpr.getOperand(); final PyExpression indexExpr = subscriptionExpr.getIndexExpression(); final PyType operandType = getType(operand, context); @@ -453,7 +446,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { final PyClass cls = ((PyClassType)operandType).getPyClass(); final List indexTypes = getIndexTypes(subscriptionExpr, context); if (PyNames.TUPLE.equals(cls.getQualifiedName())) { - return PyTupleType.create(expression, indexTypes.toArray(new PyType[indexTypes.size()])); + return PyTupleType.create(element, indexTypes.toArray(new PyType[indexTypes.size()])); } else if (indexExpr != null) { return new PyCollectionTypeImpl(cls, false, indexTypes); @@ -464,18 +457,18 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getBuiltinCollection(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - final String collectionName = resolveToQualifiedName(expression, context); + private static PyType getBuiltinCollection(@NotNull PsiElement element) { + final String collectionName = getQualifiedName(element); final String builtinName = COLLECTION_CLASSES.get(collectionName); - return builtinName != null ? PyTypeParser.getTypeByName(expression, builtinName) : null; + return builtinName != null ? PyTypeParser.getTypeByName(element, builtinName) : null; } - @Nullable - private static PsiElement resolve(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - if (expression instanceof PyReferenceOwner) { - final PyReferenceOwner referenceOwner = (PyReferenceOwner)expression; + @NotNull + private static PsiElement tryResolving(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + if (expression instanceof PyReferenceExpression) { + final PyReferenceExpression referenceExpr = (PyReferenceExpression)expression; final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); - final PsiPolyVariantReference reference = referenceOwner.getReference(resolveContext); + final PsiPolyVariantReference reference = referenceExpr.getReference(resolveContext); final PsiElement element = reference.resolve(); if (element instanceof PyFunction) { final PyFunction function = (PyFunction)element; @@ -486,14 +479,28 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } } } - return element; + else if (element instanceof PyTargetExpression) { + final PyTargetExpression targetExpr = (PyTargetExpression)element; + // XXX: Requires switching from stub to AST + final PyExpression assignedValue = targetExpr.findAssignedValue(); + if (assignedValue != null) { + return assignedValue; + } + } + if (element != null) { + return element; + } } - return null; + return expression; } @Nullable private static String resolveToQualifiedName(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { - final PsiElement element = resolve(expression, context); + return getQualifiedName(tryResolving(expression, context)); + } + + @Nullable + private static String getQualifiedName(@NotNull PsiElement element) { if (element instanceof PyQualifiedNameOwner) { final PyQualifiedNameOwner qualifiedNameOwner = (PyQualifiedNameOwner)element; return qualifiedNameOwner.getQualifiedName(); diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 1e90b72a0cac..876b1e956f8d 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -352,6 +352,19 @@ public class PyTypingTest extends PyTestCase { " pass\n"); } + // PY-16353 + public void testAssignedType() { + doTest("Iterable[int]", + "from typing import Iterable\n" + + "\n" + + "IntIterable = Iterable[int]\n" + + "\n" + + "def foo() -> IntIterable:\n" + + " pass\n" + + "\n" + + "expr = foo()\n"); + } + private void doTestNoInjectedText(@NotNull String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject()); From 31741546a3dcd2bedaeae8525b3a4d676a1ec68d Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 2 Oct 2015 20:26:15 +0300 Subject: [PATCH 03/14] make sure tab character is always LTR --- .../openapi/editor/impl/view/LineLayout.java | 34 +++++++++++++------ .../openapi/editor/impl/EditorRtlTest.java | 20 +++++++++++ 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java index 0d691ab2e388..9c54b2b9851f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java @@ -107,7 +107,7 @@ class LineLayout { List runs = createRuns(editor, chars, -1); for (BidiRun run : runs) { for (Chunk chunk : run.getChunks()) { - addFragments(chunk, run.isRtl(), chars, chunk.startOffset, chunk.endOffset, fontStyle, fontPreferences, fontRenderContext, null); + addFragments(run, chunk, chars, chunk.startOffset, chunk.endOffset, fontStyle, fontPreferences, fontRenderContext, null); } } return runs; @@ -150,6 +150,18 @@ class LineLayout { } private static void addRuns(List runs, char[] text, int start, int end) { + int afterLastTabPosition = start; + for (int i = start; i < end; i++) { + if (text[i] == '\t') { + addRunsNoTabs(runs, text, afterLastTabPosition, i); + afterLastTabPosition = i + 1; + addOrMergeRun(runs, new BidiRun((byte)0, i, i + 1)); + } + } + addRunsNoTabs(runs, text, afterLastTabPosition, end); + } + + private static void addRunsNoTabs(List runs, char[] text, int start, int end) { if (start >= end) return; Bidi bidi = new Bidi(text, start, null, 0, end - start, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT); int runCount = bidi.getRunCount(); @@ -170,7 +182,7 @@ class LineLayout { } } - private static void addFragments(Chunk chunk, boolean isRtl, char[] text, int start, int end, int fontStyle, + private static void addFragments(BidiRun run, Chunk chunk, char[] text, int start, int end, int fontStyle, FontPreferences fontPreferences, FontRenderContext fontRenderContext, @Nullable TabFragment tabFragment) { assert start < end; @@ -179,7 +191,7 @@ class LineLayout { for(int i = start; i < end; i++) { char c = text[i]; if (c == '\t' && tabFragment != null) { - assert !isRtl; + assert run.level == 0; addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFont, fontRenderContext, false); chunk.fragments.add(tabFragment); currentFont = null; @@ -188,13 +200,13 @@ class LineLayout { else { Font font = ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontStyle, fontPreferences).getFont(); if (!font.equals(currentFont)) { - addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFont, fontRenderContext, isRtl); + addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFont, fontRenderContext, run.isRtl()); currentFont = font; currentIndex = i; } } } - addTextFragmentIfNeeded(chunk, text, currentIndex, end, currentFont, fontRenderContext, isRtl); + addTextFragmentIfNeeded(chunk, text, currentIndex, end, currentFont, fontRenderContext, run.isRtl()); assert !chunk.fragments.isEmpty(); } @@ -342,7 +354,7 @@ class LineLayout { for (Chunk chunk : getChunks()) { if (chunk.endOffset <= start) continue; if (chunk.startOffset >= end) break; - subChunks.add(chunk.subChunk(view, lineStartOffset, isRtl(), start, end, quick)); + subChunks.add(chunk.subChunk(view, this, lineStartOffset, start, end, quick)); } subRun.chunks = subChunks.toArray(new Chunk[subChunks.size()]); return subRun; @@ -359,7 +371,7 @@ class LineLayout { this.endOffset = endOffset; } - private void ensureLayout(@NotNull EditorView view, int lineStartOffset, boolean isRtl) { + private void ensureLayout(@NotNull EditorView view, BidiRun run, int lineStartOffset) { if (!fragments.isEmpty()) return; int start = lineStartOffset + startOffset; int end = lineStartOffset + endOffset; @@ -367,7 +379,7 @@ class LineLayout { FontPreferences fontPreferences = view.getEditor().getColorsScheme().getFontPreferences(); char[] chars = CharArrayUtil.fromSequence(view.getEditor().getDocument().getImmutableCharSequence(), start, end); while (!it.atEnd()) { - addFragments(this, isRtl, chars, it.getStartOffset() - start, it.getEndOffset() - start, + addFragments(run, this, chars, it.getStartOffset() - start, it.getEndOffset() - start, it.getMergedAttributes().getFontType(), fontPreferences, view.getFontRenderContext(), view.getTabFragment()); it.advance(); } @@ -375,7 +387,7 @@ class LineLayout { assert !fragments.isEmpty(); } - private Chunk subChunk(EditorView view, int lineStartOffset, boolean isRtl, int targetStartOffset, int targetEndOffset, boolean quick) { + private Chunk subChunk(EditorView view, BidiRun run, int lineStartOffset, int targetStartOffset, int targetEndOffset, boolean quick) { assert targetStartOffset < endOffset; assert targetEndOffset > startOffset; int start = Math.max(startOffset, targetStartOffset); @@ -390,7 +402,7 @@ class LineLayout { if (start == startOffset && end == this.endOffset) { return this; } - ensureLayout(view, lineStartOffset, isRtl); + ensureLayout(view, run, lineStartOffset); Chunk chunk = new Chunk(start, end); int offset = startOffset; for (LineFragment fragment : fragments) { @@ -434,7 +446,7 @@ class LineLayout { if (myChunkIndex >= chunks.length) return false; Chunk chunk = chunks[run.isRtl() ? chunks.length - 1 - myChunkIndex : myChunkIndex]; if (myView != null) { - chunk.ensureLayout(myView, myLineStartOffset, run.isRtl()); + chunk.ensureLayout(myView, run, myLineStartOffset); } return myFragmentIndex < chunk.fragments.size(); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java index d55f36c1e9a6..302710ea536a 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java @@ -563,6 +563,26 @@ public class EditorRtlTest extends AbstractEditorTest { checkResult("RLR"); } + public void testTabInsideRtlText() throws Exception { + prepareText("R\tRR"); + right(); + checkResult("R\tRR"); + right(); + checkResult("R\tRR"); + right(); + checkResult("R\tRR"); + right(); + checkResult("R\tRR"); + right(); + checkResult("R\tRR"); + right(); + checkResult("R\tRR"); + right(); + checkResult("R\tRR"); + right(); + checkResult("R\tRR"); + } + private void prepareText(String text) throws IOException { prepare(text, TestFileType.TEXT); } From 79ef5cc3dd862ea44a4016003f18076333228f1b Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Fri, 2 Oct 2015 21:19:57 +0300 Subject: [PATCH 04/14] EA-74017: fix NPE Removed the line causing this NPE. The removed call is still made via off() call on the next line. --- .../intellij/find/impl/livePreview/LivePreviewController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java index 00346aeb29bd..4ea787e5a498 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java @@ -274,7 +274,6 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep public void dispose() { if (myDisposed) return; - myLivePreview.cleanUp(); off(); mySearchResults.dispose(); From 3e868975da8166fef48dc0a01fe45bcddc31f68f Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Fri, 2 Oct 2015 19:20:55 +0300 Subject: [PATCH 05/14] introduce utility ScratchFileService.isInScratchRoot(file) --- .../com/intellij/ide/scratch/ScratchFileService.java | 4 ++++ .../MoveFilesOrDirectoriesHandler.java | 10 ++-------- python/src/com/jetbrains/python/psi/PyUtil.java | 6 +++--- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileService.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileService.java index ab518d001af7..f81ed3fbf2ea 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileService.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileService.java @@ -46,4 +46,8 @@ public abstract class ScratchFileService { @NotNull public abstract PerFileMappings getScratchesMapping(); + + public static boolean isInScratchRoot(@Nullable VirtualFile file) { + return getInstance().getRootType(file) != null; + } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java index 2aa855f52711..5ede26109afd 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java @@ -22,9 +22,9 @@ import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandlerDelegate; import org.jetbrains.annotations.Nullable; @@ -62,13 +62,7 @@ public class MoveFilesOrDirectoriesHandler extends MoveHandlerDelegate { public static boolean isValidTarget(PsiElement psiElement) { if (!(psiElement instanceof PsiDirectory || psiElement instanceof PsiDirectoryContainer)) return false; - return psiElement.getManager().isInProject(psiElement) || isInScratches(psiElement); - } - - protected static boolean isInScratches(PsiElement psiElement) { - VirtualFile virtualFile = psiElement instanceof PsiFileSystemItem ? ((PsiFileSystemItem)psiElement).getVirtualFile() : null; - if (virtualFile != null && ScratchFileService.getInstance().getRootType(virtualFile) != null) return true; - return false; + return psiElement.getManager().isInProject(psiElement) || ScratchFileService.isInScratchRoot(PsiUtilCore.getVirtualFile(psiElement)); } public void doMove(final PsiElement[] elements, final PsiElement targetContainer) { diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 31bdabd31f6d..87d9be86fe81 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -23,7 +23,7 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; -import com.intellij.ide.scratch.ScratchRootType; +import com.intellij.ide.scratch.ScratchFileService; import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.lang.ASTFactory; import com.intellij.lang.ASTNode; @@ -55,6 +55,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.util.QualifiedName; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.*; @@ -1832,8 +1833,7 @@ public class PyUtil { } public static boolean isInScratchFile(@NotNull PsiElement element) { - PsiFile file = element.getContainingFile(); - return file != null && ScratchRootType.getInstance().isScratchFile(file.getVirtualFile()); + return ScratchFileService.isInScratchRoot(PsiUtilCore.getVirtualFile(element)); } /** From f08057c3f5edaad56f153da5755987161cc3e5c7 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Fri, 2 Oct 2015 21:26:44 +0300 Subject: [PATCH 06/14] ui: preserve TextFieldWithHistory text on history update --- .../src/com/intellij/util/ui/SwingHelper.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java b/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java index 7881b8a7c96a..bf9e8a783adc 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java +++ b/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java @@ -32,6 +32,7 @@ import com.intellij.ui.HyperlinkLabel; import com.intellij.ui.TextFieldWithHistory; import com.intellij.ui.TextFieldWithHistoryWithBrowseButton; import com.intellij.util.NotNullProducer; +import com.intellij.util.ObjectUtils; import com.intellij.util.PlatformIcons; import com.intellij.util.containers.ComparatorUtil; import com.intellij.util.containers.ContainerUtil; @@ -295,7 +296,7 @@ public class SwingHelper { boolean mergeWithPrevHistory) { Set newHistorySet = ContainerUtil.newHashSet(history); List prevHistory = textFieldWithHistory.getHistory(); - List mergedHistory = ContainerUtil.newArrayList(); + List mergedHistory = ContainerUtil.newArrayListWithCapacity(history.size()); if (mergeWithPrevHistory) { for (String item : prevHistory) { if (!newHistorySet.contains(item)) { @@ -303,15 +304,20 @@ public class SwingHelper { } } } - else { - String currentText = textFieldWithHistory.getText(); - if (StringUtil.isNotEmpty(currentText) && !newHistorySet.contains(currentText)) { - mergedHistory.add(currentText); - } - } mergedHistory.addAll(history); + String oldText = StringUtil.notNullize(textFieldWithHistory.getText()); + String oldSelectedItem = ObjectUtils.tryCast(textFieldWithHistory.getSelectedItem(), String.class); + if (!mergedHistory.contains(oldSelectedItem)) { + oldSelectedItem = null; + } textFieldWithHistory.setHistory(mergedHistory); setLongestAsPrototype(textFieldWithHistory, mergedHistory); + if (oldSelectedItem != null) { + textFieldWithHistory.setSelectedItem(oldSelectedItem); + } + if (!oldText.equals(oldSelectedItem)) { + textFieldWithHistory.setText(oldText); + } } private static void setLongestAsPrototype(@NotNull JComboBox comboBox, @NotNull List variants) { From d3d8d033f0bc9461e98d319d63b6e2b6721ae3a0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 2 Oct 2015 15:02:24 +0200 Subject: [PATCH 07/14] logging for EA-73982 - assert: RenameProcessor.findUsages --- .../src/com/intellij/refactoring/rename/RenameProcessor.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameProcessor.java index 06d812127d6f..ef76ae11eabb 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameProcessor.java @@ -300,7 +300,10 @@ public class RenameProcessor extends BaseRefactoringProcessor { //noinspection ForLoopReplaceableByForEach for (int i = 0; i < elements.size(); i++) { PsiElement element = elements.get(i); - LOG.assertTrue(element != null); + if (element == null) { + LOG.error("primary: " + myPrimaryElement + "; renamers: " + myRenamers); + continue; + } final String newName = myAllRenames.get(element); final UsageInfo[] usages = RenameUtil.findUsages(element, newName, mySearchInComments, mySearchTextOccurrences, myAllRenames); final List usagesList = Arrays.asList(usages); From 565835bd5fb414842ca493ab2532e4ab3b07f0fe Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 2 Oct 2015 17:29:09 +0200 Subject: [PATCH 08/14] simplify to use one guard to prevent caching --- .../com/intellij/psi/impl/source/resolve/JavaResolveCache.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java index 12b91dc196ea..51adfb34bf76 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java @@ -84,9 +84,8 @@ public class JavaResolveCache { PsiType type = isOverloadCheck ? null : myCalculatedTypes.get(expr); if (type == null) { final RecursionGuard.StackStamp dStackStamp = PsiDiamondType.ourDiamondGuard.markStack(); - final RecursionGuard.StackStamp gStackStamp = PsiResolveHelper.ourGraphGuard.markStack(); type = f.fun(expr); - if (!dStackStamp.mayCacheNow() || !gStackStamp.mayCacheNow() || isOverloadCheck) { + if (!dStackStamp.mayCacheNow() || isOverloadCheck) { return type; } if (type == null) type = TypeConversionUtil.NULL_TYPE; From 2a27f86b79bf43f39f9bf70356a75f73cf9748bd Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 2 Oct 2015 18:50:16 +0200 Subject: [PATCH 09/14] new inference: don't clear foreign caches - remove only expressions which were added --- .../graphInference/InferenceSession.java | 4 ++- ...eckedExceptionCompatibilityConstraint.java | 2 +- .../InputOutputConstraintFormula.java | 2 +- ...daBodyDontInfluenceOuterCallInference.java | 25 +++++++++++++++++++ .../lambda/Java8ExpressionsCheckTest.java | 8 +++--- 5 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/expressions/ProoveThatInferenceInsideLambdaBodyDontInfluenceOuterCallInference.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index 20d18262f9d9..6121d6530c8b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -1195,7 +1195,9 @@ public class InferenceSession { } } finally { - LambdaUtil.ourFunctionTypes.set(null); + if (formula instanceof InputOutputConstraintFormula) { + LambdaUtil.getFunctionalTypeMap().remove(((InputOutputConstraintFormula)formula).getExpression()); + } } return true; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java index f03a796350d8..bd7549957c7b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java @@ -157,7 +157,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai } @Override - protected PsiExpression getExpression() { + public PsiExpression getExpression() { return myExpression; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/InputOutputConstraintFormula.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/InputOutputConstraintFormula.java index 8efff6b10f71..0fb9e7f41d52 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/InputOutputConstraintFormula.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/InputOutputConstraintFormula.java @@ -30,7 +30,7 @@ import java.util.*; */ public abstract class InputOutputConstraintFormula implements ConstraintFormula { - protected abstract PsiExpression getExpression(); + public abstract PsiExpression getExpression(); protected abstract PsiType getT(); protected abstract void setT(PsiType t); protected abstract InputOutputConstraintFormula createSelfConstraint(PsiType type, PsiExpression expression); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/expressions/ProoveThatInferenceInsideLambdaBodyDontInfluenceOuterCallInference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/expressions/ProoveThatInferenceInsideLambdaBodyDontInfluenceOuterCallInference.java new file mode 100644 index 000000000000..c34eae729fbb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/expressions/ProoveThatInferenceInsideLambdaBodyDontInfluenceOuterCallInference.java @@ -0,0 +1,25 @@ + +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class Test { + void f(Stream stream1) { + final Supplier> revisionDiffItemDTOs = () -> stream1.map(record -> { + foo(null); + final Object stream = record.getAllNodes().stream(); + return ""; + }).collect(Collectors.toList()); + } + + + private void foo(T t) throws RuntimeException {} + + private class ReviewDiffRecord { + List getAllNodes() { + return null; + } + } + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Java8ExpressionsCheckTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Java8ExpressionsCheckTest.java index 99b4a647fe11..a325f0e32552 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Java8ExpressionsCheckTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Java8ExpressionsCheckTest.java @@ -16,17 +16,13 @@ package com.intellij.codeInsight.daemon.lambda; import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testFramework.IdeaTestUtil; import org.jetbrains.annotations.NonNls; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.List; public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase { @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/expressions"; @@ -47,6 +43,10 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase { doTestAllMethodCallExpressions(); } + public void testProoveThatInferenceInsideLambdaBodyDontInfluenceOuterCallInference() throws Exception { + doTestAllMethodCallExpressions(); + } + public void testCachedUnresolvedMethods() throws Exception { doTestCachedUnresolved(); } From 4ed1c43acfd267d32da1f052dfeb5c2e2e716984 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 2 Oct 2015 19:12:09 +0200 Subject: [PATCH 10/14] testdata for IDEA-140686 --- .../lambda/diamond/IDEA140686.java | 50 +++++++++++++++++++ .../lambda/Diamond8HighlightingTest.java | 4 ++ 2 files changed, 54 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/IDEA140686.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/IDEA140686.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/IDEA140686.java new file mode 100644 index 000000000000..eae6d376024f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/IDEA140686.java @@ -0,0 +1,50 @@ +package nise; + +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.function.Supplier; + + + +class TypeTest { + public static void main(String[] args) { + assertThat(id(new Combiner<>(echo("A"), echo("B"), (str1, str2) -> + new StringBuilder(str1.length() + str2.length()) + .append(str1) + .append(str2))).get(), + hasSameContentAs("AB")); + } + + private static Supplier id(Supplier s) { + return s; + } + + private static Supplier echo(T s) { + return () -> s; + } + + private static Predicate hasSameContentAs(CharSequence seq) { + return charSequence -> charSequence.toString().equals(seq.toString()); + } + + private static void assertThat(T actual, Predicate matcher) { + if (!matcher.test(actual)) throw new AssertionError(); + } + + private static class Combiner implements Supplier { + private final Supplier s1; + private final Supplier s2; + private final BiFunction f; + + public Combiner(Supplier s1, Supplier s2, BiFunction f) { + this.s1 = s1; + this.s2 = s2; + this.f = f; + } + + @Override + public R get() { + return f.apply(s1.get(), s2.get()); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java index 1990221b5e5f..fb31edf8d404 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java @@ -46,6 +46,10 @@ public class Diamond8HighlightingTest extends LightDaemonAnalyzerTestCase { public void testWithConstructorRefInside() throws Exception { doTest(); } + + public void testIDEA140686() throws Exception { + doTest(); + } private void doTest() throws Exception { doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false); From 02c716adcd87de750e665efd89b779952c30ac6e Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Fri, 2 Oct 2015 20:24:38 +0200 Subject: [PATCH 11/14] java scratches configurable rewrite: do not extend ApplicationConfigurable --- .../scratch/JavaScratchConfigurable.java | 109 ++++++++++++++---- 1 file changed, 86 insertions(+), 23 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurable.java b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurable.java index ea2eaca3da5c..55df9b8851ad 100644 --- a/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurable.java +++ b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurable.java @@ -15,22 +15,27 @@ */ package com.intellij.execution.scratch; -import com.intellij.execution.application.ApplicationConfigurable; -import com.intellij.execution.application.ApplicationConfiguration; +import com.intellij.application.options.ModulesComboBox; +import com.intellij.execution.ui.CommonJavaParametersPanel; +import com.intellij.execution.ui.ConfigurationModuleSelector; +import com.intellij.execution.ui.DefaultJreSelector; +import com.intellij.execution.ui.JrePathEditor; import com.intellij.ide.scratch.ScratchFileService; import com.intellij.ide.scratch.ScratchRootType; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithId; -import com.intellij.ui.components.JBLabel; -import com.intellij.util.ui.components.BorderLayoutPanel; +import com.intellij.ui.PanelWithAnchor; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,13 +48,28 @@ import java.awt.event.ActionListener; * @author Eugene Zhuravlev * Date: 30-Sep-15 */ -public class JavaScratchConfigurable extends ApplicationConfigurable{ +public class JavaScratchConfigurable extends SettingsEditor implements PanelWithAnchor { - private final TextFieldWithBrowseButton myScratchPathField; + private final CommonJavaParametersPanel myCommonProgramParameters; + private final LabeledComponent myMainClass; + private final LabeledComponent myScratchPathField; + private final LabeledComponent myModule; + private JPanel myWholePanel; + + private final ConfigurationModuleSelector myModuleSelector; + private JrePathEditor myJrePathEditor; + private JComponent myAnchor; public JavaScratchConfigurable(final Project project) { - super(project); - myScratchPathField = new TextFieldWithBrowseButton(new ActionListener() { + myMainClass = new LabeledComponent(); + myMainClass.setLabelLocation(BorderLayout.WEST); + myMainClass.setText("Main &class:"); + myMainClass.setComponent(new JTextField()); + + myScratchPathField = new LabeledComponent(); + myScratchPathField.setLabelLocation(BorderLayout.WEST); + myScratchPathField.setText("&Path to scratch file:"); + myScratchPathField.setComponent(new TextFieldWithBrowseButton(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { VirtualFile toSelect = getVFileFromEditor(); @@ -63,33 +83,64 @@ public class JavaScratchConfigurable extends ApplicationConfigurable{ setVFileToEditor(file); } } - }, this); + }, this)); + + myModule = new LabeledComponent(); + myModule.setLabelLocation(BorderLayout.WEST); + myModule.setComponent(new ModulesComboBox()); + myModule.setText("Use classpath of &module:"); + myModuleSelector = new ConfigurationModuleSelector(project, myModule.getComponent()); + + myCommonProgramParameters = new CommonJavaParametersPanel(); + myCommonProgramParameters.setModuleContext(myModuleSelector.getModule()); + myModule.getComponent().addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + myCommonProgramParameters.setModuleContext(myModuleSelector.getModule()); + } + }); + myJrePathEditor = new JrePathEditor(); + myJrePathEditor.setDefaultJreSelector(DefaultJreSelector.projectSdk(project)); + + myWholePanel = new JPanel(new GridBagLayout()); + myWholePanel.add(myMainClass, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0),0, 0 )); + myWholePanel.add(myScratchPathField, new GridBagConstraints(GridBagConstraints.RELATIVE, 1, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0),0, 0 )); + myWholePanel.add(myCommonProgramParameters, new GridBagConstraints(GridBagConstraints.RELATIVE, 2, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(12, 0, 12, 0),0, 0 )); + myWholePanel.add(myModule, new GridBagConstraints(GridBagConstraints.RELATIVE, 3, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0),0, 0 )); + myWholePanel.add(myJrePathEditor, new GridBagConstraints(GridBagConstraints.RELATIVE, 4, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0),0, 0 )); + + myAnchor = UIUtil.mergeComponentsWithAnchor(myMainClass, myScratchPathField, myCommonProgramParameters, myJrePathEditor, myModule); } @Override - public void applyEditorTo(ApplicationConfiguration configuration) throws ConfigurationException { - super.applyEditorTo(configuration); + public void applyEditorTo(JavaScratchConfiguration configuration) throws ConfigurationException { + myCommonProgramParameters.applyTo(configuration); + myModuleSelector.applyTo(configuration); + configuration.MAIN_CLASS_NAME = myMainClass.getComponent().getText().trim(); + configuration.ALTERNATIVE_JRE_PATH = myJrePathEditor.getJrePathOrName(); + configuration.ALTERNATIVE_JRE_PATH_ENABLED = myJrePathEditor.isAlternativeJreSelected(); + final VirtualFile vFile = getVFileFromEditor(); - ((JavaScratchConfiguration)configuration).SCRATCH_FILE_ID = vFile instanceof VirtualFileWithId ? ((VirtualFileWithId)vFile).getId() : 0; + configuration.SCRATCH_FILE_ID = vFile instanceof VirtualFileWithId ? ((VirtualFileWithId)vFile).getId() : 0; } @Nullable private VirtualFile getVFileFromEditor() { - final String path = FileUtil.toSystemIndependentName(myScratchPathField.getText()); + final String path = FileUtil.toSystemIndependentName(myScratchPathField.getComponent().getText().trim()); return !StringUtil.isEmpty(path) ? LocalFileSystem.getInstance().findFileByPath(path) : null; } @Override - public void resetEditorFrom(ApplicationConfiguration configuration) { - super.resetEditorFrom(configuration); - final JavaScratchConfiguration scratchConfig = (JavaScratchConfiguration)configuration; - final VirtualFile file = scratchConfig.getScratchVirtualFile(); - setVFileToEditor(file); + public void resetEditorFrom(JavaScratchConfiguration configuration) { + myCommonProgramParameters.reset(configuration); + myModuleSelector.reset(configuration); + myMainClass.getComponent().setText(configuration.MAIN_CLASS_NAME != null ? configuration.MAIN_CLASS_NAME.replaceAll("\\$", "\\.") : ""); + myJrePathEditor.setPathOrName(configuration.ALTERNATIVE_JRE_PATH, configuration.ALTERNATIVE_JRE_PATH_ENABLED); + setVFileToEditor(configuration.getScratchVirtualFile()); } private void setVFileToEditor(VirtualFile file) { if (file != null) { - myScratchPathField.setText(FileUtil.toSystemDependentName(file.getPath())); + myScratchPathField.getComponent().setText(FileUtil.toSystemDependentName(file.getPath())); } else { myScratchPathField.setText(""); @@ -99,9 +150,21 @@ public class JavaScratchConfigurable extends ApplicationConfigurable{ @NotNull @Override public JComponent createEditor() { - final JPanel panel = new JPanel(new GridBagLayout()); - panel.add(new JBLabel("Path to scratch file: "), new GridBagConstraints(0, 0, 1, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(20,0,0,10), 0, 0)); - panel.add(myScratchPathField, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(20, 0, 0, 0), 0, 0)); - return new BorderLayoutPanel().addToCenter(super.createEditor()).addToBottom(panel); + return myWholePanel; + } + + @Override + public JComponent getAnchor() { + return myAnchor; + } + + @Override + public void setAnchor(@Nullable JComponent anchor) { + myAnchor = anchor; + myMainClass.setAnchor(anchor); + myScratchPathField.setAnchor(anchor); + myCommonProgramParameters.setAnchor(anchor); + myJrePathEditor.setAnchor(anchor); + myModule.setAnchor(anchor); } } From c591e0b8650e4ddaf7e26f456c852f1329a001d0 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 2 Oct 2015 20:44:41 +0200 Subject: [PATCH 12/14] [project] inspection tuned --- .idea/inspectionProfiles/idea_default.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/inspectionProfiles/idea_default.xml b/.idea/inspectionProfiles/idea_default.xml index af758032d20b..3f2e779478a8 100644 --- a/.idea/inspectionProfiles/idea_default.xml +++ b/.idea/inspectionProfiles/idea_default.xml @@ -151,6 +151,7 @@ + From d142759d97568e794f18f82e976f63a72d2a3a32 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 2 Oct 2015 20:48:30 +0200 Subject: [PATCH 13/14] Cleanup (restarter script path extracted) --- bin/scripts/unix/idea.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/scripts/unix/idea.sh b/bin/scripts/unix/idea.sh index 6245a0620128..195cbfa0139e 100755 --- a/bin/scripts/unix/idea.sh +++ b/bin/scripts/unix/idea.sh @@ -199,9 +199,13 @@ LD_LIBRARY_PATH="$IDE_BIN_HOME:$LD_LIBRARY_PATH" "$JAVA_BIN" \ com.intellij.idea.Main \ "$@" EC=$? + test $EC -ne 88 && exit $EC -if [ -x "$HOME/.@@system_selector@@/restart/restarter.sh" ]; then - "$HOME/.@@system_selector@@/restart/restarter.sh" - "$RM" -f "$HOME/.@@system_selector@@/restart/restarter.sh" + +RESTARTER="$HOME/.@@system_selector@@/restart/restarter.sh" +if [ -x "$RESTARTER" ]; then + "$RESTARTER" + "$RM" -f "$RESTARTER" fi + exec "$0" "$@" From 955e588e03c0040bbbb6458e03cb29e3478ead2d Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 2 Oct 2015 21:50:55 +0300 Subject: [PATCH 14/14] Show generic types in PEP 484 notation (PY-16889) In particular, show unresolved refernces in generic bounds as Any. We used to ignore these unresolved types which resulted in incomprehensible warning messages. --- .../python/psi/types/PyGenericType.java | 17 ++++++++++++++++- .../PyTypeCheckerInspection/BoundedGeneric.py | 2 +- .../GenericUserClasses.py | 2 +- .../GenericUserFunctions.py | 2 +- .../PyTypeCheckerInspection/SecondFormIter.py | 2 +- .../TypingTypeVarWithUnresolvedBound.py | 11 +++++++++++ .../pyi/inspections/overloads/Overloads.py | 4 ++-- .../com/jetbrains/python/PyTypeParserTest.java | 4 ++-- .../com/jetbrains/python/PyTypingTest.java | 4 ++-- .../Py3TypeCheckerInspectionTest.java | 5 +++++ 10 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 python/testData/inspections/PyTypeCheckerInspection/TypingTypeVarWithUnresolvedBound.py diff --git a/python/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/src/com/jetbrains/python/psi/types/PyGenericType.java index 0bccf762dff2..c43f14235ab5 100644 --- a/python/src/com/jetbrains/python/psi/types/PyGenericType.java +++ b/python/src/com/jetbrains/python/psi/types/PyGenericType.java @@ -15,8 +15,11 @@ */ package com.jetbrains.python.psi.types; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; +import com.intellij.util.Function; import com.intellij.util.ProcessingContext; +import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; @@ -55,7 +58,19 @@ public class PyGenericType implements PyType { @NotNull @Override public String getName() { - return myBound != null ? myName + " <= " + myBound.getName() : myName; + if (myBound instanceof PyUnionType) { + final PyUnionType bounds = (PyUnionType)myBound; + final String boundsString = StringUtil.join(bounds.getMembers(), new Function() { + @Override + public String fun(PyType type) { + return type != null ? type.getName() : PyNames.UNKNOWN_TYPE; + } + }, ", "); + return "TypeVar('" + myName + "', " + boundsString + ")"; + } + else { + return "TypeVar('" + myName + "')"; + } } @Override diff --git a/python/testData/inspections/PyTypeCheckerInspection/BoundedGeneric.py b/python/testData/inspections/PyTypeCheckerInspection/BoundedGeneric.py index 7c626d093b1b..8de1106ee540 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/BoundedGeneric.py +++ b/python/testData/inspections/PyTypeCheckerInspection/BoundedGeneric.py @@ -8,5 +8,5 @@ def test(): x = f(10) y = f('foo') - z = f([]) + z = f([]) return x + y diff --git a/python/testData/inspections/PyTypeCheckerInspection/GenericUserClasses.py b/python/testData/inspections/PyTypeCheckerInspection/GenericUserClasses.py index e652dcf92fc6..fdef2e5afb96 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/GenericUserClasses.py +++ b/python/testData/inspections/PyTypeCheckerInspection/GenericUserClasses.py @@ -21,4 +21,4 @@ class User1(object): c = User1(10) print(c.get() + 'foo') c.put(14) -c.put('foo') +c.put('foo') diff --git a/python/testData/inspections/PyTypeCheckerInspection/GenericUserFunctions.py b/python/testData/inspections/PyTypeCheckerInspection/GenericUserFunctions.py index 937bffc0fb05..2fd5ffb4c22f 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/GenericUserFunctions.py +++ b/python/testData/inspections/PyTypeCheckerInspection/GenericUserFunctions.py @@ -40,7 +40,7 @@ def test(): print(result) print(result + 'foo') - f2(1, ['foo'], 'bar') + f2(1, ['foo'], 'bar') result = f3(1, 'foo', True) f4(result) diff --git a/python/testData/inspections/PyTypeCheckerInspection/SecondFormIter.py b/python/testData/inspections/PyTypeCheckerInspection/SecondFormIter.py index 4d2cbf6a7a6b..b44e1d22d31f 100644 --- a/python/testData/inspections/PyTypeCheckerInspection/SecondFormIter.py +++ b/python/testData/inspections/PyTypeCheckerInspection/SecondFormIter.py @@ -7,7 +7,7 @@ def test_second_form(): def test_second_form_fail(): - for chunk in iter(10, ''): + for chunk in iter(10, ''): pass diff --git a/python/testData/inspections/PyTypeCheckerInspection/TypingTypeVarWithUnresolvedBound.py b/python/testData/inspections/PyTypeCheckerInspection/TypingTypeVarWithUnresolvedBound.py new file mode 100644 index 000000000000..5953fb4baf5a --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/TypingTypeVarWithUnresolvedBound.py @@ -0,0 +1,11 @@ +from typing import TypeVar + + +T = TypeVar('T', int, unresolved) + + +def calc(a: T, b: T): + pass + + +calc('a', 0) diff --git a/python/testData/pyi/inspections/overloads/Overloads.py b/python/testData/pyi/inspections/overloads/Overloads.py index af7473a12ab9..954390000ab9 100644 --- a/python/testData/pyi/inspections/overloads/Overloads.py +++ b/python/testData/pyi/inspections/overloads/Overloads.py @@ -31,6 +31,6 @@ def test_stub_only_function(x): def tset_overloaded_generics(x): g(Gen(10).get(10, 10)) - g(Gen(10).get(10, 'foo')) - g(Gen('foo').get(10, 10)) + g(Gen(10).get(10, 'foo')) + g(Gen('foo').get(10, 10)) g(Gen('foo').get(10, 'foo')) diff --git a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java index 91fa46fbe2ed..b0f3b6aa1eeb 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java @@ -137,7 +137,7 @@ public class PyTypeParserTest extends PyTestCase { final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "T"); assertNotNull(type); assertInstanceOf(type, PyGenericType.class); - assertEquals("T", type.getName()); + assertEquals("TypeVar('T')", type.getName()); } // PY-4223 @@ -251,7 +251,7 @@ public class PyTypeParserTest extends PyTestCase { assertEquals("int", type0.getName()); final PyType type1 = parameterTypes.get(1).getType(context); assertNotNull(type1); - assertEquals("T", type1.getName()); + assertEquals("TypeVar('T')", type1.getName()); } public void testCallableWithoutArgs() { diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 876b1e956f8d..2d767ae01891 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -151,7 +151,7 @@ public class PyTypingTest extends PyTestCase { } public void testGenericType() { - doTest("A", + doTest("TypeVar('A')", "from typing import TypeVar\n" + "\n" + "T = TypeVar('A')\n" + @@ -161,7 +161,7 @@ public class PyTypingTest extends PyTestCase { } public void testGenericBoundedType() { - doTest("T <= int | str", + doTest("TypeVar('T', int, str)", "from typing import TypeVar\n" + "\n" + "T = TypeVar('T', int, str)\n" + diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java index b3fc9efa0b0e..84f2290e8a4a 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java @@ -78,4 +78,9 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase { public void testTypingListSubscriptionExpression() { doTest(); } + + // PY-16855 + public void testTypingTypeVarWithUnresolvedBound() { + doTest(); + } }