Change NO_EXPLICIT_VISIBILITY_IN_API_MODE diagnostic range to 'declaration modifiers + name'.

Motivation: missing visibility modifier is an error in visibility modifiers list, so we should highlight this list.
Including a name in the range is convenient for using alt+enter (you don't have to move cursor from name to fun/class/val keyword)

 Also change NO_EXPLICIT_RETURN_TYPE_IN_API_MODE diagnostic range to 'declaration name' to match corresponding IDE inspection.

Fix stylistic problems and typos after review
This commit is contained in:
Leonid Startsev
2019-10-30 16:43:45 +03:00
parent 24688f3503
commit 3b100e57f2
24 changed files with 103 additions and 301 deletions
@@ -207,10 +207,10 @@ public interface Errors {
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken> DEPRECATED_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> REDUNDANT_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
DiagnosticFactory1<KtDeclaration, DeclarationDescriptor> NO_EXPLICIT_VISIBILITY_IN_API_MODE = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtDeclaration> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory1<KtDeclaration, DeclarationDescriptor> NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING = DiagnosticFactory1.create(WARNING, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtDeclaration> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtDeclaration> NO_EXPLICIT_VISIBILITY_IN_API_MODE = DiagnosticFactory0.create(ERROR, DECLARATION_MODIFIERS_AND_NAME);
DiagnosticFactory0<KtNamedDeclaration> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE = DiagnosticFactory0.create(ERROR, DECLARATION_NAME);
DiagnosticFactory0<KtDeclaration> NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING = DiagnosticFactory0.create(WARNING, DECLARATION_MODIFIERS_AND_NAME);
DiagnosticFactory0<KtNamedDeclaration> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING = DiagnosticFactory0.create(WARNING, DECLARATION_NAME);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> WRONG_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(WARNING);
DiagnosticFactory1<PsiElement, KtModifierKeywordToken> ILLEGAL_INLINE_PARAMETER_MODIFIER = DiagnosticFactory1.create(ERROR);
@@ -187,6 +187,26 @@ object PositioningStrategies {
}
}
@JvmField
val DECLARATION_MODIFIERS_AND_NAME: PositioningStrategy<KtDeclaration> = object : DeclarationHeader<KtDeclaration>() {
override fun mark(element: KtDeclaration): List<TextRange> {
val startElement = element.firstChild
val nameIdentifier = (element as? KtNamedDeclaration)?.nameIdentifier
return if (nameIdentifier != null) {
markRange(startElement, nameIdentifier)
} else when (element) {
// companion object/constructors without name
is KtConstructor<*> -> {
markRange(startElement, element.getConstructorKeyword() ?: element)
}
is KtObjectDeclaration -> {
markRange(startElement, element.getObjectKeyword() ?: element)
}
else -> DEFAULT.mark(element)
}
}
}
@JvmField
val DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
override fun mark(element: KtNamedDeclaration): List<TextRange> {
@@ -195,7 +215,7 @@ object PositioningStrategies {
if (element is KtClassOrObject) {
val startElement =
element.getModifierList()?.getModifier(KtTokens.ENUM_KEYWORD)
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
?: element
return markRange(startElement, nameIdentifier)
@@ -119,10 +119,10 @@ public class DefaultErrorMessages {
MAP.put(DEPRECATED_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is deprecated for ''{1}''", TO_STRING, TO_STRING);
MAP.put(DEPRECATED_MODIFIER, "Modifier ''{0}'' is deprecated, use ''{1}'' instead", TO_STRING, TO_STRING);
MAP.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, TO_STRING);
MAP.put(NO_EXPLICIT_VISIBILITY_IN_API_MODE, "Declaration ''{0}'' is effectively public API and API mode is on, but no visibility is specified", NAME);
MAP.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE, "This declaration is effectively public API and API mode is on, but no explicit return type is specified");
MAP.put(NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING, "Declaration ''{0}'' is effectively public API and API mode is on, but no visibility is specified", NAME);
MAP.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING, "This declaration is effectively public API and API mode is on, but no explicit return type is specified");
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(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(ILLEGAL_INLINE_PARAMETER_MODIFIER, "Modifier ''{0}'' is allowed only for function parameters of an inline function", TO_STRING);
@@ -7,11 +7,9 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.ExplicitApiMode
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
@@ -19,11 +17,11 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi
class ExplicitApiDeclarationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val state = isEnabled(context.languageVersionSettings)
val state = context.languageVersionSettings.getFlag(AnalysisFlags.explicitApiMode)
if (state == ExplicitApiMode.DISABLED) return
val isApi = (descriptor as? DeclarationDescriptorWithVisibility)?.isEffectivelyPublicApi ?: return
if (!isApi) return
if (descriptor !is DeclarationDescriptorWithVisibility) return
if (!descriptor.isEffectivelyPublicApi) return
checkVisibilityModifier(state, declaration, descriptor, context)
checkExplicitReturnType(state, declaration, descriptor, context)
@@ -35,16 +33,16 @@ class ExplicitApiDeclarationChecker : DeclarationChecker {
descriptor: DeclarationDescriptorWithVisibility,
context: DeclarationCheckerContext
) {
val modifier = declaration.visibilityModifier()?.node?.elementType as? KtModifierKeywordToken
val modifier = declaration.visibilityModifier()
if (modifier != null) return
if (excludeForDiagnostic(descriptor)) return
val diagnostic =
if (state == ExplicitApiMode.STRICT)
Errors.NO_EXPLICIT_VISIBILITY_IN_API_MODE.on(declaration, descriptor)
Errors.NO_EXPLICIT_VISIBILITY_IN_API_MODE
else
Errors.NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING.on(declaration, descriptor)
context.trace.reportDiagnosticOnce(diagnostic)
Errors.NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING
context.trace.reportDiagnosticOnce(diagnostic.on(declaration))
}
private fun checkExplicitReturnType(
@@ -65,11 +63,10 @@ class ExplicitApiDeclarationChecker : DeclarationChecker {
if (shouldReport) {
val diagnostic =
if (state == ExplicitApiMode.STRICT)
Errors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE.on(declaration)
Errors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE
else
Errors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING
.on(declaration)
context.trace.reportDiagnosticOnce(diagnostic)
context.trace.reportDiagnosticOnce(diagnostic.on(declaration))
}
}
@@ -91,29 +88,23 @@ class ExplicitApiDeclarationChecker : DeclarationChecker {
}
companion object {
fun isEnabled(settings: LanguageVersionSettings): ExplicitApiMode {
return settings.getFlag(AnalysisFlags.explicitApiMode)
}
fun returnTypeRequired(
element: KtCallableDeclaration,
descriptor: DeclarationDescriptor?,
checkForPublicApi: Boolean,
checkForInternal: Boolean,
checkForPrivate: Boolean
): Boolean =
element.containingClassOrObject?.isLocal != true &&
when (element) {
is KtFunction -> !element.isLocal
is KtProperty -> !element.isLocal
else -> false
} && run {
val callableMemberDescriptor = descriptor as? CallableMemberDescriptor
): Boolean {
if (element.containingClassOrObject?.isLocal == true) return false
if (element is KtFunction && element.isLocal) return false
if (element is KtProperty && element.isLocal) return false
val visibility = callableMemberDescriptor?.effectiveVisibility()?.toVisibility()
(checkForPublicApi && visibility?.isPublicAPI == true) || (checkForInternal && visibility == Visibilities.INTERNAL) ||
(checkForPrivate && visibility == Visibilities.PRIVATE)
}
val callableMemberDescriptor = descriptor as? CallableMemberDescriptor
val visibility = callableMemberDescriptor?.effectiveVisibility()?.toVisibility()
return (checkForPublicApi && visibility?.isPublicAPI == true) || (checkForInternal && visibility == Visibilities.INTERNAL) ||
(checkForPrivate && visibility == Visibilities.PRIVATE)
}
fun returnTypeCheckIsApplicable(element: KtCallableDeclaration): Boolean {
if (element.containingFile is KtCodeFragment) return false