Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2017-03-06 15:30:53 +03:00
97 changed files with 995 additions and 210 deletions
@@ -20,12 +20,16 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.chainCall.ChainCallExtractor;
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
import com.intellij.util.ArrayUtil;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* @author Tagir Valeev
*/
@@ -59,23 +63,28 @@ public class ChainCallInplaceIntroducer extends JavaVariableInplaceIntroducer {
return myCall;
}
@Nullable
@Override
protected PsiVariable introduceVariable() {
PsiVariable variable = super.introduceVariable();
protected PsiVariable createFieldToStartTemplateOn(String[] names, PsiType psiType) {
PsiVariable variable = introduceVariable();
if (variable instanceof PsiLocalVariable) {
PsiLambdaExpression lambda = ApplicationManager.getApplication().runWriteAction(
(Computable<PsiLambdaExpression>)() -> ChainCallExtractor.extractMappingStep(myProject, (PsiLocalVariable)variable));
if (lambda != null) {
PsiParameter parameter = ArrayUtil.getFirstElement(lambda.getParameterList().getParameters());
PsiParameter parameter = Objects.requireNonNull(ArrayUtil.getFirstElement(lambda.getParameterList().getParameters()));
myParameter = parameter;
myCall = PsiTreeUtil.getParentOfType(lambda, PsiMethodCallExpression.class);
myOccurrences = PsiExpression.EMPTY_ARRAY;
myOccurrenceMarkers = null;
myExprMarker = null;
myExpr = null;
myOccurrences = StreamEx.of(ReferencesSearch.search(parameter).findAll()).map(PsiReference::getElement).select(PsiExpression.class)
.toArray(PsiExpression[]::new);
myOccurrenceMarkers = null;
final PsiIdentifier identifier = variable.getNameIdentifier();
if (identifier != null) {
myEditor.getCaretModel().moveToOffset(identifier.getTextOffset());
}
setAdvertisementText(null);
PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(myEditor.getDocument());
initOccurrencesMarkers();
return parameter;
}
else if (!variable.isValid()) {
@@ -398,8 +398,6 @@ public class JavaVariableInplaceIntroducer extends AbstractJavaInplaceIntroducer
protected PsiVariable createFieldToStartTemplateOn(String[] names, PsiType psiType) {
PsiVariable variable = introduceVariable();
if (variable == null) return null;
final PsiVariable restoredVar = getVariable();
if (restoredVar != null) {
variable = restoredVar;
@@ -429,7 +427,6 @@ public class JavaVariableInplaceIntroducer extends AbstractJavaInplaceIntroducer
return variable;
}
@Nullable
protected PsiVariable introduceVariable() {
PsiVariable variable = IntroduceVariableBase
.introduce(myProject, myExpr, myEditor, myChosenAnchor.getElement(), getOccurrences(), mySettings);
@@ -255,16 +255,16 @@ public class LambdaUtil {
}
@NotNull
private static List<HierarchicalMethodSignature> hasSubsignature(List<HierarchicalMethodSignature> signatures) {
private static List<HierarchicalMethodSignature> hasSubSignature(List<HierarchicalMethodSignature> signatures) {
for (HierarchicalMethodSignature signature : signatures) {
boolean subsignature = true;
boolean subSignature = true;
for (HierarchicalMethodSignature methodSignature : signatures) {
if (!signature.equals(methodSignature) && !skipMethod(signature, methodSignature)) {
subsignature = false;
subSignature = false;
break;
}
}
if (subsignature) return Collections.singletonList(signature);
if (subSignature) return Collections.singletonList(signature);
}
return signatures;
}
@@ -307,7 +307,7 @@ public class LambdaUtil {
}
}
return hasSubsignature(methods);
return hasSubSignature(methods);
}
@@ -554,12 +554,6 @@ public class LambdaUtil {
typeByExpression instanceof PsiLambdaParameterType;
}
public static boolean isLambdaReturnExpression(PsiElement element) {
final PsiElement parent = element.getParent();
return parent instanceof PsiLambdaExpression ||
parent instanceof PsiReturnStatement && PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class, true, PsiMethod.class) != null;
}
public static PsiReturnStatement[] getReturnStatements(PsiLambdaExpression lambdaExpression) {
final PsiElement body = lambdaExpression.getBody();
return body instanceof PsiCodeBlock ? PsiUtil.findReturnStatements((PsiCodeBlock)body) : PsiReturnStatement.EMPTY_ARRAY;
@@ -15,11 +15,11 @@
*/
class Test {
private String x;
private String s;
void simpleMethod() {
x = "";
System.out.println(x);
System.out.println(x);
s = "";
System.out.println(s);
System.out.println(s);
}
}
@@ -112,7 +112,7 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor {
@NotNull VirtualFile schemaFile,
@NotNull List<JsonSchemaWalker.Step> steps) {
if (isName) {
final boolean insertComma = myWalker.hasPropertiesBehind(myPosition);
final boolean insertComma = myWalker.hasPropertiesBehindAndNoComma(myPosition);
final boolean hasValue = myWalker.isPropertyWithValue(myPosition.getParent().getParent());
final Collection<String> properties = myWalker.getPropertyNamesOfParentObject(myOriginalPosition);
@@ -222,7 +222,7 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor {
final JsonSchemaType type = jsonSchemaObject.getType();
final List<Object> values = jsonSchemaObject.getEnum();
if (type != null || !ContainerUtil.isEmpty(values)) {
if (type != null || !ContainerUtil.isEmpty(values) || jsonSchemaObject.getDefault() != null) {
builder = builder.withInsertHandler(createPropertyInsertHandler(jsonSchemaObject, hasValue, insertComma));
} else if (!hasValue) {
builder = builder.withInsertHandler(createDefaultPropertyInsertHandler(hasValue, insertComma));
@@ -261,7 +261,8 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor {
final List<Object> values = jsonSchemaObject.getEnum();
if (type == null && values != null && !values.isEmpty()) type = detectType(values);
final Object defaultValue = jsonSchemaObject.getDefault();
final String defaultValueAsString = defaultValue == null ? null : String.valueOf(defaultValue);
final String defaultValueAsString = defaultValue == null ? null : defaultValue instanceof String ? "\"" + defaultValue + "\"" :
String.valueOf(defaultValue);
JsonSchemaType finalType = type;
return new InsertHandler<LookupElement>() {
@Override
@@ -355,18 +356,19 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor {
String defaultValue,
List<Object> values,
JsonSchemaType type, String comma) {
final boolean isNumber = JsonSchemaType._integer.equals(type) || JsonSchemaType._number.equals(type);
String start = isNumber ? ":" : ":\"";
String end = isNumber ? "" : "\"" + comma;
final boolean isNumber = type != null && (JsonSchemaType._integer.equals(type) || JsonSchemaType._number.equals(type)) ||
type == null && (defaultValue != null &&
!StringUtil.isQuotedString(defaultValue) || values != null && ContainerUtil.and(values, v -> !(v instanceof String)));
boolean hasValues = !ContainerUtil.isEmpty(values);
boolean hasDefaultValue = !StringUtil.isEmpty(defaultValue);
String stringToInsert = start + (hasDefaultValue ? defaultValue : "") + end;
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, start.length() - comma.length());
if (hasDefaultValue) {
String stringToInsert = ":" + (hasDefaultValue ? defaultValue : (isNumber ? "" : "\"\"")) + comma;
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, 1);
if (!isNumber || hasDefaultValue) {
SelectionModel model = editor.getSelectionModel();
int caretStart = model.getSelectionStart();
int newOffset = caretStart + defaultValue.length();
model.setSelection(caretStart, newOffset);
int newOffset = caretStart + (hasDefaultValue ? defaultValue.length() : 1);
if (hasDefaultValue && !isNumber) newOffset--;
model.setSelection(isNumber ? caretStart : (caretStart + 1), newOffset);
editor.getCaretModel().moveToOffset(newOffset);
}
@@ -34,7 +34,7 @@ public interface JsonLikePsiWalker {
PsiElement goUpToCheckable(@NotNull final PsiElement element);
List<JsonSchemaWalker.Step> findPosition(@NotNull final PsiElement element, boolean isName, boolean forceLastTransition);
boolean isNameQuoted();
boolean hasPropertiesBehind(@NotNull PsiElement element);
boolean hasPropertiesBehindAndNoComma(@NotNull PsiElement element);
Set<String> getPropertyNamesOfParentObject(@NotNull PsiElement element);
@Nullable JsonPropertyAdapter getParentPropertyAdapter(@NotNull PsiElement element);
boolean isTopJsonElement(@NotNull PsiElement element);
@@ -15,13 +15,13 @@
*/
package com.jetbrains.jsonSchema.impl;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -122,12 +122,21 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker {
}
@Override
public boolean hasPropertiesBehind(@NotNull PsiElement element) {
public boolean hasPropertiesBehindAndNoComma(@NotNull PsiElement element) {
PsiElement current = element instanceof JsonProperty ? element : PsiTreeUtil.getParentOfType(element, JsonProperty.class);
while (current != null && current.getNode().getElementType() != JsonElementTypes.COMMA) {
current = current.getNextSibling();
}
int commaOffset = current == null ? Integer.MAX_VALUE : current.getTextRange().getStartOffset();
final int offset = element.getTextRange().getStartOffset();
final JsonObject object = PsiTreeUtil.getParentOfType(element, JsonObject.class);
if (object != null) {
return ContainerUtil.or(object.getPropertyList(), prop -> prop.getTextRange().getStartOffset() >= offset &&
!PsiTreeUtil.isAncestor(prop, element, false));
for (JsonProperty property : object.getPropertyList()) {
final int pOffset = property.getTextRange().getStartOffset();
if (pOffset >= offset && !PsiTreeUtil.isAncestor(property, element, false)) {
return pOffset < commaOffset;
}
}
}
return false;
}
@@ -179,12 +179,7 @@ public class ReadJsonSchemaFromPsi {
if (value instanceof JsonStringLiteral) {
objects.add("\"" + StringUtil.unquoteString(((JsonStringLiteral)value).getValue()) + "\"");
} else if (value instanceof JsonNumberLiteral) {
try {
final int i = Integer.parseInt(value.getText());
objects.add(i);
} catch (NumberFormatException e) {
objects.add(((JsonNumberLiteral)value).getValue());
}
objects.add(getNumber(value));
} else if (value instanceof JsonBooleanLiteral) {
objects.add(((JsonBooleanLiteral)value).getValue());
} else if (value instanceof JsonNullLiteral) {
@@ -196,6 +191,17 @@ public class ReadJsonSchemaFromPsi {
};
}
@NotNull
private static Number getNumber(@NotNull JsonValue value) {
Number numberValue;
try {
numberValue = Integer.parseInt(value.getText());
} catch (NumberFormatException e) {
numberValue = ((JsonNumberLiteral)value).getValue();
}
return numberValue;
}
private PairConsumer<JsonElement, JsonSchemaObject> createDependencies() {
return (element, object) -> {
if (element instanceof JsonObject) {
@@ -330,17 +336,10 @@ public class ReadJsonSchemaFromPsi {
} else if (element instanceof JsonStringLiteral) {
object.setDefault(StringUtil.unquoteString(((JsonStringLiteral)element).getValue()));
} else if (element instanceof JsonNumberLiteral) {
object.setDefault(((JsonNumberLiteral)element).getValue());
object.setDefault(getNumber((JsonNumberLiteral) element));
} else if (element instanceof JsonBooleanLiteral) {
object.setDefault(((JsonBooleanLiteral)element).getValue());
}
};
}
private class MyStringReader implements PairConsumer<JsonElement,JsonSchemaObject> {
@Override
public void consume(JsonElement element, JsonSchemaObject object) {
}
}
}
@@ -0,0 +1,122 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.jsonSchema.impl;
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
import com.intellij.codeInsight.completion.CompletionType;
import com.jetbrains.jsonSchema.JsonSchemaHeavyAbstractTest;
import com.jetbrains.jsonSchema.JsonSchemaMappingsConfigurationBase;
import java.util.Collections;
/**
* @author Irina.Chernushina on 3/4/2017.
*/
public class JsonBySchemaHeavyCompletionTest extends JsonSchemaHeavyAbstractTest {
@Override
protected String getBasePath() {
return "/tests/testData/jsonSchema/completion";
}
public void testInsertEnumValue() throws Exception {
baseInsertTest("insertPropertyName", "testName");
}
public void testInsertNameWithDefaultStringValue() throws Exception {
baseInsertTest("insertPropertyName", "testNameWithDefaultStringValue");
}
public void testInsertNameWithDefaultIntegerValue() throws Exception {
baseInsertTest("insertPropertyName", "testNameWithDefaultIntegerValue");
}
public void testInsertIntegerType() throws Exception {
baseInsertTest("insertPropertyName", "testIntegerType");
}
public void testInsertStringType() throws Exception {
baseInsertTest("insertPropertyName", "testStringType");
}
public void testInsertObjectType() throws Exception {
baseInsertTest("insertPropertyName", "testObjectType");
}
public void testInsertBooleanType() throws Exception {
baseInsertTest("insertPropertyName", "testBooleanType");
}
//no quotes
public void testNameWithDefaultStringValueNoQuotes() throws Exception {
baseInsertTest("insertPropertyName", "testNameWithDefaultStringValueNoQuotes");
}
public void testNameWithDefaultIntegerValueNoQuotesComma() throws Exception {
baseInsertTest("insertPropertyName", "testNameWithDefaultIntegerValueNoQuotesComma");
}
//comma
public void testInsertIntegerTypeComma() throws Exception {
baseInsertTest("insertPropertyName", "testIntegerTypeComma");
}
public void testInsertBooleanTypeComma() throws Exception {
baseInsertTest("insertPropertyName", "testBooleanTypeComma");
}
public void testStringTypeComma() throws Exception {
baseInsertTest("insertPropertyName", "testStringTypeComma");
}
public void testNameWithDefaultStringValueComma() throws Exception {
baseInsertTest("insertPropertyName", "testNameWithDefaultStringValueComma");
}
private void baseInsertTest(final String folder, final String testFile) throws Exception {
skeleton(new Callback() {
@Override
public void registerSchemes() {
final String moduleDir = getModuleDir(getProject());
final JsonSchemaMappingsConfigurationBase.SchemaInfo base =
new JsonSchemaMappingsConfigurationBase.SchemaInfo("base", moduleDir + "/Schema.json", false,
Collections
.singletonList(new JsonSchemaMappingsConfigurationBase.Item("*.json", true, false)));
addSchema(base);
}
@Override
public void configureFiles() throws Exception {
configureByFiles(null, "/" + folder + "/" + testFile + ".json", "/" + folder + "/Schema.json");
}
@Override
public void doCheck() {
final CodeCompletionHandlerBase handlerBase = new CodeCompletionHandlerBase(CompletionType.BASIC);
handlerBase.invokeCompletion(getProject(), getEditor());
if (myItems != null) {
selectItem(myItems[0]);
}
try {
checkResultByFile("/" + folder + "/" + testFile + "_after.json");
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
}
@@ -0,0 +1,7 @@
{
"properties": {
"jsx": {
"enum": [ "preserve", "react", "react-native" ]
}
}
}
@@ -0,0 +1,3 @@
{
"jsx": <caret>
}
@@ -0,0 +1,3 @@
{
"jsx": "<selection>preserve<caret><selection>"
}
@@ -0,0 +1,25 @@
{
"properties": {
"jsx": {
"enum": [ "preserve", "react", "react-native" ]
},
"withStringDefaultValue": {
"default": "stringDefault"
},
"withIntegerDefaultValue": {
"default": 118
},
"integerType": {
"type": "integer"
},
"stringType": {
"type": "string"
},
"objectType": {
"type": "object"
},
"booleanType": {
"type": "boolean"
}
}
}
@@ -0,0 +1,3 @@
{
"booleanTy<caret>"
}
@@ -0,0 +1,4 @@
{
"booleanTy<caret>"
"someOtherProperty": false
}
@@ -0,0 +1,4 @@
{
"booleanType": <selection>false<caret></selection>,
"someOtherProperty": false
}
@@ -0,0 +1,3 @@
{
"booleanType": <selection>false<caret></selection>
}
@@ -0,0 +1,3 @@
{
"integerTy<caret>"
}
@@ -0,0 +1,4 @@
{
"integerTy<caret>"
"someOtherProperty": 1
}
@@ -0,0 +1,4 @@
{
"integerType":<caret>,
"someOtherProperty": 1
}
@@ -0,0 +1,3 @@
{
"integerType":<caret>
}
@@ -0,0 +1,3 @@
{
"js<caret>"
}
@@ -0,0 +1,3 @@
{
"withIntegerDefault<caret>"
}
@@ -0,0 +1,4 @@
{
withIntegerDefault<caret>
"someOtherProperty": 112
}
@@ -0,0 +1,4 @@
{
"withIntegerDefaultValue": <selection>118<caret></selection>,
"someOtherProperty": 112
}
@@ -0,0 +1,3 @@
{
"withIntegerDefaultValue": <selection>118<caret></selection>
}
@@ -0,0 +1,3 @@
{
"withStringDefault<caret>"
}
@@ -0,0 +1,4 @@
{
"withStringDefault<caret>",
"some": 2
}
@@ -0,0 +1,4 @@
{
"withStringDefaultValue": "<selection>stringDefault<caret></selection>",
"some": 2
}
@@ -0,0 +1,3 @@
{
withStringDefault<caret>
}
@@ -0,0 +1,3 @@
{
"withStringDefaultValue": "<selection>stringDefault<caret></selection>"
}
@@ -0,0 +1,3 @@
{
"withStringDefaultValue": "<selection>stringDefault<caret></selection>"
}
@@ -0,0 +1,3 @@
{
"jsx": "<caret>"
}
@@ -0,0 +1,3 @@
{
"objectTy<caret>"
}
@@ -0,0 +1,5 @@
{
"objectType": {
<caret>
}
}
@@ -0,0 +1,3 @@
{
"stringTy<caret>"
}
@@ -0,0 +1,4 @@
{
"stringTy<caret>"
"someOtherProperty": "123"
}
@@ -0,0 +1,4 @@
{
"stringType": "<caret>",
"someOtherProperty": "123"
}
@@ -0,0 +1,3 @@
{
"stringType": "<caret>"
}
@@ -29,6 +29,7 @@ public class HighlightUsagesDescriptionLocation extends ElementDescriptionLocati
private HighlightUsagesDescriptionLocation() {
}
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return new ElementDescriptionProvider() {
@@ -17,15 +17,15 @@
package com.intellij.usageView;
import com.intellij.ide.TypePresentationService;
import com.intellij.psi.*;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.meta.PsiMetaOwner;
import com.intellij.psi.meta.PsiPresentableMetaData;
import com.intellij.lang.LangBundle;
import com.intellij.lang.Language;
import com.intellij.lang.findUsages.FindUsagesProvider;
import com.intellij.lang.findUsages.LanguageFindUsages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.meta.PsiMetaOwner;
import com.intellij.psi.meta.PsiPresentableMetaData;
import org.jetbrains.annotations.NotNull;
/**
@@ -37,6 +37,7 @@ public class UsageViewTypeLocation extends ElementDescriptionLocation {
public static final UsageViewTypeLocation INSTANCE = new UsageViewTypeLocation();
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return DEFAULT_PROVIDER;
@@ -32,6 +32,7 @@ public class DeleteNameDescriptionLocation extends ElementDescriptionLocation {
public static DeleteNameDescriptionLocation INSTANCE = new DeleteNameDescriptionLocation();
private static final ElementDescriptionProvider ourDefaultProvider = new DefaultProvider();
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return ourDefaultProvider;
@@ -37,6 +37,7 @@ public class DeleteTypeDescriptionLocation extends ElementDescriptionLocation {
private static final ElementDescriptionProvider ourDefaultProvider = new DefaultProvider();
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return ourDefaultProvider;
@@ -18,6 +18,7 @@ package com.intellij.refactoring.util;
import com.intellij.psi.ElementDescriptionLocation;
import com.intellij.psi.ElementDescriptionProvider;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
@@ -32,6 +33,7 @@ public class NonCodeSearchDescriptionLocation extends ElementDescriptionLocation
public static final NonCodeSearchDescriptionLocation NON_JAVA = new NonCodeSearchDescriptionLocation(true);
public static final NonCodeSearchDescriptionLocation STRINGS_AND_COMMENTS = new NonCodeSearchDescriptionLocation(false);
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return DefaultNonCodeSearchElementDescriptionProvider.INSTANCE;
@@ -18,6 +18,7 @@ package com.intellij.refactoring.util;
import com.intellij.psi.ElementDescriptionLocation;
import com.intellij.psi.ElementDescriptionProvider;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
@@ -36,6 +37,7 @@ public class RefactoringDescriptionLocation extends ElementDescriptionLocation {
return myWithParent;
}
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return DefaultRefactoringElementDescriptionProvider.INSTANCE;
@@ -18,8 +18,8 @@ package com.intellij.usageView;
import com.intellij.psi.ElementDescriptionLocation;
import com.intellij.psi.ElementDescriptionProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.file.PsiDirectoryFactory;
import org.jetbrains.annotations.NotNull;
@@ -32,6 +32,7 @@ public class UsageViewLongNameLocation extends ElementDescriptionLocation {
public static final UsageViewLongNameLocation INSTANCE = new UsageViewLongNameLocation();
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return DEFAULT_PROVIDER;
@@ -37,6 +37,7 @@ public class UsageViewNodeTextLocation extends ElementDescriptionLocation {
public static final UsageViewNodeTextLocation INSTANCE = new UsageViewNodeTextLocation();
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return DEFAULT_PROVIDER;
@@ -34,6 +34,7 @@ public class UsageViewShortNameLocation extends ElementDescriptionLocation {
public static final UsageViewShortNameLocation INSTANCE = new UsageViewShortNameLocation();
@NotNull
@Override
public ElementDescriptionProvider getDefaultProvider() {
return DEFAULT_PROVIDER;
@@ -951,8 +951,6 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar, QuickAct
myPlace, myActionManager, transparentOnly);
if (forced || !newVisibleActions.equals(myVisibleActions)) {
myPresentationFactory.retainAll(newVisibleActions);
boolean shouldRebuildUI = newVisibleActions.isEmpty() || myVisibleActions.isEmpty();
myVisibleActions = newVisibleActions;
@@ -18,11 +18,9 @@ package com.intellij.openapi.actionSystem.impl;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.WeakHashMap;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Map;
public class PresentationFactory {
@@ -54,13 +52,4 @@ public class PresentationFactory {
ApplicationManager.getApplication().assertIsDispatchThread();
myAction2Presentation.clear();
}
public void retainAll(@NotNull Collection<AnAction> actions) {
HashSet<AnAction> toRemove = new HashSet<>(myAction2Presentation.keySet());
toRemove.removeAll(actions);
for (AnAction action : toRemove) {
myAction2Presentation.remove(action);
}
}
}
@@ -68,3 +68,4 @@ com.jetbrains.performancePlugin 1.1 1.3 1.3.1 1.3.2
org.vuejs 1.1.0 1.0.1 1.0.0
Vue.js 1.1.0 1.0.1 1.0.0
com.intellij.resharper.unity 1.5.0.0 1.5.0.1
com.nmatveev.idea-plugin-protobuf 0.5.9
@@ -56,6 +56,11 @@ public abstract class AbstractLanguageInjectionSupport extends LanguageInjection
return false;
}
@Override
public boolean useDefaultCommentInjector() {
return true;
}
@Nullable
@Override
public BaseInjection findCommentInjection(@NotNull PsiElement host, @Nullable Ref<PsiElement> commentRef) {
@@ -63,6 +63,8 @@ public class CommentLanguageInjector implements MultiHostInjector {
if (support == myInjectorSupport && applicableFound) continue;
applicableFound = true;
if (!support.useDefaultCommentInjector())
continue;
BaseInjection injection = support.findCommentInjection(host, null);
if (injection == null) continue;
if (!InjectorUtils.registerInjectionSimple(host, injection, support, registrar)) continue;
@@ -57,6 +57,8 @@ public abstract class LanguageInjectionSupport {
public abstract boolean useDefaultInjector(PsiLanguageInjectionHost host);
public abstract boolean useDefaultCommentInjector();
@Nullable
public abstract BaseInjection findCommentInjection(@NotNull PsiElement host, @Nullable Ref<PsiElement> commentRef);
@@ -626,7 +626,7 @@ public class GroovyBlockGenerator {
private static void addChildNodes(PsiElement elem, ArrayList<ASTNode> childNodes, TextRange range, PsiElement root) {
ASTNode node = elem.getNode();
if (range.contains(elem.getTextRange()) && node != null && elem != root) {
if (range.contains(elem.getTextRange()) && node != null && elem != root && !(elem instanceof PsiFile)) {
childNodes.add(node);
} else {
for (PsiElement child : elem.getChildren()) {
@@ -120,10 +120,10 @@ public class DuplicateStringLiteralInspection extends BaseLocalInspectionTool {
}
@NotNull
private List<PsiAnchor> findDuplicateLiterals(String stringToFind, Project project) {
private List<PsiLiteralExpression> findDuplicateLiterals(String stringToFind, Project project) {
Set<PsiFile> resultFiles = getCandidateFiles(stringToFind, project);
if (resultFiles.isEmpty()) return Collections.emptyList();
List<PsiAnchor> foundExpr = new ArrayList<>();
List<PsiLiteralExpression> foundExpr = new ArrayList<>();
for (final PsiFile file : resultFiles) {
ProgressManager.checkCanceled();
@@ -138,7 +138,7 @@ public class DuplicateStringLiteralInspection extends BaseLocalInspectionTool {
if (element == null || !(element.getParent() instanceof PsiLiteralExpression)) return true;
PsiLiteralExpression expression = (PsiLiteralExpression)element.getParent();
if (Comparing.equal(stringToFind, expression.getValue()) && shouldCheck(expression)) {
foundExpr.add(PsiAnchor.create(expression));
foundExpr.add(expression);
}
return true;
});
@@ -157,10 +157,8 @@ public class DuplicateStringLiteralInspection extends BaseLocalInspectionTool {
List<PsiLiteralExpression> foundExpr = getDuplicateLiterals(stringToFind, originalExpression);
if (foundExpr.isEmpty()) return;
Set<PsiClass> classes = new THashSet<>();
for (PsiLiteralExpression expr : foundExpr) {
if (expr == originalExpression) continue;
for (PsiElement aClass : foundExpr) {
ProgressManager.checkCanceled();
PsiElement aClass = expr;
do {
aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
}
@@ -208,15 +206,12 @@ public class DuplicateStringLiteralInspection extends BaseLocalInspectionTool {
@NotNull
private List<PsiLiteralExpression> getDuplicateLiterals(String stringToFind, PsiLiteralExpression place) {
Project project = place.getProject();
Map<String, List<PsiAnchor>> map = CachedValuesManager.getManager(project).getCachedValue(project, () -> {
Map<String, List<PsiAnchor>> value = ConcurrentFactoryMap.createConcurrentMap(
Map<String, List<PsiLiteralExpression>> map = CachedValuesManager.getManager(project).getCachedValue(project, () -> {
Map<String, List<PsiLiteralExpression>> value = ConcurrentFactoryMap.createConcurrentMap(
s -> Collections.unmodifiableList(findDuplicateLiterals(s, project)));
return CachedValueProvider.Result.create(value, PsiModificationTracker.MODIFICATION_COUNT);
});
return ContainerUtil.mapNotNull(map.get(stringToFind), anchor -> {
PsiLiteralExpression literal = (PsiLiteralExpression)anchor.retrieve();
return literal == place ? null : literal;
});
return ContainerUtil.filter(map.get(stringToFind), literal -> literal != place);
}
private boolean shouldCheck(@NotNull PsiLiteralExpression expression) {
@@ -128,11 +128,18 @@ public class PyJavaClassType implements PyClassLikeType {
return myDefinition;
}
@NotNull
@Override
public PyClassLikeType toInstance() {
return myDefinition ? new PyJavaClassType(myClass, false) : this;
}
@NotNull
@Override
public PyClassLikeType toClass() {
return myDefinition ? this : new PyJavaClassType(myClass, true);
}
@Nullable
@Override
public String getClassQName() {
@@ -624,7 +624,7 @@ public class PyPsiUtils {
Preconditions.checkArgument(!module.isDisposed(), String.format("Module %s is disposed", module));
}
@NotNull
@Nullable
public static PsiFileSystemItem getFileSystemItem(@NotNull PsiElement element) {
if (element instanceof PsiFileSystemItem) {
return (PsiFileSystemItem)element;
@@ -31,10 +31,7 @@ import java.util.Set;
/**
* @author vlan
*/
public interface PyClassLikeType extends PyCallableType, PyWithAncestors {
boolean isDefinition();
PyClassLikeType toInstance();
public interface PyClassLikeType extends PyCallableType, PyWithAncestors, PyInstantiableType<PyClassLikeType> {
@Nullable
String getClassQName();
@@ -0,0 +1,33 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.psi.types;
import org.jetbrains.annotations.NotNull;
/**
* A type that can describe either particular instantiated instance of a class or a class itself.
*
* @author Mikhail Golubev
*/
public interface PyInstantiableType<T extends PyInstantiableType<T>> extends PyType {
boolean isDefinition();
@NotNull
T toInstance();
@NotNull
T toClass();
}
@@ -66,6 +66,7 @@ public interface PyType {
Key<Set<String>> CTX_NAMES = new Key<>("Completion variants names");
/**
* TODO rename it to something like getPresentableName(), because it's not clear that these names are actually visible to end-user
* @return name of the type
*/
@Nullable
@@ -84,14 +84,23 @@ public class PyCustomType implements PyClassLikeType {
return !myInstanceType;
}
@NotNull
@Override
public final PyClassLikeType toInstance() {
return myInstanceType
? this
: new PyCustomType(myQualifiedName, myFilter, true, myTypesToMimic.toArray(new PyClassLikeType[myTypesToMimic.size()]));
: new PyCustomType(myQualifiedName, myFilter, true, myTypesToMimic.toArray(new PyClassLikeType[0]));
}
@NotNull
@Override
public PyClassLikeType toClass() {
return myInstanceType
? new PyCustomType(myQualifiedName, myFilter, false, myTypesToMimic.toArray(new PyClassLikeType[0]))
: this;
}
@Nullable
@Override
public final String getClassQName() {
@@ -68,7 +68,11 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
final PyReferenceExpression target = (PyReferenceExpression)args[0];
final PyExpression typeElement = args[1];
pushAssertion(target, myPositive, context -> context.getType(typeElement));
// TODO support tuple of types as the second argument of isinstance()
pushAssertion(target, myPositive, context -> {
final PyType type = context.getType(typeElement);
return type instanceof PyClassType ? ((PyClassType)type).toInstance() : type;
});
}
}
else if (node.isCalleeText(PyNames.CALLABLE_BUILTIN)) {
@@ -183,7 +187,7 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
final PyType initial = context.getType(target);
final PyType suggested = suggestedType.apply(context);
if (!PyUnionType.class.isInstance(initial) &&
if (!(initial instanceof PyUnionType) &&
!PyTypeChecker.isUnknown(initial) &&
PyTypeChecker.match(suggested, initial, context)) {
return initial;
@@ -103,11 +103,18 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType
return null;
}
@NotNull
@Override
public PyClassType toInstance() {
return myDefinitionLevel == 1 ? new PyNamedTupleType(myClass, myDeclaration, myName, myFields, 0) : this;
}
@NotNull
@Override
public PyClassLikeType toClass() {
return myDefinitionLevel == 0 ? this : new PyNamedTupleType(myClass, myDeclaration, myName, myFields, 1);
}
@Override
public String toString() {
return "PyNamedTupleType: " + myName;
@@ -36,6 +36,7 @@ import com.jetbrains.python.codeInsight.functionTypeComments.psi.PyFunctionTypeA
import com.jetbrains.python.codeInsight.functionTypeComments.psi.PyFunctionTypeAnnotationFile;
import com.jetbrains.python.codeInsight.functionTypeComments.psi.PyParameterTypeList;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyExpressionCodeFragmentImpl;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.PyResolveImportUtil;
@@ -62,6 +63,8 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
public static final String COROUTINE = "typing.Coroutine";
public static final String NAMEDTUPLE = "typing.NamedTuple";
public static final String GENERIC = "typing.Generic";
public static final String TYPE = "typing.Type";
public static final String ANY = "typing.Any";
public static final Pattern TYPE_COMMENT_PATTERN = Pattern.compile("# *type: *(.*)");
@@ -470,6 +473,10 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
if (callableType != null) {
return Ref.create(callableType);
}
final Ref<PyType> classObjType = getClassObjectType(resolved, context);
if (classObjType != null) {
return classObjType;
}
final PyType parameterizedType = getParameterizedType(resolved, context);
if (parameterizedType != null) {
return Ref.create(parameterizedType);
@@ -502,14 +509,49 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
}
@Nullable
private static Ref<PyType> getAnyType(@NotNull PsiElement element) {
final PyQualifiedNameOwner qualifiedNameOwner = as(element, PyQualifiedNameOwner.class);
if (qualifiedNameOwner != null && "typing.Any".equals(qualifiedNameOwner.getQualifiedName())) {
return Ref.create();
private static Ref<PyType> getClassObjectType(@NotNull PsiElement resolved, @NotNull Context context) {
if (resolved instanceof PySubscriptionExpression) {
final PySubscriptionExpression subsExpr = (PySubscriptionExpression)resolved;
final PyExpression operand = subsExpr.getOperand();
final Collection<String> operandNames = resolveToQualifiedNames(operand, context.getTypeContext());
if (operandNames.contains(TYPE)) {
final PyExpression indexExpr = subsExpr.getIndexExpression();
if (indexExpr != null) {
if (resolveToQualifiedNames(indexExpr, context.getTypeContext()).contains(ANY)) {
return Ref.create(PyBuiltinCache.getInstance(resolved).getTypeType());
}
final PyType type = Ref.deref(getType(indexExpr, context));
final PyClassType classType = as(type, PyClassType.class);
if (classType != null && !classType.isDefinition()) {
return Ref.create(new PyClassTypeImpl(classType.getPyClass(), true));
}
final PyGenericType typeVar = as(type, PyGenericType.class);
if (typeVar != null && !typeVar.isDefinition()) {
return Ref.create(new PyGenericType(typeVar.getName(), typeVar.getBound(), true));
}
// Represent Type[Union[str, int]] internally as Union[Type[str], Type[int]]
final PyUnionType unionType = as(type, PyUnionType.class);
if (unionType != null &&
unionType.getMembers().stream().allMatch(t -> t instanceof PyClassType && !((PyClassType)t).isDefinition())) {
return Ref.create(PyUnionType.union(ContainerUtil.map(unionType.getMembers(), t -> ((PyClassType)t).toClass())));
}
}
// Map Type[Something] with unsupported type parameter to Any, instead of generic type for the class "type"
return Ref.create();
}
}
// Replace plain non-parametrized Type with its builtin counterpart
else if (TYPE.equals(getQualifiedName(resolved))) {
return Ref.create(PyBuiltinCache.getInstance(resolved).getTypeType());
}
return null;
}
@Nullable
private static Ref<PyType> getAnyType(@NotNull PsiElement element) {
return ANY.equals(getQualifiedName(element)) ? Ref.create() : null;
}
@Nullable
private static Ref<PyType> getClassType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
if (element instanceof PyTypedElement) {
@@ -17,10 +17,12 @@ package com.jetbrains.python.documentation;
import com.google.common.collect.Collections2;
import com.google.common.collect.Maps;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.toolbox.ChainIterable;
import org.jetbrains.annotations.NotNull;
@@ -186,6 +188,34 @@ public class PyTypeModelBuilder {
visitor.param(this);
}
}
static class ClassObjectType extends TypeModel {
private final TypeModel classType;
public ClassObjectType(TypeModel classType) {
this.classType = classType;
}
@Override
void accept(@NotNull TypeVisitor visitor) {
visitor.classObject(this);
}
}
static class GenericType extends TypeModel {
private final String name;
private final List<TypeModel> bounds;
public GenericType(@Nullable String name, @NotNull List<TypeModel> bounds) {
this.name = name;
this.bounds = bounds;
}
@Override
void accept(@NotNull TypeVisitor visitor) {
visitor.genericType(this);
}
}
/**
* Builds tree-like type model for PyType
@@ -238,18 +268,49 @@ public class PyTypeModelBuilder {
}
else if (type instanceof PyUnionType && allowUnions) {
final PyUnionType unionType = (PyUnionType)type;
if (type instanceof PyDynamicallyEvaluatedType || PyTypeChecker.isUnknown(type)) {
final Collection<PyType> unionMembers = unionType.getMembers();
final Ref<PyType> optionalType = getOptionalType(unionType);
if (optionalType != null) {
result = new OptionalType(build(optionalType.get(), true));
}
else if (type instanceof PyDynamicallyEvaluatedType || PyTypeChecker.isUnknown(type, false)) {
result = new UnknownType(build(unionType.excludeNull(myContext), true));
}
else if (unionMembers.stream().allMatch(t -> t instanceof PyClassType && ((PyClassType)t).isDefinition())) {
final List<TypeModel> instanceTypes = ContainerUtil.map(unionMembers, t -> build(((PyClassType)t).toInstance(), allowUnions));
result = new ClassObjectType(new OneOf(instanceTypes));
}
else {
result = Optional
.ofNullable(getOptionalType(unionType))
.<PyTypeModelBuilder.TypeModel>map(optionalType -> new OptionalType(build(optionalType, true)))
.orElseGet(() -> new OneOf(Collections2.transform(unionType.getMembers(), t -> build(t, false))));
result = new OneOf(Collections2.transform(unionMembers, t -> build(t, false)));
}
}
else if (type instanceof PyCallableType && !(type instanceof PyClassLikeType)) {
result = build((PyCallableType)type);
result = buildCallable((PyCallableType)type);
}
else if (type instanceof PyInstantiableType && ((PyInstantiableType)type).isDefinition()) {
final PyInstantiableType instanceType = ((PyInstantiableType)type).toInstance();
// Special case: render Type[type] as just type
if (type instanceof PyClassType && instanceType.equals(PyBuiltinCache.getInstance(((PyClassType)type).getPyClass()).getTypeType())) {
result = NamedType.nameOrAny(type);
}
else {
result = new ClassObjectType(build(instanceType, allowUnions));
}
}
else if (type instanceof PyGenericType) {
//assert !((PyGenericType)type).isDefinition()
final PyType bound = ((PyGenericType)type).getBound();
final List<TypeModel> boundNames;
if (bound instanceof PyUnionType) {
boundNames = ContainerUtil.map(((PyUnionType)bound).getMembers(), t -> build(t, allowUnions));
}
else if (bound != null) {
boundNames = Collections.singletonList(build(bound, allowUnions));
}
else {
boundNames = Collections.emptyList();
}
result = new GenericType(type.getName(), boundNames);
}
if (result == null) {
result = NamedType.nameOrAny(type);
@@ -259,7 +320,7 @@ public class PyTypeModelBuilder {
}
@Nullable
private static PyType getOptionalType(@NotNull PyUnionType type) {
private static Ref<PyType> getOptionalType(@NotNull PyUnionType type) {
final Collection<PyType> members = type.getMembers();
if (members.size() == 2) {
boolean foundNone = false;
@@ -273,13 +334,13 @@ public class PyTypeModelBuilder {
}
}
if (foundNone) {
return optional;
return Ref.create(optional);
}
}
return null;
}
private TypeModel build(@NotNull PyCallableType type) {
private TypeModel buildCallable(@NotNull PyCallableType type) {
List<TypeModel> parameterModels = null;
final List<PyCallableParameter> parameters = type.getParameters(myContext);
if (parameters != null) {
@@ -309,6 +370,10 @@ public class PyTypeModelBuilder {
void optional(OptionalType type);
void tuple(TupleType type);
void classObject(ClassObjectType type);
void genericType(GenericType type);
}
private static class TypeToStringVisitor extends TypeNameVisitor {
@@ -503,5 +568,31 @@ public class PyTypeModelBuilder {
}
add("]");
}
@Override
public void classObject(ClassObjectType type) {
add("Type[");
type.classType.accept(this);
add("]");
}
@Override
public void genericType(GenericType type) {
add("TypeVar('");
add(type.name);
add("'");
if (!type.bounds.isEmpty()) {
add(", ");
boolean first = true;
for (TypeModel bound : type.bounds) {
if (!first) {
add(", ");
}
bound.accept(this);
first = false;
}
}
add(")");
}
}
}
@@ -78,18 +78,23 @@ public class SetupTaskChooserAction extends AnAction {
}
public static void runSetupTask(String taskName, Module module) {
final PyFile setupPy = PyPackageUtil.findSetupPy(module);
try {
final List<SetupTask.Option> options = SetupTaskIntrospector.getSetupTaskOptions(module, taskName);
List<String> parameters = new ArrayList<>();
parameters.add(taskName);
if (options != null) {
SetupTaskDialog dialog = new SetupTaskDialog(module.getProject(), taskName, options);
if (!dialog.showAndGet()) {
return;
}
parameters.addAll(dialog.getCommandLine());
final List<SetupTask.Option> options = SetupTaskIntrospector.getSetupTaskOptions(module, taskName);
List<String> parameters = new ArrayList<>();
parameters.add(taskName);
if (options != null) {
SetupTaskDialog dialog = new SetupTaskDialog(module.getProject(), taskName, options);
if (!dialog.showAndGet()) {
return;
}
parameters.addAll(dialog.getCommandLine());
}
runSetupTask(taskName, module, parameters);
}
public static void runSetupTask(String taskName, Module module, List<String> parameters) {
try {
final PyFile setupPy = PyPackageUtil.findSetupPy(module);
if (setupPy == null) return;
final PythonTask task = new PythonTask(module, taskName);
final VirtualFile virtualFile = setupPy.getVirtualFile();
task.setRunnerScript(virtualFile.getPath());
@@ -846,20 +846,13 @@ public class PyUtil {
});
}
public static <T, P> T getParameterizedCachedValue(@NotNull PsiElement element, @NotNull P param, @NotNull NotNullFunction<P, T> f) {
final Map<P, T> cache = CachedValuesManager.getCachedValue(element, new CachedValueProvider<Map<P, T>>() {
@Nullable
@Override
public Result<Map<P, T>> compute() {
return Result.create(Maps.newHashMap(), PsiModificationTracker.MODIFICATION_COUNT);
}
public static <T, P> T getParameterizedCachedValue(@NotNull PsiElement element, @Nullable P param, @NotNull NullableFunction<P, T> f) {
final CachedValuesManager manager = CachedValuesManager.getManager(element.getProject());
final Map<Optional<P>, Optional<T>> cache = CachedValuesManager.getCachedValue(element, manager.getKeyForClass(f.getClass()), () -> {
// concurrent hash map is a null-hostile collection
return CachedValueProvider.Result.create(Maps.newConcurrentMap(), PsiModificationTracker.MODIFICATION_COUNT);
});
T result = cache.get(param);
if (result == null) {
result = f.fun(param);
cache.put(param, result);
}
return result;
return cache.computeIfAbsent(Optional.ofNullable(param), p -> Optional.ofNullable(f.fun(param))).orElse(null);
}
/**
@@ -29,6 +29,7 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.scope.DelegatingScopeProcessor;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.PsiModificationTracker;
@@ -298,25 +299,15 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
@NotNull PsiElement place) {
final List<String> dunderAll = getDunderAll();
final List<String> remainingDunderAll = dunderAll == null ? null : new ArrayList<>(dunderAll);
PsiScopeProcessor wrapper = new PsiScopeProcessor() {
PsiScopeProcessor wrapper = new DelegatingScopeProcessor(processor) {
@Override
public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
if (!processor.execute(element, state)) return false;
if (!super.execute(element, state)) return false;
if (remainingDunderAll != null && element instanceof PyElement) {
remainingDunderAll.remove(((PyElement)element).getName());
}
return true;
}
@Override
public <T> T getHint(@NotNull Key<T> hintKey) {
return processor.getHint(hintKey);
}
@Override
public void handleEvent(@NotNull Event event, @Nullable Object associated) {
processor.handleEvent(event, associated);
}
};
Set<PyFile> pyFiles = resolveState.get(PROCESSED_FILES);
@@ -17,11 +17,12 @@ package com.jetbrains.python.psi.impl;
import com.google.common.collect.ImmutableList;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.scope.DelegatingScopeProcessor;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.ArrayFactory;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyElementTypes;
@@ -161,7 +162,17 @@ public class PyFromImportStatementImpl extends PyBaseElementImpl<PyFromImportSta
for (PsiElement target : targets) {
final PsiElement importedFile = PyUtil.turnDirIntoInit(target);
if (importedFile != null) {
if (!importedFile.processDeclarations(processor, state, null, place)) {
PsiScopeProcessor starImportableNamesProcessor = new DelegatingScopeProcessor(processor) {
@Override
public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
if (element instanceof PyElement && importedFile instanceof PyFile &&
!PyUtil.isStarImportableFrom(StringUtil.notNullize(((PyElement)element).getName()), (PyFile)importedFile)) {
return true;
}
return super.execute(element, state);
}
};
if (!importedFile.processDeclarations(starImportableNamesProcessor, state, null, place)) {
return false;
}
}
@@ -37,6 +37,8 @@ import javax.swing.*;
import java.util.Collections;
import java.util.List;
import static com.jetbrains.python.psi.PyUtil.as;
/**
* @author dcheryasov
*/
@@ -93,21 +95,13 @@ public class PyStarImportElementImpl extends PyBaseElementImpl<PyStarImportEleme
PyFromImportStatement fromImportStatement = (PyFromImportStatement)parent;
final List<PsiElement> importedFiles = fromImportStatement.resolveImportSourceCandidates();
for (PsiElement importedFile : new HashSet<>(importedFiles)) { // resolver gives lots of duplicates
final PsiElement source = PyUtil.turnDirIntoInit(importedFile);
if (source instanceof PyFile) {
PyFile sourceFile = (PyFile)source;
final PyFile sourceFile = as(PyUtil.turnDirIntoInit(importedFile), PyFile.class);
if (sourceFile != null && PyUtil.isStarImportableFrom(name, sourceFile)) {
final PyModuleType moduleType = new PyModuleType(sourceFile);
final List<? extends RatedResolveResult> results = moduleType.resolveMember(name, null, AccessDirection.READ,
PyResolveContext.defaultContext());
if (results != null && !results.isEmpty() && PyUtil.isStarImportableFrom(name, sourceFile)) {
if (results.isEmpty()) {
return Collections.emptyList();
}
final List<RatedResolveResult> res = Lists.newArrayList();
for (RatedResolveResult result : results) {
res.add(result);
}
return res;
if (results != null && !results.isEmpty()) {
return Lists.newArrayList(results);
}
}
}
@@ -18,6 +18,7 @@ package com.jetbrains.python.psi.resolve;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
@@ -27,11 +28,9 @@ import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -114,7 +113,15 @@ public class QualifiedNameFinder {
*/
@Nullable
public static QualifiedName findCanonicalImportPath(@NotNull PsiElement symbol, @Nullable PsiElement foothold) {
PsiFileSystemItem srcfile = symbol instanceof PsiFileSystemItem ? (PsiFileSystemItem)symbol : symbol.getContainingFile();
return PyUtil.getParameterizedCachedValue(symbol, Couple.of(symbol, foothold), QualifiedNameFinder::doFindCanonicalImportPath);
}
@Nullable
private static QualifiedName doFindCanonicalImportPath(@NotNull Couple<PsiElement> param) {
final PsiElement symbol = param.getFirst();
final PsiElement foothold = param.getSecond();
final PsiFileSystemItem srcfile = PyPsiUtils.getFileSystemItem(symbol);
if (srcfile == null) {
return null;
}
@@ -107,11 +107,18 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
return myIsDefinition;
}
@NotNull
@Override
public PyClassType toInstance() {
return myIsDefinition ? withUserDataCopy(new PyClassTypeImpl(myClass, false)) : this;
}
@NotNull
@Override
public PyClassLikeType toClass() {
return myIsDefinition ? this : new PyClassTypeImpl(myClass, true);
}
/**
* Wrap new instance to copy user data to it
*/
@@ -70,11 +70,18 @@ public class PyCollectionTypeImpl extends PyClassTypeImpl implements PyCollectio
return new PyCollectionTypeImpl(pyClass, isDefinition, elementTypes);
}
@NotNull
@Override
public PyClassType toInstance() {
return myIsDefinition ? withUserDataCopy(new PyCollectionTypeImpl(myClass, false, myElementTypes)) : this;
}
@NotNull
@Override
public PyClassLikeType toClass() {
return myIsDefinition ? this : withUserDataCopy(new PyCollectionTypeImpl(myClass, true, myElementTypes));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -15,11 +15,9 @@
*/
package com.jetbrains.python.psi.types;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.AccessDirection;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -32,13 +30,19 @@ import java.util.List;
/**
* @author vlan
*/
public class PyGenericType implements PyType {
public class PyGenericType implements PyType, PyInstantiableType<PyGenericType> {
@NotNull private final String myName;
@Nullable private PyType myBound;
@Nullable private final PyType myBound;
private boolean myIsDefinition = false;
public PyGenericType(@NotNull String name, @Nullable PyType bound) {
this(name, bound, false);
}
public PyGenericType(@NotNull String name, @Nullable PyType bound, boolean isDefinition) {
myName = name;
myBound = bound;
myIsDefinition = isDefinition;
}
@Nullable
@@ -52,20 +56,13 @@ public class PyGenericType implements PyType {
@Override
public Object[] getCompletionVariants(String completionPrefix, PsiElement location, ProcessingContext context) {
return new Object[0];
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@NotNull
@Override
public String getName() {
if (myBound instanceof PyUnionType) {
final PyUnionType bounds = (PyUnionType)myBound;
final String boundsString = StringUtil.join(bounds.getMembers(), type -> type != null ? type.getName() : PyNames.UNKNOWN_TYPE, ", ");
return "TypeVar('" + myName + "', " + boundsString + ")";
}
else {
return "TypeVar('" + myName + "')";
}
return myName;
}
@Override
@@ -86,7 +83,7 @@ public class PyGenericType implements PyType {
return false;
}
final PyGenericType type = (PyGenericType)o;
return myName.equals(type.myName);
return myName.equals(type.myName) && myIsDefinition == type.isDefinition();
}
@Override
@@ -104,4 +101,21 @@ public class PyGenericType implements PyType {
public PyType getBound() {
return myBound;
}
@Override
public boolean isDefinition() {
return myIsDefinition;
}
@NotNull
@Override
public PyGenericType toInstance() {
return myIsDefinition ? new PyGenericType(myName, myBound, false) : this;
}
@NotNull
@Override
public PyGenericType toClass() {
return myIsDefinition ? this : new PyGenericType(myName, myBound, true);
}
}
@@ -65,18 +65,38 @@ public class PyTypeChecker {
private static boolean match(@Nullable PyType expected, @Nullable PyType actual, @NotNull TypeEvalContext context,
@Nullable Map<PyGenericType, PyType> substitutions, boolean recursive) {
// TODO: subscriptable types?, module types?, etc.
if (actual instanceof PyClassType) {
final PyClassType classType = (PyClassType)actual;
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(classType.getPyClass());
if (actual == builtinCache.getObjectType(PyNames.BASESTRING)) {
final PyClassType expectedClassType = as(expected, PyClassType.class);
final PyClassType actualClassType = as(actual, PyClassType.class);
// Special cases: object and type
if (expectedClassType != null && ArrayUtil.contains(expectedClassType.getName(), PyNames.OBJECT, PyNames.TYPE)) {
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(expectedClassType.getPyClass());
if (expectedClassType.equals(builtinCache.getObjectType())) {
return true;
}
if (expectedClassType.equals(builtinCache.getTypeType()) &&
actual instanceof PyInstantiableType && ((PyInstantiableType)actual).isDefinition()) {
return true;
}
}
if (expected instanceof PyInstantiableType && actual instanceof PyInstantiableType
&& ((PyInstantiableType)expected).isDefinition() ^ ((PyInstantiableType)actual).isDefinition()) {
return false;
}
if (actualClassType != null && PyNames.BASESTRING.equals(actualClassType.getName())) {
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(actualClassType.getPyClass());
if (actualClassType.equals(builtinCache.getObjectType(PyNames.BASESTRING))) {
return match(expected, builtinCache.getStrOrUnicodeType(), context, substitutions, recursive);
}
}
if (expected instanceof PyGenericType && substitutions != null) {
final PyGenericType generic = (PyGenericType)expected;
final PyType subst = substitutions.get(generic);
final PyType bound = generic.getBound();
PyType bound = generic.getBound();
// Promote int in Type[TypeVar('T', int)] to Type[int] before checking that bounds match
if (generic.isDefinition() && bound instanceof PyInstantiableType) {
bound = ((PyInstantiableType)bound).toClass();
}
if (!match(bound, actual, context, substitutions, recursive)) {
return false;
}
@@ -102,12 +122,6 @@ public class PyTypeChecker {
if (expected == null || actual == null) {
return true;
}
if (expected instanceof PyClassType) {
final PyClass c = ((PyClassType)expected).getPyClass();
if ("object".equals(c.getName())) {
return true;
}
}
if (isUnknown(actual)) {
return true;
}
@@ -142,9 +156,9 @@ public class PyTypeChecker {
}
return false;
}
if (expected instanceof PyClassType && actual instanceof PyClassType) {
final PyClass superClass = ((PyClassType)expected).getPyClass();
final PyClass subClass = ((PyClassType)actual).getPyClass();
if (expectedClassType != null && actualClassType != null) {
final PyClass superClass = expectedClassType.getPyClass();
final PyClass subClass = actualClassType.getPyClass();
if (expected instanceof PyTupleType && actual instanceof PyTupleType) {
final PyTupleType superTupleType = (PyTupleType)expected;
final PyTupleType subTupleType = (PyTupleType)actual;
@@ -213,15 +227,15 @@ public class PyTypeChecker {
else if (matchClasses(superClass, subClass, context)) {
return true;
}
else if (((PyClassType)actual).isDefinition() && PyNames.CALLABLE.equals(expected.getName())) {
else if (actualClassType.isDefinition() && PyNames.CALLABLE.equals(expected.getName())) {
return true;
}
if (expected.equals(actual)) {
return true;
}
}
if (actual instanceof PyFunctionTypeImpl && expected instanceof PyClassType) {
final PyClass superClass = ((PyClassType)expected).getPyClass();
if (actual instanceof PyFunctionTypeImpl && expectedClassType != null) {
final PyClass superClass = expectedClassType.getPyClass();
if (PyNames.CALLABLE.equals(superClass.getName())) {
return true;
}
@@ -237,16 +251,15 @@ public class PyTypeChecker {
}
return expectedStructural.getAttributeNames().containsAll(actualStructural.getAttributeNames());
}
if (expected instanceof PyStructuralType && actual instanceof PyClassType) {
final PyClassType actualClassType = (PyClassType)actual;
if (expected instanceof PyStructuralType && actualClassType != null) {
if (overridesGetAttr(actualClassType.getPyClass(), context)) {
return true;
}
final Set<String> actualAttributes = actualClassType.getMemberNames(true, context);
return actualAttributes.containsAll(((PyStructuralType)expected).getAttributeNames());
}
if (actual instanceof PyStructuralType && expected instanceof PyClassType) {
final Set<String> expectedAttributes = ((PyClassType)expected).getMemberNames(true, context);
if (actual instanceof PyStructuralType && expectedClassType != null) {
final Set<String> expectedAttributes = expectedClassType.getMemberNames(true, context);
return expectedAttributes.containsAll(((PyStructuralType)actual).getAttributeNames());
}
if (actual instanceof PyCallableType && expected instanceof PyCallableType) {
@@ -338,13 +351,17 @@ public class PyTypeChecker {
}
public static boolean isUnknown(@Nullable PyType type) {
if (type == null || type instanceof PyGenericType) {
return isUnknown(type, true);
}
public static boolean isUnknown(@Nullable PyType type, boolean genericsAreUnknown) {
if (type == null || (genericsAreUnknown && type instanceof PyGenericType)) {
return true;
}
if (type instanceof PyUnionType) {
final PyUnionType union = (PyUnionType)type;
for (PyType t : union.getMembers()) {
if (isUnknown(t)) {
if (isUnknown(t, genericsAreUnknown)) {
return true;
}
}
@@ -416,7 +433,22 @@ public class PyTypeChecker {
@NotNull TypeEvalContext context) {
if (hasGenerics(type, context)) {
if (type instanceof PyGenericType) {
final PyType substitution = substitutions.get((PyGenericType)type);
final PyGenericType typeVar = (PyGenericType)type;
PyType substitution = substitutions.get(typeVar);
if (substitution == null) {
if (!typeVar.isDefinition()) {
final PyInstantiableType<?> classType = as(substitutions.get(typeVar.toClass()), PyInstantiableType.class);
if (classType != null) {
substitution = classType.toInstance();
}
}
else {
final PyInstantiableType<?> instanceType = as(substitutions.get(typeVar.toInstance()), PyInstantiableType.class);
if (instanceType != null) {
substitution = instanceType.toClass();
}
}
}
if (substitution instanceof PyGenericType && substitution != type) {
final PyType recursive = substitute(substitution, substitutions, context);
if (recursive != null) {
@@ -0,0 +1 @@
from pkg import <caret>
@@ -0,0 +1,2 @@
from .mod1 import *
from .mod2 import *
@@ -0,0 +1,2 @@
foo = 1
_foo = 2
@@ -0,0 +1,4 @@
__all__ = ['_bar']
bar = 1
_bar = 2
@@ -0,0 +1,36 @@
from typing import Type, TypeVar, Optional
class MyClass:
pass
def expects_myclass(x: Type[MyClass]):
pass
expects_myclass(<warning descr="Expected type 'Type[MyClass]', got 'MyClass' instead">MyClass()</warning>)
expects_class(MyClass)
T1 = TypeVar('T1')
def expects_any_class(x: Type[T1]):
pass
expects_any_class(MyClass)
expects_any_class(<warning descr="Expected type 'Type[TypeVar('T1')]', got 'MyClass' instead">MyClass()</warning>)
expects_any_class(object)
expects_any_class(<warning descr="Expected type 'Type[TypeVar('T1')]', got 'object' instead">object()</warning>)
T2 = TypeVar('T2', MyClass)
def expects_myclass_descendant(x: Type[T2]):
pass
expects_myclass_descendant(MyClass)
expects_myclass_descendant(<warning descr="Expected type 'Type[TypeVar('T2', MyClass)]', got 'MyClass' instead">MyClass()</warning>)
expects_myclass_descendant(<warning descr="Expected type 'Type[TypeVar('T2', MyClass)]', got 'Type[object]' instead">object</warning>)
expects_myclass_descendant(<warning descr="Expected type 'Type[TypeVar('T2', MyClass)]', got 'object' instead">object()</warning>)
def expects_myclass_descendant_or_none(x: Optional[Type[T2]]):
pass
expects_myclass_descendant_or_none(MyClass)
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Optional[Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'MyClass' instead">MyClass()</weak_warning>)
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Optional[Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'Type[object]' instead">object</weak_warning>)
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Optional[Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'object' instead">object()</weak_warning>)
@@ -0,0 +1,21 @@
from typing import Type, Union
class MyClass:
pass
def expects_myclass_or_str1(x: Type[Union[MyClass, str]]):
pass
expects_myclass_or_str1(MyClass)
expects_myclass_or_str1(str)
expects_myclass_or_str1(<warning descr="Expected type 'Type[Union[MyClass, str]]', got 'Type[int]' instead">int</warning>)
expects_myclass_or_str1(<warning descr="Expected type 'Type[Union[MyClass, str]]', got 'int' instead">42</warning>)
def expects_myclass_or_str2(x: Union[Type[MyClass], Type[str]]):
pass
expects_myclass_or_str2(MyClass)
expects_myclass_or_str2(str)
expects_myclass_or_str2(<warning descr="Expected type 'Type[Union[MyClass, str]]', got 'Type[int]' instead">int</warning>)
expects_myclass_or_str2(<warning descr="Expected type 'Type[Union[MyClass, str]]', got 'int' instead">42</warning>)
@@ -15,7 +15,7 @@ def test():
for item in func(<warning descr="Expected type '(Any) -> str', got '(x: Any) -> int' instead">f</warning>, []):
pass
for item in func(<warning descr="Expected type '(Any) -> str', got 'int' instead">int</warning>, []):
for item in func(<warning descr="Expected type '(Any) -> str', got 'Type[int]' instead">int</warning>, []):
pass
for item in func(<warning descr="Expected type '(Any) -> str', got '(x: Any) -> int' instead">lambda x: int(x)</warning>, []):
@@ -23,7 +23,7 @@ for x in C1:
pass
for y in <warning descr="Expected 'collections.Iterable', got 'C2' instead">C2</warning>:
for y in <warning descr="Expected 'collections.Iterable', got 'Type[C2]' instead">C2</warning>:
pass
@@ -0,0 +1,11 @@
from typing import Optional, TypeVar
T = TypeVar('T', int)
def expects_int_subclass_or_none(x: Optional[T]):
pass
expects_int_subclass_or_none(<weak_warning descr="Expected type 'Optional[Any]' (matched generic type 'Optional[TypeVar('T', int)]'), got 'str' instead">'foo'</weak_warning>)
@@ -0,0 +1,47 @@
from typing import TypeVar, Type
T = TypeVar('T')
S = TypeVar('T', str)
def expects_type(x: type):
pass
def expects_typing_type(x: Type):
expects_type(x)
def expects_typing_type_any(x: Type[Any]):
expects_type(x)
def expects_any_type_via_type_var(x: Type[T]):
expects_type(x)
def expects_str_class(x: Type[str]):
expects_type(x)
def expects_str_subclass(x: Type[S]):
expects_type(x)
def expects_object(x: object):
expects_type(<warning descr="Expected type 'type', got 'object' instead">x</warning>)
expects_type(type)
expects_type(object)
expects_typing_type(type)
expects_typing_type_any(type)
expects_typing_type(object)
expects_str_class(<warning descr="Expected type 'Type[str]', got 'type' instead">type</warning>)
expects_any_type_via_type_var(type)
expects_str_subclass(<warning descr="Expected type 'Type[TypeVar('T', str)]', got 'type' instead">type</warning>)
expects_object(type)
@@ -0,0 +1 @@
<html><body><code>def <b>f</b>(x1:&nbsp;Optional[T],&nbsp;x2:&nbsp;Union[T,&nbsp;Tuple[Any,&nbsp;Any]])<br>Inferred&nbsp;type:&nbsp;(x1:&nbsp;Optional[TypeVar('T',&nbsp;<a href="psi_element://#typename#int">int</a>)],&nbsp;x2:&nbsp;Union[TypeVar('T',&nbsp;<a href="psi_element://#typename#int">int</a>),&nbsp;Tuple[Any,&nbsp;Any]])&nbsp;-&gt;&nbsp;None<br></code></body></html>
@@ -0,0 +1,11 @@
from typing import TypeVar, Optional, Union, Tuple, Any
T = TypeVar('T', int)
def f(x1: Optional[T], x2: Union[T, Tuple[Any, Any]]):
print(x1, x2)
<the_ref>f
+1
View File
@@ -0,0 +1 @@
<html><body><code>def <b>f</b>(p1:&nbsp;T1,&nbsp;p2:&nbsp;T2,&nbsp;p3:&nbsp;T3)<br>Inferred&nbsp;type:&nbsp;(p1:&nbsp;TypeVar('T1',&nbsp;<a href="psi_element://#typename#int">int</a>),&nbsp;p2:&nbsp;TypeVar('T2',&nbsp;<a href="psi_element://#typename#int">int</a>,&nbsp;<a href="psi_element://#typename#str">str</a>),&nbsp;p3:&nbsp;TypeVar('T3',&nbsp;List[<a href="psi_element://#typename#bool">bool</a>]))&nbsp;-&gt;&nbsp;None<br></code></body></html>
+10
View File
@@ -0,0 +1,10 @@
from typing import TypeVar, List
T1 = TypeVar('T1', int)
T2 = TypeVar('T2', int, str)
T3 = TypeVar('T3', List[bool])
def f(p1: T1, p2: T2, p3: T3):
pass
<the_ref>f()
@@ -450,7 +450,7 @@ public class Py3TypeTest extends PyTestCase {
// PY-20757
public void testMinElseNone() {
doTest("Union[None, Any]",
doTest("Optional[Any]",
"def get_value(v):\n" +
" if v:\n" +
" return min(v)\n" +
@@ -277,4 +277,15 @@ public class PyQuickDocTest extends LightMarkedTestCase {
public void testUnknownTuple() {
runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
}
public void testTypeVars() {
myFixture.copyDirectoryToProject("typing", "");
runWithLanguageLevel(LanguageLevel.PYTHON35, this::checkHTMLOnly);
}
// PY-22730
public void testOptionalAndUnionTypesContainingTypeVars() {
myFixture.copyDirectoryToProject("typing", "");
runWithLanguageLevel(LanguageLevel.PYTHON36, this::checkHTMLOnly);
}
}
@@ -24,8 +24,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static com.jetbrains.python.psi.PyUtil.as;
/**
* @author yole
*/
@@ -139,7 +137,7 @@ public class PyTypeParserTest extends PyTestCase {
final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "T");
assertNotNull(type);
assertInstanceOf(type, PyGenericType.class);
assertEquals("TypeVar('T')", type.getName());
assertEquals("T", type.getName());
}
// PY-4223
@@ -251,7 +249,7 @@ public class PyTypeParserTest extends PyTestCase {
assertEquals("int", type0.getName());
final PyType type1 = parameterTypes.get(1).getType(context);
assertNotNull(type1);
assertEquals("TypeVar('T')", type1.getName());
assertEquals("T", type1.getName());
}
public void testCallableWithoutArgs() {
@@ -1496,14 +1496,14 @@ public class PyTypeTest extends PyTestCase {
// PY-20409
public void testGetFromDictWithDefaultNoneValue() {
doTest("Union[None, Any]",
doTest("Optional[Any]",
"d = {}\n" +
"expr = d.get(\"abc\", None)");
}
// PY-20757
public void testMinOrNone() {
doTest("Union[None, Any]",
doTest("Optional[Any]",
"def get_value(v):\n" +
" if v:\n" +
" return min(v)\n" +
@@ -783,6 +783,91 @@ public class PyTypingTest extends PyTestCase {
"expr = C(0).get()\n");
}
// PY-20057
public void testClassObjectType() {
doTest("Type[MyClass]",
"from typing import Type\n" +
"\n" +
"class MyClass:\n" +
" pass\n" +
"\n" +
"def f(x: Type[MyClass]): \n" +
" expr = x");
}
// PY-20057
public void testConstrainedClassObjectTypeOfParam() {
doTest("Type[TypeVar('T', int)]",
"from typing import Type, TypeVar\n" +
"\n" +
"T = TypeVar('T', bound=int)\n" +
"\n" +
"def f(x: Type[T]):\n" +
" expr = x");
}
// PY-20057
public void testFunctionCreatesInstanceFromType() {
doTest("int",
"from typing import Type, TypeVar\n" +
"\n" +
"T = TypeVar('T')\n" +
"\n" +
"def f(x: Type[T]) -> T:\n" +
" return x()\n" +
"\n" +
"expr = f(int)");
}
// PY-20057
public void testFunctionReturnsTypeOfInstance() {
doTest("Type[int]",
"from typing import Type, TypeVar\n" +
"\n" +
"T = TypeVar('T')\n" +
"\n" +
"def f(x: T) -> Type[T]:\n" +
" return type(T)\n" +
" \n" +
"expr = f(42)");
}
// PY-20057
public void testNonParametrizedTypingTypeMapsToBuiltinType() {
doTest("type",
"from typing import Type\n" +
"\n" +
"def f(x: Type):\n" +
" expr = x");
}
// PY-20057
public void testTypingTypeOfAnyMapsToBuiltinType() {
doTest("type",
"from typing import Type, Any\n" +
"\n" +
"def f(x: Type[Any]):\n" +
" expr = x");
}
// PY-20057
public void testIllegalTypingTypeFormat() {
doTest("Tuple[Any, Any, Any]",
"from typing import Type, Tuple\n" +
"\n" +
"def f(x: Tuple[Type[42], Type[], Type[unresolved]]):\n" +
" expr = x");
}
// PY-20057
public void testUnionOfClassObjectTypes() {
doTest("Type[Union[int, str]]",
"from typing import Type, Union\n" +
"\n" +
"def f(x: Type[Union[int, str]]):\n" +
" expr = x");
}
private void doTestNoInjectedText(@NotNull String text) {
myFixture.configureByText(PythonFileType.INSTANCE, text);
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());
@@ -1105,6 +1105,15 @@ public class PythonCompletionTest extends PyTestCase {
assertContainsElements(suggested, "baz");
}
// PY-22570
public void testNamesReexportedViaStarImport() {
myFixture.copyDirectoryToProject(getTestName(true), "");
myFixture.configureByFile("a.py");
myFixture.completeBasic();
final List<String> variants = myFixture.getLookupElementStrings();
assertSameElements(variants, "mod1", "mod2", "foo", "_bar");
}
@Override
protected String getTestDataPath() {
return super.getTestDataPath() + "/completion";
@@ -198,4 +198,24 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase {
public void testBuiltinInputPy3() {
doTest();
}
// PY-200057
public void testClassObjectType() {
doTest();
}
// PY-20057
public void testTypeAndClassObjectTypesCompatibility() {
doTest();
}
// PY-20057
public void testClassObjectTypeWithUnion() {
doTest();
}
// PY-22730
public void testOptionalOfBoundTypeVarInWarnings() {
doTest();
}
}