From ca9ec4b9b64590dbca6a913854d95acf27081673 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 25 Jan 2017 14:13:11 +0300 Subject: [PATCH 1/8] IDEA-166058 diff: do not save default settings * `TextDiffSettings.getSettings("custom_place")` should not add record with default settings for "custom_place" --- .../tools/util/base/TextDiffSettingsHolder.kt | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt index 9f8d44d8a53f..006f49dae445 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt @@ -154,37 +154,43 @@ class TextDiffSettingsHolder : PersistentStateComponent = defaultPlaceSettings() + internal var PLACES_MAP: TreeMap = TreeMap() internal var SHARED_SETTINGS = SharedSettings() - - companion object { - private fun defaultPlaceSettings(): TreeMap { - val map = TreeMap() - - val changes = PlaceSettings() - changes.EXPAND_BY_DEFAULT = false - val commit = PlaceSettings() - commit.EXPAND_BY_DEFAULT = false - - map.put(DiffPlaces.DEFAULT, PlaceSettings()) - map.put(DiffPlaces.CHANGES_VIEW, changes) - map.put(DiffPlaces.COMMIT_DIALOG, commit) - - return map - } - } } private var myState: State = State() override fun getState(): State { - return myState + return copyStateWithoutDefaults() } override fun loadState(state: State) { From d2db66b8f3d14d310a37861421d3e9cb9d8243dd Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 25 Jan 2017 14:25:53 +0300 Subject: [PATCH 2/8] diff: convert to Kotlin --- .../diff/impl/{DiffSettingsHolder.java => DiffSettingsHolder.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename platform/diff-impl/src/com/intellij/diff/impl/{DiffSettingsHolder.java => DiffSettingsHolder.kt} (100%) diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.java b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt similarity index 100% rename from platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.java rename to platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt From f118f1502934a43beab42d18518bed5ddeb99ea1 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 25 Jan 2017 14:30:53 +0300 Subject: [PATCH 3/8] diff: convert to Kotlin --- .../intellij/diff/impl/DiffSettingsHolder.kt | 172 +++++++----------- 1 file changed, 69 insertions(+), 103 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt index 233320827d5e..48cbdfce2a01 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt @@ -13,125 +13,91 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.diff.impl; +package com.intellij.diff.impl -import com.intellij.diff.util.DiffPlaces; -import com.intellij.diff.util.DiffUtil; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.util.Key; -import com.intellij.util.containers.HashMap; -import com.intellij.util.xmlb.annotations.MapAnnotation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import com.intellij.diff.util.DiffPlaces +import com.intellij.diff.util.DiffUtil +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.util.Key +import com.intellij.util.containers.HashMap +import com.intellij.util.xmlb.annotations.MapAnnotation +import java.util.* @State( name = "DiffSettings", - storages = @Storage(DiffUtil.DIFF_CONFIG) + storages = arrayOf(Storage(value = DiffUtil.DIFF_CONFIG)) ) -public class DiffSettingsHolder implements PersistentStateComponent { - public static final Key KEY = Key.create("DiffSettings"); +class DiffSettingsHolder : PersistentStateComponent { + companion object { + @JvmField val KEY: Key = Key.create("DiffSettings") - private static class SharedSettings { - public boolean GO_TO_NEXT_FILE_ON_NEXT_DIFFERENCE = true; - } - - private static class PlaceSettings { - @NotNull public List DIFF_TOOLS_ORDER = new ArrayList<>(); - public boolean SYNC_BINARY_EDITOR_SETTINGS = true; - } - - public static class DiffSettings { - @NotNull public SharedSettings SHARED_SETTINGS = new SharedSettings(); - @NotNull public PlaceSettings PLACE_SETTINGS = new PlaceSettings(); - - public DiffSettings() { - } - - public DiffSettings(@NotNull SharedSettings SHARED_SETTINGS, - @NotNull PlaceSettings PLACE_SETTINGS) { - this.SHARED_SETTINGS = SHARED_SETTINGS; - this.PLACE_SETTINGS = PLACE_SETTINGS; - } - - @NotNull - public List getDiffToolsOrder() { - return PLACE_SETTINGS.DIFF_TOOLS_ORDER; - } - - public void setDiffToolsOrder(@NotNull List order) { - PLACE_SETTINGS.DIFF_TOOLS_ORDER = order; - } - - public boolean isGoToNextFileOnNextDifference() { - return SHARED_SETTINGS.GO_TO_NEXT_FILE_ON_NEXT_DIFFERENCE; - } - - public void setGoToNextFileOnNextDifference(boolean value) { - SHARED_SETTINGS.GO_TO_NEXT_FILE_ON_NEXT_DIFFERENCE = value; - } - - public boolean isSyncBinaryEditorSettings() { - return PLACE_SETTINGS.SYNC_BINARY_EDITOR_SETTINGS; - } - - public void setSyncBinaryEditorSettings(boolean value) { - PLACE_SETTINGS.SYNC_BINARY_EDITOR_SETTINGS= value; - } - - // - // Impl - // - - @NotNull - public static DiffSettings getSettings() { - return getSettings(null); - } - - @NotNull - public static DiffSettings getSettings(@Nullable String place) { - return getInstance().getSettings(place); + @JvmStatic + fun getInstance(): DiffSettingsHolder { + return ServiceManager.getService(DiffSettingsHolder::class.java) } } - @NotNull - public DiffSettings getSettings(@Nullable String place) { - if (place == null) place = DiffPlaces.DEFAULT; - - PlaceSettings placeSettings = myState.PLACES_MAP.get(place); - if (placeSettings == null) { - placeSettings = new PlaceSettings(); - myState.PLACES_MAP.put(place, placeSettings); - } - return new DiffSettings(myState.SHARED_SETTINGS, placeSettings); + internal class SharedSettings { + var GO_TO_NEXT_FILE_ON_NEXT_DIFFERENCE: Boolean = true } - public static class State { + internal class PlaceSettings { + var DIFF_TOOLS_ORDER: List = ArrayList() + var SYNC_BINARY_EDITOR_SETTINGS: Boolean = true + } + + class DiffSettings internal constructor(val SHARED_SETTINGS: SharedSettings, + val PLACE_SETTINGS: PlaceSettings) { + constructor() : this(SharedSettings(), PlaceSettings()) + + var diffToolsOrder: List + get() = PLACE_SETTINGS.DIFF_TOOLS_ORDER + set(order) { PLACE_SETTINGS.DIFF_TOOLS_ORDER = order } + + var isGoToNextFileOnNextDifference: Boolean + get() = SHARED_SETTINGS.GO_TO_NEXT_FILE_ON_NEXT_DIFFERENCE + set(value) { SHARED_SETTINGS.GO_TO_NEXT_FILE_ON_NEXT_DIFFERENCE = value } + + var isSyncBinaryEditorSettings: Boolean + get() = PLACE_SETTINGS.SYNC_BINARY_EDITOR_SETTINGS + set(value) { PLACE_SETTINGS.SYNC_BINARY_EDITOR_SETTINGS = value } + + companion object { + @JvmStatic + fun getSettings(): DiffSettings { + return getSettings(null) + } + + @JvmStatic + fun getSettings(place: String?): DiffSettings { + return getInstance().getSettings(place) + } + } + } + + fun getSettings(place: String?): DiffSettings { + val placeKey = place ?: DiffPlaces.DEFAULT + val placeSettings = myState.PLACES_MAP.getOrPut(placeKey, { PlaceSettings() }) + return DiffSettings(myState.SHARED_SETTINGS, placeSettings) + } + + + class State { @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false) - public Map PLACES_MAP = new HashMap<>(); - public SharedSettings SHARED_SETTINGS = new SharedSettings(); + internal var PLACES_MAP: MutableMap = HashMap() + internal var SHARED_SETTINGS = SharedSettings() } - private State myState = new State(); + private var myState : State = State() - @NotNull - @Override - public State getState() { - return myState; + override fun getState(): State { + return myState } - @Override - public void loadState(State state) { - myState = state; - } - - public static DiffSettingsHolder getInstance() { - return ServiceManager.getService(DiffSettingsHolder.class); + override fun loadState(state: State) { + myState = state } } From 43c430f9276fb451ab9bbde401e3a044f50b4dce Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 25 Jan 2017 14:33:54 +0300 Subject: [PATCH 4/8] IDEA-166058 diff: do not save default settings --- .../intellij/diff/impl/DiffSettingsHolder.kt | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt index 48cbdfce2a01..0a27ee9620d3 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt @@ -22,7 +22,6 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.State import com.intellij.openapi.components.Storage import com.intellij.openapi.util.Key -import com.intellij.util.containers.HashMap import com.intellij.util.xmlb.annotations.MapAnnotation import java.util.* @@ -40,14 +39,14 @@ class DiffSettingsHolder : PersistentStateComponent { } } - internal class SharedSettings { + internal data class SharedSettings( var GO_TO_NEXT_FILE_ON_NEXT_DIFFERENCE: Boolean = true - } + ) - internal class PlaceSettings { - var DIFF_TOOLS_ORDER: List = ArrayList() + internal data class PlaceSettings( + var DIFF_TOOLS_ORDER: List = ArrayList(), var SYNC_BINARY_EDITOR_SETTINGS: Boolean = true - } + ) class DiffSettings internal constructor(val SHARED_SETTINGS: SharedSettings, val PLACE_SETTINGS: PlaceSettings) { @@ -80,24 +79,38 @@ class DiffSettingsHolder : PersistentStateComponent { fun getSettings(place: String?): DiffSettings { val placeKey = place ?: DiffPlaces.DEFAULT - val placeSettings = myState.PLACES_MAP.getOrPut(placeKey, { PlaceSettings() }) + val placeSettings = myState.PLACES_MAP.getOrPut(placeKey, { defaultPlaceSettings(placeKey) }) return DiffSettings(myState.SHARED_SETTINGS, placeSettings) } + private fun copyStateWithoutDefaults(): State { + val result = State() + result.SHARED_SETTINGS = myState.SHARED_SETTINGS + + myState.PLACES_MAP.entries.forEach { + if (it.value != defaultPlaceSettings(it.key)) result.PLACES_MAP.put(it.key, it.value) + } + return result + } + + private fun defaultPlaceSettings(place: String): PlaceSettings { + return PlaceSettings() + } + class State { @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false) - internal var PLACES_MAP: MutableMap = HashMap() + internal var PLACES_MAP: TreeMap = TreeMap() internal var SHARED_SETTINGS = SharedSettings() } - private var myState : State = State() + private var myState: State = State() override fun getState(): State { - return myState + return copyStateWithoutDefaults() } override fun loadState(state: State) { myState = state } -} +} \ No newline at end of file From 3b0286e2432cbbec1bd3c249231e7401d6023bac Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Wed, 11 Jan 2017 12:40:14 +0300 Subject: [PATCH 5/8] Fix warnings in PyParameterInfoTest --- .../jetbrains/python/PyParameterInfoTest.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java b/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java index fe461d073447..819c89ac53a3 100644 --- a/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java +++ b/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,6 @@ import com.intellij.util.containers.HashSet; import com.jetbrains.python.fixtures.LightMarkedTestCase; import com.jetbrains.python.psi.PyArgumentList; import com.jetbrains.python.psi.PyCallExpression; -import junit.framework.Assert; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -53,7 +52,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase { protected Map loadTest(int expected_marks) { Map marks = loadTest(); - Assert.assertEquals("Test data sanity", marks.size(), expected_marks); + assertEquals("Test data sanity", marks.size(), expected_marks); return marks; } @@ -405,14 +404,14 @@ public class PyParameterInfoTest extends LightMarkedTestCase { public void testNoArgsException() { Map marks = loadTest(1); - feignCtrlP(marks.get("").getTextOffset()).check("", new String[0], new String[]{""}); + feignCtrlP(marks.get("").getTextOffset()).check("", ArrayUtil.EMPTY_STRING_ARRAY, new String[]{""}); } public void testMultilineStringDefault() { - Map marks = loadTest(1); - feignCtrlP(marks.get("").getTextOffset()).check("length=12, allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'", - new String[]{"allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'"}, - new String[0]); + final int offset = loadTest(1).get("").getTextOffset(); + feignCtrlP(offset).check("length=12, allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'", + new String[]{"allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'"}, + ArrayUtil.EMPTY_STRING_ARRAY); } /** @@ -427,7 +426,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase { final PyArgumentList parameterOwner = handler.findElementForParameterInfo(collector); collector.setParameterOwner(parameterOwner); // finds arglist, sets items to show if (collector.getParameterOwner() != null) { - Assert.assertEquals("Collected one analysis result", 1, collector.myItems.length); + assertEquals("Collected one analysis result", 1, collector.myItems.length); handler.updateParameterInfo((PyArgumentList)collector.getParameterOwner(), collector); // moves offset to correct parameter handler.updateUI((PyCallExpression.PyArgumentsMapping)collector.getItemsToShow()[0], collector); // sets hint text and flags } @@ -501,7 +500,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase { @Override public void setParameterOwner(PsiElement o) { - Assert.assertTrue("Found element is a python arglist", o == null || o instanceof PyArgumentList); + assertTrue("Found element is a python arglist", o == null || o instanceof PyArgumentList); myParamOwner = (PyArgumentList)o; } @@ -586,7 +585,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase { * @param disabled expected disabled substrings of hint */ public void check(String text, String[] highlighted, String[] disabled) { - Assert.assertEquals("Signature", text, StringUtil.join(myTexts, "")); + assertEquals("Signature", text, StringUtil.join(myTexts, "")); StringBuilder wrongs = new StringBuilder(); // see if highlighted matches Set highlightSet = new HashSet<>(); @@ -615,7 +614,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase { } } // - if (wrongs.length() > 0) Assert.fail(wrongs.toString()); + if (wrongs.length() > 0) fail(wrongs.toString()); } public void check(String text, String[] highlighted) { @@ -623,7 +622,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase { } public void assertNotFound() { - Assert.assertNull(myParamOwner); + assertNull(myParamOwner); } } } From 60e9609754f16c242ecb8f453aafb65de0de190c Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Wed, 18 Jan 2017 14:14:59 +0300 Subject: [PATCH 6/8] Attempt to simplify methods in PythonDocumentationProvider that return type name or type description --- .../documentation/PyDocumentationBuilder.java | 6 +- .../PythonDocumentationProvider.java | 65 ++++++++++--------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index 1ff13014b987..d0eb4b77dfc1 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -104,7 +104,7 @@ public class PyDocumentationBuilder { } else if (elementDefinition != null && outerElement instanceof PyReferenceExpression) { myBody.addItem(combUp("\nInferred type: ")); - PythonDocumentationProvider.describeExpressionTypeWithLinks(myBody, (PyReferenceExpression)outerElement, context); + PythonDocumentationProvider.describeTypeWithLinks(context.getType((PyReferenceExpression)outerElement), context, outerElement, myBody); } if (elementDefinition != null) { @@ -189,7 +189,7 @@ public class PyDocumentationBuilder { } if (typeString != null) { myBody.addItem(combUp(typeString)); - PythonDocumentationProvider.describeTypeWithLinks(myBody, elementDefinition, type, context); + PythonDocumentationProvider.describeTypeWithLinks(type, context, elementDefinition, myBody); } } } diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index a4abfb0afbd6..7c92aa1433b5 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import com.intellij.lang.documentation.AbstractDocumentationProvider; import com.intellij.lang.documentation.ExternalDocumentationProvider; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; @@ -32,10 +31,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; -import com.intellij.util.Function; import com.jetbrains.python.PyNames; import com.jetbrains.python.PythonDialectsTokenSetProvider; -import com.jetbrains.python.codeInsight.PyCodeInsightSettings; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.console.PydevDocumentationProvider; import com.jetbrains.python.documentation.docstrings.DocStringUtil; @@ -151,7 +148,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i cat.addItem(escaper.apply(paramStr)); if (!PyNames.INIT.equals(name)) { cat.addItem(escaper.apply("\nInferred type: ")); - getTypeDescription(fun, cat); + describeTypeWithLinks(fun, cat); cat.addItem(BR); } return cat; @@ -171,48 +168,56 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } } if (originalElement instanceof PyTypedElement) { - result.append("\n").append(describeType((PyTypedElement)originalElement)); + final String typeName = getTypeName(((PyTypedElement)originalElement)); + result + .append("\n") + .append(String.format("Inferred type: %s", typeName)); } return result.toString(); } return null; } - private static String describeType(@NotNull PyTypedElement element) { + @NotNull + private static String getTypeName(@NotNull PyTypedElement element) { final TypeEvalContext context = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()); - return String.format("Inferred type: %s", getTypeName(context.getType(element), context)); - } - - private static void getTypeDescription(@NotNull PyFunction fun, @NotNull ChainIterable body) { - final TypeEvalContext context = TypeEvalContext.userInitiated(fun.getProject(), fun.getContainingFile()); - final PyTypeModelBuilder builder = new PyTypeModelBuilder(context); - builder.build(context.getType(fun), true).toBodyWithLinks(body, fun); + return getTypeName(context.getType(element), context); } + /** + * @param type type which name will be calculated + * @param context type evaluation context + * @return string representation of the type + */ + @NotNull public static String getTypeName(@Nullable PyType type, @NotNull TypeEvalContext context) { - final PyTypeModelBuilder.TypeModel typeModel = buildTypeModel(type, context); - return typeModel.asString(); + return buildTypeModel(type, context).asString(); } - private static PyTypeModelBuilder.TypeModel buildTypeModel(PyType type, TypeEvalContext context) { - PyTypeModelBuilder builder = new PyTypeModelBuilder(context); - return builder.build(type, true); + private static void describeTypeWithLinks(@NotNull PyTypedElement element, @NotNull ChainIterable body) { + final TypeEvalContext context = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()); + describeTypeWithLinks(context.getType(element), context, element, body); } - public static void describeExpressionTypeWithLinks(@NotNull ChainIterable body, - @NotNull PyReferenceExpression expression, - @NotNull TypeEvalContext context) { - final PyType type = context.getType(expression); - describeTypeWithLinks(body, expression, type, context); - } - - public static void describeTypeWithLinks(@NotNull ChainIterable body, + /** + * @param type type which description will be calculated. + * Description is the same as {@link PythonDocumentationProvider#getTypeDescription(PyType, TypeEvalContext)} gives but + * types are converted to links. + * @param context type evaluation context + * @param anchor anchor element + * @param body body to be used to append description + */ + public static void describeTypeWithLinks(@Nullable PyType type, + @NotNull TypeEvalContext context, @NotNull PsiElement anchor, - PyType type, TypeEvalContext context) { - final PyTypeModelBuilder builder = new PyTypeModelBuilder(context); - builder.build(type, true).toBodyWithLinks(body, anchor); + @NotNull ChainIterable body) { + buildTypeModel(type, context).toBodyWithLinks(body, anchor); } + @NotNull + private static PyTypeModelBuilder.TypeModel buildTypeModel(@Nullable PyType type, @NotNull TypeEvalContext context) { + return new PyTypeModelBuilder(context).build(type, true); + } @NotNull static ChainIterable describeDecorators(@NotNull PyDecoratable what, From a6383951ff101c4e2a7613a3e69622ceef59ca53 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Wed, 18 Jan 2017 16:49:34 +0300 Subject: [PATCH 7/8] PY-22005 Fixed: Show types in parameter hints Append expected argument type to parameter info Details: `Any` is excluded from `Union[Any, ...]`-like types `None` default value is hidden because it will be listed in the type as `Optional[...]` or `Union[..., None, ...]` --- .../python/psi/PyNamedParameter.java | 31 +++++++- .../python/PyParameterInfoHandler.java | 16 ++-- .../documentation/PyTypeModelBuilder.java | 57 ++++++++++---- .../PythonDocumentationProvider.java | 11 +++ .../inspections/PyTypeCheckerInspection.java | 10 +-- .../python/psi/impl/PyNamedParameterImpl.java | 49 +++++++++++- .../python/psi/types/PyTypeChecker.java | 26 +------ .../testData/paramInfo/WithSpecifiedType.py | 7 ++ .../jetbrains/python/PyParameterInfoTest.java | 76 +++++++++++-------- 9 files changed, 196 insertions(+), 87 deletions(-) create mode 100644 python/testData/paramInfo/WithSpecifiedType.py diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyNamedParameter.java b/python/psi-api/src/com/jetbrains/python/psi/PyNamedParameter.java index 48b5e6ec473b..8c9d4bccdf0c 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyNamedParameter.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyNamedParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,10 @@ import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.StubBasedPsiElement; import com.jetbrains.python.psi.stubs.PyNamedParameterStub; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Represents a named parameter, as opposed to a tuple parameter. @@ -39,10 +42,30 @@ public interface PyNamedParameter extends PyParameter, PsiNamedElement, PsiNameI boolean isKeywordOnly(); /** - * @param includeDefaultValue if true, include the default value after an " = ". - * @return Canonical representation of parameter. Includes asterisks for *param and **param, and name. + * @param includeDefaultValue if true, include the default value after an "=". + * @return canonical representation of parameter. + * Includes asterisks for *param and **param, and name. */ @NotNull - String getRepr(boolean includeDefaultValue); + default String getRepr(boolean includeDefaultValue) { + return getRepr(includeDefaultValue, null); + } + + /** + * @param includeDefaultValue if true, include the default value after an "=". + * @param context context to be used to resolve argument type + * @return canonical representation of parameter. + * Includes asterisks for *param and **param, and name. + * Also includes argument type if {@code context} is not null and resolved type is not unknown. + */ + @NotNull + String getRepr(boolean includeDefaultValue, @Nullable TypeEvalContext context); + + /** + * @param context context to be used to resolve argument type + * @return argument type. Returns element type for *param and value type for **param. + */ + @Nullable + PyType getArgumentType(@NotNull TypeEvalContext context); } diff --git a/python/src/com/jetbrains/python/PyParameterInfoHandler.java b/python/src/com/jetbrains/python/PyParameterInfoHandler.java index 4307c6d6d0fa..54f429490642 100644 --- a/python/src/com/jetbrains/python/PyParameterInfoHandler.java +++ b/python/src/com/jetbrains/python/PyParameterInfoHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -166,7 +166,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler flags. this includes flags for parens. final Map> hintFlags = new HashMap<>(); - final List hintsList = buildParameterListHint(parameterList, namedParameters, parameterToIndex, hintFlags); + final List hintsList = buildParameterListHint(parameterList, namedParameters, parameterToIndex, hintFlags, typeEvalContext); final int currentParamOffset = context.getCurrentParameterIndex(); // in Python mode, we get an offset here, not an index! @@ -324,15 +324,17 @@ public class PyParameterInfoHandler implements ParameterInfoHandler buildParameterListHint(@NotNull List parameters, @NotNull final List namedParameters, @NotNull final Map parameterToIndex, - @NotNull final Map> hintFlags) { + @NotNull final Map> hintFlags, + @NotNull TypeEvalContext context) { final List hintsList = new ArrayList<>(); ParamHelper.walkDownParamArray( parameters.toArray(new PyParameter[parameters.size()]), @@ -350,7 +352,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler body, @NotNull PsiElement anchor) { - TypeToBodyWithLinksVisitor visitor = new TypeToBodyWithLinksVisitor(body, anchor); - this.accept(visitor); + final TypeToBodyWithLinksVisitor visitor = new TypeToBodyWithLinksVisitor(body, anchor); + accept(visitor); + } + + @NotNull + public String asDescription() { + final TypeToDescriptionVisitor visitor = new TypeToDescriptionVisitor(); + accept(visitor); + return visitor.getDescription(); } } @@ -65,7 +73,7 @@ public class PyTypeModelBuilder { } @Override - void accept(TypeVisitor visitor) { + void accept(@NotNull TypeVisitor visitor) { visitor.oneOf(this); } } @@ -80,7 +88,7 @@ public class PyTypeModelBuilder { } @Override - void accept(TypeVisitor visitor) { + void accept(@NotNull TypeVisitor visitor) { visitor.collectionOf(this); } } @@ -93,7 +101,7 @@ public class PyTypeModelBuilder { } @Override - void accept(TypeVisitor visitor) { + void accept(@NotNull TypeVisitor visitor) { visitor.name(this.name); } } @@ -106,7 +114,7 @@ public class PyTypeModelBuilder { } @Override - void accept(TypeVisitor visitor) { + void accept(@NotNull TypeVisitor visitor) { visitor.unknown(this); } } @@ -119,7 +127,7 @@ public class PyTypeModelBuilder { } @Override - void accept(TypeVisitor visitor) { + void accept(@NotNull TypeVisitor visitor) { visitor.optional(this); } } @@ -134,7 +142,7 @@ public class PyTypeModelBuilder { } @Override - void accept(TypeVisitor visitor) { + void accept(@NotNull TypeVisitor visitor) { visitor.tuple(this); } } @@ -158,7 +166,7 @@ public class PyTypeModelBuilder { } @Override - void accept(TypeVisitor visitor) { + void accept(@NotNull TypeVisitor visitor) { visitor.function(this); } } @@ -174,7 +182,7 @@ public class PyTypeModelBuilder { } @Override - void accept(TypeVisitor visitor) { + void accept(@NotNull TypeVisitor visitor) { visitor.param(this); } } @@ -359,6 +367,27 @@ public class PyTypeModelBuilder { } } + private static class TypeToDescriptionVisitor extends TypeNameVisitor { + + @NotNull + private final StringBuilder myResult = new StringBuilder(); + + @Override + protected void add(String s) { + myResult.append(s); + } + + @Override + protected void addType(String name) { + add(name); + } + + @NotNull + public String getDescription() { + return myResult.toString(); + } + } + private abstract static class TypeNameVisitor implements TypeVisitor { private int myDepth = 0; private final static int MAX_DEPTH = 6; diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index 7c92aa1433b5..52736b30c3af 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -214,6 +214,17 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i buildTypeModel(type, context).toBodyWithLinks(body, anchor); } + /** + * @param type type which description will be calculated + * @param context type evaluation context + * @return more user-friendly description than result of {@link PythonDocumentationProvider#getTypeName(PyType, TypeEvalContext)}. + * Any is excluded from Union[Any, ...]-like types. + */ + @NotNull + public static String getTypeDescription(@Nullable PyType type, @NotNull TypeEvalContext context) { + return buildTypeModel(type, context).asDescription(); + } + @NotNull private static PyTypeModelBuilder.TypeModel buildTypeModel(@Nullable PyType type, @NotNull TypeEvalContext context) { return new PyTypeModelBuilder(context).build(type, true); diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 114ad867e10d..7af8821c0375 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -189,10 +189,8 @@ public class PyTypeCheckerInspection extends PyInspection { problemsSet.add(checkMapping(results.getReceiver(), results.getArguments())); } if (!problemsSet.isEmpty()) { - Map> minProblems = Collections.min( - problemsSet, - (o1, o2) -> o1.size() - o2.size() - ); + final Map> minProblems = Collections.min(problemsSet, + Comparator.comparingInt(Map::size)); for (Map.Entry> entry : minProblems.entrySet()) { registerProblem(entry.getKey(), entry.getValue().getFirst(), entry.getValue().getSecond()); } @@ -222,7 +220,7 @@ public class PyTypeCheckerInspection extends PyInspection { for (Map.Entry entry : mapping.entrySet()) { final PyNamedParameter param = entry.getValue(); final PyExpression arg = entry.getKey(); - final PyType expectedArgType = PyTypeChecker.getExpectedArgumentType(param, myTypeEvalContext); + final PyType expectedArgType = param.getArgumentType(myTypeEvalContext); if (expectedArgType == null) { continue; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index 326cbf8ca852..5b6c6cd1fdfd 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PlatformIcons; import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; @@ -35,6 +36,7 @@ import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.codeInsight.PyTypingTypeProvider; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; +import com.jetbrains.python.documentation.PythonDocumentationProvider; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.stubs.PyNamedParameterStub; @@ -166,13 +168,25 @@ public class PyNamedParameterImpl extends PyBaseElementImpl quotes = PyStringLiteralUtil.getQuotes(defaultValue.getText()); @@ -182,9 +196,36 @@ public class PyNamedParameterImpl extends PyBaseElementImpl) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java b/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java index 819c89ac53a3..0650215715d5 100644 --- a/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java +++ b/python/testSrc/com/jetbrains/python/PyParameterInfoTest.java @@ -29,6 +29,7 @@ import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.jetbrains.python.fixtures.LightMarkedTestCase; +import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.psi.PyArgumentList; import com.jetbrains.python.psi.PyCallExpression; import org.jetbrains.annotations.NotNull; @@ -151,7 +152,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase { public void testKwdArgInClass() { Map marks = loadTest(1); - feignCtrlP(marks.get("").getTextOffset()).check("self, **kw", new String[]{"**kw"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, **kw", new String[]{"**kw"}, new String[]{"self: A, "}); } public void testKwdArgOutOfOrder() { @@ -222,14 +223,14 @@ public class PyParameterInfoTest extends LightMarkedTestCase { public void testSimpleMethod() { Map marks = loadTest(1); - feignCtrlP(marks.get("").getTextOffset()).check("self, a", new String[]{"a"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, a", new String[]{"a"}, new String[]{"self: A, "}); } public void testSimpleClassFunction() { Map marks = loadTest(2); - feignCtrlP(marks.get("").getTextOffset()).check("self, a", new String[]{"self, "}); - feignCtrlP(marks.get("").getTextOffset()).check("self, a", new String[]{"a"}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, a", new String[]{"self: A, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, a", new String[]{"a"}); } public void testReassignedFunction() { @@ -242,65 +243,65 @@ public class PyParameterInfoTest extends LightMarkedTestCase { public void testReassignedInstanceMethod() { Map marks = loadTest(3); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b, c", new String[]{"a, "}, new String[]{"self, "}); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b, c", new String[]{"b, "}, new String[]{"self, "}); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b, c", new String[]{"c"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: Foo, a, b, c", new String[]{"a, "}, new String[]{"self: Foo, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: Foo, a, b, c", new String[]{"b, "}, new String[]{"self: Foo, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: Foo, a, b, c", new String[]{"c"}, new String[]{"self: Foo, "}); } public void testReassignedClassInit() { Map marks = loadTest(2); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b", new String[]{"a, "}, new String[]{"self, "}); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b", new String[]{"b"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: Bar, a, b", new String[]{"a, "}, new String[]{"self: Bar, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: Bar, a, b", new String[]{"b"}, new String[]{"self: Bar, "}); } public void testInheritedClassInit() { Map marks = loadTest(2); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b", new String[]{"a, "}, new String[]{"self, "}); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b", new String[]{"b"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: Bar, a, b", new String[]{"a, "}, new String[]{"self: Bar, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: Bar, a, b", new String[]{"b"}, new String[]{"self: Bar, "}); } public void testRedefinedNewConstructorCall() { Map marks = loadTest(2); - feignCtrlP(marks.get("").getTextOffset()).check("cls, a, b", new String[]{"a, "}, new String[]{"cls, "}); - feignCtrlP(marks.get("").getTextOffset()).check("cls, a, b", new String[]{"b"}, new String[]{"cls, "}); + feignCtrlP(marks.get("").getTextOffset()).check("cls: A, a, b", new String[]{"a, "}, new String[]{"cls: A, "}); + feignCtrlP(marks.get("").getTextOffset()).check("cls: A, a, b", new String[]{"b"}, new String[]{"cls: A, "}); } public void testRedefinedNewDirectCall() { Map marks = loadTest(3); - feignCtrlP(marks.get("").getTextOffset()).check("cls, a, b", new String[]{"cls, "}); - feignCtrlP(marks.get("").getTextOffset()).check("cls, a, b", new String[]{"a, "}); - feignCtrlP(marks.get("").getTextOffset()).check("cls, a, b", new String[]{"b"}); + feignCtrlP(marks.get("").getTextOffset()).check("cls: A, a, b", new String[]{"cls: A, "}); + feignCtrlP(marks.get("").getTextOffset()).check("cls: A, a, b", new String[]{"a, "}); + feignCtrlP(marks.get("").getTextOffset()).check("cls: A, a, b", new String[]{"b"}); } public void testIgnoreNewInOldStyleClass() { Map marks = loadTest(1); - feignCtrlP(marks.get("").getTextOffset()).check("self, one", new String[]{"one"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, one", new String[]{"one"}, new String[]{"self: A, "}); } public void testBoundMethodSimple() { Map marks = loadTest(2); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b", new String[]{"a, "}, new String[]{"self, "}); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b", new String[]{"b"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, a, b", new String[]{"a, "}, new String[]{"self: A, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, a, b", new String[]{"b"}, new String[]{"self: A, "}); } public void testBoundMethodReassigned() { Map marks = loadTest(2); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b", new String[]{"a, "}, new String[]{"self, "}); - feignCtrlP(marks.get("").getTextOffset()).check("self, a, b", new String[]{"b"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, a, b", new String[]{"a, "}, new String[]{"self: A, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: A, a, b", new String[]{"b"}, new String[]{"self: A, "}); } public void testConstructorFactory() { Map marks = loadTest(1); - feignCtrlP(marks.get("").getTextOffset()).check("self, color", new String[]{"color"}, new String[]{"self, "}); + feignCtrlP(marks.get("").getTextOffset()).check("self: Foo, color", new String[]{"color"}, new String[]{"self: Foo, "}); } @@ -385,16 +386,16 @@ public class PyParameterInfoTest extends LightMarkedTestCase { public void testPartialNamed() { Map marks = loadTest(2); - feignCtrlP(marks.get("").getTextOffset()).check("a, b, c=1, d=2, e=3", new String[]{"d=2, "}); - feignCtrlP(marks.get("").getTextOffset()).check("a, b, c=1, d=2, e=3", new String[]{"e=3"}); // no logical next + feignCtrlP(marks.get("").getTextOffset()).check("a, b, c: int=1, d: int=2, e: int=3", new String[]{"d: int=2, "}); + feignCtrlP(marks.get("").getTextOffset()).check("a, b, c: int=1, d: int=2, e: int=3", new String[]{"e: int=3"}); // no logical next } public void testPy3kPastTupleArg() { Map marks = loadTest(4); - feignCtrlP(marks.get("").getTextOffset()).check("*arg, a=1, b=2", new String[]{"*arg, "}); - feignCtrlP(marks.get("").getTextOffset()).check("*arg, a=1, b=2", new String[]{"*arg, "}); - feignCtrlP(marks.get("").getTextOffset()).check("*arg, a=1, b=2", new String[]{"b=2"}); - feignCtrlP(marks.get("").getTextOffset()).check("*arg, a=1, b=2", new String[]{"a=1, "}); + feignCtrlP(marks.get("").getTextOffset()).check("*arg, a: int=1, b: int=2", new String[]{"*arg, "}); + feignCtrlP(marks.get("").getTextOffset()).check("*arg, a: int=1, b: int=2", new String[]{"*arg, "}); + feignCtrlP(marks.get("").getTextOffset()).check("*arg, a: int=1, b: int=2", new String[]{"b: int=2"}); + feignCtrlP(marks.get("").getTextOffset()).check("*arg, a: int=1, b: int=2", new String[]{"a: int=1, "}); } public void testNoArgs() { @@ -409,11 +410,26 @@ public class PyParameterInfoTest extends LightMarkedTestCase { public void testMultilineStringDefault() { final int offset = loadTest(1).get("").getTextOffset(); - feignCtrlP(offset).check("length=12, allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'", - new String[]{"allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'"}, + feignCtrlP(offset).check("length: int=12, allowed_chars: str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'", + new String[]{"allowed_chars: str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'"}, ArrayUtil.EMPTY_STRING_ARRAY); } + // PY-22005 + public void testWithSpecifiedType() { + myFixture.copyDirectoryToProject("typing", ""); + + runWithLanguageLevel( + LanguageLevel.PYTHON35, + () -> { + final int offset = loadTest(1).get("").getTextOffset(); + final String expectedInfo = "a1: str, a2: Optional[str], a3: Union[str, int, None], a4: int, *args: int, **kwargs: int"; + + feignCtrlP(offset).check(expectedInfo, new String[]{"a1: str, "}); + } + ); + } + /** * Imitates pressing of Ctrl+P; fails if results are not as expected. * @param offset offset of 'cursor' where ^P is pressed. From 9c45a5ce49f8f292eb04c582a72f386770e31ce4 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Wed, 18 Jan 2017 15:48:07 +0300 Subject: [PATCH 8/8] Fix warnings in PyTypeModelBuilder --- .../documentation/PyTypeModelBuilder.java | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java index 2d68ec1fe736..074daf74c012 100644 --- a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java @@ -94,15 +94,25 @@ public class PyTypeModelBuilder { } static class NamedType extends TypeModel { + + @NotNull + private static final NamedType ANY = new NamedType(PyNames.UNKNOWN_TYPE); + + @Nullable private String name; - private NamedType(String name) { + private NamedType(@Nullable String name) { this.name = name; } @Override void accept(@NotNull TypeVisitor visitor) { - visitor.name(this.name); + visitor.name(name); + } + + @NotNull + private static NamedType nameOrAny(@Nullable PyType type) { + return type == null ? ANY : new NamedType(type.getName()); } } @@ -147,21 +157,12 @@ public class PyTypeModelBuilder { } } - private static TypeModel _(String name) { - return new NamedType(name); - } - static class FunctionType extends TypeModel { - private TypeModel returnType; - @Nullable private Collection parameters; + @NotNull private final TypeModel returnType; + @Nullable private final Collection parameters; - FunctionType(@Nullable TypeModel returnType, @Nullable Collection parameters) { - if (returnType != null) { - this.returnType = returnType; - } - else { - this.returnType = _(PyNames.UNKNOWN_TYPE); - } + private FunctionType(@Nullable TypeModel returnType, @Nullable Collection parameters) { + this.returnType = returnType != null ? returnType : NamedType.ANY; this.parameters = parameters; } @@ -175,7 +176,6 @@ public class PyTypeModelBuilder { @Nullable private final String name; @Nullable private final TypeModel type; - private ParamType(@Nullable String name, @Nullable TypeModel type) { this.name = name; this.type = type; @@ -201,7 +201,7 @@ public class PyTypeModelBuilder { return evaluated; } if (myVisited.containsKey(type)) { //already evaluating? - return type != null ? _(type.getName()) : _(PyNames.UNKNOWN_TYPE); + return NamedType.nameOrAny(type); } myVisited.put(type, null); //mark as evaluating @@ -252,7 +252,7 @@ public class PyTypeModelBuilder { result = build((PyCallableType)type); } if (result == null) { - result = type != null ? _(type.getName()) : _(PyNames.UNKNOWN_TYPE); + result = NamedType.nameOrAny(type); } myVisited.put(type, result); return result; @@ -356,10 +356,9 @@ public class PyTypeModelBuilder { @Override protected void addType(String name) { - PyType type = PyTypeParser.getTypeByName(myAnchor, name); + final PyType type = PyTypeParser.getTypeByName(myAnchor, name); if (type instanceof PyClassType) { - myBody.addWith(new DocumentationBuilderKit.LinkWrapper(PythonDocumentationProvider.LINK_TYPE_TYPENAME + name), - $(name)); + myBody.addWith(new DocumentationBuilderKit.LinkWrapper(PythonDocumentationProvider.LINK_TYPE_TYPENAME + name), $(name)); } else { add(name); @@ -400,16 +399,16 @@ public class PyTypeModelBuilder { return; } add("Union["); - processList(oneOf.oneOfTypes, ", "); + processList(oneOf.oneOfTypes); add("]"); myDepth--; } - private void processList(Collection list, String separator) { + private void processList(@NotNull Collection list) { boolean first = true; for (TypeModel t : list) { if (!first) { - add(separator); + add(", "); } else { first = false; @@ -432,7 +431,7 @@ public class PyTypeModelBuilder { final String typingName = PyTypingTypeProvider.TYPING_COLLECTION_CLASSES.get(name); addType(typingName != null ? typingName : name); add("["); - processList(collectionOf.elementTypes, ", "); + processList(collectionOf.elementTypes); add("]"); myDepth--; } @@ -454,7 +453,7 @@ public class PyTypeModelBuilder { add("("); final Collection parameters = function.parameters; if (parameters != null) { - processList(parameters, ", "); + processList(parameters); } else { add("..."); @@ -498,7 +497,7 @@ public class PyTypeModelBuilder { @Override public void tuple(TupleType type) { add("Tuple["); - processList(type.members, ", "); + processList(type.members); if (type.homogeneous) { add(", ..."); }