Merge remote-tracking branch 'origin/master'

This commit is contained in:
Daniil Ovchinnikov
2017-01-25 15:38:34 +03:00
13 changed files with 412 additions and 315 deletions
@@ -1,137 +0,0 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.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;
@State(
name = "DiffSettings",
storages = @Storage(DiffUtil.DIFF_CONFIG)
)
public class DiffSettingsHolder implements PersistentStateComponent<DiffSettingsHolder.State> {
public static final Key<DiffSettings> 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<String> 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<String> getDiffToolsOrder() {
return PLACE_SETTINGS.DIFF_TOOLS_ORDER;
}
public void setDiffToolsOrder(@NotNull List<String> 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);
}
}
@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);
}
public static class State {
@MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false)
public Map<String, PlaceSettings> PLACES_MAP = new HashMap<>();
public SharedSettings SHARED_SETTINGS = new SharedSettings();
}
private State myState = new State();
@NotNull
@Override
public State getState() {
return myState;
}
@Override
public void loadState(State state) {
myState = state;
}
public static DiffSettingsHolder getInstance() {
return ServiceManager.getService(DiffSettingsHolder.class);
}
}
@@ -0,0 +1,116 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.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.xmlb.annotations.MapAnnotation
import java.util.*
@State(
name = "DiffSettings",
storages = arrayOf(Storage(value = DiffUtil.DIFF_CONFIG))
)
class DiffSettingsHolder : PersistentStateComponent<DiffSettingsHolder.State> {
companion object {
@JvmField val KEY: Key<DiffSettings> = Key.create("DiffSettings")
@JvmStatic
fun getInstance(): DiffSettingsHolder {
return ServiceManager.getService(DiffSettingsHolder::class.java)
}
}
internal data class SharedSettings(
var GO_TO_NEXT_FILE_ON_NEXT_DIFFERENCE: Boolean = true
)
internal data class PlaceSettings(
var DIFF_TOOLS_ORDER: List<String> = 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<String>
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, { 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: TreeMap<String, PlaceSettings> = TreeMap()
internal var SHARED_SETTINGS = SharedSettings()
}
private var myState: State = State()
override fun getState(): State {
return copyStateWithoutDefaults()
}
override fun loadState(state: State) {
myState = state
}
}
@@ -154,37 +154,43 @@ class TextDiffSettingsHolder : PersistentStateComponent<TextDiffSettingsHolder.S
}
fun getSettings(place: String?): TextDiffSettings {
val placeSettings = myState.PLACES_MAP.getOrPut(place ?: DiffPlaces.DEFAULT, { PlaceSettings() })
val placeKey = place ?: DiffPlaces.DEFAULT
val placeSettings = myState.PLACES_MAP.getOrPut(placeKey, { defaultPlaceSettings(placeKey) })
return TextDiffSettings(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 {
val settings = PlaceSettings();
if (place == DiffPlaces.CHANGES_VIEW) {
settings.EXPAND_BY_DEFAULT = false
}
if (place == DiffPlaces.COMMIT_DIALOG) {
settings.EXPAND_BY_DEFAULT = false
}
return settings
}
class State {
@MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false)
internal var PLACES_MAP: TreeMap<String, PlaceSettings> = defaultPlaceSettings()
internal var PLACES_MAP: TreeMap<String, PlaceSettings> = TreeMap()
internal var SHARED_SETTINGS = SharedSettings()
companion object {
private fun defaultPlaceSettings(): TreeMap<String, PlaceSettings> {
val map = TreeMap<String, PlaceSettings>()
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) {
@@ -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);
}
@@ -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<PyArgumentLi
// formatting of hints: hint index -> flags. this includes flags for parens.
final Map<Integer, EnumSet<ParameterInfoUIContextEx.Flag>> hintFlags = new HashMap<>();
final List<String> hintsList = buildParameterListHint(parameterList, namedParameters, parameterToIndex, hintFlags);
final List<String> 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<PyArgumentLi
/**
* builds the textual picture and the list of named parameters
*
* @param parameters parameters of a callable
* @param namedParameters used to collect all named parameters of callable
* @param parameters parameters of a callable
* @param namedParameters used to collect all named parameters of callable
* @param parameterToIndex used to collect info about parameter indexes
* @param hintFlags mark parameter as deprecated/highlighted/strikeout
* @param hintFlags mark parameter as deprecated/highlighted/strikeout
* @param context context to be used to get parameter representation
*/
private static List<String> buildParameterListHint(@NotNull List<PyParameter> parameters,
@NotNull final List<PyNamedParameter> namedParameters,
@NotNull final Map<PyNamedParameter, Integer> parameterToIndex,
@NotNull final Map<Integer, EnumSet<ParameterInfoUIContextEx.Flag>> hintFlags) {
@NotNull final Map<Integer, EnumSet<ParameterInfoUIContextEx.Flag>> hintFlags,
@NotNull TypeEvalContext context) {
final List<String> hintsList = new ArrayList<>();
ParamHelper.walkDownParamArray(
parameters.toArray(new PyParameter[parameters.size()]),
@@ -350,7 +352,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentLi
public void visitNamedParameter(PyNamedParameter param, boolean first, boolean last) {
namedParameters.add(param);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(param.getRepr(true));
stringBuilder.append(param.getRepr(true, context));
if (!last) stringBuilder.append(", ");
int hintIndex = hintsList.size();
parameterToIndex.put(param, hintIndex);
@@ -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);
}
}
}
@@ -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.
@@ -43,17 +43,25 @@ public class PyTypeModelBuilder {
}
abstract static class TypeModel {
abstract void accept(TypeVisitor visitor);
abstract void accept(@NotNull TypeVisitor visitor);
@NotNull
public String asString() {
TypeToStringVisitor visitor = new TypeToStringVisitor();
this.accept(visitor);
final TypeToStringVisitor visitor = new TypeToStringVisitor();
accept(visitor);
return visitor.getString();
}
public void toBodyWithLinks(@NotNull ChainIterable<String> 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,21 +88,31 @@ public class PyTypeModelBuilder {
}
@Override
void accept(TypeVisitor visitor) {
void accept(@NotNull TypeVisitor visitor) {
visitor.collectionOf(this);
}
}
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(TypeVisitor visitor) {
visitor.name(this.name);
void accept(@NotNull TypeVisitor visitor) {
visitor.name(name);
}
@NotNull
private static NamedType nameOrAny(@Nullable PyType type) {
return type == null ? ANY : new NamedType(type.getName());
}
}
@@ -106,7 +124,7 @@ public class PyTypeModelBuilder {
}
@Override
void accept(TypeVisitor visitor) {
void accept(@NotNull TypeVisitor visitor) {
visitor.unknown(this);
}
}
@@ -119,7 +137,7 @@ public class PyTypeModelBuilder {
}
@Override
void accept(TypeVisitor visitor) {
void accept(@NotNull TypeVisitor visitor) {
visitor.optional(this);
}
}
@@ -134,31 +152,22 @@ public class PyTypeModelBuilder {
}
@Override
void accept(TypeVisitor visitor) {
void accept(@NotNull TypeVisitor visitor) {
visitor.tuple(this);
}
}
private static TypeModel _(String name) {
return new NamedType(name);
}
static class FunctionType extends TypeModel {
private TypeModel returnType;
@Nullable private Collection<TypeModel> parameters;
@NotNull private final TypeModel returnType;
@Nullable private final Collection<TypeModel> parameters;
FunctionType(@Nullable TypeModel returnType, @Nullable Collection<TypeModel> parameters) {
if (returnType != null) {
this.returnType = returnType;
}
else {
this.returnType = _(PyNames.UNKNOWN_TYPE);
}
private FunctionType(@Nullable TypeModel returnType, @Nullable Collection<TypeModel> parameters) {
this.returnType = returnType != null ? returnType : NamedType.ANY;
this.parameters = parameters;
}
@Override
void accept(TypeVisitor visitor) {
void accept(@NotNull TypeVisitor visitor) {
visitor.function(this);
}
}
@@ -167,14 +176,13 @@ 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;
}
@Override
void accept(TypeVisitor visitor) {
void accept(@NotNull TypeVisitor visitor) {
visitor.param(this);
}
}
@@ -193,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
@@ -244,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;
@@ -348,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);
@@ -359,6 +366,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;
@@ -371,16 +399,16 @@ public class PyTypeModelBuilder {
return;
}
add("Union[");
processList(oneOf.oneOfTypes, ", ");
processList(oneOf.oneOfTypes);
add("]");
myDepth--;
}
private void processList(Collection<TypeModel> list, String separator) {
private void processList(@NotNull Collection<TypeModel> list) {
boolean first = true;
for (TypeModel t : list) {
if (!first) {
add(separator);
add(", ");
}
else {
first = false;
@@ -403,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--;
}
@@ -425,7 +453,7 @@ public class PyTypeModelBuilder {
add("(");
final Collection<TypeModel> parameters = function.parameters;
if (parameters != null) {
processList(parameters, ", ");
processList(parameters);
}
else {
add("...");
@@ -469,7 +497,7 @@ public class PyTypeModelBuilder {
@Override
public void tuple(TupleType type) {
add("Tuple[");
processList(type.members, ", ");
processList(type.members);
if (type.homogeneous) {
add(", ...");
}
@@ -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,67 @@ 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<String> 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<String> body) {
final TypeEvalContext context = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile());
describeTypeWithLinks(context.getType(element), context, element, body);
}
public static void describeExpressionTypeWithLinks(@NotNull ChainIterable<String> body,
@NotNull PyReferenceExpression expression,
@NotNull TypeEvalContext context) {
final PyType type = context.getType(expression);
describeTypeWithLinks(body, expression, type, context);
}
public static void describeTypeWithLinks(@NotNull ChainIterable<String> 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<String> body) {
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)}.
* <code>Any</code> is excluded from <code>Union[Any, ...]</code>-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);
}
@NotNull
static ChainIterable<String> describeDecorators(@NotNull PyDecoratable what,
@@ -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<PyExpression, Pair<String, ProblemHighlightType>> minProblems = Collections.min(
problemsSet,
(o1, o2) -> o1.size() - o2.size()
);
final Map<PyExpression, Pair<String, ProblemHighlightType>> minProblems = Collections.min(problemsSet,
Comparator.comparingInt(Map::size));
for (Map.Entry<PyExpression, Pair<String, ProblemHighlightType>> entry : minProblems.entrySet()) {
registerProblem(entry.getKey(), entry.getValue().getFirst(), entry.getValue().getSecond());
}
@@ -222,7 +220,7 @@ public class PyTypeCheckerInspection extends PyInspection {
for (Map.Entry<PyExpression, PyNamedParameter> 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;
}
@@ -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<PyNamedParameterStub
}
@NotNull
public String getRepr(boolean includeDefaultValue) {
StringBuilder sb = new StringBuilder();
@Override
public String getRepr(boolean includeDefaultValue, @Nullable TypeEvalContext context) {
final StringBuilder sb = new StringBuilder();
if (isPositionalContainer()) sb.append("*");
else if (isKeywordContainer()) sb.append("**");
sb.append(getName());
if (context != null) {
final PyType argumentType = getArgumentType(context);
if (argumentType != null) {
sb.append(": ");
sb.append(PythonDocumentationProvider.getTypeDescription(argumentType, context));
}
}
final PyExpression defaultValue = getDefaultValue();
if (includeDefaultValue && defaultValue != null) {
if (defaultValueShouldBeIncluded(includeDefaultValue, defaultValue)) {
String representation = PyUtil.getReadableRepr(defaultValue, true);
if (defaultValue instanceof PyStringLiteralExpression) {
final Pair<String, String> quotes = PyStringLiteralUtil.getQuotes(defaultValue.getText());
@@ -182,9 +196,36 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
}
sb.append("=").append(representation);
}
return sb.toString();
}
private static boolean defaultValueShouldBeIncluded(boolean includeDefaultValue, @Nullable PyExpression defaultValue) {
if (!includeDefaultValue || defaultValue == null) return false;
// In case of `None` default value, it will be listed in the type as `Optional[...]` or `Union[..., None, ...]`
return !PyNames.NONE.equals(defaultValue.getText());
}
@Override
@Nullable
public PyType getArgumentType(@NotNull TypeEvalContext context) {
final PyType parameterType = context.getType(this);
if (parameterType instanceof PyCollectionType) {
final PyCollectionType paramCollectionType = (PyCollectionType)parameterType;
if (isPositionalContainer()) {
return paramCollectionType.getIteratedItemType();
}
else if (isKeywordContainer()) {
return ContainerUtil.getOrElse(paramCollectionType.getElementTypes(context), 1, null);
}
}
return parameterType;
}
@Override
public PyAnnotation getAnnotation() {
return getStubOrPsiChild(PyElementTypes.ANNOTATION);
@@ -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.
@@ -487,18 +487,18 @@ public class PyTypeChecker {
if (keywordParameter == null) keywordParameter = parameter;
keywordTypes.add(actualArgType);
}
else if (!match(getExpectedArgumentType(parameter, context), actualArgType, context, substitutions)) {
else if (!match(parameter.getArgumentType(context), actualArgType, context, substitutions)) {
return null;
}
}
if (positionalParameter != null &&
!match(getExpectedArgumentType(positionalParameter, context), PyUnionType.union(positionalTypes), context, substitutions)) {
!match(positionalParameter.getArgumentType(context), PyUnionType.union(positionalTypes), context, substitutions)) {
return null;
}
if (keywordParameter != null &&
!match(getExpectedArgumentType(keywordParameter, context), PyUnionType.union(keywordTypes), context, substitutions)) {
!match(keywordParameter.getArgumentType(context), PyUnionType.union(keywordTypes), context, substitutions)) {
return null;
}
@@ -757,24 +757,6 @@ public class PyTypeChecker {
}
}
@Nullable
public static PyType getExpectedArgumentType(@NotNull PyNamedParameter parameter, @NotNull TypeEvalContext context) {
final PyType parameterType = context.getType(parameter);
if (parameterType instanceof PyCollectionType) {
final PyCollectionType paramCollectionType = (PyCollectionType)parameterType;
if (parameter.isPositionalContainer()) {
return paramCollectionType.getIteratedItemType();
}
else if (parameter.isKeywordContainer()) {
return ContainerUtil.getOrElse(paramCollectionType.getElementTypes(context), 1, null);
}
}
return parameterType;
}
public static class AnalyzeCallResults {
@NotNull private final PyCallable myCallable;
@Nullable private final PyExpression myReceiver;
@@ -0,0 +1,7 @@
from typing import Union, Any
def foo(a1: str, a2: str=None, a3: Union[str, int]=None, a4: Union[Any, int], *args: int, **kwargs: int):
pass
foo(<arg1>)
@@ -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.
@@ -29,9 +29,9 @@ 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 junit.framework.Assert;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -53,7 +53,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
protected Map<String, PsiElement> loadTest(int expected_marks) {
Map<String, PsiElement> marks = loadTest();
Assert.assertEquals("Test data sanity", marks.size(), expected_marks);
assertEquals("Test data sanity", marks.size(), expected_marks);
return marks;
}
@@ -152,7 +152,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
public void testKwdArgInClass() {
Map<String, PsiElement> marks = loadTest(1);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, **kw", new String[]{"**kw"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: A, **kw", new String[]{"**kw"}, new String[]{"self: A, "});
}
public void testKwdArgOutOfOrder() {
@@ -223,14 +223,14 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
public void testSimpleMethod() {
Map<String, PsiElement> marks = loadTest(1);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, a", new String[]{"a"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: A, a", new String[]{"a"}, new String[]{"self: A, "});
}
public void testSimpleClassFunction() {
Map<String, PsiElement> marks = loadTest(2);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, a", new String[]{"self, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self, a", new String[]{"a"});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: A, a", new String[]{"self: A, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self: A, a", new String[]{"a"});
}
public void testReassignedFunction() {
@@ -243,65 +243,65 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
public void testReassignedInstanceMethod() {
Map<String, PsiElement> marks = loadTest(3);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, a, b, c", new String[]{"a, "}, new String[]{"self, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self, a, b, c", new String[]{"b, "}, new String[]{"self, "});
feignCtrlP(marks.get("<arg3>").getTextOffset()).check("self, a, b, c", new String[]{"c"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: Foo, a, b, c", new String[]{"a, "}, new String[]{"self: Foo, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self: Foo, a, b, c", new String[]{"b, "}, new String[]{"self: Foo, "});
feignCtrlP(marks.get("<arg3>").getTextOffset()).check("self: Foo, a, b, c", new String[]{"c"}, new String[]{"self: Foo, "});
}
public void testReassignedClassInit() {
Map<String, PsiElement> marks = loadTest(2);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, a, b", new String[]{"a, "}, new String[]{"self, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self, a, b", new String[]{"b"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: Bar, a, b", new String[]{"a, "}, new String[]{"self: Bar, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self: Bar, a, b", new String[]{"b"}, new String[]{"self: Bar, "});
}
public void testInheritedClassInit() {
Map<String, PsiElement> marks = loadTest(2);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, a, b", new String[]{"a, "}, new String[]{"self, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self, a, b", new String[]{"b"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: Bar, a, b", new String[]{"a, "}, new String[]{"self: Bar, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self: Bar, a, b", new String[]{"b"}, new String[]{"self: Bar, "});
}
public void testRedefinedNewConstructorCall() {
Map<String, PsiElement> marks = loadTest(2);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("cls, a, b", new String[]{"a, "}, new String[]{"cls, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("cls, a, b", new String[]{"b"}, new String[]{"cls, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("cls: A, a, b", new String[]{"a, "}, new String[]{"cls: A, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("cls: A, a, b", new String[]{"b"}, new String[]{"cls: A, "});
}
public void testRedefinedNewDirectCall() {
Map<String, PsiElement> marks = loadTest(3);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("cls, a, b", new String[]{"cls, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("cls, a, b", new String[]{"a, "});
feignCtrlP(marks.get("<arg3>").getTextOffset()).check("cls, a, b", new String[]{"b"});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("cls: A, a, b", new String[]{"cls: A, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("cls: A, a, b", new String[]{"a, "});
feignCtrlP(marks.get("<arg3>").getTextOffset()).check("cls: A, a, b", new String[]{"b"});
}
public void testIgnoreNewInOldStyleClass() {
Map<String, PsiElement> marks = loadTest(1);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, one", new String[]{"one"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: A, one", new String[]{"one"}, new String[]{"self: A, "});
}
public void testBoundMethodSimple() {
Map<String, PsiElement> marks = loadTest(2);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, a, b", new String[]{"a, "}, new String[]{"self, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self, a, b", new String[]{"b"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: A, a, b", new String[]{"a, "}, new String[]{"self: A, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self: A, a, b", new String[]{"b"}, new String[]{"self: A, "});
}
public void testBoundMethodReassigned() {
Map<String, PsiElement> marks = loadTest(2);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self, a, b", new String[]{"a, "}, new String[]{"self, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self, a, b", new String[]{"b"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("self: A, a, b", new String[]{"a, "}, new String[]{"self: A, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("self: A, a, b", new String[]{"b"}, new String[]{"self: A, "});
}
public void testConstructorFactory() {
Map<String, PsiElement> marks = loadTest(1);
feignCtrlP(marks.get("<arg>").getTextOffset()).check("self, color", new String[]{"color"}, new String[]{"self, "});
feignCtrlP(marks.get("<arg>").getTextOffset()).check("self: Foo, color", new String[]{"color"}, new String[]{"self: Foo, "});
}
@@ -386,16 +386,16 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
public void testPartialNamed() {
Map<String, PsiElement> marks = loadTest(2);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("a, b, c=1, d=2, e=3", new String[]{"d=2, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("a, b, c=1, d=2, e=3", new String[]{"e=3"}); // no logical next
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("a, b, c: int=1, d: int=2, e: int=3", new String[]{"d: int=2, "});
feignCtrlP(marks.get("<arg2>").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<String, PsiElement> marks = loadTest(4);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("*arg, a=1, b=2", new String[]{"*arg, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("*arg, a=1, b=2", new String[]{"*arg, "});
feignCtrlP(marks.get("<arg3>").getTextOffset()).check("*arg, a=1, b=2", new String[]{"b=2"});
feignCtrlP(marks.get("<arg4>").getTextOffset()).check("*arg, a=1, b=2", new String[]{"a=1, "});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("*arg, a: int=1, b: int=2", new String[]{"*arg, "});
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("*arg, a: int=1, b: int=2", new String[]{"*arg, "});
feignCtrlP(marks.get("<arg3>").getTextOffset()).check("*arg, a: int=1, b: int=2", new String[]{"b: int=2"});
feignCtrlP(marks.get("<arg4>").getTextOffset()).check("*arg, a: int=1, b: int=2", new String[]{"a: int=1, "});
}
public void testNoArgs() {
@@ -405,14 +405,29 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
public void testNoArgsException() {
Map<String, PsiElement> marks = loadTest(1);
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("<no parameters>", new String[0], new String[]{"<no parameters>"});
feignCtrlP(marks.get("<arg1>").getTextOffset()).check("<no parameters>", ArrayUtil.EMPTY_STRING_ARRAY, new String[]{"<no parameters>"});
}
public void testMultilineStringDefault() {
Map<String, PsiElement> marks = loadTest(1);
feignCtrlP(marks.get("<arg2>").getTextOffset()).check("length=12, allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'",
new String[]{"allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'"},
new String[0]);
final int offset = loadTest(1).get("<arg2>").getTextOffset();
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("<arg1>").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, "});
}
);
}
/**
@@ -427,7 +442,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 +516,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 +601,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<String> highlightSet = new HashSet<>();
@@ -615,7 +630,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 +638,7 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
}
public void assertNotFound() {
Assert.assertNull(myParamOwner);
assertNull(myParamOwner);
}
}
}