Compare commits

...

102 Commits

Author SHA1 Message Date
jetbrains-junie[bot]
178087009d feat(junie): added .devcontainer.json 2025-06-02 21:45:51 +00:00
jetbrains-junie[bot]
8bc7c3c242 feat(junie): added .junie workflow 2025-06-02 21:45:50 +00:00
Igor Yakovlev
8e885da677 [FIR IDE] Fix exception in FIR LC with special identifier names 2021-08-19 21:26:08 +02:00
Igor Yakovlev
2ce391d317 [FIR IDE] Fix unensured access to the return type 2021-08-19 21:26:08 +02:00
Igor Yakovlev
7a5a2bfcd7 [FIR] Fix invalid source for anonymous object type 2021-08-19 21:26:07 +02:00
Igor Yakovlev
5e6442b475 [FIR IDE] Suppress warnings to build project with warnings-as-errors mode 2021-08-19 21:26:07 +02:00
Igor Yakovlev
5498f40ce7 [FIR IDE] Fix reference resolve for functions call 2021-08-19 21:26:07 +02:00
Igor Yakovlev
42242e198b [FIR IDE] Fix invalid resolve for local declarations that could be outdated while incremental analisys 2021-08-19 21:26:07 +02:00
Igor Yakovlev
6360366ecc [FIR IDE] Fix invalid resolve for local declarations that could be fully replaced with new instance
+small optimisations for IMPORTS phase
2021-08-19 21:26:07 +02:00
Igor Yakovlev
ed0bfabc51 [FIR IDE] Fix invalid reference resolve for null safety operator 2021-08-19 21:26:07 +02:00
Igor Yakovlev
0a5dee567e [FIR IDE] Fix invalid property incremental analisys 2021-08-19 21:26:07 +02:00
Igor Yakovlev
0781156b42 [FIR IDE] Fix invalid reference resolve into companion with custom name 2021-08-19 21:26:07 +02:00
Igor Yakovlev
2ff4f10ff0 [FIR IDE] Fix SOE for FIR deserialized declarations provider 2021-08-19 21:26:07 +02:00
Igor Yakovlev
035f1ff89f [FIR IDE] Add ValueWithPostCompute recursive guard 2021-08-19 21:26:07 +02:00
Igor Yakovlev
d0e25eb987 [FIR IDE] Preprocess cone types in psi type mapper 2021-08-19 21:26:07 +02:00
Igor Yakovlev
79b70a6f98 [FIR IDE] Ensure resolved for status when resolving local declarations 2021-08-19 21:26:07 +02:00
Igor Yakovlev
21f36ef19a [FIR IDE] Fix inner light classes creation 2021-08-19 21:26:07 +02:00
Igor Yakovlev
0ca7fb7af5 [FIR] Fix JvmTypeMapper for generic type aliases 2021-08-19 21:26:06 +02:00
Igor Yakovlev
9bc695e245 [FIR IDE] Make one global lock for resolve 2021-08-19 21:26:06 +02:00
Georgy Bronnikov
b42358f893 JVM_IR: do not index on AttributeOwnerId in AddContinuationLowering 2021-08-19 21:53:47 +03:00
Georgy Bronnikov
32518eee4b JVM_IR: use computeIfAbsent in ClassCodegen.getOrCreate() 2021-08-19 21:53:46 +03:00
Georgy Bronnikov
a5a79215d7 JVM_IR: No need to use ConcurrentHashMap in ClassCodegen 2021-08-19 21:53:45 +03:00
Georgy Bronnikov
07eef9b751 JVM_IR: double call to adjustDefaultArgumentStubs 2021-08-19 21:53:44 +03:00
Alexander Shabalin
a7460e9061 [K/N] Enable lazy property initialization with the new MM 2021-08-19 18:23:01 +00:00
Ilmir Usmanov
b5fa129540 Loosen tail-call optimization check for functions returning Unit
Do not check, that all Unit predecessors are POPs. This is safe for the
same reason, as it is safe to allow some of ARETURN sources not be
suspension point results.
To elaborate, before Unit, the stack is empty. This is because if there
are multiple paths to Unit and at least one of them comes from POP after
suspension point (we are interested in this case only - otherwise, the
call is not tail-call), in path from said POP the stack is empty, since
after suspension point the stack contains only one element. Thus, the
stack in other paths leading to Unit has to be empty, otherwise, merge
operation is not possible and ASM will report error during analysis.
Since the stack is empty in all paths, we can hoist Unit and following
ARETURN to predecessors, effectively turning path from suspension point
to tail-call.
2021-08-19 16:05:21 +00:00
Mads Ager
d33b70af1a [JVM IR] Ensure an instruction for the line number for a break.
This ensures that the debugger always has a bytecode offset for
the line number of a break/continue so that you step there and
so that you can set breakpoints there.

The `nop` instruction is optimized out if it has no line number
information.

^KT-46450 Fixed
2021-08-19 15:40:44 +02:00
Andrey Zinovyev
894a446585 [FIR] Add missing messages for jvm diagnostics and fix some tests 2021-08-19 15:25:51 +03:00
Andrey Zinovyev
3b21759697 [FIR] SUPER_CALL_WITH_DEFAULT_PARAMETERS diagnostic 2021-08-19 15:25:50 +03:00
Andrey Zinovyev
24fbe0f072 [FIR] UPPER_BOUND_CANNOT_BE_ARRAY diagnostic 2021-08-19 15:25:49 +03:00
Andrey Zinovyev
4661656b8c [FIR] JVM_PACKAGE_NAME* diagnostics 2021-08-19 15:25:47 +03:00
Andrey Zinovyev
ae558c0290 [FIR] Add DEPRECATED_JAVA_ANNOTATION diagnostic 2021-08-19 15:25:46 +03:00
Andrey Zinovyev
f9b601edae [FIR] @JvmOverloads related checkers 2021-08-19 15:25:44 +03:00
Andrey Zinovyev
17ae69416c [FIR] Add SYNCHRONIZED_* diagnostics 2021-08-19 15:25:43 +03:00
Andrey Zinovyev
7ba8e0d9cc [FIR] Add VOLATILE_ON_VALUE/VOLATILE_ON_DELEGATE diagnostic 2021-08-19 15:25:43 +03:00
Andrey Zinovyev
f90b534c4c [FIR] Add STRICTFP_ON_CLASS diagnostic 2021-08-19 15:25:41 +03:00
sebastian.sellmair
565ea2c4f5 [Commonizer] Improve iteration performance in transformer and mergeCirTree
An allocation/iterator free `forEach` is used for lists that
are not intended to be modified at the same time.
2021-08-19 12:19:15 +00:00
sebastian.sellmair
e2816ffabb [Commonizer] Rename CirTypeSubstitutor implementations
^KT-48287
^KT-48286
2021-08-19 12:19:14 +00:00
sebastian.sellmair
8aceff3641 [Commonizer] Implement CirUnderscoredTypeAliasSubstitutor
Try substituting TypeAlias types that start with `__` in favour
of TypeAlias without the underscored prefix

^KT-48287 Verification Pending
^KT-48286 Verification Pending
2021-08-19 12:19:14 +00:00
Ilya Goncharov
7d3830ba7d [Gradle, JS] Use stable version of webpack-dev-server 2021-08-19 15:06:16 +03:00
Hung Nguyen
16dfdb620e KT-45777: Add custom serialization for classpath snapshot
Also add a few commonly-used classes/methods to externalizers.kt to
allow reuse.

Bug: KT-45777
Test: New ClasspathSnapshotSerializerTest
2021-08-19 13:50:26 +03:00
Alexander Likhachev
0d2a514a70 [Gradle, JS] Fix NPM resolution skip condition for js compilation
#KT-48241 Fixed
2021-08-19 12:07:23 +03:00
Alexander Likhachev
b74253521e [Gradle, JS] Add test for KT-48241 2021-08-19 12:06:32 +03:00
Igor Chevdar
a576160847 [K/N][IR][codegen] Lazy initialization fix for new GC
A mutable field should be registered in GC even if its initializer is a const
2021-08-19 00:50:28 +05:00
Alexander Udalov
af59955566 IR: minor, refactor code in ExpectDeclarationRemover
Inline unnecessary inline functions to keep stacktraces saner, fix
incorrect "this" in exception message in
findActualForExpect/findExpectForActual (see KT-45628).
2021-08-18 21:27:55 +02:00
Alexander Udalov
a4730dd57e Minor, set JAVA_HOME to JDK 1.8 in LauncherScriptTest
Otherwise the test would invoke the "java" executable from PATH, which
might not be 1.8, and that would cause some tests to fail because error
messages are slightly different in newer Java versions.
2021-08-18 21:27:55 +02:00
Alexander Udalov
b1bce6a29e JVM IR: fix noarg plugin for sealed class with existing noarg ctor
#KT-48111 Fixed
2021-08-18 20:57:19 +02:00
pyos
d3de0109ca Add tests for KT-48180 2021-08-18 18:39:33 +02:00
pyos
ff6de0fe6a JVM: remove InlineCodegen.expressionMap
#KT-48180 Fixed
2021-08-18 16:55:44 +02:00
pyos
47d0211370 FE: do not enhance ? in jspecify NullMarked scope
No clue whether this should be done for `@TypeQualifierDefault` since it
appears to have no specification whatsoever.

 #KT-48262 Fixed
2021-08-18 16:41:00 +03:00
Jinseong Jeon
5819959cce Consolidate arrayOf call names 2021-08-18 16:04:36 +03:00
Andrey Zinovyev
1cd321a90f [FIR] Add INAPPLICABLE_OPERATOR_MODIFIER diagnostic 2021-08-18 16:03:01 +03:00
Ilya Goncharov
16f41bd80c [Gradle, JS] Use webpack-dev-server rc.1 2021-08-18 15:50:38 +03:00
Mikhael Bogdanov
8ab546ba51 [FIR]: Pass special origins for local functions (named and anonymous) 2021-08-18 09:58:27 +00:00
Mikhael Bogdanov
a5e59e09ee Copy methods for lambdas to DefaultImpls without receiver transformation
#KT-48230 Fixed
2021-08-18 09:58:27 +00:00
pyos
6d7eb2bd21 Add test for KT-48230 2021-08-18 09:58:27 +00:00
Sebastian Sellmair
21f7e16ee6 [Gradle] NativeDistributionCommonizationCache: Acquire FileLock
A `.lock` file will be acquired before running the native
distribution commonizer. This is done to protect data corruption
when multiple process try to commonize at the same time.

This could happen when e.g. two new projects are opened that
both trigger the commonizer during syncing.

^KT-46343 Verification Pending
2021-08-18 09:22:46 +00:00
Tianyu Geng
fb1eac0985 FIR: report SMARTCAST_IMPOSSIBLE on inherited alien properties [KT-48101] 2021-08-18 12:02:02 +03:00
Mikhail Glukhikh
0a6e51e47f FirJavaGenericVarianceViolationTypeChecker: make code a bit more clear 2021-08-18 12:02:01 +03:00
Ilya Goncharov
f37d880964 [Gradle, JS] Add test on valid of webpack config
^KT-48273 fixed
2021-08-18 11:56:19 +03:00
Ivan Kochurkin
301f446433 Restore KtModifierKeywordToken instead of String in modifier diagnostics
Remove KeywordType
2021-08-18 00:45:57 +03:00
Denis.Zharkov
a8077aebb0 FIR: Ignore suspicious test on StrictJavaNullabilityAssertions
^KT-48302 Open
2021-08-17 21:38:01 +03:00
Denis.Zharkov
753ba99b04 FIR: Support enhanced types when checking if Java type is primitive 2021-08-17 21:38:01 +03:00
Denis.Zharkov
a0553f4dfd FIR: Do not build synthetic property named with first capital character 2021-08-17 21:38:01 +03:00
Denis.Zharkov
c3a327e118 FIR: Fix ambiguity on Int2IntMap in IC 2021-08-17 21:38:01 +03:00
Mikhail Glukhikh
1a5552bef8 FIR2IR: fix argument mapping for deserialized annotation #KT-48298 Fixed 2021-08-17 18:22:33 +03:00
Mikhail Glukhikh
6660c9b26b FIR: add test repeating a problem with annotation mapping (KT-48298) 2021-08-17 18:22:33 +03:00
Andrey Zinovyev
ab158a53c3 [FIR] ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION diag 2021-08-17 16:05:42 +03:00
Andrey Zinovyev
1cdbbad367 [FIR] ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION diag 2021-08-17 16:05:42 +03:00
Nikita Bobko
5e87d753b7 Fix coop-dev project import 2021-08-17 13:55:36 +02:00
Ilya Goncharov
a7cc275c7d [Gradle, JS] Update webpack-dev-server
^KT-48273 fixed
2021-08-17 14:44:29 +03:00
Elena Lepilkina
12d694de46 [K/N] Added returns before building DFG 2021-08-17 16:14:07 +05:00
Igor Chevdar
16f0ba8e46 [K/N][optmz] Reworked a bit work with fields 2021-08-17 16:14:07 +05:00
pyos
49c412b022 JVM_IR: implement view caching in kotlin-android-extensions
#KT-47733 Fixed
2021-08-17 13:46:26 +03:00
Pavel Punegov
6ea2dea28e Fix JDK 16 and 17 env variables to correspond to the TC 2021-08-17 09:51:53 +00:00
Yahor Berdnikau
e7a08b14e3 Fix 'jvmTarget' is not updated on reusing configuration cache.
Before this change 'kotlinOptions.jvmTarget' was updated
on 'providedJvm' property value calculation, but, as configuration
cache reuses property value from the cache - 'jvmTarget' update does not
 happen.

This change adds additional call to set 'jvmTarget' on task execution
 phase to ensure even on configuration cache reuse field is set
 to correct value. Update is based whether 'providedJvm' property is set
 or not.

^KT-48226 Fixed
2021-08-17 09:13:29 +00:00
Pavel Punegov
7e1c776376 [Native][tests] Fix warnings in debugger tests 2021-08-17 08:42:11 +00:00
Dmitriy Dolovov
4049cf94b1 [Gradle][Native] Mute BuildCacheRelocationIT.testRelocation on MinGW 2021-08-17 11:01:08 +03:00
Dmitriy Dolovov
da72f26d94 [IR][Tests] Unmute NativeIrLinkerIssuesIT (as far as K/N version is already updated)
^KT-44626
2021-08-17 07:53:47 +00:00
Dmitriy Dolovov
e18c3517a9 [Gradle] Advance K/N version to 1.6.0-dev-2972 2021-08-17 07:53:46 +00:00
Dmitriy Dolovov
cd08dc49a0 [IR][Tests] Mute NativeIrLinkerIssuesIT until K/N version is updated
^KT-44626
2021-08-17 07:53:46 +00:00
Dmitriy Dolovov
4edc1239ac [IR] Use only ASCII-printable chars in IR linker error reports
^KT-44626
2021-08-17 07:53:46 +00:00
Dmitriy Dolovov
af12d61388 [IR] Enhance error reporting for IR linking issues
^KT-44626

Support correct error reporting both with native static caches and without native static caches.
2021-08-17 07:53:45 +00:00
Dmitriy Dolovov
3cd43dced4 [IR] Fix tests for IR linking error reporting
- Run "ktor 1_5_4 and coroutines 1_5_0-RC-native-mt (KT-46697)" test only on Mac host
- Fix application entry point function FQN
- Use OS-neutral URI for configuration of local Maven repos instead of OS-specific path

^KT-44626
2021-08-17 07:53:45 +00:00
Andrey Zinovyev
a17a61341b [FIR] Fix false positive NON_INTERNAL_PUBLISHED_API on constructor val
#KT-48234 Fixed
2021-08-16 19:12:31 +03:00
Tianyu Geng
68f14fdd87 FIR: PrimitiveTypes -> StandardTypes 2021-08-16 16:54:33 +03:00
Tianyu Geng
5a26e79b08 FIR checker: move JAVA_TYPE_MISMATCH to FirJvmErrors 2021-08-16 16:54:32 +03:00
Tianyu Geng
b77dc4136b FIR checker: fix JAVA_TYPE_MISMATCH again 2021-08-16 16:54:22 +03:00
Tianyu Geng
64ebddcbc6 FIR checker: add convention check for ++ and +=, etc 2021-08-16 15:14:30 +03:00
sebastian.sellmair
68e7476765 [Commonizer] ClassSuperTypeCommonizer: Don't find consumed TypeNodes
This commit will also add some simple documentation
to this class and its implementation.

^KT-47430
2021-08-16 10:44:04 +00:00
sebastian.sellmair
1e95717b8d [Commonizer] Implement SimpleCirSupertypesResolverTest
^KT-47430
2021-08-16 10:44:03 +00:00
sebastian.sellmair
f64a0efa8b [Commonizer] Respect artificial supertypes when loading dependencies
CirProvided.ExportedForwardDeclarationClass will now correctly
report artificial superclasses.

The InlineTypeAliasCirNodeTransformer does not need to know anything
about artificial supertypes anymore. When inlining any
type alias, it is enough to resolve the type-alias's expansions
supertypes.

^KT-47430
2021-08-16 10:44:03 +00:00
sebastian.sellmair
26ede5d885 [Commonizer] Add small documentation on CirSupertypesResolver
^KT-47430
2021-08-16 10:44:03 +00:00
sebastian.sellmair
9fb41b6334 [Commonizer] CirKnownClassifiers: Store indices and target dependencies as 'TargetDependent'
^KT-47430
2021-08-16 10:44:02 +00:00
sebastian.sellmair
367db345a8 [Commonizer] Do not re-calculate classifier indices for transformer
^KT-47430
2021-08-16 10:44:02 +00:00
sebastian.sellmair
dda9bb93f6 [Commonizer] Consider exportForwardDeclarations as dependency
This will make follow-up commits easier:
forward declarations are closer to dependencies than being part
of the library. They will be used in the module, bot not
directly provided.

This commit also enables tracking of provided dependency classifiers
in the CirTreeRoot and CirRootNode

^KT-47430
2021-08-16 10:44:01 +00:00
sebastian.sellmair
3d4e861f05 [Commonizer] ModulesProvider: refactor 'loadModuleInfos()' to property
This is done to signal that accessing this data is indeed lightweight.

^KT-47430
2021-08-16 10:44:01 +00:00
sebastian.sellmair
6c246738a5 [Commonizer] TargetDependent: Support index based access
^KT-47430
2021-08-16 10:44:01 +00:00
sebastian.sellmair
dff392f2cd [Commonizer] ClassSuperTypeCommonizer: Include transitive supertypes
This commit still has some left-over todos that shall be done
in a separate commit.

TODOs:
- CirClassifierIndex is calculated once too often
- Reconsider position of classifierIndices in 'CirKnownClassifiers'
- Add documentation/description to complicated 'ClassSuperTypeCommonizer'
- Add documentation/description to CirSupertypesResolver

^KT-47430 Verification Pending
2021-08-16 10:44:00 +00:00
sebastian.sellmair
1857096071 [Commonizer] Implement ClassSuperTypeCommonizer
This implementation runs as regular part of the commonization.
Previous implementation inside the CommonizationVisitor was fully
replaced by it.

As a side effect: CirClass.supertypes was now marked immutable.

^KT-47430 In Progress
2021-08-16 10:44:00 +00:00
sebastian.sellmair
50a343f91e [Commonizer] Deserialize supertypes from provided dependencies
^KT-47430 In Progress
2021-08-16 10:43:59 +00:00
sebastian.sellmair
cdfe8d60a4 [Commonizer] InlineTypeAliasCirNodeTransformer: add artificial supertypes
When inlining any TypeAlias pointing towards forward declarations,
the inlined class will respect implicit supertypes.

This logic is analog to
KlibResolvedModuleDescriptorsFactoryImpl.createForwardDeclarationsModule

^KT-47430 In Progress
2021-08-16 10:43:59 +00:00
Sergey Bogolepov
0c35a3b699 [K/N] A bit cleaner reflection of code coverage state in docs. 2021-08-16 09:22:32 +00:00
381 changed files with 6708 additions and 2724 deletions

View File

@@ -0,0 +1,12 @@
{
"name": "Java",
"image": "mcr.microsoft.com/devcontainers/java:1-21",
"features": {
"ghcr.io/devcontainers/features/java:1": {
"version": "none",
"installMaven": "true",
"mavenVersion": "3.8.6",
"installGradle": "true"
}
}
}

22
.github/workflows/junie.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Junie
run-name: Junie run ${{ inputs.run_id }}
permissions:
contents: write
pull-requests: write
on:
workflow_dispatch:
inputs:
run_id:
description: "id of workflow process"
required: true
workflow_params:
description: "stringified params"
required: true
jobs:
call-workflow-passing-data:
uses: jetbrains-junie/junie-workflows/.github/workflows/ej-issue.yml@main
with:
workflow_params: ${{ inputs.workflow_params }}

View File

