Compare commits

...

190 Commits

Author SHA1 Message Date
Nikolay Krasko
7bbb85cc0b Stop mangle common project descriptor in GenerateTestSupport tests
Use custom project descriptor instead.

Mitingate flaky failures:

ERROR: Save settings failed
java.lang.RuntimeException: java.io.IOException: Cannot save /test_path/test.ipr.
Unable to open the file for writing.
  at com.intellij.util.ExceptionUtil.rethrow(ExceptionUtil.java:116)
  at com.intellij.util.lang.CompoundRuntimeException.throwIfNotEmpty(CompoundRuntimeException.java:106)
  at com.intellij.configurationStore.SaveResult.throwIfErrored(SaveResult.kt:59)
  at com.intellij.configurationStore.ComponentStoreImpl.save$suspendImpl(ComponentStoreImpl.kt:152)
  at com.intellij.configurationStore.ComponentStoreImpl$save$1.invokeSuspend(ComponentStoreImpl.kt)
  at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
  at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
  at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
  at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
  at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
  at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
  at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
  at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
  at com.intellij.configurationStore.StoreUtil$Companion.saveSettings(storeUtil.kt:44)
  at com.intellij.configurationStore.StoreUtil.saveSettings(storeUtil.kt)
  at com.intellij.openapi.project.impl.ProjectImpl.save(ProjectImpl.java:157)
  at org.jetbrains.kotlin.idea.codeInsight.generate.AbstractGenerateTestSupportMethodActionTest$setUpTestSourceRoot$1.invoke(AbstractGenerateTestSupportMethodActionTest.kt:22)
  at org.jetbrains.kotlin.idea.codeInsight.generate.AbstractGenerateTestSupportMethodActionTest$setUpTestSourceRoot$1.invoke(AbstractGenerateTestSupportMethodActionTest.kt:20)
2020-12-07 16:46:21 +03:00
Nikolay Krasko
6d95831bdf Stable order of generation and errors in ConvertSealedClassToEnumIntention 2020-12-07 16:46:21 +03:00
Nikolay Krasko
75548c26b3 Reminder about -Pidea.fir.plugin=true for running fir-idea tests 2020-12-07 16:46:21 +03:00
Mikhael Bogdanov
b8903f8cf8 Enable kotlin-annotation-processing-cli tests on TC 2020-12-07 12:38:12 +01:00
Ivan Gavrilovic
078aa18479 Fix KAPT cli tests on windows
- Fix line separator issue
- Always quote args with delimiters (=, :)
- fix one of args files by removing obsolete stdlib reference
- Fix kotlinc.bat to ensure lazy evaluation of additional classpath
2020-12-07 12:36:59 +01:00
Ilya Goncharov
82ad230e0d [Gradle, JS] Add nodeArgs to NodeJsExec
^KT-43793 fixed
2020-12-07 13:08:47 +03:00
Jinseong Jeon
cdfe1771d9 FIR DFA: reimplement type OR operation to its original semantics
#KT-43569 Fixed
2020-12-07 10:50:19 +03:00
Jinseong Jeon
16b9312695 FIR DFA: refactor type statements manipulation 2020-12-07 10:50:19 +03:00
Jinseong Jeon
7ea58adc50 FIR: reproduce KT-43569 2020-12-07 10:50:19 +03:00
Nikita Bobko
0d8cdb7bdb Fix double registered "com.intellij.psi.classFileDecompiler" for 203 platform
This commit addresses 1243c641296e74a572a4f274df72a4cda60635c6 in intellij
In intellij they added registration of "com.intellij.psi.classFileDecompiler" in
`JavaCoreApplicationEnvironment`. And because the `KotlinCoreApplicationEnvironment` inherits
`JavaCoreApplicationEnvironment` we don't need to register this EP ourselves.

This commit fixes in 203 tests + 1.4.30 compiler:
```
java.lang.RuntimeException: Duplicate registration for EP 'com.intellij.psi.classFileDecompiler': first in com.intellij.openapi.extensions.DefaultPluginDescriptor@44f464d1, second in PluginDescriptor(name=org.jetbrains.kotlin, id=org.jetbrains.kotlin, path=/home/builduser/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-for-ide/1.4.30-M1-30/kotlin-compiler-for-ide-1.4.30-M1-30.jar, version=1.2)
	at com.intellij.openapi.components.ComponentManager.createError(ComponentManager.java:167)
	at com.intellij.openapi.extensions.impl.ExtensionsAreaImpl.registerExtensionPoints(ExtensionsAreaImpl.java:262)
	at com.intellij.ide.plugins.PluginManagerCore.registerExtensionPointAndExtensions(PluginManagerCore.java:1334)
	...
```
2020-12-07 10:18:38 +03:00
Nikolay Krasko
5f91f79382 Remove usage of idea file systems for checking js libraries
The removed code is probably an outdated code from the age when Kotlin
compiler was using VirtualFiles for operating. Previously the links were
stored and passed further, but now it is only some additional check
(files are unused after the check) with an implicit dependency to
IDEA internals.

The deleted check could probably be responsible for handling references
to JS libraries because of the working compiler daemon.

The code was spotted during an investigation for the
2bf22caeb7 commit (there's a detailed
description in the commit message).
2020-12-05 22:22:30 +03:00
Jinseong Jeon
c959ad7911 FIR checker: revisit per-label iterations to avoid !! 2020-12-05 12:26:05 +03:00
Jinseong Jeon
762e315ce3 FIR checker: deprecate path-insensitive data collection 2020-12-05 12:25:59 +03:00
Jinseong Jeon
168503573a FIR checker: make unused checker path-sensitive 2020-12-05 12:25:55 +03:00
Jinseong Jeon
3d7d87ace5 FIR: keep nullability of lambda return type 2020-12-05 12:25:50 +03:00
Mikhael Bogdanov
28a1d1ceac Disable test on Windows
#KTI-405
2020-12-05 07:18:45 +01:00
Alexander Udalov
c87edc44f3 Fix compilation error in :noarg-ide-plugin
Was overlooked in a06bffc4b9.
2020-12-05 00:59:18 +01:00
Ilmir Usmanov
69be56d042 Value classes: Forbid cloneable value classes
#KT-43741 Fixed
2020-12-04 23:27:46 +01:00
Alexander Udalov
25c228297a JVM IR: support noarg compiler plugin
#KT-41265 Fixed
2020-12-04 22:12:58 +01:00
Alexander Udalov
a06bffc4b9 Noarg: prohibit noarg for inner and local classes
Report warning if old JVM backend is used, and error for JVM IR, which
is supposed to be enabled as default in the next Kotlin release.

 #KT-43725 Fixed
2020-12-04 22:12:58 +01:00
Alexander Udalov
a343fffe9e Noarg: somewhat refactor tests
Extract method that registers components, merge abstract test classes
into one file.
2020-12-04 22:12:57 +01:00
Alexander Udalov
b10e206144 IR: minor, deduplicate unbound symbol in error message 2020-12-04 22:12:57 +01:00
Nikolay Krasko
bf4f2605d4 Mark FirPsiCheckerTestGenerated.Regression.testJet53 as FLAKY 2020-12-04 19:42:17 +03:00
Vyacheslav Gerasimov
7354bcbc99 Build: Publish kotlin-compiler-internal-test-framework maven artifact 2020-12-04 19:15:12 +03:00
Mads Ager
5d9e86863a [IR] Make isHidden and isAssignable explicit on IrValueParameter.
There were a couple of places where they were confused and
isAssignable was passed as a positional parameter in the position
of isHidden.
2020-12-04 17:04:45 +01:00
Dmitry Petrov
3dbe02b7fe JVM_IR KT-43109 generate internal bridge for custom internal 'toArray'
Also add some tests for internal collection stubs.
2020-12-04 18:57:10 +03:00
Ilya Gorbunov
149bcc2d22 Revert using regex Pattern in String.replace
Use String.indexOf(..., ignoreCase) instead in all branches to preserve
compatibility with behavior before 1.4.20 that used String.split which
essentially relied on that String.indexOf

#KT-43745 Fixed
2020-12-04 17:43:54 +03:00
Jinseong Jeon
5167d69b7c FIR checker: introduce member property checker 2020-12-04 16:58:30 +03:00
Nikolay Krasko
2bf22caeb7 Revert "Keep application environment alive between JPS tests"
This reverts commit 175dd567

The revert fixes the flaky behaviour on Windows in jps-plugin tests.

java.lang.RuntimeException: java.nio.file.FileSystemException:
tempdir_path\jps-build\jslib-example.jar:
The process cannot access the file because it is being used by another process.

Can be reproduced when running KotlinJpsBuildTest after IncrementalJsJpsTestGenerated.

1. IncrementalJsJpsTestGenerated sets KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
2. KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY disables environment clean-up.
3. No disposeApplicationEnvironment() call also means no ZipHandler.clearFileAccessorCache()
4. There's jslib-example.jar opening in JsConfig.checkLibFilesAndReportErrors()
5. File handler is not closed and tests fails in tearDown()

Affected tests:
KotlinJpsBuildTest.testKotlinJavaScriptProjectWithLibraryCustomOutputDir
KotlinJpsBuildTest.testKotlinJavaScriptProjectWithLibraryAndErrors
KotlinJpsBuildTest.testKotlinJavaScriptProjectWithLibrary
KotlinJpsBuildTest.testKotlinJavaScriptProjectWithLibraryNoCopy
KotlinJpsBuildTest.testKotlinJavaScriptProjectWithTwoModulesAndWithLibrary
KotlinJpsBuildTestIncremental.testKotlinJavaScriptProjectWithLibraryCustomOutputDir
KotlinJpsBuildTestIncremental.testKotlinJavaScriptProjectWithLibraryAndErrors
KotlinJpsBuildTestIncremental.testKotlinJavaScriptProjectWithLibrary
KotlinJpsBuildTestIncremental.testKotlinJavaScriptProjectWithLibraryNoCopy
KotlinJpsBuildTestIncremental.testKotlinJavaScriptProjectWithTwoModulesAndWithLibrary
2020-12-04 14:09:36 +03:00
Nikolay Krasko
2d8bdcbc9b Minor: use unique temp directories in jps-build tests 2020-12-04 14:09:36 +03:00
Igor Yakovlev
1ee0892f73 [ULC] Fix NPE on generating data class ctor parameters 2020-12-04 13:07:20 +03:00
Ilmir Usmanov
f43899086a Value Classes: Forbid var properties with value class receivers 2020-12-04 09:45:56 +01:00
Ilmir Usmanov
19b16da183 Minor. Add test to check value classes 2020-12-04 09:19:05 +01:00
Ilmir Usmanov
0d55c9108d IC: Forbid inner classes inside inline classes
#KT-43067 Fixed
2020-12-04 05:45:53 +01:00
Ilmir Usmanov
15c325cf10 Value classes: Allow nested inline classes 2020-12-04 05:45:51 +01:00
Vyacheslav Gerasimov
235813736e Build: Set file access rights explicitly in kotlin-stdlib-js jar
Workaround for #KTI-401. Since gradle 6.6 ant.replaceregexp call sets
incorrect access rights `-rw-------` instead of `-rw-r--r--`
2020-12-04 01:47:18 +03:00
Mikhail Glukhikh
4626f21c58 Record type arguments for FirResolvedQualifier 2020-12-03 19:33:51 +03:00
Mikhail Glukhikh
68d271fc91 Move FirModifierList inside FirModifierChecker to reduce its scope 2020-12-03 19:33:51 +03:00
Mikhail Glukhikh
94ddb71213 [FIR] Simplify UnusedChecker & delete FirSourceChildren.kt 2020-12-03 19:33:51 +03:00
Mikhail Glukhikh
8abf27898d Simplify FirMemberDeclaration.implicitModality 2020-12-03 19:33:51 +03:00
Mikhail Glukhikh
5fbdc0af5e [FIR] Introduce & use MODALITY_MODIFIER positioning strategy 2020-12-03 19:33:50 +03:00
Mikhail Glukhikh
54f9edb597 Simplify RedundantVisibilityModifierChecker 2020-12-03 19:33:50 +03:00
Mikhail Glukhikh
b1c9d4b046 [FIR] Introduce & use VISIBILITY_MODIFIER positioning strategy 2020-12-03 19:33:50 +03:00
Mikhail Glukhikh
7f1b539011 [FIR] Simplify CanBeValChecker.getDestructuringChildrenCount 2020-12-03 19:33:50 +03:00
Mikhail Glukhikh
3877933913 [FIR] Adapt VAL_OR_VAR strategy & use it in CanBeValChecker 2020-12-03 19:33:50 +03:00
Mikhail Glukhikh
ea7d738ee1 [FIR] Introduce & use SourceElementPositioningStrategies.OPERATOR 2020-12-03 19:33:49 +03:00
Mikhail Glukhikh
c9806c5af9 [FIR] Simplify RedundantExplicitTypeChecker 2020-12-03 19:33:49 +03:00
Ilmir Usmanov
516fce37db Value classes: Allow unsigned arrays in annotations
including varargs, apparently.
So, we allow unsigned types and unsigned arrays in annotations,
but disallow user-defined inline classes.
 #KT-23816 Fixed
2020-12-03 17:22:08 +01:00
Alexander Udalov
a9c072f826 Regenerate compiler tests 2020-12-03 17:02:35 +01:00
Dmitry Petrov
caea0a9df0 JVM_IR KT-43721 coerce intrinsic result to corresponding unsigned type 2020-12-03 16:44:26 +03:00
Mads Ager
c776fcbd00 [JVM_IR] Fix incorrect name in inner class attributes. 2020-12-03 13:41:36 +01:00
Mads Ager
fae5b8da4b [JVM] Do not put the name of default lambda parameter in LVT.
If we do, the local variable table will not make sense. As as
example:

```
inline fun foo(getString: () -> String = { "OK" }) {
  println(getString())
}

inline fun bar() {
}

fun main() {
    bar()
    foo()
}
```

leads to the following bytecode:

```
  public static final void main();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    Code:
      stack=2, locals=4, args_size=0
         0: iconst_0
         1: istore_0
         2: nop
         3: nop
         4: iconst_0
         5: istore_1
         6: nop
         7: ldc           #53                 // String OK
         9: astore_2
        10: iconst_0
        11: istore_3
        12: getstatic     #30                 // Field java/lang/System.out:Ljava/io/PrintStream;
        15: aload_2
        16: invokevirtual #36                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        19: nop
        20: return
      LineNumberTable:
        line 9: 0
        line 13: 2
        line 10: 3
        line 14: 4
        line 15: 6
        line 16: 7
        line 17: 19
        line 11: 20
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            2       1     0 $i$f$bar   I
            6      14     1 $i$f$foo   I
            4      16     0 getString$iv   Lkotlin/jvm/functions/Function0;
```

The `getString$iv` local should not be there. It has been inlined away.
Leaving it in the local variable table leads to inconsistent locals
info. Local 0 contains an int but we declare a local of type
Function0.
2020-12-03 13:41:36 +01:00
Dmitriy Dolovov
e5c46a86aa [Commonizer] Minor. Rename file 2020-12-03 15:33:26 +03:00
Dmitriy Dolovov
daf42c1ee6 [Commonizer] Remove unnecessary nullability at CirKnownClassifiers.commonDependeeLibraries 2020-12-03 15:33:20 +03:00
Vladimir Dolzhenko
984b3c2f30 Fix to address platform expectation for project path
Project path has to be absolute
2020-12-03 12:35:31 +01:00
Dmitriy Dolovov
68f8e88d8b [Commonizer] Introduce various types of classifier caches
- New CirCommonizedClassifiers and CirForwardDeclarations caches
- New CirProvidedClassifiers cache with classifier names loaded from arbitrary modules
- CirClassifiersCache is replaced by CirKnownClassifiers umbrella
- Replace the remaining usages of 'isUnderStandardKotlinPackages' by delegation to
  CirKnownClassifiers.commonDependeeLibraries
2020-12-03 13:11:40 +03:00
Dmitriy Dolovov
dce3d4d1b7 [Commonizer] Rename InputTarget and OutputTarget
Rename target classes to better reflect their meaning:
- InputTarget -> LeafTarget
- OutputTarget -> SharedTarget
2020-12-03 13:11:33 +03:00
Dmitriy Dolovov
b0ff3e7e5e [Commonizer] More fine-grained control of commonized module dependencies
- Reduce usage of 'isUnderStandardKotlinPackages' check in commonizer source code
- Rely on common module dependencies supplied via commonizer Parameters which not only
  Kotlin standard library but may also include common fragments of other libraries
