Check experimental API markers for deprecation
#KT-22759 In Progress
This commit is contained in:
+5
-3
@@ -99,9 +99,11 @@ class AnalyzerWithCompilerReport(
|
|||||||
|
|
||||||
fun analyzeAndReport(files: Collection<KtFile>, analyze: () -> AnalysisResult) {
|
fun analyzeAndReport(files: Collection<KtFile>, analyze: () -> AnalysisResult) {
|
||||||
analysisResult = analyze()
|
analysisResult = analyze()
|
||||||
ExperimentalUsageChecker.checkCompilerArguments(analysisResult.moduleDescriptor, languageVersionSettings) { message ->
|
ExperimentalUsageChecker.checkCompilerArguments(
|
||||||
messageCollector.report(ERROR, message)
|
analysisResult.moduleDescriptor, languageVersionSettings,
|
||||||
}
|
reportError = { message -> messageCollector.report(ERROR, message) },
|
||||||
|
reportWarning = { message -> messageCollector.report(WARNING, message) }
|
||||||
|
)
|
||||||
reportSyntaxErrors(files)
|
reportSyntaxErrors(files)
|
||||||
reportDiagnostics(analysisResult.bindingContext.diagnostics, messageCollector)
|
reportDiagnostics(analysisResult.bindingContext.diagnostics, messageCollector)
|
||||||
reportIncompleteHierarchies()
|
reportIncompleteHierarchies()
|
||||||
|
|||||||
+24
-2
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.constants.KClassValue
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
import org.jetbrains.kotlin.utils.SmartSet
|
import org.jetbrains.kotlin.utils.SmartSet
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
@@ -237,7 +238,17 @@ object ExperimentalUsageChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkCompilerArguments(module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings, reportError: (String) -> Unit) {
|
fun checkCompilerArguments(
|
||||||
|
module: ModuleDescriptor,
|
||||||
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
|
reportError: (String) -> Unit,
|
||||||
|
reportWarning: (String) -> Unit
|
||||||
|
) {
|
||||||
|
// Ideally, we should run full resolution (with all classifier usage checkers) on classifiers used in "-Xexperimental" and
|
||||||
|
// "-Xuse-experimental" arguments. However, it's not easy to do this. This should be solved in the future with the support of
|
||||||
|
// module annotations. For now, we only check deprecations because this is needed to correctly retire unneeded compiler arguments.
|
||||||
|
val deprecationResolver = DeprecationResolver(LockBasedStorageManager(), languageVersionSettings)
|
||||||
|
|
||||||
fun checkAnnotation(fqName: String, allowNonCompilationImpact: Boolean): Boolean {
|
fun checkAnnotation(fqName: String, allowNonCompilationImpact: Boolean): Boolean {
|
||||||
val descriptor = module.resolveClassByFqName(FqName(fqName), NoLookupLocation.FOR_NON_TRACKED_SCOPE)
|
val descriptor = module.resolveClassByFqName(FqName(fqName), NoLookupLocation.FOR_NON_TRACKED_SCOPE)
|
||||||
val experimentality = descriptor?.loadExperimentalityForMarkerAnnotation()
|
val experimentality = descriptor?.loadExperimentalityForMarkerAnnotation()
|
||||||
@@ -250,9 +261,20 @@ object ExperimentalUsageChecker : CallChecker {
|
|||||||
!allowNonCompilationImpact && !experimentality.impact.all(Experimentality.Impact.COMPILATION::equals) ->
|
!allowNonCompilationImpact && !experimentality.impact.all(Experimentality.Impact.COMPILATION::equals) ->
|
||||||
"Experimental API marker $fqName has impact other than COMPILATION, " +
|
"Experimental API marker $fqName has impact other than COMPILATION, " +
|
||||||
"therefore it can't be used with -Xuse-experimental"
|
"therefore it can't be used with -Xuse-experimental"
|
||||||
else -> return true
|
else -> {
|
||||||
|
for (deprecation in deprecationResolver.getDeprecations(descriptor)) {
|
||||||
|
val report = when (deprecation.deprecationLevel) {
|
||||||
|
DeprecationLevelValue.WARNING -> reportWarning
|
||||||
|
DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> reportError
|
||||||
|
}
|
||||||
|
report("Experimental API marker $fqName is deprecated" + deprecation.message?.let { ". $it" }.orEmpty())
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reportError(message)
|
reportError(message)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -201,10 +201,8 @@ class DeprecationResolver(
|
|||||||
descriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings)
|
descriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDeprecations(
|
fun getDeprecations(descriptor: DeclarationDescriptor): List<Deprecation> =
|
||||||
descriptor: DeclarationDescriptor
|
deprecations(descriptor.original)
|
||||||
) = deprecations(descriptor.original)
|
|
||||||
|
|
||||||
|
|
||||||
fun isDeprecatedHidden(descriptor: DeclarationDescriptor): Boolean =
|
fun isDeprecatedHidden(descriptor: DeclarationDescriptor): Boolean =
|
||||||
getDeprecations(descriptor).any { it.deprecationLevel == HIDDEN }
|
getDeprecations(descriptor).any { it.deprecationLevel == HIDDEN }
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
$TESTDATA_DIR$/experimentalDeprecated.kt
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
|
-Xskip-runtime-version-check
|
||||||
|
-language-version
|
||||||
|
1.3
|
||||||
|
-Xexperimental=org.test.BinaryError
|
||||||
|
-Xexperimental=org.test.BinaryHidden
|
||||||
|
-Xuse-experimental=org.test.SourceError
|
||||||
|
-Xuse-experimental=org.test.SourceHidden
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.test
|
||||||
|
|
||||||
|
@Deprecated("BinaryError", level = DeprecationLevel.ERROR)
|
||||||
|
@Experimental(Experimental.Level.ERROR, [Experimental.Impact.RUNTIME])
|
||||||
|
annotation class BinaryError
|
||||||
|
|
||||||
|
@Deprecated("BinaryHidden", level = DeprecationLevel.HIDDEN)
|
||||||
|
@Experimental(Experimental.Level.ERROR, [Experimental.Impact.RUNTIME])
|
||||||
|
annotation class BinaryHidden
|
||||||
|
|
||||||
|
@Deprecated("SourceError", level = DeprecationLevel.ERROR)
|
||||||
|
@Experimental(Experimental.Level.ERROR, [Experimental.Impact.COMPILATION])
|
||||||
|
annotation class SourceError
|
||||||
|
|
||||||
|
@Deprecated("SourceHidden", level = DeprecationLevel.HIDDEN)
|
||||||
|
@Experimental(Experimental.Level.ERROR, [Experimental.Impact.COMPILATION])
|
||||||
|
annotation class SourceHidden
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
warning: language version 1.3 is experimental, there are no backwards compatibility guarantees for new language and library features
|
||||||
|
error: experimental API marker org.test.BinaryError is deprecated. BinaryError
|
||||||
|
error: experimental API marker org.test.BinaryHidden is deprecated. BinaryHidden
|
||||||
|
error: experimental API marker org.test.SourceError is deprecated. SourceError
|
||||||
|
error: experimental API marker org.test.SourceHidden is deprecated. SourceHidden
|
||||||
|
COMPILATION_ERROR
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
$TESTDATA_DIR$/experimentalDeprecatedWarning.kt
|
||||||
|
-d
|
||||||
|
$TEMP_DIR$
|
||||||
|
-Xskip-runtime-version-check
|
||||||
|
-language-version
|
||||||
|
1.3
|
||||||
|
-Xuse-experimental=org.test.SourceWarning
|
||||||
|
-Xexperimental=org.test.BinaryWarning
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.test
|
||||||
|
|
||||||
|
@Deprecated("BinaryWarning", level = DeprecationLevel.WARNING)
|
||||||
|
@Experimental(Experimental.Level.ERROR, [Experimental.Impact.RUNTIME])
|
||||||
|
annotation class BinaryWarning
|
||||||
|
|
||||||
|
@Deprecated("SourceWarning", level = DeprecationLevel.WARNING)
|
||||||
|
@Experimental(Experimental.Level.ERROR, [Experimental.Impact.COMPILATION])
|
||||||
|
annotation class SourceWarning
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
warning: language version 1.3 is experimental, there are no backwards compatibility guarantees for new language and library features
|
||||||
|
warning: experimental API marker org.test.BinaryWarning is deprecated. BinaryWarning
|
||||||
|
warning: experimental API marker org.test.SourceWarning is deprecated. SourceWarning
|
||||||
|
OK
|
||||||
@@ -183,6 +183,18 @@ public class CliTestGenerated extends AbstractCliTest {
|
|||||||
doJvmTest(fileName);
|
doJvmTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("experimentalDeprecated.args")
|
||||||
|
public void testExperimentalDeprecated() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalDeprecated.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("experimentalDeprecatedWarning.args")
|
||||||
|
public void testExperimentalDeprecatedWarning() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalDeprecatedWarning.args");
|
||||||
|
doJvmTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("experimentalIsNotAnnotation.args")
|
@TestMetadata("experimentalIsNotAnnotation.args")
|
||||||
public void testExperimentalIsNotAnnotation() throws Exception {
|
public void testExperimentalIsNotAnnotation() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalIsNotAnnotation.args");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalIsNotAnnotation.args");
|
||||||
|
|||||||
Reference in New Issue
Block a user