@@ -118,10 +118,10 @@ open class IncrementalJvmCache(
}
/**
* Saves information about the given (kotlinc-generated) class to this cache, and stores changes between this class and its previous
* version into the given [ChangesCollector].
* Saves information about the given (Kotlin) class to this cache, and stores changes between this class and its previous version into
* the given [ChangesCollector].
*
* @param kotlinClassInfo A kotlin-generated class
* @param kotlinClassInfo Information about a Kotlin class
* @param sourceFiles The source files that the given class was generated from, or `null` if this information is not available
* @param changesCollector A [ChangesCollector]
*/
@@ -129,11 +129,13 @@ open class IncrementalJvmCache(
val className = kotlinClassInfo.className
dirtyOutputClassesMap.notDirty(className)
sourceFiles?.forEach {
sourceToClassesMap.add(it, className)
}
sourceFiles?.let { internalNameToSource[className.internalName] = it }
if (sourceFiles != null) {
sourceFiles.forEach {
sourceToClassesMap.add(it, className)
}
internalNameToSource[className.internalName] = sourceFiles
}
if (kotlinClassInfo.classId.isLocal) return
@@ -149,8 +151,8 @@ open class IncrementalJvmCache(
inlineFunctionsMap.process(kotlinClassInfo, changesCollector)
}
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
val partNames = kotlinClassInfo.classHeaderData?.toList()
?: throw AssertionError("Multifile class has no parts: $className")
val partNames = kotlinClassInfo.classHeaderData.toList()
check(partNames.isNotEmpty()) { "Multifile class has no parts: $className" }
multifileFacadeToParts[className] = partNames
// When a class is replaced with a facade with the same name,
// the class' proto wouldn't ever be deleted,
@@ -315,8 +317,8 @@ open class IncrementalJvmCache(
val oldData = storage[key]
val newData = ProtoMapValue(
kotlinClassInfo.classKind != KotlinClassHeader.Kind.CLASS,
BitEncoding.decodeBytes(kotlinClassInfo.classHeaderData!!),
kotlinClassInfo.classHeaderStrings!!
BitEncoding.decodeBytes(kotlinClassInfo.classHeaderData),
kotlinClassInfo.classHeaderStrings
)
storage[key] = newData
@@ -380,7 +382,8 @@ open class IncrementalJvmCache(
}
// todo: reuse code with InlineFunctionsMap?
private inner class ConstantsMap(storageFile: File) : BasicStringMap<Map<String, Any>>(storageFile, ConstantsMapExternalizer) {
private inner class ConstantsMap(storageFile: File) :
BasicStringMap<LinkedHashMap<String, Any>>(storageFile, LinkedHashMapExternalizer(StringExternalizer, ConstantExternalizer)) {
operator fun contains(className: JvmClassName): Boolean =
className.internalName in storage
@@ -419,7 +422,7 @@ open class IncrementalJvmCache(
storage.remove(className.internalName)
}
override fun dumpValue(value: Map<String, Any>): String =
override fun dumpValue(value: LinkedHashMap<String, Any>): String =
value.dumpMap(Any::toString)
}
@@ -499,12 +502,12 @@ open class IncrementalJvmCache(
}
private fun addToClassStorage(classInfo: KotlinClassInfo, srcFile: File) {
val (nameResolver, proto) = JvmProtoBufUtil.readClassDataFrom(classInfo.classHeaderData!!, classInfo.classHeaderStrings!!)
val (nameResolver, proto) = JvmProtoBufUtil.readClassDataFrom(classInfo.classHeaderData, classInfo.classHeaderStrings)
addToClassStorage(proto, nameResolver, srcFile)
}
private inner class InlineFunctionsMap(storageFile: File) :
BasicStringMap<Map<String, Long>>(storageFile, StringToLongMapExternalizer) {
BasicStringMap<LinkedHashMap<String, Long>>(storageFile, LinkedHashMapExternalizer(StringExternalizer, LongExternalizer)) {
@Synchronized
fun process(kotlinClassInfo: KotlinClassInfo, changesCollector: ChangesCollector) {
@@ -537,7 +540,7 @@ open class IncrementalJvmCache(
storage.remove(className.internalName)
}
override fun dumpValue(value: Map<String, Long>): String =
override fun dumpValue(value: LinkedHashMap<String, Long>): String =
value.dumpMap { java.lang.Long.toHexString(it) }
}
}
@@ -596,18 +599,18 @@ fun <T : Comparable<T>> Collection<T>.dumpCollection(): String =
"[${sorted().joinToString(", ", transform = Any::toString)}]"
/**
* Minimal information about a kotlinc-generated class that will be used to compute recompilation-triggered changes to support incremental
* compilation (see [IncrementalJvmCache.saveClassToCache]).
* Minimal information about a Kotlin class to compute recompilation-triggering changes during an incremental run of the `KotlinCompile`
* task (see [IncrementalJvmCache.saveClassToCache]).
*
* It's important that this class contain only the minimal required information, as it will be part of the classpath snapshot of the
* `KotlinCompile` task and the task needs to support compile avoidance. For example, this class should contain public method signatures,
* and should not contain private method signatures, or method implementations.
*/
class KotlinClassInfo private constructor(
class KotlinClassInfo constructor(
val classId: ClassId,
val classKind: KotlinClassHeader.Kind,
val classHeaderData: Array<String>?,
val classHeaderStrings: Array<String>?,
val classHeaderData: Array<String>, // Can be empty
val classHeaderStrings: Array<String>, // Can be empty
@Suppress("SpellCheckingInspection") val multifileClassName: String?,
val constantsMap: LinkedHashMap<String, Any>,
val inlineFunctionsMap: LinkedHashMap<String, Long>
@@ -628,22 +631,22 @@ class KotlinClassInfo private constructor(
return KotlinClassInfo(
kotlinClass.classId,
kotlinClass.classHeader.kind,
kotlinClass.classHeader.data,
kotlinClass.classHeader.strings,
kotlinClass.classHeader.data ?: emptyArray(),
kotlinClass.classHeader.strings ?: emptyArray(),
kotlinClass.classHeader.multifileClassName,
getConstantsMap(kotlinClass.fileContents),
getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
)
}
/** Creates [KotlinClassInfo] from the given classContents, or returns `null` if the class is not a kotlinc-generated class. */
/** Creates [KotlinClassInfo] from the given classContents, or returns `null` if the class is not a Kotlin class. */
fun tryCreateFrom(classContents: ByteArray): KotlinClassInfo? {
return FileBasedKotlinClass.create(classContents) { classId, _, classHeader, _ ->
KotlinClassInfo(
classId,
classHeader.kind,
classHeader.data,
classHeader.strings,
classHeader.data ?: emptyArray(),
classHeader.strings ?: emptyArray(),
classHeader.multifileClassName,
getConstantsMap(classContents),
getInlineFunctionsMap(classHeader, classContents)

View File

@@ -94,13 +94,12 @@ object ProtoMapValueExternalizer : DataExternalizer<ProtoMapValue> {
}
}
abstract class StringMapExternalizer<T> : DataExternalizer<Map<String, T>> {
override fun save(output: DataOutput, map: Map<String, T>?) {
output.writeInt(map!!.size)
for ((key, value) in map.entries) {
IOUtil.writeString(key, output)
output.writeString(key)
writeValue(output, value)
}
}
@@ -110,7 +109,7 @@ abstract class StringMapExternalizer<T> : DataExternalizer<Map<String, T>> {
val map = HashMap<String, T>(size)
repeat(size) {
val name = IOUtil.readString(input)!!
val name = input.readString()
map[name] = readValue(input)
}
@@ -121,7 +120,6 @@ abstract class StringMapExternalizer<T> : DataExternalizer<Map<String, T>> {
protected abstract fun readValue(input: DataInput): T
}
object StringToLongMapExternalizer : StringMapExternalizer<Long>() {
override fun readValue(input: DataInput): Long = input.readLong()
@@ -130,58 +128,43 @@ object StringToLongMapExternalizer : StringMapExternalizer<Long>() {
}
}
object ConstantsMapExternalizer : DataExternalizer<Map<String, Any>> {
override fun save(output: DataOutput, map: Map<String, Any>?) {
output.writeInt(map!!.size)
for (name in map.keys.sorted()) {
IOUtil.writeString(name, output)
val value = map[name]!!
when (value) {
is Int -> {
output.writeByte(Kind.INT.ordinal)
output.writeInt(value)
}
is Float -> {
output.writeByte(Kind.FLOAT.ordinal)
output.writeFloat(value)
}
is Long -> {
output.writeByte(Kind.LONG.ordinal)
output.writeLong(value)
}
is Double -> {
output.writeByte(Kind.DOUBLE.ordinal)
output.writeDouble(value)
}
is String -> {
output.writeByte(Kind.STRING.ordinal)
IOUtil.writeString(value, output)
}
else -> throw IllegalStateException("Unexpected constant class: ${value::class.java}")
/** [DataExternalizer] for a Kotlin constant. */
object ConstantExternalizer : DataExternalizer<Any> {
override fun save(output: DataOutput, value: Any) {
when (value) {
is Int -> {
output.writeByte(Kind.INT.ordinal)
output.writeInt(value)
}
is Float -> {
output.writeByte(Kind.FLOAT.ordinal)
output.writeFloat(value)
}
is Long -> {
output.writeByte(Kind.LONG.ordinal)
output.writeLong(value)
}
is Double -> {
output.writeByte(Kind.DOUBLE.ordinal)
output.writeDouble(value)
}
is String -> {
output.writeByte(Kind.STRING.ordinal)
output.writeString(value)
}
else -> throw IllegalStateException("Unexpected constant class: ${value::class.java}")
}
}
override fun read(input: DataInput): Map<String, Any> {
val size = input.readInt()
val map = HashMap<String, Any>(size)
repeat(size) {
val name = IOUtil.readString(input)!!
val kind = Kind.values()[input.readByte().toInt()]
val value: Any = when (kind) {
Kind.INT -> input.readInt()
Kind.FLOAT -> input.readFloat()
Kind.LONG -> input.readLong()
Kind.DOUBLE -> input.readDouble()
Kind.STRING -> IOUtil.readString(input)!!
}
map[name] = value
override fun read(input: DataInput): Any {
return when (Kind.values()[input.readByte().toInt()]) {
Kind.INT -> input.readInt()
Kind.FLOAT -> input.readFloat()
Kind.LONG -> input.readLong()
Kind.DOUBLE -> input.readDouble()
Kind.STRING -> input.readString()
}
return map
}
private enum class Kind {
@@ -190,11 +173,18 @@ object ConstantsMapExternalizer : DataExternalizer<Map<String, Any>> {
}
object IntExternalizer : DataExternalizer<Int> {
override fun save(output: DataOutput, value: Int) = output.writeInt(value)
override fun read(input: DataInput): Int = input.readInt()
}
override fun save(output: DataOutput, value: Int) {
output.writeInt(value)
}
object LongExternalizer : DataExternalizer<Long> {
override fun save(output: DataOutput, value: Long) = output.writeLong(value)
override fun read(input: DataInput): Long = input.readLong()
}
object StringExternalizer : DataExternalizer<String> {
override fun save(output: DataOutput, value: String) = IOUtil.writeString(value, output)
override fun read(input: DataInput): String = IOUtil.readString(input)
}
@@ -244,3 +234,69 @@ open class CollectionExternalizer<T>(
object StringCollectionExternalizer : CollectionExternalizer<String>(EnumeratorStringDescriptor(), { HashSet() })
object IntCollectionExternalizer : CollectionExternalizer<Int>(IntExternalizer, { HashSet() })
fun DataOutput.writeString(value: String) = StringExternalizer.save(this, value)
fun DataInput.readString(): String = StringExternalizer.read(this)
class ListExternalizer<T>(
private val elementExternalizer: DataExternalizer<T>
) : DataExternalizer<List<T>> {
override fun save(output: DataOutput, value: List<T>) {
output.writeInt(value.size)
value.forEach {
elementExternalizer.save(output, it)
}
}
override fun read(input: DataInput): List<T> {
val size = input.readInt()
val list = ArrayList<T>(size)
repeat(size) {
list.add(elementExternalizer.read(input))
}
return list
}
}
class LinkedHashMapExternalizer<K, V>(
private val keyExternalizer: DataExternalizer<K>,
private val valueExternalizer: DataExternalizer<V>
) : DataExternalizer<LinkedHashMap<K, V>> {
override fun save(output: DataOutput, map: LinkedHashMap<K, V>) {
output.writeInt(map.size)
for ((key, value) in map) {
keyExternalizer.save(output, key)
valueExternalizer.save(output, value)
}
}
override fun read(input: DataInput): LinkedHashMap<K, V> {
val size = input.readInt()
val map = LinkedHashMap<K, V>(size)
repeat(size) {
val key = keyExternalizer.read(input)
val value = valueExternalizer.read(input)
map[key] = value
}
return map
}
}
class NullableValueExternalizer<T>(private val valueExternalizer: DataExternalizer<T>) : DataExternalizer<T> {
override fun save(output: DataOutput, value: T?) {
output.writeBoolean(value != null)
value?.let {
valueExternalizer.save(output, it)
}
}
override fun read(input: DataInput): T? {
return if (input.readBoolean()) {
valueExternalizer.read(input)
} else null
}
}

View File

@@ -148,7 +148,7 @@ extra["versions.kotlinx-collections-immutable-jvm"] = immutablesVersion
extra["versions.ktor-network"] = "1.0.1"
if (!project.hasProperty("versions.kotlin-native")) {
extra["versions.kotlin-native"] = "1.6.0-dev-1728"
extra["versions.kotlin-native"] = "1.6.0-dev-2972"
}
val useJvmFir by extra(project.kotlinBuildProperties.useFir)

View File

@@ -39,7 +39,6 @@ internal class MethodNodeExaminer(
private val popsBeforeSafeUnitInstances = mutableSetOf<AbstractInsnNode>()
private val areturnsAfterSafeUnitInstances = mutableSetOf<AbstractInsnNode>()
private val meaningfulSuccessorsCache = hashMapOf<AbstractInsnNode, List<AbstractInsnNode>>()
private val meaningfulPredecessorsCache = hashMapOf<AbstractInsnNode, List<AbstractInsnNode>>()
init {
if (!disableTailCallOptimizationForFunctionReturningUnit) {
@@ -52,10 +51,8 @@ internal class MethodNodeExaminer(
for (pop in popsBeforeUnitInstances) {
val units = pop.meaningfulSuccessors()
val allUnitsAreSafe = units.all { unit ->
// check no other predecessor exists
unit.meaningfulPredecessors().all { it in popsBeforeUnitInstances } &&
// check they have only returns among successors
unit.meaningfulSuccessors().all { it.opcode == Opcodes.ARETURN }
// check they have only returns among successors
unit.meaningfulSuccessors().all { it.opcode == Opcodes.ARETURN }
}
if (!allUnitsAreSafe) continue
// save them all to the properties
@@ -74,35 +71,22 @@ internal class MethodNodeExaminer(
private fun AbstractInsnNode.isAreturnAfterSafeUnitInstance(): Boolean = this in areturnsAfterSafeUnitInstances
private fun AbstractInsnNode.meaningfulSuccessors(): List<AbstractInsnNode> = meaningfulSuccessorsCache.getOrPut(this) {
meaningfulSuccessorsOrPredecessors(true)
}
private fun AbstractInsnNode.meaningfulPredecessors(): List<AbstractInsnNode> = meaningfulPredecessorsCache.getOrPut(this) {
meaningfulSuccessorsOrPredecessors(false)
}
private fun AbstractInsnNode.meaningfulSuccessorsOrPredecessors(isSuccessors: Boolean): List<AbstractInsnNode> {
fun AbstractInsnNode.isMeaningful() = isMeaningful && opcode != Opcodes.NOP && opcode != Opcodes.GOTO && this !is LineNumberNode
fun AbstractInsnNode.getIndices() =
if (isSuccessors) controlFlowGraph.getSuccessorsIndices(this)
else controlFlowGraph.getPredecessorsIndices(this)
val visited = mutableSetOf<AbstractInsnNode>()
fun dfs(insn: AbstractInsnNode) {
if (insn in visited) return
visited += insn
if (!insn.isMeaningful()) {
for (succIndex in insn.getIndices()) {
for (succIndex in controlFlowGraph.getSuccessorsIndices(insn)) {
dfs(methodNode.instructions[succIndex])
}
}
}
for (succIndex in getIndices()) {
for (succIndex in controlFlowGraph.getSuccessorsIndices(this)) {
dfs(methodNode.instructions[succIndex])
}
return visited.filter { it.isMeaningful() }
visited.filter { it.isMeaningful() }
}
fun replacePopsBeforeSafeUnitInstancesWithCoroutineSuspendedChecks() {

View File

@@ -520,13 +520,10 @@ class AnonymousObjectTransformer(
val paramTypes = transformationInfo.constructorDesc?.let { Type.getArgumentTypes(it) } ?: emptyArray()
for (type in paramTypes) {
val info = indexToFunctionalArgument[constructorParamBuilder.nextParameterOffset]
val isCaptured = capturedParams.contains(constructorParamBuilder.nextParameterOffset)
val parameterInfo = constructorParamBuilder.addNextParameter(type, info is LambdaInfo)
parameterInfo.functionalArgument = info
if (capturedParams.contains(parameterInfo.index)) {
parameterInfo.isCaptured = true
} else {
//otherwise it's super constructor parameter
}
parameterInfo.isCaptured = isCaptured
}
//For all inlined lambdas add their captured parameters

View File

@@ -32,7 +32,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
private val initialFrameSize = codegen.frameMap.currentSize
protected val invocationParamBuilder = ParametersBuilder.newBuilder()
protected val expressionMap = linkedMapOf<Int, FunctionalArgument>()
private val maskValues = ArrayList<Int>()
private var maskStartIndex = -1
private var methodHandleInDefaultMethodIndex = -1
@@ -80,8 +79,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
for (info in infos) {
val lambda = DefaultLambda(info, sourceCompiler)
parameters.getParameterByDeclarationSlot(info.offset).functionalArgument = lambda
val prev = expressionMap.put(info.offset, lambda)
assert(prev == null) { "Lambda with offset ${info.offset} already exists: $prev" }
if (info.needReification) {
lambda.reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(lambda.node.node))
}
@@ -98,7 +95,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
val parameters = invocationParamBuilder.buildParameters()
val info = RootInliningContext(
expressionMap, state, codegen.inlineNameGenerator.subGenerator(jvmSignature.asmMethod.name),
state, codegen.inlineNameGenerator.subGenerator(jvmSignature.asmMethod.name),
sourceCompiler, sourceCompiler.inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings
)
@@ -213,9 +210,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
}
protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) {
val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index)
closureInfo.functionalArgument = lambdaInfo
expressionMap[closureInfo.index] = lambdaInfo
invocationParamBuilder.addNextValueParameter(parameterType, true, null, index).functionalArgument = lambdaInfo
}
protected fun putCapturedToLocalVal(stackValue: StackValue, capturedParam: CapturedParamDesc, kotlinType: KotlinType?) {

View File

@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.state.GenerationState
class RootInliningContext(
expressionMap: Map<Int, FunctionalArgument>,
state: GenerationState,
nameGenerator: NameGenerator,
val sourceCompilerForInline: SourceCompilerForInline,
@@ -17,12 +16,11 @@ class RootInliningContext(
val inlineMethodReifier: ReifiedTypeInliner<*>,
typeParameterMappings: TypeParameterMappings<*>
) : InliningContext(
null, expressionMap, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), null, false
null, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), null, false
)
class RegeneratedClassContext(
parent: InliningContext,
expressionMap: Map<Int, FunctionalArgument>,
state: GenerationState,
nameGenerator: NameGenerator,
typeRemapper: TypeRemapper,
@@ -30,14 +28,13 @@ class RegeneratedClassContext(
override val callSiteInfo: InlineCallSiteInfo,
override val transformationInfo: TransformationInfo
) : InliningContext(
parent, expressionMap, state, nameGenerator, typeRemapper, lambdaInfo, true
parent, state, nameGenerator, typeRemapper, lambdaInfo, true
) {
val continuationBuilders: MutableMap<String, ClassBuilder> = hashMapOf()
}
open class InliningContext(
val parent: InliningContext?,
val expressionMap: Map<Int, FunctionalArgument>,
val state: GenerationState,
val nameGenerator: NameGenerator,
val typeRemapper: TypeRemapper,
@@ -97,7 +94,7 @@ open class InliningContext(
callSiteInfo: InlineCallSiteInfo,
transformationInfo: TransformationInfo
): InliningContext = RegeneratedClassContext(
this, expressionMap, state, generator, TypeRemapper.createFrom(typeRemapper, newTypeMappings),
this, state, generator, TypeRemapper.createFrom(typeRemapper, newTypeMappings),
lambdaInfo, callSiteInfo, transformationInfo
)
@@ -110,7 +107,7 @@ open class InliningContext(
): InliningContext {
val isInliningLambda = lambdaInfo != null
return InliningContext(
this, expressionMap, state, generator,
this, state, generator,
TypeRemapper.createFrom(
typeRemapper,
additionalTypeMappings,

View File

@@ -62,19 +62,16 @@ class PsiInlineCodegen(
return
}
try {
val registerLineNumber = registerLineNumberAfterwards(resolvedCall)
for (info in expressionMap.values) {
if (info is PsiExpressionLambda) {
// Can't be done immediately in `rememberClosure` for some reason:
info.generateLambdaBody(sourceCompiler)
// Requires `generateLambdaBody` first if the closure is non-empty (for bound callable references,
// or indeed any callable references, it *is* empty, so this was done in `rememberClosure`):
if (!info.isBoundCallableReference) {
putClosureParametersOnStack(info, null)
}
for (info in closuresToGenerate) {
// Can't be done immediately in `rememberClosure` for some reason:
info.generateLambdaBody(sourceCompiler)
// Requires `generateLambdaBody` first if the closure is non-empty (for bound callable references,
// or indeed any callable references, it *is* empty, so this was done in `rememberClosure`):
if (!info.isBoundCallableReference) {
putClosureParametersOnStack(info, null)
}
}
performInline(registerLineNumber, functionDescriptor.isInlineOnly())
performInline(registerLineNumberAfterwards(resolvedCall), functionDescriptor.isInlineOnly())
} finally {
state.globalInlineContext.exitFromInlining()
}
@@ -144,6 +141,8 @@ class PsiInlineCodegen(
private fun isCallSiteIsSuspend(descriptor: ValueParameterDescriptor): Boolean =
state.bindingContext[CodegenBinding.CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA, descriptor] == true
private val closuresToGenerate = mutableListOf<PsiExpressionLambda>()
private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor) {
val ktLambda = KtPsiUtil.deparenthesize(expression)
assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" }
@@ -155,6 +154,7 @@ class PsiInlineCodegen(
val lambda = PsiExpressionLambda(ktLambda!!, state, parameter.isCrossinline, boundReceiver != null)
rememberClosure(type, parameter.index, lambda)
closuresToGenerate += lambda
if (boundReceiver != null) {
// Has to be done immediately to preserve evaluation order.
val receiver = codegen.generateReceiverValue(boundReceiver, false)

View File

@@ -12,7 +12,7 @@ fun test() {
bar(1, z = true, y = *arrayOf("my", "yours"))
bar(0, z = false, y = "", <!ARGUMENT_PASSED_TWICE!>y<!> = "other")
bar(0, z = false, y = <!ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>, <!ARGUMENT_PASSED_TWICE!>y<!> = "other")
bar(0, "", true<!NO_VALUE_FOR_PARAMETER!>)<!>
bar(0, z = false, y = "", <!ARGUMENT_PASSED_TWICE!>y<!> = "other", <!ARGUMENT_PASSED_TWICE!>y<!> = "yet other")
bar(0, z = false, y = <!ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>, <!ARGUMENT_PASSED_TWICE!>y<!> = "other", <!ARGUMENT_PASSED_TWICE!>y<!> = "yet other")
}

View File

@@ -13,13 +13,13 @@ interface B {
}
interface C {
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun toString(): String = "Rest"<!>
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun toString(): String = "Rest"<!>
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun equals(other: Any?): Boolean = false<!>
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun hashCode(): Int = 2<!>
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hashCode(): Int = 2<!>
}
interface D {
override operator fun toString(): String
override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun toString(): String
override operator fun equals(other: Any?): Boolean
override operator fun hashCode(): Int
override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hashCode(): Int
}

View File

@@ -16,7 +16,7 @@ FILE: test.kt
private final val DERIVED_FACTORY: R|DiagnosticFactory0<ft<DerivedElement, DerivedElement?>>| = R|/DiagnosticFactory0.DiagnosticFactory0|<R|ft<DerivedElement, DerivedElement?>|>()
private get(): R|DiagnosticFactory0<ft<DerivedElement, DerivedElement?>>|
public final fun createViaFactory(d: R|EmptyDiagnostic|): R|kotlin/Unit| {
lval casted: R|Diagnostic<ft<DerivedElement, DerivedElement?>>| = R|/DERIVED_FACTORY|.R|SubstitutionOverride</DiagnosticFactory0.cast: R|Diagnostic<ft<DerivedElement, DerivedElement?>>|>|(R|<local>/d|)
lval casted: R|Diagnostic<ft<DerivedElement, DerivedElement?>>| = R|/DERIVED_FACTORY|.R|SubstitutionOverride</DiagnosticFactory0.cast: R|@EnhancedNullability Diagnostic<ft<DerivedElement, DerivedElement?>>|>|(R|<local>/d|)
lval element: R|DerivedElement| = R|<local>/casted|.R|/Diagnostic.element|
R|/Fix.Fix|(R|<local>/element|)
}

View File

@@ -25,7 +25,7 @@ abstract class NotRange4() {
}
abstract class ImproperIterator3 {
abstract operator fun hasNext() : Int
abstract <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hasNext() : Int
abstract operator fun next() : Int
}

View File

@@ -16855,6 +16855,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/j+k/innerNestedClassFromJava.kt");
}
@Test
@TestMetadata("integerNotNullable.kt")
public void testIntegerNotNullable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt");
}
@Test
@TestMetadata("invisiblePackagePrivateInheritedMember.kt")
public void testInvisiblePackagePrivateInheritedMember() throws Exception {
@@ -21700,6 +21706,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
}
@Test
@TestMetadata("kotlinStarProjection.kt")
public void testKotlinStarProjection() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinStarProjection.kt");
}
@Test
@TestMetadata("listSuperType.kt")
public void testListSuperType() throws Exception {
@@ -28046,6 +28058,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt");
}
@Test
@TestMetadata("otherModuleInheritance.kt")
public void testOtherModuleInheritance() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
}
@Test
@TestMetadata("protected.kt")
public void testProtected() throws Exception {

View File

@@ -16855,6 +16855,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/j+k/innerNestedClassFromJava.kt");
}
@Test
@TestMetadata("integerNotNullable.kt")
public void testIntegerNotNullable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt");
}
@Test
@TestMetadata("invisiblePackagePrivateInheritedMember.kt")
public void testInvisiblePackagePrivateInheritedMember() throws Exception {
@@ -21700,6 +21706,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
}
@Test
@TestMetadata("kotlinStarProjection.kt")
public void testKotlinStarProjection() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinStarProjection.kt");
}
@Test
@TestMetadata("listSuperType.kt")
public void testListSuperType() throws Exception {
@@ -28046,6 +28058,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt");
}
@Test
@TestMetadata("otherModuleInheritance.kt")
public void testOtherModuleInheritance() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
}
@Test
@TestMetadata("protected.kt")
public void testProtected() throws Exception {

View File

@@ -29,6 +29,7 @@ fun main(args: Array<String>) {
alias<FirStatement>("BasicExpressionChecker")
alias<FirQualifiedAccess>("QualifiedAccessChecker")
alias<FirQualifiedAccessExpression>("QualifiedAccessExpressionChecker")
alias<FirCall>("CallChecker")
alias<FirFunctionCall>("FunctionCallChecker")
alias<FirVariableAssignment>("VariableAssignmentChecker")
alias<FirTryExpression>("TryExpressionChecker")

View File

@@ -301,35 +301,35 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val MODIFIERS by object : DiagnosticGroup("Modifiers") {
val INAPPLICABLE_INFIX_MODIFIER by error<PsiElement>()
val REPEATED_MODIFIER by error<PsiElement> {
parameter<String>("modifier")
parameter<KtModifierKeywordToken>("modifier")
}
val REDUNDANT_MODIFIER by error<PsiElement> {
parameter<String>("redundantModifier")
parameter<String>("conflictingModifier")
parameter<KtModifierKeywordToken>("redundantModifier")
parameter<KtModifierKeywordToken>("conflictingModifier")
}
val DEPRECATED_MODIFIER by warning<PsiElement> {
parameter<String>("deprecatedModifier")
parameter<String>("actualModifier")
parameter<KtModifierKeywordToken>("deprecatedModifier")
parameter<KtModifierKeywordToken>("actualModifier")
}
val DEPRECATED_MODIFIER_PAIR by error<PsiElement> {
parameter<String>("deprecatedModifier")
parameter<String>("conflictingModifier")
parameter<KtModifierKeywordToken>("deprecatedModifier")
parameter<KtModifierKeywordToken>("conflictingModifier")
}
val DEPRECATED_MODIFIER_FOR_TARGET by warning<PsiElement> {
parameter<String>("deprecatedModifier")
parameter<KtModifierKeywordToken>("deprecatedModifier")
parameter<String>("target")
}
val REDUNDANT_MODIFIER_FOR_TARGET by warning<PsiElement> {
parameter<String>("redundantModifier")
parameter<KtModifierKeywordToken>("redundantModifier")
parameter<String>("target")
}
val INCOMPATIBLE_MODIFIERS by error<PsiElement> {
parameter<String>("modifier1")
parameter<String>("modifier2")
parameter<KtModifierKeywordToken>("modifier1")
parameter<KtModifierKeywordToken>("modifier2")
}
val REDUNDANT_OPEN_IN_INTERFACE by warning<KtModifierListOwner>(PositioningStrategy.OPEN_MODIFIER)
val WRONG_MODIFIER_TARGET by error<PsiElement> {
parameter<String>("modifier")
parameter<KtModifierKeywordToken>("modifier")
parameter<String>("target")
}
val OPERATOR_MODIFIER_REQUIRED by error<PsiElement> {
@@ -340,13 +340,16 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirNamedFunctionSymbol>("functionSymbol")
}
val WRONG_MODIFIER_CONTAINING_DECLARATION by error<PsiElement> {
parameter<String>("modifier")
parameter<KtModifierKeywordToken>("modifier")
parameter<String>("target")
}
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning<PsiElement> {
parameter<String>("modifier")
parameter<KtModifierKeywordToken>("modifier")
parameter<String>("target")
}
val INAPPLICABLE_OPERATOR_MODIFIER by error<PsiElement>(PositioningStrategy.OPERATOR_MODIFIER) {
parameter<String>("message")
}
}
val INLINE_CLASSES by object : DiagnosticGroup("Inline classes") {
@@ -442,6 +445,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
}
val SPREAD_OF_NULLABLE by error<PsiElement>(PositioningStrategy.SPREAD_OPERATOR)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
}
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
@@ -1115,6 +1121,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<ConeKotlinType>("leftType")
parameter<ConeKotlinType>("rightType")
}
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error<KtExpression>(PositioningStrategy.OPERATOR)
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error<KtExpression>(PositioningStrategy.OPERATOR) {
parameter<FirNamedFunctionSymbol>("functionSymbol")
parameter<String>("operator")
}
}
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
@@ -1258,13 +1269,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val RETURN_FOR_BUILT_IN_SUSPEND by error<KtReturnExpression>()
}
val JVM by object : DiagnosticGroup("jvm") {
val JAVA_TYPE_MISMATCH by error<KtExpression> {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
}
}
}
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {

View File

@@ -6,8 +6,14 @@
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@Suppress("UNUSED_VARIABLE", "LocalVariableName", "ClassName", "unused")
@OptIn(PrivateForInline::class)
@@ -15,4 +21,44 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
val DECLARATIONS by object : DiagnosticGroup("Declarations") {
val CONFLICTING_JVM_DECLARATIONS by error<PsiElement>()
}
val TYPES by object : DiagnosticGroup("Types") {
val JAVA_TYPE_MISMATCH by error<KtExpression> {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
}
}
val TYPE_PARAMETERS by object : DiagnosticGroup("Type parameters") {
val UPPER_BOUND_CANNOT_BE_ARRAY by error<PsiElement>()
}
val ANNOTATIONS by object : DiagnosticGroup("annotations") {
val STRICTFP_ON_CLASS by error<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning<KtAnnotationEntry>()
val OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS by warning<KtAnnotationEntry>()
val OVERLOADS_ABSTRACT by error<KtAnnotationEntry>()
val OVERLOADS_INTERFACE by error<KtAnnotationEntry>()
val OVERLOADS_LOCAL by error<KtAnnotationEntry>()
val OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR by deprecationError<KtAnnotationEntry>(LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses)
val OVERLOADS_PRIVATE by warning<KtAnnotationEntry>()
val DEPRECATED_JAVA_ANNOTATION by warning<KtAnnotationEntry>() {
parameter<FqName>("kotlinName")
}
val JVM_PACKAGE_NAME_CANNOT_BE_EMPTY by error<KtAnnotationEntry>()
val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error<KtAnnotationEntry>()
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error<KtAnnotationEntry>()
}
val SUPER by object : DiagnosticGroup("Super") {
val SUPER_CALL_WITH_DEFAULT_PARAMETERS by error<PsiElement>() {
parameter<String>("name")
}
}
}

View File

@@ -103,6 +103,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
ABSTRACT_MODIFIER,
LABEL,
COMMAS,
OPERATOR_MODIFIER,
;

View File

@@ -6,7 +6,12 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics.jvm
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtExpression
/*
* This file was generated automatically
@@ -17,4 +22,31 @@ object FirJvmErrors {
// Declarations
val CONFLICTING_JVM_DECLARATIONS by error0<PsiElement>()
// Types
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
// Type parameters
val UPPER_BOUND_CANNOT_BE_ARRAY by error0<PsiElement>()
// annotations
val STRICTFP_ON_CLASS by error0<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error0<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error0<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error0<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error0<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning0<KtAnnotationEntry>()
val OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS by warning0<KtAnnotationEntry>()
val OVERLOADS_ABSTRACT by error0<KtAnnotationEntry>()
val OVERLOADS_INTERFACE by error0<KtAnnotationEntry>()
val OVERLOADS_LOCAL by error0<KtAnnotationEntry>()
val OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR by deprecationError0<KtAnnotationEntry>(ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses)
val OVERLOADS_PRIVATE by warning0<KtAnnotationEntry>()
val DEPRECATED_JAVA_ANNOTATION by warning1<KtAnnotationEntry, FqName>()
val JVM_PACKAGE_NAME_CANNOT_BE_EMPTY by error0<KtAnnotationEntry>()
val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error0<KtAnnotationEntry>()
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error0<KtAnnotationEntry>()
// Super
val SUPER_CALL_WITH_DEFAULT_PARAMETERS by error1<PsiElement, String>()
}

View File

@@ -5,13 +5,33 @@
package org.jetbrains.kotlin.fir.analysis.jvm.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.FirJvmExternalDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.*
object JvmDeclarationCheckers : DeclarationCheckers() {
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
get() = setOf(
FirJvmExternalDeclarationChecker,
)
override val classCheckers: Set<FirClassChecker>
get() = setOf(
FirStrictfpApplicabilityChecker,
)
override val propertyCheckers: Set<FirPropertyChecker>
get() = setOf(
FirVolatileAnnotationChecker,
)
override val functionCheckers: Set<FirFunctionChecker>
get() = setOf(
FirSynchronizedAnnotationChecker,
FirOverloadsChecker,
)
override val typeParameterCheckers: Set<FirTypeParameterChecker>
get() = setOf(
FirUpperBoundsChecker,
)
}

View File

@@ -6,12 +6,23 @@
package org.jetbrains.kotlin.fir.analysis.jvm.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirDeprecatedJavaAnnotationsChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirJavaGenericVarianceViolationTypeChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirJvmPackageNameAnnotationsChecker
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirSuperCallWithDefaultsChecker
object JvmExpressionCheckers : ExpressionCheckers() {
override val functionCallCheckers: Set<FirFunctionCallChecker>
get() = setOf(
FirJavaGenericVarianceViolationTypeChecker,
FirSuperCallWithDefaultsChecker,
)
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
get() = setOf(
FirDeprecatedJavaAnnotationsChecker,
FirJvmPackageNameAnnotationsChecker,
)
}

View File

@@ -32,7 +32,7 @@ object FirJvmExternalDeclarationChecker : FirBasicDeclarationChecker() {
}
val externalModifier = declaration.getModifier(KtTokens.EXTERNAL_KEYWORD)
externalModifier?.let {
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token.toString(), target, context)
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token, target, context)
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.jvm.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
import org.jetbrains.kotlin.fir.declarations.utils.isActual
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject
import org.jetbrains.kotlin.name.FqName
object FirOverloadsChecker : FirFunctionChecker() {
private val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads")
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
val annotation = declaration.getAnnotationByFqName(JVM_OVERLOADS_FQ_NAME) ?: return
//todo need to have expect declaration here to check if it has default values
if (declaration.isActual) return
val containingDeclaration = declaration.getContainingClassSymbol(context.session)
when {
containingDeclaration?.classKind == ClassKind.INTERFACE ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_INTERFACE, context)
declaration.isAbstract ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_ABSTRACT, context)
(declaration is FirSimpleFunction && declaration.isLocal) ||
context.containingDeclarations.any { it.isLocalClassOrAnonymousObject() } ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_LOCAL, context)
declaration is FirConstructor && containingDeclaration?.classKind == ClassKind.ANNOTATION_CLASS ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR, context)
!declaration.visibility.isPublicAPI && declaration.visibility != Visibilities.Internal ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_PRIVATE, context)
declaration.valueParameters.none { it.defaultValue != null } ->
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS, context)
}
}
}

View File

@@ -0,0 +1,24 @@
/*
* 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.jvm.checkers.declaration
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
import org.jetbrains.kotlin.name.FqName
object FirStrictfpApplicabilityChecker : FirClassChecker() {
private val STRICTFP_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Strictfp")
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
val annotation = declaration.getAnnotationByFqName(STRICTFP_ANNOTATION_FQ_NAME) ?: return
reporter.reportOn(annotation.source, FirJvmErrors.STRICTFP_ON_CLASS, context)
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.jvm.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.name.FqName
object FirSynchronizedAnnotationChecker : FirFunctionChecker() {
private val SYNCHRONIZED_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Synchronized")
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
val annotation = declaration.getAnnotationByFqName(SYNCHRONIZED_ANNOTATION_FQ_NAME) ?: return
if (declaration.isInline) {
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_INLINE, context)
return
}
val containingClass = declaration.getContainingClassSymbol(context.session) ?: return
if (containingClass.classKind == ClassKind.INTERFACE) {
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_IN_INTERFACE, context)
} else if (declaration.isAbstract) {
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT, context)
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* 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.jvm.checkers.declaration
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirTypeParameterChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isArrayType
object FirUpperBoundsChecker : FirTypeParameterChecker() {
override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.bounds.any { it.coneType.isArrayType }) {
reporter.reportOn(declaration.source, FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY, context)
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.jvm.checkers.declaration
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
import org.jetbrains.kotlin.name.FqName
object FirVolatileAnnotationChecker : FirPropertyChecker() {
private val VOLATILE_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Volatile")
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.source?.kind != FirRealSourceElementKind) return
val fieldAnnotation = declaration.backingFieldSymbol.getAnnotationByFqName(VOLATILE_ANNOTATION_FQ_NAME)
if (fieldAnnotation != null && !declaration.isVar) {
reporter.reportOn(fieldAnnotation.source, FirJvmErrors.VOLATILE_ON_VALUE, context)
}
val delegateAnnotation = declaration.delegateFieldSymbol?.getAnnotationByFqName(VOLATILE_ANNOTATION_FQ_NAME)
if (delegateAnnotation != null) {
reporter.reportOn(delegateAnnotation.source, FirJvmErrors.VOLATILE_ON_DELEGATE, context)
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.jvm.checkers.expression
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.FqName
object FirDeprecatedJavaAnnotationsChecker : FirAnnotationCallChecker() {
private val javaToKotlinNameMap: Map<FqName, FqName> =
mapOf(
JvmAnnotationNames.TARGET_ANNOTATION to StandardNames.FqNames.target,
JvmAnnotationNames.RETENTION_ANNOTATION to StandardNames.FqNames.retention,
JvmAnnotationNames.DEPRECATED_ANNOTATION to StandardNames.FqNames.deprecated,
JvmAnnotationNames.DOCUMENTED_ANNOTATION to StandardNames.FqNames.mustBeDocumented
)
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
if (context.containingDeclarations.lastOrNull()?.source?.kind != FirRealSourceElementKind) return
val lookupTag = expression.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return
javaToKotlinNameMap[lookupTag.classId.asSingleFqName()]?.let { betterName ->
reporter.reportOn(expression.source, FirJvmErrors.DEPRECATED_JAVA_ANNOTATION, betterName, context)
}
}
}

View File

@@ -5,10 +5,11 @@
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression
import org.jetbrains.kotlin.fir.StandardTypes
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
@@ -109,7 +110,7 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
// actually created because of type projection from `get`. Hence, to workaround this problem, we simply remove all the out
// projection and type capturing and compare the types after such erasure. This way, we won't incorrectly reject any valid code
// though we may accept some invalid code. But in presence of the unsound flexible types, we are allowing invalid code already.
val argTypeWithoutOutProjection = argType.removeOutProjection(true)
val argTypeWithoutOutProjection = argType.removeOutProjection(isCovariant = true)
val lowerBoundWithoutCapturing = context.session.inferenceComponents.approximator.approximateToSuperType(
lowerBound,
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
@@ -121,36 +122,39 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
lowerBoundWithoutCapturing.withNullability(ConeNullability.NULLABLE, typeCtx)
)
) {
reporter.reportOn(arg.source, FirErrors.JAVA_TYPE_MISMATCH, expectedType, argType, context)
reporter.reportOn(arg.source, FirJvmErrors.JAVA_TYPE_MISMATCH, expectedType, argType, context)
}
}
}
private fun ConeKotlinType.removeOutProjection(positive: Boolean): ConeKotlinType {
private fun ConeKotlinType.removeOutProjection(isCovariant: Boolean): ConeKotlinType {
return when (this) {
is ConeFlexibleType -> ConeFlexibleType(lowerBound.removeOutProjection(positive), upperBound.removeOutProjection(positive))
is ConeFlexibleType -> ConeFlexibleType(
lowerBound.removeOutProjection(isCovariant),
upperBound.removeOutProjection(isCovariant)
)
is ConeCapturedType -> ConeCapturedType(
captureStatus,
lowerType?.removeOutProjection(positive),
lowerType?.removeOutProjection(isCovariant),
nullability,
constructor.apply {
ConeCapturedTypeConstructor(
projection.removeOutProjection(positive),
supertypes?.map { it.removeOutProjection(positive) },
projection.removeOutProjection(isCovariant),
supertypes?.map { it.removeOutProjection(isCovariant) },
typeParameterMarker
)
},
attributes,
isProjectionNotNull
)
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(positive))
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(isCovariant))
is ConeIntersectionType -> ConeIntersectionType(
intersectedTypes.map { it.removeOutProjection(positive) },
alternativeType?.removeOutProjection(positive)
intersectedTypes.map { it.removeOutProjection(isCovariant) },
alternativeType?.removeOutProjection(isCovariant)
)
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(
lookupTag,
typeArguments.map { it.removeOutProjection(positive) }.toTypedArray(),
typeArguments.map { it.removeOutProjection(isCovariant) }.toTypedArray(),
isNullable,
attributes
)
@@ -158,14 +162,20 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
}
}
private fun ConeTypeProjection.removeOutProjection(positive: Boolean): ConeTypeProjection {
/**
* @param isCovariant true if the current context is covariant and false if contravariant.
*
* This function only remove out projections in covariant context.
* 'in' projections are never removed, nor would an out projection in a contravariant context.
*/
private fun ConeTypeProjection.removeOutProjection(isCovariant: Boolean): ConeTypeProjection {
return when (this) {
is ConeKotlinTypeProjectionOut -> if (positive) type else this
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!positive))
is ConeKotlinTypeProjectionOut -> if (isCovariant) type else this
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!isCovariant))
is ConeStarProjection -> if (isCovariant) StandardTypes.Any else this
// Don't remove nested projections for types at invariant position.
is ConeKotlinTypeConflictingProjection,
is ConeKotlinType,
is ConeStarProjection -> this
is ConeKotlinType -> this
}
}
@@ -181,7 +191,10 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
for (immediateSuperType in subTypeConstructor.supertypes()) {
val immediateSuperTypeConstructor = immediateSuperType.typeConstructor()
if (superTypeConstructor == immediateSuperTypeConstructor) return true
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(immediateSuperTypeConstructor, superTypeConstructor)) return true
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(
immediateSuperTypeConstructor, superTypeConstructor
)
) return true
}
return false
}

View File

@@ -0,0 +1,42 @@
/*
* 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.jvm.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.getStringArgument
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.name.*
object FirJvmPackageNameAnnotationsChecker : FirAnnotationCallChecker() {
private val jvmPackageNameClassId = ClassId.topLevel(FqName("kotlin.jvm.JvmPackageName"))
private val stringParameterName = Name.identifier("name")
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
val lookupTag = expression.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return
if (lookupTag.classId != jvmPackageNameClassId) return
val nameValue = expression.getStringArgument(stringParameterName) ?: return
if (nameValue.isEmpty()) {
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, context)
} else if (!isValidJavaFqName(nameValue)) {
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_MUST_BE_VALID_NAME, context)
}
val file = context.containingDeclarations.firstOrNull() as? FirFile ?: return
if (file.declarations.any { it is FirClass }) {
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES, context)
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.jvm.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirSuperCallWithDefaultsChecker : FirFunctionCallChecker() {
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
expression.explicitReceiver.safeAs<FirQualifiedAccessExpression>()
?.calleeReference.safeAs<FirSuperReference>()
?: return
val functionSymbol =
(expression.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirNamedFunctionSymbol ?: return
if (!functionSymbol.valueParameterSymbols.any { it.hasDefaultValue }) return
val arguments = expression.argumentList as? FirResolvedArgumentList ?: return
if (arguments.arguments.size < functionSymbol.valueParameterSymbols.size) {
reporter.reportOn(
expression.calleeReference.source,
FirJvmErrors.SUPER_CALL_WITH_DEFAULT_PARAMETERS,
functionSymbol.name.asString(),
context
)
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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.jvm.diagnostics
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDefaultErrorMessages
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.TO_STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONFLICTING_JVM_DECLARATIONS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.DEPRECATED_JAVA_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_CANNOT_BE_EMPTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_MUST_BE_VALID_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ABSTRACT
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_LOCAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_PRIVATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.STRICTFP_ON_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SUPER_CALL_WITH_DEFAULT_PARAMETERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_ON_INLINE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_DELEGATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_VALUE
object FirJvmDefaultErrorMessages {
fun installJvmErrorMessages() {
FirDefaultErrorMessages.Companion.MAP.also { map ->
map.put(CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash")
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch expected {0} but found {1}. Use explicit cast", RENDER_TYPE, RENDER_TYPE)
map.put(UPPER_BOUND_CANNOT_BE_ARRAY, "Upper bound of a type parameter cannot be an array")
map.put(STRICTFP_ON_CLASS, "'@Strictfp' annotation on classes is unsupported yet")
map.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties")
map.put(VOLATILE_ON_DELEGATE, "'@Volatile' annotation cannot be used on delegated properties")
map.put(SYNCHRONIZED_ON_ABSTRACT, "'@Synchronized' annotation cannot be used on abstract functions")
map.put(SYNCHRONIZED_ON_INLINE, "'@Synchronized' annotation has no effect on inline functions")
map.put(SYNCHRONIZED_IN_INTERFACE, "'@Synchronized' annotation cannot be used on interface members")
map.put(OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS, "'@JvmOverloads' annotation has no effect for methods without default arguments")
map.put(OVERLOADS_ABSTRACT, "'@JvmOverloads' annotation cannot be used on abstract methods")
map.put(OVERLOADS_INTERFACE, "'@JvmOverloads' annotation cannot be used on interface methods")
map.put(OVERLOADS_PRIVATE, "'@JvmOverloads' annotation has no effect on private declarations")
map.put(OVERLOADS_LOCAL, "'@JvmOverloads' annotation cannot be used on local declarations")
map.put(
OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR,
"'@JvmOverloads' annotation cannot be used on constructors of annotation classes"
)
map.put(DEPRECATED_JAVA_ANNOTATION, "This annotation is deprecated in Kotlin. Use ''@{0}'' instead", TO_STRING)
map.put(JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, "''@JvmPackageName'' annotation value cannot be empty")
map.put(
JVM_PACKAGE_NAME_MUST_BE_VALID_NAME,
"''@JvmPackageName'' annotation value must be a valid dot-qualified name of a package"
)
map.put(
JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES,
"''@JvmPackageName'' annotation is not supported for files with class declarations"
)
map.put(
SUPER_CALL_WITH_DEFAULT_PARAMETERS,
"Super-calls with default arguments are not allowed. Please specify all arguments of ''super.{0}'' explicitly",
TO_STRING
)
}
}
}

View File

@@ -19,6 +19,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
get() = _qualifiedAccessCheckers
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
get() = _qualifiedAccessExpressionCheckers
override val callCheckers: Set<FirCallChecker>
get() = _callCheckers
override val functionCallCheckers: Set<FirFunctionCallChecker>
get() = _functionCallCheckers
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
@@ -73,6 +75,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
private val _qualifiedAccessExpressionCheckers: MutableSet<FirQualifiedAccessExpressionChecker> = mutableSetOf()
private val _callCheckers: MutableSet<FirCallChecker> = mutableSetOf()
private val _functionCallCheckers: MutableSet<FirFunctionCallChecker> = mutableSetOf()
private val _variableAssignmentCheckers: MutableSet<FirVariableAssignmentChecker> = mutableSetOf()
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = mutableSetOf()
@@ -104,6 +107,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
_basicExpressionCheckers += checkers.basicExpressionCheckers
_qualifiedAccessCheckers += checkers.qualifiedAccessCheckers
_qualifiedAccessExpressionCheckers += checkers.qualifiedAccessExpressionCheckers
_callCheckers += checkers.callCheckers
_functionCallCheckers += checkers.functionCallCheckers
_variableAssignmentCheckers += checkers.variableAssignmentCheckers
_tryExpressionCheckers += checkers.tryExpressionCheckers

View File

@@ -20,6 +20,7 @@ abstract class ExpressionCheckers {
open val basicExpressionCheckers: Set<FirBasicExpressionChecker> = emptySet()
open val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker> = emptySet()
open val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> = emptySet()
open val callCheckers: Set<FirCallChecker> = emptySet()
open val functionCallCheckers: Set<FirFunctionCallChecker> = emptySet()
open val variableAssignmentCheckers: Set<FirVariableAssignmentChecker> = emptySet()
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
@@ -49,7 +50,8 @@ abstract class ExpressionCheckers {
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> by lazy { basicExpressionCheckers }
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> by lazy { qualifiedAccessCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> by lazy { qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
@CheckersComponentInternal internal val allCallCheckers: Set<FirCallChecker> by lazy { callCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers }
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> by lazy { variableAssignmentCheckers + qualifiedAccessCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> by lazy { tryExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allWhenExpressionCheckers: Set<FirWhenExpressionChecker> by lazy { whenExpressionCheckers + basicExpressionCheckers }
@@ -58,20 +60,20 @@ abstract class ExpressionCheckers {
@CheckersComponentInternal internal val allLogicExpressionCheckers: Set<FirLogicExpressionChecker> by lazy { logicExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allReturnExpressionCheckers: Set<FirReturnExpressionChecker> by lazy { returnExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allBlockCheckers: Set<FirBlockChecker> by lazy { blockCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> by lazy { annotationCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allCheckNotNullCallCheckers: Set<FirCheckNotNullCallChecker> by lazy { checkNotNullCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> by lazy { annotationCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allCheckNotNullCallCheckers: Set<FirCheckNotNullCallChecker> by lazy { checkNotNullCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allElvisExpressionCheckers: Set<FirElvisExpressionChecker> by lazy { elvisExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allGetClassCallCheckers: Set<FirGetClassCallChecker> by lazy { getClassCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allGetClassCallCheckers: Set<FirGetClassCallChecker> by lazy { getClassCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allSafeCallExpressionCheckers: Set<FirSafeCallExpressionChecker> by lazy { safeCallExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> by lazy { equalityOperatorCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> by lazy { stringConcatenationCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> by lazy { equalityOperatorCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> by lazy { stringConcatenationCallCheckers + callCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allResolvedQualifierCheckers: Set<FirResolvedQualifierChecker> by lazy { resolvedQualifierCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allConstExpressionCheckers: Set<FirConstExpressionChecker> by lazy { constExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allCallableReferenceAccessCheckers: Set<FirCallableReferenceAccessChecker> by lazy { callableReferenceAccessCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
@CheckersComponentInternal internal val allThisReceiverExpressionCheckers: Set<FirThisReceiverExpressionChecker> by lazy { thisReceiverExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
@CheckersComponentInternal internal val allWhileLoopCheckers: Set<FirWhileLoopChecker> by lazy { whileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allDoWhileLoopCheckers: Set<FirDoWhileLoopChecker> by lazy { doWhileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allArrayOfCallCheckers: Set<FirArrayOfCallChecker> by lazy { arrayOfCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allArrayOfCallCheckers: Set<FirArrayOfCallChecker> by lazy { arrayOfCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allClassReferenceExpressionCheckers: Set<FirClassReferenceExpressionChecker> by lazy { classReferenceExpressionCheckers + basicExpressionCheckers }
}

View File

@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirCall
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
@@ -42,6 +43,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
typealias FirBasicExpressionChecker = FirExpressionChecker<FirStatement>
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccess>
typealias FirQualifiedAccessExpressionChecker = FirExpressionChecker<FirQualifiedAccessExpression>
typealias FirCallChecker = FirExpressionChecker<FirCall>
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>

View File

@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@@ -253,19 +255,20 @@ object FirErrors {
// Modifiers
val INAPPLICABLE_INFIX_MODIFIER by error0<PsiElement>()
val REPEATED_MODIFIER by error1<PsiElement, String>()
val REDUNDANT_MODIFIER by error2<PsiElement, String, String>()
val DEPRECATED_MODIFIER by warning2<PsiElement, String, String>()
val DEPRECATED_MODIFIER_PAIR by error2<PsiElement, String, String>()
val DEPRECATED_MODIFIER_FOR_TARGET by warning2<PsiElement, String, String>()
val REDUNDANT_MODIFIER_FOR_TARGET by warning2<PsiElement, String, String>()
val INCOMPATIBLE_MODIFIERS by error2<PsiElement, String, String>()
val REPEATED_MODIFIER by error1<PsiElement, KtModifierKeywordToken>()
val REDUNDANT_MODIFIER by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER by warning2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER_PAIR by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER_FOR_TARGET by warning2<PsiElement, KtModifierKeywordToken, String>()
val REDUNDANT_MODIFIER_FOR_TARGET by warning2<PsiElement, KtModifierKeywordToken, String>()
val INCOMPATIBLE_MODIFIERS by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val REDUNDANT_OPEN_IN_INTERFACE by warning0<KtModifierListOwner>(SourceElementPositioningStrategies.OPEN_MODIFIER)
val WRONG_MODIFIER_TARGET by error2<PsiElement, String, String>()
val WRONG_MODIFIER_TARGET by error2<PsiElement, KtModifierKeywordToken, String>()
val OPERATOR_MODIFIER_REQUIRED by error2<PsiElement, FirNamedFunctionSymbol, String>()
val INFIX_MODIFIER_REQUIRED by error1<PsiElement, FirNamedFunctionSymbol>()
val WRONG_MODIFIER_CONTAINING_DECLARATION by error2<PsiElement, String, String>()
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning2<PsiElement, String, String>()
val WRONG_MODIFIER_CONTAINING_DECLARATION by error2<PsiElement, KtModifierKeywordToken, String>()
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning2<PsiElement, KtModifierKeywordToken, String>()
val INAPPLICABLE_OPERATOR_MODIFIER by error1<PsiElement, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER)
// Inline classes
val INLINE_CLASS_NOT_TOP_LEVEL by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
@@ -305,6 +308,8 @@ object FirErrors {
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error1<KtElement, String>()
val SPREAD_OF_NULLABLE by error0<PsiElement>(SourceElementPositioningStrategies.SPREAD_OPERATOR)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
// Ambiguity
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -577,6 +582,8 @@ object FirErrors {
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error0<KtExpression>(SourceElementPositioningStrategies.OPERATOR)
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error2<KtExpression, FirNamedFunctionSymbol, String>(SourceElementPositioningStrategies.OPERATOR)
// Type alias
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
@@ -646,7 +653,4 @@ object FirErrors {
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>()
// jvm
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
}

View File

@@ -45,6 +45,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
get() = setOf(
FirFunctionNameChecker,
FirFunctionTypeParametersSyntaxChecker,
FirOperatorModifierChecker,
)
override val propertyCheckers: Set<FirPropertyChecker>

View File

@@ -45,12 +45,19 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirSuspendCallChecker,
)
override val callCheckers: Set<FirCallChecker>
get() = setOf(
FirNamedVarargChecker,
)
override val functionCallCheckers: Set<FirFunctionCallChecker>
get() = setOf(
FirConventionFunctionCallChecker,
FirDivisionByZeroChecker,
FirConstructorCallChecker,
FirSpreadOfNullableChecker
FirSpreadOfNullableChecker,
FirAssignmentOperatorCallChecker,
FirNamedVarargChecker,
)
override val tryExpressionCheckers: Set<FirTryExpressionChecker>

View File

@@ -16,8 +16,11 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.resolve.SessionHolder
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
@@ -578,7 +581,11 @@ fun checkTypeMismatch(
rValueType = lValueType
lValueType = tempType
}
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
if (rValueType.isUnit) {
reporter.reportOn(source, FirErrors.INC_DEC_SHOULD_NOT_RETURN_UNIT, context)
} else {
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
}
}
else -> {
reporter.reportOn(source, FirErrors.ASSIGNMENT_TYPE_MISMATCH, lValueType, rValueType, context)

View File

@@ -1,51 +0,0 @@
/*
* 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 licensedot/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.resolve.KeywordType
fun getKeywordType(modifier: FirModifier<*>): KeywordType {
return ktKeywordToKeywordTypeMap[modifier.token]!!
}
private val ktKeywordToKeywordTypeMap: Map<KtKeywordToken, KeywordType> = mapOf(
INNER_KEYWORD to KeywordType.Inner,
OVERRIDE_KEYWORD to KeywordType.Override,
PUBLIC_KEYWORD to KeywordType.Public,
PROTECTED_KEYWORD to KeywordType.Protected,
INTERNAL_KEYWORD to KeywordType.Internal,
PRIVATE_KEYWORD to KeywordType.Private,
COMPANION_KEYWORD to KeywordType.Companion,
FINAL_KEYWORD to KeywordType.Final,
VARARG_KEYWORD to KeywordType.Vararg,
ENUM_KEYWORD to KeywordType.Enum,
ABSTRACT_KEYWORD to KeywordType.Abstract,
OPEN_KEYWORD to KeywordType.Open,
SEALED_KEYWORD to KeywordType.Sealed,
IN_KEYWORD to KeywordType.In,
OUT_KEYWORD to KeywordType.Out,
REIFIED_KEYWORD to KeywordType.Reified,
LATEINIT_KEYWORD to KeywordType.Lateinit,
DATA_KEYWORD to KeywordType.Data,
INLINE_KEYWORD to KeywordType.Inline,
NOINLINE_KEYWORD to KeywordType.Noinline,
TAILREC_KEYWORD to KeywordType.Tailrec,
SUSPEND_KEYWORD to KeywordType.Suspend,
EXTERNAL_KEYWORD to KeywordType.External,
ANNOTATION_KEYWORD to KeywordType.Annotation,
CROSSINLINE_KEYWORD to KeywordType.Crossinline,
CONST_KEYWORD to KeywordType.Const,
OPERATOR_KEYWORD to KeywordType.Operator,
INFIX_KEYWORD to KeywordType.Infix,
HEADER_KEYWORD to KeywordType.Header,
IMPL_KEYWORD to KeywordType.Impl,
EXPECT_KEYWORD to KeywordType.Expect,
ACTUAL_KEYWORD to KeywordType.Actual,
FUN_KEYWORD to KeywordType.Fun,
VALUE_KEYWORD to KeywordType.Value
)

View File

@@ -29,7 +29,7 @@ object FirConstPropertyChecker : FirPropertyChecker() {
if (declaration.isVar) {
val constModifier = declaration.getModifier(KtTokens.CONST_KEYWORD)
constModifier?.let {
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token.toString(), "vars", context)
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token, "vars", context)
}
}

View File

@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.resolve.*
object FirModifierChecker : FirBasicDeclarationChecker() {
@@ -87,10 +89,10 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
}
if (secondModifier !in reportedNodes) {
val modifierSource = secondModifier.source
val modifierType = getKeywordType(secondModifier)
val modifier = secondModifier.token
when {
!checkTarget(modifierSource, modifierType, actualTargets, parent, context, reporter) -> reportedNodes += secondModifier
!checkParent(modifierSource, modifierType, actualParents, context, reporter) -> reportedNodes += secondModifier
!checkTarget(modifierSource, modifier, actualTargets, parent, context, reporter) -> reportedNodes += secondModifier
!checkParent(modifierSource, modifier, actualParents, context, reporter) -> reportedNodes += secondModifier
}
}
}
@@ -104,21 +106,21 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
owner: FirDeclaration?,
context: CheckerContext
) {
val firstModifierType = getKeywordType(firstModifier)
val secondModifierType = getKeywordType(secondModifier)
when (val compatibilityType = compatibility(firstModifierType, secondModifierType)) {
val firstModifierToken = firstModifier.token
val secondModifierToken = secondModifier.token
when (val compatibilityType = compatibility(firstModifierToken, secondModifierToken)) {
Compatibility.COMPATIBLE -> {
}
Compatibility.REPEATED ->
if (reportedNodes.add(secondModifier)) {
reporter.reportOn(secondModifier.source, FirErrors.REPEATED_MODIFIER, secondModifierType.render(), context)
reporter.reportOn(secondModifier.source, FirErrors.REPEATED_MODIFIER, secondModifierToken, context)
}
Compatibility.REDUNDANT -> {
reporter.reportOn(
secondModifier.source,
FirErrors.REDUNDANT_MODIFIER,
secondModifierType.render(),
firstModifierType.render(),
secondModifierToken,
firstModifierToken,
context
)
}
@@ -126,8 +128,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
reporter.reportOn(
firstModifier.source,
FirErrors.REDUNDANT_MODIFIER,
firstModifierType.render(),
secondModifierType.render(),
firstModifierToken,
secondModifierToken,
context
)
}
@@ -135,15 +137,15 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
reporter.reportOn(
firstModifier.source,
FirErrors.DEPRECATED_MODIFIER_PAIR,
firstModifierType.render(),
secondModifierType.render(),
firstModifierToken,
secondModifierToken,
context
)
reporter.reportOn(
secondModifier.source,
FirErrors.DEPRECATED_MODIFIER_PAIR,
secondModifierType.render(),
firstModifierType.render(),
secondModifierToken,
firstModifierToken,
context
)
}
@@ -155,8 +157,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
reporter.reportOn(
firstModifier.source,
FirErrors.INCOMPATIBLE_MODIFIERS,
firstModifierType.render(),
secondModifierType.render(),
firstModifierToken,
secondModifierToken,
context
)
}
@@ -164,8 +166,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
reporter.reportOn(
secondModifier.source,
FirErrors.INCOMPATIBLE_MODIFIERS,
secondModifierType.render(),
firstModifierType.render(),
secondModifierToken,
firstModifierToken,
context
)
}
@@ -175,19 +177,19 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
private fun checkTarget(
modifierSource: FirSourceElement,
modifierType: KeywordType,
modifierToken: KtModifierKeywordToken,
actualTargets: List<KotlinTarget>,
parent: FirDeclaration?,
context: CheckerContext,
reporter: DiagnosticReporter
): Boolean {
fun checkModifier(factory: FirDiagnosticFactory2<String, String>): Boolean {
fun checkModifier(factory: FirDiagnosticFactory2<KtModifierKeywordToken, String>): Boolean {
val map = when (factory) {
FirErrors.WRONG_MODIFIER_TARGET -> possibleTargetMap
FirErrors.DEPRECATED_MODIFIER_FOR_TARGET -> deprecatedTargetMap
else -> redundantTargetMap
}
val set = map[modifierType] ?: emptySet()
val set = map[modifierToken] ?: emptySet()
val checkResult = if (factory == FirErrors.WRONG_MODIFIER_TARGET) {
actualTargets.none { it in set }
} else {
@@ -197,7 +199,7 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
reporter.reportOn(
modifierSource,
factory,
modifierType.render(),
modifierToken,
actualTargets.firstOrThis(),
context
)
@@ -211,19 +213,19 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
}
if (parent is FirRegularClass) {
if (modifierType == KeywordType.Expect || modifierType == KeywordType.Header) {
reporter.reportOn(modifierSource, FirErrors.WRONG_MODIFIER_TARGET, modifierType.render(), "nested class", context)
if (modifierToken == KtTokens.EXPECT_KEYWORD || modifierToken == KtTokens.HEADER_KEYWORD) {
reporter.reportOn(modifierSource, FirErrors.WRONG_MODIFIER_TARGET, modifierToken, "nested class", context)
return false
}
}
val deprecatedModifierReplacement = deprecatedModifierMap[modifierType]
val deprecatedModifierReplacement = deprecatedModifierMap[modifierToken]
if (deprecatedModifierReplacement != null) {
reporter.reportOn(
modifierSource,
FirErrors.DEPRECATED_MODIFIER,
modifierType.render(),
deprecatedModifierReplacement.render(),
modifierToken,
deprecatedModifierReplacement,
context
)
} else if (checkModifier(FirErrors.DEPRECATED_MODIFIER_FOR_TARGET)) {
@@ -235,30 +237,30 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
private fun checkParent(
modifierSource: FirSourceElement,
modifierType: KeywordType,
modifierToken: KtModifierKeywordToken,
actualParents: List<KotlinTarget>,
context: CheckerContext,
reporter: DiagnosticReporter
): Boolean {
val deprecatedParents = deprecatedParentTargetMap[modifierType]
val deprecatedParents = deprecatedParentTargetMap[modifierToken]
if (deprecatedParents != null && actualParents.any { it in deprecatedParents }) {
reporter.reportOn(
modifierSource,
FirErrors.DEPRECATED_MODIFIER_CONTAINING_DECLARATION,
modifierType.render(),
modifierToken,
actualParents.firstOrThis(),
context
)
return true
}
val possibleParentPredicate = possibleParentTargetPredicateMap[modifierType] ?: return true
val possibleParentPredicate = possibleParentTargetPredicateMap[modifierToken] ?: return true
if (actualParents.any { possibleParentPredicate.isAllowed(it, context.session.languageVersionSettings) }) return true
reporter.reportOn(
modifierSource,
FirErrors.WRONG_MODIFIER_CONTAINING_DECLARATION,
modifierType.render(),
modifierToken,
actualParents.firstOrThis(),
context
)

View File

@@ -0,0 +1,221 @@
/*
* 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.
*/
/*
* 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.declaration
import javaslang.Function2
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.Returns
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.ValueParametersCount
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.isKProperty
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.member
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.memberOrExtension
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.noDefaultAndVarargs
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeOf
import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf
import org.jetbrains.kotlin.fir.analysis.checkers.overriddenFunctions
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.containingClass
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions.ASSIGNMENT_OPERATIONS
import org.jetbrains.kotlin.util.OperatorNameConventions.BINARY_OPERATION_NAMES
import org.jetbrains.kotlin.util.OperatorNameConventions.COMPARE_TO
import org.jetbrains.kotlin.util.OperatorNameConventions.COMPONENT_REGEX
import org.jetbrains.kotlin.util.OperatorNameConventions.CONTAINS
import org.jetbrains.kotlin.util.OperatorNameConventions.DEC
import org.jetbrains.kotlin.util.OperatorNameConventions.EQUALS
import org.jetbrains.kotlin.util.OperatorNameConventions.GET
import org.jetbrains.kotlin.util.OperatorNameConventions.GET_VALUE
import org.jetbrains.kotlin.util.OperatorNameConventions.HAS_NEXT
import org.jetbrains.kotlin.util.OperatorNameConventions.INC
import org.jetbrains.kotlin.util.OperatorNameConventions.INVOKE
import org.jetbrains.kotlin.util.OperatorNameConventions.ITERATOR
import org.jetbrains.kotlin.util.OperatorNameConventions.NEXT
import org.jetbrains.kotlin.util.OperatorNameConventions.PROVIDE_DELEGATE
import org.jetbrains.kotlin.util.OperatorNameConventions.RANGE_TO
import org.jetbrains.kotlin.util.OperatorNameConventions.SET
import org.jetbrains.kotlin.util.OperatorNameConventions.SET_VALUE
import org.jetbrains.kotlin.util.OperatorNameConventions.SIMPLE_UNARY_OPERATION_NAMES
object FirOperatorModifierChecker : FirSimpleFunctionChecker() {
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isOperator) return
//we are not interested in implicit operators from override
if (!declaration.hasModifier(KtTokens.OPERATOR_KEYWORD)) return
val checks = OperatorFunctionChecks.checksByName.getOrElse(declaration.name) {
OperatorFunctionChecks.regexChecks.find { it.first.matches(declaration.name.asString()) }?.second
}
if (checks == null) {
reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_OPERATOR_MODIFIER, "illegal function name", context)
return
}
for (check in checks) {
check.check(context, declaration)?.let { error ->
reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_OPERATOR_MODIFIER, error, context)
return
}
}
}
}
interface Check : Function2<CheckerContext, FirSimpleFunction, String?> {
override fun apply(t1: CheckerContext, t2: FirSimpleFunction): String? = check(t1, t2)
fun check(context: CheckerContext, function: FirSimpleFunction): String?
}
object Checks {
fun simple(message: String, predicate: (FirSimpleFunction) -> Boolean) = object : Check {
override fun check(context: CheckerContext, function: FirSimpleFunction): String? = message.takeIf { !predicate(function) }
}
fun full(message: String, predicate: (CheckerContext, FirSimpleFunction) -> Boolean) = object : Check {
override fun check(context: CheckerContext, function: FirSimpleFunction): String? = message.takeIf { !predicate(context, function) }
}
val memberOrExtension = simple("must be a member or an extension function") {
it.dispatchReceiverType != null || it.receiverTypeRef != null
}
val member = simple("must be a member function") {
it.dispatchReceiverType != null
}
object ValueParametersCount {
fun atLeast(n: Int) = simple("must have at least $n value parameter" + (if (n > 1) "s" else "")) {
it.valueParameters.size >= n
}
fun exactly(n: Int) = simple("must have exactly $n value parameters") {
it.valueParameters.size == n
}
val single = simple("must have a single value parameter") {
it.valueParameters.size == 1
}
val none = simple("must have no value parameters") {
it.valueParameters.isEmpty()
}
}
object Returns {
val boolean = simple("must return Boolean") {
it.returnTypeRef.isBoolean
}
val int = simple("must return Int") {
it.returnTypeRef.isInt
}
val unit = simple("must return Unit") {
it.returnTypeRef.isUnit
}
}
val noDefaultAndVarargs = simple("should not have varargs or parameters with default values") {
it.valueParameters.all { param ->
param.defaultValue == null && !param.isVararg
}
}
private val kPropertyType = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(StandardNames.FqNames.kProperty),
arrayOf(ConeStarProjection),
isNullable = false
)
val isKProperty = full("second parameter must be of type KProperty<*> or its supertype") { ctx, function ->
val paramType = function.valueParameters[1].returnTypeRef.coneType
paramType.isSupertypeOf(ctx.session.typeContext, kPropertyType)
}
}
@OptIn(ExperimentalStdlibApi::class)
object OperatorFunctionChecks {
//reimplementation of org.jetbrains.kotlin.util.OperatorChecks for FIR
val checksByName: Map<Name, List<Check>> = buildMap<Name, List<Check>> {
checkFor(GET, memberOrExtension, ValueParametersCount.atLeast(1))
checkFor(
SET,
memberOrExtension, ValueParametersCount.atLeast(2),
Checks.simple("last parameter should not have a default value or be a vararg") {
it.valueParameters.lastOrNull()?.let { param ->
param.defaultValue == null && !param.isVararg
} == true
}
)
checkFor(GET_VALUE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.atLeast(2), isKProperty)
checkFor(SET_VALUE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.atLeast(3), isKProperty)
checkFor(PROVIDE_DELEGATE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.exactly(2), isKProperty)
checkFor(INVOKE, memberOrExtension)
checkFor(CONTAINS, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs, Returns.boolean)
checkFor(ITERATOR, memberOrExtension, ValueParametersCount.none)
checkFor(NEXT, memberOrExtension, ValueParametersCount.none)
checkFor(HAS_NEXT, memberOrExtension, ValueParametersCount.none, Returns.boolean)
checkFor(RANGE_TO, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs)
checkFor(
EQUALS,
member,
Checks.full("must override ''equals()'' in Any") { ctx, function ->
val containingClass = function.containingClass()?.toFirRegularClass(ctx.session) ?: return@full true
function.overriddenFunctions(containingClass, ctx).any {
it.containingClass()?.classId?.asSingleFqName() == StandardNames.FqNames.any.toSafe()
}
}
)
checkFor(COMPARE_TO, memberOrExtension, Returns.int, ValueParametersCount.single, noDefaultAndVarargs)
checkFor(BINARY_OPERATION_NAMES, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs)
checkFor(SIMPLE_UNARY_OPERATION_NAMES, memberOrExtension, ValueParametersCount.none)
checkFor(
setOf(INC, DEC),
memberOrExtension,
Checks.full("receiver must be a supertype of the return type") { ctx, function ->
val receiver = function.dispatchReceiverType ?: function.receiverTypeRef?.coneType ?: return@full false
function.returnTypeRef.coneType.isSubtypeOf(ctx.session.typeContext, receiver)
}
)
checkFor(ASSIGNMENT_OPERATIONS, memberOrExtension, Returns.unit, ValueParametersCount.single, noDefaultAndVarargs)
}
val regexChecks: List<Pair<Regex, List<Check>>> = buildList {
checkFor(COMPONENT_REGEX, memberOrExtension, ValueParametersCount.none)
}
private fun MutableMap<Name, List<Check>>.checkFor(name: Name, vararg checks: Check) {
put(name, checks.asList())
}
private fun MutableMap<Name, List<Check>>.checkFor(names: Set<Name>, vararg checks: Check) {
names.forEach { put(it, checks.asList()) }
}
private fun MutableList<Pair<Regex, List<Check>>>.checkFor(regex: Regex, vararg checks: Check) {
add(regex to checks.asList())
}
}

View File

@@ -13,12 +13,14 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
import org.jetbrains.kotlin.fir.declarations.utils.visibility
object FirPublishedApiChecker : FirAnnotatedDeclarationChecker() {
override fun check(declaration: FirAnnotatedDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirMemberDeclaration) return
if (declaration is FirValueParameter) return
if (declaration.visibility == Visibilities.Internal) return
val annotation = declaration.getAnnotationByFqName(StandardNames.FqNames.publishedApi) ?: return
reporter.reportOn(annotation.source, FirErrors.NON_INTERNAL_PUBLISHED_API, context)

View File

@@ -0,0 +1,40 @@
/*
* 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.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
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.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin
import org.jetbrains.kotlin.fir.expressions.FirOperationNameConventions
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isUnit
object FirAssignmentOperatorCallChecker : FirFunctionCallChecker() {
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
val resolvedCallee = expression.calleeReference as? FirResolvedNamedReference ?: return
val resolvedCalleeSymbol = resolvedCallee.resolvedSymbol as? FirNamedFunctionSymbol ?: return
val resolvedCalleeName = resolvedCalleeSymbol.name
if (expression.origin != FirFunctionCallOrigin.Operator ||
resolvedCalleeName !in FirOperationNameConventions.ASSIGNMENT_NAMES
) {
return
}
if (!expression.typeRef.coneType.isUnit) {
reporter.reportOn(
expression.source,
FirErrors.ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT,
resolvedCalleeSymbol,
FirOperationNameConventions.ASSIGNMENT_NAMES[resolvedCalleeName]!!.operator,
context
)
}
}
}

View File

@@ -32,7 +32,7 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
if (!allowedSourceKinds.contains(expression.source?.kind)) return
if (expression is FirAnnotationCall) return //checked by FirDeprecatedTypeChecker
if (expression is FirAnnotationCall || expression is FirDelegatedConstructorCall) return //checked by FirDeprecatedTypeChecker
val resolvable = expression as? FirResolvable ?: return
val reference = resolvable.calleeReference as? FirResolvedNamedReference ?: return
val referencedSymbol = reference.resolvedSymbol

View File

@@ -0,0 +1,59 @@
/*
* 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.
*/
/*
* 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.expression
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
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.expressions.*
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
import org.jetbrains.kotlin.fir.types.isArrayType
object FirNamedVarargChecker : FirCallChecker() {
override fun check(expression: FirCall, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression !is FirFunctionCall && expression !is FirAnnotationCall && expression !is FirDelegatedConstructorCall) return
val isAnnotation = expression is FirAnnotationCall
val errorFactory =
if (isAnnotation) FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION
else FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION
val allowAssignArray = context.session.languageVersionSettings.supportsFeature(
if (isAnnotation) LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations
else LanguageFeature.AllowAssigningArrayElementsToVarargsInNamedFormForFunctions
)
fun checkArgument(argument: FirExpression) {
if (argument !is FirNamedArgumentExpression) return
if (argument.isSpread) return
val typeRef = argument.expression.typeRef
if (typeRef is FirErrorTypeRef) return
if (argument.expression is FirArrayOfCall) return
if (allowAssignArray && typeRef.isArrayType) return
reporter.reportOn(argument.expression.source, errorFactory, context)
}
val argumentMap = expression.argumentMapping ?: return
for ((argument, parameter) in argumentMap) {
if (!parameter.isVararg) continue
if (argument is FirVarargArgumentsExpression) {
argument.arguments.forEach(::checkArgument)
} else {
checkArgument(argument)
}
}
}
}

View File

@@ -38,7 +38,7 @@ object FirSuspendModifierChecker : FirTypeRefChecker() {
reporter.reportOn(
suspendModifier.source,
FirErrors.WRONG_MODIFIER_TARGET,
suspendModifier.token.toString(),
suspendModifier.token,
"non-functional type",
context
)

View File

@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirExpressionChecker
import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.expressions.*
@OptIn(CheckersComponentInternal::class)
@@ -137,6 +136,10 @@ class ExpressionCheckersDiagnosticComponent(
checkers.allBlockCheckers.check(block, data, reporter)
}
override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall, data: CheckerContext) {
checkers.allCallCheckers.check(delegatedConstructorCall, data, reporter)
}
private fun <E : FirStatement> Collection<FirExpressionChecker<E>>.check(
expression: E,
context: CheckerContext,

View File

@@ -64,6 +64,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_PASSED_T
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNED_VALUE_IS_NEVER_READ
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNMENT_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BACKING_FIELD_IN_INTERFACE
@@ -208,6 +211,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CAND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_FILE_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_INFIX_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_LATEINIT_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_OPERATOR_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_PARAM_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_TARGET_ON_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD
@@ -219,6 +223,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_TYPES_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCONSISTENT_TYPE_PARAMETER_BOUNDS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCONSISTENT_TYPE_PARAMETER_VALUES
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INC_DEC_SHOULD_NOT_RETURN_UNIT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFIX_MODIFIER_REQUIRED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZATION_BEFORE_DECLARATION
@@ -238,14 +243,13 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_INSID
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SUPERCLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_CHARACTERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_IF_AS_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_REFERENCE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IS_ENUM_ENTRY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.JAVA_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_ANNOTATION_CLASS_ERROR
@@ -290,9 +294,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_LOOP_LABEL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_SUPERTYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_YET_SUPPORTED_IN_INLINE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_FOR_EXPECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_YET_SUPPORTED_IN_INLINE
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_GET_METHOD
@@ -729,18 +733,19 @@ class FirDefaultErrorMessages {
// Modifiers
map.put(INAPPLICABLE_INFIX_MODIFIER, "''infix'' modifier is inapplicable on this function")
map.put(REPEATED_MODIFIER, "Repeated ''{0}''", STRING)
map.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", STRING, STRING)
map.put(DEPRECATED_MODIFIER, "Modifier ''{0}'' is deprecated, use ''{1}'' instead", STRING, STRING)
map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", STRING, STRING)
map.put(DEPRECATED_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is deprecated for ''{1}''", STRING, STRING)
map.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", STRING, STRING)
map.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", STRING, STRING)
map.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING)
map.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING)
map.put(DEPRECATED_MODIFIER, "Modifier ''{0}'' is deprecated, use ''{1}'' instead", 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(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, 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(WRONG_MODIFIER_TARGET, "Modifier ''{0}'' is not applicable to ''{1}''", STRING, STRING)
map.put(WRONG_MODIFIER_TARGET, "Modifier ''{0}'' is not applicable to ''{1}''", TO_STRING, STRING)
map.put(INFIX_MODIFIER_REQUIRED, "''infix'' modifier is required on ''{0}''", TO_STRING)
map.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", STRING, STRING)
map.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", STRING, STRING)
map.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, STRING)
map.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, STRING)
map.put(INAPPLICABLE_OPERATOR_MODIFIER, "''operator'' modifier is inapplicable on this function: {0}", STRING)
// Classes and interfaces
map.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here")
@@ -758,6 +763,8 @@ class FirDefaultErrorMessages {
map.put(NAMED_PARAMETER_NOT_FOUND, "Cannot find a parameter with this name: {0}", TO_STRING)
map.put(MANY_LAMBDA_EXPRESSION_ARGUMENTS, "Only one lambda expression is allowed outside a parenthesized argument list")
map.put(SPREAD_OF_NULLABLE, "The spread operator (*foo) may not be applied to an argument of nullable type")
map.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION, "Assigning single elements to varargs in named form is forbidden")
map.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION, "Assigning single elements to varargs in named form is forbidden")
map.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", TO_STRING, TO_STRING)
map.put(THROWABLE_TYPE_MISMATCH, "Throwable type mismatch: actual type is {0}", TO_STRING)
@@ -1471,6 +1478,13 @@ class FirDefaultErrorMessages {
RENDER_TYPE,
RENDER_TYPE
)
map.put(INC_DEC_SHOULD_NOT_RETURN_UNIT, "Functions inc(), dec() shouldn't return Unit to be used by operators ++, --")
map.put(
ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT,
"Function ''{0}'' should return Unit to be used by corresponding operator ''{1}''",
SYMBOL,
TO_STRING
)
// Type alias
map.put(TOPLEVEL_TYPEALIASES_ONLY, "Nested and local type aliases are not supported")
@@ -1597,9 +1611,6 @@ class FirDefaultErrorMessages {
)
map.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited")
// JVM
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch expected {0} but found {1}. Use explicit cast", RENDER_TYPE, RENDER_TYPE)
// Extended checkers group
map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier")
map.put(REDUNDANT_MODALITY_MODIFIER, "Redundant modality modifier")

View File

@@ -373,6 +373,9 @@ object LightTreePositioningStrategies {
val DATA_MODIFIER: LightTreePositioningStrategy =
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.DATA_KEYWORD))
val OPERATOR_MODIFIER: LightTreePositioningStrategy =
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.OPERATOR_KEYWORD))
val INLINE_PARAMETER_MODIFIER: LightTreePositioningStrategy =
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.NOINLINE_KEYWORD, KtTokens.CROSSINLINE_KEYWORD))

View File

@@ -304,4 +304,9 @@ object SourceElementPositioningStrategies {
LightTreePositioningStrategies.INLINE_PARAMETER_MODIFIER,
PositioningStrategies.INLINE_PARAMETER_MODIFIER
)
val OPERATOR_MODIFIER = SourceElementPositioningStrategy(
LightTreePositioningStrategies.OPERATOR_MODIFIER,
PositioningStrategies.OPERATOR_MODIFIER
)
}

View File

@@ -212,11 +212,10 @@ data class ConeCapturedType(
data class ConeTypeVariableType(
override val nullability: ConeNullability,
override val lookupTag: ConeClassifierLookupTag
override val lookupTag: ConeClassifierLookupTag,
override val attributes: ConeAttributes = ConeAttributes.Empty,
) : ConeLookupTagBasedType() {
override val typeArguments: Array<out ConeTypeProjection> get() = emptyArray()
override val attributes: ConeAttributes get() = ConeAttributes.Empty
}
data class ConeDefinitelyNotNullType(val original: ConeKotlinType) : ConeSimpleKotlinType(), DefinitelyNotNullTypeMarker {
@@ -227,7 +226,7 @@ data class ConeDefinitelyNotNullType(val original: ConeKotlinType) : ConeSimpleK
get() = ConeNullability.NOT_NULL
override val attributes: ConeAttributes
get() = ConeAttributes.Empty
get() = original.attributes
companion object
}

View File

@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.extensions.additionalCheckers
import org.jetbrains.kotlin.fir.analysis.jvm.diagnostics.FirJvmDefaultErrorMessages
import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers
import org.jetbrains.kotlin.fir.checkers.registerJvmCheckers
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
@@ -180,6 +181,7 @@ object FirSessionFactory {
dependenciesSymbolProvider
)
FirJvmDefaultErrorMessages.installJvmErrorMessages()
FirSessionConfigurator(this).apply {
registerCommonCheckers()
registerJvmCheckers()

View File

@@ -67,7 +67,7 @@ abstract class AbstractFirDeserializedSymbolsProvider(
private val packagePartsCache = session.firCachesFactory.createCache(::tryComputePackagePartInfos)
private val typeAliasCache = session.firCachesFactory.createCache(::findAndDeserializeTypeAlias)
private val classCache: FirCache<ClassId, FirRegularClassSymbol?, FirDeserializationContext?> =
protected val classCache: FirCache<ClassId, FirRegularClassSymbol?, FirDeserializationContext?> =
session.firCachesFactory.createCacheWithPostCompute(
createValue = { classId, context -> findAndDeserializeClass(classId, context) },
postCompute = { _, symbol, postProcessor ->
@@ -154,6 +154,9 @@ abstract class AbstractFirDeserializedSymbolsProvider(
private fun findAndDeserializeClassViaParent(classId: ClassId): FirRegularClassSymbol? {
val outerClassId = classId.outerClassId ?: return null
//This will cause cyclic cache request that is highly observable in IDE (but not in the compiler - but possible SOE bug also)
//To avoid it in IDE there is special implementation that forces load parent class before any nested class request:
//[org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSessionFactory.KotlinDeserializedJvmSymbolsProviderForIde]
getClass(outerClassId) ?: return null
return classCache.getValueIfComputed(classId)
}
@@ -180,7 +183,7 @@ abstract class AbstractFirDeserializedSymbolsProvider(
return packagePartsCache.getValue(packageFqName)
}
private fun getClass(
protected open fun getClass(
classId: ClassId,
parentContext: FirDeserializationContext? = null
): FirRegularClassSymbol? {

View File

@@ -92,18 +92,18 @@ class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext<JvmSignatur
typeContext.hasNothingInNonContravariantPosition(type)
}
private fun FirClassLikeSymbol<*>.toRegularClassSymbol(): FirRegularClassSymbol? = when (this) {
is FirRegularClassSymbol -> this
is FirTypeAliasSymbol -> {
val expandedType = fir.expandedTypeRef.coneType.fullyExpandedType(session) as? ConeClassLikeType
expandedType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol
}
else -> null
}
private fun ConeKotlinType.buildPossiblyInnerType(): PossiblyInnerConeType? {
if (this !is ConeClassLikeType) return null
return buildPossiblyInnerType(lookupTag.toSymbol(session)?.toRegularClassSymbol(), 0)
return when (val symbol = lookupTag.toSymbol(session)) {
is FirRegularClassSymbol -> buildPossiblyInnerType(symbol, 0)
is FirTypeAliasSymbol -> {
val expandedType = fullyExpandedType(session) as? ConeClassLikeType
val classSymbol = expandedType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol
classSymbol?.let { expandedType.buildPossiblyInnerType(it, 0) }
}
else -> null
}
}
private fun ConeClassLikeType.parentClassOrNull(): FirRegularClassSymbol? {

View File

@@ -217,7 +217,7 @@ class Fir2IrVisitor(
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Any?): IrElement {
val irFunction = if (simpleFunction.visibility == Visibilities.Local) {
declarationStorage.createIrFunction(
simpleFunction, irParent = conversionScope.parent(), isLocal = true
simpleFunction, irParent = conversionScope.parent(), origin = IrDeclarationOrigin.LOCAL_FUNCTION, isLocal = true
)
} else {
declarationStorage.getCachedIrFunction(simpleFunction)!!
@@ -236,7 +236,7 @@ class Fir2IrVisitor(
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?): IrElement {
return anonymousFunction.convertWithOffsets { startOffset, endOffset ->
val irFunction = declarationStorage.createIrFunction(
anonymousFunction, irParent = conversionScope.parent(), isLocal = true
anonymousFunction, irParent = conversionScope.parent(), origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA, isLocal = true
)
conversionScope.withFunction(irFunction) {
memberGenerator.convertFunctionContent(irFunction, anonymousFunction, containingClass = null)

View File

@@ -42,17 +42,17 @@ private fun leastCommonPrimitiveNumericType(t1: ConeClassLikeType, t2: ConeClass
val pt2 = t2.promoteIntegerTypeToIntIfRequired()
return when {
pt1.isDouble() || pt2.isDouble() -> PrimitiveTypes.Double
pt1.isFloat() || pt2.isFloat() -> PrimitiveTypes.Float
pt1.isLong() || pt2.isLong() -> PrimitiveTypes.Long
pt1.isInt() || pt2.isInt() -> PrimitiveTypes.Int
pt1.isDouble() || pt2.isDouble() -> StandardTypes.Double
pt1.isFloat() || pt2.isFloat() -> StandardTypes.Float
pt1.isLong() || pt2.isLong() -> StandardTypes.Long
pt1.isInt() || pt2.isInt() -> StandardTypes.Int
else -> error("Unexpected types: t1=$t1, t2=$t2")
}
}
private fun ConeClassLikeType.promoteIntegerTypeToIntIfRequired(): ConeClassLikeType =
when (lookupTag.classId) {
StandardClassIds.Byte, StandardClassIds.Short -> PrimitiveTypes.Int
StandardClassIds.Byte, StandardClassIds.Short -> StandardTypes.Int
StandardClassIds.Long, StandardClassIds.Int, StandardClassIds.Float, StandardClassIds.Double, StandardClassIds.Char -> this
else -> error("Primitive number type expected: $this")
}

View File

@@ -505,10 +505,15 @@ class CallAndReferenceGenerator(
return applyArgumentsWithReorderingIfNeeded(argumentMapping, valueParameters, substitutor, annotationMode)
}
}
// Case without argument mapping (deserialized annotation)
// TODO: support argument mapping in deserialized annotations and remove me
for ((index, argument) in call.arguments.withIndex()) {
val valueParameter = valueParameters?.get(index)
val valueParameter = when (argument) {
is FirNamedArgumentExpression -> valueParameters?.find { it.name == argument.name }
else -> null
} ?: valueParameters?.get(index)
val argumentExpression = convertArgument(argument, valueParameter, substitutor)
putValueArgument(index, argumentExpression)
putValueArgument(valueParameters?.indexOf(valueParameter)?.takeIf { it >= 0 } ?: index, argumentExpression)
}
}
} else {

View File

@@ -2390,6 +2390,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/builtinStubMethods/inheritedImplementations.kt");
}
@Test
@TestMetadata("int2IntMap.kt")
public void testInt2IntMap() throws Exception {
runTest("compiler/testData/codegen/box/builtinStubMethods/int2IntMap.kt");
}
@Test
@TestMetadata("Iterator.kt")
public void testIterator() throws Exception {
@@ -12138,6 +12144,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/functionReference.kt");
}
@Test
@TestMetadata("inline.kt")
public void testInline() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/inline.kt");
}
@Test
@TestMetadata("override.kt")
public void testOverride() throws Exception {
@@ -41754,6 +41766,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/syntheticExtensions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("firstCapitalizedProperty.kt")
public void testFirstCapitalizedProperty() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/firstCapitalizedProperty.kt");
}
@Test
@TestMetadata("fromTwoBases.kt")
public void testFromTwoBases() throws Exception {

View File

@@ -1318,6 +1318,18 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
runTest("compiler/testData/codegen/boxInline/capture/generics.kt");
}
@Test
@TestMetadata("kt48230.kt")
public void testKt48230() throws Exception {
runTest("compiler/testData/codegen/boxInline/capture/kt48230.kt");
}
@Test
@TestMetadata("kt48230_2.kt")
public void testKt48230_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/capture/kt48230_2.kt");
}
@Test
@TestMetadata("simpleCapturingInClass.kt")
public void testSimpleCapturingInClass() throws Exception {
@@ -1727,6 +1739,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/checkStaticObjectClassIsPresent.kt");
}
@Test
@TestMetadata("defaultAfterCapturing.kt")
public void testDefaultAfterCapturing() throws Exception {
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/defaultAfterCapturing.kt");
}
@Test
@TestMetadata("defaultCallInDefaultLambda.kt")
public void testDefaultCallInDefaultLambda() throws Exception {
@@ -1841,6 +1859,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/receiverClashInClass2.kt");
}
@Test
@TestMetadata("reordering.kt")
public void testReordering() throws Exception {
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/reordering.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
@@ -1958,6 +1982,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/callableReferences/constuctorReference.kt");
}
@Test
@TestMetadata("defaultAfterBoundReference.kt")
public void testDefaultAfterBoundReference() throws Exception {
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/callableReferences/defaultAfterBoundReference.kt");
}
@Test
@TestMetadata("differentInvokeSignature.kt")
public void testDifferentInvokeSignature() throws Exception {

View File

@@ -36,7 +36,7 @@ import java.nio.file.Path
import java.nio.file.Paths
@ThreadSafeMutableState
class KotlinDeserializedJvmSymbolsProvider(
open class KotlinDeserializedJvmSymbolsProvider(
session: FirSession,
moduleDataProvider: ModuleDataProvider,
kotlinScopeProvider: FirKotlinScopeProvider,

View File

@@ -66,11 +66,22 @@ class JavaOverrideChecker internal constructor(
candidateTypeRef: FirTypeRef,
baseTypeRef: FirTypeRef,
substitutor: ConeSubstitutor
) = isEqualTypes(
candidateTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
baseTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
substitutor
)
): Boolean {
val candidateType = candidateTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack)
val baseType = baseTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack)
if (candidateType.isPrimitiveInJava() != baseType.isPrimitiveInJava()) return false
return isEqualTypes(
candidateType,
baseType,
substitutor
)
}
private fun ConeKotlinType.isPrimitiveInJava(): Boolean = with(context) {
!isNullableType() && CompilerConeAttributes.EnhancedNullability !in attributes && isPrimitiveOrNullablePrimitive
}
private fun isEqualArrayElementTypeProjections(
candidateTypeProjection: ConeTypeProjection,

View File

@@ -28,6 +28,8 @@ object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
if (name.isSpecial) return emptyList()
val identifier = name.identifier
if (identifier.isEmpty()) return emptyList()
val firstChar = identifier[0]
if (!firstChar.isJavaIdentifierStart() || firstChar in 'A'..'Z') return emptyList()
val result = ArrayList<Name>(3)
val standardName = Name.identifier(GETTER_PREFIX + identifier.capitalizeAsciiOnly())
val length = identifier.length

View File

@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneType
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
private val RETENTION_CLASS_ID = ClassId.fromString("kotlin/annotation/Retention")
private val TARGET_CLASS_ID = ClassId.fromString("kotlin/annotation/Target")
@@ -97,6 +99,10 @@ fun FirAnnotationContainer.getAnnotationByFqName(fqName: FqName): FirAnnotationC
}
}
fun <D> FirBasedSymbol<out D>.getAnnotationByFqName(fqName: FqName): FirAnnotationCall? where D : FirAnnotationContainer, D : FirDeclaration {
return fir.getAnnotationByFqName(fqName)
}
fun FirAnnotationContainer.getAnnotationsByFqName(fqName: FqName): List<FirAnnotationCall> = annotations.getAnnotationsByFqName(fqName)
fun List<FirAnnotationCall>.getAnnotationsByFqName(fqName: FqName): List<FirAnnotationCall> {
@@ -120,3 +126,8 @@ fun FirAnnotationCall.findArgumentByName(name: Name): FirExpression? {
// TODO: this line is still needed. However it should be replaced with 'return null'
return arguments.singleOrNull()
}
fun FirAnnotationCall.getStringArgument(name: Name): String? =
findArgumentByName(name)?.let { expression ->
expression.safeAs<FirConstExpression<*>>()?.value as? String
}

View File

@@ -90,11 +90,6 @@ private fun FirBasedSymbol<*>.getDeprecationForCallSite(
return (deprecations ?: EmptyDeprecationsPerUseSite).forUseSite(*sites)
}
private fun FirAnnotationCall.getStringArgument(name: Name): String? =
findArgumentByName(name)?.let { expression ->
expression.safeAs<FirConstExpression<*>>()?.value as? String
}
private fun FirAnnotationCall.getVersionFromArgument(name: Name): ApiVersion? =
getStringArgument(name)?.let { ApiVersion.parse(it) }

View File

@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.originalIfFakeOverride
import org.jetbrains.kotlin.fir.originalOrSelf
import org.jetbrains.kotlin.fir.references.FirThisReference
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -184,7 +186,7 @@ class VariableStorage(private val session: FirSession) {
property.isVar -> PropertyStability.MUTABLE_PROPERTY
property.receiverTypeRef != null -> PropertyStability.PROPERTY_WITH_GETTER
property.getter.let { it != null && it !is FirDefaultPropertyAccessor } -> PropertyStability.PROPERTY_WITH_GETTER
property.moduleData.session != session -> PropertyStability.ALIEN_PUBLIC_PROPERTY
property.originalOrSelf().moduleData.session != session -> PropertyStability.ALIEN_PUBLIC_PROPERTY
property.modality != Modality.FINAL -> {
val dispatchReceiver = (originalFir.unwrapElement() as? FirQualifiedAccess)?.dispatchReceiver ?: return null
val receiverType = dispatchReceiver.typeRef.coneTypeSafe<ConeClassLikeType>()?.fullyExpandedType(session) ?: return null

View File

@@ -84,7 +84,10 @@ abstract class AbstractConeSubstitutor(private val typeContext: ConeTypeContext)
}
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeKotlinType? {
val substituted = substituteOrNull(original)?.withNullability(ConeNullability.NOT_NULL, typeContext) ?: return null
val substituted = substituteOrNull(original)
?.withNullability(ConeNullability.NOT_NULL, typeContext)
?.withAttributes(original.attributes, typeContext)
?: return null
return ConeDefinitelyNotNullType.create(substituted, typeContext) ?: substituted
}

View File

@@ -75,6 +75,7 @@ class FirStatusResolver(
ProcessorAction.NEXT
}
}.map {
it.ensureResolved(FirResolvePhase.STATUS)
it.status as FirResolvedDeclarationStatus
}
}

View File

@@ -1148,7 +1148,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
anonymousObjectExpression.transformAnonymousObject(transformer, data)
if (anonymousObjectExpression.typeRef !is FirResolvedTypeRef) {
anonymousObjectExpression.resultType = buildResolvedTypeRef {
source = anonymousObjectExpression.source
source = anonymousObjectExpression.source?.fakeElement(FirFakeSourceElementKind.ImplicitTypeRef)
this.type = anonymousObjectExpression.anonymousObject.defaultType()
}
}

View File

@@ -13,8 +13,8 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
@@ -110,6 +110,13 @@ fun <T : ConeKotlinType> T.withAttributes(attributes: ConeAttributes, typeSystem
lowerBound.withAttributes(attributes, typeSystemContext),
upperBound.withAttributes(attributes, typeSystemContext)
)
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag, attributes)
is ConeCapturedType -> ConeCapturedType(
captureStatus, lowerType, nullability, constructor, attributes, isProjectionNotNull,
)
// TODO: Consider correct application of attributes to ConeIntersectionType
// Currently, ConeAttributes.union works a bit strange, because it lefts only `other` parts
is ConeIntersectionType -> this
else -> error("Not supported: $this: ${this.render()}")
} as T
}

View File

@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.StandardClassIds
object PrimitiveTypes {
object StandardTypes {
val Boolean: ConeClassLikeType = StandardClassIds.Boolean.createType()
val Char: ConeClassLikeType = StandardClassIds.Char.createType()
val Byte: ConeClassLikeType = StandardClassIds.Byte.createType()
@@ -23,6 +23,8 @@ object PrimitiveTypes {
val Long: ConeClassLikeType = StandardClassIds.Long.createType()
val Float: ConeClassLikeType = StandardClassIds.Float.createType()
val Double: ConeClassLikeType = StandardClassIds.Double.createType()
val Any: ConeClassLikeType = StandardClassIds.Any.createType()
}
private fun ClassId.createType(): ConeClassLikeType =

View File

@@ -60,6 +60,7 @@ object FirOperationNameConventions {
FirOperation.REM_ASSIGN to OperatorNameConventions.REM_ASSIGN
)
)
val ASSIGNMENT_NAMES = ASSIGNMENTS.map { (k, v) -> v to k }.toMap()
val ASSIGNMENTS_TO_SIMPLE_OPERATOR: Map<FirOperation, Name> = EnumMap(
mapOf(

View File

@@ -40,6 +40,7 @@ val FirTypeRef.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing
val FirTypeRef.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
val FirTypeRef.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
val FirTypeRef.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
val FirTypeRef.isInt: Boolean get() = isBuiltinType(StandardClassIds.Int, false)
val FirTypeRef.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
val FirTypeRef.isArrayType: Boolean
get() =

View File

@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.StandardNames.FqNames
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
object ArrayFqNames {
@@ -20,5 +22,20 @@ object ArrayFqNames {
PrimitiveType.DOUBLE to Name.identifier("doubleArrayOf")
)
val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
}
val UNSIGNED_TYPE_TO_ARRAY: Map<FqName, Name> = hashMapOf(
FqNames.uByteFqName to Name.identifier("ubyteArrayOf"),
FqNames.uShortFqName to Name.identifier("ushortArrayOf"),
FqNames.uIntFqName to Name.identifier("uintArrayOf"),
FqNames.uLongFqName to Name.identifier("ulongArrayOf")
)
val ARRAY_OF_FUNCTION: Name = Name.identifier("arrayOf")
val EMPTY_ARRAY: Name = Name.identifier("emptyArray")
val ARRAY_CALL_NAMES: Set<Name> =
setOf(ARRAY_OF_FUNCTION, EMPTY_ARRAY) + PRIMITIVE_TYPE_TO_ARRAY.values.toSet() + UNSIGNED_TYPE_TO_ARRAY.values.toSet()
@JvmField
val ARRAY_CALL_FQ_NAMES: Set<FqName> = ARRAY_CALL_NAMES.map { FqName("kotlin." + it.identifier) }.toSet()
}

View File

@@ -224,7 +224,7 @@ public interface Errors {
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken> REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> WRONG_MODIFIER_TARGET = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken> DEPRECATED_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> REDUNDANT_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
DiagnosticFactory0<KtDeclaration> NO_EXPLICIT_VISIBILITY_IN_API_MODE = DiagnosticFactory0.create(ERROR, DECLARATION_START_TO_NAME);
DiagnosticFactory0<KtNamedDeclaration> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE = DiagnosticFactory0.create(ERROR, DECLARATION_NAME);

View File

@@ -377,6 +377,9 @@ object PositioningStrategies {
@JvmField
val DATA_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.DATA_KEYWORD)
@JvmField
val OPERATOR_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OPERATOR_KEYWORD)
@JvmField
val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {

View File

@@ -16,13 +16,13 @@
package org.jetbrains.kotlin.resolve;
import kotlin.collections.SetsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.builtins.UnsignedTypes;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtParameter;
import org.jetbrains.kotlin.psi.KtPsiUtil;
@@ -39,33 +39,16 @@ import org.jetbrains.kotlin.types.TypeProjection;
import org.jetbrains.kotlin.types.TypeUtils;
import java.util.List;
import java.util.Set;
import static org.jetbrains.kotlin.diagnostics.Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER;
import static org.jetbrains.kotlin.diagnostics.Errors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER;
import static org.jetbrains.kotlin.resolve.ArrayFqNames.ARRAY_CALL_FQ_NAMES;
import static org.jetbrains.kotlin.resolve.BindingContext.VALUE_PARAMETER;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isAnnotationClass;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass;
public class CompileTimeConstantUtils {
private final static Set<String> ARRAY_CALL_NAMES = SetsKt.hashSetOf(
"kotlin.arrayOf",
"kotlin.doubleArrayOf",
"kotlin.floatArrayOf",
"kotlin.longArrayOf",
"kotlin.intArrayOf",
"kotlin.charArrayOf",
"kotlin.shortArrayOf",
"kotlin.byteArrayOf",
"kotlin.booleanArrayOf",
"kotlin.emptyArray",
"kotlin.ubyteArrayOf",
"kotlin.ushortArrayOf",
"kotlin.uintArrayOf",
"kotlin.ulongArrayOf"
);
public static void checkConstructorParametersType(@NotNull List<KtParameter> parameters, @NotNull BindingTrace trace) {
for (KtParameter parameter : parameters) {
VariableDescriptor parameterDescriptor = trace.getBindingContext().get(VALUE_PARAMETER, parameter);
@@ -121,7 +104,10 @@ public class CompileTimeConstantUtils {
}
public static boolean isArrayFunctionCall(@NotNull ResolvedCall<?> resolvedCall) {
return ARRAY_CALL_NAMES.contains(DescriptorUtils.getFqName(resolvedCall.getCandidateDescriptor()).asString());
FqNameUnsafe unsafe = DescriptorUtils.getFqName(resolvedCall.getCandidateDescriptor());
// If the fully qualified name is unsafe, i.e., contains < or >, it shouldn't be any of `arrayOf` calls.
if (!unsafe.isSafe()) return false;
return ARRAY_CALL_FQ_NAMES.contains(unsafe.toSafe());
}
public static boolean canBeReducedToBooleanConstant(

View File

@@ -13,55 +13,15 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtModifierList
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.resolve.KeywordType.*
import org.jetbrains.kotlin.resolve.KeywordType.Annotation
import org.jetbrains.kotlin.resolve.calls.checkers.checkCoroutinesFeature
object ModifierCheckerCore {
private val ktKeywordToKeywordTypeMap: Map<KtKeywordToken, KeywordType> = mapOf(
INNER_KEYWORD to Inner,
OVERRIDE_KEYWORD to Override,
PUBLIC_KEYWORD to Public,
PROTECTED_KEYWORD to Protected,
INTERNAL_KEYWORD to Internal,
PRIVATE_KEYWORD to Private,
COMPANION_KEYWORD to KeywordType.Companion,
FINAL_KEYWORD to Final,
VARARG_KEYWORD to Vararg,
ENUM_KEYWORD to KeywordType.Enum,
ABSTRACT_KEYWORD to Abstract,
OPEN_KEYWORD to Open,
SEALED_KEYWORD to Sealed,
IN_KEYWORD to In,
OUT_KEYWORD to Out,
REIFIED_KEYWORD to Reified,
LATEINIT_KEYWORD to Lateinit,
DATA_KEYWORD to Data,
INLINE_KEYWORD to Inline,
NOINLINE_KEYWORD to Noinline,
TAILREC_KEYWORD to Tailrec,
SUSPEND_KEYWORD to Suspend,
EXTERNAL_KEYWORD to External,
ANNOTATION_KEYWORD to Annotation,
CROSSINLINE_KEYWORD to Crossinline,
CONST_KEYWORD to Const,
OPERATOR_KEYWORD to Operator,
INFIX_KEYWORD to Infix,
HEADER_KEYWORD to Header,
IMPL_KEYWORD to Impl,
EXPECT_KEYWORD to Expect,
ACTUAL_KEYWORD to Actual,
FUN_KEYWORD to Fun,
VALUE_KEYWORD to Value
)
fun check(
listOwner: KtModifierListOwner,
trace: BindingTrace,
@@ -123,10 +83,9 @@ object ModifierCheckerCore {
owner: PsiElement,
incorrectNodes: MutableSet<ASTNode>
) {
val (firstModifier, firstModifierType) = getModifierAndModifierType(firstNode)
val (secondModifier, secondModifierType) = getModifierAndModifierType(secondNode)
when (val compatibility = compatibility(firstModifierType, secondModifierType)) {
val firstModifier = firstNode.elementType as KtModifierKeywordToken
val secondModifier = secondNode.elementType as KtModifierKeywordToken
when (val compatibility = compatibility(firstModifier, secondModifier)) {
Compatibility.COMPATIBLE -> {
}
Compatibility.REPEATED -> if (incorrectNodes.add(secondNode)) {
@@ -156,19 +115,19 @@ object ModifierCheckerCore {
// Should return false if error is reported, true otherwise
private fun checkTarget(trace: BindingTrace, node: ASTNode, actualTargets: List<KotlinTarget>): Boolean {
val (modifier, modifierType) = getModifierAndModifierType(node)
val modifier = node.elementType as KtModifierKeywordToken
val possibleTargets = possibleTargetMap[modifierType] ?: emptySet()
val possibleTargets = possibleTargetMap[modifier] ?: emptySet()
if (!actualTargets.any { it in possibleTargets }) {
trace.report(Errors.WRONG_MODIFIER_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
return false
}
val deprecatedModifierReplacement = deprecatedModifierMap[modifierType]
val deprecatedTargets = deprecatedTargetMap[modifierType] ?: emptySet()
val redundantTargets = redundantTargetMap[modifierType] ?: emptySet()
val deprecatedModifierReplacement = deprecatedModifierMap[modifier]
val deprecatedTargets = deprecatedTargetMap[modifier] ?: emptySet()
val redundantTargets = redundantTargetMap[modifier] ?: emptySet()
when {
deprecatedModifierReplacement != null ->
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement.render()))
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement))
actualTargets.any { it in deprecatedTargets } ->
trace.report(
Errors.DEPRECATED_MODIFIER_FOR_TARGET.on(
@@ -196,7 +155,7 @@ object ModifierCheckerCore {
parentDescriptor: DeclarationDescriptor?,
languageVersionSettings: LanguageVersionSettings
): Boolean {
val (modifier, modifierType) = getModifierAndModifierType(node)
val modifier = node.elementType as KtModifierKeywordToken
val actualParents: List<KotlinTarget> = when (parentDescriptor) {
is ClassDescriptor -> KotlinTarget.classActualTargets(
@@ -210,7 +169,7 @@ object ModifierCheckerCore {
is FunctionDescriptor -> KotlinTarget.FUNCTION_LIST
else -> KotlinTarget.FILE_LIST
}
val deprecatedParents = deprecatedParentTargetMap[modifierType]
val deprecatedParents = deprecatedParentTargetMap[modifier]
if (deprecatedParents != null && actualParents.any { it in deprecatedParents }) {
trace.report(
Errors.DEPRECATED_MODIFIER_CONTAINING_DECLARATION.on(
@@ -221,7 +180,7 @@ object ModifierCheckerCore {
)
return true
}
val possibleParentPredicate = possibleParentTargetPredicateMap[modifierType] ?: return true
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) return true
trace.report(
Errors.WRONG_MODIFIER_CONTAINING_DECLARATION.on(
@@ -239,9 +198,9 @@ object ModifierCheckerCore {
languageVersionSettings: LanguageVersionSettings,
actualTargets: List<KotlinTarget>
): Boolean {
val (_, modifierType) = getModifierAndModifierType(node)
val modifier = node.elementType as KtModifierKeywordToken
val dependencies = featureDependencies[modifierType] ?: return true
val dependencies = featureDependencies[modifier] ?: return true
for (dependency in dependencies) {
val restrictedTargets = featureDependenciesTargets[dependency]
if (restrictedTargets != null && actualTargets.intersect(restrictedTargets).isEmpty()) {
@@ -282,9 +241,4 @@ object ModifierCheckerCore {
return true
}
private fun getModifierAndModifierType(node: ASTNode): Pair<KtModifierKeywordToken, KeywordType> {
val modifier = node.elementType as KtModifierKeywordToken
return Pair(modifier, ktKeywordToKeywordTypeMap[modifier]!!)
}
}

View File

@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
@@ -23,6 +25,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
// `doRemove` means should expect-declaration be removed from IR
@OptIn(ObsoleteDescriptorBasedAPI::class)
@@ -100,10 +103,11 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
// the `actual fun` or `actual constructor` for this may be in a different module.
// Nothing we can do with those.
// TODO they may not actually have the defaults though -- may be a frontend bug.
val expectFunction = function.findExpectForActual()
val expectParameter = expectFunction?.valueParameters?.get(index) ?: return
val expectFunction =
function.descriptor.findExpectForActual().safeAs<FunctionDescriptor>()?.let { symbolTable.referenceFunction(it).owner }
?: return
val defaultValue = expectParameter.defaultValue ?: return
val defaultValue = expectFunction.valueParameters[index].defaultValue ?: return
val expectToActual = expectFunction to function
if (expectToActual !in typeParameterSubstitutionMap) {
@@ -129,30 +133,19 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
}
}
private fun IrFunction.findActualForExpected(): IrFunction? =
descriptor.findActualForExpect()?.let { symbolTable.referenceFunction(it).owner }
private fun IrFunction.findExpectForActual(): IrFunction? =
descriptor.findExpectForActual()?.let { symbolTable.referenceFunction(it).owner }
private fun IrClass.findActualForExpected(): IrClass? =
descriptor.findActualForExpect()?.let { symbolTable.referenceClass(it).owner }
private inline fun <reified T : MemberDescriptor> T.findActualForExpect() = with(ExpectedActualResolver) {
val descriptor = this@findActualForExpect
if (!descriptor.isExpect) error(this)
findCompatibleActualForExpected(descriptor.module).singleOrNull()
} as T?
private inline fun <reified T : MemberDescriptor> T.findExpectForActual() = with(ExpectedActualResolver) {
val descriptor = this@findExpectForActual
if (!descriptor.isActual) error(this) else {
findCompatibleExpectedForActual(descriptor.module).singleOrNull()
private fun MemberDescriptor.findActualForExpect(): MemberDescriptor? {
if (!isExpect) error(this)
return with(ExpectedActualResolver) {
findCompatibleActualForExpected(this@findActualForExpect.module).singleOrNull()
}
} as T?
}
private fun MemberDescriptor.findExpectForActual(): MemberDescriptor? {
if (!isActual) error(this)
return with(ExpectedActualResolver) {
findCompatibleExpectedForActual(this@findExpectForActual.module).singleOrNull()
}
}
private fun IrExpression.remapExpectValueSymbols(): IrExpression {
return this.transform(object : IrElementTransformerVoid() {
@@ -179,22 +172,25 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
}
val parameter = symbol.owner
val parent = parameter.parent
return when (parent) {
return when (val parent = parameter.parent) {
is IrClass -> {
assert(parameter == parent.thisReceiver)
parent.findActualForExpected()!!.thisReceiver!!
symbolTable.referenceClass(parent.descriptor.findActualForExpect() as ClassDescriptor).owner.thisReceiver!!
}
is IrFunction -> when (parameter) {
parent.dispatchReceiverParameter ->
parent.findActualForExpected()!!.dispatchReceiverParameter!!
parent.extensionReceiverParameter ->
parent.findActualForExpected()!!.extensionReceiverParameter!!
else -> {
assert(parent.valueParameters[parameter.index] == parameter)
parent.findActualForExpected()!!.valueParameters[parameter.index]
is IrFunction -> {
val actualFunction =
symbolTable.referenceFunction(parent.descriptor.findActualForExpect() as FunctionDescriptor).owner
when (parameter) {
parent.dispatchReceiverParameter ->
actualFunction.dispatchReceiverParameter!!
parent.extensionReceiverParameter ->
actualFunction.extensionReceiverParameter!!
else -> {
assert(parent.valueParameters[parameter.index] == parameter)
actualFunction.valueParameters[parameter.index]
}
}
}

View File

@@ -121,8 +121,12 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
input.files.clear()
input.files.addAll(filesAndStates.map { (irFile, _) -> irFile }.toMutableList())
// Some remappers in handleDeepCopy depend on entries in remappedFunctions inserted by adjustDefaultArgumentStubs.
adjustDefaultArgumentStubs(context, remappedFunctions)
context.handleDeepCopy(remappedFiles, remappedClasses, remappedFunctions)
// and some entries in adjustDefaultArgumentStubs depend on those inserted by handleDeepCopy, so we need to repeat the call.
adjustDefaultArgumentStubs(context, remappedFunctions)
input.transformChildrenVoid(CrossFileCallAdjuster(remappedFunctions))
}

View File

@@ -54,7 +54,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.Method
import java.io.File
import java.util.concurrent.ConcurrentHashMap
interface MetadataSerializer {
fun serialize(metadata: MetadataSource): Pair<MessageLite, JvmStringTable>?
@@ -335,7 +334,7 @@ class ClassCodegen private constructor(
}
}
private val generatedInlineMethods = ConcurrentHashMap<IrFunction, SMAPAndMethodNode>()
private val generatedInlineMethods = mutableMapOf<IrFunction, SMAPAndMethodNode>()
fun generateMethodNode(method: IrFunction): SMAPAndMethodNode {
if (!method.isInline && !method.isSuspendCapturingCrossinline()) {
@@ -501,7 +500,7 @@ class ClassCodegen private constructor(
it.origin == JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER
},
): ClassCodegen =
context.classCodegens.getOrPut(irClass) { ClassCodegen(irClass, context, parentFunction) }.also {
context.classCodegens.computeIfAbsent(irClass) { ClassCodegen(irClass, context, parentFunction) }.also {
assert(parentFunction == null || it.parentFunction == parentFunction) {
"inconsistent parent function for ${irClass.render()}:\n" +
"New: ${parentFunction!!.render()}\n" +

View File

@@ -1159,6 +1159,11 @@ class ExpressionCodegen(
override fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): PromisedValue {
jump.markLineNumber(startOffset = true)
// Make sure that the line number has an instruction so that the debugger can always
// break on the break/continue. As an example, unwindBlockStack could otherwise
// generate a new line number immediately which would lead to the line number for
// the break/continue being ignored.
mv.nop()
val endLabel = Label()
val stackElement = unwindBlockStack(endLabel, data) { it.loop == jump.loop }
if (stackElement == null) {

View File

@@ -377,7 +377,7 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
// the result is called 'view', just to be consistent with old backend.
private fun IrSimpleFunction.suspendFunctionViewOrStub(context: JvmBackendContext): IrSimpleFunction {
if (!isSuspend) return this
return context.suspendFunctionOriginalToView.getOrPut(suspendFunctionOriginal()) { createSuspendFunctionStub(context) }
return context.suspendFunctionOriginalToView.getOrPut(this) { createSuspendFunctionStub(context) }
}
internal fun IrSimpleFunction.suspendFunctionOriginal(): IrSimpleFunction =

View File

@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
private val removedFunctions = hashMapOf<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>()
private val removedFunctionsWithoutRemapping = mutableSetOf<IrSimpleFunctionSymbol>()
override fun lower(irClass: IrClass) {
if (!irClass.isJvmInterface) return
@@ -50,7 +51,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
}
irClass.declarations.removeAll {
it is IrFunction && removedFunctions.containsKey(it.symbol)
it is IrFunction && (removedFunctions.containsKey(it.symbol) || removedFunctionsWithoutRemapping.contains(it.symbol))
}
val defaultImplsIrClass = context.cachedDeclarations.getDefaultImplsClass(irClass)
@@ -131,9 +132,17 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
(function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_OR_TYPEALIAS_ANNOTATIONS &&
(isCompatibilityMode || jvmDefaultMode == JvmDefaultMode.ENABLE) &&
function.isCompiledToJvmDefault(jvmDefaultMode)) -> {
val defaultImpl = createDefaultImpl(function)
defaultImpl.body = function.moveBodyTo(defaultImpl)
removedFunctions[function.symbol] = defaultImpl.symbol
if (function.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || function.origin == IrDeclarationOrigin.LOCAL_FUNCTION) {
//move as is
val defaultImplsClass = context.cachedDeclarations.getDefaultImplsClass(irClass)
defaultImplsClass.declarations.add(function)
removedFunctionsWithoutRemapping.add(function.symbol)
function.parent = defaultImplsClass
} else {
val defaultImpl = createDefaultImpl(function)
defaultImpl.body = function.moveBodyTo(defaultImpl)
removedFunctions[function.symbol] = defaultImpl.symbol
}
}
/**

View File

@@ -39,11 +39,15 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
constructor(context: GeneratorContext) : this(DeclarationGenerator(context))
fun generateFunctionDeclaration(ktFunction: KtNamedFunction): IrSimpleFunction =
@JvmOverloads
fun generateFunctionDeclaration(
ktFunction: KtNamedFunction,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrSimpleFunction =
declareSimpleFunction(
ktFunction,
ktFunction.receiverTypeReference,
IrDeclarationOrigin.DEFINED,
origin,
getOrFail(BindingContext.FUNCTION, ktFunction)
) {
ktFunction.bodyExpression?.let { generateFunctionBody(it) }

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl
import org.jetbrains.kotlin.psi.KtLambdaExpression
@@ -53,5 +54,5 @@ class LocalFunctionGenerator(statementGenerator: StatementGenerator) : Statement
}
private fun generateFunctionDeclaration(ktFun: KtNamedFunction) =
FunctionGenerator(context).generateFunctionDeclaration(ktFun)
FunctionGenerator(context).generateFunctionDeclaration(ktFun, IrDeclarationOrigin.LOCAL_FUNCTION)
}

View File

@@ -49,6 +49,7 @@ interface IrDeclarationOrigin {
object SCRIPT_RESULT_PROPERTY : IrDeclarationOriginImpl("SCRIPT_RESULT_PROPERTY")
object GENERATED_DATA_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_DATA_CLASS_MEMBER")
object GENERATED_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_INLINE_CLASS_MEMBER")
object LOCAL_FUNCTION : IrDeclarationOriginImpl("LOCAL_FUNCTION")
object LOCAL_FUNCTION_FOR_LAMBDA : IrDeclarationOriginImpl("LOCAL_FUNCTION_FOR_LAMBDA")
object CATCH_PARAMETER : IrDeclarationOriginImpl("CATCH_PARAMETER")
object INSTANCE_RECEIVER : IrDeclarationOriginImpl("INSTANCE_RECEIVER")

View File

@@ -67,6 +67,7 @@ class SignatureIdNotFoundInModuleWithDependencies(
allModules = allModules,
problemModuleIds = setOf(problemModuleId),
problemCause = "This module requires symbol ${idSignature.render()}",
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
)
}
@@ -113,6 +114,7 @@ class SymbolTypeMismatch(
potentiallyConflictingDependencies = findPotentiallyConflictingIncomingDependencies(
problemModuleId = declaringModuleId,
allModules = allModules,
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
),
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
)
@@ -125,6 +127,7 @@ class SymbolTypeMismatch(
problemCause = "This module contains ${
idSignature?.render()?.let { "symbol $it" } ?: "a symbol"
} that is the cause of the conflict",
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
)
}
@@ -159,6 +162,7 @@ private fun StringBuilder.appendProjectDependencies(
allModules: Map<ResolvedDependencyId, ResolvedDependency>,
problemModuleIds: Set<ResolvedDependencyId>,
problemCause: String,
sourceCodeModuleId: ResolvedDependencyId,
moduleIdComparator: Comparator<ResolvedDependencyId>
) {
append("\n\nProject dependencies:")
@@ -195,8 +199,7 @@ private fun StringBuilder.appendProjectDependencies(
append('\n').append(data.regularLinePrefix)
append(module.id)
val incomingDependencyId: ResolvedDependencyId = parentData?.incomingDependencyId
?: ResolvedDependencyId.SOURCE_CODE_MODULE_ID
val incomingDependencyId: ResolvedDependencyId = parentData?.incomingDependencyId ?: sourceCodeModuleId
val requestedVersion: ResolvedDependencyVersion = module.requestedVersionsByIncomingDependencies.getValue(incomingDependencyId)
if (!requestedVersion.isEmpty() || !module.selectedVersion.isEmpty()) {
append(": ")
@@ -240,8 +243,7 @@ private fun StringBuilder.appendProjectDependencies(
}
// Find first-level dependencies. I.e. the modules that the source code module directly depends on.
val firstLevelDependencies: Collection<ResolvedDependency> =
incomingDependencyIdToDependencies.getValue(ResolvedDependencyId.SOURCE_CODE_MODULE_ID)
val firstLevelDependencies: Collection<ResolvedDependency> = incomingDependencyIdToDependencies.getValue(sourceCodeModuleId)
renderModules(firstLevelDependencies, parentData = null)
@@ -257,9 +259,9 @@ private class Data(val parent: Data?, val incomingDependencyId: ResolvedDependen
get() {
return generateSequence(this) { it.parent }.map {
if (it === this) {
if (it.isLast) "\u2514\u2500\u2500\u2500 " /* └─── */ else "\u251C\u2500\u2500\u2500 " /* ├─── */
if (it.isLast) "\\--- " else "+--- "
} else {
if (it.isLast) " " else "\u2502 " /* │ */
if (it.isLast) " " else "| "
}
}.toList().asReversed().joinToString(separator = "")
}
@@ -267,7 +269,7 @@ private class Data(val parent: Data?, val incomingDependencyId: ResolvedDependen
val errorLinePrefix: String
get() {
return generateSequence(this) { it.parent }.map {
if (it.isLast) " " else "\u2502 " /* │ */
if (it.isLast) " " else "| "
}.toList().asReversed().joinToString(separator = "")
}
}
@@ -375,7 +377,8 @@ private fun findPotentiallyConflictingOutgoingDependencies(
*/
private fun findPotentiallyConflictingIncomingDependencies(
problemModuleId: ResolvedDependencyId,
allModules: Map<ResolvedDependencyId, ResolvedDependency>
allModules: Map<ResolvedDependencyId, ResolvedDependency>,
sourceCodeModuleId: ResolvedDependencyId
): Map<ResolvedDependencyId, PotentialConflictDescription> {
val dependencyStatesMap: MutableMap<ResolvedDependencyId, MutableSet<DependencyState>> = mutableMapOf()
@@ -384,7 +387,7 @@ private fun findPotentiallyConflictingIncomingDependencies(
val module = allModules.findMatchingModule(moduleId)
module.requestedVersionsByIncomingDependencies.forEach { (incomingDependencyId, requestedVersion) ->
if (incomingDependencyId == ResolvedDependencyId.SOURCE_CODE_MODULE_ID) return@forEach
if (incomingDependencyId == sourceCodeModuleId) return@forEach
val dependencyState: DependencyState = when {
aboveConflictingDependency -> {

View File

@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.uniqueName
import org.jetbrains.kotlin.utils.*
open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader: ExternalDependenciesLoader) {
open class UserVisibleIrModulesSupport(externalDependenciesLoader: ExternalDependenciesLoader) {
/**
* Load external [ResolvedDependency]s provided by the build system. These dependencies:
* - all have [ResolvedDependency.selectedVersion] specified
@@ -23,24 +23,24 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
* not visible to the build system
*/
interface ExternalDependenciesLoader {
fun load(): Collection<ResolvedDependency>
fun load(): ResolvedDependencies
companion object {
val EMPTY = object : ExternalDependenciesLoader {
override fun load(): Collection<ResolvedDependency> = emptyList()
override fun load(): ResolvedDependencies = ResolvedDependencies.EMPTY
}
fun from(externalDependenciesFile: File?, onMalformedExternalDependencies: (String) -> Unit): ExternalDependenciesLoader =
if (externalDependenciesFile != null)
object : ExternalDependenciesLoader {
override fun load(): Collection<ResolvedDependency> {
override fun load(): ResolvedDependencies {
return if (externalDependenciesFile.exists) {
// Deserialize external dependencies from the [externalDependenciesFile].
val externalDependenciesText = String(externalDependenciesFile.readBytes())
ResolvedDependenciesSupport.deserialize(externalDependenciesText) { lineNo, line ->
onMalformedExternalDependencies("Malformed external dependencies at $externalDependenciesFile:$lineNo: $line")
}
} else emptyList()
} else ResolvedDependencies.EMPTY
}
}
else
@@ -48,6 +48,16 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
}
}
private val externalDependencies: ResolvedDependencies by lazy {
externalDependenciesLoader.load()
}
private val externalDependencyModules: Collection<ResolvedDependency>
get() = externalDependencies.modules
val sourceCodeModuleId: ResolvedDependencyId
get() = externalDependencies.sourceCodeModuleId
fun getUserVisibleModuleId(deserializer: IrModuleDeserializer): ResolvedDependencyId {
val nameFromMetadataModuleHeader: String = deserializer.moduleFragment.name.asStringStripSpecialMarkers()
val nameFromKlibManifest: String? = deserializer.kotlinLibrary?.uniqueName
@@ -65,23 +75,30 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
* (and therefore are missing in [ExternalDependenciesLoader.load]) but are provided by the compiler. For Kotlin/Native such
* libraries are stdlib, endorsed and platform libraries.
*/
protected open fun modulesFromDeserializers(deserializers: Collection<IrModuleDeserializer>): Map<ResolvedDependencyId, ResolvedDependency> {
val modules: Map<ResolvedDependencyId, ModuleWithUninitializedDependencies> = deserializers.associate { deserializer ->
protected open fun modulesFromDeserializers(
deserializers: Collection<IrModuleDeserializer>,
excludedModuleIds: Set<ResolvedDependencyId>
): Map<ResolvedDependencyId, ResolvedDependency> {
val modules: Map<ResolvedDependencyId, ModuleWithUninitializedDependencies> = deserializers.mapNotNull { deserializer ->
val moduleId = getUserVisibleModuleId(deserializer)
if (moduleId in excludedModuleIds) return@mapNotNull null
val module = ResolvedDependency(
id = moduleId,
// TODO: support extracting all the necessary details for non-Native libs: selectedVersion, requestedVersions, artifacts
selectedVersion = ResolvedDependencyVersion.EMPTY,
// Assumption: As we don't know for sure which modules the source code module depends on directly and which modules
// it depends on transitively, so let's assume it depends on all modules directly.
requestedVersionsByIncomingDependencies = mutableMapOf(ResolvedDependencyId.SOURCE_CODE_MODULE_ID to ResolvedDependencyVersion.EMPTY),
requestedVersionsByIncomingDependencies = mutableMapOf(
ResolvedDependencyId.DEFAULT_SOURCE_CODE_MODULE_ID to ResolvedDependencyVersion.EMPTY
),
artifactPaths = mutableSetOf()
)
val outgoingDependencyIds = deserializer.moduleDependencies.map { getUserVisibleModuleId(it) }
moduleId to ModuleWithUninitializedDependencies(module, outgoingDependencyIds)
}
}.toMap()
// Stamp dependencies.
return modules.stampDependenciesWithRequestedVersionEqualToSelectedVersion()
@@ -91,9 +108,6 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
* The result of the merge of [ExternalDependenciesLoader.load] and [modulesFromDeserializers].
*/
protected fun mergedModules(deserializers: Collection<IrModuleDeserializer>): MutableMap<ResolvedDependencyId, ResolvedDependency> {
// First, load external dependencies.
val externalDependencyModules: Collection<ResolvedDependency> = externalDependenciesLoader.load()
val externalDependencyModulesByNames: Map</* unique name */ String, ResolvedDependency> =
mutableMapOf<String, ResolvedDependency>().apply {
externalDependencyModules.forEach { externalDependency ->
@@ -118,7 +132,10 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
val providedModules = mutableListOf<ResolvedDependency>()
// Next, merge external dependencies with dependencies from deserializers.
modulesFromDeserializers(deserializers).forEach { (moduleId, module) ->
modulesFromDeserializers(
deserializers = deserializers,
excludedModuleIds = setOf(sourceCodeModuleId)
).forEach { (moduleId, module) ->
val externalDependencyModule = findMatchingExternalDependencyModule(moduleId)
if (externalDependencyModule != null) {
// Just add missing dependencies to the same module in [mergedModules].
@@ -146,7 +163,7 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
// Just keep the module as is. If it has no incoming dependencies, then treat it as
// the first-level dependency module (i.e. the module that only the source code module depends on).
if (module.requestedVersionsByIncomingDependencies.isEmpty()) {
module.requestedVersionsByIncomingDependencies[ResolvedDependencyId.SOURCE_CODE_MODULE_ID] = module.selectedVersion
module.requestedVersionsByIncomingDependencies[sourceCodeModuleId] = module.selectedVersion
}
}

View File

@@ -0,0 +1,366 @@
/*
* 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.resolve
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens.*
import java.util.*
enum class Compatibility {
// modifier pair is compatible: ok (default)
COMPATIBLE,
// second is redundant to first: warning
REDUNDANT,
// first is redundant to second: warning
REVERSE_REDUNDANT,
// error
REPEATED,
// pair is deprecated, will become incompatible: warning
DEPRECATED,
// pair is incompatible: error
INCOMPATIBLE,
// same but only for functions / properties: error
COMPATIBLE_FOR_CLASSES_ONLY
}
val compatibilityTypeMap = hashMapOf<Pair<KtKeywordToken, KtKeywordToken>, Compatibility>()
fun compatibility(first: KtKeywordToken, second: KtKeywordToken): Compatibility {
return if (first == second) {
Compatibility.REPEATED
} else {
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
}
}
// First modifier in pair should be also first in declaration
private val mutualCompatibility = buildCompatibilityMap()
private fun buildCompatibilityMap(): Map<Pair<KtKeywordToken, KtKeywordToken>, Compatibility> {
val result = hashMapOf<Pair<KtKeywordToken, KtKeywordToken>, Compatibility>()
// Variance: in + out are incompatible
result += incompatibilityRegister(IN_KEYWORD, OUT_KEYWORD)
// Visibilities: incompatible
result += incompatibilityRegister(PRIVATE_KEYWORD, PROTECTED_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD)
// Abstract + open + final + sealed: incompatible
result += incompatibilityRegister(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD, SEALED_KEYWORD)
// data + open, data + inner, data + abstract, data + sealed, data + inline, data + value
result += incompatibilityRegister(DATA_KEYWORD, OPEN_KEYWORD)
result += incompatibilityRegister(DATA_KEYWORD, INNER_KEYWORD)
result += incompatibilityRegister(DATA_KEYWORD, ABSTRACT_KEYWORD)
result += incompatibilityRegister(DATA_KEYWORD, SEALED_KEYWORD)
result += incompatibilityRegister(DATA_KEYWORD, INLINE_KEYWORD)
result += incompatibilityRegister(DATA_KEYWORD, VALUE_KEYWORD)
// open is redundant to abstract & override
result += redundantRegister(ABSTRACT_KEYWORD, OPEN_KEYWORD)
// abstract is redundant to sealed
result += redundantRegister(SEALED_KEYWORD, ABSTRACT_KEYWORD)
// const is incompatible with abstract, open, override
result += incompatibilityRegister(CONST_KEYWORD, ABSTRACT_KEYWORD)
result += incompatibilityRegister(CONST_KEYWORD, OPEN_KEYWORD)
result += incompatibilityRegister(CONST_KEYWORD, OVERRIDE_KEYWORD)
// private is incompatible with override
result += incompatibilityRegister(PRIVATE_KEYWORD, OVERRIDE_KEYWORD)
// private is compatible with open / abstract only for classes
result += compatibilityForClassesRegister(PRIVATE_KEYWORD, OPEN_KEYWORD)
result += compatibilityForClassesRegister(PRIVATE_KEYWORD, ABSTRACT_KEYWORD)
result += incompatibilityRegister(CROSSINLINE_KEYWORD, NOINLINE_KEYWORD)
// 1. subclasses contained inside a sealed class can not be instantiated, because their constructors needs
// an instance of an outer sealed (effectively abstract) class
// 2. subclasses of a non-top-level sealed class must be declared inside the class
// (see the KEEP https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md)
result += incompatibilityRegister(SEALED_KEYWORD, INNER_KEYWORD)
// header / expect / impl / actual are all incompatible
result += incompatibilityRegister(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD, ACTUAL_KEYWORD)
return result
}
private fun incompatibilityRegister(vararg list: KtKeywordToken): Map<Pair<KtKeywordToken, KtKeywordToken>, Compatibility> {
return compatibilityRegister(Compatibility.INCOMPATIBLE, *list)
}
private fun redundantRegister(
sufficient: KtKeywordToken,
redundant: KtKeywordToken
): Map<Pair<KtKeywordToken, KtKeywordToken>, Compatibility> {
return mapOf(
Pair(sufficient, redundant) to Compatibility.REDUNDANT,
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT
)
}
private fun compatibilityForClassesRegister(vararg list: KtKeywordToken) =
compatibilityRegister(Compatibility.COMPATIBLE_FOR_CLASSES_ONLY, *list)
private fun compatibilityRegister(
compatibility: Compatibility, vararg list: KtKeywordToken
): Map<Pair<KtKeywordToken, KtKeywordToken>, Compatibility> {
val result = hashMapOf<Pair<KtKeywordToken, KtKeywordToken>, Compatibility>()
for (first in list) {
for (second in list) {
if (first != second) {
result[Pair(first, second)] = compatibility
}
}
}
return result
}
val featureDependencies = mapOf(
SUSPEND_KEYWORD to listOf(LanguageFeature.Coroutines),
INLINE_KEYWORD to listOf(LanguageFeature.InlineProperties, LanguageFeature.InlineClasses),
HEADER_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
IMPL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables),
FUN_KEYWORD to listOf(LanguageFeature.FunctionalInterfaceConversion)
)
val featureDependenciesTargets = mapOf(
LanguageFeature.InlineProperties to setOf(KotlinTarget.PROPERTY, KotlinTarget.PROPERTY_GETTER, KotlinTarget.PROPERTY_SETTER),
LanguageFeature.LateinitLocalVariables to setOf(KotlinTarget.LOCAL_VARIABLE),
LanguageFeature.LateinitTopLevelProperties to setOf(KotlinTarget.TOP_LEVEL_PROPERTY),
LanguageFeature.InlineClasses to setOf(KotlinTarget.CLASS_ONLY),
LanguageFeature.JvmInlineValueClasses to setOf(KotlinTarget.CLASS_ONLY),
LanguageFeature.FunctionalInterfaceConversion to setOf(KotlinTarget.INTERFACE)
)
val defaultVisibilityTargets: EnumSet<KotlinTarget> = EnumSet.of(
KotlinTarget.CLASS_ONLY, KotlinTarget.OBJECT, KotlinTarget.INTERFACE, KotlinTarget.ENUM_CLASS, KotlinTarget.ANNOTATION_CLASS,
KotlinTarget.MEMBER_FUNCTION, KotlinTarget.TOP_LEVEL_FUNCTION, KotlinTarget.PROPERTY_GETTER, KotlinTarget.PROPERTY_SETTER,
KotlinTarget.MEMBER_PROPERTY, KotlinTarget.TOP_LEVEL_PROPERTY, KotlinTarget.CONSTRUCTOR, KotlinTarget.TYPEALIAS
)
val possibleTargetMap = mapOf(
ENUM_KEYWORD to EnumSet.of(KotlinTarget.ENUM_CLASS),
ABSTRACT_KEYWORD to EnumSet.of(
KotlinTarget.CLASS_ONLY,
KotlinTarget.LOCAL_CLASS,
KotlinTarget.INTERFACE,
KotlinTarget.MEMBER_PROPERTY,
KotlinTarget.MEMBER_FUNCTION
),
OPEN_KEYWORD to EnumSet.of(
KotlinTarget.CLASS_ONLY,
KotlinTarget.LOCAL_CLASS,
KotlinTarget.INTERFACE,
KotlinTarget.MEMBER_PROPERTY,
KotlinTarget.MEMBER_FUNCTION
),
FINAL_KEYWORD to EnumSet.of(
KotlinTarget.CLASS_ONLY,
KotlinTarget.LOCAL_CLASS,
KotlinTarget.ENUM_CLASS,
KotlinTarget.OBJECT,
KotlinTarget.MEMBER_PROPERTY,
KotlinTarget.MEMBER_FUNCTION
),
SEALED_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.INTERFACE),
INNER_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY),
OVERRIDE_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_PROPERTY, KotlinTarget.MEMBER_FUNCTION),
PRIVATE_KEYWORD to defaultVisibilityTargets,
PUBLIC_KEYWORD to defaultVisibilityTargets,
INTERNAL_KEYWORD to defaultVisibilityTargets,
PROTECTED_KEYWORD to EnumSet.of(
KotlinTarget.CLASS_ONLY,
KotlinTarget.OBJECT,
KotlinTarget.INTERFACE,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ANNOTATION_CLASS,
KotlinTarget.MEMBER_FUNCTION,
KotlinTarget.PROPERTY_GETTER,
KotlinTarget.PROPERTY_SETTER,
KotlinTarget.MEMBER_PROPERTY,
KotlinTarget.CONSTRUCTOR,
KotlinTarget.TYPEALIAS
),
IN_KEYWORD to EnumSet.of(KotlinTarget.TYPE_PARAMETER, KotlinTarget.TYPE_PROJECTION),
OUT_KEYWORD to EnumSet.of(KotlinTarget.TYPE_PARAMETER, KotlinTarget.TYPE_PROJECTION),
REIFIED_KEYWORD to EnumSet.of(KotlinTarget.TYPE_PARAMETER),
VARARG_KEYWORD to EnumSet.of(KotlinTarget.VALUE_PARAMETER, KotlinTarget.PROPERTY_PARAMETER),
COMPANION_KEYWORD to EnumSet.of(KotlinTarget.OBJECT),
LATEINIT_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_PROPERTY, KotlinTarget.TOP_LEVEL_PROPERTY, KotlinTarget.LOCAL_VARIABLE),
DATA_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS),
INLINE_KEYWORD to EnumSet.of(
KotlinTarget.FUNCTION,
KotlinTarget.PROPERTY,
KotlinTarget.PROPERTY_GETTER,
KotlinTarget.PROPERTY_SETTER,
KotlinTarget.CLASS_ONLY
),
NOINLINE_KEYWORD to EnumSet.of(KotlinTarget.VALUE_PARAMETER),
TAILREC_KEYWORD to EnumSet.of(KotlinTarget.FUNCTION),
SUSPEND_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_FUNCTION, KotlinTarget.TOP_LEVEL_FUNCTION, KotlinTarget.LOCAL_FUNCTION),
EXTERNAL_KEYWORD to EnumSet.of(
KotlinTarget.FUNCTION,
KotlinTarget.PROPERTY,
KotlinTarget.PROPERTY_GETTER,
KotlinTarget.PROPERTY_SETTER,
KotlinTarget.CLASS
),
ANNOTATION_KEYWORD to EnumSet.of(KotlinTarget.ANNOTATION_CLASS),
CROSSINLINE_KEYWORD to EnumSet.of(KotlinTarget.VALUE_PARAMETER),
CONST_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_PROPERTY, KotlinTarget.TOP_LEVEL_PROPERTY),
OPERATOR_KEYWORD to EnumSet.of(KotlinTarget.FUNCTION),
INFIX_KEYWORD to EnumSet.of(KotlinTarget.FUNCTION),
HEADER_KEYWORD to EnumSet.of(
KotlinTarget.TOP_LEVEL_FUNCTION,
KotlinTarget.TOP_LEVEL_PROPERTY,
KotlinTarget.CLASS_ONLY,
KotlinTarget.OBJECT,
KotlinTarget.INTERFACE,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ANNOTATION_CLASS
),
IMPL_KEYWORD to EnumSet.of(
KotlinTarget.TOP_LEVEL_FUNCTION,
KotlinTarget.MEMBER_FUNCTION,
KotlinTarget.TOP_LEVEL_PROPERTY,
KotlinTarget.MEMBER_PROPERTY,
KotlinTarget.CONSTRUCTOR,
KotlinTarget.CLASS_ONLY,
KotlinTarget.OBJECT,
KotlinTarget.INTERFACE,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ANNOTATION_CLASS,
KotlinTarget.TYPEALIAS
),
EXPECT_KEYWORD to EnumSet.of(
KotlinTarget.TOP_LEVEL_FUNCTION,
KotlinTarget.TOP_LEVEL_PROPERTY,
KotlinTarget.CLASS_ONLY,
KotlinTarget.OBJECT,
KotlinTarget.INTERFACE,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ANNOTATION_CLASS
),
ACTUAL_KEYWORD to EnumSet.of(
KotlinTarget.TOP_LEVEL_FUNCTION,
KotlinTarget.MEMBER_FUNCTION,
KotlinTarget.TOP_LEVEL_PROPERTY,
KotlinTarget.MEMBER_PROPERTY,
KotlinTarget.CONSTRUCTOR,
KotlinTarget.CLASS_ONLY,
KotlinTarget.OBJECT,
KotlinTarget.INTERFACE,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ANNOTATION_CLASS,
KotlinTarget.TYPEALIAS
),
FUN_KEYWORD to EnumSet.of(KotlinTarget.INTERFACE),
VALUE_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY)
)
// NOTE: deprecated targets must be possible!
val deprecatedTargetMap = mapOf<KtKeywordToken, Set<KotlinTarget>>()
val deprecatedParentTargetMap = mapOf<KtKeywordToken, Set<KotlinTarget>>()
val deprecatedModifierMap = mapOf(
HEADER_KEYWORD to EXPECT_KEYWORD,
IMPL_KEYWORD to ACTUAL_KEYWORD
)
// NOTE: redundant targets must be possible!
val redundantTargetMap = mapOf<KtKeywordToken, Set<KotlinTarget>>(
OPEN_KEYWORD to EnumSet.of(KotlinTarget.INTERFACE)
)
interface TargetAllowedPredicate {
fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings): Boolean
}
fun always(target: KotlinTarget, vararg targets: KotlinTarget) = object : TargetAllowedPredicate {
private val targetSet = EnumSet.of(target, *targets)
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
target in targetSet
}
fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) =
object : TargetAllowedPredicate {
private val targetSet = EnumSet.of(target, *targets)
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
languageVersionSettings.supportsFeature(languageFeature) && target in targetSet
}
fun or(p1: TargetAllowedPredicate, p2: TargetAllowedPredicate) = object : TargetAllowedPredicate {
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
p1.isAllowed(target, languageVersionSettings) ||
p2.isAllowed(target, languageVersionSettings)
}
val possibleParentTargetPredicateMap = mapOf(
INNER_KEYWORD to or(
always(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS, KotlinTarget.ENUM_CLASS),
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, KotlinTarget.ENUM_ENTRY)
),
OVERRIDE_KEYWORD to always(
KotlinTarget.CLASS_ONLY,
KotlinTarget.LOCAL_CLASS,
KotlinTarget.OBJECT,
KotlinTarget.OBJECT_LITERAL,
KotlinTarget.INTERFACE,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ENUM_ENTRY
),
PROTECTED_KEYWORD to always(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS, KotlinTarget.ENUM_CLASS, KotlinTarget.COMPANION_OBJECT),
INTERNAL_KEYWORD to always(
KotlinTarget.CLASS_ONLY,
KotlinTarget.LOCAL_CLASS,
KotlinTarget.OBJECT,
KotlinTarget.OBJECT_LITERAL,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ENUM_ENTRY,
KotlinTarget.FILE
),
PRIVATE_KEYWORD to always(
KotlinTarget.CLASS_ONLY,
KotlinTarget.LOCAL_CLASS,
KotlinTarget.OBJECT,
KotlinTarget.OBJECT_LITERAL,
KotlinTarget.INTERFACE,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ENUM_ENTRY,
KotlinTarget.FILE
),
COMPANION_KEYWORD to always(
KotlinTarget.CLASS_ONLY,
KotlinTarget.INTERFACE,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ANNOTATION_CLASS
),
FINAL_KEYWORD to always(
KotlinTarget.CLASS_ONLY,
KotlinTarget.LOCAL_CLASS,
KotlinTarget.OBJECT,
KotlinTarget.OBJECT_LITERAL,
KotlinTarget.ENUM_CLASS,
KotlinTarget.ENUM_ENTRY,
KotlinTarget.ANNOTATION_CLASS,
KotlinTarget.FILE
),
VARARG_KEYWORD to always(KotlinTarget.CONSTRUCTOR, KotlinTarget.FUNCTION, KotlinTarget.CLASS)
)

View File

@@ -1,400 +0,0 @@
/*
* 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.resolve;
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
import java.util.*
import org.jetbrains.kotlin.resolve.KeywordType.*
enum class KeywordType {
Inner,
Override,
Public,
Protected,
Internal,
Private,
Companion,
Final,
Vararg,
Enum,
Abstract,
Open,
Sealed,
In,
Out,
Reified,
Lateinit,
Data,
Inline,
Noinline,
Tailrec,
Suspend,
External,
Annotation,
Crossinline,
Const,
Operator,
Infix,
Header,
Impl,
Expect,
Actual,
Fun,
Value
}
fun KeywordType.render(): String {
return toString().lowercase()
}
enum class Compatibility {
// modifier pair is compatible: ok (default)
COMPATIBLE,
// second is redundant to first: warning
REDUNDANT,
// first is redundant to second: warning
REVERSE_REDUNDANT,
// error
REPEATED,
// pair is deprecated, will become incompatible: warning
DEPRECATED,
// pair is incompatible: error
INCOMPATIBLE,
// same but only for functions / properties: error
COMPATIBLE_FOR_CLASSES_ONLY
}
val compatibilityTypeMap = hashMapOf<Pair<KeywordType, KeywordType>, Compatibility>()
fun compatibility(first: KeywordType, second: KeywordType): Compatibility {
return if (first == second) {
Compatibility.REPEATED
} else {
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
}
}
// First modifier in pair should be also first in declaration
private val mutualCompatibility = buildCompatibilityMap()
private fun buildCompatibilityMap(): Map<Pair<KeywordType, KeywordType>, Compatibility> {
val result = hashMapOf<Pair<KeywordType, KeywordType>, Compatibility>()
// Variance: in + out are incompatible
result += incompatibilityRegister(In, Out)
// Visibilities: incompatible
result += incompatibilityRegister(Private, Protected, Public, Internal)
// Abstract + open + final + sealed: incompatible
result += incompatibilityRegister(Abstract, Open, Final, Sealed)
// data + open, data + inner, data + abstract, data + sealed, data + inline, data + value
result += incompatibilityRegister(Data, Open)
result += incompatibilityRegister(Data, Inner)
result += incompatibilityRegister(Data, Abstract)
result += incompatibilityRegister(Data, Sealed)
result += incompatibilityRegister(Data, Inline)
result += incompatibilityRegister(Data, Value)
// open is redundant to abstract & override
result += redundantRegister(Abstract, Open)
// abstract is redundant to sealed
result += redundantRegister(Sealed, Abstract)
// const is incompatible with abstract, open, override
result += incompatibilityRegister(Const, Abstract)
result += incompatibilityRegister(Const, Open)
result += incompatibilityRegister(Const, Override)
// private is incompatible with override
result += incompatibilityRegister(Private, Override)
// private is compatible with open / abstract only for classes
result += compatibilityForClassesRegister(Private, Open)
result += compatibilityForClassesRegister(Private, Abstract)
result += incompatibilityRegister(Crossinline, Noinline)
// 1. subclasses contained inside a sealed class can not be instantiated, because their constructors needs
// an instance of an outer sealed (effectively abstract) class
// 2. subclasses of a non-top-level sealed class must be declared inside the class
// (see the KEEP https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md)
result += incompatibilityRegister(Sealed, Inner)
// header / expect / impl / actual are all incompatible
result += incompatibilityRegister(Header, Expect, Impl, Actual)
return result
}
private fun incompatibilityRegister(vararg list: KeywordType): Map<Pair<KeywordType, KeywordType>, Compatibility> {
return compatibilityRegister(Compatibility.INCOMPATIBLE, *list)
}
private fun redundantRegister(
sufficient: KeywordType,
redundant: KeywordType
): Map<Pair<KeywordType, KeywordType>, Compatibility> {
return mapOf(
Pair(sufficient, redundant) to Compatibility.REDUNDANT,
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT
)
}
private fun compatibilityForClassesRegister(vararg list: KeywordType) =
compatibilityRegister(Compatibility.COMPATIBLE_FOR_CLASSES_ONLY, *list)
private fun compatibilityRegister(
compatibility: Compatibility, vararg list: KeywordType
): Map<Pair<KeywordType, KeywordType>, Compatibility> {
val result = hashMapOf<Pair<KeywordType, KeywordType>, Compatibility>()
for (first in list) {
for (second in list) {
if (first != second) {
result[Pair(first, second)] = compatibility
}
}
}
return result
}
val featureDependencies = mapOf(
Suspend to listOf(LanguageFeature.Coroutines),
Inline to listOf(LanguageFeature.InlineProperties, LanguageFeature.InlineClasses),
Header to listOf(LanguageFeature.MultiPlatformProjects),
Impl to listOf(LanguageFeature.MultiPlatformProjects),
Expect to listOf(LanguageFeature.MultiPlatformProjects),
Actual to listOf(LanguageFeature.MultiPlatformProjects),
Lateinit to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables),
Fun to listOf(LanguageFeature.FunctionalInterfaceConversion)
)
val featureDependenciesTargets = mapOf(
LanguageFeature.InlineProperties to setOf(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
LanguageFeature.LateinitLocalVariables to setOf(LOCAL_VARIABLE),
LanguageFeature.LateinitTopLevelProperties to setOf(TOP_LEVEL_PROPERTY),
LanguageFeature.InlineClasses to setOf(CLASS_ONLY),
LanguageFeature.JvmInlineValueClasses to setOf(CLASS_ONLY),
LanguageFeature.FunctionalInterfaceConversion to setOf(INTERFACE)
)
val defaultVisibilityTargets: EnumSet<KotlinTarget> = EnumSet.of(
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS
)
val possibleTargetMap = mapOf(
KeywordType.Enum to EnumSet.of(ENUM_CLASS),
Abstract to EnumSet.of(
CLASS_ONLY,
LOCAL_CLASS,
INTERFACE,
MEMBER_PROPERTY,
MEMBER_FUNCTION
),
Open to EnumSet.of(
CLASS_ONLY,
LOCAL_CLASS,
INTERFACE,
MEMBER_PROPERTY,
MEMBER_FUNCTION
),
Final to EnumSet.of(
CLASS_ONLY,
LOCAL_CLASS,
ENUM_CLASS,
OBJECT,
MEMBER_PROPERTY,
MEMBER_FUNCTION
),
Sealed to EnumSet.of(CLASS_ONLY, INTERFACE),
Inner to EnumSet.of(CLASS_ONLY),
Override to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
Private to defaultVisibilityTargets,
Public to defaultVisibilityTargets,
Internal to defaultVisibilityTargets,
Protected to EnumSet.of(
CLASS_ONLY,
OBJECT,
INTERFACE,
ENUM_CLASS,
ANNOTATION_CLASS,
MEMBER_FUNCTION,
PROPERTY_GETTER,
PROPERTY_SETTER,
MEMBER_PROPERTY,
CONSTRUCTOR,
TYPEALIAS
),
In to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
Out to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
Reified to EnumSet.of(TYPE_PARAMETER),
Vararg to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
KeywordType.Companion to EnumSet.of(OBJECT),
Lateinit to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, LOCAL_VARIABLE),
Data to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
Inline to EnumSet.of(
FUNCTION,
PROPERTY,
PROPERTY_GETTER,
PROPERTY_SETTER,
CLASS_ONLY
),
Noinline to EnumSet.of(VALUE_PARAMETER),
Tailrec to EnumSet.of(FUNCTION),
Suspend to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, LOCAL_FUNCTION),
External to EnumSet.of(
FUNCTION,
PROPERTY,
PROPERTY_GETTER,
PROPERTY_SETTER,
CLASS
),
KeywordType.Annotation to EnumSet.of(ANNOTATION_CLASS), // TODO: Workaround for FIR, https://youtrack.jetbrains.com/issue/KT-48157
Crossinline to EnumSet.of(VALUE_PARAMETER),
Const to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
Operator to EnumSet.of(FUNCTION),
Infix to EnumSet.of(FUNCTION),
Header to EnumSet.of(
TOP_LEVEL_FUNCTION,
TOP_LEVEL_PROPERTY,
CLASS_ONLY,
OBJECT,
INTERFACE,
ENUM_CLASS,
ANNOTATION_CLASS
),
Impl to EnumSet.of(
TOP_LEVEL_FUNCTION,
MEMBER_FUNCTION,
TOP_LEVEL_PROPERTY,
MEMBER_PROPERTY,
CONSTRUCTOR,
CLASS_ONLY,
OBJECT,
INTERFACE,
ENUM_CLASS,
ANNOTATION_CLASS,
TYPEALIAS
),
Expect to EnumSet.of(
TOP_LEVEL_FUNCTION,
TOP_LEVEL_PROPERTY,
CLASS_ONLY,
OBJECT,
INTERFACE,
ENUM_CLASS,
ANNOTATION_CLASS
),
Actual to EnumSet.of(
TOP_LEVEL_FUNCTION,
MEMBER_FUNCTION,
TOP_LEVEL_PROPERTY,
MEMBER_PROPERTY,
CONSTRUCTOR,
CLASS_ONLY,
OBJECT,
INTERFACE,
ENUM_CLASS,
ANNOTATION_CLASS,
TYPEALIAS
),
Fun to EnumSet.of(INTERFACE),
Value to EnumSet.of(CLASS_ONLY)
)
// NOTE: deprecated targets must be possible!
val deprecatedTargetMap = mapOf<KeywordType, Set<KotlinTarget>>()
val deprecatedParentTargetMap = mapOf<KeywordType, Set<KotlinTarget>>()
val deprecatedModifierMap = mapOf(
Header to Expect,
Impl to Actual
)
// NOTE: redundant targets must be possible!
val redundantTargetMap = mapOf<KeywordType, Set<KotlinTarget>>(
Open to EnumSet.of(INTERFACE)
)
interface TargetAllowedPredicate {
fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings): Boolean
}
fun always(target: KotlinTarget, vararg targets: KotlinTarget) = object : TargetAllowedPredicate {
private val targetSet = EnumSet.of(target, *targets)
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
target in targetSet
}
fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) =
object : TargetAllowedPredicate {
private val targetSet = EnumSet.of(target, *targets)
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
languageVersionSettings.supportsFeature(languageFeature) && target in targetSet
}
fun or(p1: TargetAllowedPredicate, p2: TargetAllowedPredicate) = object : TargetAllowedPredicate {
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
p1.isAllowed(target, languageVersionSettings) ||
p2.isAllowed(target, languageVersionSettings)
}
val possibleParentTargetPredicateMap = mapOf(
Inner to or(
always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)
),
Override to always(
CLASS_ONLY,
LOCAL_CLASS,
OBJECT,
OBJECT_LITERAL,
INTERFACE,
ENUM_CLASS,
ENUM_ENTRY
),
Protected to always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, COMPANION_OBJECT),
Internal to always(
CLASS_ONLY,
LOCAL_CLASS,
OBJECT,
OBJECT_LITERAL,
ENUM_CLASS,
ENUM_ENTRY,
FILE
),
Private to always(
CLASS_ONLY,
LOCAL_CLASS,
OBJECT,
OBJECT_LITERAL,
INTERFACE,
ENUM_CLASS,
ENUM_ENTRY,
FILE
),
KeywordType.Companion to always(CLASS_ONLY, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
Final to always(
CLASS_ONLY,
LOCAL_CLASS,
OBJECT,
OBJECT_LITERAL,
ENUM_CLASS,
ENUM_ENTRY,
ANNOTATION_CLASS,
FILE
),
Vararg to always(CONSTRUCTOR, FUNCTION, CLASS)
)

View File

@@ -0,0 +1,6 @@
$TESTDATA_DIR$/firVsClassicAnnotation.kt
-classpath
$TESTDATA_DIR$/firVsClassicAnnotation
-Xuse-fir
-d
$TEMP_DIR$

View File

@@ -0,0 +1,24 @@
// Library part (build by FE 1.0)
//package lib
//
//@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD)
//annotation class Property(
// val description: String = "",
// val ignore: Boolean = false,
//
// val externalName: String = ""
//)
//
//open class LocatableRunConfigurationOptions {
// @Property(ignore = true)
// val isNameGenerated by lazy { false }
//}
// Main part
package use
import lib.LocatableRunConfigurationOptions
class JvmMainMethodRunConfigurationOptions : LocatableRunConfigurationOptions()

View File

@@ -0,0 +1,4 @@
warning: ATTENTION!
This build uses in-dev FIR:
-Xuse-fir
OK

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More