Support platform/impl modifiers for functions
Also add a new capability for ModuleDescriptor, which is used to obtain the platform in the multi-platform scenario in tests. Suppress the following errors for platform functions: "function has no body" and "nothing to inline". Also do not report redeclaration between platform and non-platform functions because this is the case when the common + platform-specific code are analyzed together. Note that some diagnostics reported in tests are not yet implemented in this commit, they appear in subsequent commits
This commit is contained in:
@@ -489,6 +489,11 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtParameter> DATA_CLASS_VARARG_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtParameter> DATA_CLASS_NOT_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
// Multi-platform projects
|
||||
|
||||
DiagnosticFactory0<KtDeclaration> PLATFORM_DECLARATION_WITH_BODY = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtParameter> PLATFORM_DECLARATION_WITH_DEFAULT_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Errors/warnings inside code blocks
|
||||
|
||||
+3
@@ -257,6 +257,9 @@ public class DefaultErrorMessages {
|
||||
MAP.put(USELESS_VARARG_ON_PARAMETER, "Vararg on this parameter is useless");
|
||||
MAP.put(MULTIPLE_VARARG_PARAMETERS, "Multiple vararg-parameters are prohibited");
|
||||
|
||||
MAP.put(PLATFORM_DECLARATION_WITH_BODY, "Platform declaration must not have a body");
|
||||
MAP.put(PLATFORM_DECLARATION_WITH_DEFAULT_PARAMETER, "Platform declaration cannot have parameters with default values");
|
||||
|
||||
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
|
||||
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
|
||||
MAP.put(NOTHING_TO_OVERRIDE, "''{0}'' overrides nothing", NAME);
|
||||
|
||||
@@ -732,10 +732,26 @@ class DeclarationsChecker(
|
||||
}
|
||||
}
|
||||
else /* top-level only */ {
|
||||
if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier) {
|
||||
if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier && !functionDescriptor.isPlatform) {
|
||||
trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
|
||||
}
|
||||
}
|
||||
|
||||
if (functionDescriptor.isPlatform) {
|
||||
checkPlatformFunction(function)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPlatformFunction(function: KtNamedFunction) {
|
||||
if (function.hasBody()) {
|
||||
trace.report(PLATFORM_DECLARATION_WITH_BODY.on(function))
|
||||
}
|
||||
|
||||
for (parameter in function.valueParameters) {
|
||||
if (parameter.hasDefaultValue()) {
|
||||
trace.report(PLATFORM_DECLARATION_WITH_DEFAULT_PARAMETER.on(parameter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkImplicitCallableType(declaration: KtCallableDeclaration, descriptor: CallableDescriptor) {
|
||||
|
||||
@@ -184,6 +184,10 @@ class FunctionDescriptorResolver(
|
||||
functionDescriptor.isInline = function.hasModifier(KtTokens.INLINE_KEYWORD)
|
||||
functionDescriptor.isTailrec = function.hasModifier(KtTokens.TAILREC_KEYWORD)
|
||||
functionDescriptor.isSuspend = function.hasModifier(KtTokens.SUSPEND_KEYWORD)
|
||||
functionDescriptor.isPlatform = function.hasModifier(KtTokens.PLATFORM_KEYWORD) ||
|
||||
containingDescriptor is ClassDescriptor && containingDescriptor.isPlatform
|
||||
functionDescriptor.isImpl = function.hasModifier(KtTokens.IMPL_KEYWORD)
|
||||
|
||||
receiverType?.let { ForceResolveUtil.forceResolveAllContents(it.annotations) }
|
||||
for (valueParameterDescriptor in valueParameterDescriptors) {
|
||||
ForceResolveUtil.forceResolveAllContents(valueParameterDescriptor.type.annotations)
|
||||
@@ -293,6 +297,12 @@ class FunctionDescriptorResolver(
|
||||
isPrimary,
|
||||
declarationToTrace.toSourceElement()
|
||||
)
|
||||
if (classDescriptor.isPlatform) {
|
||||
constructorDescriptor.isPlatform = true
|
||||
}
|
||||
if (classDescriptor.isImpl) {
|
||||
constructorDescriptor.isImpl = true
|
||||
}
|
||||
trace.record(BindingContext.CONSTRUCTOR, declarationToTrace, constructorDescriptor)
|
||||
val parameterScope = LexicalWritableScope(
|
||||
scope,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-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 org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
|
||||
sealed class MultiTargetPlatform {
|
||||
object Common : MultiTargetPlatform()
|
||||
|
||||
data class Specific(val platform: String) : MultiTargetPlatform()
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val CAPABILITY = ModuleDescriptor.Capability<MultiTargetPlatform>("MULTI_TARGET_PLATFORM")
|
||||
}
|
||||
}
|
||||
|
||||
fun ModuleDescriptor.getMultiTargetPlatform(): MultiTargetPlatform? =
|
||||
module.getCapability(MultiTargetPlatform.CAPABILITY)
|
||||
|
||||
fun MemberDescriptor.getMultiTargetPlatform(): String? =
|
||||
(module.getMultiTargetPlatform() as? MultiTargetPlatform.Specific)?.platform
|
||||
@@ -252,6 +252,8 @@ class OverloadResolver(
|
||||
if (member1 == member2) continue
|
||||
if (isConstructorsOfDifferentRedeclaredClasses(member1, member2)) continue
|
||||
if (isTopLevelMainInDifferentFiles(member1, member2)) continue
|
||||
if (isDefinitionsForDifferentPlatforms(member1, member2)) continue
|
||||
if (isPlatformDeclarationAndDefinition(member1, member2) || isPlatformDeclarationAndDefinition(member2, member1)) continue
|
||||
|
||||
if (!overloadChecker.isOverloadable(member1, member2)) {
|
||||
redeclarations.add(member1)
|
||||
@@ -281,6 +283,18 @@ class OverloadResolver(
|
||||
return file1 == null || file2 == null || file1 !== file2
|
||||
}
|
||||
|
||||
private fun isPlatformDeclarationAndDefinition(declaration: DeclarationDescriptor, definition: DeclarationDescriptor): Boolean {
|
||||
return declaration is MemberDescriptor && declaration.isPlatform &&
|
||||
definition is MemberDescriptor && !definition.isPlatform
|
||||
}
|
||||
|
||||
private fun isDefinitionsForDifferentPlatforms(member1: DeclarationDescriptorNonRoot, member2: DeclarationDescriptorNonRoot): Boolean {
|
||||
if (member1 !is MemberDescriptor || member2 !is MemberDescriptor) return false
|
||||
|
||||
return member1.isImpl && member2.isImpl &&
|
||||
member1.getMultiTargetPlatform() != member2.getMultiTargetPlatform()
|
||||
}
|
||||
|
||||
private fun reportRedeclarations(redeclarations: Collection<DeclarationDescriptorNonRoot>) {
|
||||
if (redeclarations.isEmpty()) return
|
||||
|
||||
|
||||
+8
-16
@@ -134,25 +134,17 @@ object InlineAnalyzerExtension : AnalyzerExtensions.AnalyzerExtension {
|
||||
containingDeclaration is ClassDescriptor && containingDeclaration.modality == Modality.FINAL
|
||||
}
|
||||
|
||||
private fun checkHasInlinableAndNullability(
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
function: KtFunction,
|
||||
trace: BindingTrace) {
|
||||
var hasInlinable = false
|
||||
val parameters = functionDescriptor.valueParameters
|
||||
var index = 0
|
||||
for (parameter in parameters) {
|
||||
hasInlinable = hasInlinable or checkInlinableParameter(parameter, function.valueParameters[index++], functionDescriptor, trace)
|
||||
private fun checkHasInlinableAndNullability(functionDescriptor: FunctionDescriptor, function: KtFunction, trace: BindingTrace) {
|
||||
for ((parameter, descriptor) in function.valueParameters.zip(functionDescriptor.valueParameters)) {
|
||||
if (checkInlinableParameter(descriptor, parameter, functionDescriptor, trace)) return
|
||||
}
|
||||
|
||||
hasInlinable = hasInlinable or InlineUtil.containsReifiedTypeParameters(functionDescriptor)
|
||||
if (InlineUtil.containsReifiedTypeParameters(functionDescriptor) ||
|
||||
functionDescriptor.isInlineOnlyOrReified() ||
|
||||
functionDescriptor.isPlatform) return
|
||||
|
||||
if (!hasInlinable && !functionDescriptor.isInlineOnlyOrReified()) {
|
||||
val modifierList = function.modifierList
|
||||
val inlineModifier = modifierList?.getModifier(KtTokens.INLINE_KEYWORD)
|
||||
val reportOn = inlineModifier ?: function
|
||||
trace.report(Errors.NOTHING_TO_INLINE.on(reportOn, functionDescriptor))
|
||||
}
|
||||
val reportOn = function.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?: function
|
||||
trace.report(Errors.NOTHING_TO_INLINE.on(reportOn, functionDescriptor))
|
||||
}
|
||||
|
||||
fun checkInlinableParameter(
|
||||
|
||||
Reference in New Issue
Block a user