2020-12-03 13:11:27 +03:00
LepilkinaElena
9d749feb64 Fix gradle test for endorsed libraries in K/N (#3953) 2020-12-03 12:57:02 +03:00
Victor Petukhov
d25ad269e0 Reuse captured arguments for flexible type's bounds properly, by equality of type constructors modulo mutability and type argument
^KT-43630 Fixed
2020-12-03 11:13:41 +03:00
Victor Petukhov
9f58e4bcfe Add FlexibleTypeBoundsChecker which can answer the question: "can two types be different bounds of the same flexible type?"; and provide the base bound for the given bound.
For instance: `MutableList` and `List` may be within the same flexible type.
2020-12-03 11:13:39 +03:00
Victor Petukhov
1ccbb09029 Fix formatting in flexibleTypes.kt 2020-12-03 11:13:38 +03:00
Shagen Ogandzhanian
8e5bcd349e [JS IR] Respect JsExport while assigning stable names
see https://youtrack.jetbrains.com/issue/KT-43404
2020-12-02 22:21:16 +01:00
Alexander Udalov
6b649d02d3 JVM IR: fix visibility/modality of $suspendImpl methods
#KT-43614 Fixed
2020-12-02 20:53:55 +01:00
Alexander Udalov
8ce2e4654b JVM IR: allow custom toArray to have any array type
To avoid breaking Java source compatibility. This problem can be fixed
later once JVM IR is stabilized.

 #KT-43111 Fixed
2020-12-02 20:53:47 +01:00
Dmitry Petrov
e6a3e38c4d JVM_IR no static inline class members for Kotlin JvmDefault methods
KT-43698 KT-43051
2020-12-02 20:04:13 +03:00
Ivan Gavrilovic
11673bd09c KAPT: add tests for processed types, remove dead code, simplify logic
Add integration test which checks if only types can be
reprocessed in an incremental round. Also, remove unused
`invalidateTypesForFiles` method.

Furthermore, clarify that types that are reprocessed
(i.e types from .class files) are not necessarily
aggregating types, but simply types that should be reprocessed.

Test: KaptIncrementalWithIsolatingApt.testClasspathChangesCauseTypesToBeReprocessed
2020-12-02 16:55:50 +01:00
Ivan Gavrilovic
08a2b47c77 Incremental KAPT: fix typo and do check processed sources on
clean build
2020-12-02 16:55:49 +01:00
Ivan Gavrilovic
0522583602 Incremental KAPT: add test for isolating AP with classpath origin
Add a regression test for KT-34340 that allows APs to have
classpath types as origins.
2020-12-02 16:55:49 +01:00
Ivan Gavrilovic
05e47da458 Incremental KAPT: simplify impacted types computation
Process aggregating types first, and when computing impacted types
compute isolating generated impacted by classpath changes first.
2020-12-02 16:55:49 +01:00
Ivan Gavrilovic
c7e5beece5 Use types are origins for incremental KAPT and track generated source
This change introduces tracking of generated sources structure in order
to e.g track classpath changes impacting generated sources. This fixes KT-42182.

Also, origin tracking for isolating processors is now using types, allowing
for origin elements from classpath. This fixes KT-34340. However, classpath
origin is used only to invalidate generated files when the type changes and
processing will not be requested for that type. This is in line with the
incap spec.
2020-12-02 16:55:49 +01:00
Shagen Ogandzhanian
d512158c25 [JS IR] Remove redundant guard assertion for extension funs with default params
Introduce corresponding test
See https://youtrack.jetbrains.com/issue/KT-41076
2020-12-02 16:45:12 +01:00
Alexander Udalov
a917ebd11e JVM IR: use origin to detect property/typealias $annotations methods
Now that DEFAULT_IMPLS origins for methods do not exist after previous
commits, the name heuristic is no longer needed.
2020-12-02 15:54:15 +01:00
Alexander Udalov
c7c793c724 JVM IR: do not use origin DEFAULT_IMPLS_BRIDGE(_TO_SYNTHETIC)
Instead, check that origin of the parent class is DEFAULT_IMPLS. Also,
add a separate origin SUPER_INTERFACE_METHOD_BRIDGE for interface
methods with bodies that are copied to classes.
2020-12-02 15:54:14 +01:00
Alexander Udalov
d41d1bf64d JVM IR: remove obsolete isDefaultImplsBridge in findInterfaceImplementation 2020-12-02 15:54:14 +01:00
Alexander Udalov
be03bc477d JVM IR: do not use origin DEFAULT_IMPLS_WITH_MOVED_RECEIVERS(_SYNTHETIC)
Instead, check that origin of the parent class is DEFAULT_IMPLS.
2020-12-02 15:54:14 +01:00
Alexander Udalov
988cc52174 JVM IR: do not use origin DEFAULT_IMPLS_BRIDGE_FOR_COMPATIBILITY(_SYNTHETIC)
It was only used to generate deprecation in codegen, but it's annotated
with `javaLangDeprecatedConstructorWithDeprecatedFlag`, and a similar
annotation for IrField results in ACC_DEPRECATED. Adapt codegen to
generate this flag for functions too.
2020-12-02 15:54:13 +01:00
Ilya Goncharov
697b2b02f1 [JS IR] Add properties lazy initialization with multiple modules
[JS IR] Move tests into compiler/testData

[JS IR] Add cyclic dependencies with lazy property initialization

[JS IR] Add test on not initialization in case of call non properties (classed, objects, enum classes, const vals)

[JS IR] Add initialization through top level

[JS IR] Ignore enum getInstance function in property lazy initialization

[JS IR] Use let function with useful result instead of pure apply and also

[JS IR] Remove duplicated tests in js.translator
2020-12-02 17:35:30 +03:00
pyos
6cb573cb45 [FIR] Import parents of companion objects first
Otherwise, information about members moved from companion objects to the
parent class (e.g. on JVM, companion object fields -> static fields in
parent class) will be incorrect.
2020-12-02 15:29:42 +03:00
Igor Yakovlev
4d7b6c022b [FIR IDE] LC Anonymous to SuperClass type substitution 2020-12-02 15:13:09 +03:00
Igor Yakovlev
842d31d04e [FIR IDE] Fix HL API test data
Ignore failed tests
Set passing test to comparison mode
Fix testdata for symbols
Fix invalid LAZINESS parameter reading from testdata
2020-12-02 15:13:09 +03:00
Igor Yakovlev
7cbcde77dd [FIR IDE] LC More accurate fields visibility and modality 2020-12-02 15:13:08 +03:00
Igor Yakovlev
a7d7aa123e [FIR IDE] LC minor refactorings 2020-12-02 15:13:08 +03:00
Igor Yakovlev
a1603716ed [FIR IDE] LC Add anonymous objects support
+minor fixes
2020-12-02 15:13:08 +03:00
Igor Yakovlev
5630667320 [FIR IDE] LC better support for JvmMultiFileClass annotation 2020-12-02 15:13:08 +03:00
Igor Yakovlev
56c3faee00 [FIR IDE] LC Fix generating unique field names 2020-12-02 15:13:08 +03:00
Igor Yakovlev
18e5af37ff [FIR IDE] LC Fixed incorrect JvmOverloads 2020-12-02 15:13:07 +03:00
Igor Yakovlev
535aa1e9e0 [FIR IDE] LC expand typealiases for applied annotations 2020-12-02 15:13:07 +03:00
Igor Yakovlev
229c6f97ac [FIR IDE] LC Fixed nullability for getters 2020-12-02 15:13:07 +03:00
Igor Yakovlev
aff90b335c [FIR IDE] LC Implement special keywords like transient, volatile, synchronized, strictfp 2020-12-02 15:13:07 +03:00
Igor Yakovlev
6aff96a401 [FIR IDE] Remove extra analyzing for local declarations 2020-12-02 15:13:07 +03:00
Igor Yakovlev
3fc424246b [FIR IDE] LC basic support for type arguments
+ small fixes for deprecation, etc.
2020-12-02 15:13:06 +03:00
Igor Yakovlev
2a8f783393 [FIR IDE] HL API Better support of nullability and modality 2020-12-02 15:13:06 +03:00
Igor Yakovlev
4c69043a15 [FIR IDE] Move refactoring and minor bugfixing for modality, jvmname, etc. 2020-12-02 15:13:06 +03:00
Igor Yakovlev
3e3ec5fc69 [FIR IDE] Supporting member scopes in EnumEntries 2020-12-02 15:13:06 +03:00
Igor Yakovlev
fdaf31dbf3 [FIR IDE] Fix typemapping for FirTypeAliasSymbol 2020-12-02 15:13:05 +03:00
Igor Yakovlev
aae0081f3f [FIR IDE] Fixed invalid HL API getters request 2020-12-02 15:13:05 +03:00
Mikhail Glukhikh
2429f429c5 [FIR] Set isStubTypeEqualsToAnything = true for inference as in FE 1.0
#KT-43616 Fixed
2020-12-02 14:49:08 +03:00
Mikhail Glukhikh
eae8821dec FIR Java: unbind possible named annotation cycle 2020-12-02 14:48:46 +03:00
Nikolay Krasko
2ffedd2731 Fix Daemon compiler tests on Windows
In 202 platform tearDown tries to remove temporary directory, but this
fails on Windows, because while Daemon is active directory can't be
deleted.
2020-12-02 14:23:32 +03:00
Georgy Bronnikov
8a969dab7d Bugfix for FIR 2020-12-02 09:47:34 +03:00
Georgy Bronnikov
b23d7a79b0 IR: get rid of WrappedDescriptorWithContainerSource 2020-12-02 09:47:34 +03:00
Georgy Bronnikov
c0cd9064d7 IR: IrMemberWithContainerSource 2020-12-02 09:47:34 +03:00
Georgy Bronnikov
14b773c1fd JVM_IR: do not rely on DescriptorWithContainerSource in InlineCodegen 2020-12-02 09:47:34 +03:00
Ilmir Usmanov
f0a787551a Value classes: Raise retention of @JvmInline to RUNTIME
so it will be visible by reflection
2020-12-01 23:45:50 +01:00
Ilmir Usmanov
129de76288 Value classes: Generate @JvmInline annotation for inline classes
but not for value classes.
Since inline classes and value classes share the same flag, we use
presence of the annotation to distinguish them.
2020-12-01 23:45:47 +01:00
Dmitry Petrov
ae8abd1832 Minor: ignore nestedBigArityFunCalls.kt in WASM 2020-12-01 19:43:52 +03:00
Dmitry Petrov
1412ee96f8 JVM_IR KT-43524 static wrappers for deprecated accessors are deprecated 2020-12-01 19:43:52 +03:00
Dmitry Petrov
e96fc74ffa JVM_IR KT-43519 no delegates for external funs in multifile facades
Also add ABI tests for @JvmStatic/JvmOverloads + 'external'.
2020-12-01 19:43:52 +03:00
Dmitry Petrov
2b4564059e JVM_IR KT-43459 fix $annotations method receiver type 2020-12-01 19:43:51 +03:00
Dmitry Petrov
85b5948931 JVM_IR KT-43051 no static inline class members for default Java methods 2020-12-01 19:43:51 +03:00
Dmitry Petrov
4c3ffc3451 JVM_IR KT-41911 process big arity 'invoke' arguments recursively 2020-12-01 19:43:51 +03:00
Georgy Bronnikov
b0e2d5637d Mute a test for WASM 2020-12-01 18:37:55 +03:00
Georgy Bronnikov
bb4950a021 Regenerate LightAnalysis tests 2020-12-01 16:01:48 +03:00
Dmitriy Novozhilov
91bccad72b [JS] Fix path of generated js tests 2020-12-01 15:43:25 +03:00
Mikhail Glukhikh
7550a1870b [FIR2IR] Make checks about f/o accessors necessity more precise
#KT-43342 Fixed
2020-12-01 14:23:19 +03:00
Ilya Goncharov
b179b567a9 [Gradle, JS] Add test on resolution of js project with directory dependency
^KT-43668 fixed
2020-12-01 14:12:39 +03:00
Alexander Udalov
2fdc2dfaaf JVM IR: fix regression in JvmStatic-in-object lowering for properties
References to properties with JvmStatic getter were not handled in
MakeCallsStatic (by overwriting dispatchReceiver with null) because the
property itself was not considered static.

 #KT-43672 Fixed
2020-12-01 11:54:45 +01:00
Georgy Bronnikov
4607eca987 JVM_IR: bug fix in classFileContainsMethod
The old test sequence failed for toplevel functions because of file
class wrappers, so that the second branch was never invoked.
2020-12-01 13:15:51 +03:00
Roman Golyshev
f50480d258 FIR IDE: Fix resolving of nested types in type references 2020-12-01 09:24:20 +00:00
Roman Golyshev
94a5379631 FIR IDE: Add tests for resolving from nested types references
Some of those tests are failing in the FIR IDE
2020-12-01 09:24:20 +00:00
Alexander Udalov
19ca9c0fde Enable JVM IR for bootstrap in the project 2020-11-30 22:09:24 +01:00
Alexander Udalov
606de26646 JVM IR: fix generation of equals/hashCode for fun interfaces over references
... in case `-Xno-optimized-callable-references` is enabled. Before this
change, the generated abstract equals/hashCode methods were considered
as accidental overrides because they did not have equals/hashCode from
the supertype in the overriddenSymbols list.

 #KT-43666 Fixed
2020-11-30 19:15:20 +01:00
pyos
50ae360ff9 FIR2IR: fix the way annotations are moved to fields
1. When an annotation has multiple targets, the priority goes like this:
    constructor parameter (if applicable) -> property -> backing field.

 2. The argument to `kotlin.annotation.Target` is a vararg, so that
    should be handled as well.

 3. `AnnotationTarget.VALUE_PARAMETER` allows receivers, constructor
    parameters, and setter parameters, while `AnnotationTarget.FIELD` allows
    both backing fields and delegates.

Known issue: java.lang.annotation.Target is not remapped to the Kotlin
equivalent, so things are still broken for pure Java annotations.
2020-11-30 20:29:18 +03:00
Andrei Klunnyi
4817d5e01d KTIJ-585 [Gradle Runner]: main() cannot be launched from AS 4.1
Android gradle-project model differs from what we have for pure Java
and MPP. It's the reason why application classpath cannot be collected
correctly.
Until universal solution is provided delegation to gradle is put under
the registry flag. If disable platform runner is used as before.
2020-11-30 15:44:37 +00:00
Ilya Goncharov
995d96e5a3 [JS IR] Use one concat elements for non vararg and vararg arguments
^KT-42357 fixed
2020-11-30 17:34:44 +03:00
Ilya Goncharov
67e4b0948e [JS IR] Constructor call with vararg invoking with apply
[JS IR] Nullize external empty varargs

[JS IR] Concat varargs with array of nonVarargs arguments

^KT-42357 fixed
2020-11-30 17:33:28 +03:00
Ilya Goncharov
ac42dcd8da [JS IR] Add test for external fun vararg
[JS IR] Add tests with empty vararg and default arg before it

[JS IR] Ignore backend in tests instead of target backend

[JS IR] Add function with named spread operator

[JS IR] Remove ignoring of current js backend in jsExternalVarargFun

[JS IR] Add with arguments after vararg

^KT-42357 fixed
2020-11-30 17:33:07 +03:00
Ilya Goncharov
e7789d2e30 [Gradle, JS] Add filter on file on fileCollectionDependencies because Gradle can't hash directory
^KT-43668 fixed
2020-11-30 17:04:30 +03:00
Dmitry Petrov
96ed99d62e JVM_IR KT-40305 no nullability assertions on built-in stubs 2020-11-30 15:49:02 +03:00
Dmitry Petrov
b2aed536c9 JVM_IR KT-39612 process subexpressions recursively in 'name' lowering 2020-11-30 15:49:02 +03:00
Dmitry Petrov
3b604cfa7f JVM_IR KT-32701 generate multiple big arity invokes, report error later 2020-11-30 15:49:02 +03:00
Dmitry Petrov
a157b58c61 JVM_IR KT-43610 keep track of "special bridges" for interface funs 2020-11-30 15:49:01 +03:00
Dmitriy Novozhilov
c43db2ee8d [TEST] Inherit UpdateConfigurationQuickFixTest from KotlinLightPlatformCodeInsightFixtureTestCase
This is needed for proper test muting
2020-11-30 15:39:05 +03:00
Alexander Udalov
7d9eeb6847 Minor, add workaround for KT-42137 2020-11-30 12:44:42 +01:00
Alexander Udalov
e1d54bf99f Minor, add workaround for KT-43666 2020-11-30 12:37:27 +01:00
Mikhael Bogdanov
ad579de328 Don't run KaptPathsTest.testSymbolicLinks test on Windows 2020-11-30 12:17:00 +01:00
Dmitriy Novozhilov
d706a7ff74 Build: mute failing tests
Those tests are failing only on windows agents after
  switch to 202 platform
2020-11-30 13:40:29 +03:00
pyos
1cccf2645f FIR: serialize HAS_CONSTANT at least for const properties
Non-const properties may need them too with if the 1.4 feature
NoConstantValueAttributeForNonConstVals is disabled.
2020-11-30 13:05:28 +03:00
Mikhail Glukhikh
04d9afe83e FIR Java: add workaround for classId = null in JavaAnnotation 2020-11-30 13:05:27 +03:00
Mikhail Glukhikh
feb13f98c0 [FIR2IR] Handle Java annotation parameter mapping properly
#KT-43584 Fixed
2020-11-30 13:05:26 +03:00
Mikhail Glukhikh
9b30655d66 [FIR] Load Java annotations named arguments properly (see KT-43584) 2020-11-30 13:05:23 +03:00
Roman Golyshev
e6f380182a Revert "FIR IDE: Add tests for resolving from nested types references"
This reverts commit e127ea3d
2020-11-30 12:37:40 +03:00
Roman Golyshev
f8b6559b6a Revert "FIR IDE: Fix resolving of nested types in type references"
This reverts commit dba14ba9
2020-11-30 12:37:26 +03:00
Roman Golyshev
dba14ba995 FIR IDE: Fix resolving of nested types in type references 2020-11-30 09:26:15 +00:00
Roman Golyshev
e127ea3dad FIR IDE: Add tests for resolving from nested types references
Some of those tests are failing in the FIR IDE
2020-11-30 09:26:15 +00:00
Mikhael Bogdanov
8a00470b40 Enable kotlin-annotation-processing-base tests on TC 2020-11-30 10:06:22 +01:00
Sergey Bogolepov
29bed39a54 Bump to native version version with watchos_x64 enabled 2020-11-30 14:01:12 +07:00
Sergey Bogolepov
37ee2cbe53 [KT-43276] Update tests to support watchos_x64 2020-11-30 14:01:12 +07:00
Sergey Bogolepov
d6f54a7730 [KT-43276] Fix watchos target shortcut. 2020-11-30 14:01:12 +07:00
Sergey Bogolepov
f3424a98b7 generateMppTargetContainerWithPresets: remove unneeded hack 2020-11-30 14:01:12 +07:00
Sergey Bogolepov
e39560b134 [KT-43276] Add watchos_x64 target 2020-11-30 14:01:12 +07:00
Ilya Gorbunov
0634351fbc Introduce pathString/absolute/absolutePathString
Rename invariantSeparatorsPath to invariantSeparatorsPathString
to have more consistent names of methods returning path strings.

KT-19192
2020-11-29 17:46:47 +03:00
Ilya Gorbunov
84f5a294f7 Allow passing null parent directory to createTempFile/Directory
null signifies the default temp directory.

KT-19192
2020-11-29 17:46:47 +03:00
Ilya Gorbunov
64d85f259c Relax writeText/appendText parameter type to CharSequence
KT-19192
2020-11-29 17:46:47 +03:00
Pavel Punegov
2ee8bf7dde Add fastutil dependency for 202 and higher platforms 2020-11-28 14:26:01 +03:00
Dmitriy Novozhilov
f668e906cc Build: unmute passed tests 2020-11-28 14:26:01 +03:00
Dmitriy Novozhilov
e7d305b97a Build: mute failing stepping tests 2020-11-28 14:26:00 +03:00
Dmitriy Novozhilov
78c786de46 Build: Mute failing goto declaration tests 2020-11-28 14:26:00 +03:00
Dmitriy Novozhilov
33b545aea7 Build: Mute failing gradle import with android tests 2020-11-28 14:25:59 +03:00
Dmitriy Novozhilov
85c59328c7 [DEBUGGER] Temporary mute AbstractKotlinEvaluateExpressionTest 2020-11-28 14:25:59 +03:00
Vladimir Dolzhenko
3d33ea7da8 Use absolute paths to locate existed projects to open in AbstractConfigureKotlinTest 2020-11-28 14:25:58 +03:00
Vladimir Dolzhenko
124888eb43 Revert back AddFunctionParametersFix test data output for 201- 2020-11-28 14:25:58 +03:00
Dmitriy Novozhilov
e251a9be14 Build: fix finding layout-api jar in parcelize box test due to platform change 2020-11-28 14:25:57 +03:00
Dmitriy Novozhilov
cc1a0bf6d7 [FE] Update testdata 2020-11-28 14:25:57 +03:00
Vladimir Dolzhenko
17e6e88176 Fixed AddFunctionParametersFix test data output 2020-11-28 14:25:57 +03:00
Dmitriy Novozhilov
406e863a73 [FE] Fix creating location of compiler errors in CLI 2020-11-28 14:25:56 +03:00
Dmitriy Novozhilov
dc364b8be4 Remove useless @author comment 2020-11-28 14:25:56 +03:00
Vladimir Dolzhenko
95e5ea4840 temporary ignore/disable tests 2020-11-28 14:25:55 +03:00
Dmitriy Novozhilov
02f71a63b8 [FE] Disable SKIP_DEBUG flag when building java model from binaries
This is needed to avoid skipping jvm annotations with names of
  function parameters
2020-11-28 14:25:55 +03:00
Dmitriy Novozhilov
bf1abed246 Build: add shadowing processor for core.xml in embeddable compiler 2020-11-28 14:25:54 +03:00
Dmitriy Novozhilov
ad953b6285 Build: remove redundant bunch TODO's 2020-11-28 14:25:54 +03:00
Dmitriy Novozhilov
986ab9cb54 Build: remove useless .as40 files 2020-11-28 14:25:54 +03:00
Dmitriy Novozhilov
1b559fe676 Don't set KOTLIN_BUNDLED in unit tests 2020-11-28 14:25:53 +03:00
Dmitriy Novozhilov
7396abf5a4 Build: add fastutil dependency to scripting tests 2020-11-28 14:25:53 +03:00
Dmitriy Novozhilov
5ab9710cc5 Remove ./local directory from CodeConformanceTest 2020-11-28 14:25:52 +03:00
Dmitriy Novozhilov
d3ef0eb519 Build: register missing TreeAspect service in KtParsingTestCase 2020-11-28 14:25:52 +03:00
Dmitriy Novozhilov
68719831ee Build: update asm version in kotlinp 2020-11-28 14:25:52 +03:00
Dmitriy Novozhilov
dc35a13008 Build: remove useless bunch files 2020-11-28 14:25:51 +03:00
Dmitriy Novozhilov
46fcc7d59d Build: fix registration of ClassFileDecompilers extension 2020-11-28 14:25:51 +03:00
Dmitriy Novozhilov
48cbb74a01 Build: drop deprecated extension point used in test of old j2k 2020-11-28 14:25:50 +03:00
Dmitriy Novozhilov
d887814cc5 Build: fix compilation of :libraries:tools:kotlin-maven-plugin-test 2020-11-28 14:25:50 +03:00
Dmitriy Novozhilov
4779092ba5 Build: fix API differences between 201 and 202 in idea performance tests 2020-11-28 14:25:49 +03:00
Dmitriy Novozhilov
2a053c214d Build: fix API differences between 201 and 202 in scratch tests 2020-11-28 14:25:49 +03:00
Dmitriy Novozhilov
d50d56f68c Build: fix API differences between 201 and 202 in NewKotlinFileAction 2020-11-28 14:25:49 +03:00
Dmitriy Novozhilov
e4e28a5495 Build: update grovy dependencies in :compiler:tests-spec 2020-11-28 14:25:48 +03:00
Dmitriy Novozhilov
07dd9179e8 Build: change 202 platform version 2020-11-28 14:25:48 +03:00
Dmitriy Novozhilov
eeb9b3214c Switch to 202 platform 2020-11-28 14:25:19 +03:00
Ilya Muradyan
89bba93615 Introduce GetScriptingClassByClassLoader interface
It is needed to override default JVM behaviour
2020-11-28 09:44:06 +01:00
Ilya Muradyan
65ce7cd0c2 Fix path for Windows in Fibonacci test 2020-11-28 09:44:06 +01:00
920 changed files with 17333 additions and 8534 deletions

11
.bunch
View File

@@ -1,7 +1,6 @@
201
202
203_202
193
as40_193
as41
as42_202
201
193_201
as40_193_201
as41_201
as42

View File

@@ -188,7 +188,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.4.30-dev-17200"
extra["versions.kotlin-native"] = "1.4.30-dev-17395"
}
val intellijUltimateEnabled by extra(project.kotlinBuildProperties.intellijUltimateEnabled)
@@ -854,6 +854,8 @@ tasks {
register("kaptIdeTest") {
dependsOn(":kotlin-annotation-processing:test")
dependsOn(":kotlin-annotation-processing-base:test")
dependsOn(":kotlin-annotation-processing-cli:test")
}
register("gradleIdeTest") {

View File

@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
@@ -55,6 +56,13 @@ class ErasedInlineClassBodyCodegen(
generateUnboxMethod()
generateFunctionsFromAny()
generateSpecializedEqualsStub()
generateJvmInlineAnnotation()
}
private fun generateJvmInlineAnnotation() {
if (descriptor.isInline) {
v.newAnnotation(JVM_INLINE_ANNOTATION_FQ_NAME.topLevelClassAsmType().descriptor, true).visitEnd()
}
}
private fun generateFunctionsFromAny() {

View File

@@ -136,9 +136,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
) {
var nodeAndSmap: SMAPAndMethodNode? = null
try {
nodeAndSmap = createInlineMethodNode(
functionDescriptor, methodOwner, jvmSignature, mapDefaultSignature, typeArguments, typeSystem, state, sourceCompiler
)
nodeAndSmap = createInlineMethodNode(mapDefaultSignature, typeArguments, typeSystem)
endCall(inlineCall(nodeAndSmap, inlineDefaultLambdas), registerLineNumberAfterwards)
} catch (e: CompilationException) {
throw e
@@ -274,6 +272,8 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
abstract fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda>
abstract fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean
fun generateAndInsertFinallyBlocks(
intoNode: MethodNode,
insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>,
@@ -512,38 +512,33 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
}
companion object {
internal fun createInlineMethodNode(
functionDescriptor: FunctionDescriptor,
methodOwner: Type,
jvmSignature: JvmMethodSignature,
callDefault: Boolean,
typeArguments: List<TypeParameterMarker>?,
typeSystem: TypeSystemCommonBackendContext,
state: GenerationState,
sourceCompilerForInline: SourceCompilerForInline
): SMAPAndMethodNode {
val intrinsic = generateInlineIntrinsic(state, functionDescriptor, typeArguments, typeSystem)
if (intrinsic != null) {
return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP())
}
val asmMethod = if (callDefault)
state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompilerForInline.contextKind)
else
mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
if (!isBuiltInArrayIntrinsic(functionDescriptor) && directMember !is DescriptorWithContainerSource) {
val node = sourceCompilerForInline.doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, callDefault, asmMethod)
node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
return node
}
return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature)
internal fun createInlineMethodNode(
callDefault: Boolean,
typeArguments: List<TypeParameterMarker>?,
typeSystem: TypeSystemCommonBackendContext
): SMAPAndMethodNode {
val intrinsic = generateInlineIntrinsic(state, functionDescriptor, typeArguments, typeSystem)
if (intrinsic != null) {
return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP())
}
val asmMethod = if (callDefault)
state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompiler.contextKind)
else
mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
if (!isBuiltInArrayIntrinsic(functionDescriptor) && !descriptorIsDeserialized(directMember)) {
val node = sourceCompiler.doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, callDefault, asmMethod)
node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
return node
}
return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature)
}
companion object {
internal fun createSpecialInlineMethodNodeFromBinaries(functionDescriptor: FunctionDescriptor, state: GenerationState): MethodNode {
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
assert(directMember is DescriptorWithContainerSource) {
@@ -577,7 +572,8 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
doCreateMethodNodeFromCompiled(directMember, state, jvmSignature.asmMethod)
else
null
result ?: throw IllegalStateException("Couldn't obtain compiled function body for $functionDescriptor")
result ?:
throw IllegalStateException("Couldn't obtain compiled function body for $functionDescriptor")
}
return SMAPAndMethodNode(cloneMethodNode(resultInCache.node), resultInCache.classSMAP)

View File

@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.linkWithLabel
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
@@ -16,7 +15,6 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class InlineCodegenForDefaultBody(
@@ -41,8 +39,10 @@ class InlineCodegenForDefaultBody(
}
override fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) {
val nodeAndSmap = InlineCodegen.createInlineMethodNode(
function, methodOwner, jvmSignature, callDefault, null, codegen.typeSystem, state, sourceCompilerForInline
val nodeAndSmap = PsiInlineCodegen(
codegen, state, function, methodOwner, jvmSignature, TypeParameterMappings(), sourceCompilerForInline
).createInlineMethodNode(
callDefault, null, codegen.typeSystem
)
val childSourceMapper = SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP)

View File

@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getMethodAsmFlags
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpres
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
@@ -208,4 +210,7 @@ class PsiInlineCodegen(
::PsiDefaultLambda
)
}
override fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean =
memberDescriptor is DescriptorWithContainerSource
}

View File

@@ -130,7 +130,9 @@ fun <T, R : DefaultLambda> expandMaskConditionsAndUpdateVariableNodes(
node.instructions.insert(position, newInsn)
}
node.localVariables.removeIf { it.start in toDelete && it.end in toDelete }
node.localVariables.removeIf {
(it.start in toDelete && it.end in toDelete) || defaultLambdas.contains(it.index)
}
node.remove(toDelete)

View File

@@ -8,4 +8,4 @@ package org.jetbrains.kotlin.codegen.optimization.common
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
typealias TypeAnnotatedFrames = Array<Frame<BasicValue>?>
typealias TypeAnnotatedFrames = Array<Frame<BasicValue>>

View File

@@ -8,4 +8,4 @@ package org.jetbrains.kotlin.codegen.optimization.common
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
typealias TypeAnnotatedFrames = Array<Frame<BasicValue>>
typealias TypeAnnotatedFrames = Array<Frame<BasicValue>?>

View File

@@ -5,4 +5,4 @@
package org.jetbrains.kotlin.codegen.state
typealias JvmMethodExceptionTypes = Array<out String>?
typealias JvmMethodExceptionTypes = Array<out String?>?

View File

@@ -5,4 +5,4 @@
package org.jetbrains.kotlin.codegen.state
typealias JvmMethodExceptionTypes = Array<out String?>?
typealias JvmMethodExceptionTypes = Array<out String>?

View File

@@ -49,6 +49,7 @@ if "%_KOTLIN_RUNNER%"=="1" (
"%_JAVACMD%" %JAVA_OPTS% "-Dkotlin.home=%_KOTLIN_HOME%" -cp "%_KOTLIN_HOME%\lib\kotlin-runner.jar" ^
org.jetbrains.kotlin.runner.Main %KOTLIN_OPTS%
) else (
setlocal EnableDelayedExpansion
SET _ADDITIONAL_CLASSPATH=
if not "%_KOTLIN_TOOL%"=="" (
@@ -56,7 +57,7 @@ if "%_KOTLIN_RUNNER%"=="1" (
)
"%_JAVACMD%" %JAVA_OPTS% -noverify -cp "%_KOTLIN_HOME%\lib\kotlin-preloader.jar" ^
org.jetbrains.kotlin.preloading.Preloader -cp "%_KOTLIN_HOME%\lib\kotlin-compiler.jar%_ADDITIONAL_CLASSPATH%" ^
org.jetbrains.kotlin.preloading.Preloader -cp "%_KOTLIN_HOME%\lib\kotlin-compiler.jar!_ADDITIONAL_CLASSPATH!" ^
%_KOTLIN_COMPILER% %KOTLIN_OPTS%
)

View File

@@ -0,0 +1,12 @@
<idea-plugin>
<id>org.jetbrains.kotlin</id>
<version>1.2</version>
<!-- Don't add more extension points here! Logic in KotlinCoreEnvironment assumes that there is only one EP. -->
<!-- And this file should be removed once 202 is no longer supported -->
<extensionPoints>
<extensionPoint qualifiedName="com.intellij.psi.classFileDecompiler"
interface="com.intellij.psi.compiled.ClassFileDecompilers$Decompiler"
dynamic="true"/>
</extensionPoints>
</idea-plugin>

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.cli.common.messages
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
/**
* This class behaviour is the same as [MessageCollector.report] in [AnalyzerWithCompilerReport.reportDiagnostic].
*/
class DefaultDiagnosticReporter(override val messageCollector: MessageCollector) : MessageCollectorBasedReporter
interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
val messageCollector: MessageCollector
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
render,
MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumn(diagnostic))
)
}

