Add checks that coroutines are available at the given language level
This commit is contained in:
@@ -24,6 +24,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion) {
|
|||||||
BoundCallableReferences(KOTLIN_1_1),
|
BoundCallableReferences(KOTLIN_1_1),
|
||||||
LocalDelegatedProperties(KOTLIN_1_1),
|
LocalDelegatedProperties(KOTLIN_1_1),
|
||||||
TopLevelSealedInheritance(KOTLIN_1_1),
|
TopLevelSealedInheritance(KOTLIN_1_1),
|
||||||
|
Coroutines(KOTLIN_1_1)
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement;
|
|||||||
import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.cfg.WhenMissingCase;
|
import org.jetbrains.kotlin.cfg.WhenMissingCase;
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken;
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken;
|
||||||
@@ -54,6 +55,7 @@ public interface Errors {
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
DiagnosticFactory1<PsiElement, String> UNSUPPORTED = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, String> UNSUPPORTED = DiagnosticFactory1.create(ERROR);
|
||||||
|
DiagnosticFactory1<PsiElement, LanguageFeature> UNSUPPORTED_FEATURE = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory1<PsiElement, Throwable> EXCEPTION_FROM_ANALYZER = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, Throwable> EXCEPTION_FROM_ANALYZER = DiagnosticFactory1.create(ERROR);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
+1
@@ -497,6 +497,7 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(UNSAFE_IMPLICIT_INVOKE_CALL, "Reference has a nullable type ''{0}'', use explicit ''?.invoke()'' to make a function-like call instead", RENDER_TYPE);
|
MAP.put(UNSAFE_IMPLICIT_INVOKE_CALL, "Reference has a nullable type ''{0}'', use explicit ''?.invoke()'' to make a function-like call instead", RENDER_TYPE);
|
||||||
MAP.put(AMBIGUOUS_LABEL, "Ambiguous label");
|
MAP.put(AMBIGUOUS_LABEL, "Ambiguous label");
|
||||||
MAP.put(UNSUPPORTED, "Unsupported [{0}]", STRING);
|
MAP.put(UNSUPPORTED, "Unsupported [{0}]", STRING);
|
||||||
|
MAP.put(UNSUPPORTED_FEATURE, "{0} are unsupported at this language level", TO_STRING);
|
||||||
MAP.put(EXCEPTION_FROM_ANALYZER, "Internal Error occurred while analyzing this expression:\n{0}", THROWABLE);
|
MAP.put(EXCEPTION_FROM_ANALYZER, "Internal Error occurred while analyzing this expression:\n{0}", THROWABLE);
|
||||||
MAP.put(UNNECESSARY_SAFE_CALL, "Unnecessary safe call on a non-null receiver of type {0}", RENDER_TYPE);
|
MAP.put(UNNECESSARY_SAFE_CALL, "Unnecessary safe call on a non-null receiver of type {0}", RENDER_TYPE);
|
||||||
MAP.put(UNEXPECTED_SAFE_CALL, "Safe-call is not allowed here");
|
MAP.put(UNEXPECTED_SAFE_CALL, "Safe-call is not allowed here");
|
||||||
|
|||||||
@@ -558,7 +558,7 @@ public class BodyResolver {
|
|||||||
|
|
||||||
private void processModifiersOnInitializer(@NotNull KtModifierListOwner owner, @NotNull LexicalScope scope) {
|
private void processModifiersOnInitializer(@NotNull KtModifierListOwner owner, @NotNull LexicalScope scope) {
|
||||||
annotationChecker.check(owner, trace, null);
|
annotationChecker.check(owner, trace, null);
|
||||||
ModifierCheckerCore.INSTANCE.check(owner, trace, null);
|
ModifierCheckerCore.INSTANCE.check(owner, trace, null, languageFeatureSettings);
|
||||||
KtModifierList modifierList = owner.getModifierList();
|
KtModifierList modifierList = owner.getModifierList();
|
||||||
if (modifierList == null) return;
|
if (modifierList == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet
|
|||||||
import com.google.common.collect.Sets
|
import com.google.common.collect.Sets
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
@@ -70,10 +71,11 @@ internal class DeclarationsCheckerBuilder(
|
|||||||
private val descriptorResolver: DescriptorResolver,
|
private val descriptorResolver: DescriptorResolver,
|
||||||
private val originalModifiersChecker: ModifiersChecker,
|
private val originalModifiersChecker: ModifiersChecker,
|
||||||
private val annotationChecker: AnnotationChecker,
|
private val annotationChecker: AnnotationChecker,
|
||||||
private val identifierChecker: IdentifierChecker
|
private val identifierChecker: IdentifierChecker,
|
||||||
|
private val languageFeatureSettings: LanguageFeatureSettings
|
||||||
) {
|
) {
|
||||||
fun withTrace(trace: BindingTrace) =
|
fun withTrace(trace: BindingTrace) =
|
||||||
DeclarationsChecker(descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace)
|
DeclarationsChecker(descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageFeatureSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeclarationsChecker(
|
class DeclarationsChecker(
|
||||||
@@ -81,7 +83,8 @@ class DeclarationsChecker(
|
|||||||
modifiersChecker: ModifiersChecker,
|
modifiersChecker: ModifiersChecker,
|
||||||
private val annotationChecker: AnnotationChecker,
|
private val annotationChecker: AnnotationChecker,
|
||||||
private val identifierChecker: IdentifierChecker,
|
private val identifierChecker: IdentifierChecker,
|
||||||
private val trace: BindingTrace
|
private val trace: BindingTrace,
|
||||||
|
private val languageFeatureSettings: LanguageFeatureSettings
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
||||||
@@ -190,7 +193,7 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
annotationChecker.check(packageDirective, trace, null)
|
annotationChecker.check(packageDirective, trace, null)
|
||||||
ModifierCheckerCore.check(packageDirective, trace, null)
|
ModifierCheckerCore.check(packageDirective, trace, descriptor = null, languageFeatureSettings = languageFeatureSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkTypesInClassHeader(classOrObject: KtClassOrObject) {
|
private fun checkTypesInClassHeader(classOrObject: KtClassOrObject) {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.google.common.collect.Sets;
|
|||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeatureSettings;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
||||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||||
@@ -157,9 +158,12 @@ public class ModifiersChecker {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final BindingTrace trace;
|
private final BindingTrace trace;
|
||||||
|
@NotNull
|
||||||
|
private final LanguageFeatureSettings languageFeatureSettings;
|
||||||
|
|
||||||
private ModifiersCheckingProcedure(@NotNull BindingTrace trace) {
|
private ModifiersCheckingProcedure(@NotNull BindingTrace trace, LanguageFeatureSettings languageFeatureSettings) {
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
|
this.languageFeatureSettings = languageFeatureSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkParameterHasNoValOrVar(
|
public void checkParameterHasNoValOrVar(
|
||||||
@@ -182,7 +186,7 @@ public class ModifiersChecker {
|
|||||||
AnnotationUseSiteTargetChecker.INSTANCE.check(modifierListOwner, descriptor, trace);
|
AnnotationUseSiteTargetChecker.INSTANCE.check(modifierListOwner, descriptor, trace);
|
||||||
runDeclarationCheckers(modifierListOwner, descriptor);
|
runDeclarationCheckers(modifierListOwner, descriptor);
|
||||||
annotationChecker.check(modifierListOwner, trace, descriptor);
|
annotationChecker.check(modifierListOwner, trace, descriptor);
|
||||||
ModifierCheckerCore.INSTANCE.check(modifierListOwner, trace, descriptor);
|
ModifierCheckerCore.INSTANCE.check(modifierListOwner, trace, descriptor, languageFeatureSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkModifiersForLocalDeclaration(
|
public void checkModifiersForLocalDeclaration(
|
||||||
@@ -194,10 +198,10 @@ public class ModifiersChecker {
|
|||||||
|
|
||||||
public void checkModifiersForDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration) {
|
public void checkModifiersForDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration) {
|
||||||
annotationChecker.check(multiDeclaration, trace, null);
|
annotationChecker.check(multiDeclaration, trace, null);
|
||||||
ModifierCheckerCore.INSTANCE.check(multiDeclaration, trace, null);
|
ModifierCheckerCore.INSTANCE.check(multiDeclaration, trace, null, languageFeatureSettings);
|
||||||
for (KtDestructuringDeclarationEntry multiEntry: multiDeclaration.getEntries()) {
|
for (KtDestructuringDeclarationEntry multiEntry: multiDeclaration.getEntries()) {
|
||||||
annotationChecker.check(multiEntry, trace, null);
|
annotationChecker.check(multiEntry, trace, null);
|
||||||
ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null);
|
ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null, languageFeatureSettings);
|
||||||
UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace);
|
UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,13 +239,14 @@ public class ModifiersChecker {
|
|||||||
for (DeclarationChecker checker : declarationCheckers) {
|
for (DeclarationChecker checker : declarationCheckers) {
|
||||||
checker.check(declaration, descriptor, trace, trace.getBindingContext());
|
checker.check(declaration, descriptor, trace, trace.getBindingContext());
|
||||||
}
|
}
|
||||||
|
OperatorModifierChecker.INSTANCE.check(declaration, descriptor, trace, languageFeatureSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkTypeParametersModifiers(@NotNull KtModifierListOwner modifierListOwner) {
|
public void checkTypeParametersModifiers(@NotNull KtModifierListOwner modifierListOwner) {
|
||||||
if (!(modifierListOwner instanceof KtTypeParameterListOwner)) return;
|
if (!(modifierListOwner instanceof KtTypeParameterListOwner)) return;
|
||||||
List<KtTypeParameter> typeParameters = ((KtTypeParameterListOwner) modifierListOwner).getTypeParameters();
|
List<KtTypeParameter> typeParameters = ((KtTypeParameterListOwner) modifierListOwner).getTypeParameters();
|
||||||
for (KtTypeParameter typeParameter : typeParameters) {
|
for (KtTypeParameter typeParameter : typeParameters) {
|
||||||
ModifierCheckerCore.INSTANCE.check(typeParameter, trace, null);
|
ModifierCheckerCore.INSTANCE.check(typeParameter, trace, null, languageFeatureSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,13 +257,21 @@ public class ModifiersChecker {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private final Iterable<DeclarationChecker> declarationCheckers;
|
private final Iterable<DeclarationChecker> declarationCheckers;
|
||||||
|
|
||||||
public ModifiersChecker(@NotNull AnnotationChecker annotationChecker, @NotNull Iterable<DeclarationChecker> declarationCheckers) {
|
@NotNull
|
||||||
|
private final LanguageFeatureSettings languageFeatureSettings;
|
||||||
|
|
||||||
|
public ModifiersChecker(
|
||||||
|
@NotNull AnnotationChecker annotationChecker,
|
||||||
|
@NotNull Iterable<DeclarationChecker> declarationCheckers,
|
||||||
|
@NotNull LanguageFeatureSettings languageFeatureSettings
|
||||||
|
) {
|
||||||
this.annotationChecker = annotationChecker;
|
this.annotationChecker = annotationChecker;
|
||||||
this.declarationCheckers = declarationCheckers;
|
this.declarationCheckers = declarationCheckers;
|
||||||
|
this.languageFeatureSettings = languageFeatureSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ModifiersCheckingProcedure withTrace(@NotNull BindingTrace trace) {
|
public ModifiersCheckingProcedure withTrace(@NotNull BindingTrace trace) {
|
||||||
return new ModifiersCheckingProcedure(trace);
|
return new ModifiersCheckingProcedure(trace, languageFeatureSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.resolve
|
|||||||
import com.intellij.lang.ASTNode
|
import com.intellij.lang.ASTNode
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.tree.TokenSet
|
import com.intellij.psi.tree.TokenSet
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
@@ -90,6 +92,11 @@ object ModifierCheckerCore {
|
|||||||
INFIX_KEYWORD to EnumSet.of(FUNCTION)
|
INFIX_KEYWORD to EnumSet.of(FUNCTION)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val featureDependencies = mapOf(
|
||||||
|
COROUTINE_KEYWORD to LanguageFeature.Coroutines,
|
||||||
|
SUSPEND_KEYWORD to LanguageFeature.Coroutines
|
||||||
|
)
|
||||||
|
|
||||||
// NOTE: deprecated targets must be possible!
|
// NOTE: deprecated targets must be possible!
|
||||||
private val deprecatedTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
|
private val deprecatedTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
|
||||||
|
|
||||||
@@ -242,6 +249,23 @@ object ModifierCheckerCore {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkLanguageLevelSupport(
|
||||||
|
trace: BindingTrace,
|
||||||
|
node: ASTNode,
|
||||||
|
languageFeatureSettings: LanguageFeatureSettings
|
||||||
|
): Boolean {
|
||||||
|
val modifier = node.elementType as KtModifierKeywordToken
|
||||||
|
val dependency = featureDependencies[modifier] ?: return true
|
||||||
|
|
||||||
|
if (!languageFeatureSettings.supportsFeature(dependency)) {
|
||||||
|
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, dependency))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Should return false if error is reported, true otherwise
|
// Should return false if error is reported, true otherwise
|
||||||
private fun checkParent(trace: BindingTrace, node: ASTNode, parentDescriptor: DeclarationDescriptor?): Boolean {
|
private fun checkParent(trace: BindingTrace, node: ASTNode, parentDescriptor: DeclarationDescriptor?): Boolean {
|
||||||
val modifier = node.elementType as KtModifierKeywordToken
|
val modifier = node.elementType as KtModifierKeywordToken
|
||||||
@@ -264,7 +288,13 @@ object ModifierCheckerCore {
|
|||||||
|
|
||||||
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD))
|
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD))
|
||||||
|
|
||||||
private fun checkModifierList(list: KtModifierList, trace: BindingTrace, parentDescriptor: DeclarationDescriptor?, actualTargets: List<KotlinTarget>) {
|
private fun checkModifierList(
|
||||||
|
list: KtModifierList,
|
||||||
|
trace: BindingTrace,
|
||||||
|
parentDescriptor: DeclarationDescriptor?,
|
||||||
|
actualTargets: List<KotlinTarget>,
|
||||||
|
languageFeatureSettings: LanguageFeatureSettings
|
||||||
|
) {
|
||||||
// It's a list of all nodes with error already reported
|
// It's a list of all nodes with error already reported
|
||||||
// General strategy: report no more than one error but any number of warnings
|
// General strategy: report no more than one error but any number of warnings
|
||||||
val incorrectNodes = hashSetOf<ASTNode>()
|
val incorrectNodes = hashSetOf<ASTNode>()
|
||||||
@@ -283,21 +313,29 @@ object ModifierCheckerCore {
|
|||||||
else if (!checkParent(trace, second, parentDescriptor)) {
|
else if (!checkParent(trace, second, parentDescriptor)) {
|
||||||
incorrectNodes += second
|
incorrectNodes += second
|
||||||
}
|
}
|
||||||
|
else if (!checkLanguageLevelSupport(trace, second, languageFeatureSettings)) {
|
||||||
|
incorrectNodes += second
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun check(listOwner: KtModifierListOwner, trace: BindingTrace, descriptor: DeclarationDescriptor?) {
|
fun check(
|
||||||
|
listOwner: KtModifierListOwner,
|
||||||
|
trace: BindingTrace,
|
||||||
|
descriptor: DeclarationDescriptor?,
|
||||||
|
languageFeatureSettings: LanguageFeatureSettings
|
||||||
|
) {
|
||||||
if (listOwner is KtDeclarationWithBody) {
|
if (listOwner is KtDeclarationWithBody) {
|
||||||
// JetFunction or JetPropertyAccessor
|
// JetFunction or JetPropertyAccessor
|
||||||
for (parameter in listOwner.valueParameters) {
|
for (parameter in listOwner.valueParameters) {
|
||||||
if (!parameter.hasValOrVar()) {
|
if (!parameter.hasValOrVar()) {
|
||||||
check(parameter, trace, null)
|
check(parameter, trace, null, languageFeatureSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList(listOwner, descriptor as? ClassDescriptor, trace)
|
val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList(listOwner, descriptor as? ClassDescriptor, trace)
|
||||||
val list = listOwner.modifierList ?: return
|
val list = listOwner.modifierList ?: return
|
||||||
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets)
|
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets, languageFeatureSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve
|
package org.jetbrains.kotlin.resolve
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||||
@@ -40,20 +42,28 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import org.jetbrains.kotlin.util.CheckResult
|
import org.jetbrains.kotlin.util.CheckResult
|
||||||
import org.jetbrains.kotlin.util.OperatorChecks
|
import org.jetbrains.kotlin.util.OperatorChecks
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
class OperatorModifierChecker : DeclarationChecker {
|
object OperatorModifierChecker {
|
||||||
override fun check(
|
fun check(
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
diagnosticHolder: DiagnosticSink,
|
diagnosticHolder: DiagnosticSink,
|
||||||
bindingContext: BindingContext
|
languageFeatureSettings: LanguageFeatureSettings
|
||||||
) {
|
) {
|
||||||
val functionDescriptor = descriptor as? FunctionDescriptor ?: return
|
val functionDescriptor = descriptor as? FunctionDescriptor ?: return
|
||||||
if (!functionDescriptor.isOperator) return
|
if (!functionDescriptor.isOperator) return
|
||||||
val modifier = declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD) ?: return
|
val modifier = declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD) ?: return
|
||||||
|
|
||||||
val checkResult = OperatorChecks.checkOperator(functionDescriptor)
|
val checkResult = OperatorChecks.checkOperator(functionDescriptor)
|
||||||
if (checkResult.isSuccess) return
|
if (checkResult.isSuccess) {
|
||||||
|
if (functionDescriptor.name == OperatorNameConventions.COROUTINE_HANDLE_RESULT
|
||||||
|
&& !languageFeatureSettings.supportsFeature(LanguageFeature.Coroutines)
|
||||||
|
) {
|
||||||
|
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(modifier, LanguageFeature.Coroutines))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val errorDescription = if (checkResult is CheckResult.IllegalSignature)
|
val errorDescription = if (checkResult is CheckResult.IllegalSignature)
|
||||||
checkResult.error
|
checkResult.error
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
|||||||
ConstModifierChecker,
|
ConstModifierChecker,
|
||||||
UnderscoreChecker,
|
UnderscoreChecker,
|
||||||
InlineParameterChecker,
|
InlineParameterChecker,
|
||||||
OperatorModifierChecker(),
|
|
||||||
InfixModifierChecker(),
|
InfixModifierChecker(),
|
||||||
SuspendModifierChecker,
|
SuspendModifierChecker,
|
||||||
CoroutineModifierChecker)
|
CoroutineModifierChecker)
|
||||||
|
|||||||
@@ -673,7 +673,7 @@ class TypeResolver(
|
|||||||
): List<TypeProjection> {
|
): List<TypeProjection> {
|
||||||
return argumentElements.mapIndexed { i, argumentElement ->
|
return argumentElements.mapIndexed { i, argumentElement ->
|
||||||
val projectionKind = argumentElement.projectionKind
|
val projectionKind = argumentElement.projectionKind
|
||||||
ModifierCheckerCore.check(argumentElement, c.trace, null)
|
ModifierCheckerCore.check(argumentElement, c.trace, null, languageFeatureSettings)
|
||||||
if (projectionKind == KtProjectionKind.STAR) {
|
if (projectionKind == KtProjectionKind.STAR) {
|
||||||
val parameters = constructor.parameters
|
val parameters = constructor.parameters
|
||||||
if (parameters.size > i) {
|
if (parameters.size > i) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls
|
package org.jetbrains.kotlin.resolve.calls
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||||
import org.jetbrains.kotlin.coroutines.controllerTypeIfCoroutine
|
import org.jetbrains.kotlin.coroutines.controllerTypeIfCoroutine
|
||||||
import org.jetbrains.kotlin.coroutines.resolveCoroutineHandleResultCallIfNeeded
|
import org.jetbrains.kotlin.coroutines.resolveCoroutineHandleResultCallIfNeeded
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
@@ -27,6 +28,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
|
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariable
|
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariable
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.checkCoroutineBuilderCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
|
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
|
||||||
@@ -58,7 +60,8 @@ class CallCompleter(
|
|||||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||||
private val callCheckers: Iterable<CallChecker>,
|
private val callCheckers: Iterable<CallChecker>,
|
||||||
private val builtIns: KotlinBuiltIns,
|
private val builtIns: KotlinBuiltIns,
|
||||||
private val fakeCallResolver: FakeCallResolver
|
private val fakeCallResolver: FakeCallResolver,
|
||||||
|
private val languageFeatureSettings: LanguageFeatureSettings
|
||||||
) {
|
) {
|
||||||
fun <D : CallableDescriptor> completeCall(
|
fun <D : CallableDescriptor> completeCall(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
@@ -92,6 +95,7 @@ class CallCompleter(
|
|||||||
symbolUsageValidator.validateCall(resolvedCall, resolvedCall.resultingDescriptor, context.trace, element!!)
|
symbolUsageValidator.validateCall(resolvedCall, resolvedCall.resultingDescriptor, context.trace, element!!)
|
||||||
|
|
||||||
resolveHandleResultCallForCoroutineLambdaExpressions(context, resolvedCall)
|
resolveHandleResultCallForCoroutineLambdaExpressions(context, resolvedCall)
|
||||||
|
checkCoroutineBuilderCall(resolvedCall, context, languageFeatureSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (results.isSingleResult && results.resultingCall.status.isSuccess) {
|
if (results.isSingleResult && results.resultingCall.status.isSuccess) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import kotlin.jvm.functions.Function0;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeatureSettings;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
@@ -70,13 +71,16 @@ public class CallResolver {
|
|||||||
private CallCompleter callCompleter;
|
private CallCompleter callCompleter;
|
||||||
private NewResolutionOldInference newCallResolver;
|
private NewResolutionOldInference newCallResolver;
|
||||||
private final KotlinBuiltIns builtIns;
|
private final KotlinBuiltIns builtIns;
|
||||||
|
private final LanguageFeatureSettings languageFeatureSettings;
|
||||||
|
|
||||||
private static final PerformanceCounter callResolvePerfCounter = PerformanceCounter.Companion.create("Call resolve", ExpressionTypingVisitorDispatcher.typeInfoPerfCounter);
|
private static final PerformanceCounter callResolvePerfCounter = PerformanceCounter.Companion.create("Call resolve", ExpressionTypingVisitorDispatcher.typeInfoPerfCounter);
|
||||||
|
|
||||||
public CallResolver(
|
public CallResolver(
|
||||||
@NotNull KotlinBuiltIns builtIns
|
@NotNull KotlinBuiltIns builtIns,
|
||||||
|
@NotNull LanguageFeatureSettings languageFeatureSettings
|
||||||
) {
|
) {
|
||||||
this.builtIns = builtIns;
|
this.builtIns = builtIns;
|
||||||
|
this.languageFeatureSettings = languageFeatureSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
// component dependency cycle
|
// component dependency cycle
|
||||||
@@ -583,7 +587,7 @@ public class CallResolver {
|
|||||||
for (KtTypeProjection projection : typeArguments) {
|
for (KtTypeProjection projection : typeArguments) {
|
||||||
if (projection.getProjectionKind() != KtProjectionKind.NONE) {
|
if (projection.getProjectionKind() != KtProjectionKind.NONE) {
|
||||||
context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
|
context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
|
||||||
ModifierCheckerCore.INSTANCE.check(projection, context.trace, null);
|
ModifierCheckerCore.INSTANCE.check(projection, context.trace, null, languageFeatureSettings);
|
||||||
}
|
}
|
||||||
KotlinType type = argumentTypeResolver.resolveTypeRefWithDefault(
|
KotlinType type = argumentTypeResolver.resolveTypeRefWithDefault(
|
||||||
projection.getTypeReference(), context.scope, context.trace,
|
projection.getTypeReference(), context.scope, context.trace,
|
||||||
|
|||||||
+18
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
@@ -37,3 +39,19 @@ object CoroutineSuspendCallChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It can't be another CallChecker implementation because of 3rd parameter
|
||||||
|
fun checkCoroutineBuilderCall(
|
||||||
|
resolvedCall: ResolvedCall<*>,
|
||||||
|
context: BasicCallResolutionContext,
|
||||||
|
languageFeatureSettings: LanguageFeatureSettings
|
||||||
|
) {
|
||||||
|
val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return
|
||||||
|
if (descriptor.valueParameters.any { it.isCoroutine }
|
||||||
|
&& !languageFeatureSettings.supportsFeature(LanguageFeature.Coroutines)) {
|
||||||
|
context.trace.report(
|
||||||
|
Errors.UNSUPPORTED_FEATURE.on(
|
||||||
|
resolvedCall.call.calleeExpression ?: resolvedCall.call.callElement, LanguageFeature.Coroutines))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+1
-1
@@ -489,7 +489,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
components.identifierChecker.checkDeclaration(catchParameter, context.trace);
|
components.identifierChecker.checkDeclaration(catchParameter, context.trace);
|
||||||
ModifiersChecker.ModifiersCheckingProcedure modifiersChecking = components.modifiersChecker.withTrace(context.trace);
|
ModifiersChecker.ModifiersCheckingProcedure modifiersChecking = components.modifiersChecker.withTrace(context.trace);
|
||||||
modifiersChecking.checkParameterHasNoValOrVar(catchParameter, VAL_OR_VAR_ON_CATCH_PARAMETER);
|
modifiersChecking.checkParameterHasNoValOrVar(catchParameter, VAL_OR_VAR_ON_CATCH_PARAMETER);
|
||||||
ModifierCheckerCore.INSTANCE.check(catchParameter, context.trace, null);
|
ModifierCheckerCore.INSTANCE.check(catchParameter, context.trace, null, components.languageFeatureSettings);
|
||||||
|
|
||||||
VariableDescriptor variableDescriptor = components.descriptorResolver.resolveLocalVariableDescriptor(
|
VariableDescriptor variableDescriptor = components.descriptorResolver.resolveLocalVariableDescriptor(
|
||||||
context.scope, catchParameter, context.trace);
|
context.scope, catchParameter, context.trace);
|
||||||
|
|||||||
+7
-6
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.types.expressions;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
import org.jetbrains.kotlin.builtins.ReflectionTypes;
|
import org.jetbrains.kotlin.builtins.ReflectionTypes;
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeatureSettings;
|
||||||
import org.jetbrains.kotlin.context.GlobalContext;
|
import org.jetbrains.kotlin.context.GlobalContext;
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupTracker;
|
import org.jetbrains.kotlin.incremental.components.LookupTracker;
|
||||||
import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap;
|
import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap;
|
||||||
@@ -61,8 +62,8 @@ public class ExpressionTypingComponents {
|
|||||||
/*package*/ DeclarationsCheckerBuilder declarationsCheckerBuilder;
|
/*package*/ DeclarationsCheckerBuilder declarationsCheckerBuilder;
|
||||||
/*package*/ LocalVariableResolver localVariableResolver;
|
/*package*/ LocalVariableResolver localVariableResolver;
|
||||||
/*package*/ LookupTracker lookupTracker;
|
/*package*/ LookupTracker lookupTracker;
|
||||||
/*package*/ DelegatedPropertyResolver delegatedPropertyResolver;
|
|
||||||
/*package*/ OverloadChecker overloadChecker;
|
/*package*/ OverloadChecker overloadChecker;
|
||||||
|
/*package*/ LanguageFeatureSettings languageFeatureSettings;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void setGlobalContext(@NotNull GlobalContext globalContext) {
|
public void setGlobalContext(@NotNull GlobalContext globalContext) {
|
||||||
@@ -209,13 +210,13 @@ public class ExpressionTypingComponents {
|
|||||||
this.lookupTracker = lookupTracker;
|
this.lookupTracker = lookupTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
|
||||||
public void setDelegatedPropertyResolver(DelegatedPropertyResolver delegatedPropertyResolver) {
|
|
||||||
this.delegatedPropertyResolver = delegatedPropertyResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void setOverloadChecker(OverloadChecker overloadChecker) {
|
public void setOverloadChecker(OverloadChecker overloadChecker) {
|
||||||
this.overloadChecker = overloadChecker;
|
this.overloadChecker = overloadChecker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public void setLanguageFeatureSettings(@NotNull LanguageFeatureSettings languageFeatureSettings) {
|
||||||
|
this.languageFeatureSettings = languageFeatureSettings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// !LANGUAGE: -Coroutines
|
||||||
|
|
||||||
|
class Controller {
|
||||||
|
<!UNSUPPORTED_FEATURE!>suspend<!> fun suspendHere(x: Continuation<String>) {
|
||||||
|
x.resume("OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
<!UNSUPPORTED_FEATURE!>operator<!> fun handleResult(x: String, y: Continuation<Nothing>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder(<!UNSUPPORTED_FEATURE!>coroutine<!> c: Controller.() -> Continuation<Unit>) {
|
||||||
|
c(Controller()).resume(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var result = ""
|
||||||
|
|
||||||
|
<!UNSUPPORTED_FEATURE!>builder<!> {
|
||||||
|
suspendHere()
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun box(): kotlin.String
|
||||||
|
public fun builder(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
|
|
||||||
|
public final class Controller {
|
||||||
|
public constructor Controller()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final operator fun handleResult(/*0*/ x: kotlin.String, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final suspend fun suspendHere(/*0*/ x: kotlin.coroutines.Continuation<kotlin.String>): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -3915,6 +3915,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unsupported.kt")
|
||||||
|
public void testUnsupported() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/unsupported.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("wrongHandleResult.kt")
|
@TestMetadata("wrongHandleResult.kt")
|
||||||
public void testWrongHandleResult() throws Exception {
|
public void testWrongHandleResult() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/wrongHandleResult.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/wrongHandleResult.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user