Deprecated reportFromPlugin way to report diagnostics from plugin
Originally reportFromPlugin method was introduced to address the problem with loading of DefaultErrorMessages.Extension vis ServiceLoader. For some cases this extension was not loaded by ServiceLoader because classes was loaded via different class loader, common scenario here is compiler plugins. Ideally we should load such extension point via getService approach, but unfortunately to do that we need project and DefaultErrorMessages.render is static method for now. Also with reportFromPlugin approach is a problem -- all diagnostics reported via this method has the same id: PLUGIN_[WARNING|ERROR|INFO] and it isn't possible to suppress only one particular diagnostic. To bypass this problem the new method initializeFactoryNamesAndDefaultErrorMessages was introduced. It basically store DiagnosticRenderer inside DiagnosticFactory. It is not ideal, because one DiagnosticFactory could have different renderers for different scenarios -- for compiler and for IDE, but I think that it is better than reportByPlugin approach.
This commit is contained in:
+10
-14
@@ -21,13 +21,11 @@ import com.intellij.psi.util.PsiTreeUtil
|
||||
import kotlinx.android.parcel.IgnoredOnParcel
|
||||
import kotlinx.android.parcel.TypeParceler
|
||||
import kotlinx.android.parcel.WriteWith
|
||||
import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid
|
||||
import org.jetbrains.kotlin.android.synthetic.diagnostic.ErrorsAndroid
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.diagnostics.reportFromPlugin
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
@@ -70,12 +68,11 @@ class ParcelableAnnotationChecker : CallChecker {
|
||||
|
||||
private fun checkIgnoredOnParcelUsage(annotationEntry: KtAnnotationEntry, context: CallCheckerContext, element: KtModifierListOwner) {
|
||||
if (element is KtParameter && PsiTreeUtil.getParentOfType(element, KtDeclaration::class.java) is KtPrimaryConstructor) {
|
||||
context.trace.reportFromPlugin(
|
||||
ErrorsAndroid.INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY.on(annotationEntry),
|
||||
DefaultErrorMessagesAndroid
|
||||
context.trace.report(
|
||||
ErrorsAndroid.INAPPLICABLE_IGNORED_ON_PARCEL_CONSTRUCTOR_PROPERTY.on(annotationEntry)
|
||||
)
|
||||
} else if (element !is KtProperty || PsiTreeUtil.getParentOfType(element, KtDeclaration::class.java) !is KtClass) {
|
||||
context.trace.reportFromPlugin(ErrorsAndroid.INAPPLICABLE_IGNORED_ON_PARCEL.on(annotationEntry), DefaultErrorMessagesAndroid)
|
||||
context.trace.report(ErrorsAndroid.INAPPLICABLE_IGNORED_ON_PARCEL.on(annotationEntry))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +92,7 @@ class ParcelableAnnotationChecker : CallChecker {
|
||||
|
||||
if (duplicatingAnnotationCount > 1) {
|
||||
val reportElement = annotationEntry.typeArguments.firstOrNull() ?: annotationEntry
|
||||
context.trace.reportFromPlugin(ErrorsAndroid.DUPLICATING_TYPE_PARCELERS.on(reportElement), DefaultErrorMessagesAndroid)
|
||||
context.trace.report(ErrorsAndroid.DUPLICATING_TYPE_PARCELERS.on(reportElement))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -115,8 +112,9 @@ class ParcelableAnnotationChecker : CallChecker {
|
||||
// We can ignore value arguments here cause @TypeParceler is a zero-parameter annotation
|
||||
if (containingClassDescriptor.annotations.any { it.type == thisAnnotationDescriptor.type }) {
|
||||
val reportElement = (annotationEntry.typeReference?.typeElement as? KtUserType)?.referenceExpression ?: annotationEntry
|
||||
context.trace.reportFromPlugin(
|
||||
ErrorsAndroid.REDUNDANT_TYPE_PARCELER.on(reportElement, containingClass), DefaultErrorMessagesAndroid)
|
||||
context.trace.report(
|
||||
ErrorsAndroid.REDUNDANT_TYPE_PARCELER.on(reportElement, containingClass)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +139,7 @@ class ParcelableAnnotationChecker : CallChecker {
|
||||
fun reportElement() = annotationEntry.typeArguments.singleOrNull() ?: annotationEntry
|
||||
|
||||
if (parcelerClass.kind != ClassKind.OBJECT) {
|
||||
context.trace.reportFromPlugin(ErrorsAndroid.PARCELER_SHOULD_BE_OBJECT.on(reportElement()), DefaultErrorMessagesAndroid)
|
||||
context.trace.report(ErrorsAndroid.PARCELER_SHOULD_BE_OBJECT.on(reportElement()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -150,8 +148,7 @@ class ParcelableAnnotationChecker : CallChecker {
|
||||
val expectedType = parcelerSuperType.arguments.singleOrNull()?.type ?: return
|
||||
|
||||
if (!actualType.isSubtypeOf(expectedType)) {
|
||||
context.trace.reportFromPlugin(ErrorsAndroid.PARCELER_TYPE_INCOMPATIBLE.on(reportElement(), expectedType, actualType),
|
||||
DefaultErrorMessagesAndroid)
|
||||
context.trace.report(ErrorsAndroid.PARCELER_TYPE_INCOMPATIBLE.on(reportElement(), expectedType, actualType))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +161,7 @@ class ParcelableAnnotationChecker : CallChecker {
|
||||
val containingClassDescriptor = context.trace[BindingContext.CLASS, containingClass]
|
||||
if (containingClassDescriptor != null && !containingClassDescriptor.isParcelize) {
|
||||
val reportElement = (annotationEntry.typeReference?.typeElement as? KtUserType)?.referenceExpression ?: annotationEntry
|
||||
context.trace.reportFromPlugin(ErrorsAndroid.CLASS_SHOULD_BE_PARCELIZE.on(reportElement, containingClass),
|
||||
DefaultErrorMessagesAndroid)
|
||||
context.trace.report(ErrorsAndroid.CLASS_SHOULD_BE_PARCELIZE.on(reportElement, containingClass))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-34
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.android.parcel
|
||||
import kotlinx.android.parcel.IgnoredOnParcel
|
||||
import org.jetbrains.kotlin.android.parcel.serializers.ParcelSerializer
|
||||
import org.jetbrains.kotlin.android.parcel.serializers.isParcelable
|
||||
import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid
|
||||
import org.jetbrains.kotlin.android.synthetic.diagnostic.ErrorsAndroid
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
||||
import org.jetbrains.kotlin.codegen.FrameMap
|
||||
@@ -20,7 +19,6 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.reportFromPlugin
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -76,9 +74,8 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
if (method.isWriteToParcel() && declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
|
||||
val reportElement =
|
||||
declaration.modifierList?.getModifier(KtTokens.OVERRIDE_KEYWORD) ?: declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED.on(reportElement),
|
||||
DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED.on(reportElement)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -101,7 +98,7 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
&& !hasIgnoredOnParcel()
|
||||
) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(ErrorsAndroid.PROPERTY_WONT_BE_SERIALIZED.on(reportElement), DefaultErrorMessagesAndroid)
|
||||
diagnosticHolder.report(ErrorsAndroid.PROPERTY_WONT_BE_SERIALIZED.on(reportElement))
|
||||
}
|
||||
|
||||
// @JvmName is not applicable to property so we can check just the descriptor name
|
||||
@@ -109,9 +106,8 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
val outerClass = containingClass.containingDeclaration as? ClassDescriptor
|
||||
if (outerClass != null && outerClass.isParcelize) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.CREATOR_DEFINITION_IS_NOT_ALLOWED.on(reportElement),
|
||||
DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.CREATOR_DEFINITION_IS_NOT_ALLOWED.on(reportElement)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -127,22 +123,21 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
if (!descriptor.isParcelize) return
|
||||
|
||||
if (declaration !is KtClassOrObject) {
|
||||
diagnosticHolder.reportFromPlugin(ErrorsAndroid.PARCELABLE_SHOULD_BE_CLASS.on(declaration), DefaultErrorMessagesAndroid)
|
||||
diagnosticHolder.report(ErrorsAndroid.PARCELABLE_SHOULD_BE_CLASS.on(declaration))
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration is KtClass && (declaration.isAnnotation() || declaration.isInterface())) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(ErrorsAndroid.PARCELABLE_SHOULD_BE_CLASS.on(reportElement), DefaultErrorMessagesAndroid)
|
||||
diagnosticHolder.report(ErrorsAndroid.PARCELABLE_SHOULD_BE_CLASS.on(reportElement))
|
||||
return
|
||||
}
|
||||
|
||||
for (companion in declaration.companionObjects) {
|
||||
if (companion.name == "CREATOR") {
|
||||
val reportElement = companion.nameIdentifier ?: companion
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.CREATOR_DEFINITION_IS_NOT_ALLOWED.on(reportElement),
|
||||
DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.CREATOR_DEFINITION_IS_NOT_ALLOWED.on(reportElement)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -150,26 +145,25 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
val sealedOrAbstract =
|
||||
declaration.modifierList?.let { it.getModifier(KtTokens.ABSTRACT_KEYWORD) ?: it.getModifier(KtTokens.SEALED_KEYWORD) }
|
||||
if (sealedOrAbstract != null) {
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.PARCELABLE_SHOULD_BE_INSTANTIABLE.on(sealedOrAbstract),
|
||||
DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.PARCELABLE_SHOULD_BE_INSTANTIABLE.on(sealedOrAbstract)
|
||||
)
|
||||
}
|
||||
|
||||
if (declaration is KtClass && declaration.isInner()) {
|
||||
val reportElement = declaration.modifierList?.getModifier(KtTokens.INNER_KEYWORD) ?: declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(ErrorsAndroid.PARCELABLE_CANT_BE_INNER_CLASS.on(reportElement), DefaultErrorMessagesAndroid)
|
||||
diagnosticHolder.report(ErrorsAndroid.PARCELABLE_CANT_BE_INNER_CLASS.on(reportElement))
|
||||
}
|
||||
|
||||
if (declaration.isLocal) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(ErrorsAndroid.PARCELABLE_CANT_BE_LOCAL_CLASS.on(reportElement), DefaultErrorMessagesAndroid)
|
||||
diagnosticHolder.report(ErrorsAndroid.PARCELABLE_CANT_BE_LOCAL_CLASS.on(reportElement))
|
||||
}
|
||||
|
||||
val superTypes = TypeUtils.getAllSupertypes(descriptor.defaultType)
|
||||
if (superTypes.none { it.constructor.declarationDescriptor?.fqNameSafe == ANDROID_PARCELABLE_CLASS_FQNAME }) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(ErrorsAndroid.NO_PARCELABLE_SUPERTYPE.on(reportElement), DefaultErrorMessagesAndroid)
|
||||
diagnosticHolder.report(ErrorsAndroid.NO_PARCELABLE_SUPERTYPE.on(reportElement))
|
||||
}
|
||||
|
||||
for (supertypeEntry in declaration.superTypeListEntries) {
|
||||
@@ -178,9 +172,8 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
val type = bindingContext[BindingContext.TYPE, supertypeEntry.typeReference] ?: continue
|
||||
if (type.isParcelable()) {
|
||||
val reportElement = supertypeEntry.byKeywordNode?.psi ?: delegateExpression
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.PARCELABLE_DELEGATE_IS_NOT_ALLOWED.on(reportElement),
|
||||
DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.PARCELABLE_DELEGATE_IS_NOT_ALLOWED.on(reportElement)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -188,15 +181,13 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
val primaryConstructor = declaration.primaryConstructor
|
||||
if (primaryConstructor == null && declaration.secondaryConstructors.isNotEmpty()) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR.on(reportElement),
|
||||
DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.PARCELABLE_SHOULD_HAVE_PRIMARY_CONSTRUCTOR.on(reportElement)
|
||||
)
|
||||
} else if (primaryConstructor != null && primaryConstructor.valueParameters.isEmpty()) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY.on(reportElement),
|
||||
DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY.on(reportElement)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -220,8 +211,8 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
) {
|
||||
if (!parameter.hasValOrVar()) {
|
||||
val reportElement = parameter.nameIdentifier ?: parameter
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR.on(reportElement), DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.PARCELABLE_CONSTRUCTOR_PARAMETER_SHOULD_BE_VAL_OR_VAR.on(reportElement)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -244,9 +235,8 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// get() throws IllegalArgumentException on unknown types
|
||||
val reportElement = parameter.typeReference ?: parameter.nameIdentifier ?: parameter
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
ErrorsAndroid.PARCELABLE_TYPE_NOT_SUPPORTED.on(reportElement),
|
||||
DefaultErrorMessagesAndroid
|
||||
diagnosticHolder.report(
|
||||
ErrorsAndroid.PARCELABLE_TYPE_NOT_SUPPORTED.on(reportElement)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty
|
||||
import org.jetbrains.kotlin.android.synthetic.res.isErrorType
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.reportFromPlugin
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
@@ -51,7 +50,7 @@ class AndroidExtensionPropertiesCallChecker : CallChecker {
|
||||
|
||||
private fun DiagnosticSink.checkDeprecated(expression: KtExpression, packageDescriptor: AndroidSyntheticPackageFragmentDescriptor) {
|
||||
if (packageDescriptor.packageData.isDeprecated) {
|
||||
reportFromPlugin(SYNTHETIC_DEPRECATED_PACKAGE.on(expression), DefaultErrorMessagesAndroid)
|
||||
report(SYNTHETIC_DEPRECATED_PACKAGE.on(expression))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +59,7 @@ class AndroidExtensionPropertiesCallChecker : CallChecker {
|
||||
val type = property.errorType ?: return
|
||||
|
||||
val warning = if (type.contains('.')) SYNTHETIC_UNRESOLVED_WIDGET_TYPE else SYNTHETIC_INVALID_WIDGET_TYPE
|
||||
reportFromPlugin(warning.on(expression, type), DefaultErrorMessagesAndroid)
|
||||
report(warning.on(expression, type))
|
||||
}
|
||||
|
||||
private fun DiagnosticSink.checkPartiallyDefinedResource(
|
||||
@@ -73,7 +72,7 @@ class AndroidExtensionPropertiesCallChecker : CallChecker {
|
||||
|
||||
val expectedType = context.resolutionContext.expectedType
|
||||
if (!TypeUtils.noExpectedType(expectedType) && !expectedType.isMarkedNullable && !expectedType.isFlexible()) {
|
||||
reportFromPlugin(UNSAFE_CALL_ON_PARTIALLY_DEFINED_RESOURCE.on(calleeExpression), DefaultErrorMessagesAndroid)
|
||||
report(UNSAFE_CALL_ON_PARTIALLY_DEFINED_RESOURCE.on(calleeExpression))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -81,7 +80,7 @@ class AndroidExtensionPropertiesCallChecker : CallChecker {
|
||||
val usage = outermostQualifiedExpression.parent
|
||||
|
||||
if (usage is KtDotQualifiedExpression && usage.receiverExpression == outermostQualifiedExpression) {
|
||||
reportFromPlugin(UNSAFE_CALL_ON_PARTIALLY_DEFINED_RESOURCE.on(calleeExpression), DefaultErrorMessagesAndroid)
|
||||
report(UNSAFE_CALL_ON_PARTIALLY_DEFINED_RESOURCE.on(calleeExpression))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -21,9 +21,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject;
|
||||
import org.jetbrains.kotlin.psi.KtElement;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
@@ -62,7 +60,7 @@ public interface ErrorsAndroid {
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
{
|
||||
Errors.Initializer.initializeFactoryNames(ErrorsAndroid.class);
|
||||
Errors.Initializer.initializeFactoryNamesAndDefaultErrorMessages(ErrorsAndroid.class, DefaultErrorMessagesAndroid.INSTANCE);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user