View File

@@ -17,8 +17,6 @@
package org.jetbrains.kotlin.cli.common.messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.impl.jar.CoreJarVirtualFile;
import com.intellij.openapi.vfs.local.CoreLocalVirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
@@ -53,10 +51,6 @@ public class MessageUtil {
@NotNull
public static String virtualFileToPath(@NotNull VirtualFile virtualFile) {
// Convert path to platform-dependent format when virtualFile is local file.
if (virtualFile instanceof CoreLocalVirtualFile || virtualFile instanceof CoreJarVirtualFile) {
return toSystemDependentName(virtualFile.getPath());
}
return virtualFile.getPath();
return toSystemDependentName(virtualFile.getPath());
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.cli.common.messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils;
import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName;
public class MessageUtil {
private MessageUtil() {}
@Nullable
public static CompilerMessageLocation psiElementToMessageLocation(@Nullable PsiElement element) {
if (element == null) return null;
PsiFile file = element.getContainingFile();
return psiFileToMessageLocation(file, "<no path>", DiagnosticUtils.getLineAndColumnInPsiFile(file, element.getTextRange()));
}
@Nullable
public static CompilerMessageLocation psiFileToMessageLocation(
@NotNull PsiFile file,
@Nullable String defaultValue,
@NotNull PsiDiagnosticUtils.LineAndColumn lineAndColumn
) {
VirtualFile virtualFile = file.getVirtualFile();
String path = virtualFile != null ? virtualFileToPath(virtualFile) : defaultValue;
return CompilerMessageLocation.create(path, lineAndColumn.getLine(), lineAndColumn.getColumn(), lineAndColumn.getLineContent());
}
@NotNull
public static String virtualFileToPath(@NotNull VirtualFile virtualFile) {
return toSystemDependentName(virtualFile.getPath());
}
}

View File

@@ -40,7 +40,6 @@ public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnviron
registerApplicationExtensionPoint(JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
registerApplicationExtensionPoint(ContainerProvider.EP_NAME, ContainerProvider.class);
registerApplicationExtensionPoint(ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
registerApplicationExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
@@ -52,4 +51,4 @@ public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnviron
protected VirtualFileSystem createJrtFileSystem() {
return new CoreJrtFileSystem();
}
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2010-2020 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.cli.jvm.compiler;
import com.intellij.DynamicBundle;
import com.intellij.codeInsight.ContainerProvider;
import com.intellij.codeInsight.runner.JavaMainMethodProvider;
import com.intellij.core.JavaCoreApplicationEnvironment;
import com.intellij.lang.MetaLanguage;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.psi.FileContextProvider;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.compiled.ClassFileDecompilers;
import com.intellij.psi.meta.MetaDataContributor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnvironment {
public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
KotlinCoreApplicationEnvironment environment = new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
registerExtensionPoints();
return environment;
}
private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
super(parentDisposable, unitTestMode);
}
private static void registerExtensionPoints() {
registerApplicationExtensionPoint(DynamicBundle.LanguageBundleEP.EP_NAME, DynamicBundle.LanguageBundleEP.class);
registerApplicationExtensionPoint(FileContextProvider.EP_NAME, FileContextProvider.class);
registerApplicationExtensionPoint(MetaDataContributor.EP_NAME, MetaDataContributor.class);
registerApplicationExtensionPoint(PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
registerApplicationExtensionPoint(JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
registerApplicationExtensionPoint(ContainerProvider.EP_NAME, ContainerProvider.class);
registerApplicationExtensionPoint(ClassFileDecompilers.getInstance().EP_NAME, ClassFileDecompilers.Decompiler.class);
registerApplicationExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(Extensions.getRootArea());
}
@Nullable
@Override
protected VirtualFileSystem createJrtFileSystem() {
return new CoreJrtFileSystem();
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2010-2019 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.cli.jvm.compiler;
import com.intellij.DynamicBundle;
import com.intellij.codeInsight.ContainerProvider;
import com.intellij.codeInsight.runner.JavaMainMethodProvider;
import com.intellij.core.JavaCoreApplicationEnvironment;
import com.intellij.lang.MetaLanguage;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.psi.FileContextProvider;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.meta.MetaDataContributor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnvironment {
public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
KotlinCoreApplicationEnvironment environment = new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
registerExtensionPoints();
return environment;
}
private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
super(parentDisposable, unitTestMode);
}
private static void registerExtensionPoints() {
registerApplicationExtensionPoint(DynamicBundle.LanguageBundleEP.EP_NAME, DynamicBundle.LanguageBundleEP.class);
registerApplicationExtensionPoint(FileContextProvider.EP_NAME, FileContextProvider.class);
registerApplicationExtensionPoint(MetaDataContributor.EP_NAME, MetaDataContributor.class);
registerApplicationExtensionPoint(PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
registerApplicationExtensionPoint(JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
registerApplicationExtensionPoint(ContainerProvider.EP_NAME, ContainerProvider.class);
registerApplicationExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(Extensions.getRootArea());
}
@Nullable
@Override
protected VirtualFileSystem createJrtFileSystem() {
return new CoreJrtFileSystem();
}
}

View File

@@ -40,6 +40,7 @@ import com.intellij.openapi.vfs.*
import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.PsiManager
import com.intellij.psi.compiled.ClassFileDecompilers
import com.intellij.psi.impl.JavaClassSupersImpl
import com.intellij.psi.impl.PsiElementFinderImpl
import com.intellij.psi.impl.PsiTreeChangePreprocessor
@@ -509,6 +510,11 @@ class KotlinCoreEnvironment private constructor(
val applicationEnvironment = KotlinCoreApplicationEnvironment.create(parentDisposable, unitTestMode)
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/compiler.xml")
// FIX ME WHEN BUNCH 202 REMOVED: this code is required to support compiler bundled to both 202 and 203.
// Please, remove "com.intellij.psi.classFileDecompiler" EP registration once 202 is no longer supported by the compiler
if (!Extensions.getRootArea().hasExtensionPoint("com.intellij.psi.classFileDecompiler")) {
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/core.xml")
}
registerApplicationServicesForCLI(applicationEnvironment)
registerApplicationServices(applicationEnvironment)
@@ -692,4 +698,4 @@ class KotlinCoreEnvironment private constructor(
}
}
}
}
}

View File

@@ -686,4 +686,4 @@ class KotlinCoreEnvironment private constructor(
}
}
}
}
}

View File

@@ -12,4 +12,6 @@ fun setupIdeaStandaloneExecution() {
System.getProperties().setProperty("psi.incremental.reparse.depth.limit", "1000")
System.getProperties().setProperty("ide.hide.excluded.files", "false")
System.getProperties().setProperty("ast.loading.filter", "false")
System.getProperties().setProperty("idea.ignore.disabled.plugins", "true")
System.getProperties().setProperty("idea.home.path", System.getProperty("java.io.tmpdir"))
}

View File

@@ -12,6 +12,4 @@ fun setupIdeaStandaloneExecution() {
System.getProperties().setProperty("psi.incremental.reparse.depth.limit", "1000")
System.getProperties().setProperty("ide.hide.excluded.files", "false")
System.getProperties().setProperty("ast.loading.filter", "false")
System.getProperties().setProperty("idea.ignore.disabled.plugins", "true")
System.getProperties().setProperty("idea.home.path", System.getProperty("java.io.tmpdir"))
}

View File

@@ -28,7 +28,7 @@ public final class Test : R|kotlin/Any| {
}
public final inline class Z : R|kotlin/Any| {
@R|kotlin/jvm/JvmInline|() public final inline class Z : R|kotlin/Any| {
public open operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean|
public open fun hashCode(): R|kotlin/Int|
@@ -41,3 +41,4 @@ public final inline class Z : R|kotlin/Any| {
public constructor(x: R|kotlin/Int|): R|test/Z|
}

View File

@@ -1,4 +1,4 @@
public final inline class Z : R|kotlin/Any| {
@R|kotlin/jvm/JvmInline|() public final inline class Z : R|kotlin/Any| {
public open operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean|
public open fun hashCode(): R|kotlin/Int|
@@ -11,3 +11,4 @@ public final inline class Z : R|kotlin/Any| {
@R|kotlin/PublishedApi|() internal constructor(value: R|kotlin/Int|): R|test/Z|
}

View File

@@ -40,6 +40,6 @@ public final const val s: R|kotlin/Short| = Short(20000)
public final const val s1: R|kotlin/Short| = Short(1)
public get(): R|kotlin/Short|
public final const val str: R|kotlin/String|
public final const val str: R|kotlin/String| = String(:))
public get(): R|kotlin/String|

View File

@@ -3,11 +3,11 @@ interface Some {
open fun bar() {}
open val x: Int
open val y = 1
open val y = <!PROPERTY_INITIALIZER_IN_INTERFACE!>1<!>
open val z get() = 1
open var xx: Int
open var yy = 1
open var yy = <!PROPERTY_INITIALIZER_IN_INTERFACE!>1<!>
open var zz: Int
set(value) {
field = value

View File

@@ -0,0 +1,44 @@
interface CommonBackendContext
interface PhaserState<Data> {
var depth: Int
}
interface PhaseConfig {
val needProfiling: Boolean
}
inline fun <R, D> PhaserState<D>.downlevel(nlevels: Int, block: () -> R): R {
depth += nlevels
val result = block()
depth -= nlevels
return result
}
interface CompilerPhase<in Context : CommonBackendContext, Input, Output> {
fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input): Output
}
class NamedCompilerPhase<in Context : CommonBackendContext, Data>(
private val lower: CompilerPhase<Context, Data, Data>
) : CompilerPhase<Context, Data, Data> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, input: Data): Data {
// Expected: output: Data, Actual: output: Data?
val output = if (phaseConfig.needProfiling) {
runAndProfile(phaseConfig, phaserState, context, input)
} else {
phaserState.downlevel(1) {
lower.invoke(phaseConfig, phaserState, context, input)
}
}
runAfter(phaseConfig, phaserState, context, output)
}
private fun runAfter(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, output: Data) {
}
private fun runAndProfile(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, source: Data): Data {
}
}

View File

@@ -0,0 +1,55 @@
FILE: compilerPhase.kt
public abstract interface CommonBackendContext : R|kotlin/Any| {
}
public abstract interface PhaserState<Data> : R|kotlin/Any| {
public abstract var depth: R|kotlin/Int|
public get(): R|kotlin/Int|
public set(value: R|kotlin/Int|): R|kotlin/Unit|
}
public abstract interface PhaseConfig : R|kotlin/Any| {
public abstract val needProfiling: R|kotlin/Boolean|
public get(): R|kotlin/Boolean|
}
public final inline fun <R, D> R|PhaserState<D>|.downlevel(nlevels: R|kotlin/Int|, block: R|() -> R|): R|R| {
this@R|/downlevel|.R|/PhaserState.depth| = this@R|/downlevel|.R|/PhaserState.depth|.R|kotlin/Int.plus|(R|<local>/nlevels|)
lval result: R|R| = R|<local>/block|.R|SubstitutionOverride<kotlin/Function0.invoke: R|R|>|()
this@R|/downlevel|.R|/PhaserState.depth| = this@R|/downlevel|.R|/PhaserState.depth|.R|kotlin/Int.minus|(R|<local>/nlevels|)
^downlevel R|<local>/result|
}
public abstract interface CompilerPhase<in Context : R|CommonBackendContext|, Input, Output> : R|kotlin/Any| {
public abstract fun invoke(phaseConfig: R|PhaseConfig|, phaserState: R|PhaserState<Input>|, context: R|Context|, input: R|Input|): R|Output|
}
public final class NamedCompilerPhase<in Context : R|CommonBackendContext|, Data> : R|CompilerPhase<Context, Data, Data>| {
public constructor<in Context : R|CommonBackendContext|, Data>(lower: R|CompilerPhase<Context, Data, Data>|): R|NamedCompilerPhase<Context, Data>| {
super<R|kotlin/Any|>()
}
private final val lower: R|CompilerPhase<Context, Data, Data>| = R|<local>/lower|
private get(): R|CompilerPhase<Context, Data, Data>|
public final override fun invoke(phaseConfig: R|PhaseConfig|, phaserState: R|PhaserState<Data>|, context: R|Context|, input: R|Data|): R|Data| {
lval output: R|Data| = when () {
R|<local>/phaseConfig|.R|/PhaseConfig.needProfiling| -> {
this@R|/NamedCompilerPhase|.R|/NamedCompilerPhase.runAndProfile|(R|<local>/phaseConfig|, R|<local>/phaserState|, R|<local>/context|, R|<local>/input|)
}
else -> {
R|<local>/phaserState|.R|/downlevel|<R|Data|, R|Data|>(Int(1), <L> = downlevel@fun <anonymous>(): R|Data| <kind=UNKNOWN> {
^ this@R|/NamedCompilerPhase|.R|/NamedCompilerPhase.lower|.R|SubstitutionOverride</CompilerPhase.invoke: R|Data|>|(R|<local>/phaseConfig|, R|<local>/phaserState|, R|<local>/context|, R|<local>/input|)
}
)
}
}
this@R|/NamedCompilerPhase|.R|/NamedCompilerPhase.runAfter|(R|<local>/phaseConfig|, R|<local>/phaserState|, R|<local>/context|, R|<local>/output|)
}
private final fun runAfter(phaseConfig: R|PhaseConfig|, phaserState: R|PhaserState<Data>|, context: R|Context|, output: R|Data|): R|kotlin/Unit| {
}
private final fun runAndProfile(phaseConfig: R|PhaseConfig|, phaserState: R|PhaserState<Data>|, context: R|Context|, source: R|Data|): R|Data| {
}
}

View File

@@ -0,0 +1,20 @@
// FILE: AliasFor.java
public @interface AliasFor {
@AliasFor(value = "attribute")
String value() default "";
@AliasFor(value = "value")
String attribute() default "";
}
// FILE: Service.java
public @interface Service {
@AliasFor(value = "component")
String value() default "";
}
// FILE: Annotated.kt
@Service(value = "Your")
class My

View File

@@ -0,0 +1,7 @@
FILE: Annotated.kt
@R|Service|(value = String(Your)) public final class My : R|kotlin/Any| {
public constructor(): R|My| {
super<R|kotlin/Any|>()
}
}

View File

@@ -2024,6 +2024,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/problems"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("compilerPhase.kt")
public void testCompilerPhase() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/compilerPhase.kt");
}
@TestMetadata("complexLambdaWithTypeVariableAsExpectedType.kt")
public void testComplexLambdaWithTypeVariableAsExpectedType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/complexLambdaWithTypeVariableAsExpectedType.kt");
@@ -2079,6 +2084,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/questionableSmartCast.kt");
}
@TestMetadata("recursiveNamedAnnotation.kt")
public void testRecursiveNamedAnnotation() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/recursiveNamedAnnotation.kt");
}
@TestMetadata("safeCallInvoke.kt")
public void testSafeCallInvoke() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/safeCallInvoke.kt");

View File

@@ -2024,6 +2024,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/problems"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("compilerPhase.kt")
public void testCompilerPhase() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/compilerPhase.kt");
}
@TestMetadata("complexLambdaWithTypeVariableAsExpectedType.kt")
public void testComplexLambdaWithTypeVariableAsExpectedType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/complexLambdaWithTypeVariableAsExpectedType.kt");
@@ -2079,6 +2084,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/problems/questionableSmartCast.kt");
}
@TestMetadata("recursiveNamedAnnotation.kt")
public void testRecursiveNamedAnnotation() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/recursiveNamedAnnotation.kt");
}
@TestMetadata("safeCallInvoke.kt")
public void testSafeCallInvoke() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/safeCallInvoke.kt");

View File

@@ -10659,6 +10659,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/captureTypeOnlyOnTopLevel.kt");
}
@TestMetadata("capturedFlexibleIntersectionTypesWithDifferentBounds.kt")
public void testCapturedFlexibleIntersectionTypesWithDifferentBounds() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentBounds.kt");
}
@TestMetadata("capturedFlexibleIntersectionTypesWithDifferentConstructors.kt")
public void testCapturedFlexibleIntersectionTypesWithDifferentConstructors() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt");
}
@TestMetadata("capturedType.kt")
public void testCapturedType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedType.kt");
@@ -12907,6 +12917,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassesInsideAnnotations.kt");
}
@TestMetadata("innerClassInsideInlineClass.kt")
public void testInnerClassInsideInlineClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/innerClassInsideInlineClass.kt");
}
@TestMetadata("lateinitInlineClasses.kt")
public void testLateinitInlineClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/lateinitInlineClasses.kt");
@@ -12942,6 +12957,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inlineClasses/unsignedLiteralsWithoutArtifactOnClasspath.kt");
}
@TestMetadata("varPropertyWithInlineClassReceiver.kt")
public void testVarPropertyWithInlineClassReceiver() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/varPropertyWithInlineClassReceiver.kt");
}
@TestMetadata("varargsOnParametersOfInlineClassType.kt")
public void testVarargsOnParametersOfInlineClassType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/varargsOnParametersOfInlineClassType.kt");

View File

@@ -2024,6 +2024,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/problems"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("compilerPhase.kt")
public void testCompilerPhase() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/compilerPhase.kt");
}
@TestMetadata("complexLambdaWithTypeVariableAsExpectedType.kt")
public void testComplexLambdaWithTypeVariableAsExpectedType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/complexLambdaWithTypeVariableAsExpectedType.kt");
@@ -2079,6 +2084,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
runTest("compiler/fir/analysis-tests/testData/resolve/problems/questionableSmartCast.kt");
}
@TestMetadata("recursiveNamedAnnotation.kt")
public void testRecursiveNamedAnnotation() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/recursiveNamedAnnotation.kt");
}
@TestMetadata("safeCallInvoke.kt")
public void testSafeCallInvoke() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/safeCallInvoke.kt");

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2010-2020 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
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.fir.*
fun FirSourceElement.getChild(type: IElementType, index: Int = 0, depth: Int = -1): FirSourceElement? {
return getChild(setOf(type), index, depth)
}
fun FirSourceElement.getChild(types: TokenSet, index: Int = 0, depth: Int = -1): FirSourceElement? {
return getChild(types.types.toSet(), index, depth)
}
fun FirSourceElement.getChild(types: Set<IElementType>, index: Int = 0, depth: Int = -1): FirSourceElement? {
return when (this) {
is FirPsiSourceElement<*> -> {
getChild(types, index, depth)
}
is FirLightSourceElement -> {
getChild(types, index, depth)
}
else -> null
}
}
private fun FirPsiSourceElement<*>.getChild(types: Set<IElementType>, index: Int, depth: Int): FirSourceElement? {
val visitor = PsiElementFinderByType(types, index, depth)
return visitor.find(psi)?.toFirPsiSourceElement()
}
private fun FirLightSourceElement.getChild(types: Set<IElementType>, index: Int, depth: Int): FirSourceElement? {
val visitor = LighterTreeElementFinderByType(treeStructure, types, index, depth)
return visitor.find(lighterASTNode)?.toFirLightSourceElement(treeStructure)
}

View File

@@ -112,7 +112,7 @@ class PropertyInitializationInfoCollector(private val localProperties: Set<FirPr
}
fun getData(graph: ControlFlowGraph) =
graph.collectPathAwareDataForNode(
graph.collectDataForNode(
TraverseDirection.Forward,
PathAwarePropertyInitializationInfo.EMPTY,
this
@@ -128,15 +128,14 @@ class PropertyInitializationInfoCollector(private val localProperties: Set<FirPr
}
internal fun <P : PathAwareControlFlowInfo<P, S>, S : ControlFlowInfo<S, K, EventOccurrencesRange>, K : Any> addRange(
info: P,
pathAwareInfo: P,
key: K,
range: EventOccurrencesRange,
constructor: (PersistentMap<EdgeLabel, S>) -> P
): P {
var resultMap = persistentMapOf<EdgeLabel, S>()
// before: { |-> { p1 |-> PI1 }, l1 |-> { p2 |-> PI2 } }
for (label in info.keys) {
val dataPerLabel = info[label]!!
for ((label, dataPerLabel) in pathAwareInfo) {
val existingKind = dataPerLabel[key] ?: EventOccurrencesRange.ZERO
val kind = existingKind + range
resultMap = resultMap.put(label, dataPerLabel.put(key, kind))

View File

@@ -31,14 +31,12 @@ fun ControlFlowGraph.traverse(
traverse(direction, visitor, null)
}
// ---------------------- Path-sensitive data collection -----------------------
// --------------------- Path-insensitive data collection ----------------------
// TODO: Deprecate and make all existing checkers path-sensitive
fun <I : ControlFlowInfo<I, K, V>, K : Any, V : Any> ControlFlowGraph.collectDataForNode(
direction: TraverseDirection,
initialInfo: I,
visitor: ControlFlowGraphVisitor<I, Collection<I>>
visitor: ControlFlowGraphVisitor<I, Collection<Pair<EdgeLabel, I>>>
): Map<CFGNode<*>, I> {
val nodeMap = LinkedHashMap<CFGNode<*>, I>()
val startNode = getEnterNode(direction)
@@ -53,56 +51,6 @@ fun <I : ControlFlowInfo<I, K, V>, K : Any, V : Any> ControlFlowGraph.collectDat
}
private fun <I : ControlFlowInfo<I, K, V>, K : Any, V : Any> ControlFlowGraph.collectDataForNodeInternal(
direction: TraverseDirection,
initialInfo: I,
visitor: ControlFlowGraphVisitor<I, Collection<I>>,
nodeMap: MutableMap<CFGNode<*>, I>,
changed: MutableMap<CFGNode<*>, Boolean>
) {
val nodes = getNodesInOrder(direction)
for (node in nodes) {
if (direction == TraverseDirection.Backward && node is CFGNodeWithCfgOwner<*>) {
node.subGraphs.forEach { it.collectDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed) }
}
val previousNodes = when (direction) {
TraverseDirection.Forward -> node.previousCfgNodes
TraverseDirection.Backward -> node.followingCfgNodes
}
val previousData = previousNodes.mapNotNull { nodeMap[it] }
val data = nodeMap[node]
val newData = node.accept(visitor, previousData)
val hasChanged = newData != data
changed[node] = hasChanged
if (hasChanged) {
nodeMap[node] = newData
}
if (direction == TraverseDirection.Forward && node is CFGNodeWithCfgOwner<*>) {
node.subGraphs.forEach { it.collectDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed) }
}
}
}
// ---------------------- Path-sensitive data collection -----------------------
// TODO: Once migration is done, get rid of "PathAware" from util names
fun <I : ControlFlowInfo<I, K, V>, K : Any, V : Any> ControlFlowGraph.collectPathAwareDataForNode(
direction: TraverseDirection,
initialInfo: I,
visitor: ControlFlowGraphVisitor<I, Collection<Pair<EdgeLabel, I>>>
): Map<CFGNode<*>, I> {
val nodeMap = LinkedHashMap<CFGNode<*>, I>()
val startNode = getEnterNode(direction)
nodeMap[startNode] = initialInfo
val changed = mutableMapOf<CFGNode<*>, Boolean>()
do {
collectPathAwareDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed)
} while (changed.any { it.value })
return nodeMap
}
private fun <I : ControlFlowInfo<I, K, V>, K : Any, V : Any> ControlFlowGraph.collectPathAwareDataForNodeInternal(
direction: TraverseDirection,
initialInfo: I,
visitor: ControlFlowGraphVisitor<I, Collection<Pair<EdgeLabel, I>>>,
@@ -112,7 +60,7 @@ private fun <I : ControlFlowInfo<I, K, V>, K : Any, V : Any> ControlFlowGraph.co
val nodes = getNodesInOrder(direction)
for (node in nodes) {
if (direction == TraverseDirection.Backward && node is CFGNodeWithCfgOwner<*>) {
node.subGraphs.forEach { it.collectPathAwareDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed) }
node.subGraphs.forEach { it.collectDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed) }
}
val previousNodes = when (direction) {
TraverseDirection.Forward -> node.previousCfgNodes
@@ -136,7 +84,7 @@ private fun <I : ControlFlowInfo<I, K, V>, K : Any, V : Any> ControlFlowGraph.co
nodeMap[node] = newData
}
if (direction == TraverseDirection.Forward && node is CFGNodeWithCfgOwner<*>) {
node.subGraphs.forEach { it.collectPathAwareDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed) }
node.subGraphs.forEach { it.collectDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed) }
}
}
}

