FIR checker: report violations related to API mode
This commit is contained in:
committed by
Mikhail Glukhikh
parent
52b247937e
commit
c262f17d75
+24
@@ -1199,6 +1199,30 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.NO_EXPLICIT_VISIBILITY_IN_API_MODE) { firDiagnostic ->
|
||||||
|
NoExplicitVisibilityInApiModeImpl(
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
add(FirErrors.NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING) { firDiagnostic ->
|
||||||
|
NoExplicitVisibilityInApiModeWarningImpl(
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
add(FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE) { firDiagnostic ->
|
||||||
|
NoExplicitReturnTypeInApiModeImpl(
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
add(FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING) { firDiagnostic ->
|
||||||
|
NoExplicitReturnTypeInApiModeWarningImpl(
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.INLINE_CLASS_NOT_TOP_LEVEL) { firDiagnostic ->
|
add(FirErrors.INLINE_CLASS_NOT_TOP_LEVEL) { firDiagnostic ->
|
||||||
InlineClassNotTopLevelImpl(
|
InlineClassNotTopLevelImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic,
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
|||||||
+16
@@ -867,6 +867,22 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
abstract val message: String
|
abstract val message: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class NoExplicitVisibilityInApiMode : KtFirDiagnostic<KtDeclaration>() {
|
||||||
|
override val diagnosticClass get() = NoExplicitVisibilityInApiMode::class
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NoExplicitVisibilityInApiModeWarning : KtFirDiagnostic<KtDeclaration>() {
|
||||||
|
override val diagnosticClass get() = NoExplicitVisibilityInApiModeWarning::class
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NoExplicitReturnTypeInApiMode : KtFirDiagnostic<KtDeclaration>() {
|
||||||
|
override val diagnosticClass get() = NoExplicitReturnTypeInApiMode::class
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NoExplicitReturnTypeInApiModeWarning : KtFirDiagnostic<KtDeclaration>() {
|
||||||
|
override val diagnosticClass get() = NoExplicitReturnTypeInApiModeWarning::class
|
||||||
|
}
|
||||||
|
|
||||||
abstract class InlineClassNotTopLevel : KtFirDiagnostic<KtDeclaration>() {
|
abstract class InlineClassNotTopLevel : KtFirDiagnostic<KtDeclaration>() {
|
||||||
override val diagnosticClass get() = InlineClassNotTopLevel::class
|
override val diagnosticClass get() = InlineClassNotTopLevel::class
|
||||||
}
|
}
|
||||||
|
|||||||
+20
@@ -1036,6 +1036,26 @@ internal class InapplicableOperatorModifierImpl(
|
|||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtFirDiagnostic.InapplicableOperatorModifier(), KtAbstractFirDiagnostic<PsiElement>
|
) : KtFirDiagnostic.InapplicableOperatorModifier(), KtAbstractFirDiagnostic<PsiElement>
|
||||||
|
|
||||||
|
internal class NoExplicitVisibilityInApiModeImpl(
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.NoExplicitVisibilityInApiMode(), KtAbstractFirDiagnostic<KtDeclaration>
|
||||||
|
|
||||||
|
internal class NoExplicitVisibilityInApiModeWarningImpl(
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.NoExplicitVisibilityInApiModeWarning(), KtAbstractFirDiagnostic<KtDeclaration>
|
||||||
|
|
||||||
|
internal class NoExplicitReturnTypeInApiModeImpl(
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.NoExplicitReturnTypeInApiMode(), KtAbstractFirDiagnostic<KtDeclaration>
|
||||||
|
|
||||||
|
internal class NoExplicitReturnTypeInApiModeWarningImpl(
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.NoExplicitReturnTypeInApiModeWarning(), KtAbstractFirDiagnostic<KtDeclaration>
|
||||||
|
|
||||||
internal class InlineClassNotTopLevelImpl(
|
internal class InlineClassNotTopLevelImpl(
|
||||||
override val firDiagnostic: FirPsiDiagnostic,
|
override val firDiagnostic: FirPsiDiagnostic,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
|
|||||||
+6
@@ -381,6 +381,12 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
val INAPPLICABLE_OPERATOR_MODIFIER by error<PsiElement>(PositioningStrategy.OPERATOR_MODIFIER) {
|
val INAPPLICABLE_OPERATOR_MODIFIER by error<PsiElement>(PositioningStrategy.OPERATOR_MODIFIER) {
|
||||||
parameter<String>("message")
|
parameter<String>("message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val NO_EXPLICIT_VISIBILITY_IN_API_MODE by error<KtDeclaration>(PositioningStrategy.DECLARATION_START_TO_NAME)
|
||||||
|
val NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING by warning<KtDeclaration>(PositioningStrategy.DECLARATION_START_TO_NAME)
|
||||||
|
|
||||||
|
val NO_EXPLICIT_RETURN_TYPE_IN_API_MODE by error<KtDeclaration>(PositioningStrategy.DECLARATION_NAME)
|
||||||
|
val NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING by warning<KtDeclaration>(PositioningStrategy.DECLARATION_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
val INLINE_CLASSES by object : DiagnosticGroup("Inline classes") {
|
val INLINE_CLASSES by object : DiagnosticGroup("Inline classes") {
|
||||||
|
|||||||
+2
-1
@@ -108,8 +108,9 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
|||||||
ENUM_MODIFIER,
|
ENUM_MODIFIER,
|
||||||
FIELD_KEYWORD,
|
FIELD_KEYWORD,
|
||||||
TAILREC_MODIFIER,
|
TAILREC_MODIFIER,
|
||||||
IMPORT_ALIAS,
|
|
||||||
PROPERTY_DELEGATE,
|
PROPERTY_DELEGATE,
|
||||||
|
IMPORT_ALIAS,
|
||||||
|
DECLARATION_START_TO_NAME,
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -284,6 +284,10 @@ object FirErrors {
|
|||||||
val WRONG_MODIFIER_CONTAINING_DECLARATION by error2<PsiElement, KtModifierKeywordToken, String>()
|
val WRONG_MODIFIER_CONTAINING_DECLARATION by error2<PsiElement, KtModifierKeywordToken, String>()
|
||||||
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning2<PsiElement, KtModifierKeywordToken, String>()
|
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning2<PsiElement, KtModifierKeywordToken, String>()
|
||||||
val INAPPLICABLE_OPERATOR_MODIFIER by error1<PsiElement, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER)
|
val INAPPLICABLE_OPERATOR_MODIFIER by error1<PsiElement, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER)
|
||||||
|
val NO_EXPLICIT_VISIBILITY_IN_API_MODE by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_START_TO_NAME)
|
||||||
|
val NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING by warning0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_START_TO_NAME)
|
||||||
|
val NO_EXPLICIT_RETURN_TYPE_IN_API_MODE by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||||
|
val NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING by warning0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||||
|
|
||||||
// Inline classes
|
// Inline classes
|
||||||
val INLINE_CLASS_NOT_TOP_LEVEL by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
|
val INLINE_CLASS_NOT_TOP_LEVEL by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
|
||||||
|
|||||||
+1
@@ -29,6 +29,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
|||||||
FirExpectActualDeclarationChecker,
|
FirExpectActualDeclarationChecker,
|
||||||
FirInvalidAndDangerousCharactersChecker,
|
FirInvalidAndDangerousCharactersChecker,
|
||||||
FirAmbiguousAnonymousTypeChecker,
|
FirAmbiguousAnonymousTypeChecker,
|
||||||
|
FirExplicitApiDeclarationChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
override val functionCheckers: Set<FirFunctionChecker>
|
override val functionCheckers: Set<FirFunctionChecker>
|
||||||
|
|||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.analysis.checkers.syntax
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
|
import org.jetbrains.kotlin.config.AnalysisFlags
|
||||||
|
import org.jetbrains.kotlin.config.ExplicitApiMode
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.isLocalMember
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.isData
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
|
||||||
|
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.publishedApiEffectiveVisibility
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
|
||||||
|
object FirExplicitApiDeclarationChecker : FirDeclarationSyntaxChecker<FirDeclaration, KtDeclaration>() {
|
||||||
|
private val codeFragmentTypes =
|
||||||
|
setOf(KtNodeTypes.BLOCK_CODE_FRAGMENT, KtNodeTypes.EXPRESSION_CODE_FRAGMENT, KtNodeTypes.TYPE_CODE_FRAGMENT)
|
||||||
|
|
||||||
|
override fun checkLightTree(element: FirDeclaration, source: FirSourceElement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
if ((source.kind !is FirRealSourceElementKind && source.kind != FirFakeSourceElementKind.PropertyFromParameter) ||
|
||||||
|
element !is FirMemberDeclaration
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val state = context.session.languageVersionSettings.getFlag(AnalysisFlags.explicitApiMode)
|
||||||
|
if (state == ExplicitApiMode.DISABLED) return
|
||||||
|
// Enum entries do not have visibilities
|
||||||
|
if (element is FirEnumEntry) return
|
||||||
|
if (!element.effectiveVisibility.publicApi && element.publishedApiEffectiveVisibility == null) return
|
||||||
|
|
||||||
|
checkVisibilityModifier(state, element, source, context, reporter)
|
||||||
|
checkExplicitReturnType(state, element, source, context, reporter)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkVisibilityModifier(
|
||||||
|
state: ExplicitApiMode,
|
||||||
|
declaration: FirMemberDeclaration,
|
||||||
|
source: FirSourceElement,
|
||||||
|
context: CheckerContext,
|
||||||
|
reporter: DiagnosticReporter
|
||||||
|
) {
|
||||||
|
val visibilityModifier = source.getChild(KtNodeTypes.MODIFIER_LIST)?.getChild(KtTokens.VISIBILITY_MODIFIERS)
|
||||||
|
if (visibilityModifier != null) return
|
||||||
|
|
||||||
|
if (explicitVisibilityIsNotRequired(declaration, context)) return
|
||||||
|
val factory = if (state == ExplicitApiMode.STRICT)
|
||||||
|
FirErrors.NO_EXPLICIT_VISIBILITY_IN_API_MODE
|
||||||
|
else
|
||||||
|
FirErrors.NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING
|
||||||
|
reporter.reportOn(source, factory, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exclusion list:
|
||||||
|
* 1. Primary constructors of public API classes
|
||||||
|
* 2. Properties of data classes in public API
|
||||||
|
* 3. Overrides of public API. Effectively, this means 'no report on overrides at all'
|
||||||
|
* 4. Getters and setters (because getters can't change visibility and setter-only explicit visibility looks ugly)
|
||||||
|
* 5. Properties of annotations in public API
|
||||||
|
* 6. Value parameter declaration
|
||||||
|
*
|
||||||
|
* TODO: Do we need something like @PublicApiFile to disable (or invert) this inspection per-file?
|
||||||
|
*/
|
||||||
|
private fun explicitVisibilityIsNotRequired(declaration: FirMemberDeclaration, context: CheckerContext): Boolean {
|
||||||
|
return when (declaration) {
|
||||||
|
// 1,
|
||||||
|
is FirPrimaryConstructor,
|
||||||
|
// 4
|
||||||
|
is FirPropertyAccessor,
|
||||||
|
// 6
|
||||||
|
is FirValueParameter -> true
|
||||||
|
is FirCallableDeclaration -> {
|
||||||
|
val containingClass = context.containingDeclarations.lastOrNull() as? FirRegularClass
|
||||||
|
// 2, 5
|
||||||
|
if (declaration is FirProperty &&
|
||||||
|
containingClass != null &&
|
||||||
|
(containingClass.isData || containingClass.classKind == ClassKind.ANNOTATION_CLASS)
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3
|
||||||
|
declaration.isOverride
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkExplicitReturnType(
|
||||||
|
state: ExplicitApiMode,
|
||||||
|
declaration: FirMemberDeclaration,
|
||||||
|
source: FirSourceElement,
|
||||||
|
context: CheckerContext,
|
||||||
|
reporter: DiagnosticReporter
|
||||||
|
) {
|
||||||
|
if (declaration !is FirCallableDeclaration) return
|
||||||
|
if (!returnTypeCheckIsApplicable(source, context)) return
|
||||||
|
|
||||||
|
val shouldReport = returnTypeRequired(declaration, context)
|
||||||
|
if (shouldReport) {
|
||||||
|
val factory =
|
||||||
|
if (state == ExplicitApiMode.STRICT)
|
||||||
|
FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE
|
||||||
|
else
|
||||||
|
FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING
|
||||||
|
reporter.reportOn(source, factory, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun returnTypeCheckIsApplicable(source: FirSourceElement, context: CheckerContext): Boolean {
|
||||||
|
// Note that by default getChild uses `depth = -1`, which would find all descendents.
|
||||||
|
if (source.getChild(KtNodeTypes.TYPE_REFERENCE, depth = 1) != null) return false
|
||||||
|
// Do not check if the containing file is not a physical file.
|
||||||
|
val containingFile = context.containingDeclarations.first()
|
||||||
|
if (containingFile.source?.elementType in codeFragmentTypes) return false
|
||||||
|
|
||||||
|
return when (source.elementType) {
|
||||||
|
// Only require return type if the function is defined via `=`. If it has a block body or is abstract, we don't require return
|
||||||
|
// type because not declaring means it returns `Unit`.
|
||||||
|
KtNodeTypes.FUN -> source.getChild(KtTokens.EQ, depth = 1) != null
|
||||||
|
KtNodeTypes.PROPERTY -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun returnTypeRequired(declaration: FirCallableDeclaration, context: CheckerContext): Boolean {
|
||||||
|
// If current declaration is local or it's a member in a local declaration (local class, etc), then we do not require return type.
|
||||||
|
return !declaration.isLocalMember && context.containingDeclarations.lastOrNull()?.isLocalMember != true
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -308,6 +308,10 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_CLASS_M
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_FOR_EXPECT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_FOR_EXPECT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_COMPANION_OBJECT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_COMPANION_OBJECT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_EXPLICIT_VISIBILITY_IN_API_MODE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_GET_METHOD
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_GET_METHOD
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RECEIVER_ALLOWED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RECEIVER_ALLOWED
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY
|
||||||
@@ -799,6 +803,11 @@ class FirDefaultErrorMessages {
|
|||||||
map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING)
|
map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING)
|
||||||
map.put(DEPRECATED_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is deprecated for ''{1}''", TO_STRING, STRING)
|
map.put(DEPRECATED_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is deprecated for ''{1}''", TO_STRING, STRING)
|
||||||
map.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, STRING)
|
map.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, STRING)
|
||||||
|
map.put(NO_EXPLICIT_VISIBILITY_IN_API_MODE, "Visibility must be specified in explicit API mode");
|
||||||
|
map.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE, "Return type must be specified in explicit API mode");
|
||||||
|
map.put(NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING, "Visibility must be specified in explicit API mode");
|
||||||
|
map.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING, "Return type must be specified in explicit API mode");
|
||||||
|
|
||||||
map.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", TO_STRING, TO_STRING)
|
map.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", TO_STRING, TO_STRING)
|
||||||
map.put(REDUNDANT_OPEN_IN_INTERFACE, "Modifier 'open' is redundant for abstract interface members")
|
map.put(REDUNDANT_OPEN_IN_INTERFACE, "Modifier 'open' is redundant for abstract interface members")
|
||||||
map.put(WRONG_MODIFIER_TARGET, "Modifier ''{0}'' is not applicable to ''{1}''", TO_STRING, STRING)
|
map.put(WRONG_MODIFIER_TARGET, "Modifier ''{0}'' is not applicable to ''{1}''", TO_STRING, STRING)
|
||||||
|
|||||||
+43
@@ -148,6 +148,43 @@ object LightTreePositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val DECLARATION_START_TO_NAME: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||||
|
|
||||||
|
private fun FlyweightCapableTreeStructure<LighterASTNode>.firstNonCommentNonAnnotationLeaf(node: LighterASTNode): LighterASTNode? {
|
||||||
|
val childrenArray = getChildrenArray(node).filterNotNull()
|
||||||
|
// this is leaf
|
||||||
|
if (childrenArray.isEmpty()) return node
|
||||||
|
for (child in childrenArray) {
|
||||||
|
val childTokenType = child.tokenType ?: return null
|
||||||
|
if (childTokenType in KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET || childTokenType == KtNodeTypes.ANNOTATION_ENTRY) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return firstNonCommentNonAnnotationLeaf(child) ?: continue
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mark(
|
||||||
|
node: LighterASTNode,
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||||
|
): List<TextRange> {
|
||||||
|
val startNode = tree.firstNonCommentNonAnnotationLeaf(node) ?: node
|
||||||
|
val nameIdentifier = tree.nameIdentifier(node)
|
||||||
|
return if (nameIdentifier != null) {
|
||||||
|
markRange(startNode, nameIdentifier, startOffset, endOffset, tree, node)
|
||||||
|
} else {
|
||||||
|
val endNode = when (node.tokenType) {
|
||||||
|
KtNodeTypes.PRIMARY_CONSTRUCTOR, KtNodeTypes.SECONDARY_CONSTRUCTOR -> tree.constructorKeyword(node)
|
||||||
|
KtNodeTypes.OBJECT_DECLARATION -> tree.objectKeyword(node)
|
||||||
|
else -> return DEFAULT.mark(node, startOffset, endOffset, tree)
|
||||||
|
}
|
||||||
|
markRange(startNode, endNode ?: node, startOffset, endOffset, tree, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val DECLARATION_NAME: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
val DECLARATION_NAME: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||||
override fun mark(
|
override fun mark(
|
||||||
node: LighterASTNode,
|
node: LighterASTNode,
|
||||||
@@ -1083,6 +1120,12 @@ fun LighterASTNode.isExpression(): Boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FlyweightCapableTreeStructure<LighterASTNode>.getChildrenArray(node: LighterASTNode): Array<LighterASTNode?> {
|
||||||
|
val childrenRef = Ref<Array<LighterASTNode?>>()
|
||||||
|
getChildren(node, childrenRef)
|
||||||
|
return childrenRef.get() ?: emptyArray()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for diagnostics
|
* @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for diagnostics
|
||||||
* on super and unresolved references. For example, with the following, only the part inside the parentheses should be highlighted.
|
* on super and unresolved references. For example, with the following, only the part inside the parentheses should be highlighted.
|
||||||
|
|||||||
+8
-3
@@ -330,13 +330,18 @@ object SourceElementPositioningStrategies {
|
|||||||
PositioningStrategies.TAILREC_MODIFIER
|
PositioningStrategies.TAILREC_MODIFIER
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val PROPERTY_DELEGATE = SourceElementPositioningStrategy(
|
||||||
|
LightTreePositioningStrategies.PROPERTY_DELEGATE,
|
||||||
|
PositioningStrategies.PROPERTY_DELEGATE
|
||||||
|
)
|
||||||
|
|
||||||
val IMPORT_ALIAS = SourceElementPositioningStrategy(
|
val IMPORT_ALIAS = SourceElementPositioningStrategy(
|
||||||
LightTreePositioningStrategies.IMPORT_ALIAS,
|
LightTreePositioningStrategies.IMPORT_ALIAS,
|
||||||
PositioningStrategies.IMPORT_ALIAS
|
PositioningStrategies.IMPORT_ALIAS
|
||||||
)
|
)
|
||||||
|
|
||||||
val PROPERTY_DELEGATE = SourceElementPositioningStrategy(
|
val DECLARATION_START_TO_NAME = SourceElementPositioningStrategy(
|
||||||
LightTreePositioningStrategies.PROPERTY_DELEGATE,
|
LightTreePositioningStrategies.DECLARATION_START_TO_NAME,
|
||||||
PositioningStrategies.PROPERTY_DELEGATE
|
PositioningStrategies.DECLARATION_START_TO_NAME
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
annotation class A
|
|
||||||
|
|
||||||
@Target(
|
|
||||||
AnnotationTarget.CLASS,
|
|
||||||
AnnotationTarget.PROPERTY,
|
|
||||||
AnnotationTarget.CONSTRUCTOR,
|
|
||||||
AnnotationTarget.FUNCTION
|
|
||||||
)
|
|
||||||
public annotation class B
|
|
||||||
|
|
||||||
annotation class C(val a: String)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Foo1 KDoc
|
|
||||||
*/
|
|
||||||
@B
|
|
||||||
class Foo1() {}
|
|
||||||
|
|
||||||
public class Foo2() {
|
|
||||||
/**
|
|
||||||
* KDoc for methodWithAnnotations
|
|
||||||
*/
|
|
||||||
@B
|
|
||||||
fun methodWithAnnotations() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Property KDoc
|
|
||||||
*/
|
|
||||||
@B
|
|
||||||
var simple: Int = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
public open class ClassWithOpen {
|
|
||||||
/**
|
|
||||||
* constructor KDoc
|
|
||||||
*/
|
|
||||||
@B
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KDoc for openAnnotatedMethod
|
|
||||||
*/
|
|
||||||
@B
|
|
||||||
open fun openAnnotatedMethod() {}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>annotation class A<!>
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>annotation class A<!>
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KDoc for Foo1
|
|
||||||
*/
|
|
||||||
class Foo1() {}
|
|
||||||
|
|
||||||
public class Foo2() {
|
|
||||||
/**
|
|
||||||
* KDoc for method
|
|
||||||
*/
|
|
||||||
fun method() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KDoc for method2
|
|
||||||
*/
|
|
||||||
public fun method2() {}
|
|
||||||
private fun method3() {}
|
|
||||||
|
|
||||||
fun implicit() = 10
|
|
||||||
public fun implicit2() = 10
|
|
||||||
public fun implicit3(): Int = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
public open class ClassWithOpen() {
|
|
||||||
/**
|
|
||||||
* KDoc for method
|
|
||||||
*/
|
|
||||||
fun method() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KDoc for openMethod
|
|
||||||
*/
|
|
||||||
open fun openMethod() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public data class FooData(val i: Int, val s: String)
|
|
||||||
|
|
||||||
data class FooData2(val i: Int, val s: String)
|
|
||||||
|
|
||||||
public class WithNested {
|
|
||||||
class Nested {}
|
|
||||||
inner class Inner {}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Foo { A, B }
|
|
||||||
public enum class Bar { A, B }
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
-20
@@ -1,20 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
public class Bar {
|
|
||||||
companion object {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Bar2 {
|
|
||||||
companion object MyCompanion {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Bar3 {
|
|
||||||
/**
|
|
||||||
* Nested object KDoc
|
|
||||||
*/
|
|
||||||
object NestedObject {}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class FooData2(val i: Int, val s: String) {
|
|
||||||
object NestedObject {}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
public class Bar {
|
public class Bar {
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
public class Foo1 () {}
|
|
||||||
public class Foo2 constructor() {}
|
|
||||||
public class Foo3 public constructor() {}
|
|
||||||
public class Foo4 private constructor() {}
|
|
||||||
|
|
||||||
public class Foo5 {
|
|
||||||
/**
|
|
||||||
* constructor KDoc
|
|
||||||
*/
|
|
||||||
constructor() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Foo6 {
|
|
||||||
public constructor() {}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
public class Foo1 () {}
|
public class Foo1 () {}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -EXPERIMENTAL_FEATURE_WARNING
|
|
||||||
// !LANGUAGE: -JvmInlineValueClasses
|
|
||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
inline class Value1(val inner: Int)
|
|
||||||
public inline class Value2(val inner: Int)
|
|
||||||
inline class Value3(public val inner: Int)
|
|
||||||
public inline class Value4(public val inner: Int)
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -EXPERIMENTAL_FEATURE_WARNING
|
// !DIAGNOSTICS: -EXPERIMENTAL_FEATURE_WARNING
|
||||||
// !LANGUAGE: -JvmInlineValueClasses
|
// !LANGUAGE: -JvmInlineValueClasses
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
interface I1 {
|
|
||||||
fun i()
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface I2 {
|
|
||||||
fun i()
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface I3 {
|
|
||||||
public fun i()
|
|
||||||
public val v: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface I4 {
|
|
||||||
public fun i(): Int
|
|
||||||
public val v: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Impl: I3 {
|
|
||||||
override fun i() {}
|
|
||||||
override val v: Int
|
|
||||||
get() = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Impl2: I4 {
|
|
||||||
override fun i() = 10
|
|
||||||
override val v = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PrivateImpl: I4 {
|
|
||||||
override fun i() = 10
|
|
||||||
override val v = 10
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>interface I1<!> {
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>interface I1<!> {
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
public class Foo(val bar: Int, private var bar2: String, internal var bar3: Long, public var bar4: Int) {
|
|
||||||
/**
|
|
||||||
* Property KDoc
|
|
||||||
*/
|
|
||||||
var simple: Int = 10
|
|
||||||
public var simple2: Int = 10
|
|
||||||
|
|
||||||
val withGetter: Int
|
|
||||||
get() = 10
|
|
||||||
|
|
||||||
public val withGetter2: Int
|
|
||||||
get() = 10
|
|
||||||
|
|
||||||
var getterAndSetter: Int = 10
|
|
||||||
get() = field
|
|
||||||
set(v) { field = v }
|
|
||||||
|
|
||||||
public var getterAndSetter2: Int = 10
|
|
||||||
get() = field
|
|
||||||
set(v) { field = v }
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
public class Foo(<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>val bar<!>: Int, private var bar2: String, internal var bar3: Long, public var bar4: Int) {
|
public class Foo(<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>val bar<!>: Int, private var bar2: String, internal var bar3: Long, public var bar4: Int) {
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
public class A {
|
|
||||||
@PublishedApi
|
|
||||||
internal fun foo() = 1
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* foo KDoc
|
|
||||||
*/
|
|
||||||
fun foo() {}
|
|
||||||
|
|
||||||
public fun foo2() {}
|
|
||||||
|
|
||||||
fun bar() = 10
|
|
||||||
public fun bar2() = 10
|
|
||||||
public fun bar3(): Int = 10
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+8
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.test.runners
|
package org.jetbrains.kotlin.test.runners
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.ExplicitApiMode
|
||||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||||
import org.jetbrains.kotlin.test.Constructor
|
import org.jetbrains.kotlin.test.Constructor
|
||||||
import org.jetbrains.kotlin.test.TestJdkKind
|
import org.jetbrains.kotlin.test.TestJdkKind
|
||||||
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.WITH_EXTEND
|
|||||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JDK_KIND
|
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JDK_KIND
|
||||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_REFLECT
|
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_REFLECT
|
||||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_STDLIB
|
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_STDLIB
|
||||||
|
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
|
||||||
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.LANGUAGE
|
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives.LANGUAGE
|
||||||
import org.jetbrains.kotlin.test.frontend.fir.FirFailingTestSuppressor
|
import org.jetbrains.kotlin.test.frontend.fir.FirFailingTestSuppressor
|
||||||
import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
|
import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
|
||||||
@@ -108,6 +110,12 @@ fun TestConfigurationBuilder.baseFirDiagnosticTestConfiguration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forTestsMatching("compiler/testData/diagnostics/tests/testsWithExplicitApi/*") {
|
||||||
|
defaultDirectives {
|
||||||
|
LanguageSettingsDirectives.EXPLICIT_API_MODE with ExplicitApiMode.STRICT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
forTestsMatching(
|
forTestsMatching(
|
||||||
"compiler/fir/analysis-tests/testData/resolve/extendedCheckers/*" or
|
"compiler/fir/analysis-tests/testData/resolve/extendedCheckers/*" or
|
||||||
"compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/*"
|
"compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/*"
|
||||||
|
|||||||
Reference in New Issue
Block a user