[FIR] Add references to TODOs in checkers
This commit is contained in:
committed by
Space Team
parent
8c5b2ae85b
commit
da60be06a0
+1
-1
@@ -39,7 +39,7 @@ import kotlin.contracts.contract
|
||||
object FirCallsEffectAnalyzer : FirControlFlowChecker() {
|
||||
|
||||
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, context: CheckerContext) {
|
||||
// TODO: this is quadratic due to `graph.traverse`, surely there is a better way?
|
||||
// TODO, KT-59816: this is quadratic due to `graph.traverse`, surely there is a better way?
|
||||
for (subGraph in graph.subGraphs) {
|
||||
analyze(subGraph, reporter, context)
|
||||
}
|
||||
|
||||
+3
-3
@@ -57,7 +57,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
||||
isWrongConditionOnNode(it, coneEffect, returnValue, function, logicSystem, dataFlowInfo, context)
|
||||
}
|
||||
if (wrongCondition) {
|
||||
// TODO: reportOn(firEffect.source, ...)
|
||||
// TODO, KT-59813: reportOn(firEffect.source, ...)
|
||||
reporter.reportOn(function.contractDescription.source, FirErrors.WRONG_IMPLIES_CONDITION, context)
|
||||
}
|
||||
}
|
||||
@@ -106,10 +106,10 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: if this is not a top-level function, `FirDataFlowAnalyzer` has erased its value parameters
|
||||
// TODO, KT-59814: if this is not a top-level function, `FirDataFlowAnalyzer` has erased its value parameters
|
||||
// from `dataFlowInfo.variableStorage` for some reason, so its `getLocalVariable` doesn't work.
|
||||
val knownVariables = flow.knownVariables.associateBy { it.identifier }
|
||||
// TODO: these should be the same on all return paths, so maybe don't recompute them every time?
|
||||
// TODO, KT-59815: these should be the same on all return paths, so maybe don't recompute them every time?
|
||||
val argumentVariables = Array(function.valueParameters.size + 1) { i ->
|
||||
val parameterSymbol = if (i > 0) {
|
||||
function.valueParameters[i - 1].symbol
|
||||
|
||||
+1
-1
@@ -258,7 +258,7 @@ fun ConeKotlinType.isNonReifiedTypeParameter(): Boolean {
|
||||
fun shouldCheckForExactType(expression: FirTypeOperatorCall, context: CheckerContext): Boolean {
|
||||
return when (expression.operation) {
|
||||
FirOperation.IS, FirOperation.NOT_IS -> false
|
||||
// TODO: differentiate if this expression defines the enclosing thing's type
|
||||
// TODO, KT-59820: differentiate if this expression defines the enclosing thing's type
|
||||
// e.g.,
|
||||
// val c1 get() = 1 as Number
|
||||
// val c2: Number get() = 1 <!USELESS_CAST!>as Number<!>
|
||||
|
||||
+4
-4
@@ -101,7 +101,7 @@ internal fun checkConstantArguments(
|
||||
//DO NOTHING
|
||||
}
|
||||
expressionSymbol is FirFieldSymbol -> {
|
||||
//TODO: fix checking of Java fields initializer
|
||||
//TODO, KT-59821: fix checking of Java fields initializer
|
||||
if (!expressionSymbol.isStatic || expressionSymbol.modality != Modality.FINAL) {
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
@@ -125,7 +125,7 @@ internal fun checkConstantArguments(
|
||||
return ConstantArgumentKind.NOT_KCLASS_LITERAL
|
||||
}
|
||||
|
||||
//TODO: UNRESOLVED REFERENCE
|
||||
//TODO, KT-59822: UNRESOLVED REFERENCE
|
||||
if (expression.dispatchReceiver is FirThisReceiverExpression) {
|
||||
return null
|
||||
}
|
||||
@@ -140,7 +140,7 @@ internal fun checkConstantArguments(
|
||||
for (exp in expression.arguments.plus(expression.dispatchReceiver).plus(expression.extensionReceiver)) {
|
||||
if (exp is FirNoReceiverExpression) continue
|
||||
val expClassId = exp.typeRef.coneType.lowerBoundIfFlexible().classId
|
||||
// TODO: add annotation for allowed constant types
|
||||
// TODO, KT-59823: add annotation for allowed constant types
|
||||
if (expClassId !in StandardClassIds.constantAllowedTypes) {
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
@@ -168,7 +168,7 @@ internal fun checkConstantArguments(
|
||||
propertySymbol.isLocal || propertySymbol.callableId.className?.isRoot == false -> return ConstantArgumentKind.NOT_CONST
|
||||
expressionType.classId == StandardClassIds.KClass -> return ConstantArgumentKind.NOT_KCLASS_LITERAL
|
||||
|
||||
//TODO: UNRESOLVED REFERENCE
|
||||
//TODO, KT-59822: UNRESOLVED REFERENCE
|
||||
expression.dispatchReceiver is FirThisReceiverExpression -> return null
|
||||
}
|
||||
return when (property.initializer) {
|
||||
|
||||
@@ -384,7 +384,7 @@ fun FirCallableSymbol<*>.getImplementationStatus(
|
||||
) {
|
||||
return ImplementationStatus.INHERITED_OR_SYNTHESIZED
|
||||
}
|
||||
// TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override
|
||||
// TODO, KT-59818: suspend function overridden by a Java class in the middle is not properly regarded as an override
|
||||
if (isSuspend) {
|
||||
return ImplementationStatus.INHERITED_OR_SYNTHESIZED
|
||||
}
|
||||
@@ -670,7 +670,7 @@ fun getActualTargetList(container: FirAnnotationContainer): AnnotationTargetList
|
||||
} else {
|
||||
TargetLists.T_OBJECT_LITERAL
|
||||
}
|
||||
// TODO: properly implement those cases
|
||||
// TODO, KT-59819: properly implement those cases
|
||||
// is KtDestructuringDeclarationEntry -> TargetLists.T_LOCAL_VARIABLE
|
||||
// is KtDestructuringDeclaration -> TargetLists.T_DESTRUCTURING_DECLARATION
|
||||
// is KtLambdaExpression -> TargetLists.T_FUNCTION_LITERAL
|
||||
|
||||
+2
-2
@@ -62,14 +62,14 @@ fun FirDeclaration.checkSinceKotlinVersionAccessibility(context: CheckerContext)
|
||||
private fun FirDeclaration.getOwnSinceKotlinVersion(session: FirSession): FirSinceKotlinValue? {
|
||||
var result: FirSinceKotlinValue? = null
|
||||
|
||||
// TODO: use-site targeted annotations
|
||||
// TODO, KT-59824: use-site targeted annotations
|
||||
fun FirDeclaration.consider() {
|
||||
val sinceKotlinSingleArgument = getAnnotationByClassId(StandardClassIds.Annotations.SinceKotlin, session)?.findArgumentByName(
|
||||
StandardClassIds.Annotations.ParameterNames.sinceKotlinVersion
|
||||
)
|
||||
val apiVersion = ((sinceKotlinSingleArgument as? FirConstExpression<*>)?.value as? String)?.let(ApiVersion.Companion::parse)
|
||||
if (apiVersion != null) {
|
||||
// TODO: combine wasExperimentalMarkerClasses in case of several associated declarations with the same maximal API version
|
||||
// TODO, KT-59825: combine wasExperimentalMarkerClasses in case of several associated declarations with the same maximal API version
|
||||
if (result == null || apiVersion > result!!.apiVersion) {
|
||||
result = FirSinceKotlinValue(apiVersion, loadWasExperimentalMarkerClasses(session))
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ object FirContractChecker : FirFunctionChecker() {
|
||||
for (unresolvedEffect in contractDescription.unresolvedEffects) {
|
||||
val diagnostic = unresolvedEffect.effect.accept(DiagnosticExtractor, null) ?: continue
|
||||
|
||||
// TODO: report on fine-grained locations, e.g., ... implies unresolved => report on unresolved, not the entire statement.
|
||||
// TODO, KT-59806: report on fine-grained locations, e.g., ... implies unresolved => report on unresolved, not the entire statement.
|
||||
// but, sometimes, it's just reported on `contract`...
|
||||
reporter.reportOn(unresolvedEffect.source, FirErrors.ERROR_IN_CONTRACT_DESCRIPTION, diagnostic.reason, context)
|
||||
}
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ object FirMemberPropertiesChecker : FirClassChecker() {
|
||||
(it.symbol as? FirPropertySymbol)?.takeIf { symbol -> symbol.requiresInitialization(isForClassInitialization = true) }
|
||||
}
|
||||
if (memberPropertySymbols.isEmpty()) return null
|
||||
// TODO: merge with `FirPropertyInitializationAnalyzer` for fewer passes.
|
||||
// TODO, KT-59803: merge with `FirPropertyInitializationAnalyzer` for fewer passes.
|
||||
val data = PropertyInitializationInfoData(memberPropertySymbols, symbol, graph)
|
||||
data.checkPropertyAccesses(isForClassInitialization = true, context, reporter)
|
||||
return data.getValue(graph.exitNode)[NormalPath]
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ object FirSealedSupertypeChecker : FirClassChecker() {
|
||||
reporter.reportOn(superTypeRef.source, FirErrors.SEALED_INHERITOR_IN_DIFFERENT_PACKAGE, context)
|
||||
}
|
||||
if (superClass.moduleData != declaration.moduleData) {
|
||||
// TODO: implement logic like in org.jetbrains.kotlin.resolve.checkers.SealedInheritorInSameModuleChecker for MPP support.
|
||||
// TODO, KT-59804: implement logic like in org.jetbrains.kotlin.resolve.checkers.SealedInheritorInSameModuleChecker for MPP support.
|
||||
reporter.reportOn(superTypeRef.source, FirErrors.SEALED_INHERITOR_IN_DIFFERENT_MODULE, context)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ object FirTailrecFunctionChecker : FirSimpleFunctionChecker() {
|
||||
}
|
||||
val graph = declaration.controlFlowGraphReference?.controlFlowGraph ?: return
|
||||
|
||||
// TODO: this is not how CFG works, tail calls inside try-catch should be detected by FIR tree traversal.
|
||||
// TODO, KT-59668: this is not how CFG works, tail calls inside try-catch should be detected by FIR tree traversal.
|
||||
var tryScopeCount = 0
|
||||
var catchScopeCount = 0
|
||||
var finallyScopeCount = 0
|
||||
|
||||
+1
-1
@@ -140,7 +140,7 @@ internal fun checkPropertyInitializer(
|
||||
if (isExpect) {
|
||||
reporter.reportOn(propertySource, FirErrors.EXPECTED_LATEINIT_PROPERTY, context)
|
||||
}
|
||||
// TODO: like [BindingContext.MUST_BE_LATEINIT], we should consider variable with uninitialized error.
|
||||
// TODO, KT-59807: like [BindingContext.MUST_BE_LATEINIT], we should consider variable with uninitialized error.
|
||||
if (backingFieldRequired && !inInterface && isCorrectlyInitialized) {
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
|
||||
reporter.reportOn(propertySource, FirErrors.UNNECESSARY_LATEINIT, context)
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ object FirClassLiteralChecker : FirGetClassCallChecker() {
|
||||
}
|
||||
|
||||
if (argument !is FirResolvedQualifier) return
|
||||
// TODO: differentiate RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS
|
||||
// TODO, KT-59835: differentiate RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS
|
||||
if (argument.typeArguments.isNotEmpty() && !argument.typeRef.coneType.fullyExpandedType(context.session).isAllowedInClassLiteral(context)) {
|
||||
val symbol = argument.symbol
|
||||
symbol?.lazyResolveToPhase(FirResolvePhase.TYPES)
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@ object FirOptInUsageBaseChecker {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: getAnnotationsOnContainingModule
|
||||
// TODO, KT-59802: getAnnotationsOnContainingModule
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -49,7 +49,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
for (dataPerLabel in dataPerNode.values) {
|
||||
val data = dataPerLabel[variableSymbol] ?: continue
|
||||
if (data == VariableStatus.ONLY_WRITTEN_NEVER_READ) {
|
||||
// todo: report case like "a += 1" where `a` `doesn't writes` different way (special for Idea)
|
||||
// TODO, KT-59831: report case like "a += 1" where `a` `doesn't writes` different way (special for Idea)
|
||||
val source = node.fir.lValue.source
|
||||
reporter.reportOn(source, FirErrors.ASSIGNED_VALUE_IS_NEVER_READ, context)
|
||||
// To avoid duplicate reports, stop investigating remaining paths once reported.
|
||||
@@ -63,7 +63,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
if (node.fir.source == null) return
|
||||
if (variableSymbol.isLoopIterator) return
|
||||
val dataPerNode = data[node] ?: return
|
||||
// TODO: merge values for labels, otherwise diagnostics are inconsistent
|
||||
// TODO, KT-59832: merge values for labels, otherwise diagnostics are inconsistent
|
||||
for (dataPerLabel in dataPerNode.values) {
|
||||
val data = dataPerLabel[variableSymbol] ?: continue
|
||||
|
||||
@@ -117,7 +117,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
else variableUseState
|
||||
|
||||
return base.also {
|
||||
// TODO: is this modifying constant enum values???
|
||||
// TODO, KT-59833: is this modifying constant enum values???
|
||||
it.isRead = this.isRead || variableUseState?.isRead == true
|
||||
it.isRedundantInit = this.isRedundantInit && variableUseState?.isRedundantInit == true
|
||||
}
|
||||
@@ -146,7 +146,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
}
|
||||
|
||||
override fun plus(other: VariableStatusInfo): VariableStatusInfo =
|
||||
merge(other) // TODO: not sure
|
||||
merge(other) // TODO, KT-59834: not sure
|
||||
}
|
||||
|
||||
private class ValueWritesWithoutReading(
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
|
||||
object UselessCallOnNotNullChecker : FirQualifiedAccessExpressionChecker() {
|
||||
// todo: add 'call may be reduced' in cases like 's?.isNullOrEmpty()' where 's: String? = ""'
|
||||
// todo, KT-59829: add 'call may be reduced' in cases like 's?.isNullOrEmpty()' where 's: String? = ""'
|
||||
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val method = expression.getCallableId() ?: return
|
||||
val calleeOn = expression.explicitReceiver ?: return
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ object FirExplicitApiDeclarationChecker : FirDeclarationSyntaxChecker<FirDeclara
|
||||
* 7. An anonymous function
|
||||
* 8. A local named function
|
||||
*
|
||||
* TODO: Do we need something like @PublicApiFile to disable (or invert) this inspection per-file?
|
||||
* TODO, KT-59828: 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
-1
@@ -121,7 +121,7 @@ object FirDiagnosticRenderers {
|
||||
}
|
||||
|
||||
val RENDER_TYPE = Renderer { t: ConeKotlinType ->
|
||||
// TODO: need a way to tune granuality, e.g., without parameter names in functional types.
|
||||
// TODO, KT-59811: need a way to tune granuality, e.g., without parameter names in functional types.
|
||||
t.renderReadableWithFqNames()
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -191,7 +191,7 @@ private fun mapUnsafeCallError(
|
||||
(candidateFunctionSymbol?.isOperator == true || candidateFunctionSymbol?.isInfix == true)
|
||||
) {
|
||||
// For augmented assignment operations (e.g., `a += b`), the source is the entire binary expression (BINARY_EXPRESSION).
|
||||
// TODO: No need to check for source.elementType == BINARY_EXPRESSION if we use operator as callee reference source
|
||||
// TODO, KT-59809: No need to check for source.elementType == BINARY_EXPRESSION if we use operator as callee reference source
|
||||
// (see FirExpressionsResolveTransformer.transformAssignmentOperatorStatement)
|
||||
val operationSource = if (source.elementType == KtNodeTypes.BINARY_EXPRESSION) {
|
||||
source.getChild(KtNodeTypes.OPERATION_REFERENCE)
|
||||
@@ -387,7 +387,7 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
val position = position.from
|
||||
val argument =
|
||||
when (position) {
|
||||
// TODO: Support other ReceiverConstraintPositionImpl, LHSArgumentConstraintPositionImpl
|
||||
// TODO, KT-59810: Support other ReceiverConstraintPositionImpl, LHSArgumentConstraintPositionImpl
|
||||
is ConeArgumentConstraintPosition -> position.argument
|
||||
is ConeLambdaArgumentConstraintPosition -> position.lambda
|
||||
else -> null
|
||||
|
||||
Reference in New Issue
Block a user