View File

@@ -80,7 +80,7 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
}
}
val invocationData = graph.collectPathAwareDataForNode(
val invocationData = graph.collectDataForNode(
TraverseDirection.Forward,
PathAwareLambdaInvocationInfo.EMPTY,
InvocationDataCollector(functionalTypeEffects.keys.filterTo(mutableSetOf()) { it !in leakedSymbols })
@@ -89,9 +89,9 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
for ((symbol, effectDeclaration) in functionalTypeEffects) {
graph.exitNode.previousCfgNodes.forEach { node ->
val requiredRange = effectDeclaration.kind
val info = invocationData.getValue(node)
for (label in info.keys) {
if (investigate(info.getValue(label), symbol, requiredRange, function, reporter)) {
val pathAwareInfo = invocationData.getValue(node)
for (info in pathAwareInfo.values) {
if (investigate(info, symbol, requiredRange, function, reporter)) {
// To avoid duplicate reports, stop investigating remaining paths once reported.
break
}

View File

@@ -49,8 +49,8 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
if (symbol !in localProperties) return
if (symbol.fir.isLateInit) return
val pathAwareInfo = data.getValue(node)
for (label in pathAwareInfo.keys) {
if (investigate(pathAwareInfo[label]!!, symbol, node)) {
for (info in pathAwareInfo.values) {
if (investigate(info, symbol, node)) {
// To avoid duplicate reports, stop investigating remaining paths if the property is not initialized at any path.
break
}

View File

@@ -12,6 +12,9 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSymbolOwner
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
@@ -250,20 +253,21 @@ fun FirMemberDeclaration.implicitModality(context: CheckerContext): Modality {
}
val klass = context.findClosestClassOrObject() ?: return Modality.FINAL
val modifiers = this.modifierListOrNull() ?: return Modality.FINAL
if (modifiers.contains(KtTokens.OVERRIDE_KEYWORD)) {
val klassModifiers = klass.modifierListOrNull()
if (klassModifiers != null && klassModifiers.run {
contains(KtTokens.ABSTRACT_KEYWORD) || contains(KtTokens.OPEN_KEYWORD) || contains(KtTokens.SEALED_KEYWORD)
}) {
val source = source ?: return Modality.FINAL
val tree = source.treeStructure
if (tree.overrideModifier(source.lighterASTNode) != null) {
val klassModalityTokenType = klass.source?.let { tree.modalityModifier(it.lighterASTNode)?.tokenType }
if (klassModalityTokenType == KtTokens.ABSTRACT_KEYWORD ||
klassModalityTokenType == KtTokens.OPEN_KEYWORD ||
klassModalityTokenType == KtTokens.SEALED_KEYWORD
) {
return Modality.OPEN
}
}
if (
klass is FirRegularClass
if (klass is FirRegularClass
&& klass.classKind == ClassKind.INTERFACE
&& !modifiers.contains(KtTokens.PRIVATE_KEYWORD)
&& tree.visibilityModifier(source.lighterASTNode)?.tokenType != KtTokens.PRIVATE_KEYWORD
) {
return if (this.hasBody()) Modality.OPEN else Modality.ABSTRACT
}
@@ -271,8 +275,6 @@ fun FirMemberDeclaration.implicitModality(context: CheckerContext): Modality {
return Modality.FINAL
}
private fun FirDeclaration.modifierListOrNull() = this.source.getModifierList()?.modifiers?.map { it.token }
private fun FirDeclaration.hasBody(): Boolean = when (this) {
is FirSimpleFunction -> this.body != null && this.body !is FirEmptyExpressionBlock
is FirProperty -> this.setter?.body !is FirEmptyExpressionBlock? || this.getter?.body !is FirEmptyExpressionBlock?

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2010-2020 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
import com.intellij.lang.ASTNode
import com.intellij.lang.LighterASTNode
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.TokenSet
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtModifierList
import org.jetbrains.kotlin.psi.KtModifierListOwner
sealed class FirModifierList {
abstract val modifiers: List<FirModifier<*>>
}
fun FirSourceElement?.getModifierList(): FirModifierList? {
return when (this) {
null -> null
is FirPsiSourceElement<*> -> (psi as? KtModifierListOwner)?.modifierList?.let { FirPsiModifierList(it) }
is FirLightSourceElement -> {
val modifierListNode = lighterASTNode.getChildren(treeStructure).find { it?.tokenType == KtNodeTypes.MODIFIER_LIST }
?: return null
FirLightModifierList(modifierListNode, treeStructure)
}
}
}
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD, KtTokens.FUN_KEYWORD))
class FirPsiModifierList(val modifierList: KtModifierList) : FirModifierList() {
override val modifiers: List<FirPsiModifier>
get() = modifierList.node.getChildren(MODIFIER_KEYWORD_SET).map { node ->
FirPsiModifier(node, node.elementType as KtModifierKeywordToken)
}
}
class FirLightModifierList(val modifierList: LighterASTNode, val tree: FlyweightCapableTreeStructure<LighterASTNode>) : FirModifierList() {
override val modifiers: List<FirLightModifier>
get() {
val modifierNodes = modifierList.getChildren(tree)
return modifierNodes.filterNotNull()
.filter { it.tokenType is KtModifierKeywordToken }
.map { FirLightModifier(it, it.tokenType as KtModifierKeywordToken, tree) }
}
}
sealed class FirModifier<Node : Any>(val node: Node, val token: KtModifierKeywordToken)
class FirPsiModifier(
node: ASTNode,
token: KtModifierKeywordToken
) : FirModifier<ASTNode>(node, token)
class FirLightModifier(
node: LighterASTNode,
token: KtModifierKeywordToken,
val tree: FlyweightCapableTreeStructure<LighterASTNode>
) : FirModifier<LighterASTNode>(node, token)
val FirModifier<*>.psi: PsiElement? get() = (this as? FirPsiModifier)?.node?.psi
val FirModifier<*>.lightNode: LighterASTNode? get() = (this as? FirLightModifier)?.node
val FirModifier<*>.source: FirSourceElement?
get() = when (this) {
is FirPsiModifier -> psi?.toFirPsiSourceElement()
is FirLightModifier -> node.toFirLightSourceElement(tree)
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2010-2020 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 org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
// See old FE's [DeclarationsChecker]
object FirMemberPropertyChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirRegularClass) {
return
}
for (member in declaration.declarations) {
if (member is FirProperty) {
checkProperty(declaration, member, reporter)
}
}
}
private fun checkProperty(containingDeclaration: FirRegularClass, property: FirProperty, reporter: DiagnosticReporter) {
if (inInterface(containingDeclaration) &&
property.visibility == Visibilities.Private &&
!property.isAbstract &&
(property.getter == null || property.getter is FirDefaultPropertyAccessor)
) {
property.source?.let { source ->
reporter.report(source, FirErrors.PRIVATE_PROPERTY_IN_INTERFACE)
}
}
if (property.isAbstract) {
if (!containingDeclaration.isAbstract && !containingDeclaration.isSealed && !inEnumClass(containingDeclaration)) {
property.source?.let { source ->
reporter.report(source, FirErrors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS)
return
}
}
if (property.delegate != null) {
property.delegate!!.source?.let {
if (inInterface(containingDeclaration)) {
reporter.report(FirErrors.DELEGATED_PROPERTY_IN_INTERFACE.on(it, property.delegate!!))
} else {
reporter.report(FirErrors.ABSTRACT_DELEGATED_PROPERTY.on(it, property.delegate!!))
}
}
}
checkAccessor(property.getter, property.delegate) { src, symbol ->
reporter.report(FirErrors.ABSTRACT_PROPERTY_WITH_GETTER.on(src, symbol))
}
checkAccessor(property.setter, property.delegate) { src, symbol ->
if (symbol.fir.visibility == Visibilities.Private && property.visibility != Visibilities.Private) {
reporter.report(FirErrors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY.on(src, symbol))
} else {
reporter.report(FirErrors.ABSTRACT_PROPERTY_WITH_SETTER.on(src, symbol))
}
}
}
checkPropertyInitializer(containingDeclaration, property, reporter)
if (property.isOpen) {
checkAccessor(property.setter, property.delegate) { src, symbol ->
if (symbol.fir.visibility == Visibilities.Private && property.visibility != Visibilities.Private) {
reporter.report(FirErrors.PRIVATE_SETTER_FOR_OPEN_PROPERTY.on(src, symbol))
}
}
}
}
private fun checkPropertyInitializer(containingDeclaration: FirRegularClass, property: FirProperty, reporter: DiagnosticReporter) {
property.initializer?.source?.let {
if (property.isAbstract) {
reporter.report(FirErrors.ABSTRACT_PROPERTY_WITH_INITIALIZER.on(it, property.initializer!!))
} else if (inInterface(containingDeclaration)) {
reporter.report(FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE.on(it, property.initializer!!))
}
}
if (property.isAbstract) {
if (property.initializer == null && property.delegate == null && property.returnTypeRef is FirImplicitTypeRef) {
property.source?.let {
reporter.report(FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(it, property.symbol))
}
}
}
}
private fun checkAccessor(
accessor: FirPropertyAccessor?,
delegate: FirExpression?,
report: (FirSourceElement, FirPropertyAccessorSymbol) -> Unit,
) {
if (accessor != null && accessor !is FirDefaultPropertyAccessor && accessor.hasBody && delegate == null) {
accessor.source?.let {
report.invoke(it, accessor.symbol)
}
}
}
private fun inInterface(containingDeclaration: FirRegularClass): Boolean =
containingDeclaration.classKind == ClassKind.INTERFACE
private fun inEnumClass(containingDeclaration: FirRegularClass): Boolean =
containingDeclaration.classKind == ClassKind.ENUM_CLASS
}

View File

@@ -5,19 +5,22 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import com.intellij.lang.ASTNode
import com.intellij.lang.LighterASTNode
import com.intellij.psi.tree.TokenSet
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.FirModifier
import org.jetbrains.kotlin.fir.analysis.checkers.FirModifierList
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
import org.jetbrains.kotlin.fir.analysis.checkers.source
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.KtModifierList
import org.jetbrains.kotlin.psi.KtModifierListOwner
object FirModifierChecker : FirBasicDeclarationChecker() {
@@ -112,7 +115,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
val firstToken = firstModifier.token
val secondToken = secondModifier.token
when (val compatibilityType = deduceCompatibilityType(firstToken, secondToken)) {
CompatibilityType.COMPATIBLE -> {}
CompatibilityType.COMPATIBLE -> {
}
CompatibilityType.REPEATED ->
if (reportedNodes.add(secondModifier)) reporter.reportRepeatedModifier(secondModifier, secondToken)
CompatibilityType.REDUNDANT_2_TO_1 ->
@@ -170,35 +174,94 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
if (!isDeclarationMappedToSourceCorrectly(declaration, source)) return
if (context.containingDeclarations.last() is FirDefaultPropertyAccessor) return
val modifierList = source.getModifierList()
val modifierList = with(FirModifierList) { source.getModifierList() }
modifierList?.let { checkModifiers(it, declaration, reporter) }
}
private fun DiagnosticReporter.reportRepeatedModifier(
modifier: FirModifier<*>, keyword: KtModifierKeywordToken
) {
val source = modifier.source
source?.let { report(FirErrors.REPEATED_MODIFIER.on(it, keyword)) }
report(FirErrors.REPEATED_MODIFIER.on(modifier.source, keyword))
}
private fun DiagnosticReporter.reportRedundantModifier(
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken
) {
val source = modifier.source
source?.let { report(FirErrors.REDUNDANT_MODIFIER.on(it, firstKeyword, secondKeyword)) }
report(FirErrors.REDUNDANT_MODIFIER.on(modifier.source, firstKeyword, secondKeyword))
}
private fun DiagnosticReporter.reportDeprecatedModifierPair(
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken
) {
val source = modifier.source
source?.let { report(FirErrors.DEPRECATED_MODIFIER_PAIR.on(it, firstKeyword, secondKeyword)) }
report(FirErrors.DEPRECATED_MODIFIER_PAIR.on(modifier.source, firstKeyword, secondKeyword))
}
private fun DiagnosticReporter.reportIncompatibleModifiers(
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken
) {
val source = modifier.source
source?.let { report(FirErrors.INCOMPATIBLE_MODIFIERS.on(it, firstKeyword, secondKeyword)) }
report(FirErrors.INCOMPATIBLE_MODIFIERS.on(modifier.source, firstKeyword, secondKeyword))
}
private sealed class FirModifierList {
abstract val modifiers: List<FirModifier<*>>
class FirPsiModifierList(val modifierList: KtModifierList) : FirModifierList() {
override val modifiers: List<FirModifier.FirPsiModifier>
get() = modifierList.node.getChildren(MODIFIER_KEYWORD_SET).map { node ->
FirModifier.FirPsiModifier(node, node.elementType as KtModifierKeywordToken)
}
}
class FirLightModifierList(
val modifierList: LighterASTNode,
val tree: FlyweightCapableTreeStructure<LighterASTNode>
) : FirModifierList() {
override val modifiers: List<FirModifier.FirLightModifier>
get() {
val modifierNodes = modifierList.getChildren(tree)
return modifierNodes.filterNotNull()
.filter { it.tokenType is KtModifierKeywordToken }
.map { FirModifier.FirLightModifier(it, it.tokenType as KtModifierKeywordToken, tree) }
}
}
companion object {
fun FirSourceElement?.getModifierList(): FirModifierList? {
return when (this) {
null -> null
is FirPsiSourceElement<*> -> (psi as? KtModifierListOwner)?.modifierList?.let { FirPsiModifierList(it) }
is FirLightSourceElement -> {
val modifierListNode = lighterASTNode.getChildren(treeStructure).find { it?.tokenType == KtNodeTypes.MODIFIER_LIST }
?: return null
FirLightModifierList(modifierListNode, treeStructure)
}
}
}
}
}
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(SOFT_KEYWORDS, TokenSet.create(IN_KEYWORD, FUN_KEYWORD))
sealed class FirModifier<Node : Any>(val node: Node, val token: KtModifierKeywordToken) {
class FirPsiModifier(
node: ASTNode,
token: KtModifierKeywordToken
) : FirModifier<ASTNode>(node, token) {
override val source: FirSourceElement
get() = node.psi.toFirPsiSourceElement()
}
class FirLightModifier(
node: LighterASTNode,
token: KtModifierKeywordToken,
val tree: FlyweightCapableTreeStructure<LighterASTNode>
) : FirModifier<LighterASTNode>(node, token) {
override val source: FirSourceElement
get() = node.toFirLightSourceElement(tree)
}
abstract val source: FirSourceElement
}
}

View File

@@ -5,22 +5,12 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import com.intellij.lang.LighterASTNode
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes.TYPE_ARGUMENT_LIST
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.psi.KtTypeArgumentList
object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -29,36 +19,13 @@ object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessChecker()
val explicitReceiver = expression.explicitReceiver
if (explicitReceiver is FirResolvedQualifier && explicitReceiver.symbol == null) {
if (explicitReceiver.source?.hasAnyArguments() == true) {
if (explicitReceiver.typeArguments.isNotEmpty()) {
reporter.report(explicitReceiver.source)
return
}
}
}
private fun FirSourceElement.hasAnyArguments(): Boolean {
val localPsi = this.psi
val localLight = this.lighterASTNode
if (localPsi != null && localPsi !is PsiErrorElement) {
return localPsi.hasAnyArguments()
} else if (this is FirLightSourceElement) {
return localLight.hasAnyArguments(this.treeStructure)
}
return false
}
private fun PsiElement.hasAnyArguments(): Boolean {
val children = this.children // this is a method call and it collects children
return children.size > 1 && children[1] is KtTypeArgumentList
}
private fun LighterASTNode.hasAnyArguments(tree: FlyweightCapableTreeStructure<LighterASTNode>): Boolean {
val children = getChildren(tree)
return children.count { it != null } > 1 && children[1]?.tokenType == TYPE_ARGUMENT_LIST
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let {
report(FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.on(it))

View File

@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
import org.jetbrains.kotlin.fir.expressions.FirOperation
import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -17,7 +16,6 @@ import org.jetbrains.kotlin.fir.expressions.arguments
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.lexer.KtTokens
object ArrayEqualityCanBeReplacedWithEquals : FirBasicExpressionChecker() {
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -29,7 +27,6 @@ object ArrayEqualityCanBeReplacedWithEquals : FirBasicExpressionChecker() {
if (left.typeRef.coneType.classId != StandardClassIds.Array) return
if (right.typeRef.coneType.classId != StandardClassIds.Array) return
val source = expression.source?.getChild(setOf(KtTokens.EQEQ, KtTokens.EXCLEQ))
reporter.report(source, ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS)
reporter.report(expression.source, ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS)
}
}

View File

@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirExpressionChecke
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
@@ -59,8 +58,7 @@ object CanBeReplacedWithOperatorAssignmentChecker : FirExpressionChecker<FirVari
}
if (needToReport) {
val source = expression.source?.getChild(setOf(KtTokens.EQ))
reporter.report(source, FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT)
reporter.report(expression.source, FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT)
}
}

View File

@@ -12,11 +12,9 @@ import org.jetbrains.kotlin.fir.analysis.cfa.*
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.lexer.KtTokens
object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
override fun analyze(
@@ -42,7 +40,7 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
var lastDestructuredVariables = 0
for ((symbol, value) in propertiesCharacteristics) {
val source = symbol.fir.source?.getChild(setOf(KtTokens.VAL_KEYWORD, KtTokens.VAR_KEYWORD), depth = 1)
val source = symbol.fir.source
if (symbol.isDestructuring) {
lastDestructuringSource = source
lastDestructuredVariables = symbol.getDestructuringChildrenCount() ?: continue
@@ -97,15 +95,11 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
}
}
private fun FirPropertySymbol.getDestructuringChildrenCount(): Int? = when (fir.source) {
is FirPsiSourceElement<*> -> fir.psi?.children?.size?.minus(1) // -1 cuz we don't need expression node after equals operator
is FirLightSourceElement -> {
val source = fir.source as FirLightSourceElement
val tree = (fir.source as FirLightSourceElement).treeStructure
val children = source.lighterASTNode.getChildren(tree)
children.filter { it?.tokenType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY }.size
private fun FirPropertySymbol.getDestructuringChildrenCount(): Int? {
val source = fir.source ?: return null
return source.lighterASTNode.getChildren(source.treeStructure).count {
it?.tokenType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY
}
else -> null
}
private val FirPropertySymbol.isDestructuring

View File

@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers.extended
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
@@ -17,14 +15,11 @@ import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -71,10 +66,10 @@ object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
}
}
is FirNamedReference -> {
if (typeReference.text != initializer.name.identifier) return
if (!type.hasSameNameWithoutModifiers(initializer.name)) return
}
is FirFunctionCall -> {
if (typeReference.text != initializer.calleeReference.name.asString()) return
if (!type.hasSameNameWithoutModifiers(initializer.calleeReference.name)) return
}
is FirGetClassCall -> {
return
@@ -91,23 +86,12 @@ object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
reporter.report(declaration.returnTypeRef.source, FirErrors.REDUNDANT_EXPLICIT_TYPE)
}
private val FirTypeRef.text: String?
get() {
return when (source) {
is FirPsiSourceElement<*> -> {
source.psi?.text
}
is FirLightSourceElement -> {
source?.lighterASTNode?.toString()
}
else -> null
}
}
private fun ConeKotlinType.isSame(other: ClassId?): Boolean {
if (this.nullability.isNullable) return false
if (this.type.classId == other) return true
return false
}
private fun ConeKotlinType.hasSameNameWithoutModifiers(name: Name): Boolean =
this is ConeClassLikeType && lookupTag.name == name && typeArguments.isEmpty() && !isMarkedNullable
}

View File

@@ -11,17 +11,17 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.implicitModality
import org.jetbrains.kotlin.fir.analysis.checkers.toToken
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.modality
object RedundantModalityModifierChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.source?.kind is FirFakeSourceElementKind) return
val source = declaration.source
if (source?.kind is FirFakeSourceElementKind) return
val modality = declaration.modality ?: return
if (
@@ -29,11 +29,10 @@ object RedundantModalityModifierChecker : FirMemberDeclarationChecker() {
&& (context.containingDeclarations.last() as? FirClass<*>)?.classKind == ClassKind.INTERFACE
) return
if (source != null && source.treeStructure.modalityModifier(source.lighterASTNode) == null) return
val implicitModality = declaration.implicitModality(context)
if (modality != implicitModality) return
val modalityModifierSource = declaration.source?.getChild(modality.toToken(), depth = 2)
reporter.report(modalityModifierSource, REDUNDANT_MODALITY_MODIFIER)
reporter.report(source, REDUNDANT_MODALITY_MODIFIER)
}
}

View File

@@ -16,34 +16,31 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
object RedundantVisibilityModifierChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration is FirConstructor && declaration.source?.kind is FirFakeSourceElementKind) return
if (declaration.source is FirFakeSourceElement<*>) return
val source = declaration.source ?: return
if (declaration is FirConstructor && source.kind is FirFakeSourceElementKind) return
if (source is FirFakeSourceElement<*>) return
if (
declaration !is FirMemberDeclaration
&& !(declaration is FirPropertyAccessor && declaration.visibility == context.containingPropertyVisibility)
) return
val modifiers = declaration.source.getModifierList()
val visibilityModifier = when (modifiers) {
is FirPsiModifierList -> modifiers.modifierList.getVisibility()
is FirLightModifierList -> modifiers.modifiers.visibilityOrNull()
else -> null
} ?: return
val visibilityModifier = source.treeStructure.visibilityModifier(source.lighterASTNode)
val explicitVisibility = (visibilityModifier?.tokenType as? KtModifierKeywordToken)?.toVisibilityOrNull()
val implicitVisibility = declaration.implicitVisibility(context)
val containingMemberDeclaration = context.findClosest<FirMemberDeclaration>()
val redundantVisibility = when {
visibilityModifier == implicitVisibility -> implicitVisibility
modifiers?.modifiers.hasModifier(KtTokens.INTERNAL_KEYWORD) &&
explicitVisibility == implicitVisibility -> implicitVisibility
explicitVisibility == Visibilities.Internal &&
containingMemberDeclaration.let { decl ->
decl != null && (decl.isLocalMember || modifiers?.modifiers.hasModifier(KtTokens.PRIVATE_KEYWORD))
decl != null && decl.isLocalMember
} -> Visibilities.Internal
else -> return
}
@@ -51,12 +48,12 @@ object RedundantVisibilityModifierChecker : FirBasicDeclarationChecker() {
if (
redundantVisibility == Visibilities.Public
&& declaration is FirProperty
&& modifiers?.modifiers.hasModifier(KtTokens.OVERRIDE_KEYWORD)
&& source.treeStructure.overrideModifier(source.lighterASTNode) != null
&& declaration.isVar
&& declaration.setter?.visibility == Visibilities.Public
) return
reporter.report(declaration.source?.getChild(KtTokens.VISIBILITY_MODIFIERS), FirErrors.REDUNDANT_VISIBILITY_MODIFIER)
reporter.report(source, FirErrors.REDUNDANT_VISIBILITY_MODIFIER)
}
private fun FirDeclaration.implicitVisibility(context: CheckerContext): Visibility {
@@ -126,10 +123,4 @@ object RedundantVisibilityModifierChecker : FirBasicDeclarationChecker() {
private val CheckerContext.containingPropertyVisibility
get() = (this.containingDeclarations.last() as? FirProperty)?.visibility
private fun List<FirLightModifier>.visibilityOrNull() =
firstOrNull { it.token.toVisibilityOrNull() != null }?.token?.toVisibilityOrNull()
private fun List<FirModifier<*>>?.hasModifier(token: KtModifierKeywordToken) = this != null && any { it.token == token }
}

View File

@@ -7,8 +7,8 @@ package org.jetbrains.kotlin.fir.analysis.checkers.extended
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.FirSymbolOwner
import org.jetbrains.kotlin.fir.analysis.cfa.*
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
@@ -17,16 +17,17 @@ import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass
import org.jetbrains.kotlin.fir.analysis.checkers.isIterator
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.lexer.KtTokens
object UnusedChecker : FirControlFlowChecker() {
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, checkerContext: CheckerContext) {
if ((graph.declaration as? FirSymbolOwner<*>)?.getContainingClass(checkerContext)?.takeIf { !it.symbol.classId.isLocal }!= null) return
if ((graph.declaration as? FirSymbolOwner<*>)?.getContainingClass(checkerContext)?.takeIf {
!it.symbol.classId.isLocal
} != null
) return
val properties = LocalPropertyCollector.collect(graph)
if (properties.isEmpty()) return
@@ -35,42 +36,52 @@ object UnusedChecker : FirControlFlowChecker() {
}
class CfaVisitor(
val data: Map<CFGNode<*>, VariableStatusInfo>,
val data: Map<CFGNode<*>, PathAwareVariableStatusInfo>,
val reporter: DiagnosticReporter
) : ControlFlowGraphVisitorVoid() {
override fun visitNode(node: CFGNode<*>) {}
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
val variableSymbol = (node.fir.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol ?: return
val data = data[node]?.get(variableSymbol) ?: return
if (data == VariableStatus.ONLY_WRITTEN_NEVER_READ) {
// todo: report case like "a += 1" where `a` `doesn't writes` different way (special for Idea)
val source = node.fir.lValue.source
reporter.report(source, FirErrors.ASSIGNED_VALUE_IS_NEVER_READ)
val dataPerNode = data[node] ?: return
for (dataPerLabel in dataPerNode.values) {
val data = dataPerLabel[variableSymbol] ?: continue
if (data == VariableStatus.ONLY_WRITTEN_NEVER_READ) {
// todo: report case like "a += 1" where `a` `doesn't writes` different way (special for Idea)
val source = node.fir.lValue.source
reporter.report(source, FirErrors.ASSIGNED_VALUE_IS_NEVER_READ)
// To avoid duplicate reports, stop investigating remaining paths once reported.
break
}
}
}
override fun visitVariableDeclarationNode(node: VariableDeclarationNode) {
val variableSymbol = node.fir.symbol
if (variableSymbol.isLoopIterator) return
val data = data[node]?.get(variableSymbol) ?: return
val dataPerNode = data[node] ?: return
for (dataPerLabel in dataPerNode.values) {
val data = dataPerLabel[variableSymbol] ?: continue
when {
data == VariableStatus.UNUSED -> {
if ((node.fir.initializer as? FirFunctionCall)?.isIterator != true) {
val source = variableSymbol.identifierSource
reporter.report(source, FirErrors.UNUSED_VARIABLE)
val variableSource = variableSymbol.fir.source.takeIf { it?.elementType != KtNodeTypes.DESTRUCTURING_DECLARATION }
when {
data == VariableStatus.UNUSED -> {
if ((node.fir.initializer as? FirFunctionCall)?.isIterator != true) {
reporter.report(variableSource, FirErrors.UNUSED_VARIABLE)
break
}
}
data.isRedundantInit -> {
val source = variableSymbol.fir.initializer?.source
reporter.report(source, FirErrors.VARIABLE_INITIALIZER_IS_REDUNDANT)
break
}
data == VariableStatus.ONLY_WRITTEN_NEVER_READ -> {
reporter.report(variableSource, FirErrors.VARIABLE_NEVER_READ)
break
}
else -> {
}
}
data.isRedundantInit -> {
val source = variableSymbol.fir.initializer?.source
reporter.report(source, FirErrors.VARIABLE_INITIALIZER_IS_REDUNDANT)
}
data == VariableStatus.ONLY_WRITTEN_NEVER_READ -> {
val source = variableSymbol.identifierSource
reporter.report(source, FirErrors.VARIABLE_NEVER_READ)
}
else -> {
}
}
}
@@ -122,72 +133,102 @@ object UnusedChecker : FirControlFlowChecker() {
}
class PathAwareVariableStatusInfo(
map: PersistentMap<EdgeLabel, VariableStatusInfo> = persistentMapOf()
) : PathAwareControlFlowInfo<PathAwareVariableStatusInfo, VariableStatusInfo>(map) {
companion object {
val EMPTY = PathAwareVariableStatusInfo(persistentMapOf(NormalPath to VariableStatusInfo.EMPTY))
}
override val constructor: (PersistentMap<EdgeLabel, VariableStatusInfo>) -> PathAwareVariableStatusInfo =
::PathAwareVariableStatusInfo
override val empty: () -> PathAwareVariableStatusInfo =
::EMPTY
}
private class ValueWritesWithoutReading(
private val localProperties: Set<FirPropertySymbol>
) : ControlFlowGraphVisitor<VariableStatusInfo, Collection<VariableStatusInfo>>() {
fun getData(graph: ControlFlowGraph): Map<CFGNode<*>, VariableStatusInfo> {
return graph.collectDataForNode(TraverseDirection.Backward, VariableStatusInfo.EMPTY, this)
) : ControlFlowGraphVisitor<PathAwareVariableStatusInfo, Collection<Pair<EdgeLabel, PathAwareVariableStatusInfo>>>() {
fun getData(graph: ControlFlowGraph): Map<CFGNode<*>, PathAwareVariableStatusInfo> {
return graph.collectDataForNode(TraverseDirection.Backward, PathAwareVariableStatusInfo.EMPTY, this)
}
override fun visitNode(node: CFGNode<*>, data: Collection<VariableStatusInfo>): VariableStatusInfo {
if (data.isEmpty()) return VariableStatusInfo.EMPTY
return data.reduce(VariableStatusInfo::merge)
override fun visitNode(
node: CFGNode<*>,
data: Collection<Pair<EdgeLabel, PathAwareVariableStatusInfo>>
): PathAwareVariableStatusInfo {
if (data.isEmpty()) return PathAwareVariableStatusInfo.EMPTY
return data.map { (label, info) -> info.applyLabel(node, label) }
.reduce(PathAwareVariableStatusInfo::merge)
}
override fun visitVariableDeclarationNode(node: VariableDeclarationNode, data: Collection<VariableStatusInfo>): VariableStatusInfo {
override fun visitVariableDeclarationNode(
node: VariableDeclarationNode,
data: Collection<Pair<EdgeLabel, PathAwareVariableStatusInfo>>
): PathAwareVariableStatusInfo {
val dataForNode = visitNode(node, data)
if (node.fir.source?.kind is FirFakeSourceElementKind) return dataForNode
val symbol = node.fir.symbol
return when (dataForNode[symbol]) {
null -> {
dataForNode.put(symbol, VariableStatus.UNUSED)
}
VariableStatus.ONLY_WRITTEN_NEVER_READ, VariableStatus.WRITTEN_AFTER_READ -> {
if (node.fir.initializer != null && dataForNode[symbol]?.isRead == true) {
val newData = dataForNode[symbol] ?: VariableStatus.UNUSED
newData.isRedundantInit = true
dataForNode.put(symbol, newData)
} else if (node.fir.initializer != null) {
dataForNode.put(symbol, VariableStatus.ONLY_WRITTEN_NEVER_READ)
} else {
dataForNode
return update(dataForNode, symbol) { prev ->
when (prev) {
null -> {
VariableStatus.UNUSED
}
VariableStatus.ONLY_WRITTEN_NEVER_READ, VariableStatus.WRITTEN_AFTER_READ -> {
if (node.fir.initializer != null && prev.isRead) {
prev.isRedundantInit = true
prev
} else if (node.fir.initializer != null) {
VariableStatus.ONLY_WRITTEN_NEVER_READ
} else {
null
}
}
VariableStatus.READ -> {
VariableStatus.READ
}
else -> {
null
}
}
VariableStatus.READ -> {
dataForNode.put(symbol, VariableStatus.READ)
}
else -> {
dataForNode
}
}
}
override fun visitVariableAssignmentNode(node: VariableAssignmentNode, data: Collection<VariableStatusInfo>): VariableStatusInfo {
override fun visitVariableAssignmentNode(
node: VariableAssignmentNode,
data: Collection<Pair<EdgeLabel, PathAwareVariableStatusInfo>>
): PathAwareVariableStatusInfo {
val dataForNode = visitNode(node, data)
val reference = node.fir.lValue as? FirResolvedNamedReference ?: return dataForNode
val symbol = reference.resolvedSymbol as? FirPropertySymbol ?: return dataForNode
val toPut = when {
symbol !in localProperties -> {
null
}
dataForNode[symbol] == VariableStatus.READ -> {
VariableStatus.WRITTEN_AFTER_READ
}
dataForNode[symbol] == VariableStatus.WRITTEN_AFTER_READ -> {
VariableStatus.ONLY_WRITTEN_NEVER_READ
}
else -> {
VariableStatus.ONLY_WRITTEN_NEVER_READ.merge(dataForNode[symbol] ?: VariableStatus.UNUSED)
return update(dataForNode, symbol) update@{ prev ->
val toPut = when {
symbol !in localProperties -> {
null
}
prev == VariableStatus.READ -> {
VariableStatus.WRITTEN_AFTER_READ
}
prev == VariableStatus.WRITTEN_AFTER_READ -> {
VariableStatus.ONLY_WRITTEN_NEVER_READ
}
else -> {
VariableStatus.ONLY_WRITTEN_NEVER_READ.merge(prev ?: VariableStatus.UNUSED)
}
}
toPut ?: return@update null
toPut.isRead = prev?.isRead ?: false
toPut
}
toPut ?: return dataForNode
toPut.isRead = dataForNode[symbol]?.isRead ?: false
return dataForNode.put(symbol, toPut)
}
override fun visitQualifiedAccessNode(node: QualifiedAccessNode, data: Collection<VariableStatusInfo>): VariableStatusInfo {
override fun visitQualifiedAccessNode(
node: QualifiedAccessNode,
data: Collection<Pair<EdgeLabel, PathAwareVariableStatusInfo>>
): PathAwareVariableStatusInfo {
val dataForNode = visitNode(node, data)
if (node.fir.source?.kind is FirFakeSourceElementKind) return dataForNode
val reference = node.fir.calleeReference as? FirResolvedNamedReference ?: return dataForNode
@@ -197,13 +238,29 @@ object UnusedChecker : FirControlFlowChecker() {
val status = VariableStatus.READ
status.isRead = true
return dataForNode.put(symbol, status)
return update(dataForNode, symbol) { status }
}
private fun update(
pathAwareInfo: PathAwareVariableStatusInfo,
symbol: FirPropertySymbol,
updater: (VariableStatus?) -> VariableStatus?,
): PathAwareVariableStatusInfo {
var resultMap = persistentMapOf<EdgeLabel, VariableStatusInfo>()
var changed = false
for ((label, dataPerLabel) in pathAwareInfo) {
val v = updater.invoke(dataPerLabel[symbol])
if (v != null) {
resultMap = resultMap.put(label, dataPerLabel.put(symbol, v))
changed = true
} else {
resultMap = resultMap.put(label, dataPerLabel)
}
}
return if (changed) PathAwareVariableStatusInfo(resultMap) else pathAwareInfo
}
}
private val FirPropertySymbol.isLoopIterator
get() = fir.initializer?.source?.kind == FirFakeSourceElementKind.DesugaredForLoop
private val FirPropertySymbol.identifierSource: FirSourceElement?
get() = fir.source?.getChild(KtTokens.IDENTIFIER, 0, 1)
}

View File

@@ -12,7 +12,9 @@ import org.jetbrains.kotlin.fir.FirEffectiveVisibility
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
@@ -147,6 +149,23 @@ object FirErrors {
val LOCAL_OBJECT_NOT_ALLOWED by error1<FirSourceElement, KtNamedDeclaration, Name>(SourceElementPositioningStrategies.DECLARATION_NAME)
val LOCAL_INTERFACE_NOT_ALLOWED by error1<FirSourceElement, KtNamedDeclaration, Name>(SourceElementPositioningStrategies.DECLARATION_NAME)
// Properties & accessors
val ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.MODALITY_MODIFIER)
val PRIVATE_PROPERTY_IN_INTERFACE by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
val ABSTRACT_PROPERTY_WITH_INITIALIZER by error1<FirSourceElement, PsiElement, FirExpression>()
val PROPERTY_INITIALIZER_IN_INTERFACE by error1<FirSourceElement, PsiElement, FirExpression>()
val PROPERTY_WITH_NO_TYPE_NO_INITIALIZER by error1<FirSourceElement, PsiElement, FirPropertySymbol>()
val ABSTRACT_DELEGATED_PROPERTY by error1<FirSourceElement, PsiElement, FirExpression>()
val DELEGATED_PROPERTY_IN_INTERFACE by error1<FirSourceElement, PsiElement, FirExpression>()
// TODO: val ACCESSOR_FOR_DELEGATED_PROPERTY by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>()
val ABSTRACT_PROPERTY_WITH_GETTER by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>()
val ABSTRACT_PROPERTY_WITH_SETTER by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>()
val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>()
val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>()
// Control flow diagnostics
val UNINITIALIZED_VARIABLE by error1<FirSourceElement, PsiElement, FirPropertySymbol>()
val WRONG_INVOCATION_KIND by warning3<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>, EventOccurrencesRange, EventOccurrencesRange>()
@@ -154,20 +173,20 @@ object FirErrors {
val WRONG_IMPLIES_CONDITION by error0<FirSourceElement, PsiElement>()
// Extended checkers group
val REDUNDANT_VISIBILITY_MODIFIER by warning0<FirSourceElement, PsiElement>()
val REDUNDANT_MODALITY_MODIFIER by warning0<FirSourceElement, PsiElement>()
val REDUNDANT_VISIBILITY_MODIFIER by warning0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
val REDUNDANT_MODALITY_MODIFIER by warning0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.MODALITY_MODIFIER)
val REDUNDANT_RETURN_UNIT_TYPE by warning0<FirSourceElement, PsiTypeElement>()
val REDUNDANT_EXPLICIT_TYPE by warning0<FirSourceElement, PsiElement>()
val REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE by warning0<FirSourceElement, PsiElement>()
val CAN_BE_VAL by warning0<FirSourceElement, PsiElement>()
val CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT by warning0<FirSourceElement, PsiElement>()
val CAN_BE_VAL by warning0<FirSourceElement, KtDeclaration>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
val CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT by warning0<FirSourceElement, KtExpression>(SourceElementPositioningStrategies.OPERATOR)
val REDUNDANT_CALL_OF_CONVERSION_METHOD by warning0<FirSourceElement, PsiElement>()
val ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS by warning0<FirSourceElement, PsiElement>()
val ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS by warning0<FirSourceElement, KtExpression>(SourceElementPositioningStrategies.OPERATOR)
val EMPTY_RANGE by warning0<FirSourceElement, PsiElement>()
val REDUNDANT_SETTER_PARAMETER_TYPE by warning0<FirSourceElement, PsiElement>()
val UNUSED_VARIABLE by warning0<FirSourceElement, PsiElement>()
val UNUSED_VARIABLE by warning0<FirSourceElement, KtNamedDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
val ASSIGNED_VALUE_IS_NEVER_READ by warning0<FirSourceElement, PsiElement>()
val VARIABLE_INITIALIZER_IS_REDUNDANT by warning0<FirSourceElement, PsiElement>()
val VARIABLE_NEVER_READ by warning0<FirSourceElement, PsiElement>()
val VARIABLE_NEVER_READ by warning0<FirSourceElement, KtNamedDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
val USELESS_CALL_ON_NOT_NULL by warning0<FirSourceElement, PsiElement>()
}

View File

@@ -14,6 +14,8 @@ import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.MODALITY_MODIFIERS
import org.jetbrains.kotlin.lexer.KtTokens.VISIBILITY_MODIFIERS
import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET
object LightTreePositioningStrategies {
@@ -142,6 +144,32 @@ object LightTreePositioningStrategies {
return super.mark(node, tree)
}
}
private class ModifierSetBasedLightTreePositioningStrategy(private val modifierSet: TokenSet) : LightTreePositioningStrategy() {
override fun mark(node: LighterASTNode, tree: FlyweightCapableTreeStructure<LighterASTNode>): List<TextRange> {
tree.findChildByType(node, modifierSet)?.let { return markElement(it, tree) }
tree.nameIdentifier(node)?.let { return markElement(it, tree) }
return when (node.tokenType) {
KtNodeTypes.OBJECT_DECLARATION -> {
markElement(tree.objectKeyword(node)!!, tree)
}
KtNodeTypes.PROPERTY_ACCESSOR -> {
markElement(tree.accessorNamePlaceholder(node), tree)
}
else -> markElement(node, tree)
}
}
}
val VISIBILITY_MODIFIER: LightTreePositioningStrategy = ModifierSetBasedLightTreePositioningStrategy(VISIBILITY_MODIFIERS)
val MODALITY_MODIFIER: LightTreePositioningStrategy = ModifierSetBasedLightTreePositioningStrategy(MODALITY_MODIFIERS)
val OPERATOR: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
override fun mark(node: LighterASTNode, tree: FlyweightCapableTreeStructure<LighterASTNode>): List<TextRange> {
return markElement(tree.operationReference(node) ?: node, tree)
}
}
}
fun FirSourceElement.hasValOrVar(): Boolean =
@@ -162,6 +190,9 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.initKeyword(node: Ligh
private fun FlyweightCapableTreeStructure<LighterASTNode>.nameIdentifier(node: LighterASTNode): LighterASTNode? =
findChildByType(node, KtTokens.IDENTIFIER)
private fun FlyweightCapableTreeStructure<LighterASTNode>.operationReference(node: LighterASTNode): LighterASTNode? =
findChildByType(node, KtNodeTypes.OPERATION_REFERENCE)
private fun FlyweightCapableTreeStructure<LighterASTNode>.rightParenthesis(node: LighterASTNode): LighterASTNode? =
findChildByType(node, KtTokens.RPAR)
@@ -171,6 +202,15 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.objectKeyword(node: Li
private fun FlyweightCapableTreeStructure<LighterASTNode>.valOrVarKeyword(node: LighterASTNode): LighterASTNode? =
findChildByType(node, VAL_VAR_TOKEN_SET)
internal fun FlyweightCapableTreeStructure<LighterASTNode>.visibilityModifier(declaration: LighterASTNode): LighterASTNode? =
modifierList(declaration)?.let { findChildByType(it, VISIBILITY_MODIFIERS) }
internal fun FlyweightCapableTreeStructure<LighterASTNode>.modalityModifier(declaration: LighterASTNode): LighterASTNode? =
modifierList(declaration)?.let { findChildByType(it, MODALITY_MODIFIERS) }
internal fun FlyweightCapableTreeStructure<LighterASTNode>.overrideModifier(declaration: LighterASTNode): LighterASTNode? =
modifierList(declaration)?.let { findChildByType(it, KtTokens.OVERRIDE_KEYWORD) }
private fun FlyweightCapableTreeStructure<LighterASTNode>.accessorNamePlaceholder(node: LighterASTNode): LighterASTNode =
findChildByType(node, KtTokens.GET_KEYWORD) ?: findChildByType(node, KtTokens.SET_KEYWORD)!!

View File

@@ -32,4 +32,19 @@ object SourceElementPositioningStrategies {
LightTreePositioningStrategies.DECLARATION_SIGNATURE,
PositioningStrategies.DECLARATION_SIGNATURE
)
val VISIBILITY_MODIFIER = SourceElementPositioningStrategy(
LightTreePositioningStrategies.VISIBILITY_MODIFIER,
PositioningStrategies.VISIBILITY_MODIFIER
)
val MODALITY_MODIFIER = SourceElementPositioningStrategy(
LightTreePositioningStrategies.MODALITY_MODIFIER,
PositioningStrategies.MODALITY_MODIFIER
)
val OPERATOR = SourceElementPositioningStrategy(
LightTreePositioningStrategies.OPERATOR,
PositioningStrategies.OPERATOR
)
}

View File

@@ -43,6 +43,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val regularClassCheckers: Set<FirRegularClassChecker> = setOf(
FirTypeMismatchOnOverrideChecker,
FirMemberPropertyChecker,
)
override val constructorCheckers: Set<FirConstructorChecker> = setOf(

View File

@@ -20,24 +20,21 @@ import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerial
class FirConstDeserializer(
val session: FirSession,
private val partSource: KotlinJvmBinaryClass? = null,
private val facadeSource: KotlinJvmBinaryClass? = null
private val binaryClass: KotlinJvmBinaryClass? = null
) {
companion object {
private val constantCache = mutableMapOf<CallableId, FirExpression>()
}
private val constantCache = mutableMapOf<CallableId, FirExpression>()
fun loadConstant(propertyProto: ProtoBuf.Property, callableId: CallableId, nameResolver: NameResolver): FirExpression? {
if (!Flags.HAS_CONSTANT.get(propertyProto.flags)) return null
constantCache[callableId]?.let { return it }
if (facadeSource == null && partSource == null) {
if (binaryClass == null) {
val value = propertyProto.getExtensionOrNull(BuiltInSerializerProtocol.compileTimeValue) ?: return null
return buildFirConstant(value, null, value.type.name, nameResolver)?.apply { constantCache[callableId] = this }
}
(facadeSource ?: partSource)!!.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor {
binaryClass.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor {
override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor? = null
override fun visitField(name: Name, desc: String, initializer: Any?): KotlinJvmBinaryClass.AnnotationVisitor? {
@@ -60,11 +57,11 @@ class FirConstDeserializer(
"CHAR", "C" -> buildConstExpression(null, FirConstKind.Char, ((protoValue?.intValue ?: sourceValue) as Number).toChar())
"SHORT", "S" -> buildConstExpression(null, FirConstKind.Short, ((protoValue?.intValue ?: sourceValue) as Number).toShort())
"INT", "I" -> buildConstExpression(null, FirConstKind.Int, protoValue?.intValue?.toInt() ?: sourceValue as Int)
"LONG", "J" -> buildConstExpression(null, FirConstKind.Long, (protoValue?.intValue ?: sourceValue) as Long)
"FLOAT", "F" -> buildConstExpression(null, FirConstKind.Float, (protoValue?.floatValue ?: sourceValue) as Float)
"DOUBLE", "D" -> buildConstExpression(null, FirConstKind.Double, (protoValue?.doubleValue ?: sourceValue) as Double)
"LONG", "J" -> buildConstExpression(null, FirConstKind.Long, protoValue?.intValue ?: sourceValue as Long)
"FLOAT", "F" -> buildConstExpression(null, FirConstKind.Float, protoValue?.floatValue ?: sourceValue as Float)
"DOUBLE", "D" -> buildConstExpression(null, FirConstKind.Double, protoValue?.doubleValue ?: sourceValue as Double)
"BOOLEAN", "Z" -> buildConstExpression(null, FirConstKind.Boolean, (protoValue?.intValue?.toInt() ?: sourceValue) != 0)
"STRING", "Ljava/lang/String" -> buildConstExpression(
"STRING", "Ljava/lang/String;" -> buildConstExpression(
null, FirConstKind.String, protoValue?.stringValue?.let { nameResolver.getString(it) } ?: sourceValue as String
)
else -> null

View File

@@ -205,9 +205,6 @@ class FirElementSerializer private constructor(
var hasGetter = false
var hasSetter = false
//val compileTimeConstant = property.compileTimeInitializer
val hasConstant = false // TODO: compileTimeConstant != null && compileTimeConstant !is NullValue
val hasAnnotations = property.nonSourceAnnotations(session).isNotEmpty()
// TODO: hasAnnotations(descriptor) || hasAnnotations(descriptor.backingField) || hasAnnotations(descriptor.delegateField)
@@ -247,6 +244,7 @@ class FirElementSerializer private constructor(
}
}
val hasConstant = property.isConst // TODO: this is only correct with LanguageFeature.NoConstantValueAttributeForNonConstVals
val flags = Flags.getPropertyFlags(
hasAnnotations,
ProtoEnumFlags.visibility(normalizeVisibility(property)),

View File

@@ -14,14 +14,14 @@ import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.inference.*
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.ir.util.*
@@ -86,8 +86,17 @@ 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 ConeClassLikeType.buildPossiblyInnerType(): PossiblyInnerConeType? =
buildPossiblyInnerType(lookupTag.toSymbol(session) as? FirRegularClassSymbol?, 0)
buildPossiblyInnerType(lookupTag.toSymbol(session)?.toRegularClassSymbol(), 0)
private fun ConeClassLikeType.parentClassOrNull(): FirRegularClassSymbol? {
val parentClassId = classId?.outerClassId ?: return null

View File

@@ -338,7 +338,8 @@ internal fun IrDeclarationParent.declareThisReceiverParameter(
symbolTable.irFactory.createValueParameter(
startOffset, endOffset, thisOrigin, symbol,
Name.special("<this>"), UNDEFINED_PARAMETER_INDEX, thisType,
varargElementType = null, isCrossinline = false, isNoinline = false, isAssignable = false
varargElementType = null, isCrossinline = false, isNoinline = false,
isHidden = false, isAssignable = false
).apply {
this.parent = this@declareThisReceiverParameter
receiverDescriptor.bind(this)

View File

@@ -269,7 +269,8 @@ class Fir2IrDeclarationStorage(
startOffset, endOffset, IrDeclarationOrigin.DEFINED, symbol,
Name.special("<set-?>"), 0, type,
varargElementType = null,
isCrossinline = false, isNoinline = false, isAssignable = false
isCrossinline = false, isNoinline = false,
isHidden = false, isAssignable = false
).apply {
this.parent = parent
descriptor.bind(this)
@@ -404,9 +405,7 @@ class Fir2IrDeclarationStorage(
factory: (IrSimpleFunctionSymbol) -> IrSimpleFunction
): IrSimpleFunction {
if (signature == null) {
val descriptor =
if (containerSource != null) WrappedFunctionDescriptorWithContainerSource()
else WrappedSimpleFunctionDescriptor()
val descriptor = WrappedSimpleFunctionDescriptor()
return symbolTable.declareSimpleFunction(descriptor, factory).apply { descriptor.bind(this) }
}
return symbolTable.declareSimpleFunction(signature, { Fir2IrSimpleFunctionSymbol(signature, containerSource) }, factory)
@@ -687,9 +686,7 @@ class Fir2IrDeclarationStorage(
factory: (IrPropertySymbol) -> IrProperty
): IrProperty {
if (signature == null) {
val descriptor =
if (containerSource != null) WrappedPropertyDescriptorWithContainerSource()
else WrappedPropertyDescriptor()
val descriptor = WrappedPropertyDescriptor()
return symbolTable.declareProperty(0, 0, IrDeclarationOrigin.DEFINED, descriptor, isDelegated = false, factory).apply {
descriptor.bind(this)
}
@@ -899,7 +896,8 @@ class Fir2IrDeclarationStorage(
valueParameter.name, index, type,
if (!valueParameter.isVararg) null
else valueParameter.returnTypeRef.coneType.arrayElementType()?.toIrType(typeContext),
valueParameter.isCrossinline, valueParameter.isNoinline
isCrossinline = valueParameter.isCrossinline, isNoinline = valueParameter.isNoinline,
isHidden = false, isAssignable = false
).apply {
descriptor.bind(this)
if (valueParameter.defaultValue.let {

View File

@@ -266,6 +266,7 @@ internal class AdapterGenerator(
varargElementType = null,
isCrossinline = false,
isNoinline = false,
isHidden = false,
isAssignable = false
).also { irAdapterValueParameter ->
descriptor.bind(irAdapterValueParameter)

View File

@@ -7,14 +7,14 @@ package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.hasMetaAnnotationUseSiteTargets
import org.jetbrains.kotlin.fir.declarations.useSiteTargetsFromMetaAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.util.isPropertyField
import org.jetbrains.kotlin.ir.util.isSetter
/**
@@ -36,80 +36,73 @@ class AnnotationGenerator(private val components: Fir2IrComponents) : Fir2IrComp
irContainer.annotations = firContainer.annotations.toIrAnnotations()
}
fun generate(irValueParameter: IrValueParameter, firValueParameter: FirValueParameter, isInConstructor: Boolean) {
irValueParameter.annotations +=
firValueParameter.annotations
.filter {
// TODO: for `null` use-site, refer to targets on the meta annotation
it.useSiteTarget == null || !isInConstructor || it.useSiteTarget == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER
}
.toIrAnnotations()
private fun FirAnnotationCall.target(applicable: List<AnnotationUseSiteTarget>): AnnotationUseSiteTarget? =
useSiteTarget ?: applicable.firstOrNull(useSiteTargetsFromMetaAnnotation(session)::contains)
companion object {
// Priority order: constructor parameter (if applicable) -> property -> field. So, for example, if `A`
// can be attached to all three, then in a declaration like
// class C(@A val x: Int) { @A val y = 1 }
// the parameter `x` and the property `y` will have the annotation, while the property `x` and both backing fields will not.
private val propertyTargets = listOf(AnnotationUseSiteTarget.PROPERTY, AnnotationUseSiteTarget.FIELD)
private val constructorPropertyTargets = listOf(AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER) + propertyTargets
private val delegatedPropertyTargets = propertyTargets + listOf(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD)
}
private fun FirAnnotationCall.targetsField(): Boolean =
// Check if the annotation has a field-targeting meta annotation, e.g., @Target(FIELD)
hasMetaAnnotationUseSiteTargets(session, AnnotationUseSiteTarget.FIELD, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD)
// TODO: third argument should be whether this parameter is a property declaration (though this probably makes no difference)
fun generate(irValueParameter: IrValueParameter, firValueParameter: FirValueParameter, isInConstructor: Boolean) {
if (isInConstructor) {
irValueParameter.annotations += firValueParameter.annotations
.filter { it.target(constructorPropertyTargets) == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER }
.toIrAnnotations()
} else {
irValueParameter.annotations += firValueParameter.annotations.toIrAnnotations()
}
}
fun generate(irProperty: IrProperty, property: FirProperty) {
irProperty.annotations +=
property.annotations
.filter {
it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY ||
// NB: annotation with null use-site should be landed on the property (ahead of field),
// unless it has FIELD target on the meta annotation, like @Target(FIELD)
(it.useSiteTarget == null && !it.targetsField())
}
.toIrAnnotations()
val applicableTargets = when {
property.source?.kind == FirFakeSourceElementKind.PropertyFromParameter -> constructorPropertyTargets
irProperty.isDelegated -> delegatedPropertyTargets
else -> propertyTargets
}
irProperty.annotations += property.annotations
.filter { it.target(applicableTargets) == AnnotationUseSiteTarget.PROPERTY }
.toIrAnnotations()
}
fun generate(irField: IrField, property: FirProperty) {
assert(irField.isPropertyField) {
"$irField is not a property field."
val irProperty = irField.correspondingPropertySymbol?.owner ?: throw AssertionError("$irField is not a property field")
val applicableTargets = when {
property.source?.kind == FirFakeSourceElementKind.PropertyFromParameter -> constructorPropertyTargets
irProperty.isDelegated -> delegatedPropertyTargets
else -> propertyTargets
}
irField.annotations +=
property.annotations
.filter {
it.useSiteTarget == AnnotationUseSiteTarget.FIELD ||
it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD ||
(it.useSiteTarget == null && it.targetsField())
}
.toIrAnnotations()
irField.annotations += property.annotations.filter {
val target = it.target(applicableTargets)
target == AnnotationUseSiteTarget.FIELD || target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
}.toIrAnnotations()
}
fun generate(propertyAccessor: IrFunction, property: FirProperty) {
assert(propertyAccessor.isPropertyAccessor) {
"$propertyAccessor is not a property accessor."
}
assert(propertyAccessor.isPropertyAccessor) { "$propertyAccessor is not a property accessor." }
if (propertyAccessor.isSetter) {
propertyAccessor.annotations +=
property.annotations
.filter {
it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_SETTER
}
.toIrAnnotations()
propertyAccessor.valueParameters.singleOrNull()?.annotations =
propertyAccessor.valueParameters.singleOrNull()?.annotations?.plus(
property.annotations
.filter {
it.useSiteTarget == AnnotationUseSiteTarget.SETTER_PARAMETER
}
.toIrAnnotations()
)!!
propertyAccessor.annotations += property.annotations
.filter { it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_SETTER }
.toIrAnnotations()
val parameter = propertyAccessor.valueParameters.single()
parameter.annotations += property.annotations
.filter { it.useSiteTarget == AnnotationUseSiteTarget.SETTER_PARAMETER }
.toIrAnnotations()
} else {
propertyAccessor.annotations +=
property.annotations
.filter {
it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_GETTER
}
.toIrAnnotations()
propertyAccessor.annotations += property.annotations
.filter { it.useSiteTarget == AnnotationUseSiteTarget.PROPERTY_GETTER }
.toIrAnnotations()
}
propertyAccessor.extensionReceiverParameter?.let { receiver ->
receiver.annotations += property.annotations
.filter { it.useSiteTarget == AnnotationUseSiteTarget.RECEIVER }
.toIrAnnotations()
}
propertyAccessor.extensionReceiverParameter?.annotations =
propertyAccessor.extensionReceiverParameter?.annotations?.plus(
property.annotations
.filter {
it.useSiteTarget == AnnotationUseSiteTarget.RECEIVER
}
.toIrAnnotations()
)!!
}
}

View File

@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.references.FirDelegateFieldReference
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.calls.getExpectedTypeForSAMConversion
import org.jetbrains.kotlin.fir.resolve.calls.isFunctional
@@ -445,8 +446,14 @@ class CallAndReferenceGenerator(
is FirDelegatedConstructorCall -> call.calleeReference
is FirAnnotationCall -> call.calleeReference
else -> null
} as? FirResolvedNamedReference
val function = (calleeReference?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
}
val function = if (calleeReference == FirReferencePlaceholderForResolvedAnnotations) {
val coneClassLikeType = (call as FirAnnotationCall).annotationTypeRef.coneTypeSafe<ConeClassLikeType>()
val firClass = (coneClassLikeType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol)?.fir
firClass?.declarations?.filterIsInstance<FirConstructor>()?.firstOrNull()
} else {
((calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
}
val valueParameters = function?.valueParameters
val argumentMapping = call.argumentMapping
if (argumentMapping != null && (annotationMode || argumentMapping.isNotEmpty())) {
@@ -559,11 +566,13 @@ class CallAndReferenceGenerator(
}
}
with(adapterGenerator) {
irArgument = irArgument.applySuspendConversionIfNeeded(argument, parameter)
if (parameter?.returnTypeRef is FirResolvedTypeRef) {
// Java type case (from annotations)
irArgument = irArgument.applySuspendConversionIfNeeded(argument, parameter)
irArgument = irArgument.applySamConversionIfNeeded(argument, parameter)
}
}
return irArgument
.applySamConversionIfNeeded(argument, parameter)
.applyAssigningArrayElementsToVarargInNamedForm(argument, parameter)
return irArgument.applyAssigningArrayElementsToVarargInNamedForm(argument, parameter)
}
private fun IrExpression.applySamConversionIfNeeded(

View File

@@ -295,7 +295,7 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
) { symbol ->
components.irFactory.createValueParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, symbol, name, index, type, null,
isCrossinline = false, isNoinline = false, isAssignable = false
isCrossinline = false, isNoinline = false, isHidden = false, isAssignable = false
)
}.apply {
parent = irFunction

View File

@@ -232,13 +232,14 @@ class FakeOverrideGenerator(
private fun IrProperty.discardAccessorsAccordingToBaseVisibility(baseSymbols: List<FirPropertySymbol>) {
for (baseSymbol in baseSymbols) {
val unwrapped = baseSymbol.unwrapFakeOverrides()
val unwrappedSymbol = baseSymbol.unwrapFakeOverrides()
val unwrappedProperty = unwrappedSymbol.fir
// Do not create fake overrides for accessors if not allowed to do so, e.g., private lateinit var.
if (unwrapped.fir.getter?.allowsToHaveFakeOverride != true) {
if (!(unwrappedProperty.getter?.allowsToHaveFakeOverride ?: unwrappedProperty.allowsToHaveFakeOverride)) {
getter = null
}
// or private setter
if (unwrapped.fir.setter?.allowsToHaveFakeOverride != true) {
if (!(unwrappedProperty.setter?.allowsToHaveFakeOverride ?: unwrappedProperty.allowsToHaveFakeOverride)) {
setter = null
}
}

View File

@@ -6,8 +6,6 @@
package org.jetbrains.kotlin.fir.symbols
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.*
@@ -42,8 +40,6 @@ abstract class Fir2IrBindableSymbol<out D : DeclarationDescriptor, B : IrSymbolO
is IrClass -> WrappedClassDescriptor().apply { bind(owner) }
is IrConstructor -> WrappedClassConstructorDescriptor().apply { bind(owner) }
is IrSimpleFunction -> when {
containerSource != null ->
WrappedFunctionDescriptorWithContainerSource()
owner.name.isSpecial && owner.name.asString().startsWith(GETTER_PREFIX) ->
WrappedPropertyGetterDescriptor()
owner.name.isSpecial && owner.name.asString().startsWith(SETTER_PREFIX) ->
@@ -54,11 +50,7 @@ abstract class Fir2IrBindableSymbol<out D : DeclarationDescriptor, B : IrSymbolO
is IrVariable -> WrappedVariableDescriptor().apply { bind(owner) }
is IrValueParameter -> WrappedValueParameterDescriptor().apply { bind(owner) }
is IrTypeParameter -> WrappedTypeParameterDescriptor().apply { bind(owner) }
is IrProperty -> if (containerSource != null) {
WrappedPropertyDescriptorWithContainerSource()
} else {
WrappedPropertyDescriptor()
}.apply { bind(owner) }
is IrProperty -> WrappedPropertyDescriptor().apply { bind(owner) }
is IrField -> WrappedFieldDescriptor().apply { bind(owner) }
is IrTypeAlias -> WrappedTypeAliasDescriptor().apply { bind(owner) }
else -> throw IllegalStateException("Unsupported owner in Fir2IrBindableSymbol: $owner")

View File

@@ -148,6 +148,11 @@ public class FirCompileKotlinAgainstKotlinTestGenerated extends AbstractFirCompi
runTest("compiler/testData/compileKotlinAgainstKotlin/expectClassActualTypeAlias.kt");
}
@TestMetadata("importCompanion.kt")
public void testImportCompanion() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/importCompanion.kt");
}
@TestMetadata("inlineClassFromBinaryDependencies.kt")
public void testInlineClassFromBinaryDependencies() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/inlineClassFromBinaryDependencies.kt");
@@ -243,6 +248,11 @@ public class FirCompileKotlinAgainstKotlinTestGenerated extends AbstractFirCompi
runTest("compiler/testData/compileKotlinAgainstKotlin/jvmStaticInObject.kt");
}
@TestMetadata("jvmStaticInObjectPropertyReference.kt")
public void testJvmStaticInObjectPropertyReference() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/jvmStaticInObjectPropertyReference.kt");
}
@TestMetadata("kotlinPropertyAsAnnotationParameter.kt")
public void testKotlinPropertyAsAnnotationParameter() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/kotlinPropertyAsAnnotationParameter.kt");

View File

@@ -3840,6 +3840,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/classes/exceptionConstructor.kt");
}
@TestMetadata("extensionFunWithDefaultParam.kt")
public void testExtensionFunWithDefaultParam() throws Exception {
runTest("compiler/testData/codegen/box/classes/extensionFunWithDefaultParam.kt");
}
@TestMetadata("extensionOnNamedClassObject.kt")
public void testExtensionOnNamedClassObject() throws Exception {
runTest("compiler/testData/codegen/box/classes/extensionOnNamedClassObject.kt");
@@ -5018,6 +5023,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/collections/inheritFromHashtable.kt");
}
@TestMetadata("internalRemove.kt")
public void testInternalRemove() throws Exception {
runTest("compiler/testData/codegen/box/collections/internalRemove.kt");
}
@TestMetadata("internalRemoveFromJava.kt")
public void testInternalRemoveFromJava() throws Exception {
runTest("compiler/testData/codegen/box/collections/internalRemoveFromJava.kt");
}
@TestMetadata("irrelevantImplCharSequence.kt")
public void testIrrelevantImplCharSequence() throws Exception {
runTest("compiler/testData/codegen/box/collections/irrelevantImplCharSequence.kt");
@@ -5058,6 +5073,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/collections/javaCollectionWithRemovePrimitiveInt.kt");
}
@TestMetadata("kt40305.kt")
public void testKt40305() throws Exception {
runTest("compiler/testData/codegen/box/collections/kt40305.kt");
}
@TestMetadata("kt41123.kt")
public void testKt41123() throws Exception {
runTest("compiler/testData/codegen/box/collections/kt41123.kt");
@@ -9833,6 +9853,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/defaultArguments/function/covariantOverrideGeneric.kt");
}
@TestMetadata("defaultLambdaInline.kt")
public void testDefaultLambdaInline() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/defaultLambdaInline.kt");
}
@TestMetadata("extensionFunctionManyArgs.kt")
public void testExtensionFunctionManyArgs() throws Exception {
runTest("compiler/testData/codegen/box/defaultArguments/function/extensionFunctionManyArgs.kt");
@@ -12189,6 +12214,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
}
@TestMetadata("noOptimizedCallableReferences.kt")
public void testNoOptimizedCallableReferences() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/noOptimizedCallableReferences.kt");
}
@TestMetadata("nonAbstractMethod.kt")
public void testNonAbstractMethod() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/nonAbstractMethod.kt");
@@ -12562,6 +12592,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt");
}
@TestMetadata("nestedBigArityFunCalls.kt")
public void testNestedBigArityFunCalls() throws Exception {
runTest("compiler/testData/codegen/box/functions/bigArity/nestedBigArityFunCalls.kt");
}
@TestMetadata("subclass.kt")
public void testSubclass() throws Exception {
runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt");
@@ -14127,6 +14162,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inlineClasses/mappingOfBoxedFlexibleInlineClassType.kt");
}
@TestMetadata("multifileClass.kt")
public void testMultifileClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/multifileClass.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");
@@ -15139,6 +15184,59 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Jvm8DefaultInterfaceMethods extends AbstractFirBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_FIR: ");
}
public void testAllFilesPresentInJvm8DefaultInterfaceMethods() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("javaDefaultMethod.kt")
public void testJavaDefaultMethod() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/javaDefaultMethod.kt");
}
@TestMetadata("javaDefaultMethodOverriddenByKotlin.kt")
public void testJavaDefaultMethodOverriddenByKotlin() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/javaDefaultMethodOverriddenByKotlin.kt");
}
@TestMetadata("jvmDefaultAll.kt")
public void testJvmDefaultAll() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAll.kt");
}
@TestMetadata("jvmDefaultAllPrimaryProperty.kt")
public void testJvmDefaultAllPrimaryProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAllPrimaryProperty.kt");
}
@TestMetadata("jvmDefaultAllProperty.kt")
public void testJvmDefaultAllProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAllProperty.kt");
}
@TestMetadata("jvmDefaultEnable.kt")
public void testJvmDefaultEnable() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnable.kt");
}
@TestMetadata("jvmDefaultEnablePrimaryProperty.kt")
public void testJvmDefaultEnablePrimaryProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnablePrimaryProperty.kt");
}
@TestMetadata("jvmDefaultEnableProperty.kt")
public void testJvmDefaultEnableProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnableProperty.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/propertyDelegation")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -17959,6 +18057,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/jvmStatic/propertyGetterDelegatesToAnother.kt");
}
@TestMetadata("propertyReference.kt")
public void testPropertyReference() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/propertyReference.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/simple.kt");
@@ -21443,6 +21546,31 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/properties/kt9603.kt");
}
@TestMetadata("lazyInitialization.kt")
public void testLazyInitialization() throws Exception {
runTest("compiler/testData/codegen/box/properties/lazyInitialization.kt");
}
@TestMetadata("lazyInitializationCyclicImports.kt")
public void testLazyInitializationCyclicImports() throws Exception {
runTest("compiler/testData/codegen/box/properties/lazyInitializationCyclicImports.kt");
}
@TestMetadata("lazyInitializationMultiModule.kt")
public void testLazyInitializationMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/lazyInitializationMultiModule.kt");
}
@TestMetadata("lazyInitializationOrder.kt")
public void testLazyInitializationOrder() throws Exception {
runTest("compiler/testData/codegen/box/properties/lazyInitializationOrder.kt");
}
@TestMetadata("lazyInitializationSplitPerModule.kt")
public void testLazyInitializationSplitPerModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/lazyInitializationSplitPerModule.kt");
}
@TestMetadata("primitiveOverrideDefaultAccessor.kt")
public void testPrimitiveOverrideDefaultAccessor() throws Exception {
runTest("compiler/testData/codegen/box/properties/primitiveOverrideDefaultAccessor.kt");
@@ -32016,6 +32144,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/unsignedTypes/equalsImplForInlineClassWrappingNullableInlineClass.kt");
}
@TestMetadata("evaluateConstructorOfUnsignedArrayType.kt")
public void testEvaluateConstructorOfUnsignedArrayType() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedArrayType.kt");
}
@TestMetadata("evaluateConstructorOfUnsignedType.kt")
public void testEvaluateConstructorOfUnsignedType() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedType.kt");
@@ -32195,6 +32328,77 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
public void testWhenByUnsigned() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/whenByUnsigned.kt");
}
@TestMetadata("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Jvm8Intrinsics extends AbstractFirBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_FIR: ");
}
public void testAllFilesPresentInJvm8Intrinsics() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("unsignedIntCompare_jvm8.kt")
public void testUnsignedIntCompare_jvm8() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics/unsignedIntCompare_jvm8.kt");
}
@TestMetadata("unsignedIntDivide_jvm8.kt")
public void testUnsignedIntDivide_jvm8() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics/unsignedIntDivide_jvm8.kt");
}
@TestMetadata("unsignedIntRemainder_jvm8.kt")
public void testUnsignedIntRemainder_jvm8() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics/unsignedIntRemainder_jvm8.kt");
}
@TestMetadata("unsignedIntToString_jvm8.kt")
public void testUnsignedIntToString_jvm8() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics/unsignedIntToString_jvm8.kt");
}
@TestMetadata("unsignedLongCompare_jvm8.kt")
public void testUnsignedLongCompare_jvm8() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics/unsignedLongCompare_jvm8.kt");
}
@TestMetadata("unsignedLongDivide_jvm8.kt")
public void testUnsignedLongDivide_jvm8() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics/unsignedLongDivide_jvm8.kt");
}
@TestMetadata("unsignedLongRemainder_jvm8.kt")
public void testUnsignedLongRemainder_jvm8() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics/unsignedLongRemainder_jvm8.kt");
}
@TestMetadata("unsignedLongToString_jvm8.kt")
public void testUnsignedLongToString_jvm8() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/jvm8Intrinsics/unsignedLongToString_jvm8.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/box/valueClasses")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ValueClasses extends AbstractFirBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_FIR: ");
}
public void testAllFilesPresentInValueClasses() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("jvmInline.kt")
public void testJvmInline() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/jvmInline.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/vararg")

View File

@@ -774,6 +774,11 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/callableReference/kt36975.kt");
}
@TestMetadata("kt39612.kt")
public void testKt39612() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/callableReference/kt39612.kt");
}
@TestMetadata("nameIntrinsicWithImplicitThis.kt")
public void testNameIntrinsicWithImplicitThis() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/callableReference/nameIntrinsicWithImplicitThis.kt");

View File

@@ -1807,11 +1807,21 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
runTest("compiler/testData/ir/irText/firProblems/FirBuilder.kt");
}
@TestMetadata("inapplicableCollectionSet.kt")
public void testInapplicableCollectionSet() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/inapplicableCollectionSet.kt");
}
@TestMetadata("InnerClassInAnonymous.kt")
public void testInnerClassInAnonymous() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/InnerClassInAnonymous.kt");
}
@TestMetadata("kt43342.kt")
public void testKt43342() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/kt43342.kt");
}
@TestMetadata("MultiList.kt")
public void testMultiList() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/MultiList.kt");

View File

@@ -50,7 +50,7 @@ class JavaSymbolProvider(
private val searchScope: GlobalSearchScope,
) : FirSymbolProvider(session) {
companion object {
private val VALUE_METHOD_NAME = Name.identifier("value")
internal val VALUE_METHOD_NAME = Name.identifier("value")
}
private val classCache = SymbolProviderCache<ClassId, FirRegularClassSymbol>()
@@ -168,6 +168,7 @@ class JavaSymbolProvider(
javaTypeParameterStack.addStack(parentStack)
}
}
val methodMap = mutableMapOf<JavaMethod, FirJavaMethod>()
val firJavaClass = buildJavaClass {
source = (javaClass as? JavaElementImpl<*>)?.psi?.toFirPsiSourceElement()
session = this@JavaSymbolProvider.session
@@ -219,7 +220,9 @@ class JavaSymbolProvider(
classIsAnnotation,
valueParametersForAnnotationConstructor,
dispatchReceiver
)
).apply {
methodMap[javaMethod] = this
}
}
val javaClassDeclaredConstructors = javaClass.constructors
val constructorId = CallableId(classId.packageFqName, classId.relativeClassName, classId.shortClassName)
@@ -270,6 +273,10 @@ class JavaSymbolProvider(
}
)
firJavaClass.addAnnotationsFrom(this@JavaSymbolProvider.session, javaClass, javaTypeParameterStack)
// NB: this is done here to unbind possible annotation cycle
for ((javaMethod, firJavaMethod) in methodMap) {
firJavaMethod.annotations.addAnnotationsFrom(session, javaMethod, javaTypeParameterStack)
}
return firJavaClass
}
@@ -364,7 +371,6 @@ class JavaSymbolProvider(
returnTypeRef = returnType.toFirJavaTypeRef(this@JavaSymbolProvider.session, javaTypeParameterStack)
isStatic = javaMethod.isStatic
typeParameters += javaMethod.typeParameters.convertTypeParameters(javaTypeParameterStack)
addAnnotationsFrom(this@JavaSymbolProvider.session, javaMethod, javaTypeParameterStack)
for ((index, valueParameter) in javaMethod.valueParameters.withIndex()) {
valueParameters += valueParameter.toFirValueParameter(
this@JavaSymbolProvider.session, index, javaTypeParameterStack,

View File

@@ -21,7 +21,9 @@ import org.jetbrains.kotlin.fir.java.enhancement.readOnlyToMutable
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.resolve.bindSymbolToLookupTag
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredCallableSymbols
import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -31,6 +33,7 @@ import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
@@ -418,16 +421,51 @@ private fun FirRegularClass.createRawArguments(
computeRawProjection(session, typeParameter, position, erasedUpperBound)
}
private fun FirAnnotationCallBuilder.buildArgumentMapping(
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
classId: ClassId?,
annotationArguments: Collection<JavaAnnotationArgument>
): LinkedHashMap<FirExpression, FirValueParameter>? {
if (classId == null) {
annotationTypeRef = buildErrorTypeRef { diagnostic = ConeUnresolvedReferenceError() }
return null
}
val lookupTag = ConeClassLikeLookupTagImpl(classId)
annotationTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(lookupTag, emptyArray(), isNullable = false)
}
if (annotationArguments.any { it.name != null }) {
val mapping = linkedMapOf<FirExpression, FirValueParameter>()
val annotationClassSymbol = session.firSymbolProvider.getClassLikeSymbolByFqName(classId).also {
lookupTag.bindSymbolToLookupTag(session, it)
}
if (annotationClassSymbol != null) {
val annotationConstructor =
(annotationClassSymbol.fir as FirRegularClass).declarations.filterIsInstance<FirConstructor>().first()
for (argument in annotationArguments) {
mapping[argument.toFirExpression(session, javaTypeParameterStack)] =
annotationConstructor.valueParameters.find { it.name == (argument.name ?: JavaSymbolProvider.VALUE_METHOD_NAME) }
?: return null
}
return mapping
}
}
return null
}
internal fun JavaAnnotation.toFirAnnotationCall(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack
): FirAnnotationCall {
return buildAnnotationCall {
annotationTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(FirRegularClassSymbol(classId!!).toLookupTag(), emptyArray(), isNullable = false)
}
argumentList = buildArgumentList {
for (argument in this@toFirAnnotationCall.arguments) {
arguments += argument.toFirExpression(session, javaTypeParameterStack)
val mapping = buildArgumentMapping(session, javaTypeParameterStack, classId, arguments)
argumentList = if (mapping != null) {
buildResolvedArgumentList(mapping)
} else {
buildArgumentList {
for (argument in this@toFirAnnotationCall.arguments) {
arguments += argument.toFirExpression(session, javaTypeParameterStack)
}
}
}
calleeReference = FirReferencePlaceholderForResolvedAnnotations
@@ -447,7 +485,7 @@ internal fun FirJavaClass.addAnnotationsFrom(
annotations.addAnnotationsFrom(session, javaAnnotationOwner, javaTypeParameterStack)
}
private fun MutableList<FirAnnotationCall>.addAnnotationsFrom(
internal fun MutableList<FirAnnotationCall>.addAnnotationsFrom(
session: FirSession,
javaAnnotationOwner: JavaAnnotationOwner,
javaTypeParameterStack: JavaTypeParameterStack

View File

@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
@@ -126,7 +127,7 @@ class KotlinDeserializedJvmSymbolsProvider(
FirDeserializationContext.createForPackage(
packageFqName, packageProto, nameResolver, session,
JvmBinaryAnnotationDeserializer(session, kotlinJvmBinaryClass, byteContent),
FirConstDeserializer(session, kotlinJvmBinaryClass, facadeBinaryClass),
FirConstDeserializer(session, facadeBinaryClass ?: kotlinJvmBinaryClass),
source
),
source,
@@ -300,6 +301,12 @@ class KotlinDeserializedJvmSymbolsProvider(
return loadAnnotation(annotationClassId, result)
}
private fun findAndDeserializeClassViaParent(classId: ClassId): FirRegularClassSymbol? {
val outerClassId = classId.outerClassId ?: return null
findAndDeserializeClass(outerClassId) ?: return null
return classCache[classId]
}
private fun findAndDeserializeClass(
classId: ClassId,
parentContext: FirDeserializationContext? = null
@@ -314,7 +321,7 @@ class KotlinDeserializedJvmSymbolsProvider(
} catch (e: ProcessCanceledException) {
return null
}
val kotlinClassWithContent = when (result) {
val (kotlinJvmBinaryClass, byteContent) = when (result) {
is KotlinClassFinder.Result.KotlinClass -> result
is KotlinClassFinder.Result.ClassFileContent -> {
handledByJava.add(classId)
@@ -324,45 +331,39 @@ class KotlinDeserializedJvmSymbolsProvider(
null
}
}
null -> null
null -> return findAndDeserializeClassViaParent(classId)
}
if (kotlinClassWithContent == null) {
val outerClassId = classId.outerClassId ?: return null
findAndDeserializeClass(outerClassId) ?: return null
} else {
val (kotlinJvmBinaryClass, byteContent) = kotlinClassWithContent
if (kotlinJvmBinaryClass.classHeader.kind != KotlinClassHeader.Kind.CLASS) return null
val (nameResolver, classProto) = kotlinJvmBinaryClass.readClassDataFrom() ?: return null
if (kotlinJvmBinaryClass.classHeader.kind != KotlinClassHeader.Kind.CLASS) return null
val (nameResolver, classProto) = kotlinJvmBinaryClass.readClassDataFrom() ?: return null
val symbol = FirRegularClassSymbol(classId)
deserializeClassToSymbol(
classId, classProto, symbol, nameResolver, session,
JvmBinaryAnnotationDeserializer(session, kotlinJvmBinaryClass, byteContent),
kotlinScopeProvider,
parentContext, KotlinJvmBinarySourceElement(kotlinJvmBinaryClass),
this::findAndDeserializeClass
)
classCache[classId] = symbol
val annotations = mutableListOf<FirAnnotationCall>()
kotlinJvmBinaryClass.loadClassAnnotations(
object : KotlinJvmBinaryClass.AnnotationVisitor {
override fun visitAnnotation(classId: ClassId, source: SourceElement): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
return loadAnnotationIfNotSpecial(classId, annotations)
}
override fun visitEnd() {
}
},
byteContent,
)
(symbol.fir.annotations as MutableList<FirAnnotationCall>) += annotations
if (parentContext == null && Flags.CLASS_KIND.get(classProto.flags) == ProtoBuf.Class.Kind.COMPANION_OBJECT) {
return findAndDeserializeClassViaParent(classId)
}
return classCache[classId]
val symbol = FirRegularClassSymbol(classId)
deserializeClassToSymbol(
classId, classProto, symbol, nameResolver, session,
JvmBinaryAnnotationDeserializer(session, kotlinJvmBinaryClass, byteContent),
kotlinScopeProvider,
parentContext, KotlinJvmBinarySourceElement(kotlinJvmBinaryClass),
this::findAndDeserializeClass
)
classCache[classId] = symbol
val annotations = mutableListOf<FirAnnotationCall>()
kotlinJvmBinaryClass.loadClassAnnotations(
object : KotlinJvmBinaryClass.AnnotationVisitor {
override fun visitAnnotation(classId: ClassId, source: SourceElement): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
return loadAnnotationIfNotSpecial(classId, annotations)
}
override fun visitEnd() {
}
},
byteContent,
)
(symbol.fir.annotations as MutableList<FirAnnotationCall>) += annotations
return symbol
}
private fun loadFunctionsByName(part: PackagePartsCacheData, name: Name): List<FirCallableSymbol<*>> {

View File

@@ -168,7 +168,7 @@ class FirCallResolver(
fun <T : FirQualifiedAccess> resolveVariableAccessAndSelectCandidate(qualifiedAccess: T): FirStatement {
val callee = qualifiedAccess.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccess
qualifiedResolver.initProcessingQualifiedAccess(callee)
qualifiedResolver.initProcessingQualifiedAccess(callee, qualifiedAccess.typeArguments)
@Suppress("NAME_SHADOWING")
val qualifiedAccess = qualifiedAccess.transformExplicitReceiver<FirQualifiedAccess>()

View File

@@ -16,14 +16,17 @@ import org.jetbrains.kotlin.fir.resolve.transformers.PackageOrClass
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class FirQualifiedNameResolver(private val components: BodyResolveComponents) {
private val session = components.session
private var qualifierStack = mutableListOf<Name>()
private var qualifierStack = mutableListOf<NameWithTypeArguments>()
private var qualifierPartsToDrop = 0
private class NameWithTypeArguments(val name: Name, val typeArguments: List<FirTypeProjection>)
fun reset() {
qualifierStack.clear()
qualifierPartsToDrop = 0
@@ -41,11 +44,11 @@ class FirQualifiedNameResolver(private val components: BodyResolveComponents) {
*/
fun isPotentialQualifierPartPosition() = qualifierStack.size > 1
fun initProcessingQualifiedAccess(callee: FirSimpleNamedReference) {
fun initProcessingQualifiedAccess(callee: FirSimpleNamedReference, typeArguments: List<FirTypeProjection>) {
if (callee.name.isSpecial) {
qualifierStack.clear()
} else {
qualifierStack.add(callee.name)
qualifierStack.add(NameWithTypeArguments(callee.name, typeArguments))
}
}
@@ -62,7 +65,7 @@ class FirQualifiedNameResolver(private val components: BodyResolveComponents) {
return null
}
val symbolProvider = session.firSymbolProvider
var qualifierParts = qualifierStack.asReversed().map { it.asString() }
var qualifierParts = qualifierStack.asReversed().map { it.name.asString() }
var resolved: PackageOrClass?
do {
resolved = resolveToPackageOrClass(
@@ -80,6 +83,7 @@ class FirQualifiedNameResolver(private val components: BodyResolveComponents) {
packageFqName = resolved.packageFqName
relativeClassFqName = resolved.relativeClassFqName
symbol = resolved.classSymbol
typeArguments.addAll(qualifierStack.take(qualifierParts.size).flatMap { it.typeArguments })
}.apply {
resultType = components.typeForQualifier(this)
}

View File

@@ -54,36 +54,36 @@ inline val FirProperty.hasJvmFieldAnnotation: Boolean
val FirAnnotationCall.isJvmFieldAnnotation: Boolean
get() = toAnnotationClassId() == JVM_FIELD_CLASS_ID
private fun FirAnnotationCall.useSiteTargetsFromMetaAnnotation(session: FirSession): List<AnnotationUseSiteTarget> {
val metaAnnotationAboutTarget =
toAnnotationClass(session)?.annotations?.find { it.toAnnotationClassId() == TARGET_CLASS_ID }
?: return emptyList()
return metaAnnotationAboutTarget.argumentList.arguments.toAnnotationUseSiteTargets()
}
fun FirAnnotationCall.useSiteTargetsFromMetaAnnotation(session: FirSession): Set<AnnotationUseSiteTarget> =
toAnnotationClass(session)?.annotations?.find { it.toAnnotationClassId() == TARGET_CLASS_ID }?.argumentList?.arguments
?.toAnnotationUseSiteTargets() ?: DEFAULT_USE_SITE_TARGETS
private fun List<FirExpression>.toAnnotationUseSiteTargets(): List<AnnotationUseSiteTarget> =
flatMap { arg ->
val unwrappedArg = if (arg is FirNamedArgumentExpression) arg.expression else arg
if (unwrappedArg is FirArrayOfCall) {
unwrappedArg.argumentList.arguments.toAnnotationUseSiteTargets()
} else {
unwrappedArg.toAnnotationUseSiteTarget()?.let { listOf(it) } ?: emptyList()
private fun List<FirExpression>.toAnnotationUseSiteTargets(): Set<AnnotationUseSiteTarget> =
flatMapTo(mutableSetOf()) { arg ->
when (val unwrappedArg = if (arg is FirNamedArgumentExpression) arg.expression else arg) {
is FirArrayOfCall -> unwrappedArg.argumentList.arguments.toAnnotationUseSiteTargets()
is FirVarargArgumentsExpression -> unwrappedArg.arguments.toAnnotationUseSiteTargets()
else -> USE_SITE_TARGET_NAME_MAP[unwrappedArg.callableNameOfMetaAnnotationArgument?.identifier] ?: setOf()
}
}
private val USE_SITE_TARGET_NAME_MAP =
AnnotationUseSiteTarget.values().map { it.name to it }.toMap()
// See [org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.USE_SITE_MAPPING] (it's in reverse)
private val USE_SITE_TARGET_NAME_MAP = mapOf(
"FIELD" to setOf(AnnotationUseSiteTarget.FIELD, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD),
"FILE" to setOf(AnnotationUseSiteTarget.FILE),
"PROPERTY" to setOf(AnnotationUseSiteTarget.PROPERTY),
"PROPERTY_GETTER" to setOf(AnnotationUseSiteTarget.PROPERTY_GETTER),
"PROPERTY_SETTER" to setOf(AnnotationUseSiteTarget.PROPERTY_SETTER),
"VALUE_PARAMETER" to setOf(
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER,
AnnotationUseSiteTarget.RECEIVER,
AnnotationUseSiteTarget.SETTER_PARAMETER,
),
)
private fun FirExpression.toAnnotationUseSiteTarget(): AnnotationUseSiteTarget? =
// TODO: depending on the context, "PARAMETER" can be mapped to either CONSTRUCTOR_PARAMETER or SETTER_PARAMETER ?
callableNameOfMetaAnnotationArgument?.identifier?.let {
USE_SITE_TARGET_NAME_MAP[it]
}
fun FirAnnotationCall.hasMetaAnnotationUseSiteTargets(session: FirSession, vararg useSiteTargets: AnnotationUseSiteTarget): Boolean {
val meta = useSiteTargetsFromMetaAnnotation(session)
return useSiteTargets.any { meta.contains(it) }
}
// See [org.jetbrains.kotlin.descriptors.annotations.KotlinTarget] (the second argument of each entry)
private val DEFAULT_USE_SITE_TARGETS: Set<AnnotationUseSiteTarget> =
USE_SITE_TARGET_NAME_MAP.values.fold(setOf<AnnotationUseSiteTarget>()) { a, b -> a + b } - setOf(AnnotationUseSiteTarget.FILE)
fun FirAnnotatedDeclaration.hasAnnotation(classId: ClassId): Boolean {
return annotations.any { it.toAnnotationClassId() == classId }

View File

@@ -122,37 +122,39 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
return result
}
protected fun or(statements: Collection<TypeStatement>): MutableTypeStatement {
private inline fun manipulateTypeStatements(
statements: Collection<TypeStatement>,
op: (Collection<Set<ConeKotlinType>>) -> MutableSet<ConeKotlinType>
): MutableTypeStatement {
require(statements.isNotEmpty())
statements.singleOrNull()?.let { return it as MutableTypeStatement }
val variable = statements.first().variable
assert(statements.all { it.variable == variable })
val exactType = orForTypes(statements.map { it.exactType })
val exactNotType = orForTypes(statements.map { it.exactNotType })
val exactType = op.invoke(statements.map { it.exactType })
val exactNotType = op.invoke(statements.map { it.exactNotType })
return MutableTypeStatement(variable, exactType, exactNotType)
}
protected fun or(statements: Collection<TypeStatement>): MutableTypeStatement =
manipulateTypeStatements(statements, ::orForTypes)
private fun orForTypes(types: Collection<Set<ConeKotlinType>>): MutableSet<ConeKotlinType> {
if (types.any { it.isEmpty() }) return mutableSetOf()
val allTypes = types.flatMapTo(mutableSetOf()) { it }
val commonTypes = allTypes.toMutableSet()
types.forEach { commonTypes.retainAll(it) }
val differentTypes = types.mapNotNull { typeSet -> (typeSet - commonTypes).takeIf { it.isNotEmpty() } }
if (differentTypes.size == types.size) {
context.commonSuperTypeOrNull(differentTypes.flatten())?.let { commonTypes += it }
val intersectedTypes = types.map {
if (it.size > 1) {
context.intersectTypes(it.toList()) as ConeKotlinType
} else {
assert(it.size == 1) { "We've already checked each set of types is not empty." }
it.single()
}
}
return commonTypes
val result = mutableSetOf<ConeKotlinType>()
context.commonSuperTypeOrNull(intersectedTypes)?.let { result.add(it) }
return result
}
protected fun and(statements: Collection<TypeStatement>): MutableTypeStatement {
require(statements.isNotEmpty())
statements.singleOrNull()?.let { return it as MutableTypeStatement }
val variable = statements.first().variable
assert(statements.all { it.variable == variable })
val exactType = andForTypes(statements.map { it.exactType })
val exactNotType = andForTypes(statements.map { it.exactNotType })
return MutableTypeStatement(variable, exactType, exactNotType)
}
protected fun and(statements: Collection<TypeStatement>): MutableTypeStatement =
manipulateTypeStatements(statements, ::andForTypes)
private fun andForTypes(types: Collection<Set<ConeKotlinType>>): MutableSet<ConeKotlinType> {
return types.flatMapTo(mutableSetOf()) { it }

View File

@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.types.AbstractTypeApproximator
@NoMutableState
class InferenceComponents(val session: FirSession) : FirSessionComponent {
val ctx: ConeTypeCheckerContext = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = false, session)
val ctx: ConeTypeCheckerContext = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = true, session)
val approximator: AbstractTypeApproximator = object : AbstractTypeApproximator(ctx) {}
val trivialConstraintTypeInferenceOracle = TrivialConstraintTypeInferenceOracle.create(ctx)

View File

@@ -13,8 +13,7 @@ import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeVariable
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzerContext
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
@@ -117,7 +116,8 @@ class PostponedArgumentsAnalyzer(
c.canBeProper(rawReturnType) -> substitute(rawReturnType)
// For Unit-coercion
c.hasUpperOrEqualUnitConstraint(rawReturnType) -> unitType
c.hasUpperOrEqualUnitConstraint(rawReturnType) ->
if (rawReturnType.isMarkedNullable) unitType.withNullability(ConeNullability.NULLABLE) else unitType
else -> null
}

View File

@@ -584,7 +584,7 @@ class ConeTypeCheckerContext(
errorTypesEqualToAnything: Boolean,
stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext =
if (this.isErrorTypeEqualsToAnything == errorTypesEqualToAnything)
if (this.isErrorTypeEqualsToAnything == errorTypesEqualToAnything && this.isStubTypeEqualsToAnything == stubTypesEqualToAnything)
this
else
ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session)

View File

@@ -34,7 +34,7 @@ fun ConeClassLikeType.isByte(): Boolean = lookupTag.classId == StandardClassIds.
fun ConeClassLikeType.isBoolean(): Boolean = lookupTag.classId == StandardClassIds.Boolean
fun ConeClassLikeType.isChar(): Boolean = lookupTag.classId == StandardClassIds.Char
fun ConeClassLikeType.isPrimitiveType(): Boolean = isPrimitiveNumberOrUnsignedNumberType() || isBoolean() || isByte() || isShort()
fun ConeClassLikeType.isPrimitiveType(): Boolean = isPrimitiveNumberOrUnsignedNumberType() || isBoolean() || isByte() || isShort() || isChar()
fun ConeClassLikeType.isPrimitiveNumberType(): Boolean = lookupTag.classId in PRIMITIVE_NUMBER_CLASS_IDS
fun ConeClassLikeType.isPrimitiveUnsignedNumberType(): Boolean = lookupTag.classId in PRIMITIVE_UNSIGNED_NUMBER_CLASS_IDS
fun ConeClassLikeType.isPrimitiveNumberOrUnsignedNumberType(): Boolean = isPrimitiveNumberType() || isPrimitiveUnsignedNumberType()

View File

@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.declarations
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.declarations.builder.FirRegularClassBuilder
import org.jetbrains.kotlin.fir.declarations.builder.FirTypeParameterBuilder
@@ -35,15 +36,24 @@ fun FirTypeParameterBuilder.addDefaultBoundIfNecessary(isFlexible: Boolean = fal
}
}
inline val FirRegularClass.modality get() = status.modality
inline val FirRegularClass.isSealed get() = status.modality == Modality.SEALED
inline val FirRegularClass.isAbstract get() = status.modality == Modality.ABSTRACT
inline val FirRegularClass.isInner get() = status.isInner
inline val FirRegularClass.isCompanion get() = status.isCompanion
inline val FirRegularClass.isData get() = status.isData
inline val FirRegularClass.isInline get() = status.isInline
inline val FirRegularClass.isFun get() = status.isFun
inline val FirMemberDeclaration.modality get() = status.modality
inline val FirMemberDeclaration.isAbstract get() = status.modality == Modality.ABSTRACT
inline val FirMemberDeclaration.isOpen get() = status.modality == Modality.OPEN
inline val FirMemberDeclaration.visibility get() = status.visibility
inline val FirMemberDeclaration.allowsToHaveFakeOverride: Boolean
get() = !Visibilities.isPrivate(visibility) && visibility != Visibilities.InvisibleFake
inline val FirMemberDeclaration.isActual get() = status.isActual
inline val FirMemberDeclaration.isExpect get() = status.isExpect
inline val FirMemberDeclaration.isInner get() = status.isInner
@@ -64,6 +74,10 @@ inline val FirPropertyAccessor.modality get() = status.modality
inline val FirPropertyAccessor.visibility get() = status.visibility
inline val FirPropertyAccessor.isInline get() = status.isInline
inline val FirPropertyAccessor.isExternal get() = status.isExternal
inline val FirPropertyAccessor.hasBody get() = body != null
inline val FirProperty.allowsToHaveFakeOverride: Boolean
get() = !Visibilities.isPrivate(visibility) && visibility != Visibilities.InvisibleFake
inline val FirPropertyAccessor.allowsToHaveFakeOverride: Boolean
get() = !Visibilities.isPrivate(visibility) && visibility != Visibilities.InvisibleFake

View File

@@ -44,6 +44,7 @@ inline val FirCall.argumentMapping: LinkedHashMap<FirExpression, FirValueParamet
get() = (argumentList as? FirResolvedArgumentList)?.mapping
fun FirExpression.toResolvedCallableReference(): FirResolvedNamedReference? {
if (this is FirWrappedArgumentExpression) return expression.toResolvedCallableReference()
return (this as? FirResolvable)?.calleeReference as? FirResolvedNamedReference
}

View File

@@ -347,7 +347,7 @@ public interface Errors {
DiagnosticFactory0<PsiElement> NON_PRIVATE_CONSTRUCTOR_IN_ENUM = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> NON_PRIVATE_CONSTRUCTOR_IN_SEALED = DiagnosticFactory0.create(ERROR);
// Inline classes
// Inline and value classes
DiagnosticFactory0<PsiElement> INLINE_CLASS_NOT_TOP_LEVEL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INLINE_CLASS_NOT_FINAL = DiagnosticFactory0.create(ERROR);
@@ -355,6 +355,7 @@ public interface Errors {
DiagnosticFactory0<KtElement> INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtParameter> INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtProperty> PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<PsiElement> RESERVED_VAR_PROPERTY_OF_VALUE_CLASS = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> DELEGATED_PROPERTY_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<KtTypeReference, KotlinType> INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> INLINE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION = DiagnosticFactory0.create(ERROR);
@@ -362,6 +363,8 @@ public interface Errors {
DiagnosticFactory0<KtTypeReference> INLINE_CLASS_CANNOT_BE_RECURSIVE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> RESERVED_MEMBER_INSIDE_INLINE_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INNER_CLASS_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> VALUE_CLASS_CANNOT_BE_CLONEABLE = DiagnosticFactory0.create(ERROR);
// Result class

View File

@@ -17,6 +17,8 @@ import org.jetbrains.kotlin.diagnostics.Errors.ACTUAL_WITHOUT_EXPECT
import org.jetbrains.kotlin.diagnostics.Errors.NO_ACTUAL_FOR_EXPECT
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.MODALITY_MODIFIERS
import org.jetbrains.kotlin.lexer.KtTokens.VISIBILITY_MODIFIERS
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver.Compatibility.Incompatible
@@ -402,15 +404,12 @@ object PositioningStrategies {
}
}
@JvmField
val VISIBILITY_MODIFIER: PositioningStrategy<KtModifierListOwner> = object : PositioningStrategy<KtModifierListOwner>() {
private class ModifierSetBasedPositioningStrategy(private val modifierSet: TokenSet) : PositioningStrategy<KtModifierListOwner>() {
override fun mark(element: KtModifierListOwner): List<TextRange> {
val visibilityTokens =
listOf(KtTokens.PRIVATE_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PUBLIC_KEYWORD, KtTokens.INTERNAL_KEYWORD)
val modifierList = element.modifierList
val result = visibilityTokens.mapNotNull { modifierList?.getModifier(it)?.textRange }
if (!result.isEmpty()) return result
val result = modifierSet.types.mapNotNull { modifierList?.getModifier(it as KtModifierKeywordToken)?.textRange }
if (result.isNotEmpty()) return result
// Try to resolve situation when there's no visibility modifiers written before element
if (element is PsiNameIdentifierOwner) {
@@ -432,6 +431,12 @@ object PositioningStrategies {
}
}
@JvmField
val VISIBILITY_MODIFIER: PositioningStrategy<KtModifierListOwner> = ModifierSetBasedPositioningStrategy(VISIBILITY_MODIFIERS)
@JvmField
val MODALITY_MODIFIER: PositioningStrategy<KtModifierListOwner> = ModifierSetBasedPositioningStrategy(MODALITY_MODIFIERS)
@JvmField
val VARIANCE_IN_PROJECTION: PositioningStrategy<KtTypeProjection> = object : PositioningStrategy<KtTypeProjection>() {
override fun mark(element: KtTypeProjection): List<TextRange> {
@@ -477,11 +482,12 @@ object PositioningStrategies {
}
@JvmField
val VAL_OR_VAR_NODE: PositioningStrategy<KtNamedDeclaration> = object : PositioningStrategy<KtNamedDeclaration>() {
override fun mark(element: KtNamedDeclaration): List<TextRange> {
val VAL_OR_VAR_NODE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
override fun mark(element: KtDeclaration): List<TextRange> {
return when (element) {
is KtParameter -> markElement(element.valOrVarKeyword ?: element)
is KtProperty -> markElement(element.valOrVarKeyword)
is KtDestructuringDeclaration -> markElement(element.valOrVarKeyword ?: element)
else -> error("Declaration is neither a parameter nor a property: " + element.getElementTextWithContext())
}
}
@@ -687,4 +693,14 @@ object PositioningStrategies {
return DEFAULT.mark(element)
}
}
val OPERATOR: PositioningStrategy<KtExpression> = object : PositioningStrategy<KtExpression>() {
override fun mark(element: KtExpression): List<TextRange> {
return when (element) {
is KtBinaryExpression -> mark(element.operationReference)
is KtUnaryExpression -> mark(element.operationReference)
else -> super.mark(element)
}
}
}
}

View File

@@ -704,12 +704,13 @@ public class DefaultErrorMessages {
MAP.put(NON_PRIVATE_CONSTRUCTOR_IN_ENUM, "Constructor must be private in enum class");
MAP.put(NON_PRIVATE_CONSTRUCTOR_IN_SEALED, "Constructor must be private in sealed class");
MAP.put(INLINE_CLASS_NOT_TOP_LEVEL, "Inline classes are only allowed on top level");
MAP.put(INLINE_CLASS_NOT_TOP_LEVEL, "Inline classes cannot be local or inner");
MAP.put(INLINE_CLASS_NOT_FINAL, "Inline classes can be only final");
MAP.put(ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_INLINE_CLASS, "Primary constructor is required for inline class");
MAP.put(INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, "Inline class must have exactly one primary constructor parameter");
MAP.put(INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER, "Value class primary constructor must have only final read-only (val) property parameter");
MAP.put(PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS, "Inline class cannot have properties with backing fields");
MAP.put(RESERVED_VAR_PROPERTY_OF_VALUE_CLASS, "'var' properties with value class receivers are reserved for future use");
MAP.put(DELEGATED_PROPERTY_INSIDE_INLINE_CLASS, "Inline class cannot have delegated properties");
MAP.put(INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE, "Inline class cannot have value parameter of type ''{0}''", RENDER_TYPE);
MAP.put(INLINE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION, "Inline class cannot implement an interface by delegation");
@@ -717,6 +718,8 @@ public class DefaultErrorMessages {
MAP.put(INLINE_CLASS_CANNOT_BE_RECURSIVE, "Inline class cannot be recursive");
MAP.put(RESERVED_MEMBER_INSIDE_INLINE_CLASS, "Member with the name ''{0}'' is reserved for future releases", STRING);
MAP.put(SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, "Secondary constructors with bodies are reserved for for future releases");
MAP.put(INNER_CLASS_INSIDE_INLINE_CLASS, "Inline class cannot have inner classes");
MAP.put(VALUE_CLASS_CANNOT_BE_CLONEABLE, "Value class cannot be Cloneable");
MAP.put(RESULT_CLASS_IN_RETURN_TYPE, "'kotlin.Result' cannot be used as a return type");
MAP.put(RESULT_CLASS_WITH_NULLABLE_OPERATOR, "Expression of type 'kotlin.Result' cannot be used as a left operand of ''{0}''", STRING);

View File

@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.UnsignedTypes
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
@@ -93,12 +94,16 @@ class CollectionLiteralResolver(
}
private fun getArrayFunctionCallName(expectedType: KotlinType): Name {
if (NO_EXPECTED_TYPE === expectedType || !KotlinBuiltIns.isPrimitiveArray(expectedType)) {
if (NO_EXPECTED_TYPE === expectedType ||
!(KotlinBuiltIns.isPrimitiveArray(expectedType) || KotlinBuiltIns.isUnsignedArrayType(expectedType))
) {
return ArrayFqNames.ARRAY_OF_FUNCTION
}
val descriptor = expectedType.constructor.declarationDescriptor ?: return ArrayFqNames.ARRAY_OF_FUNCTION
return ArrayFqNames.PRIMITIVE_TYPE_TO_ARRAY[KotlinBuiltIns.getPrimitiveArrayType(descriptor)] ?: ArrayFqNames.ARRAY_OF_FUNCTION
return ArrayFqNames.PRIMITIVE_TYPE_TO_ARRAY[KotlinBuiltIns.getPrimitiveArrayType(descriptor)]
?: UnsignedTypes.unsignedArrayTypeToArrayCall[UnsignedTypes.toUnsignedArrayType(descriptor)]
?: ArrayFqNames.ARRAY_OF_FUNCTION
}
}

View File

@@ -59,7 +59,11 @@ public class CompileTimeConstantUtils {
"kotlin.shortArrayOf",
"kotlin.byteArrayOf",
"kotlin.booleanArrayOf",
"kotlin.emptyArray"
"kotlin.emptyArray",
"kotlin.ubyteArrayOf",
"kotlin.ushortArrayOf",
"kotlin.uintArrayOf",
"kotlin.ulongArrayOf"
);
public static void checkConstructorParametersType(@NotNull List<KtParameter> parameters, @NotNull BindingTrace trace) {
@@ -91,7 +95,8 @@ public class CompileTimeConstantUtils {
KotlinBuiltIns.isPrimitiveArray(parameterType) ||
KotlinBuiltIns.isPrimitiveType(parameterType) ||
KotlinBuiltIns.isString(parameterType) ||
UnsignedTypes.INSTANCE.isUnsignedType(parameterType)) {
UnsignedTypes.isUnsignedType(parameterType) ||
UnsignedTypes.isUnsignedArrayType(parameterType)) {
return true;
}

View File

@@ -27,7 +27,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
KClassWithIncorrectTypeArgumentChecker,
SuspendLimitationsChecker,
InlineClassDeclarationChecker,
PropertiesWithBackingFieldsInsideInlineClass(),
InnerClassInsideInlineClass(),
PropertiesWithInlineClassAsReceiver(),
AnnotationClassTargetAndRetentionChecker(),
ReservedMembersAndConstructsForInlineClass(),
ResultClassInReturnTypeChecker(),

View File

@@ -6,18 +6,26 @@
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
private val javaLangCloneable = FqNameUnsafe("java.lang.Cloneable")
object InlineClassDeclarationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration !is KtClass) return
@@ -29,7 +37,7 @@ object InlineClassDeclarationChecker : DeclarationChecker {
require(inlineOrValueKeyword != null) { "Declaration of inline class must have 'inline' keyword" }
val trace = context.trace
if (!DescriptorUtils.isTopLevelDeclaration(descriptor)) {
if (descriptor.isInner || DescriptorUtils.isLocal(descriptor)) {
trace.report(Errors.INLINE_CLASS_NOT_TOP_LEVEL.on(inlineOrValueKeyword))
return
}
@@ -87,6 +95,13 @@ object InlineClassDeclarationChecker : DeclarationChecker {
}
}
}
if (descriptor.getAllSuperClassifiers().any {
it.fqNameUnsafe == StandardNames.FqNames.cloneable || it.fqNameUnsafe == javaLangCloneable }
) {
trace.report(Errors.VALUE_CLASS_CANNOT_BE_CLONEABLE.on(inlineOrValueKeyword))
return
}
}
private fun KotlinType.isInapplicableParameterType() =
@@ -107,20 +122,40 @@ object InlineClassDeclarationChecker : DeclarationChecker {
}
}
class PropertiesWithBackingFieldsInsideInlineClass : DeclarationChecker {
class PropertiesWithInlineClassAsReceiver : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration !is KtProperty) return
if (descriptor !is PropertyDescriptor) return
if (descriptor.containingDeclaration.isInlineClass()) {
if (context.trace.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) == true) {
context.trace.report(Errors.PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS.on(declaration))
}
declaration.delegate?.let {
context.trace.report(Errors.DELEGATED_PROPERTY_INSIDE_INLINE_CLASS.on(it))
}
}
if (!descriptor.isVar) return
if (descriptor.containingDeclaration.isInlineClass() ||
descriptor.extensionReceiverParameter?.type?.isInlineClassType() == true
) {
context.trace.report(Errors.RESERVED_VAR_PROPERTY_OF_VALUE_CLASS.on(declaration.valOrVarKeyword))
}
}
}
class InnerClassInsideInlineClass : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration !is KtClass) return
if (descriptor !is ClassDescriptor) return
if (!descriptor.isInner) return
if (!descriptor.containingDeclaration.isInlineClass()) return
if (context.trace.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) == true) {
context.trace.report(Errors.PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS.on(declaration))
}
declaration.delegate?.let {
context.trace.report(Errors.DELEGATED_PROPERTY_INSIDE_INLINE_CLASS.on(it))
}
context.trace.report(Errors.INNER_CLASS_INSIDE_INLINE_CLASS.on(declaration.modifierList!!.getModifier(KtTokens.INNER_KEYWORD)!!))
}
}

View File

@@ -144,7 +144,8 @@ fun IrValueParameter.copyTo(
}
return factory.createValueParameter(
startOffset, endOffset, origin, symbol,
name, index, type, varargElementType, isCrossinline, isNoinline, isAssignable = isAssignable
name, index, type, varargElementType, isCrossinline = isCrossinline,
isNoinline = isNoinline, isHidden = false, isAssignable = isAssignable
).also {
descriptor.bind(it)
it.parent = irFunction
@@ -173,7 +174,8 @@ fun IrFunction.copyReceiverParametersFrom(from: IrFunction, substitutionMap: Map
name, index,
type.substitute(substitutionMap),
varargElementType?.substitute(substitutionMap),
isCrossinline, isNoinline
isCrossinline, isNoinline,
isHidden, isAssignable
).also { parameter ->
parameter.parent = this@copyReceiverParametersFrom
newDescriptor.bind(this)
@@ -397,7 +399,7 @@ fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() {
@Suppress("UNCHECKED_CAST")
fun isElseBranch(branch: IrBranch) = branch is IrElseBranch || ((branch.condition as? IrConst<Boolean>)?.value == true)
fun IrSimpleFunction.isMethodOfAny() =
fun IrFunction.isMethodOfAny() =
((valueParameters.size == 0 && name.asString().let { it == "hashCode" || it == "toString" }) ||
(valueParameters.size == 1 && name.asString() == "equals" && valueParameters[0].type.isNullableAny()))
@@ -428,7 +430,9 @@ fun IrFunction.createDispatchReceiverParameter(origin: IrDeclarationOrigin? = nu
parentAsClass.defaultType,
null,
isCrossinline = false,
isNoinline = false
isNoinline = false,
isHidden = false,
isAssignable = false
).apply {
parent = this@createDispatchReceiverParameter
newDescriptor.bind(this)
@@ -497,9 +501,7 @@ fun IrFactory.createStaticFunctionWithReceivers(
copyMetadata: Boolean = true,
typeParametersFromContext: List<IrTypeParameter> = listOf()
): IrSimpleFunction {
val descriptor = (oldFunction.descriptor as? DescriptorWithContainerSource)?.let {
WrappedFunctionDescriptorWithContainerSource()
} ?: WrappedSimpleFunctionDescriptor()
val descriptor = WrappedSimpleFunctionDescriptor()
return createFunction(
oldFunction.startOffset, oldFunction.endOffset,
origin,

View File

@@ -55,14 +55,19 @@ private class KCallableNamePropertyTransformer(val lower: KCallableNamePropertyL
}
override fun visitCall(expression: IrCall): IrExpression {
val callableReference = expression.dispatchReceiver as? IrCallableReference<*> ?: return expression
val callableReference = expression.dispatchReceiver as? IrCallableReference<*>
?: return super.visitCall(expression)
//TODO rewrite checking
val directMember = expression.symbol.owner.let {
(it as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: it
}
val irClass = directMember.parent as? IrClass ?: return expression
if (!irClass.isSubclassOf(lower.context.irBuiltIns.kCallableClass.owner)) return expression
val irClass = directMember.parent as? IrClass
?: return super.visitCall(expression)
if (!irClass.isSubclassOf(lower.context.irBuiltIns.kCallableClass.owner)) {
return super.visitCall(expression)
}
val name = when (directMember) {
is IrSimpleFunction -> directMember.name
is IrProperty -> directMember.name

View File

@@ -11,8 +11,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyProperty
import org.jetbrains.kotlin.ir.descriptors.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.IrType
@@ -77,9 +75,7 @@ fun IrClass.addField(fieldName: String, fieldType: IrType, fieldVisibility: Desc
@PublishedApi
internal fun IrFactory.buildProperty(builder: IrPropertyBuilder): IrProperty = with(builder) {
val wrappedDescriptor = if (originalDeclaration is IrLazyProperty || containerSource != null)
WrappedPropertyDescriptorWithContainerSource()
else WrappedPropertyDescriptor()
val wrappedDescriptor = WrappedPropertyDescriptor()
createProperty(
startOffset, endOffset, origin,
@@ -117,9 +113,7 @@ inline fun IrProperty.addGetter(builder: IrFunctionBuilder.() -> Unit = {}): IrS
@PublishedApi
internal fun IrFactory.buildFunction(builder: IrFunctionBuilder): IrSimpleFunction = with(builder) {
val wrappedDescriptor = if (originalDeclaration is IrLazyFunction || containerSource != null)
WrappedFunctionDescriptorWithContainerSource()
else WrappedSimpleFunctionDescriptor()
val wrappedDescriptor = WrappedSimpleFunctionDescriptor()
createFunction(
startOffset, endOffset, origin,
IrSimpleFunctionSymbolImpl(wrappedDescriptor),
@@ -217,7 +211,8 @@ fun <D> buildReceiverParameter(
parent.factory.createValueParameter(
startOffset, endOffset, origin,
IrValueParameterSymbolImpl(wrappedDescriptor),
RECEIVER_PARAMETER_NAME, -1, type, null, isCrossinline = false, isNoinline = false, isAssignable = false
RECEIVER_PARAMETER_NAME, -1, type, null, isCrossinline = false, isNoinline = false,
isHidden = false, isAssignable = false
).also {
wrappedDescriptor.bind(it)
it.parent = parent

View File

@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
import org.jetbrains.kotlin.ir.backend.js.utils.hasStableJsName
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
@@ -118,7 +118,7 @@ abstract class BridgesConstruction(val context: JsCommonBackendContext) : Declar
): IrFunction {
val origin =
if (bridge.isEffectivelyExternal() || bridge.getJsName() != null)
if (bridge.hasStableJsName())
JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION
else
IrDeclarationOrigin.BRIDGE

View File

@@ -37,11 +37,12 @@ class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) :
): IrExpression {
val paramCount = oldIrFunction.valueParameters.size
val invokeFunctionN = resolveInvoke(paramCount)
// NOTE: currently we do not have a syntax to perform super extension call
// but in case we have such functionality in the future the logic bellow should be fixed
return irCall(invokeFunctionN, IrStatementOrigin.INVOKE).apply {
dispatchReceiver = irImplicitCast(irGet(handlerDeclaration), invokeFunctionN.dispatchReceiverParameter!!.type)
assert(newIrFunction.extensionReceiverParameter == null)
// NOTE: currently we do not have a syntax to perform super extension call
// that's why we've used to just fail with an exception in case we have extension function in for JS IR compilation
// TODO: that was overkill, however, we still need to revisit this issue later on
params.forEachIndexed { i, variable -> putValueArgument(i, irGet(variable)) }
}
}

View File

@@ -47,9 +47,11 @@ class PropertyLazyInitLowering(
return
}
if (container !is IrSimpleFunction && container !is IrField && container !is IrProperty)
if (container !is IrField && container !is IrSimpleFunction && container !is IrProperty)
return
if (container.origin !in compatibleOrigins) return
val file = container.parent as? IrFile
?: return
@@ -224,6 +226,8 @@ class RemoveInitializersForLazyProperties(
if (declaration !is IrField) return null
if (!declaration.isCompatibleDeclaration()) return null
val file = declaration.parent as? IrFile ?: return null
if (fileToInitializerPureness[file] == true) return null
@@ -257,6 +261,7 @@ class RemoveInitializersForLazyProperties(
private fun calculateFieldToExpression(declarations: Collection<IrDeclaration>): Map<IrField, IrExpression> =
declarations
.asSequence()
.filter { it.isCompatibleDeclaration() }
.map { it.correspondingProperty }
.filterNotNull()
.filter { it.isForLazyInit() }
@@ -288,4 +293,14 @@ private val IrDeclaration.correspondingProperty: IrProperty?
private fun IrDeclaration.propertyWithPersistentSafe(transform: IrDeclaration.() -> IrProperty?): IrProperty? =
if (((this as? PersistentIrElementBase<*>)?.createdOn ?: 0) <= stageController.currentStage) {
transform()
} else null
} else null
private fun IrDeclaration.isCompatibleDeclaration() =
origin in compatibleOrigins
private val compatibleOrigins = listOf(
IrDeclarationOrigin.DEFINED,
IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR,
IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
)

View File

@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -156,14 +153,33 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
// Argument value constructs unboxed inline class instance
arguments.single()
} else {
val ref = when {
klass.isEffectivelyExternal() ->
context.getRefForExternalClass(klass)
else ->
context.getNameForClass(klass).makeRef()
when {
klass.isEffectivelyExternal() -> {
val refForExternalClass = context.getRefForExternalClass(klass)
val varargParameterIndex = expression.symbol.owner.varargParameterIndex()
if (varargParameterIndex == -1) {
JsNew(refForExternalClass, arguments)
} else {
val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
JsNullLiteral(),
arguments,
varargParameterIndex
)
JsNew(
JsInvocation(
JsNameRef("apply", JsNameRef("bind", JsNameRef("Function"))),
refForExternalClass,
argumentsAsSingleArray
),
emptyList()
)
}
}
else -> {
val ref = context.getNameForClass(klass).makeRef()
JsNew(ref, arguments)
}
}
JsNew(ref, arguments)
}
}

View File

@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -120,7 +121,7 @@ fun translateCall(
return JsInvocation(callRef, jsDispatchReceiver?.let { receiver -> listOf(receiver) + arguments } ?: arguments)
}
val varargParameterIndex = function.valueParameters.indexOfFirst { it.varargElementType != null }
val varargParameterIndex = function.varargParameterIndex()
val isExternalVararg = function.isEffectivelyExternal() && varargParameterIndex != -1
val symbolName = when (jsDispatchReceiver) {
@@ -134,28 +135,12 @@ fun translateCall(
}
return if (isExternalVararg) {
// External vararg arguments should be represented in JS as multiple "plain" arguments (opposed to arrays in Kotlin)
// We are using `Function.prototype.apply` function to pass all arguments as a single array.
// For this purpose are concatenating non-vararg arguments with vararg.
// TODO: Don't use `Function.prototype.apply` when number of arguments is known at compile time (e.g. there are no spread operators)
val arrayConcat = JsNameRef("concat", JsArrayLiteral())
val arraySliceCall = JsNameRef("call", JsNameRef("slice", JsArrayLiteral()))
val argumentsAsSingleArray = JsInvocation(
arrayConcat,
listOfNotNull(jsExtensionReceiver) + arguments.mapIndexed { index, argument ->
when (index) {
// Call `Array.prototype.slice` on vararg arguments in order to convert array-like objects into proper arrays
// TODO: Optimize for proper arrays
varargParameterIndex -> JsInvocation(arraySliceCall, argument)
// TODO: Don't wrap non-array-like arguments with array literal
// TODO: Wrap adjacent non-vararg arguments in a single array literal
else -> JsArrayLiteral(listOf(argument))
}
}
val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
jsExtensionReceiver,
arguments,
varargParameterIndex
)
if (jsDispatchReceiver != null) {
@@ -198,13 +183,66 @@ fun translateCall(
}
}
fun argumentsWithVarargAsSingleArray(
additionalReceiver: JsExpression?,
arguments: List<JsExpression>,
varargParameterIndex: Int,
): JsExpression {
// External vararg arguments should be represented in JS as multiple "plain" arguments (opposed to arrays in Kotlin)
// We are using `Function.prototype.apply` function to pass all arguments as a single array.
// For this purpose are concatenating non-vararg arguments with vararg.
var arraysForConcat: MutableList<JsExpression> = mutableListOf<JsExpression>().apply {
additionalReceiver?.let { add(it) }
}
val concatElements: MutableList<JsExpression> = mutableListOf()
arguments
.forEachIndexed { index, argument ->
when (index) {
// Call `Array.prototype.slice` on vararg arguments in order to convert array-like objects into proper arrays
varargParameterIndex -> {
concatElements.add(JsArrayLiteral(arraysForConcat))
arraysForConcat = mutableListOf()
val varargArgument = if (argument is JsArrayLiteral) {
argument
} else {
val arraySliceCall = JsNameRef("call", JsNameRef("slice", JsArrayLiteral()))
JsInvocation(arraySliceCall, argument)
}
concatElements.add(varargArgument)
}
else -> {
arraysForConcat.add(argument)
}
}
}
if (arraysForConcat.isNotEmpty() || concatElements.isEmpty()) {
concatElements.add(JsArrayLiteral(arraysForConcat))
}
return concatElements.singleOrNull()
?: JsInvocation(
JsNameRef("concat", concatElements.first()),
concatElements.drop(1)
)
}
fun IrFunction.varargParameterIndex() = valueParameters.indexOfFirst { it.varargElementType != null }
fun translateCallArguments(
expression: IrMemberAccessExpression<*>,
expression: IrMemberAccessExpression<IrFunctionSymbol>,
context: JsGenerationContext,
transformer: IrElementToJsExpressionTransformer,
): List<JsExpression> {
val size = expression.valueArgumentsCount
val varargParameterIndex = expression.symbol.owner.realOverrideTarget.varargParameterIndex()
val validWithNullArgs = expression.validWithNullArgs()
val arguments = (0 until size)
.mapTo(ArrayList(size)) { index ->
@@ -216,6 +254,16 @@ fun translateCallArguments(
assert(validWithNullArgs)
}
}
.mapIndexed { index, result ->
val isEmptyExternalVararg = validWithNullArgs &&
varargParameterIndex == index &&
result is JsArrayLiteral &&
result.expressions.isEmpty()
if (isEmptyExternalVararg) {
null
} else result
}
.dropLastWhile { it == null }
.map { it ?: JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1)) }

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