Extract collection literal resolve components to separate Kotlin file
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2010-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 org.jetbrains.kotlin.resolve
|
||||
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED_FEATURE
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.COLLECTION_LITERAL_CALL
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
|
||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
||||
|
||||
object CollectionLiteralResolver {
|
||||
private val PRIMITIVE_TYPE_TO_ARRAY: Map<PrimitiveType, Name> = hashMapOf(
|
||||
PrimitiveType.BOOLEAN to Name.identifier("booleanArrayOf"),
|
||||
PrimitiveType.CHAR to Name.identifier("charArrayOf"),
|
||||
PrimitiveType.INT to Name.identifier("intArrayOf"),
|
||||
PrimitiveType.BYTE to Name.identifier("byteArrayOf"),
|
||||
PrimitiveType.SHORT to Name.identifier("shortArrayOf"),
|
||||
PrimitiveType.FLOAT to Name.identifier("floatArrayOf"),
|
||||
PrimitiveType.LONG to Name.identifier("longArrayOf"),
|
||||
PrimitiveType.DOUBLE to Name.identifier("doubleArrayOf")
|
||||
)
|
||||
|
||||
private val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
|
||||
|
||||
fun resolveCollectionLiteral(collectionLiteralExpression: KtCollectionLiteralExpression,
|
||||
context: ExpressionTypingContext,
|
||||
callResolver: CallResolver,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): KotlinTypeInfo {
|
||||
if (!isInsideAnnotationEntryOrClass(collectionLiteralExpression)) {
|
||||
context.trace.report(UNSUPPORTED.on(collectionLiteralExpression, "Collection literals outside of annotations"))
|
||||
}
|
||||
|
||||
checkSupportsArrayLiterals(collectionLiteralExpression, context, languageVersionSettings)
|
||||
|
||||
return resolveCollectionLiteralSpecialMethod(collectionLiteralExpression, context, callResolver)
|
||||
}
|
||||
|
||||
private fun resolveCollectionLiteralSpecialMethod(
|
||||
collectionLiteralExpression: KtCollectionLiteralExpression,
|
||||
context: ExpressionTypingContext,
|
||||
callResolver: CallResolver
|
||||
): KotlinTypeInfo {
|
||||
val collectionLiteralCallName = getArrayFunctionCallName(context.expectedType)
|
||||
val call = CallMaker.makeCallForCollectionLiteral(collectionLiteralExpression)
|
||||
val resolutionResults = callResolver.resolveCallWithGivenName(context, call, collectionLiteralExpression, collectionLiteralCallName)
|
||||
|
||||
// TODO: check that resolved function is from package `kotlin`, otherwise report an error
|
||||
if (!resolutionResults.isSingleResult) {
|
||||
return noTypeInfo(context)
|
||||
}
|
||||
|
||||
context.trace.record(COLLECTION_LITERAL_CALL, collectionLiteralExpression, resolutionResults.resultingCall)
|
||||
return createTypeInfo(resolutionResults.resultingDescriptor.returnType, context)
|
||||
}
|
||||
|
||||
fun checkSupportsArrayLiterals(expression: KtCollectionLiteralExpression,
|
||||
context: ExpressionTypingContext,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
if (isInsideAnnotationEntryOrClass(expression) &&
|
||||
!languageVersionSettings.supportsFeature(LanguageFeature.ArrayLiteralsInAnnotations)) {
|
||||
context.trace.report(UNSUPPORTED_FEATURE.on(expression, LanguageFeature.ArrayLiteralsInAnnotations to languageVersionSettings))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isInsideAnnotationEntryOrClass(expression: KtCollectionLiteralExpression): Boolean {
|
||||
val parent = PsiTreeUtil.getParentOfType(expression, KtAnnotationEntry::class.java, KtClass::class.java)
|
||||
return parent is KtAnnotationEntry || (parent is KtClass && parent.isAnnotation())
|
||||
}
|
||||
|
||||
private fun getArrayFunctionCallName(expectedType: KotlinType): Name {
|
||||
if (NO_EXPECTED_TYPE === expectedType || !KotlinBuiltIns.isPrimitiveArray(expectedType)) {
|
||||
return ARRAY_OF_FUNCTION
|
||||
}
|
||||
|
||||
val descriptor = expectedType.constructor.declarationDescriptor ?: return ARRAY_OF_FUNCTION
|
||||
|
||||
val arrayFqName = DescriptorUtils.getFqName(descriptor)
|
||||
val primitiveType = KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(arrayFqName)
|
||||
|
||||
return PRIMITIVE_TYPE_TO_ARRAY[primitiveType] ?: ARRAY_OF_FUNCTION
|
||||
}
|
||||
}
|
||||
+6
-72
@@ -29,7 +29,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.KtNodeTypes;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -37,7 +36,6 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
||||
@@ -77,7 +75,10 @@ import org.jetbrains.kotlin.types.expressions.unqualifiedSuper.UnqualifiedSuperK
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
||||
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -97,20 +98,6 @@ import static org.jetbrains.kotlin.types.expressions.TypeReconstructionUtil.reco
|
||||
|
||||
@SuppressWarnings("SuspiciousMethodCalls")
|
||||
public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
private static final Map<PrimitiveType, Name> PRIMITIVE_TYPE_TO_ARRAY = new HashMap<PrimitiveType, Name>();
|
||||
static {
|
||||
PRIMITIVE_TYPE_TO_ARRAY.put(PrimitiveType.BOOLEAN, Name.identifier("booleanArrayOf"));
|
||||
PRIMITIVE_TYPE_TO_ARRAY.put(PrimitiveType.CHAR, Name.identifier("charArrayOf"));
|
||||
PRIMITIVE_TYPE_TO_ARRAY.put(PrimitiveType.INT, Name.identifier("intArrayOf"));
|
||||
PRIMITIVE_TYPE_TO_ARRAY.put(PrimitiveType.BYTE, Name.identifier("byteArrayOf"));
|
||||
PRIMITIVE_TYPE_TO_ARRAY.put(PrimitiveType.SHORT, Name.identifier("shortArrayOf"));
|
||||
PRIMITIVE_TYPE_TO_ARRAY.put(PrimitiveType.FLOAT, Name.identifier("floatArrayOf"));
|
||||
PRIMITIVE_TYPE_TO_ARRAY.put(PrimitiveType.LONG, Name.identifier("longArrayOf"));
|
||||
PRIMITIVE_TYPE_TO_ARRAY.put(PrimitiveType.DOUBLE, Name.identifier("doubleArrayOf"));
|
||||
}
|
||||
|
||||
private static final Name ARRAY_OF_FUNCTION = Name.identifier("arrayOf");
|
||||
|
||||
private static final TokenSet BARE_TYPES_ALLOWED = TokenSet.create(AS_KEYWORD, AS_SAFE);
|
||||
|
||||
protected BasicExpressionTypingVisitor(@NotNull ExpressionTypingInternals facade) {
|
||||
@@ -1517,12 +1504,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
public KotlinTypeInfo visitCollectionLiteralExpression(
|
||||
@NotNull KtCollectionLiteralExpression expression, ExpressionTypingContext context
|
||||
) {
|
||||
if (!isInsideAnnotationEntryOrClass(expression)) {
|
||||
context.trace.report(UNSUPPORTED.on(expression, "Collection literals outside of annotations"));
|
||||
}
|
||||
|
||||
checkSupportsArrayLiterals(expression, context);
|
||||
return resolveCollectionLiteralSpecialMethod(expression, context);
|
||||
return CollectionLiteralResolver.INSTANCE.resolveCollectionLiteral(
|
||||
expression, context, components.callResolver, components.languageVersionSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1785,53 +1768,4 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
functionResults.getResultingCall());
|
||||
return resultTypeInfo.replaceType(functionResults.getResultingDescriptor().getReturnType());
|
||||
}
|
||||
|
||||
private void checkSupportsArrayLiterals(KtCollectionLiteralExpression expression, ExpressionTypingContext context) {
|
||||
if (isInsideAnnotationEntryOrClass(expression) &&
|
||||
!components.languageVersionSettings.supportsFeature(LanguageFeature.ArrayLiteralsInAnnotations)) {
|
||||
context.trace.report(UNSUPPORTED_FEATURE.on(
|
||||
expression, TuplesKt.to(LanguageFeature.ArrayLiteralsInAnnotations, components.languageVersionSettings)));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInsideAnnotationEntryOrClass(KtCollectionLiteralExpression expression) {
|
||||
//noinspection unchecked
|
||||
PsiElement parent = PsiTreeUtil.getParentOfType(expression, KtAnnotationEntry.class, KtClass.class);
|
||||
return parent instanceof KtAnnotationEntry || (parent instanceof KtClass && ((KtClass) parent).isAnnotation());
|
||||
}
|
||||
|
||||
private KotlinTypeInfo resolveCollectionLiteralSpecialMethod(
|
||||
@NotNull KtCollectionLiteralExpression collectionLiteralExpression,
|
||||
@NotNull ExpressionTypingContext context
|
||||
) {
|
||||
Name collectionLiteralCallName;
|
||||
KotlinType expectedType = context.expectedType;
|
||||
if (NO_EXPECTED_TYPE == expectedType || !KotlinBuiltIns.isPrimitiveArray(expectedType)) {
|
||||
collectionLiteralCallName = ARRAY_OF_FUNCTION;
|
||||
}
|
||||
else {
|
||||
ClassifierDescriptor descriptor = expectedType.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor != null) {
|
||||
FqNameUnsafe arrayFqName = DescriptorUtils.getFqName(descriptor);
|
||||
PrimitiveType primitiveType = KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(arrayFqName);
|
||||
|
||||
collectionLiteralCallName = PRIMITIVE_TYPE_TO_ARRAY.get(primitiveType);
|
||||
}
|
||||
else {
|
||||
collectionLiteralCallName = ARRAY_OF_FUNCTION;
|
||||
}
|
||||
}
|
||||
|
||||
Call call = CallMaker.makeCallForCollectionLiteral(collectionLiteralExpression);
|
||||
OverloadResolutionResults<FunctionDescriptor> resolutionResults = components.callResolver.resolveCallWithGivenName(
|
||||
context, call, collectionLiteralExpression, collectionLiteralCallName);
|
||||
|
||||
// TODO: check that resolved function is from package `kotlin`, otherwise report an error
|
||||
if (!resolutionResults.isSingleResult()) {
|
||||
return TypeInfoFactoryKt.noTypeInfo(context);
|
||||
}
|
||||
|
||||
context.trace.record(COLLECTION_LITERAL_CALL, collectionLiteralExpression, resolutionResults.getResultingCall());
|
||||
return TypeInfoFactoryKt.createTypeInfo(resolutionResults.getResultingDescriptor().getReturnType(), context);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user