Compare commits

..

187 Commits

Author SHA1 Message Date
Mikhael Bogdanov
0f7411b1b5 Support type parameter generation
Generate type parameter annotation by default for `-Xjvm-target 1.8` and above

 #KT-43714
2021-05-06 19:29:14 +02:00
Mikhael Bogdanov
13f5f15407 Make copy for disabled ir tests 2021-05-06 19:27:58 +02:00
Mikhael Bogdanov
2df328d57b Render generic signature in type parameters tests 2021-05-06 19:27:58 +02:00
Mikhael Bogdanov
66bfbbffe1 Render all annotations in type parameters tests 2021-05-06 19:27:57 +02:00
Mads Ager
b6fa28ea81 [JVM_IR] Deal with inline-class arguments in large arity lambdas.
FunctionNVarargBridgeLowering checked the name of the method instead
of whether the method overrides an invoke method. That doesn't work
when the name of the function gets mangled because of inline class
arguments.

Fixed KT-45084.
2021-05-06 17:27:59 +02:00
pyos
1181854bd6 Add a couple more tests for array constructors and references 2021-05-06 18:25:56 +03:00
pyos
a30cfc332d JVM_IR: remove JvmArrayConstructorLowering
ExpressionCodegen already spills the stack before any loop, so it has
no effect.
2021-05-06 18:25:55 +03:00
pyos
9f53d70109 JVM_IR: move ArrayConstructor below function reference phases
This allows taking function references to inline array constructors.

Also, redundant classes are no longer generated when function references
are passed as arguments to the array constructors.

 #KT-46426 Fixed
2021-05-06 18:25:53 +03:00
Mikhail Glukhikh
776920f77d Cleanup code in FirAnnotationArgumentChecker 2021-05-06 17:51:24 +03:00
Mark Punzalan
18f617a582 FIR: Make FirAnnotationArgumentChecker a FirAnnotationCallChecker, to
run on all annotation calls, including those inside type annotations.
2021-05-06 17:51:22 +03:00
Mikhail Glukhikh
87d05bcf83 Fix spec test data after rebase 2021-05-06 17:50:37 +03:00
Mikhail Glukhikh
e451ecf000 Regenerate FIR IDE tests 2021-05-06 17:50:36 +03:00
Mikhail Glukhikh
1936a815e2 ConeTypeCompatibilityChecker: add temporary workaround for KT-46383 2021-05-06 17:50:35 +03:00
Tianyu Geng
db55a973d4 FIR: fix infinite recursion with equality operator checker 2021-05-06 17:50:34 +03:00
Tianyu Geng
d4717569b9 Fix inferred type of FirGetClassCall
The inferred type should be `KClass<out Blah>` for `FirGetClassCall`
invoked on expressions.
2021-05-06 17:50:33 +03:00
Tianyu Geng
7bb81ef157 FIR: add equality call checker
Added checker for FirEqualityOperatorCall. It's surfaced as one of the
following diagnostics depending on the PSI structure and types under
comparison:

* INCOMPATIBLE_TYPES(_WARNING)
* EQUALITY_NOT_APPLICABLE(_WARNING)
* INCOMPATIBLE_ENUM_COMPARISON_ERROR

Comparing with FE1.0, the current implementation is more conservative
and only highlights error if the types are known to follow certain
contracts with `equals` method. Otherwise, the checker reports warnings
instead.

However, the current checker is more strict in the following situations:
1. it now rejects incompatible enum types like `Enum<E1>` and
  `Enum<E2>`, which was previously accepted
2. it now rejects incompatible class types like `Class<String>` and
  `Class<Int>`, which was previously accepted
3. the check now takes smart cast into consideration, so
  `if (x is String) x == 3` is now rejected
2021-05-06 17:50:32 +03:00
Andrey Zinovyev
787c743333 [FIR] Syntax checkers
Introduce base class for checkers that dive into source trees.
2021-05-06 17:38:04 +03:00
Ilya Matveev
1be39cb505 [K/N] Replace thread_local with THREAD_LOCAL_VARIABLE
For some reason using C++'s thread_local modifier
causes crashes during TLS access on runtime initialization
Kotlin dlls on Windows. This patch replaces the thread_local
modifier with __thread which doesn't have this problem
2021-05-06 14:10:22 +00:00
Ilya Matveev
e2e173b92c [K/N][New MM] Disable tests for ObjC interop 2021-05-06 14:10:22 +00:00
Ilya Matveev
4d346d3735 [K/N][New MM] Support thread state switching
Including

* Support thread state switching in codegen
* Introduce and use GCUnsafeCall annotation
* Switch thread state in C++ runtime code

Also

* Register current thread in Mark&Sweep tests
* Store MemoryState in Worker instance
* Set worker tid in WorkerInit
2021-05-06 14:10:21 +00:00
Ilya Matveev
0b46ed3cde [K/N][New MM] Add thread state asserts to reference updates 2021-05-06 14:10:20 +00:00
Ilya Matveev
08688670b1 [K/N] Adjust repository root in K/N's .idea directory 2021-05-06 14:10:19 +00:00
Yahor Berdnikau
c6fc393417 Enable kotlin java toolchain support for kapt task.
With this change 'KaptWithoutKotlincTask' will also support overriding
default Gradle JDK to run kapt. In such case only 'in-process' kapt
 worker isolation mode is supported.

If user does not provide custom JDK, kapt worker isolation mode will
be 'no-isolation' as before.

^KT-45611 In Progress
2021-05-06 16:04:23 +02:00
Mads Ager
afa1b8bfdc [JVM] Extend boxing/unboxing optimizations to coroutine boxing. 2021-05-06 15:35:49 +02:00
Ivan Gavrilovic
4994cb3774 [Gradle] Create kotlinOptions during task init and keep outputFile for js
This is so that existing build scripts using
withType() do not break. Also, fix the failing
test.

It was necessary to keep outputFile for the js compile task
as it was accessed from the build scripts. Instead, a new
property is introduced which uses Gradle lazy properties.
2021-05-06 13:54:18 +03:00
Ivan Gavrilovic
80181c1091 [Gradle] Add Android bootclasspath lazily 2021-05-06 13:54:17 +03:00
Ivan Gavrilovic
1c0d40055e [Gradle] Support getting the sourceSet name from tasks when...
...Gradle property is being used, instead of the direct String
value.
2021-05-06 13:54:16 +03:00
Ivan Gavrilovic
98cc99e36b [Gradle] Fix adding KAPT generated classess to the compilation classes output 2021-05-06 13:54:15 +03:00
Ivan Gavrilovic
f5caa49c31 [Gradle] Use Gradle properties for KAPT tasks
Use lazy properties to configure KAPT tasks and in the model builder.
Also, avoid eager dependency resolution of the kaptExternalClasspath
file collection.
2021-05-06 13:54:14 +03:00
Ivan Gavrilovic
0882da1788 [Gradle] Introduce classes to configure KAPT tasks
Avoid storing references to KotlinCompile task and use lazy properties
to configure task. Values are kept in-sync with the
Kotlin compile task (for the stub generation) using this mechanism.
2021-05-06 13:54:13 +03:00
Ivan Gavrilovic
01dd15cc3e [Gradle] Use task properties to modify task configuration
This change migrates to using properties of KGP tasks and Gradle
built-in tasks. Also, in TaskProvider class, Configurator instances are
created to configure KGP tasks.
2021-05-06 13:54:12 +03:00
Ivan Gavrilovic
ad9f6e63b6 [Gradle] Extract configuration of KotlinJsIrLink to a class
Migrate KotlinJsIrLink to properties create Configurator class
to configure the task properties.
2021-05-06 13:54:11 +03:00
Ivan Gavrilovic
5eed9a4e6e [Gradle] Extract configuration of KotlinCompileCommon to a class
Migrate KotlinCompileCommon to properties create Configurator class
to configure the task properties.
2021-05-06 13:54:10 +03:00
Ivan Gavrilovic
ff27a61252 [Gradle] Use ConfigurableFileCollection for task local state
Use ConfigurableFileCollection so that tasks can simply append to the
file collection and tasks that do not need this, can simply do nothing.
2021-05-06 13:54:09 +03:00
Ivan Gavrilovic
571c9c10d4 [Gradle] Update compile tasks to use properties and clean up code
Update AbstractKotlinCompile, KotlinCompile, and Kotlin2JsCompile to
use Gradle properties, and introduce Configurator classes that are
using configuration-time data to configure task. Also, introduce
TaskConfigurator interface that should be implemented by classes that
are used to configure tasks.
2021-05-06 13:54:08 +03:00
Ivan Gavrilovic
56cad96718 [Gradle] Remove KotlinCompileTaskData
When getting the incremental compilation information use the
task graph which processes all tasks present in it. Tasks have
all information that is needed to get IncrementalModuleInfo for all
compilations.
2021-05-06 13:54:06 +03:00
Ivan Gavrilovic
b3d8187df4 [Gradle] Remove deprecated ways to specify compiler classpath
This change removes options to specify compiler classpath using
deprecated properties that were deprecated for more than 2 years.
2021-05-06 13:54:05 +03:00
Jinseong Jeon
61e21ef6a2 FIR: ensure the absence of FirResolvedTypeRef with erroneous type 2021-05-06 12:22:40 +03:00
Andrey Zinovyev
cba21c68a3 [lombok] Actualize README 2021-05-06 11:27:51 +03:00
Jinseong Jeon
e2dc21da90 FIR checker: warn useless as and is 2021-05-05 18:20:51 +03:00
Jinseong Jeon
19d939c36e TEST: remove redundant diagnostic directive (w/ syntax error) 2021-05-05 18:20:50 +03:00
Mikhail Glukhikh
7ee6597873 FIR: make inference context mandatory in withNullability() etc. 2021-05-05 17:35:50 +03:00
Jinseong Jeon
bb37728e4f FIR: use withNullability with type context whenever possible
It could simplify flexible type cases.
2021-05-05 17:35:48 +03:00
Anton Lakotka
f94ed1a00c Fail only when KotlinPm20ProjectExtension is passed
to buildKotlinProjectStructureMetadata
#Fixes KTIJ-11586
2021-05-05 16:53:20 +03:00
Jinseong Jeon
291cd842b9 UAST Kotlin: update test data
Addition of directive IGNORE_FIR alters synthetic local variable names.
2021-05-05 14:22:40 +02:00
Jinseong Jeon
dad198cb67 UAST Kotlin: make super type lookup test robust
Newly added directive IGNORE_FIR bothers lookup for object "O".
2021-05-05 14:22:40 +02:00
Jinseong Jeon
03d4cb0dfa FIR UAST: use uast-kotlin/testData for legecy tests 2021-05-05 14:22:40 +02:00
Jinseong Jeon
eac875b5d6 FIR UAST: commonize utils from UAST Kotlin 2021-05-05 14:22:40 +02:00
Jinseong Jeon
f37c722c76 UAST Kotlin: fix typos 2021-05-05 14:22:40 +02:00
Jinseong Jeon
40eaabdbb5 FIR UAST: prototype plugin entrypoint, declarations, test infra 2021-05-05 14:22:40 +02:00
Jinseong Jeon
225e3a747c LC: introduce light class interface for facade
so that FIR-based light class for facade can work well in LC utils
2021-05-05 14:11:48 +02:00
Jinseong Jeon
efba90c6f1 LC: rename KtLightClassForFacade to ...Impl
before introducing a common interface for light class for facade

This is a mechanical refactoring.
2021-05-05 14:11:48 +02:00
Alexander Udalov
c14a890e7e IR: fix capturing of type parameters in local functions
collectPotentiallyCapturedTypeParameters no longer stops on the first
class when going through parents. This is needed because otherwise type
parameters of the containing class, and its outer classes, were never
considered "captured", and thus not duplicated/remapped later in
LocalDeclarationsLowering.

This led to the IR where a local function referenced generic type
parameters of the outer class. On JVM, local function is generated into
a private static function in that container class, and static functions
can't use generic type parameters, which crashed some bytecode
processing tools.

Also, add another explicit call to `seeType` to cover references to
generic type parameters in function return types.

 #KT-45941 Fixed
2021-05-04 21:10:56 +02:00
Vasily Levchenko
b389fd6667 [performance][build][kotlin-build-gradle-plugin] version 0.0.27 (fix) 2021-05-04 15:44:19 +00:00
Stanislav Erokhin
d9be05fea8 Support getContainer for the synthetic it value parameter
Also fixed incorrect KtSymbolOrigin:
it was SOURCE instead of SOURCE_MEMBER_GENERATED
2021-05-04 17:25:34 +02:00
Stanislav Erokhin
c24ad0ba51 Use KtFunctionLiteral as key for KtAnonymousFunctionSymbol retrieving
It seems logical to do, because KtFunctionLiteral is KtDeclaration
and KtLambdaExpression is not. Also FirAnonymousFunction use it as
realPsi reference
2021-05-04 14:01:30 +02:00
Dmitriy Dolovov
75d2e415e1 [K/N][IR] Generate missing return statement, p. 2
^KT-42832
2021-05-04 13:26:02 +03:00
Alexander Shabalin
5e456ed82b Put GC implementations into separate modules.
The mm module now compiles separately for each GC implementation.
2021-05-04 10:23:16 +00:00
Ilya Kirillov
41ab97ff1f FIR IDE: introduce single function for checking if declaration can be lazily resolved 2021-05-04 08:19:50 +02:00
Ilya Kirillov
babf079c31 FIR IDE: fix resolving of inner type aliases 2021-05-04 08:19:50 +02:00
Ilya Kirillov
9e1bc5680d FIR IDE: do not consider KtEnumEntry as ktClassOrObject 2021-05-04 08:19:50 +02:00
Ilya Kirillov
ef5f0e77ec FIR IDE: use KtClassLikeDeclaration.classId instead of hacks 2021-05-04 08:19:50 +02:00
Ilya Kirillov
aff807e3af Stubs: bump stubs version 2021-05-04 08:19:50 +02:00
Ilya Kirillov
4942f5eb66 Stubs: add classId to KtTypeAlias stubs 2021-05-04 08:19:50 +02:00
Ilya Kirillov
fdb091d98e Stubs: add classId to KtClassOrObject stubs 2021-05-04 08:19:49 +02:00
Ilya Kirillov
09a94f3200 FIR IDE: ignore non-passing tests in compiler based tests 2021-05-04 08:19:49 +02:00
Ilya Kirillov
3503a54437 FIR IDE: run tests in parallel in module idea-fir-low-level-api 2021-05-04 08:19:49 +02:00
Ilya Kirillov
65ce641b22 FIR IDE: introduce diagnostics tests bases on FIR diagnostics tests 2021-05-04 08:19:49 +02:00
Mads Ager
0c77565104 JVM_IR: Add more local variable tests for finally code. 2021-05-03 07:43:38 +02:00
Mads Ager
6095d8a7fa [JVM] Split the variable range for external finally blocks in inliner
When external finally blocks are inlined none of the current locals
are in scope of the finally block.
2021-05-03 07:43:37 +02:00
Mads Ager
6d9f02cfc6 [JVM_IR] Fix range of locals in connection with finally blocks.
For code such as:

```
try {
  var y = "y"
  for (i in 0 until 1) {
    return y
  }
} finally {
  println("finally")
}
```

The local variables `y` and `i` ended up covering the finally block as
well in the debugger.

This change splits the range of the locals so that they do
not cover the finally block.

This change does not change the inliner to do similar transformations,
so the range of locals is still wrong win finally blocks when inlined
into an inline function. Added a failing test to that effect.
2021-05-03 07:43:37 +02:00
Mikhail Glukhikh
0764a0601c Fix FIR IDE test data broken by 80a44986 2021-05-01 19:12:05 +03:00
sebastian.sellmair
a1ed81146e [Commonizer] Logging: NativeDistributionCommonizationCache: Log in level 'quite' on cache misses
^KT-36679 Verification Pending
2021-05-01 14:36:18 +03:00
sebastian.sellmair
b48850c993 [Commonizer] Logging: Implement CommonizerLogLevel and hide verbose output by default
^KT-36679 Fixed
2021-05-01 14:36:18 +03:00
sebastian.sellmair
7349ec8f2f [Commonizer] Logging: Implement ProgressLogger.fork
^KT-36679
2021-05-01 14:36:16 +03:00
sebastian.sellmair
ec440aecf6 [Commonizer] Logging: Remove 'COMMONIZATION' prologue
^KT-36679
2021-05-01 14:36:15 +03:00
sebastian.sellmair
9d9e11d6d8 [Commonizer] Logging: 'Preparing commonized Kotlin/Native libraries': show outputTarget instead of flat list of targets
^KT-36679
2021-05-01 14:36:14 +03:00
sebastian.sellmair
0d9e32f963 [Commonizer] Logging: Show [Step x of y] only when more than one task is scheduled
^KT-36679
2021-05-01 14:36:13 +03:00
Victor Petukhov
9eaec8d919 Use platform-independent line separator in jspecify tests handler 2021-05-01 13:39:28 +03:00
Nikolay Krasko
2a2fa31577 Allow emulate sonatype publishing when publishing to folder (KTI-552) 2021-05-01 01:41:30 +03:00
Nikolay Krasko
624740a80a Force usage of passed deploy url for sonatype publication (KTI-552) 2021-05-01 01:41:28 +03:00
Nikolay Krasko
2eda82f178 Allow in memory signing (KTI-552) 2021-05-01 01:41:27 +03:00
Nikolay Krasko
8f97d8a78e Drop legacy publishing 2021-05-01 01:37:09 +03:00
Mads Ager
df225c0c7f [JVM] Fix uninitialized locals after coroutine transformation.
The coroutine transformation would leave locals in the local
variable table across the code that reloads local variables from
the continuation on reentry. However, when reentering the function
the local has no value until after the reloads from the
continuation.

This change splits the locals in the local variable table to
avoid such uninitialized locals. A local alive across a
suspension point has its range split in two. One that goes
from the original start to the state label for the restart
after the suspension. The other goes from after the local
has been reloaded from the continuation until the previous
end of the local.
2021-04-30 22:24:03 +02:00
Dmitry Petrov
83e3a702c5 JVM_IR KT-46408 properly map fake overrides in method handles 2021-04-30 22:24:02 +03:00
Vasily Levchenko
ef2c2c2c9e [kotlin][tests][compiler/testData/debug/stepping] kt-42208 test added. 2021-04-30 18:44:55 +00:00
Vasily Levchenko
3160fc84fa [kotlin-native][tests] kt-42208 test added. 2021-04-30 18:44:54 +00:00
Vasily Levchenko
a6a7da31c9 [IR][provisional function expression] do generate function reference with offset of call site. 2021-04-30 18:44:54 +00:00
Tianyu Geng
b6bd4ae8e6 FIR: check DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH 2021-04-30 19:58:50 +03:00
Mikhael Bogdanov
84e67da2af Mute test on JDK 6 2021-04-30 18:24:10 +02:00
Mikhael Bogdanov
95d95f9a9b Put reification markers came from super object signature
#KT-44770 Fixed
  #KT-30696 Open
2021-04-30 17:34:16 +02:00
Sergey Shanshin
8dd307573a Fix IR compilation of external serializers in native 2021-04-30 18:17:08 +03:00
Mikhail Glukhikh
80a449862e FIR: implement diagnostics for qualifier as stand-alone expression case 2021-04-30 17:59:45 +03:00
Mikhail Glukhikh
84ccf7bbb1 FIR: use Java 8 rules in not implemented checker 2021-04-30 17:59:38 +03:00
Mikhail Glukhikh
5de8401494 Reset FirQualifiedNameResolver properly 2021-04-30 17:59:32 +03:00
Victor Petukhov
4fb78fab93 Temporary disable failing jspecify tests on Windows 2021-04-30 17:50:56 +03:00
Victor Petukhov
c9568c0744 Fix FIR tests 2021-04-30 16:49:56 +03:00
Victor Petukhov
7c62e9aecd Introduce warnings reporting by missed constraints because of incorrect optimization in the constraints processor 2021-04-30 15:46:04 +03:00
Victor Petukhov
e110b49cab Revert "Don't stop constraints processing if all type variables have proper equality constraints"
This reverts commit b87c2a15
2021-04-30 15:46:03 +03:00
Andrey Zinovyev
287ff3ed55 [FIR] Fix for AugmentedArraySetCall expression type
Hacky fix so it's type is Unit and not error
2021-04-30 15:25:44 +03:00
Simon Ogorodnik
6365164c21 FIR: Fix gradle integration tests broken by c6fa3634 2021-04-30 15:19:58 +03:00
Sergey Bogolepov
13464cce68 [Native] Adapt Skia interop to ClangArgs refactoring. 2021-04-30 12:07:46 +00:00
Victor Petukhov
f330d67740 Mute foreign annotations tests with compiled java through psi class files reading 2021-04-30 14:43:28 +03:00
Victor Petukhov
78ffefe107 Add jspecify license 2021-04-30 14:43:27 +03:00
Victor Petukhov
909f0d8bdb Implement caching module annotations per class id 2021-04-30 14:43:27 +03:00
Victor Petukhov
2e57ff25ee Leave KotlinCliJavaFileManager::findClass only passing JavaClassFinder.Request 2021-04-30 14:43:27 +03:00
Victor Petukhov
072bba109f Move foreign annotations logic into the corresponding configurator for the tests 2021-04-30 14:43:27 +03:00
Victor Petukhov
e93133a28f Implement jspecify marks processing in the tests properly, by adding specific handler and cleanuper 2021-04-30 14:43:27 +03:00
Victor Petukhov
b9536a25d6 Support type enhancement on freshly supported module level annotations
^KT-45189 Fixed
2021-04-30 14:43:27 +03:00
Victor Petukhov
bc5e92033b Support reading annotations on java 9 module on sources and binaries 2021-04-30 14:43:27 +03:00
Victor Petukhov
24685ee9d6 Add directive ALL_JAVA_AS_BINARIES and use it explicitly for foreign annotations tests with compiled java 2021-04-30 14:43:27 +03:00
Victor Petukhov
89270399db Update some third-party annotations 2021-04-30 14:43:26 +03:00
Victor Petukhov
cdcde634e8 Add basic Java 9 module tests 2021-04-30 14:43:26 +03:00
Victor Petukhov
757fdb2b32 Add Java 9 jspecify annotations including module level ones 2021-04-30 14:43:26 +03:00
Victor Petukhov
71755b7a5e Support java 9 modules in the diagnostic tests both in sources and binaries 2021-04-30 14:43:26 +03:00
Victor Petukhov
1f0616439c Introduce special common directives for tests based on foreign annotation tests 2021-04-30 14:43:26 +03:00
Victor Petukhov
6065f0e2d0 [Jspecify] Move diagnostic tests against compiled java under the new tests infrastructure 2021-04-30 14:43:26 +03:00
Victor Petukhov
8f097b14cc [Jspecify] Move jspecify test runner under the new tests infrastructure 2021-04-30 14:43:26 +03:00
Victor Petukhov
6f9694174f Move foreign annotation tests into diagnostics folder 2021-04-30 14:43:25 +03:00
Victor Petukhov
57bd4d3a98 [Jspecify] Remove Kotlin use sites generator: consider manually picking changes from the jspecify repo 2021-04-30 14:43:25 +03:00
Victor Petukhov
49e838781c Clean-up JavaModuleInfo.kt 2021-04-30 14:43:25 +03:00
Vasily Levchenko
788d3c022a [build][kotlin-build-gradle-plugin] version 0.0.27
- reading konanVersion and konanMetaVersion from project properties
2021-04-30 10:26:36 +00:00
Vasily Levchenko
9cbcafa8d1 [dependencies][kotlin-build-gradle-plugin] version 0.0.27
- reading konanVersion and konanMetaVersion from project properties
2021-04-30 10:26:35 +00:00
Dmitry Petrov
72804d2e8c JVM_IR KT-45779 don't generate intrinsic method refs via invokedynamic 2021-04-30 12:45:11 +03:00
Sergey Bogolepov
f3a935adb9 Support explicit C++ flags in run_konan tool 2021-04-30 08:39:27 +00:00
Sergey Bogolepov
25ebb3fa75 Remove obsolete Gradle native plugin configuration 2021-04-30 08:39:27 +00:00
Sergey Bogolepov
274d18a141 [Kotlin/Native] Add a workaround for Xcode 12.5
SDKs from Xcode 12.5 contain C++ stdlib and it
breaks compilation of C++ parts of compiler.
Mitigate this problem by explicitly specifying
path to C++ stdlib.
2021-04-30 08:39:26 +00:00
Victor Petukhov
8dd71ec5c8 Build recursive raw types and raw types which contain type parameters properly
1) Substitute erasure of other type parameters
2) Use star projection at top level for recursive raw types

^KT-46126 Fixed
2021-04-30 10:49:47 +03:00
Andi Wenger
f9d2ca68ce KJS IR: Fix KT-45738 - Consider recursive checkForPrimitiveOrPattern
Recursive results from checkForPrimitiveOrPattern were ignored. If it found a case/condition that could not be optimized the resulting "false" was not propagated. This would lead to a "optimized" when without all conditions.
- see KT-45738
- The return is now lifted out of the when to make it more obvious what is going on.
- New test for mixed multiple conditions in when
2021-04-29 23:52:01 +03:00
Ilya Kirillov
caff279255 FIR IDE: add missing binary extensions
This also reveals and error in find usages for fir: it does not work for library source files
So, corresponding tests are muted
2021-04-29 23:31:05 +03:00
Andrey Zinovyev
e4a5775570 Remove duplicated code in annotation-based-compiler-plugins-ide-support 2021-04-29 23:14:16 +03:00
Andrey Zinovyev
8afb6d2761 [lombok] Support import from gradle to IDE
Introduce base module for ide compiler plugins
2021-04-29 23:14:15 +03:00
Andrey Zinovyev
b58bea6fa1 [lombok] IDE plugin with maven import handler 2021-04-29 23:14:14 +03:00
Andrey Zinovyev
07daf2165a [lombok] Rename maven subplugin to 'lombok' 2021-04-29 23:14:13 +03:00
Andrey Zinovyev
b88f54b31a [lombok] Add maven plugin integration test with kapt 2021-04-29 23:14:12 +03:00
Andrey Zinovyev
3e883120dd [lombok] Simple maven plugin to enable lombok support 2021-04-29 23:14:11 +03:00
Ivan Kochurkin
7ec709cf46 FIR: fix incorrect reporting of underscores, simplify code, fix test data file 2021-04-29 22:31:39 +03:00
Jinseong Jeon
9b39a8abc2 FIR: avoid wrapping an erroneous type as FirResolvedTypeRef
Instead, use FirErrorTypeRef, a subtype of FirResolvedTypeRef
2021-04-29 22:31:38 +03:00
Alexander Gorshenev
887032667d [Kotlin/Native][Interop] Skia interop plugin for cinterop 2021-04-29 21:43:26 +03:00
Vladimir Ivanov
5f582ad28a [Kotlin/Native][Interop] Provide pure c wrappers over cpp for skia interop 2021-04-29 21:43:25 +03:00
Yahor Berdnikau
61825e9aec Made GradleCompileTaskProvder compative with configuration cache.
After moving compilerRunner() method evaluation into execution phase,
creation of GradleCompileTaskProvider class started to violate
configuration cache.

^KT-45611 In Progress
2021-04-29 20:43:59 +03:00
Yahor Berdnikau
816e955c61 Introduce KotlinJavaToolchain compile tasks input.
This task input provides a way to set different from current Gradle
JDK and use it for Kotlin files compilation. By default it provides
current Gradle JDK.

Provided JDK major version is used as task input, so on providing
different JDK user will see cache miss.

All required interfaces are located inside api module.

^KT-45611 In Progress
2021-04-29 20:43:58 +03:00
Yahor Berdnikau
201b6dfa60 Print path to java executable Kotlin daemon was started with.
Useful for tests to validate toolchain correct behaviour.

^KT-45611 In Progress
2021-04-29 20:43:57 +03:00
Yahor Berdnikau
85456bd6d8 Add helper methods simplifying working with lazy properties from Kotlin.
Just allow to write Kotlin code easier and nicer when using Gradle
lazy properties.

^KT-45611 In Progress
2021-04-29 20:43:55 +03:00
Yahor Berdnikau
007f11e22e Add initial test setup to enable and test Gradle build cache.
This will allow to write JUnit5 tests to verify tasks are re-using
build cache on rebuilding same project from clean state.

^KT-45611 In Progress
2021-04-29 20:43:54 +03:00
Ilya Kirillov
ddf451739b FIR IDE: add member type-alias test for FileStructureTest 2021-04-29 17:51:28 +02:00
Ilya Kirillov
d438d2db40 FIR IDE: do not remove duplicated diagnostics
This hides the real problem why diagnostics are duplicated
2021-04-29 17:51:28 +02:00
Ilya Kirillov
77ae1fa1f2 FIR IDE: run lazy resolve phases in ContextIndependent ResolutionMode 2021-04-29 17:51:28 +02:00
Ilya Kirillov
663c0d975d FIR IDE: add cases for diagnostics traversal test 2021-04-29 17:51:27 +02:00
Ilya Kirillov
602be42b24 FIR IDE: fix lazy resolve for generated synthetic accessors 2021-04-29 17:51:27 +02:00
Nikolay Krasko
66683d2952 Unwrap both parts of light element in KtLightElementBase.isEquivalentTo
Even if origins are same, wrapped light elements are not equivalent.

Revealed by running bunch of JavaAgainstKotlinBinariesCheckerTestGenerated
tests.

com.intellij.testFramework.LoggedErrorProcessor$TestLoggerAssertionError: Non-idempotent computation:
it returns different results when invoked multiple times or on different threads:

  KtLightMethodForDecompiledDeclaration of KtLightClassForDecompiledDeclaration of PsiFile:A.class != KtLightMethodForDecompiledDeclaration of KtLightClassForDecompiledDeclaration of PsiFile:A.class
2021-04-29 18:20:38 +03:00
Andrey Zinovyev
c8a81911c0 [lombok] Add message about experimental status of the plugin 2021-04-29 18:05:27 +03:00
Ivan Gavrilovic
f0199d7277 [Gradle] Simplify Parcelize Gradle plugin
Do not iterate over all configurations, just
add the dependency to the compile and runtime classpath.
2021-04-29 17:26:36 +03:00
Ilmir Usmanov
cb89bd0e13 Generate SuspendFunction marker interface if supertype is suspend
Otherwise, is/as checks will not work.
 #KT-18707
2021-04-29 17:11:31 +03:00
Margarita Bobova
5d296a01c2 Add changelog for 1.4.31 and 1.4.32 2021-04-29 16:13:13 +03:00
Dmitriy Novozhilov
dbaaf081d7 Fix warning in Kotlin/Native build 2021-04-29 16:07:24 +03:00
Dmitriy Novozhilov
df51856e65 Advance bootstrap to 1.5.20-dev-5753 2021-04-29 16:07:22 +03:00
Mikhail Glukhikh
8147a88353 Cleanup: OverrideResolver.kt 2021-04-29 15:24:57 +03:00
Mikhail Glukhikh
cc05d91bda FE 1.0: add deprecation ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED_WARNING
#KT-45508 Fixed
2021-04-29 15:24:49 +03:00
Svyatoslav Scherbina
59b5475350 Fix WITH_COROUTINES tests compilation on Native after 5617d83c 2021-04-29 11:16:02 +00:00
Steven Schäfer
84d78035e4 JVM IR: Avoid double mangling of function reference invoke methods 2021-04-29 13:10:43 +02:00
Alexander Udalov
276ffd5a4b JVM IR: fix ::class reference and type mapping for scripts
#KT-46284 Fixed
2021-04-29 00:33:34 +03:00
Alexander Udalov
d10f734594 Fix warnings after making getKotlinPluginVersion non-null
See 4cb6303fa8.
2021-04-29 00:18:07 +03:00
Ilya Kirillov
7149d08995 FIR IDE: resolve supertypes before retrieving them 2021-04-28 22:11:05 +03:00
Ilya Kirillov
cccf9b7d54 FIR IDE: add JVM checkers 2021-04-28 17:57:45 +02:00
Ilya Kirillov
81a7271009 FIR: Decouple AbstractDiagnosticCollectorComponent and AbstractDiagnosticCollector 2021-04-28 17:57:45 +02:00
Nikolay Krasko
e43835c9f5 Bump konanVersion: 1.5.30 2021-04-28 17:58:40 +03:00
Ivan Kochurkin
525cc6df97 [FIR] Implement MANY_LAMBDA_EXPRESSION_ARGUMENTS diagnostics, fix tests 2021-04-28 16:21:48 +03:00
Udi Cohen
b8002cb54f [Kapt] Support dumping processors stats to a file
Using the option -Kapt-dump-processor-timings
2021-04-28 11:48:19 +03:00
sebastian.sellmair
beba85a848 [Commonizer] Calculate 'commonModuleNames' in hierarchical context
^KT-46330 Verification Pending
2021-04-28 02:03:20 +03:00
Nikolay Krasko
f7fdffefd6 Add an explicit dependency on dist for UAST tests 2021-04-27 22:00:18 +03:00
Dmitry Petrov
b34e2c1474 JVM_IR KT-36646 fuze primitive equality with safe call 2021-04-27 19:41:31 +03:00
Dmitry Petrov
72849a3dc3 JVM_IR update test for KT-36637 2021-04-27 19:41:29 +03:00
Dmitry Petrov
bdf914e8d5 JVM_IR use static 'hashCode' for boxed primitives on JVM 1.8+ 2021-04-27 19:41:28 +03:00
Dmitriy Novozhilov
07b15f9de6 [FIR] Support effective visibility with @PublishedApi
#KT-46270 Fixed
2021-04-27 18:39:10 +03:00
Dmitriy Novozhilov
32c3f85679 [FIR] Add inline checker for bodies of inline functions
This checker doesn't support `@PublishedAPI` yet, so some BB tests for it
 were muted. #KT-46270
2021-04-27 18:39:09 +03:00
Dmitriy Novozhilov
7e052c1eb1 [FIR] Fix suppressing diagnostics for some expressions 2021-04-27 18:39:07 +03:00
Dmitriy Novozhilov
2a08923c51 [FIR] Add more utilities for builtin functional types 2021-04-27 18:39:06 +03:00
Dmitriy Novozhilov
8925b8c922 [FIR] Fix leaking mutable map type of resolved argument mapping 2021-04-27 18:39:05 +03:00
Dmitriy Novozhilov
1afb844e1a [FIR] Fix FirExpressionWithSmartcastImpl.acceptChildren 2021-04-27 18:39:03 +03:00
Dmitriy Novozhilov
12331cb10c [FIR] Build resolved declaration status for all non-raw declarations 2021-04-27 18:39:02 +03:00
Ivan Kochurkin
d54808e33f [FIR] Implement CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS diagnostics, fix tests 2021-04-27 18:27:39 +03:00
Alexander Likhachev
f2f2df90aa [Gradle] Prevent early resolve of compiler classpath
#KT-45834 Fixed
2021-04-27 18:21:19 +03:00
Dmitry Petrov
660208740e PSI2IR KT-44013 WA: function interface constructor call accepted by FE 2021-04-27 17:35:37 +03:00
Ivan Kochurkin
704b5a0e13 [FIR] Implement UNDERSCORE_IS_RESERVED, UNDERSCORE_USAGE_WITHOUT_BACKTICKS diagnostics (lighttree) 2021-04-27 17:03:53 +03:00
Ivan Kochurkin
ea2d9f7c0c [FIR] Implement UNDERSCORE_IS_RESERVED, UNDERSCORE_USAGE_WITHOUT_BACKTICKS diagnostics (psi only) 2021-04-27 17:03:52 +03:00
Sergey Bogolepov
cc4adb798f Add cacheable targets for macos_arm64 host. 2021-04-27 13:47:20 +00:00
1998 changed files with 71182 additions and 10463 deletions

View File

@@ -1,5 +1,45 @@
# CHANGELOG
## 1.4.32
### IDE
- [`KT-43824`](https://youtrack.jetbrains.com/issue/KT-43824) KtLightClassForSourceDeclaration#isInheritor works in a different way than java implementation
- [`KT-45287`](https://youtrack.jetbrains.com/issue/KT-45287) LightClasses: `KtLightSimpleModifierList` is no more a parent of `KtLightAnnotationForSourceEntry`
- [`KT-45291`](https://youtrack.jetbrains.com/issue/KT-45291) LightClasses: can't get annotations for constructor val-parameter
- [`KT-45417`](https://youtrack.jetbrains.com/issue/KT-45417) ULC leakage of primitive type annotations
### Tools. CLI
- [`KT-44758`](https://youtrack.jetbrains.com/issue/KT-44758) kotlin-compiler-embeddable dependency includes unshaded `fastutil` package
- [`KT-45007`](https://youtrack.jetbrains.com/issue/KT-45007) Concurrent Kotlin script compilation/execution results in NullPointerException in KeyedExtensionCollector.getPoint()
## 1.4.31
### Compiler
- [`KT-39776`](https://youtrack.jetbrains.com/issue/KT-39776) 2020.3+: Unresolved reference to Kotlin stdlib function
### IDE. Gradle Integration
- [`KT-44845`](https://youtrack.jetbrains.com/issue/KT-44845) After update to Kotlin 1.4.30 all external dependencies is unresolved in IDE with kotlin.mpp.enableGranularSourceSetsMetadata=true
### IDE. Gradle. Script
- [`KTIJ-11137`](https://youtrack.jetbrains.com/issue/KTIJ-1137) build.gradle.kts: Fatal error during save/load standalone scripts settings
- [`KTIJ-898`](https://youtrack.jetbrains.com/issue/KTIJ-898) Unable to import with Kotlin DSL buildscript - NullPointerException in KotlinDslScriptModelProcessorKt.toListOfScriptModels
### IDE. Multiplatform
- [`KTIJ-1200`](https://youtrack.jetbrains.com/issue/KTIJ-1200) KotlinIconProviderKt.addExpectActualMarker takes up to 180+ seconds
### IDE
#### Fixes
- [`KT-44697`](https://youtrack.jetbrains.com/issue/KT-44697) New JVM IR backend notification - narrow its triggering to Kotlin projects
- [`KT-44523`](https://youtrack.jetbrains.com/issue/KT-44523) IDE notification for trying new JVM backend
- [`KTIJ-696`](https://youtrack.jetbrains.com/issue/KTIJ-696) Freeze during startup of IDEA with intellij project with Kotlin (211-1.4.10-release-IJ1440)
## 1.4.30

View File

@@ -14,8 +14,11 @@ buildscript {
if (cacheRedirectorEnabled) {
maven("https://cache-redirector.jetbrains.com/plugins.gradle.org/m2")
maven("https://cache-redirector.jetbrains.com/repo.maven.apache.org/maven2")
} else {
maven("https://plugins.gradle.org/m2")
mavenCentral()
}
}
@@ -27,7 +30,7 @@ buildscript {
dependencies {
bootstrapCompilerClasspath(kotlin("compiler-embeddable", bootstrapKotlinVersion))
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.26")
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.27")
classpath(kotlin("gradle-plugin", bootstrapKotlinVersion))
classpath(kotlin("serialization", bootstrapKotlinVersion))
classpath("org.jetbrains.dokka:dokka-gradle-plugin:0.9.17")
@@ -333,7 +336,9 @@ extra["tasksWithWarnings"] = listOf(
":kotlin-stdlib-jdk7:compileTestKotlin",
":kotlin-stdlib-jdk8:compileTestKotlin",
":plugins:uast-kotlin:compileKotlin",
":plugins:uast-kotlin:compileTestKotlin"
":plugins:uast-kotlin:compileTestKotlin",
":plugins:uast-kotlin-fir:compileKotlin",
":plugins:uast-kotlin-fir:compileTestKotlin"
)
val tasksWithWarnings: List<String> by extra
@@ -378,7 +383,7 @@ apply {
}
apply {
if (extra["isSonatypeRelease"] as? Boolean == true) {
if (extra["isDeployStagingRepoGenerationRequired"] as? Boolean == true) {
logger.info("Applying configuration for sonatype release")
from("libraries/prepareSonatypeStaging.gradle")
}
@@ -844,11 +849,11 @@ tasks {
":idea:idea-fir:test",
":idea:idea-frontend-api:test",
":idea:idea-frontend-fir:test",
":idea:idea-frontend-fir:idea-fir-low-level-api:test"
":idea:idea-frontend-fir:idea-fir-low-level-api:test",
":plugins:uast-kotlin-fir:test"
)
}
register("android-ide-tests") {
dependsOn("dist")
dependsOn(
@@ -894,7 +899,6 @@ tasks {
}
}
register("kaptIdeTest") {
dependsOn(":kotlin-annotation-processing:test")
dependsOn(":kotlin-annotation-processing-base:test")
@@ -962,6 +966,7 @@ tasks {
":prepare:ide-plugin-dependencies:sam-with-receiver-compiler-plugin-for-ide:publish",
":prepare:ide-plugin-dependencies:compiler-components-for-jps:publish",
":prepare:ide-plugin-dependencies:parcelize-compiler-plugin-for-ide:publish",
":prepare:ide-plugin-dependencies:lombok-compiler-plugin-for-ide:publish",
":kotlin-script-runtime:publish",
":kotlin-script-util:publish",
":kotlin-scripting-common:publish",

View File

@@ -22,7 +22,7 @@ buildscript {
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.26")
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.27")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.bootstrapKotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-sam-with-receiver:${project.bootstrapKotlinVersion}")
}
@@ -144,7 +144,7 @@ java {
dependencies {
implementation(kotlin("stdlib", embeddedKotlinVersion))
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.bootstrapKotlinVersion}")
implementation("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.26")
implementation("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.27")
implementation("com.gradle.publish:plugin-publish-plugin:0.14.0")
implementation("net.rubygrapefruit:native-platform:${property("versions.native-platform")}")

View File

@@ -18,9 +18,10 @@ buildscript {
} else {
maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-dependencies" }
}
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.26")
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.27")
}
}

View File

@@ -229,23 +229,6 @@ fun Project.publish(moduleMetadata: Boolean = false, configure: MavenPublication
publication.configure()
}
fun Project.publishWithLegacyMavenPlugin(body: Upload.() -> Unit = {}): Upload {
apply<plugins.PublishedKotlinModule>()
if (artifactsRemovedDiagnosticFlag) {
error("`publish()` should be called before removing artifacts typically done in `noDefaultJar()` or `runtimeJar()` call")
}
afterEvaluate {
if (configurations.findByName("classes-dirs") != null)
throw GradleException("classesDirsArtifact() is incompatible with publish(), see sources comments for details")
}
return (tasks.getByName("uploadArchives") as Upload).apply {
body()
}
}
fun Project.idePluginDependency(block: () -> Unit) {
val shouldActivate = rootProject.findProperty("publish.ide.plugin.dependencies")?.toString()?.toBoolean() == true
if (shouldActivate) {

View File

@@ -164,7 +164,17 @@ fun Project.configureDefaultPublishing() {
private fun Project.configureSigning() {
configure<SigningExtension> {
sign(extensions.getByType<PublishingExtension>().publications) // all publications
useGpgCmd()
val signKeyId = project.findProperty("signKeyId") as? String
if (!signKeyId.isNullOrBlank()) {
val signKeyPrivate = project.findProperty("signKeyPrivate") as? String
?: error("Parameter `signKeyPrivate` not found")
val signKeyPassphrase = project.findProperty("signKeyPassphrase") as? String
?: error("Parameter `signKeyPassphrase` not found")
useInMemoryPgpKeys(signKeyId, signKeyPrivate, signKeyPassphrase)
} else {
useGpgCmd()
}
}
}

View File

@@ -1,173 +0,0 @@
@file:Suppress("DEPRECATION")
package plugins
import org.codehaus.groovy.runtime.InvokerHelper
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.maven.Conf2ScopeMappingContainer
import org.gradle.api.artifacts.maven.MavenDeployment
import org.gradle.api.artifacts.maven.MavenResolver
import org.gradle.api.plugins.MavenPluginConvention
import org.gradle.api.plugins.MavenRepositoryHandlerConvention
import org.gradle.api.publication.maven.internal.deployer.MavenRemoteRepository
import org.gradle.api.tasks.Upload
import org.gradle.kotlin.dsl.*
import org.gradle.plugins.signing.Sign
import org.gradle.plugins.signing.SigningExtension
import kotlin.properties.Delegates
/**
* Configures a Kotlin module for publication.
*/
open class PublishedKotlinModule : Plugin<Project> {
private fun String.toBooleanOrNull() = listOf(true, false).firstOrNull { it.toString().equals(this, ignoreCase = true) }
override fun apply(project: Project) {
project.run {
plugins.apply("maven")
configurations.maybeCreate("publishedRuntime").apply {
the<MavenPluginConvention>()
.conf2ScopeMappings
.addMapping(0, this, Conf2ScopeMappingContainer.RUNTIME)
}
configurations.maybeCreate("publishedCompile").apply {
the<MavenPluginConvention>()
.conf2ScopeMappings
.addMapping(0, this, Conf2ScopeMappingContainer.COMPILE)
}
if (!project.hasProperty("prebuiltJar")) {
plugins.apply("signing")
val signingRequired = project.findProperty("signingRequired")?.toString()?.toBooleanOrNull()
?: project.property("isSonatypeRelease") as Boolean
configure<SigningExtension> {
isRequired = signingRequired
sign(configurations["archives"])
useGpgCmd()
}
tasks.named<Sign>("signArchives").configure {
enabled = signingRequired
}
}
fun MavenResolver.configurePom() {
pom.project {
withGroovyBuilder {
"licenses" {
"license" {
"name"("The Apache Software License, Version 2.0")
"url"("http://www.apache.org/licenses/LICENSE-2.0.txt")
"distribution"("repo")
}
}
"name"("${project.group}:${project.name}")
"packaging"("jar")
// optionally artifactId can be defined here
"description"(project.description)
"url"("https://kotlinlang.org/")
"licenses" {
"license" {
"name"("The Apache License, Version 2.0")
"url"("http://www.apache.org/licenses/LICENSE-2.0.txt")
}
}
"scm" {
"url"("https://github.com/JetBrains/kotlin")
"connection"("scm:git:https://github.com/JetBrains/kotlin.git")
"developerConnection"("scm:git:https://github.com/JetBrains/kotlin.git")
}
"developers" {
"developer" {
"name"("Kotlin Team")
setProperty("organization", "JetBrains")
"organizationUrl"("https://www.jetbrains.com")
}
}
}
}
pom.whenConfigured {
dependencies.removeIf {
InvokerHelper.getMetaClass(it).getProperty(it, "scope") == "test"
}
dependencies
.find {
InvokerHelper.getMetaClass(it).getProperty(it, "groupId") == "org.jetbrains.kotlin"
&& InvokerHelper.getMetaClass(it).getProperty(it, "artifactId") == "kotlin-stdlib"
}
?.also {
InvokerHelper.getMetaClass(it).setProperty(it, "exclusions", emptyList<Any>())
logger.warn("WARNING! Removed exclusions from kotlin-stdlib dependency of ${this.artifactId} artifact's maven metadata, check kotlin-stdlib dependency of ${project.path} project")
}
}
}
tasks.named<Upload>("uploadArchives").configure {
val preparePublication = project.rootProject.tasks.named("preparePublication").get()
dependsOn(preparePublication)
val username: String? by preparePublication.extra
val password: String? by preparePublication.extra
val repoUrl: String by preparePublication.extra
var repository by Delegates.notNull<MavenRemoteRepository>()
repositories {
withConvention(MavenRepositoryHandlerConvention::class) {
mavenDeployer {
withGroovyBuilder {
"beforeDeployment" {
val signing = project.the<SigningExtension>()
if (signing.isRequired)
signing.signPom(delegate as MavenDeployment)
}
"repository"("url" to repoUrl)!!.also { repository = it as MavenRemoteRepository }.withGroovyBuilder {
if (username != null && password != null) {
"authentication"("userName" to username, "password" to password)
}
}
}
configurePom()
}
}
}
doFirst {
repository.url = repoUrl
}
}
val install = if (tasks.names.contains("install")) tasks.getByName("install") as Upload
else tasks.create("install", Upload::class.java)
install.apply {
configuration = project.configurations.getByName(Dependency.ARCHIVES_CONFIGURATION)
description = "Installs the 'archives' artifacts into the local Maven repository."
repositories {
withConvention(MavenRepositoryHandlerConvention::class) {
mavenInstaller {
configurePom()
}
}
}
}
tasks.register("publish") {
dependsOn(tasks.named("uploadArchives"))
}
}
}
}

View File

@@ -354,8 +354,8 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
extractor.provideConfigurationKeys()
extractor.configure(keyConfiguration, module.directives)
}
val kind = configuratorForFlags.extractConfigurationKind(module.directives)
val jdkKind = configuratorForFlags.extractJdkKind(module.directives)
val kind = JvmEnvironmentConfigurator.extractConfigurationKind(module.directives)
val jdkKind = JvmEnvironmentConfigurator.extractJdkKind(module.directives)
keyConfiguration.languageVersionSettings = module.languageVersionSettings

View File

@@ -18,6 +18,7 @@ interface TypeMappingContext<Writer : JvmDescriptorTypeWriter<Type>> {
val typeContext: TypeSystemCommonBackendContextForTypeMapping
fun getClassInternalName(typeConstructor: TypeConstructorMarker): String
fun getScriptInternalName(typeConstructor: TypeConstructorMarker): String
fun Writer.writeGenericType(type: SimpleTypeMarker, asmType: Type, mode: TypeMappingMode)
}
@@ -117,9 +118,7 @@ object AbstractTypeMapper {
}
typeConstructor.isScript() -> {
val asmType = AsmTypes.JAVA_CLASS_TYPE
with(context) { sw?.writeGenericType(type, asmType, mode) }
return asmType
return Type.getObjectType(context.getScriptInternalName(typeConstructor))
}
typeConstructor.isTypeParameter() -> {

View File

@@ -265,13 +265,23 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
);
}
private static void addReifiedParametersFromSignature(@NotNull MemberCodegen member, @NotNull ClassDescriptor descriptor) {
private static void addReifiedParametersFromSignature(@NotNull MemberCodegen<?> member, @NotNull ClassDescriptor descriptor) {
for (KotlinType type : descriptor.getTypeConstructor().getSupertypes()) {
for (TypeProjection supertypeArgument : type.getArguments()) {
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(supertypeArgument.getType());
if (parameterDescriptor != null && parameterDescriptor.isReified()) {
processTypeArguments(member, type);
}
}
private static void processTypeArguments(@NotNull MemberCodegen<?> member, KotlinType type) {
for (TypeProjection supertypeArgument : type.getArguments()) {
if (supertypeArgument.isStarProjection()) continue;
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(supertypeArgument.getType());
if (parameterDescriptor != null) {
if (parameterDescriptor.isReified()) {
member.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterDescriptor.getName().asString());
}
} else {
processTypeArguments(member, supertypeArgument.getType());
}
}
}

View File

@@ -650,7 +650,7 @@ class CoroutineTransformerMethodVisitor(
val livenessFrames = analyzeLiveness(methodNode)
// References shall be cleaned up after uspill (during spill in next suspension point) to prevent memory leaks,
// References shall be cleaned up after unspill (during spill in next suspension point) to prevent memory leaks,
val referencesToSpillBySuspensionPointIndex = arrayListOf<List<ReferenceToSpill>>()
// while primitives shall not
val primitivesToSpillBySuspensionPointIndex = arrayListOf<List<PrimitiveToSpill>>()
@@ -759,6 +759,35 @@ class CoroutineTransformerMethodVisitor(
referencesToCleanBySuspensionPointIndex += currentSpilledReferencesCount to predSpilledReferencesCount
}
// Calculate debug metadata mapping before modifying method node to make it easier to locate
// locals alive across suspension points.
fun calculateSpilledVariableAndField(
suspension: SuspensionPoint,
slot: Int,
spillableVariable: SpillableVariable?
): SpilledVariableAndField? {
if (spillableVariable == null) return null
val name = localVariableName(methodNode, slot, suspension.suspensionCallBegin.index()) ?: return null
return SpilledVariableAndField(spillableVariable.fieldName, name)
}
val spilledToVariableMapping = arrayListOf<List<SpilledVariableAndField>>()
for (suspensionPointIndex in suspensionPoints.indices) {
val suspension = suspensionPoints[suspensionPointIndex]
val spilledToVariable = arrayListOf<SpilledVariableAndField>()
referencesToSpillBySuspensionPointIndex[suspensionPointIndex].mapNotNullTo(spilledToVariable) { (slot, spillableVariable) ->
calculateSpilledVariableAndField(suspension, slot, spillableVariable)
}
primitivesToSpillBySuspensionPointIndex[suspensionPointIndex].mapNotNullTo(spilledToVariable) { (slot, spillableVariable) ->
calculateSpilledVariableAndField(suspension, slot, spillableVariable)
}
spilledToVariableMapping += spilledToVariable
}
// Mutate method node
fun generateSpillAndUnspill(suspension: SuspensionPoint, slot: Int, spillableVariable: SpillableVariable?) {
@@ -772,6 +801,22 @@ class CoroutineTransformerMethodVisitor(
return
}
// Find and remove the local variable node, if any, in the local variable table corresponding to the slot that is spilled.
var local: LocalVariableNode? = null
val localRestart = LabelNode().linkWithLabel()
val iterator = methodNode.localVariables.listIterator()
while (iterator.hasNext()) {
val node = iterator.next()
if (node.index == slot &&
methodNode.instructions.indexOf(node.start) <= methodNode.instructions.indexOf(suspension.suspensionCallBegin) &&
methodNode.instructions.indexOf(node.end) > methodNode.instructions.indexOf(suspension.tryCatchBlockEndLabelAfterSuspensionCall)
) {
local = node
iterator.remove()
break
}
}
with(instructions) {
// store variable before suspension call
insertBefore(suspension.suspensionCallBegin, withInstructionAdapter {
@@ -795,8 +840,31 @@ class CoroutineTransformerMethodVisitor(
)
StackValue.coerce(spillableVariable.normalizedType, spillableVariable.type, this)
store(slot, spillableVariable.type)
if (local != null) {
visitLabel(localRestart.label)
}
})
}
// Split the local variable range for the local so that it is visible until the next state label, but is
// not visible until it has been unspilled from the continuation on the reentry path.
if (local != null) {
val previousEnd = local.end
local.end = suspension.stateLabel
// Add the local back, but end it at the next state label.
methodNode.localVariables.add(local)
// Add a new entry that starts after the local variable is restored from the continuation.
methodNode.localVariables.add(
LocalVariableNode(
local.name,
local.desc,
local.signature,
localRestart,
previousEnd,
local.index
)
)
}
}
fun cleanUpField(suspension: SuspensionPoint, fieldIndex: Int) {
@@ -839,33 +907,6 @@ class CoroutineTransformerMethodVisitor(
}
}
// Calculate debug metadata mapping
fun calculateSpilledVariableAndField(
suspension: SuspensionPoint,
slot: Int,
spillableVariable: SpillableVariable?
): SpilledVariableAndField? {
if (spillableVariable == null) return null
val name = localVariableName(methodNode, slot, suspension.suspensionCallEnd.next.index()) ?: return null
return SpilledVariableAndField(spillableVariable.fieldName, name)
}
val spilledToVariableMapping = arrayListOf<List<SpilledVariableAndField>>()
for (suspensionPointIndex in suspensionPoints.indices) {
val suspension = suspensionPoints[suspensionPointIndex]
val spilledToVariable = arrayListOf<SpilledVariableAndField>()
referencesToSpillBySuspensionPointIndex[suspensionPointIndex].mapNotNullTo(spilledToVariable) { (slot, spillableVariable) ->
calculateSpilledVariableAndField(suspension, slot, spillableVariable)
}
primitivesToSpillBySuspensionPointIndex[suspensionPointIndex].mapNotNullTo(spilledToVariable) { (slot, spillableVariable) ->
calculateSpilledVariableAndField(suspension, slot, spillableVariable)
}
spilledToVariableMapping += spilledToVariable
}
return spilledToVariableMapping
}
@@ -901,7 +942,6 @@ class CoroutineTransformerMethodVisitor(
suspendMarkerVarIndex: Int,
suspendPointLineNumber: LineNumberNode?
): LabelNode {
val stateLabel = LabelNode().linkWithLabel()
val continuationLabelAfterLoadedResult = LabelNode()
val suspendElementLineNumber = lineNumber
var nextLineNumberNode = nextDefinitelyHitLineNumber(suspension)
@@ -929,7 +969,7 @@ class CoroutineTransformerMethodVisitor(
load(suspendMarkerVarIndex, AsmTypes.OBJECT_TYPE)
areturn(AsmTypes.OBJECT_TYPE)
// Mark place for continuation
visitLabel(stateLabel.label)
visitLabel(suspension.stateLabel.label)
})
// After suspension point there is always three nodes: L1, NOP, L2
@@ -985,7 +1025,7 @@ class CoroutineTransformerMethodVisitor(
}
}
return stateLabel
return suspension.stateLabel
}
// Find the next line number instruction that is defintely hit. That is, a line number
@@ -1154,6 +1194,7 @@ internal class SuspensionPoint(
) {
lateinit var tryCatchBlocksContinuationLabel: LabelNode
val stateLabel = LabelNode().linkWithLabel()
val unboxInlineClassInstructions: List<AbstractInsnNode> = findUnboxInlineClassInstructions()
private fun findUnboxInlineClassInstructions(): List<AbstractInsnNode> {

View File

@@ -320,8 +320,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd)
processor.tryBlocksMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true)
//processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy);
processor.localVarsMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true);
mark.dropTo()
}
@@ -330,8 +329,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
}
processor.substituteTryBlockNodes(intoNode)
//processor.substituteLocalVarTable(intoNode);
processor.substituteLocalVarTable(intoNode);
}
protected abstract fun generateAssertFieldIfNeeded(info: RootInliningContext)

View File

@@ -18,12 +18,16 @@ package org.jetbrains.kotlin.codegen.optimization.boxing
import com.google.common.collect.ImmutableSet
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.coroutines.RELEASE_COROUTINES_VERSION_SETTINGS
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.codegen.topLevelClassInternalName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -174,7 +178,7 @@ fun AbstractInsnNode.isUnboxing(state: GenerationState) =
isPrimitiveUnboxing() || isJavaLangClassUnboxing() || isInlineClassUnboxing(state)
fun AbstractInsnNode.isBoxing(state: GenerationState) =
isPrimitiveBoxing() || isJavaLangClassBoxing() || isInlineClassBoxing(state)
isPrimitiveBoxing() || isJavaLangClassBoxing() || isInlineClassBoxing(state) || isCoroutinePrimitiveBoxing()
fun AbstractInsnNode.isPrimitiveUnboxing() =
isMethodInsnWith(Opcodes.INVOKEVIRTUAL) {
@@ -211,6 +215,19 @@ fun AbstractInsnNode.isPrimitiveBoxing() =
isBoxingMethodDescriptor()
}
private val BOXING_CLASS_INTERNAL_NAME =
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
private fun isJvmPrimitiveName(name: String) = JvmPrimitiveType.values().any { it.javaKeywordName == name }
fun AbstractInsnNode.isCoroutinePrimitiveBoxing(): Boolean {
return isMethodInsnWith(Opcodes.INVOKESTATIC) {
owner == BOXING_CLASS_INTERNAL_NAME &&
name.startsWith("box") &&
isJvmPrimitiveName(name.substring(3).lowercase())
}
}
private fun MethodInsnNode.isBoxingMethodDescriptor(): Boolean {
val ownerType = Type.getObjectType(owner)
return desc == Type.getMethodDescriptor(ownerType, AsmUtil.unboxType(ownerType))

View File

@@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.light.LightJavaModule
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.cli.common.config.ContentRoot
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.isValidJavaFqName
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
import org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME
@@ -52,10 +54,13 @@ class ClasspathRootsResolver(
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?,
private val javaModuleFinder: CliJavaModuleFinder,
private val requireStdlibModule: Boolean,
private val outputDirectory: VirtualFile?
private val outputDirectory: VirtualFile?,
private val javaFileManager: KotlinCliJavaFileManager
) {
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
private val searchScope = GlobalSearchScope.allScope(psiManager.project)
data class RootsAndModules(val roots: List<JavaRoot>, val modules: List<JavaModule>)
private data class RootWithPrefix(val root: VirtualFile, val packagePrefix: String?)
@@ -160,7 +165,7 @@ class ClasspathRootsResolver(
}
if (moduleInfoFile != null) {
val moduleInfo = JavaModuleInfo.read(moduleInfoFile) ?: return null
val moduleInfo = JavaModuleInfo.read(moduleInfoFile, javaFileManager, searchScope) ?: return null
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(root, isBinary = true)), moduleInfoFile)
}

View File

@@ -37,7 +37,7 @@ class CliKotlinAsJavaSupport(
return findFacadeFilesInPackage(packageFqName, scope)
.groupBy { it.javaFileFacadeFqName }
.mapNotNull { (facadeClassFqName, _) ->
KtLightClassForFacade.createForFacade(psiManager, facadeClassFqName, scope)
KtLightClassForFacadeImpl.createForFacade(psiManager, facadeClassFqName, scope)
}
}
@@ -54,7 +54,7 @@ class CliKotlinAsJavaSupport(
.orEmpty()
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
return listOfNotNull(KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope))
return listOfNotNull(KtLightClassForFacadeImpl.createForFacade(psiManager, facadeFqName, scope))
}
override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {

View File

@@ -35,6 +35,10 @@ class CliVirtualFileFinder(
override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? =
findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class")
override fun findSourceOrBinaryVirtualFile(classId: ClassId) =
findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class")
?: findSourceClass(classId, classId.relativeClassName.asString() + ".java")
override fun findMetadata(classId: ClassId): InputStream? {
assert(!classId.isNestedClass) { "Nested classes are not supported here: $classId" }
@@ -61,8 +65,11 @@ class CliVirtualFileFinder(
return findBinaryClass(classId, BuiltInSerializerProtocol.getBuiltInsFileName(packageFqName))?.inputStream
}
private fun findBinaryClass(classId: ClassId, fileName: String): VirtualFile? =
index.findClass(classId, acceptedRootTypes = JavaRoot.OnlyBinary) { dir, _ ->
private fun findClass(classId: ClassId, fileName: String, rootType: Set<JavaRoot.RootType>) =
index.findClass(classId, acceptedRootTypes = rootType) { dir, _ ->
dir.findChild(fileName)?.takeIf(VirtualFile::isValid)
}?.takeIf { it in scope }
private fun findBinaryClass(classId: ClassId, fileName: String) = findClass(classId, fileName, JavaRoot.OnlyBinary)
private fun findSourceClass(classId: ClassId, fileName: String) = findClass(classId, fileName, JavaRoot.OnlySource)
}

View File

@@ -82,7 +82,7 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
private val signatureParsingComponent = BinaryClassSignatureParser()
fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? = findClass(JavaClassFinder.Request(classId), searchScope)
fun findClass(classId: ClassId, searchScope: GlobalSearchScope) = findClass(JavaClassFinder.Request(classId), searchScope)
override fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? {
val (classId, classFileContentFromRequest, outerClassFromRequest) = request

View File

@@ -190,11 +190,17 @@ class KotlinCoreEnvironment private constructor(
sourceFiles.sortBy { it.virtualFile.path }
val javaFileManager = ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path ->
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
})
val javaModuleFinder = CliJavaModuleFinder(
jdkHome?.path?.let { path ->
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
},
javaFileManager,
project
)
val outputDirectory =
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
@@ -207,7 +213,8 @@ class KotlinCoreEnvironment private constructor(
this::contentRootToVirtualFile,
javaModuleFinder,
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
outputDirectory?.let(this::findLocalFile)
outputDirectory?.let(this::findLocalFile),
javaFileManager
)
val (initialRoots, javaModules) =
@@ -231,7 +238,7 @@ class KotlinCoreEnvironment private constructor(
updateClasspathFromRootsIndex(this)
}
(ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl).initialize(
javaFileManager.initialize(
rootsIndex,
packagePartProviders,
SingleJavaFileRootsIndex(singleJavaFileRoots),
@@ -240,7 +247,7 @@ class KotlinCoreEnvironment private constructor(
project.registerService(
JavaModuleResolver::class.java,
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList())
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList(), project)
)
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)

View File

@@ -78,10 +78,7 @@ import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.APPEND_JAVA_SOURCE_ROOTS_HANDLER_KEY
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.extensions.*
import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor
import org.jetbrains.kotlin.extensions.internal.TypeResolutionInterceptor
@@ -193,11 +190,16 @@ class KotlinCoreEnvironment private constructor(
sourceFiles.sortBy { it.virtualFile.path }
val javaFileManager = ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path ->
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
})
val javaModuleFinder = CliJavaModuleFinder(
jdkHome?.path?.let { path ->
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
},
javaFileManager
)
val outputDirectory =
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
@@ -210,7 +212,8 @@ class KotlinCoreEnvironment private constructor(
this::contentRootToVirtualFile,
javaModuleFinder,
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
outputDirectory?.let(this::findLocalFile)
outputDirectory?.let(this::findLocalFile),
javaFileManager
)
val (initialRoots, javaModules) =
@@ -234,7 +237,7 @@ class KotlinCoreEnvironment private constructor(
updateClasspathFromRootsIndex(this)
}
(ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl).initialize(
javaFileManager.initialize(
rootsIndex,
packagePartProviders,
SingleJavaFileRootsIndex(singleJavaFileRoots),
@@ -243,7 +246,7 @@ class KotlinCoreEnvironment private constructor(
project.registerService(
JavaModuleResolver::class.java,
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList())
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList(), project)
)
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)

View File

@@ -49,6 +49,9 @@ fun CompilerConfiguration.addJvmSdkRoots(files: List<File>) {
val CompilerConfiguration.jvmClasspathRoots: List<File>
get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance<JvmClasspathRoot>().map(JvmContentRoot::file)
val CompilerConfiguration.jvmModularRoots: List<File>
get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance<JvmModulePathRoot>().map(JvmContentRoot::file)
@JvmOverloads
fun CompilerConfiguration.addJavaSourceRoot(file: File, packagePrefix: String? = null) {
add(CLIConfigurationKeys.CONTENT_ROOTS, JavaSourceRoot(file, packagePrefix))

View File

@@ -45,6 +45,7 @@ data class JavaRoot(val file: VirtualFile, val type: RootType, val prefixFqName:
companion object RootTypes {
val OnlyBinary: Set<RootType> = EnumSet.of(RootType.BINARY)
val OnlySource: Set<RootType> = EnumSet.of(RootType.SOURCE)
val SourceAndBinary: Set<RootType> = EnumSet.of(RootType.BINARY, RootType.SOURCE)
}
}

View File

@@ -16,16 +16,25 @@
package org.jetbrains.kotlin.cli.jvm.modules
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleFinder
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
class CliJavaModuleFinder(
jrtFileSystemRoot: VirtualFile?,
private val javaFileManager: KotlinCliJavaFileManager,
project: Project
) : JavaModuleFinder {
private val modulesRoot = jrtFileSystemRoot?.findChild("modules")
private val userModules = linkedMapOf<String, JavaModule>()
private val allScope = GlobalSearchScope.allScope(project)
fun addUserModule(module: JavaModule) {
userModules.putIfAbsent(module.name, module)
}
@@ -41,7 +50,7 @@ class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null
val moduleInfo = JavaModuleInfo.read(file) ?: return null
val moduleInfo = JavaModuleInfo.read(file, javaFileManager, allScope) ?: return null
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(moduleRoot, isBinary = true)), file)
}
}

View File

@@ -18,18 +18,24 @@ package org.jetbrains.kotlin.cli.jvm.modules
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import java.util.concurrent.ConcurrentHashMap
class CliJavaModuleResolver(
private val moduleGraph: JavaModuleGraph,
private val userModules: List<JavaModule>,
private val systemModules: List<JavaModule.Explicit>
private val systemModules: List<JavaModule.Explicit>,
private val project: Project
) : JavaModuleResolver {
init {
assert(userModules.count(JavaModule::isSourceModule) <= 1) {
@@ -37,6 +43,14 @@ class CliJavaModuleResolver(
}
}
private val virtualFileFinder by lazy { VirtualFileFinder.getInstance(project) }
override fun getAnnotationsForModuleOwnerOfClass(classId: ClassId): List<JavaAnnotation>? {
val virtualFile = virtualFileFinder.findSourceOrBinaryVirtualFile(classId) ?: return null
return (findJavaModule(virtualFile) as? JavaModule.Explicit)?.moduleInfo?.annotations
}
private val sourceModule: JavaModule? = userModules.firstOrNull(JavaModule::isSourceModule)
private fun findJavaModule(file: VirtualFile): JavaModule? {
@@ -77,4 +91,8 @@ class CliJavaModuleResolver(
return null
}
companion object {
private const val MODULE_ANNOTATIONS_CACHE_SIZE = 10000
}
}

View File

@@ -101,7 +101,11 @@ object KotlinCompilerClient {
fun CompileService.leaseImpl(): CompileServiceSession? {
// the newJVMOptions could be checked here for additional parameters, if needed
registerClient(clientAliveFlagFile.absolutePath)
reportingTargets.report(DaemonReportCategory.DEBUG, "connected to the daemon")
val javaExecutablePath = compilerId.javaExecutable?.absolutePath ?: "'user jvm'"
reportingTargets.report(
DaemonReportCategory.DEBUG,
"connected to the daemon. Daemon is using following 'java' executable to run itself: $javaExecutablePath"
)
if (!leaseSession) return CompileServiceSession(this, CompileService.NO_SESSION)

View File

@@ -2789,6 +2789,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
}
@TestMetadata("symbolsAndDescriptors.kt")
public void testSymbolsAndDescriptors() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
}
@TestMetadata("transform.kt")
public void testTransform() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/transform.kt");

View File

@@ -10,7 +10,7 @@ FILE: A.kt
}
FILE: main.kt
public final fun test_1(): R|kotlin/Unit| {
lval a: R|ERROR CLASS: Unresolved name: A| = <Unresolved name: A>#()
lval a: <ERROR TYPE REF: Unresolved name: A> = <Unresolved name: A>#()
lval b: R|foo/A| = R|foo/A.A|()
lval c: R|foo/A| = <Unresolved name: A>#()
}

View File

@@ -18,7 +18,7 @@ FILE: cast.kt
}
public get(): R|(kotlin/String) -> kotlin/Boolean|
public final val hError: R|(ERROR CLASS: No type for parameter) -> kotlin/Boolean| = fun <anonymous>(_: R|ERROR CLASS: No type for parameter|): R|kotlin/Boolean| <inline=Unknown> {
public final val hError: R|(ERROR CLASS: No type for parameter) -> kotlin/Boolean| = fun <anonymous>(_: <ERROR TYPE REF: No type for parameter>): R|kotlin/Boolean| <inline=Unknown> {
^ Boolean(true)
}

View File

@@ -13,6 +13,6 @@ interface B
fun test_2(x: Any?) {
if (x is A && x is B) {
x is A
<!USELESS_IS_CHECK!>x is A<!>
}
}

View File

@@ -25,7 +25,7 @@ FILE: instanceAccessBeforeSuperCall.kt
}
public constructor(x: R|kotlin/Int|): R|C| {
this<R|C|>(fun <anonymous>(): R|ERROR CLASS: Cannot access ''<this>'' before superclass constructor has been called| <inline=Unknown> {
this<R|C|>(fun <anonymous>(): <ERROR TYPE REF: Cannot access ''<this>'' before superclass constructor has been called> <inline=Unknown> {
lval a: R|kotlin/Int| = Int(10)
^ this@R|/C|
}
@@ -63,8 +63,8 @@ FILE: instanceAccessBeforeSuperCall.kt
}
public final fun test(f: R|F|): R|kotlin/Unit| {
}
public final val a: R|ERROR CLASS: 'this' is not defined in this context| = this#
public get(): R|ERROR CLASS: 'this' is not defined in this context|
public final val a: <ERROR TYPE REF: 'this' is not defined in this context> = this#
public get(): <ERROR TYPE REF: 'this' is not defined in this context>
public final class F : R|kotlin/Any| {
public constructor(a: R|kotlin/Int|, b: R|kotlin/Int|, closure: R|() -> kotlin/Unit|, instance: R|F?|): R|F| {
super<R|kotlin/Any|>()

View File

@@ -13,7 +13,7 @@ FILE: superIsNotAnExpression.kt
public final fun act(): R|kotlin/Unit| {
<Super cannot be a callee>#()
<Unresolved name: invoke>#()
<Super cannot be a callee>#(<L> = <Super cannot be a callee>@fun <anonymous>(): R|ERROR CLASS: Unresolved name: println| <inline=Unknown> {
<Super cannot be a callee>#(<L> = <Super cannot be a callee>@fun <anonymous>(): <ERROR TYPE REF: Unresolved name: println> <inline=Unknown> {
^ <Unresolved name: println>#(ERROR_EXPR(Incorrect character: 'weird'))
}
)

View File

@@ -22,10 +22,10 @@ FILE: typeArgumentsNotAllowed.kt
}
}
public final val a: R|ERROR CLASS: Unresolved name: MyClass| = Q|rest|.<Unresolved name: MyClass>#
public get(): R|ERROR CLASS: Unresolved name: MyClass|
public final val b: R|ERROR CLASS: Unresolved name: MyClass| = Q|rest/Best|.<Unresolved name: MyClass>#
public get(): R|ERROR CLASS: Unresolved name: MyClass|
public final val a: <ERROR TYPE REF: Unresolved name: MyClass> = Q|rest|.<Unresolved name: MyClass>#
public get(): <ERROR TYPE REF: Unresolved name: MyClass>
public final val b: <ERROR TYPE REF: Unresolved name: MyClass> = Q|rest/Best|.<Unresolved name: MyClass>#
public get(): <ERROR TYPE REF: Unresolved name: MyClass>
public final class B<E> : R|kotlin/Any| {
public constructor<E>(): R|rest/B<E>| {
super<R|kotlin/Any|>()

View File

@@ -22,7 +22,7 @@ FILE: upperBoundViolated.kt
lval b1: R|B<kotlin/Int>| = R|/B.B|<R|kotlin/Int|>()
lval b2: R|B<C>| = R|/B.B|<R|C|>()
lval b3: R|B<kotlin/Any?>| = R|/B.B|<R|kotlin/Any?|>()
lval b4: R|ERROR CLASS: Unresolved name: NumberPhile| = R|/B.B|<<ERROR TYPE REF: Symbol not found for UnexistingType>>().<Unresolved name: NL>#(ERROR_EXPR(No right operand)).<Unresolved name: Int>#(<Call has no callee>#()).<Unresolved name: NumberPhile>#(ERROR_EXPR(No right operand))
lval b4: <ERROR TYPE REF: Unresolved name: NumberPhile> = R|/B.B|<<ERROR TYPE REF: Symbol not found for UnexistingType>>().<Unresolved name: NL>#(ERROR_EXPR(No right operand)).<Unresolved name: Int>#(<Call has no callee>#()).<Unresolved name: NumberPhile>#(ERROR_EXPR(No right operand))
lval b5: R|B<B<ERROR CLASS: Symbol not found for UnexistingType>>| = R|/B.B|<R|B<ERROR CLASS: Symbol not found for UnexistingType>|>()
R|/fest|<R|kotlin/Boolean|>()
R|/fest|<R|C|>()
@@ -58,8 +58,8 @@ FILE: upperBoundViolated.kt
}
public final typealias NL<K> = R|NumColl<kotlin/collections/List<K>>|
public final val test7: R|ERROR CLASS: Unresolved name: NumberPhile| = R|/NumColl.NumColl|<R|kotlin/Int|>().<Unresolved name: NumberPhile>#(ERROR_EXPR(No right operand))
public get(): R|ERROR CLASS: Unresolved name: NumberPhile|
public final val test7: <ERROR TYPE REF: Unresolved name: NumberPhile> = R|/NumColl.NumColl|<R|kotlin/Int|>().<Unresolved name: NumberPhile>#(ERROR_EXPR(No right operand))
public get(): <ERROR TYPE REF: Unresolved name: NumberPhile>
public final val test8: R|NumColl<kotlin/collections/List<kotlin/String>>| = R|/NumColl.NumColl|<R|kotlin/String|>()
public get(): R|NumColl<kotlin/collections/List<kotlin/String>>|
public final class NumberPhile<T : R|kotlin/Number|> : R|kotlin/Any| {

View File

@@ -1,6 +1,6 @@
FILE: main.kt
public final fun test_1(e: R|JavaEnum|): R|kotlin/Unit| {
lval a: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
lval a: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
==($subj$, Q|JavaEnum|.R|/JavaEnum.A|) -> {
Int(1)
}
@@ -9,7 +9,7 @@ FILE: main.kt
}
}
.<Unresolved name: plus>#(Int(0))
lval b: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
lval b: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
==($subj$, Q|JavaEnum|.R|/JavaEnum.A|) -> {
Int(1)
}
@@ -44,7 +44,7 @@ FILE: main.kt
.R|kotlin/Int.plus|(Int(0))
}
public final fun test_2(e: R|JavaEnum?|): R|kotlin/Unit| {
lval a: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
lval a: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
==($subj$, Q|JavaEnum|.R|/JavaEnum.A|) -> {
Int(1)
}

View File

@@ -77,7 +77,7 @@ FILE: exhaustiveness_sealedSubClass.kt
.R|kotlin/Int.plus|(Int(0))
}
public final fun test_2(e: R|A|): R|kotlin/Unit| {
lval a: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
lval a: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
($subj$ is R|D|) -> {
Int(1)
}
@@ -86,7 +86,7 @@ FILE: exhaustiveness_sealedSubClass.kt
}
}
.<Unresolved name: plus>#(Int(0))
lval b: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
lval b: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
($subj$ is R|B|) -> {
Int(1)
}
@@ -98,7 +98,7 @@ FILE: exhaustiveness_sealedSubClass.kt
}
}
.<Unresolved name: plus>#(Int(0))
lval c: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
lval c: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
($subj$ is R|B|) -> {
Int(1)
}

View File

@@ -27,7 +27,7 @@ fun test_1(e: A) {
val d = when (e) {
is E -> 1
is A -> 2
<!USELESS_IS_CHECK!>is A<!> -> 2
}.plus(0)
}

View File

@@ -29,8 +29,8 @@ FILE: CallBasedInExpressionGenerator.kt
public final val codegen: R|org/jetbrains/kotlin/codegen/range/inExpression/ExpressionCodegen| = R|<local>/codegen|
public get(): R|org/jetbrains/kotlin/codegen/range/inExpression/ExpressionCodegen|
private final val resolvedCall: R|ERROR CLASS: Unresolved name: getResolvedCallWithAssert| = R|<local>/operatorReference|.<Unresolved name: getResolvedCallWithAssert>#(this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.codegen|.<Unresolved name: bindingContext>#)
private get(): R|ERROR CLASS: Unresolved name: getResolvedCallWithAssert|
private final val resolvedCall: <ERROR TYPE REF: Unresolved name: getResolvedCallWithAssert> = R|<local>/operatorReference|.<Unresolved name: getResolvedCallWithAssert>#(this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.codegen|.<Unresolved name: bindingContext>#)
private get(): <ERROR TYPE REF: Unresolved name: getResolvedCallWithAssert>
private final val isInverted: R|kotlin/Boolean| = ==(R|<local>/operatorReference|.<Unresolved name: getReferencedNameElementType>#(), <Unresolved name: KtTokens>#.<Unresolved name: NOT_IN>#)
private get(): R|kotlin/Boolean|
@@ -75,7 +75,7 @@ FILE: CallBasedInExpressionGenerator.kt
}
private final fun invokeFunction(v: R|org/jetbrains/kotlin/codegen/range/inExpression/InstructionAdapter|): R|kotlin/Unit| {
lval result: R|ERROR CLASS: Unresolved name: invokeFunction| = this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.codegen|.<Unresolved name: invokeFunction>#(this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.resolvedCall|.<Unresolved name: call>#, this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.resolvedCall|, <Unresolved name: none>#())
lval result: <ERROR TYPE REF: Unresolved name: invokeFunction> = this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.codegen|.<Unresolved name: invokeFunction>#(this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.resolvedCall|.<Unresolved name: call>#, this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.resolvedCall|, <Unresolved name: none>#())
R|<local>/result|.<Unresolved name: put>#(R|<local>/result|.<Unresolved name: type>#, R|<local>/result|.<Unresolved name: kotlinType>#, R|<local>/v|)
}

View File

@@ -57,7 +57,7 @@ FILE: access.kt
lval a: R|kotlin/Int| = Int(10)
lval b: R|kotlin/Int| = R|<local>/a|
lval d: R|kotlin/String| = String()
lval c: R|ERROR CLASS: Unresolved name: c| = <Unresolved name: c>#
lval c: <ERROR TYPE REF: Unresolved name: c> = <Unresolved name: c>#
<Unresolved name: abc>#()
local final fun bcd(): R|kotlin/Unit| {
}

View File

@@ -29,7 +29,7 @@ FILE: Test.kt
lval bbd: R|BB.D| = Q|BB.D|
lval aac: R|AA.C| = Q|AA.C|
Q|JavaClass|.R|/JavaClass.bar|()
lval errC: R|ERROR CLASS: Unresolved name: C| = Q|BB|.<Unresolved name: C>#
lval errBarViaBB: R|ERROR CLASS: Unresolved name: bar| = Q|BB|.<Unresolved name: bar>#()
lval errBarViaAA: R|ERROR CLASS: Unresolved name: bar| = Q|AA|.<Unresolved name: bar>#()
lval errC: <ERROR TYPE REF: Unresolved name: C> = Q|BB|.<Unresolved name: C>#
lval errBarViaBB: <ERROR TYPE REF: Unresolved name: bar> = Q|BB|.<Unresolved name: bar>#()
lval errBarViaAA: <ERROR TYPE REF: Unresolved name: bar> = Q|AA|.<Unresolved name: bar>#()
}

View File

@@ -4,7 +4,7 @@ class Factory {
}
companion object {
val f = Function
val f = <!NO_COMPANION_OBJECT!>Function<!>
val x = Function.Default
}
}

View File

@@ -47,5 +47,5 @@ FILE: companion.kt
Q|B|.R|/B.Companion.baz|()
lval x: R|kotlin/String| = Q|A|.R|/A.Companion.D|
lval y: R|kotlin/String| = Q|B|.R|/B.Companion.C|
lval z: R|ERROR CLASS: Unresolved name: D| = Q|B|.<Unresolved name: D>#
lval z: <ERROR TYPE REF: Unresolved name: D> = Q|B|.<Unresolved name: D>#
}

View File

@@ -18,10 +18,10 @@ FILE: errCallable.kt
}
public final fun foo(): R|kotlin/Unit| {
lval x: R|ERROR CLASS: Unresolved reference: Nested| = ::<Unresolved reference: Nested>#
lval x: <ERROR TYPE REF: Unresolved reference: Nested> = ::<Unresolved reference: Nested>#
}
}
public final fun R|Your|.foo(): R|kotlin/Unit| {
lval x: R|ERROR CLASS: Unresolved reference: Nested| = ::<Unresolved reference: Nested>#
lval x: <ERROR TYPE REF: Unresolved reference: Nested> = ::<Unresolved reference: Nested>#
}

View File

@@ -2,5 +2,5 @@ class Outer {
inner class Inner
}
val x = Outer.Inner
val x = Outer.<!NO_COMPANION_OBJECT!>Inner<!>
val klass = Outer.Inner::class

View File

@@ -40,5 +40,5 @@ FILE: localObjects.kt
Q|B|.R|/B.foo|()
}
public final val bb: R|ERROR CLASS: Unresolved name: foo| = <Unresolved name: B>#.<Unresolved name: foo>#()
public get(): R|ERROR CLASS: Unresolved name: foo|
public final val bb: <ERROR TYPE REF: Unresolved name: foo> = <Unresolved name: B>#.<Unresolved name: foo>#()
public get(): <ERROR TYPE REF: Unresolved name: foo>

View File

@@ -25,7 +25,7 @@ FILE: nestedObjects.kt
}
}
public final val err: R|ERROR CLASS: Unresolved name: B| = Q|B|.<Unresolved name: A>#.<Unresolved name: B>#
public get(): R|ERROR CLASS: Unresolved name: B|
public final val err: <ERROR TYPE REF: Unresolved name: B> = Q|B|.<Unresolved name: A>#.<Unresolved name: B>#
public get(): <ERROR TYPE REF: Unresolved name: B>
public final val correct: R|A.B.A| = Q|A.B.A|
public get(): R|A.B.A|

View File

@@ -33,7 +33,7 @@ FILE: privateObjectLiteral.kt
internal get(): R|kotlin/Any|
public final val w: R|ERROR CLASS: Unresolved name: foo| = this@R|/C|.R|/C.z|.<Unresolved name: foo>#()
public get(): R|ERROR CLASS: Unresolved name: foo|
public final val w: <ERROR TYPE REF: Unresolved name: foo> = this@R|/C|.R|/C.z|.<Unresolved name: foo>#()
public get(): <ERROR TYPE REF: Unresolved name: foo>
}

View File

@@ -23,7 +23,8 @@ object D {
val D.E get() = ""
val def = D.E.F // object
val de = D.E // extension
// See KT-46409
val de = D.<!NO_COMPANION_OBJECT!>E<!> // Should be: extension & no error, in fact: qualifier
enum class G {
H;

View File

@@ -1,6 +1,6 @@
fun foo() = if (true) 1 else 0
fun bar(arg: Any?) = when (arg) {
is Int -> arg as Int
is Int -> arg <!USELESS_CAST!>as Int<!>
else -> 42
}

View File

@@ -41,7 +41,7 @@ FILE: inner.kt
public final fun test(): R|kotlin/Unit| {
lval o: R|Owner| = R|/Owner.Owner|()
R|<local>/o|.R|/Owner.foo|()
lval err: R|ERROR CLASS: Unresolved name: Inner| = Q|Owner|.<Unresolved name: Inner>#()
lval err: <ERROR TYPE REF: Unresolved name: Inner> = Q|Owner|.<Unresolved name: Inner>#()
R|<local>/err|.<Unresolved name: baz>#()
lval i: R|Owner.Inner| = R|<local>/o|.R|/Owner.Inner.Inner|()
R|<local>/i|.R|/Owner.Inner.gau|()

View File

@@ -32,7 +32,7 @@ fun case1(javaClass: JavaClass?) {
}
class Case1(val javaClass: JavaClass?) {
val x = if (javaClass != null) { it -> it == javaClass } else BooCase2.FILTER
val x = if (javaClass != null) { it -> <!EQUALITY_NOT_APPLICABLE_WARNING!>it == javaClass<!> } else BooCase2.FILTER
}
class BooCase1() {

View File

@@ -35,7 +35,7 @@ FILE: nestedClassContructor.kt
public final fun foo(): R|kotlin/Unit| {
lval a: R|A| = R|/A.A|()
lval ac: R|A.C| = Q|A|.R|/A.C.C|()
lval c: R|ERROR CLASS: Unresolved name: C| = <Unresolved name: C>#()
lval c: <ERROR TYPE REF: Unresolved name: C> = <Unresolved name: C>#()
}
}

View File

@@ -26,7 +26,7 @@ FILE: test.kt
public final fun test(): R|kotlin/Unit| {
lval descriptor: R|WrappedPropertyDescriptor| = R|/WrappedPropertyDescriptor.WrappedPropertyDescriptor|()
lval res1: R|kotlin/String| = R|<local>/descriptor|.R|/WrappedPropertyDescriptor.setter|
lval res2: R|ERROR CLASS: Unresolved name: getSetter| = R|<local>/descriptor|.<Unresolved name: getSetter>#()
lval res2: <ERROR TYPE REF: Unresolved name: getSetter> = R|<local>/descriptor|.<Unresolved name: getSetter>#()
lval res3: R|kotlin/Boolean| = R|<local>/descriptor|.R|/WrappedPropertyDescriptor.isDelegated|
lval res4: R|ERROR CLASS: Unresolved name: isDelegated| = R|<local>/descriptor|.<Unresolved name: isDelegated>#()
lval res4: <ERROR TYPE REF: Unresolved name: isDelegated> = R|<local>/descriptor|.<Unresolved name: isDelegated>#()
}

View File

@@ -1,5 +1,5 @@
FILE: main.kt
public final fun test(): R|kotlin/Unit| {
lval some: R|foo/Some| = R|foo/Some.Some|()
lval another: R|ERROR CLASS: Unresolved name: Another| = <Unresolved name: Another>#()
lval another: <ERROR TYPE REF: Unresolved name: Another> = <Unresolved name: Another>#()
}

View File

@@ -1,3 +1,4 @@
// FIR_IDE_IGNORE
// FILE: foo/Some.java
package foo;

View File

@@ -0,0 +1,46 @@
FILE: symbolsAndDescriptors.kt
public final class IrClassSymbolImpl : R|IrBindableSymbolBase<kotlin/String>|, R|IrClassSymbol| {
public constructor(descriptor: R|kotlin/String?| = Null(null)): R|IrClassSymbolImpl| {
super<R|IrBindableSymbolBase<kotlin/String>|>(R|<local>/descriptor|)
}
}
public abstract interface IrClassSymbol : R|IrClassifierSymbol|, R|IrBindableSymbol<kotlin/String>| {
}
public abstract interface IrClassifierSymbol : R|IrSymbol|, R|TypeConstructorMarker| {
public abstract override val descriptor: R|kotlin/CharSequence|
public get(): R|kotlin/CharSequence|
}
public abstract interface IrSymbol : R|kotlin/Any| {
public abstract val descriptor: R|kotlin/Any|
public get(): R|kotlin/Any|
}
public abstract interface TypeConstructorMarker : R|kotlin/Any| {
}
public abstract interface IrBindableSymbol<out D : R|kotlin/Any|> : R|IrSymbol| {
public abstract override val descriptor: R|D|
public get(): R|D|
}
public abstract class IrBindableSymbolBase<out D : R|kotlin/Any|> : R|IrBindableSymbol<D>|, R|IrSymbolBase<D>| {
public constructor<out D : R|kotlin/Any|>(descriptor: R|D?|): R|IrBindableSymbolBase<D>| {
super<R|IrSymbolBase<D>|>(R|<local>/descriptor|)
}
}
public abstract class IrSymbolBase<out D : R|kotlin/Any|> : R|IrSymbol| {
public constructor<out D : R|kotlin/Any|>(_descriptor: R|D?|): R|IrSymbolBase<D>| {
super<R|kotlin/Any|>()
}
private final val _descriptor: R|D?| = R|<local>/_descriptor|
private get(): R|D?|
public open override val descriptor: R|D|
public get(): R|D| {
^ this@R|/IrSymbolBase|.R|/IrSymbolBase._descriptor|!!
}
}

View File

@@ -0,0 +1,33 @@
class IrClassSymbolImpl(descriptor: String? = null) :
IrBindableSymbolBase<String>(descriptor),
IrClassSymbol
interface IrClassSymbol : IrClassifierSymbol, IrBindableSymbol<String>
interface IrClassifierSymbol : IrSymbol, TypeConstructorMarker {
override val descriptor: CharSequence
}
interface IrSymbol {
val descriptor: Any
}
interface TypeConstructorMarker
interface IrBindableSymbol<out D : Any> : IrSymbol {
override val descriptor: D
}
abstract class IrBindableSymbolBase<out D : Any>(descriptor: D?) :
IrBindableSymbol<D>, IrSymbolBase<D>(descriptor)
abstract class IrSymbolBase<out D : Any>(
private val _descriptor: D?
) : IrSymbol {
override val descriptor: D
get() = _descriptor!!
}

View File

@@ -1,15 +1,15 @@
FILE: main.kt
public final fun test_1(x: R|A|): R|kotlin/Unit| {
lval str1: R|ft<kotlin/String, kotlin/String?>| = R|<local>/x|.R|/A.vmParameters|
lval str2: R|ERROR CLASS: Unresolved name: vMParameters| = R|<local>/x|.<Unresolved name: vMParameters>#
lval str2: <ERROR TYPE REF: Unresolved name: vMParameters> = R|<local>/x|.<Unresolved name: vMParameters>#
}
public final fun test_2(x: R|B|): R|kotlin/Unit| {
lval int: R|ft<kotlin/Int, kotlin/Int?>| = R|<local>/x|.R|/B.vmParameters|
lval error: R|ERROR CLASS: Unresolved name: vMParameters| = R|<local>/x|.<Unresolved name: vMParameters>#
lval error: <ERROR TYPE REF: Unresolved name: vMParameters> = R|<local>/x|.<Unresolved name: vMParameters>#
}
public final fun test_3(x: R|C|): R|kotlin/Unit| {
lval error: R|ERROR CLASS: Ambiguity: vmParameters, [/C.vmParameters, /C.vmParameters]| = R|<local>/x|.<Ambiguity: vmParameters, [/C.vmParameters, /C.vmParameters]>#
lval int: R|ERROR CLASS: Unresolved name: vMParameters| = R|<local>/x|.<Unresolved name: vMParameters>#
lval error: <ERROR TYPE REF: Ambiguity: vmParameters, [/C.vmParameters, /C.vmParameters]> = R|<local>/x|.<Ambiguity: vmParameters, [/C.vmParameters, /C.vmParameters]>#
lval int: <ERROR TYPE REF: Unresolved name: vMParameters> = R|<local>/x|.<Unresolved name: vMParameters>#
}
public final class Foo : R|kotlin/Any| {
public constructor(): R|Foo| {

View File

@@ -7,7 +7,7 @@ FILE: leakedImplicitType.kt
public final fun bar(): R|kotlin/Unit| {
}
public final fun f(): R|ERROR CLASS: Unresolved reference: bar| {
public final fun f(): <ERROR TYPE REF: Unresolved reference: bar> {
^f <Unresolved name: Unresolved>#()::<Unresolved reference: bar>#
}

View File

@@ -40,8 +40,8 @@ FILE: referenceToExtension.kt
}
public final fun test_2(): R|kotlin/Unit| {
lval extensionValRef: R|ERROR CLASS: Unresolved reference: extensionVal| = Q|GenericTest.B|::<Unresolved reference: extensionVal>#
lval extensionFunRef: R|ERROR CLASS: Unresolved reference: extensionFun| = Q|GenericTest.B|::<Unresolved reference: extensionFun>#
lval extensionValRef: <ERROR TYPE REF: Unresolved reference: extensionVal> = Q|GenericTest.B|::<Unresolved reference: extensionVal>#
lval extensionFunRef: <ERROR TYPE REF: Unresolved reference: extensionFun> = Q|GenericTest.B|::<Unresolved reference: extensionFun>#
}
}

View File

@@ -3,7 +3,7 @@ class Some
fun foo(): () -> Boolean {
val s = Some()
if (true) {
return { if (s is Some) true else false }
return { if (<!USELESS_IS_CHECK!>s is Some<!>) true else false }
} else {
return { true }
}

View File

@@ -45,12 +45,12 @@ fun case3() {
val flag = "" //A
val l1 = <!NO_ELSE_IN_WHEN!>when<!> (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {// should be NO_ELSE_IN_WHEN
A.A1 -> B() //should be INCOMPATIBLE_TYPES
A.A2 -> B() //should be INCOMPATIBLE_TYPES
<!INCOMPATIBLE_TYPES!>A.A1<!> -> B() //should be INCOMPATIBLE_TYPES
<!INCOMPATIBLE_TYPES!>A.A2<!> -> B() //should be INCOMPATIBLE_TYPES
}
val l2 = <!NO_ELSE_IN_WHEN!>when<!> (flag) {// should be NO_ELSE_IN_WHEN
A.A1 -> B() //should be INCOMPATIBLE_TYPES
A.A2 -> B() //should be INCOMPATIBLE_TYPES
<!INCOMPATIBLE_TYPES!>A.A1<!> -> B() //should be INCOMPATIBLE_TYPES
<!INCOMPATIBLE_TYPES!>A.A2<!> -> B() //should be INCOMPATIBLE_TYPES
}
}

View File

@@ -13,7 +13,7 @@ FILE: beyoundCalls.kt
}
public final fun foo(): R|kotlin/Unit| {
lval x: R|(kotlin/String) -> kotlin/Int| = ::R|/bar|
lval y: R|ERROR CLASS: Ambiguity: bar, [/bar, /bar]| = ::<Ambiguity: bar, [/bar, /bar]>#
lval y: <ERROR TYPE REF: Ambiguity: bar, [/bar, /bar]> = ::<Ambiguity: bar, [/bar, /bar]>#
lval z: R|kotlin/reflect/KFunction1<kotlin/String, kotlin/Int>| = ::R|/baz|
lval w: R|(kotlin/String) -> kotlin/Int| = ::R|/foobaz<kotlin/String, kotlin/Int>|
::R|/baz|

View File

@@ -9,7 +9,7 @@ FILE: moreSpecificAmbiguousExtensions.kt
}
public final fun test(): R|kotlin/Unit| {
lval extFun1: R|@ExtensionFunctionType kotlin/reflect/KFunction2<IA, IB, kotlin/Unit>| = Q|IA|::R|/extFun|
lval extFun2: R|ERROR CLASS: Ambiguity: extFun, [/extFun, /extFun]| = Q|IB|::<Ambiguity: extFun, [/extFun, /extFun]>#
lval extFun2: <ERROR TYPE REF: Ambiguity: extFun, [/extFun, /extFun]> = Q|IB|::<Ambiguity: extFun, [/extFun, /extFun]>#
}
public final fun testWithExpectedType(): R|kotlin/Unit| {
lval extFun_AB_A: R|IA.(IB) -> kotlin/Unit| = Q|IA|::R|/extFun|

View File

@@ -172,9 +172,9 @@ FILE: forLoopChecker.kt
}
public final fun test(notRange1: R|NotRange1|, notRange2: R|NotRange2|, notRange3: R|NotRange3|, notRange4: R|NotRange4|, notRange5: R|NotRange5|, notRange6: R|NotRange6|, notRange7: R|NotRange7|, notRange8: R|NotRange8|, notRange9: R|NotRange9|, range0: R|Range0|, range1: R|Range1|): R|kotlin/Unit| {
{
lval <iterator>: R|ERROR CLASS: Unresolved name: iterator| = R|<local>/notRange1|.<Unresolved name: iterator>#()
lval <iterator>: <ERROR TYPE REF: Unresolved name: iterator> = R|<local>/notRange1|.<Unresolved name: iterator>#()
while(R|<local>/<iterator>|.<Unresolved name: hasNext>#()) {
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
lval i: <ERROR TYPE REF: Unresolved name: next> = R|<local>/<iterator>|.<Unresolved name: next>#()
}
}
@@ -182,7 +182,7 @@ FILE: forLoopChecker.kt
{
lval <iterator>: R|kotlin/Unit| = R|<local>/notRange2|.R|/NotRange2.iterator|()
while(R|<local>/<iterator>|.<Unresolved name: hasNext>#()) {
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
lval i: <ERROR TYPE REF: Unresolved name: next> = R|<local>/<iterator>|.<Unresolved name: next>#()
}
}
@@ -190,7 +190,7 @@ FILE: forLoopChecker.kt
{
lval <iterator>: R|ImproperIterator1| = R|<local>/notRange3|.R|/NotRange3.iterator|()
while(R|<local>/<iterator>|.R|/ImproperIterator1.hasNext|()) {
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
lval i: <ERROR TYPE REF: Unresolved name: next> = R|<local>/<iterator>|.<Unresolved name: next>#()
}
}

View File

@@ -1,3 +1,4 @@
// FIR_IDE_IGNORE
// FILE: K1.kt
class KSub : J1()

View File

@@ -7,8 +7,8 @@ FILE: test.kt
super<R|kotlin/Any|>()
}
private final val klass: R|java/lang/Class<MyTest>| = <getClass>(this@R|/MyTest|).R|kotlin/jvm/java|<R|MyTest|>
private get(): R|java/lang/Class<MyTest>|
private final val klass: R|java/lang/Class<out MyTest>| = <getClass>(this@R|/MyTest|).R|kotlin/jvm/java|<R|MyTest|>
private get(): R|java/lang/Class<out MyTest>|
private final val logger: R|ft<Logger, Logger?>| = Q|Logger|.R|/Logger.getInstance|(this@R|/MyTest|.R|/MyTest.klass|)
private get(): R|ft<Logger, Logger?>|

View File

@@ -1,3 +1,4 @@
// FIR_IDE_IGNORE
// FILE: K1.kt
class K2: J1() {
class Q : <!UNRESOLVED_REFERENCE!>Nested<!>()

View File

@@ -14,7 +14,7 @@ class Case1() {
this.yield("") //UNRESOLVED_REFERENCE
this as SequenceScope<String>
this <!USELESS_CAST!>as SequenceScope<String><!>
yield("") // resolved to SequenceScope.yield
@@ -31,10 +31,10 @@ fun case2() {
this.yield("") //UNRESOLVED_REFERENCE
this as SequenceScope<String>
this <!USELESS_CAST!>as SequenceScope<String><!>
yield("") // UNRESOLVED_REFERENCE
this.yield("") // UNRESOLVED_REFERENCE
}
}
}

View File

@@ -3159,6 +3159,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
}
@Test
@TestMetadata("symbolsAndDescriptors.kt")
public void testSymbolsAndDescriptors() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
}
@Test
@TestMetadata("transform.kt")
public void testTransform() throws Exception {

View File

@@ -3159,6 +3159,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
}
@Test
@TestMetadata("symbolsAndDescriptors.kt")
public void testSymbolsAndDescriptors() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
}
@Test
@TestMetadata("transform.kt")
public void testTransform() throws Exception {

View File

@@ -620,6 +620,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
}
@Test
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
}
@Test
@TestMetadata("ReserveYield.kt")
public void testReserveYield() throws Exception {
@@ -9071,6 +9077,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/enum/starImportNestedClassAndEntries.kt");
}
@Test
@TestMetadata("typeCompatibility.kt")
public void testTypeCompatibility() throws Exception {
runTest("compiler/testData/diagnostics/tests/enum/typeCompatibility.kt");
}
@Test
@TestMetadata("typeParametersInEnum.kt")
public void testTypeParametersInEnum() throws Exception {
@@ -12587,6 +12599,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/inference/violatingUpperBoundForSelfType.kt");
}
@Test
@TestMetadata("violatingUpperBoundForSelfTypeError.kt")
public void testViolatingUpperBoundForSelfTypeError() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/violatingUpperBoundForSelfTypeError.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference")
@TestDataPath("$PROJECT_ROOT")
@@ -16840,6 +16858,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented.kt");
}
@Test
@TestMetadata("abstractBaseClassMemberNotImplemented_15.kt")
public void testAbstractBaseClassMemberNotImplemented_15() throws Exception {
runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.kt");
}
@Test
@TestMetadata("abstractVsAbstract.kt")
public void testAbstractVsAbstract() throws Exception {
@@ -16869,6 +16893,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/java8Overrides/implementingMethodOfAny.kt");
}
@Test
@TestMetadata("kt45508.kt")
public void testKt45508() throws Exception {
runTest("compiler/testData/diagnostics/tests/java8Overrides/kt45508.kt");
}
@Test
@TestMetadata("notAMethodOfAny.kt")
public void testNotAMethodOfAny() throws Exception {
@@ -21130,6 +21160,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/arrays.kt");
}
@Test
@TestMetadata("dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt")
public void testDontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt");
}
@Test
@TestMetadata("dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt")
public void testDontSubstituteAnotherErasedTypeArgumentIfRecursive() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt");
}
@Test
@TestMetadata("errorType.kt")
public void testErrorType() throws Exception {
@@ -21220,6 +21262,30 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/starProjectionToRaw.kt");
}
@Test
@TestMetadata("substituteAnotherErasedTypeArgument.kt")
public void testSubstituteAnotherErasedTypeArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt");
}
@Test
@TestMetadata("substituteOtherErasedDeepTypeArguments.kt")
public void testSubstituteOtherErasedDeepTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt");
}
@Test
@TestMetadata("substituteSeveralOtherErasedDependentTypeArguments.kt")
public void testSubstituteSeveralOtherErasedDependentTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt");
}
@Test
@TestMetadata("substituteSeveralOtherErasedTypeArguments.kt")
public void testSubstituteSeveralOtherErasedTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt");
}
@Test
@TestMetadata("typeEnhancement.kt")
public void testTypeEnhancement() throws Exception {
@@ -29147,6 +29213,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42042.kt");
}
@Test
@TestMetadata("kt42042Error.kt")
public void testKt42042Error() throws Exception {
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42042Error.kt");
}
@Test
@TestMetadata("kt42396.kt")
public void testKt42396() throws Exception {

View File

@@ -620,6 +620,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
}
@Test
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
}
@Test
@TestMetadata("ReserveYield.kt")
public void testReserveYield() throws Exception {
@@ -9071,6 +9077,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/enum/starImportNestedClassAndEntries.kt");
}
@Test
@TestMetadata("typeCompatibility.kt")
public void testTypeCompatibility() throws Exception {
runTest("compiler/testData/diagnostics/tests/enum/typeCompatibility.kt");
}
@Test
@TestMetadata("typeParametersInEnum.kt")
public void testTypeParametersInEnum() throws Exception {
@@ -12587,6 +12599,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/inference/violatingUpperBoundForSelfType.kt");
}
@Test
@TestMetadata("violatingUpperBoundForSelfTypeError.kt")
public void testViolatingUpperBoundForSelfTypeError() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/violatingUpperBoundForSelfTypeError.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference")
@TestDataPath("$PROJECT_ROOT")
@@ -16840,6 +16858,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented.kt");
}
@Test
@TestMetadata("abstractBaseClassMemberNotImplemented_15.kt")
public void testAbstractBaseClassMemberNotImplemented_15() throws Exception {
runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.kt");
}
@Test
@TestMetadata("abstractVsAbstract.kt")
public void testAbstractVsAbstract() throws Exception {
@@ -16869,6 +16893,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/java8Overrides/implementingMethodOfAny.kt");
}
@Test
@TestMetadata("kt45508.kt")
public void testKt45508() throws Exception {
runTest("compiler/testData/diagnostics/tests/java8Overrides/kt45508.kt");
}
@Test
@TestMetadata("notAMethodOfAny.kt")
public void testNotAMethodOfAny() throws Exception {
@@ -21130,6 +21160,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/arrays.kt");
}
@Test
@TestMetadata("dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt")
public void testDontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt");
}
@Test
@TestMetadata("dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt")
public void testDontSubstituteAnotherErasedTypeArgumentIfRecursive() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt");
}
@Test
@TestMetadata("errorType.kt")
public void testErrorType() throws Exception {
@@ -21220,6 +21262,30 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/starProjectionToRaw.kt");
}
@Test
@TestMetadata("substituteAnotherErasedTypeArgument.kt")
public void testSubstituteAnotherErasedTypeArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt");
}
@Test
@TestMetadata("substituteOtherErasedDeepTypeArguments.kt")
public void testSubstituteOtherErasedDeepTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt");
}
@Test
@TestMetadata("substituteSeveralOtherErasedDependentTypeArguments.kt")
public void testSubstituteSeveralOtherErasedDependentTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt");
}
@Test
@TestMetadata("substituteSeveralOtherErasedTypeArguments.kt")
public void testSubstituteSeveralOtherErasedTypeArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt");
}
@Test
@TestMetadata("typeEnhancement.kt")
public void testTypeEnhancement() throws Exception {
@@ -29147,6 +29213,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42042.kt");
}
@Test
@TestMetadata("kt42042Error.kt")
public void testKt42042Error() throws Exception {
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42042Error.kt");
}
@Test
@TestMetadata("kt42396.kt")
public void testKt42396() throws Exception {

View File

@@ -94,7 +94,7 @@ class Generator(
printPackageAndCopyright()
printImports()
printGeneratedMessage()
println("internal class $composedComponentName : $checkersComponentName() {")
println("class $composedComponentName : $checkersComponentName() {")
withIndent {
// public overrides
for (alias in configuration.aliases.values) {
@@ -122,7 +122,7 @@ class Generator(
// register function
println(CHECKERS_COMPONENT_INTERNAL_ANNOTATION)
println("internal fun register(checkers: $checkersComponentName) {")
println("fun register(checkers: $checkersComponentName) {")
withIndent {
for (alias in configuration.aliases.values) {
println("_${alias.fieldName} += checkers.${alias.fieldName}")

View File

@@ -38,6 +38,8 @@ fun main(args: Array<String>) {
alias<FirEqualityOperatorCall>("EqualityOperatorCallChecker")
alias<FirAnonymousFunction>("AnonymousFunctionAsExpressionChecker")
alias<FirStringConcatenationCall>("StringConcatenationCallChecker")
alias<FirTypeOperatorCall>("TypeOperatorCallChecker")
alias<FirResolvedQualifier>("ResolvedQualifierChecker")
}
val declarationPackage = "org.jetbrains.kotlin.fir.analysis.checkers.declaration"

View File

@@ -52,6 +52,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
CONST_MODIFIER,
ARRAY_ACCESS,
SAFE_ACCESS,
AS_TYPE,
USELESS_ELVIS,
NAME_OF_NAMED_ARGUMENT,
VALUE_ARGUMENTS,
@@ -67,6 +68,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
FUN_MODIFIER,
SUSPEND_MODIFIER,
FUN_INTERFACE,
RESERVED_UNDERSCORE,
;

View File

@@ -82,6 +82,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val NO_THIS by error<PsiElement>()
}
val CALL_RESOLUTION by object : DiagnosticGroup("Call resolution") {
val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error<KtExpression>()
}
val SUPER by object : DiagnosticGroup("Super") {
val SUPER_IS_NOT_AN_EXPRESSION by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val SUPER_NOT_AVAILABLE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
@@ -251,6 +255,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val NAMED_PARAMETER_NOT_FOUND by error<KtValueArgument>(PositioningStrategy.NAME_OF_NAMED_ARGUMENT) {
parameter<String>("name")
}
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>()
}
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
@@ -354,6 +360,16 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning<KtTypeParameter>()
val DYNAMIC_UPPER_BOUND by error<KtTypeReference>()
val INCOMPATIBLE_TYPES by error<KtElement> {
parameter<ConeKotlinType>("typeA")
parameter<ConeKotlinType>("typeB")
}
val INCOMPATIBLE_TYPES_WARNING by warning<KtElement> {
parameter<ConeKotlinType>("typeA")
parameter<ConeKotlinType>("typeB")
}
}
val REFLECTION by object : DiagnosticGroup("Reflection") {
@@ -648,6 +664,13 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val USELESS_ELVIS_RIGHT_IS_NULL by warning<KtBinaryExpression>(PositioningStrategy.USELESS_ELVIS)
}
val CASTS_AND_IS_CHECKS by object : DiagnosticGroup("Casts and is-checks") {
val USELESS_CAST by warning<KtBinaryExpressionWithTypeRHS>(PositioningStrategy.AS_TYPE)
val USELESS_IS_CHECK by warning<KtElement> {
parameter<Boolean>("compileTimeCheckResult")
}
}
val WHEN_EXPRESSIONS by object : DiagnosticGroup("When expressions") {
val NO_ELSE_IN_WHEN by error<KtWhenExpression>(PositioningStrategy.WHEN_EXPRESSION) {
parameter<List<WhenMissingCase>>("missingWhenCases")
@@ -663,6 +686,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val TYPE_PARAMETER_ON_LHS_OF_DOT by error<KtSimpleNameExpression> {
parameter<FirTypeParameterSymbol>("typeParameter")
}
val NO_COMPANION_OBJECT by error<KtSimpleNameExpression>(PositioningStrategy.SELECTOR_BY_QUALIFIED) {
parameter<FirRegularClassSymbol>("klass")
}
val EXPRESSION_EXPECTED_PACKAGE_FOUND by error<KtSimpleNameExpression>(PositioningStrategy.SELECTOR_BY_QUALIFIED)
}
val FUNCTION_CONTRACTS by object : DiagnosticGroup("Function contracts") {
@@ -696,6 +723,29 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
parameter<String>("expectedFunctionSignature")
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
}
val DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH by error<KtExpression> {
parameter<String>("delegateFunction")
parameter<ConeKotlinType>("expected")
parameter<ConeKotlinType>("actual")
}
val UNDERSCORE_IS_RESERVED by error<KtExpression>(PositioningStrategy.RESERVED_UNDERSCORE)
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error<KtExpression>(PositioningStrategy.RESERVED_UNDERSCORE)
val EQUALITY_NOT_APPLICABLE by error<KtBinaryExpression> {
parameter<String>("operator")
parameter<ConeKotlinType>("leftType")
parameter<ConeKotlinType>("rightType")
}
val EQUALITY_NOT_APPLICABLE_WARNING by warning<KtBinaryExpression> {
parameter<String>("operator")
parameter<ConeKotlinType>("leftType")
parameter<ConeKotlinType>("rightType")
}
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error<KtElement> {
parameter<ConeKotlinType>("leftType")
parameter<ConeKotlinType>("rightType")
}
}
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
@@ -725,6 +775,49 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val RETURN_NOT_ALLOWED by error<KtReturnExpression>(PositioningStrategy.RETURN_WITH_LABEL)
val RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY by error<KtReturnExpression>(PositioningStrategy.RETURN_WITH_LABEL)
}
val INLINE by object : DiagnosticGroup("Inline") {
val USAGE_IS_NOT_INLINABLE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("parameter")
}
val NON_LOCAL_RETURN_NOT_ALLOWED by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("parameter")
}
val RECURSION_IN_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("symbol")
}
val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("inlineDeclaration")
parameter<Symbol>("referencedDeclaration")
}
val PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("inlineDeclaration")
parameter<Symbol>("referencedDeclaration")
}
val PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("inlineDeclaration")
parameter<Symbol>("referencedDeclaration")
}
val PROTECTED_CALL_FROM_PUBLIC_INLINE by warning<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("inlineDeclaration")
parameter<Symbol>("referencedDeclaration")
}
val PRIVATE_CLASS_MEMBER_FROM_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("inlineDeclaration")
parameter<Symbol>("referencedDeclaration")
}
val SUPER_CALL_FROM_PUBLIC_INLINE by warning<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("symbol")
}
}
}
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {

View File

@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
* DO NOT MODIFY IT MANUALLY
*/
internal class ComposedDeclarationCheckers : DeclarationCheckers() {
class ComposedDeclarationCheckers : DeclarationCheckers() {
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
get() = _basicDeclarationCheckers
override val memberDeclarationCheckers: Set<FirMemberDeclarationChecker>
@@ -54,7 +54,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() {
private val _variableAssignmentCfaBasedCheckers: MutableSet<AbstractFirPropertyInitializationChecker> = mutableSetOf()
@CheckersComponentInternal
internal fun register(checkers: DeclarationCheckers) {
fun register(checkers: DeclarationCheckers) {
_basicDeclarationCheckers += checkers.basicDeclarationCheckers
_memberDeclarationCheckers += checkers.memberDeclarationCheckers
_functionCheckers += checkers.functionCheckers

View File

@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
* DO NOT MODIFY IT MANUALLY
*/
internal class ComposedExpressionCheckers : ExpressionCheckers() {
class ComposedExpressionCheckers : ExpressionCheckers() {
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
get() = _basicExpressionCheckers
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
@@ -45,6 +45,10 @@ internal class ComposedExpressionCheckers : ExpressionCheckers() {
get() = _anonymousFunctionAsExpressionCheckers
override val stringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker>
get() = _stringConcatenationCallCheckers
override val typeOperatorCallCheckers: Set<FirTypeOperatorCallChecker>
get() = _typeOperatorCallCheckers
override val resolvedQualifierCheckers: Set<FirResolvedQualifierChecker>
get() = _resolvedQualifierCheckers
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
@@ -62,9 +66,11 @@ internal class ComposedExpressionCheckers : ExpressionCheckers() {
private val _equalityOperatorCallCheckers: MutableSet<FirEqualityOperatorCallChecker> = mutableSetOf()
private val _anonymousFunctionAsExpressionCheckers: MutableSet<FirAnonymousFunctionAsExpressionChecker> = mutableSetOf()
private val _stringConcatenationCallCheckers: MutableSet<FirStringConcatenationCallChecker> = mutableSetOf()
private val _typeOperatorCallCheckers: MutableSet<FirTypeOperatorCallChecker> = mutableSetOf()
private val _resolvedQualifierCheckers: MutableSet<FirResolvedQualifierChecker> = mutableSetOf()
@CheckersComponentInternal
internal fun register(checkers: ExpressionCheckers) {
fun register(checkers: ExpressionCheckers) {
_basicExpressionCheckers += checkers.basicExpressionCheckers
_qualifiedAccessCheckers += checkers.qualifiedAccessCheckers
_functionCallCheckers += checkers.functionCallCheckers
@@ -81,5 +87,7 @@ internal class ComposedExpressionCheckers : ExpressionCheckers() {
_equalityOperatorCallCheckers += checkers.equalityOperatorCallCheckers
_anonymousFunctionAsExpressionCheckers += checkers.anonymousFunctionAsExpressionCheckers
_stringConcatenationCallCheckers += checkers.stringConcatenationCallCheckers
_typeOperatorCallCheckers += checkers.typeOperatorCallCheckers
_resolvedQualifierCheckers += checkers.resolvedQualifierCheckers
}
}

View File

@@ -33,6 +33,8 @@ abstract class ExpressionCheckers {
open val equalityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> = emptySet()
open val anonymousFunctionAsExpressionCheckers: Set<FirAnonymousFunctionAsExpressionChecker> = emptySet()
open val stringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> = emptySet()
open val typeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> = emptySet()
open val resolvedQualifierCheckers: Set<FirResolvedQualifierChecker> = emptySet()
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> get() = basicExpressionCheckers
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> get() = qualifiedAccessCheckers + basicExpressionCheckers
@@ -50,4 +52,6 @@ abstract class ExpressionCheckers {
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> get() = equalityOperatorCallCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allAnonymousFunctionAsExpressionCheckers: Set<FirAnonymousFunctionAsExpressionChecker> get() = anonymousFunctionAsExpressionCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> get() = stringConcatenationCallCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> get() = typeOperatorCallCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allResolvedQualifierCheckers: Set<FirResolvedQualifierChecker> get() = resolvedQualifierCheckers + basicExpressionCheckers
}

View File

@@ -19,11 +19,13 @@ import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.FirStringConcatenationCall
import org.jetbrains.kotlin.fir.expressions.FirTryExpression
import org.jetbrains.kotlin.fir.expressions.FirTypeOperatorCall
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
@@ -43,3 +45,5 @@ typealias FirSafeCallExpressionChecker = FirExpressionChecker<FirSafeCallExpress
typealias FirEqualityOperatorCallChecker = FirExpressionChecker<FirEqualityOperatorCall>
typealias FirAnonymousFunctionAsExpressionChecker = FirExpressionChecker<FirAnonymousFunction>
typealias FirStringConcatenationCallChecker = FirExpressionChecker<FirStringConcatenationCall>
typealias FirTypeOperatorCallChecker = FirExpressionChecker<FirTypeOperatorCall>
typealias FirResolvedQualifierChecker = FirExpressionChecker<FirResolvedQualifier>

View File

@@ -12,14 +12,14 @@ import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
* DO NOT MODIFY IT MANUALLY
*/
internal class ComposedTypeCheckers : TypeCheckers() {
class ComposedTypeCheckers : TypeCheckers() {
override val typeRefCheckers: Set<FirTypeRefChecker>
get() = _typeRefCheckers
private val _typeRefCheckers: MutableSet<FirTypeRefChecker> = mutableSetOf()
@CheckersComponentInternal
internal fun register(checkers: TypeCheckers) {
fun register(checkers: TypeCheckers) {
_typeRefCheckers += checkers.typeRefCheckers
}
}

View File

@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotation
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
@@ -105,6 +106,9 @@ object FirErrors {
val MISSING_STDLIB_CLASS by error0<PsiElement>()
val NO_THIS by error0<PsiElement>()
// Call resolution
val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error0<KtExpression>()
// Super
val SUPER_IS_NOT_AN_EXPRESSION by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val SUPER_NOT_AVAILABLE by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
@@ -209,6 +213,7 @@ object FirErrors {
val TOO_MANY_ARGUMENTS by error1<PsiElement, FirCallableDeclaration<*>>()
val NO_VALUE_FOR_PARAMETER by error1<KtElement, FirValueParameter>(SourceElementPositioningStrategies.VALUE_ARGUMENTS)
val NAMED_PARAMETER_NOT_FOUND by error1<KtValueArgument, String>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
// Ambiguity
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -254,6 +259,8 @@ object FirErrors {
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<KtTypeParameter>()
val DYNAMIC_UPPER_BOUND by error0<KtTypeReference>()
val INCOMPATIBLE_TYPES by error2<KtElement, ConeKotlinType, ConeKotlinType>()
val INCOMPATIBLE_TYPES_WARNING by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
// Reflection
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<KtExpression, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -386,6 +393,10 @@ object FirErrors {
val USELESS_ELVIS by warning1<KtBinaryExpression, ConeKotlinType>(SourceElementPositioningStrategies.USELESS_ELVIS)
val USELESS_ELVIS_RIGHT_IS_NULL by warning0<KtBinaryExpression>(SourceElementPositioningStrategies.USELESS_ELVIS)
// Casts and is-checks
val USELESS_CAST by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.AS_TYPE)
val USELESS_IS_CHECK by warning1<KtElement, Boolean>()
// When expressions
val NO_ELSE_IN_WHEN by error1<KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
@@ -394,6 +405,8 @@ object FirErrors {
// Context tracking
val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
val TYPE_PARAMETER_ON_LHS_OF_DOT by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
val NO_COMPANION_OBJECT by error1<KtSimpleNameExpression, FirRegularClassSymbol>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
val EXPRESSION_EXPECTED_PACKAGE_FOUND by error0<KtSimpleNameExpression>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
// Function contracts
val ERROR_IN_CONTRACT_DESCRIPTION by error1<KtElement, String>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
@@ -409,6 +422,12 @@ object FirErrors {
val DELEGATE_SPECIAL_FUNCTION_MISSING by error3<KtExpression, String, ConeKotlinType, String>()
val DELEGATE_SPECIAL_FUNCTION_AMBIGUITY by error2<KtExpression, String, Collection<AbstractFirBasedSymbol<*>>>()
val DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE by error2<KtExpression, String, Collection<AbstractFirBasedSymbol<*>>>()
val DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH by error3<KtExpression, String, ConeKotlinType, ConeKotlinType>()
val UNDERSCORE_IS_RESERVED by error0<KtExpression>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error0<KtExpression>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
// Type alias
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
@@ -435,4 +454,15 @@ object FirErrors {
val RETURN_NOT_ALLOWED by error0<KtReturnExpression>(SourceElementPositioningStrategies.RETURN_WITH_LABEL)
val RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY by error0<KtReturnExpression>(SourceElementPositioningStrategies.RETURN_WITH_LABEL)
// Inline
val USAGE_IS_NOT_INLINABLE by error1<KtElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val NON_LOCAL_RETURN_NOT_ALLOWED by error1<KtElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val RECURSION_IN_INLINE by error1<KtElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE by error2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE by error2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR by error2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val PROTECTED_CALL_FROM_PUBLIC_INLINE by warning2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val PRIVATE_CLASS_MEMBER_FROM_INLINE by error2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val SUPER_CALL_FROM_PUBLIC_INLINE by warning1<KtElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
}

View File

@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.collectors.FirDiagnosticsCollector
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.ScopeSession
@@ -19,7 +20,7 @@ class FirCheckersResolveProcessor(
session: FirSession,
scopeSession: ScopeSession
) : FirTransformerBasedResolveProcessor(session, scopeSession) {
val diagnosticCollector = FirDiagnosticsCollector.create(session, scopeSession)
val diagnosticCollector: AbstractDiagnosticCollector = FirDiagnosticsCollector.create(session, scopeSession)
override val transformer: FirTransformer<Nothing?> = FirCheckersRunnerTransformer(diagnosticCollector)
}
@@ -30,7 +31,8 @@ class FirCheckersRunnerTransformer(private val diagnosticCollector: AbstractDiag
}
override fun transformFile(file: FirFile, data: Nothing?): FirDeclaration {
diagnosticCollector.collectDiagnostics(file)
val reporter = DiagnosticReporterFactory.createReporter()
diagnosticCollector.collectDiagnostics(file, reporter)
return file
}
}

View File

@@ -0,0 +1,468 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.isPrimitiveType
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.calls.fullyExpandedClass
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.Variance
/**
* Checks if a given collection of [ConeKotlinType] are compatible. In other words, the types are compatible if it's possible at all to
* define a type that's a subtype of all of the given types. The compatibility of a given set of types concept is closely related to whether
* the intersection of these types is inhabited. But it's not identical because 1) one can manually control visibility of constructors and
* 2) there can be unused type parameters.
*
* The compatibility check is done recursively on the given types and all type arguments passed to each corresponding type parameters. For
* example, consider the following two types:
*
* ```
* - ArrayList<Set<String>>
* - List<HashSet<Int>>
* ```
*
* The checker first checks the base types `ArrayList` and `List`, and it sees no issue since `ArrayList <: List`. Next it checks the type
* parameters bound to these base types: `T1` in `ArrayList<T1>` and `T2` in `List<T2>`. For `T1`, there is only one bound type argument
* `Set<String>`, so it's good. For `T2`, there are two bound type arguments: `Set<String>` and `HashSet<Int>`. Now the checker recursively
* checks whether these two types are compatible. Again, it first checks the base type `Set` and `HashSet`, and it finds no problem since
* `HashSet <: Set`. Finally, checks the type arguments `String` and `Int` that are bound to `T` in `Set<T>`. They are incompatible since
* `String` and `Int` are unrelated classes.
*
* The above example only goes over covariant type arguments. For contravariant types, the checker simply checks whether the range formed by
* covariant and contravariant bounds is empty. For example, a range like `[Collection, List]` is empty and hence invalid because `List` is
* not a super class/interface of `Collection`
*/
internal object ConeTypeCompatibilityChecker {
/**
* The result returned by [ConeTypeCompatibilityChecker]. Note the order of enum entries matters.
*/
enum class Compatibility : Comparable<Compatibility> {
/** The given types are fully compatible. */
COMPATIBLE,
/** The given types may not be compatible. But the compiler would allow such comparisons. */
SOFT_INCOMPATIBLE,
/**
* The given types are definitely incompatible. If the established contracts of Kotlin code are respected, values of the given
* types can never be considered equal.
*/
HARD_INCOMPATIBLE,
}
fun Collection<ConeKotlinType>.areCompatible(ctx: ConeInferenceContext): Compatibility {
// If all types are nullable, then `null` makes the given types compatible.
if (all { with(ctx) { it.isNullableType() } }) return Compatibility.COMPATIBLE
// Next can simply focus on the type hierarchy and don't need to worry about nullability.
val compatibilityUpperBound = when {
all {
it.classId in StandardClassIds.primitiveTypes
} -> Compatibility.SOFT_INCOMPATIBLE // TODO: remove after KT-46383 is fixed
all {
it.isConcreteType()
} -> Compatibility.HARD_INCOMPATIBLE
// If any type is not concrete, for example, type parameter, we only report warning for incompatible types.
// This is to stay compatible with FE1.0.
else -> Compatibility.SOFT_INCOMPATIBLE
}
return ctx.areCompatible(flatMap { it.collectUpperBounds() }.toSet(), emptySet(), compatibilityUpperBound)
}
private fun ConeKotlinType.isConcreteType(): Boolean {
return when (this) {
is ConeClassLikeType -> true
is ConeDefinitelyNotNullType -> original.isConcreteType()
is ConeIntersectionType -> intersectedTypes.all { it.isConcreteType() }
else -> false
}
}
/**
* @param compatibilityUpperBound the max compatibility result that can be returned by this method. For example, if this is set to
* [Compatibility.SOFT_INCOMPATIBLE], then even if the given bounds don't match the hard way (for example, incompatible primitives) the
* method should still return [Compatibility.SOFT_INCOMPATIBLE]. This is useful for checking type parameters since we don't want to
* dictate what semantics a type parameter may have in user code. In other words, if user wants to compare `MyCustom<out String>` with
* `MyCustom<out Int>`, we let them do so since we do not know what class `MyCustom` uses the type parameter for. Empty containers are
* another example: `emptyList<Int>() == emptyList<String>()`.
*/
private fun ConeInferenceContext.areCompatible(
upperBounds: Set<ConeClassLikeType>,
lowerBounds: Set<ConeClassLikeType>,
compatibilityUpperBound: Compatibility,
checkedTypeParameters: MutableSet<FirTypeParameterRef> = mutableSetOf(),
): Compatibility {
val upperBoundClasses: Set<FirClassWithSuperClasses> = upperBounds.mapNotNull { it.toFirClassWithSuperClasses(this) }.toSet()
// Following if condition is an optimization: if we ignore the subtyping relation and treat all upper bounds as unrelated
// classes/interfaces, yet the types are deemed compatible for sure, then we just bail out early.
if (lowerBounds.isEmpty() &&
(upperBounds.size < 2 ||
this.areClassesOrInterfacesCompatible(upperBoundClasses, compatibilityUpperBound) == Compatibility.COMPATIBLE)
) {
return Compatibility.COMPATIBLE
}
val leafClassesOrInterfaces = computeLeafClassesOrInterfaces(upperBoundClasses)
this.areClassesOrInterfacesCompatible(leafClassesOrInterfaces, compatibilityUpperBound)?.let { return it }
// Check if the range formed by upper bounds and lower bounds is empty.
if (!lowerBounds.all { lowerBoundType ->
val classesSatisfyingLowerBounds =
lowerBoundType.toFirClassWithSuperClasses(this)?.thisAndAllSuperClasses ?: emptySet()
leafClassesOrInterfaces.all { it in classesSatisfyingLowerBounds }
}
) {
return compatibilityUpperBound
}
if (upperBounds.size < 2) return Compatibility.COMPATIBLE
// Base types are compatible. Now we check type parameters.
val typeArgumentMapping = mutableMapOf<FirTypeParameterRef, BoundTypeArguments>().apply {
for (type in upperBounds) {
collectTypeArgumentMapping(type, this@areCompatible, compatibilityUpperBound)
}
}
var result = Compatibility.COMPATIBLE
val typeArgsCompatibility = typeArgumentMapping.asSequence()
.map { (paramRef, boundTypeArguments) ->
val (upper, lower, compatibility) = boundTypeArguments
if (paramRef in checkedTypeParameters) {
// if we are already checking this type parameter, simply bail out to prevent infinite recursion.
Compatibility.COMPATIBLE
} else {
checkedTypeParameters.add(paramRef)
areCompatible(upper, lower, compatibility, checkedTypeParameters)
}
}
for (compatibility in typeArgsCompatibility) {
if (compatibility == compatibilityUpperBound) return compatibility
if (compatibility > result) {
result = compatibility
}
}
return result
}
/**
* Puts the upper bound classes into the class hierarchy and count hows many subclasses are there for each encountered class. Then
* output a list of leaf classes or interfaces in the class hierarchy.
*/
private fun computeLeafClassesOrInterfaces(upperBoundClasses: Set<FirClassWithSuperClasses>): Set<FirClassWithSuperClasses> {
val isLeaf = mutableMapOf<FirClassWithSuperClasses, Boolean>()
upperBoundClasses.associateWithTo(isLeaf) { true } // implementation of keysToMap actually ends up creating 2 maps so this is better
val queue = ArrayDeque(upperBoundClasses)
while (queue.isNotEmpty()) {
for (superClass in queue.removeFirst().superClasses) {
when (isLeaf[superClass]) {
true -> isLeaf[superClass] = false
false -> {
// nothing to be done since this super class has already been handled.
}
else -> {
isLeaf[superClass] = false
queue.addLast(superClass)
}
}
}
}
return isLeaf.filterValues { it }.keys
}
/**
* Checks whether the given classes are compatible. In other words, check if it's possible for objects of the given classes to be
* considered equal by [Any.equals].
*
* @return null if this check is inconclusive
*/
private fun ConeInferenceContext.areClassesOrInterfacesCompatible(
classesOrInterfaces: Collection<FirClassWithSuperClasses>,
compatibilityUpperBound: Compatibility
): Compatibility? {
val classes = classesOrInterfaces.filter { !it.isInterface }
// Java force single inheritance, so any pair of unrelated classes are incompatible.
if (classes.size >= 2) {
return if (classes.any { it.getHasPredefinedEqualityContract(this) }) {
compatibilityUpperBound
} else {
Compatibility.SOFT_INCOMPATIBLE
}
}
val finalClass = classes.firstOrNull { it.isFinal } ?: return null
// One final class and some other unrelated interface are not compatible
if (classesOrInterfaces.size > classes.size) {
return if (finalClass.getHasPredefinedEqualityContract(this)) {
compatibilityUpperBound
} else {
Compatibility.SOFT_INCOMPATIBLE
}
}
return null
}
/**
* Collects the upper bounds as [ConeClassLikeType].
*/
private fun ConeKotlinType?.collectUpperBounds(): Set<ConeClassLikeType> {
if (this == null) return emptySet()
return when (this) {
is ConeClassErrorType -> emptySet() // Ignore error types
is ConeLookupTagBasedType -> when (this) {
is ConeClassLikeType -> setOf(this)
is ConeTypeVariableType -> when (val tag = lookupTag) {
is ConeTypeVariableTypeConstructor -> (tag.originalTypeParameter as? ConeTypeParameterLookupTag)?.typeParameterSymbol.collectUpperBounds()
else -> throw IllegalStateException("missing branch for ${lookupTag.javaClass.name}")
}
is ConeTypeParameterType -> lookupTag.typeParameterSymbol.collectUpperBounds()
else -> throw IllegalStateException("missing branch for ${javaClass.name}")
}
is ConeDefinitelyNotNullType -> original.collectUpperBounds()
is ConeIntersectionType -> intersectedTypes.flatMap { it.collectUpperBounds() }.toSet()
is ConeFlexibleType -> upperBound.collectUpperBounds()
is ConeCapturedType, is ConeStubType, is ConeIntegerLiteralType -> throw IllegalStateException("$this should not reach here")
}
}
private fun FirTypeParameterSymbol?.collectUpperBounds(): Set<ConeClassLikeType> {
if (this == null) return emptySet()
return fir.bounds.flatMap { it.coneTypeSafe<ConeKotlinType>().collectUpperBounds() }.toSet()
}
private fun ConeKotlinType?.collectLowerBounds(): Set<ConeClassLikeType> {
if (this == null) return emptySet()
return when (this) {
is ConeClassErrorType -> emptySet() // Ignore error types
is ConeLookupTagBasedType -> when (this) {
is ConeClassLikeType -> setOf(this)
is ConeTypeVariableType -> emptySet()
is ConeTypeParameterType -> emptySet()
else -> throw IllegalStateException("missing branch for ${javaClass.name}")
}
is ConeDefinitelyNotNullType -> original.collectLowerBounds()
is ConeIntersectionType -> intersectedTypes.flatMap { it.collectLowerBounds() }.toSet()
is ConeFlexibleType -> lowerBound.collectLowerBounds()
is ConeCapturedType, is ConeStubType, is ConeIntegerLiteralType -> throw IllegalStateException("$this should not reach here")
}
}
/**
* For each type parameters appeared in the class hierarchy, collect all type arguments that eventually mapped to it. For example,
* given type `List<String>`, the returned map contains
*
* - type parameter of `List` -> upper:[`String`], lower:[]
* - type parameter of `Collection` -> upper:[`String`], lower:[]
* - type parameter of `Iterable` -> upper:[`String`], lower:[]
*
* If later `Collection<Int>` is passed to this method with the same receiver map, the receiver map would become:
*
* - type parameter of `List` -> upper:[`String`], lower:[]
* - type parameter of `Collection` -> upper:[`String`, `Int`], lower:[]
* - type parameter of `Iterable` -> upper:[`String`, `Int`], lower:[]
*/
private fun MutableMap<FirTypeParameterRef, BoundTypeArguments>.collectTypeArgumentMapping(
coneType: ConeClassLikeType,
ctx: ConeInferenceContext,
compatibilityUpperBound: Compatibility
) {
val queue = ArrayDeque<TypeArgumentMapping>()
queue.addLast(coneType.toTypeArgumentMapping(ctx) ?: return)
while (queue.isNotEmpty()) {
val (typeParameterOwner, mapping) = queue.removeFirst()
val superTypes = typeParameterOwner.getSuperTypes()
for (superType in superTypes) {
queue.addLast(superType.toTypeArgumentMapping(ctx, mapping) ?: continue)
}
for ((firTypeParameterRef, boundTypeArgument) in mapping) {
this.collect(ctx, typeParameterOwner, firTypeParameterRef, boundTypeArgument, compatibilityUpperBound)
}
}
}
/** Converts type arguments in a [ConeClassLikeType] to a [TypeArgumentMapping]. */
@OptIn(ExperimentalStdlibApi::class)
private fun ConeClassLikeType.toTypeArgumentMapping(
ctx: ConeInferenceContext,
envMapping: Map<FirTypeParameterRef, BoundTypeArgument> = emptyMap(),
): TypeArgumentMapping? {
val typeParameterOwner = getClassLikeElement(ctx) ?: return null
val mapping = buildMap<FirTypeParameterRef, BoundTypeArgument> {
typeArguments.forEachIndexed { index, coneTypeProjection ->
val typeParameter: FirTypeParameterRef = typeParameterOwner.getTypeParameter(index) ?: return@forEachIndexed
var boundTypeArgument: BoundTypeArgument = when (coneTypeProjection) {
// Ignore star since it doesn't provide any constraints.
ConeStarProjection -> return@forEachIndexed
// Ignore contravariant projection because they induces union types. Hence, whatever type argument should always be
// considered compatible.
is ConeKotlinTypeProjectionIn -> BoundTypeArgument(coneTypeProjection.type, Variance.IN_VARIANCE)
is ConeKotlinTypeProjectionOut -> BoundTypeArgument(coneTypeProjection.type, Variance.OUT_VARIANCE)
is ConeKotlinType ->
when ((typeParameter as? FirTypeParameter)?.variance) {
Variance.IN_VARIANCE -> BoundTypeArgument(coneTypeProjection.type, Variance.IN_VARIANCE)
Variance.OUT_VARIANCE -> BoundTypeArgument(coneTypeProjection.type, Variance.OUT_VARIANCE)
else -> BoundTypeArgument(coneTypeProjection.type, Variance.INVARIANT)
}
}
val coneKotlinType = boundTypeArgument.type
if (coneKotlinType is ConeTypeParameterType) {
val envTypeParameter = coneKotlinType.lookupTag.typeParameterSymbol.fir
val envTypeArgument = envMapping[envTypeParameter]
if (envTypeArgument != null) {
boundTypeArgument = envTypeArgument
}
}
put(typeParameter, boundTypeArgument)
}
}
return TypeArgumentMapping(typeParameterOwner, mapping)
}
private fun MutableMap<FirTypeParameterRef, BoundTypeArguments>.collect(
ctx: ConeInferenceContext,
typeParameterOwner: FirClassLikeDeclaration<*>,
parameter: FirTypeParameterRef,
boundTypeArgument: BoundTypeArgument,
compatibilityUpperBound: Compatibility,
) {
computeIfAbsent(parameter) {
// the semantic of type parameter in Enum and KClass are fixed: values of types with incompatible type parameters are always
// incompatible.
val compatibilityUpperBoundForTypeArg =
if ((ctx.prohibitComparisonOfIncompatibleEnums && typeParameterOwner.symbol.classId == StandardClassIds.Enum) ||
(ctx.prohibitComparisonOfIncompatibleClasses && typeParameterOwner.symbol.classId == StandardClassIds.KClass)
) {
compatibilityUpperBound
} else {
Compatibility.SOFT_INCOMPATIBLE
}
BoundTypeArguments(mutableSetOf(), mutableSetOf(), compatibilityUpperBoundForTypeArg)
}.let {
val type = boundTypeArgument.type
if (boundTypeArgument.variance.allowsInPosition) {
it.lower += type.collectLowerBounds()
}
if (boundTypeArgument.variance.allowsOutPosition) {
it.upper += type.collectUpperBounds()
}
}
}
private fun FirClassLikeDeclaration<*>.getSuperTypes(): List<ConeClassLikeType> {
return when (this) {
is FirTypeAlias -> listOfNotNull(expandedTypeRef.coneTypeSafe())
is FirClass<*> -> superTypeRefs.mapNotNull { it.coneTypeSafe() }
else -> emptyList()
}
}
private fun ConeClassLikeType.getClassLikeElement(ctx: ConeInferenceContext): FirClassLikeDeclaration<*>? =
ctx.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir
private fun FirClassLikeDeclaration<*>.getTypeParameter(index: Int): FirTypeParameterRef? {
return when (this) {
is FirTypeAlias -> typeParameters[index]
is FirClass<*> -> typeParameters[index]
else -> return null
}
}
/** A class declaration and the arguments bound to the declared type parameters. */
private data class TypeArgumentMapping(
val typeParameterOwner: FirClassLikeDeclaration<*>,
val mapping: Map<FirTypeParameterRef, BoundTypeArgument>
)
/** A single bound type argument to a type parameter declared in a class. */
private data class BoundTypeArgument(val type: ConeKotlinType, val variance: Variance)
/** Accumulated type arguments bound to a type parameter declared in a class. */
private data class BoundTypeArguments(
val upper: MutableSet<ConeClassLikeType>,
val lower: MutableSet<ConeClassLikeType>,
val compatibilityUpperBound: Compatibility
)
private fun ConeClassLikeType.toFirClassWithSuperClasses(ctx: ConeInferenceContext): FirClassWithSuperClasses? {
return lookupTag.toFirClassWithSuperClasses(ctx)
}
private fun ConeClassLikeLookupTag.toFirClassWithSuperClasses(
ctx: ConeInferenceContext
): FirClassWithSuperClasses? = when (val klass = ctx.symbolProvider.getSymbolByLookupTag(this)?.fir) {
is FirTypeAlias -> klass.fullyExpandedClass(ctx.session)?.let { FirClassWithSuperClasses(it, ctx) }
is FirClass<*> -> FirClassWithSuperClasses(klass, ctx)
else -> null
}
private data class FirClassWithSuperClasses(val firClass: FirClass<*>, val ctx: ConeInferenceContext) {
val isInterface: Boolean get() = firClass.isInterface
val superClasses: Set<FirClassWithSuperClasses> by lazy {
firClass.superConeTypes.mapNotNull { it.lookupTag.toFirClassWithSuperClasses(ctx) }.toSet()
}
@OptIn(ExperimentalStdlibApi::class)
val thisAndAllSuperClasses: Set<FirClassWithSuperClasses> by lazy {
val queue = ArrayDeque<FirClassWithSuperClasses>()
queue.addLast(this)
buildSet {
add(this@FirClassWithSuperClasses)
while (queue.isNotEmpty()) {
val current = queue.removeFirst()
val superTypes = current.superClasses
superTypes.filterNotTo(queue) { it in this@buildSet }
addAll(superTypes)
}
}
}
val isFinal: Boolean get() = firClass.isFinal
/**
* The following are considered to have a predefined equality contract:
* - enums
* - primitives (including unsigned integer types)
* - classes
* - strings
* - objects of data classes
* - objects of inline classes
* - kotlin.Unit
*/
fun getHasPredefinedEqualityContract(ctx: ConeInferenceContext): Boolean {
return (ctx.prohibitComparisonOfIncompatibleEnums && (firClass.isEnumClass || firClass.classId == StandardClassIds.Enum)) ||
firClass.isPrimitiveType() ||
(ctx.prohibitComparisonOfIncompatibleClasses && firClass.classId == StandardClassIds.KClass) ||
firClass.classId == StandardClassIds.String || firClass.classId == StandardClassIds.Unit ||
(firClass is FirRegularClass && (firClass.isData || firClass.isInline))
}
private val FirClass<*>.isFinal: Boolean
get() {
return when (this) {
is FirAnonymousObject -> true
is FirRegularClass -> status.modality == Modality.FINAL
else -> throw java.lang.IllegalStateException("unknown type of FirClass $this")
}
}
}
private val ConeInferenceContext.prohibitComparisonOfIncompatibleEnums: Boolean
get() = session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitComparisonOfIncompatibleEnums)
private val ConeInferenceContext.prohibitComparisonOfIncompatibleClasses: Boolean
get() = session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitComparisonOfIncompatibleClasses)
}

View File

@@ -9,12 +9,14 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.*
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.analysis.getChild
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirComponentCall
import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -34,6 +36,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
@@ -88,6 +91,14 @@ fun FirClass<*>.isSupertypeOf(other: FirClass<*>, session: FirSession): Boolean
return isSupertypeOf(other, mutableSetOf())
}
/**
* Returns the FirClass associated with this
* or null of something goes wrong.
*/
fun ConeClassLikeType.toClass(session: FirSession): FirClass<*>? {
return lookupTag.toSymbol(session).safeAs<FirClassSymbol<*>>()?.fir
}
/**
* Returns the FirRegularClass associated with this
* or null of something goes wrong.

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.getAncestors
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
import org.jetbrains.kotlin.psi.KtTypeReference
/**
* Service to answer source-related questions in generic fashion.
* Shouldn't expose (receive or return) any specific source tree types
*/
interface SourceNavigator {
fun FirTypeRef.isInConstructorCallee(): Boolean
fun FirTypeRef.isInTypeConstraint(): Boolean
companion object {
private val lightTreeInstance = LightTreeSourceNavigator()
fun forElement(e: FirElement): SourceNavigator = when (e.source) {
is FirLightSourceElement -> lightTreeInstance
is FirPsiSourceElement<*> -> PsiSourceNavigator
null -> lightTreeInstance //shouldn't matter
}
inline fun <R> FirElement.withNavigator(block: SourceNavigator.() -> R): R = with(forElement(this), block)
}
}
open class LightTreeSourceNavigator : SourceNavigator {
private fun <T> FirElement.withSource(f: (FirSourceElement) -> T): T? =
source?.let { f(it) }
override fun FirTypeRef.isInConstructorCallee(): Boolean = withSource { source ->
source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE
} ?: false
override fun FirTypeRef.isInTypeConstraint(): Boolean {
val source = source ?: return false
return source.treeStructure.getAncestors(source.lighterASTNode)
.find { it.tokenType == KtNodeTypes.TYPE_CONSTRAINT || it.tokenType == KtNodeTypes.TYPE_PARAMETER }
?.tokenType == KtNodeTypes.TYPE_CONSTRAINT
}
}
//by default psi tree can reuse light tree manipulations
object PsiSourceNavigator : LightTreeSourceNavigator() {
//Swallows incorrect casts!!!
private inline fun <reified P : PsiElement> FirElement.psi(): P? {
val psi = (source as? FirPsiSourceElement<*>)?.psi
return psi as? P
}
override fun FirTypeRef.isInConstructorCallee(): Boolean = psi<KtTypeReference>()?.parent is KtConstructorCalleeExpression
}

View File

@@ -186,7 +186,8 @@ internal val FirDeclaration.isEnumEntryInitializer: Boolean
return (containingClassAttr as? ConeClassLookupTagWithFixedSymbol)?.symbol?.fir?.classKind == ClassKind.ENUM_ENTRY
}
internal val FirMemberDeclaration.isLocalMember: Boolean
// contract: returns(true) implies (this is FirMemberDeclaration)
internal val FirDeclaration.isLocalMember: Boolean
get() = when (this) {
is FirProperty -> this.isLocal
is FirRegularClass -> this.isLocal

View File

@@ -21,18 +21,23 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.render
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.AbstractTypeChecker
object FirDelegatedPropertyChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
val delegate = declaration.delegate ?: return
val delegateType = delegate.typeRef.coneType
// TODO: Also suppress delegate issue if type inference failed. For example, in
// compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.fir.kt, no delegate issues are
// reported due to the inference issue.
if (delegateType is ConeKotlinErrorType) {
val delegateSource = delegate.source
// Implicit recursion type is not reported since the type ref does not have a real source.
@@ -47,8 +52,13 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
override fun visitElement(element: FirElement) = element.acceptChildren(this)
override fun visitFunctionCall(functionCall: FirFunctionCall) {
val errorNamedReference = functionCall.calleeReference as? FirErrorNamedReference ?: return
if (errorNamedReference.source?.kind != FirFakeSourceElementKind.DelegatedPropertyAccessor) return
val hasReferenceError = hasFunctionReferenceErrors(functionCall)
if (isGet && !hasReferenceError) checkReturnType(functionCall)
}
private fun hasFunctionReferenceErrors(functionCall: FirFunctionCall): Boolean {
val errorNamedReference = functionCall.calleeReference as? FirErrorNamedReference ?: return false
if (errorNamedReference.source?.kind != FirFakeSourceElementKind.DelegatedPropertyAccessor) return false
val expectedFunctionSignature =
(if (isGet) "getValue" else "setValue") + "(${functionCall.arguments.joinToString(", ") { it.typeRef.coneType.render() }})"
val delegateDescription = if (isGet) "delegate" else "delegate for var (read-write property)"
@@ -77,7 +87,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
}
}
when (val diagnostic = errorNamedReference.diagnostic) {
return when (val diagnostic = errorNamedReference.diagnostic) {
is ConeUnresolvedNameError -> {
reporter.reportOn(
errorNamedReference.source,
@@ -87,6 +97,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
delegateDescription,
context
)
true
}
is ConeAmbiguityError -> {
if (diagnostic.applicability.isSuccess) {
@@ -101,10 +112,28 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
} else {
reportInapplicableDiagnostics(diagnostic.applicability, diagnostic.candidates.map { it.symbol })
}
true
}
is ConeInapplicableCandidateError -> {
reportInapplicableDiagnostics(diagnostic.applicability, listOf(diagnostic.candidate.symbol))
true
}
else -> false
}
}
private fun checkReturnType(functionCall: FirFunctionCall) {
val returnType = functionCall.typeRef.coneType
val propertyType = declaration.returnTypeRef.coneType
if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, returnType, propertyType)) {
reporter.reportOn(
delegate.source,
FirErrors.DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH,
"getValue",
propertyType,
returnType,
context
)
}
}
}

View File

@@ -1,29 +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.declaration
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isInterface
object FirDelegationInInterfaceChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isInterface) {
return
}
for (superTypeRef in declaration.superTypeRefs) {
val source = superTypeRef.source ?: continue
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.DELEGATED_SUPER_TYPE_ENTRY) {
reporter.reportOn(source, FirErrors.DELEGATION_IN_INTERFACE, context)
}
}
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.toFirLightSourceElement
object FirFunctionTypeParametersChecker : FirSimpleFunctionChecker() {
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
declaration.source?.let { source ->
if (source.kind is FirFakeSourceElementKind) return
val typeParamsNode = source.treeStructure.typeParametersList(source.lighterASTNode)
val nameNode = source.treeStructure.nameIdentifier(source.lighterASTNode)
if (typeParamsNode != null && nameNode != null && typeParamsNode.startOffset > nameNode.startOffset) {
reporter.reportOn(
source,
FirErrors.DEPRECATED_TYPE_PARAMETER_SYNTAX,
context
)
}
}
}
}

View File

@@ -0,0 +1,312 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.util.checkChildrenWithCustomVisitor
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.resolve.inference.isFunctionalType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.publishedApiEffectiveVisibility
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isMarkedNullable
import org.jetbrains.kotlin.fir.types.toSymbol
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.util.OperatorNameConventions
object FirInlineDeclarationChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isInline) return
// local inline functions are prohibited
if (declaration.isLocalMember) return
if (declaration !is FirPropertyAccessor && declaration !is FirSimpleFunction) return
val effectiveVisibility = declaration.effectiveVisibility
val function = declaration as FirFunction<*>
checkInlineFunctionBody(function, effectiveVisibility, context, reporter)
}
private fun checkInlineFunctionBody(
function: FirFunction<*>,
effectiveVisibility: EffectiveVisibility,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val body = function.body ?: return
val inlinableParameters = function.valueParameters.filter {
if (it.isNoinline) return@filter false
val type = it.returnTypeRef.coneType
!type.isMarkedNullable && type.isFunctionalType(context.session) { kind -> !kind.isReflectType }
}
val visitor = Visitor(
function,
effectiveVisibility,
inlinableParameters,
context.session,
reporter
)
body.checkChildrenWithCustomVisitor(context, visitor)
}
private class Visitor(
val inlineFunction: FirFunction<*>,
val inlineFunEffectiveVisibility: EffectiveVisibility,
val inlinableParameters: List<FirValueParameter>,
val session: FirSession,
val reporter: DiagnosticReporter
) : FirDefaultVisitor<Unit, CheckerContext>() {
private val isEffectivelyPrivateApiFunction: Boolean = inlineFunEffectiveVisibility.privateApi
private val prohibitProtectedCallFromInline: Boolean =
session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitProtectedCallFromInline)
override fun visitElement(element: FirElement, data: CheckerContext) {}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: CheckerContext) {
val targetSymbol = functionCall.toResolvedCallableSymbol()
checkReceiversOfQualifiedAccessExpression(functionCall, targetSymbol, data)
checkArgumentsOfCall(functionCall, targetSymbol, data)
checkQualifiedAccess(functionCall, targetSymbol, data)
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: CheckerContext) {
val targetSymbol = qualifiedAccessExpression.toResolvedCallableSymbol()
checkQualifiedAccess(qualifiedAccessExpression, targetSymbol, data)
checkReceiversOfQualifiedAccessExpression(qualifiedAccessExpression, targetSymbol, data)
}
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: CheckerContext) {
val propertySymbol = variableAssignment.calleeReference.toResolvedCallableSymbol() as? FirPropertySymbol ?: return
val setterSymbol = propertySymbol.fir.setter?.symbol ?: return
checkQualifiedAccess(variableAssignment, setterSymbol, data)
}
private fun checkReceiversOfQualifiedAccessExpression(
qualifiedAccessExpression: FirQualifiedAccessExpression,
targetSymbol: AbstractFirBasedSymbol<*>?,
context: CheckerContext
) {
checkReceiver(qualifiedAccessExpression, qualifiedAccessExpression.dispatchReceiver, targetSymbol, context)
checkReceiver(qualifiedAccessExpression, qualifiedAccessExpression.extensionReceiver, targetSymbol, context)
}
private fun checkArgumentsOfCall(
functionCall: FirFunctionCall,
targetSymbol: AbstractFirBasedSymbol<*>?,
context: CheckerContext
) {
val calledFunction = (targetSymbol as? FirNamedFunctionSymbol)?.fir ?: return
val argumentMapping = functionCall.resolvedArgumentMapping ?: return
for ((wrappedArgument, valueParameter) in argumentMapping) {
val argument = wrappedArgument.unwrapArgument()
val resolvedArgumentSymbol = argument.toResolvedCallableSymbol() as? FirVariableSymbol<*> ?: continue
val valueParameterOfOriginalInlineFunction = inlinableParameters.firstOrNull { it == resolvedArgumentSymbol.fir }
if (valueParameterOfOriginalInlineFunction != null) {
val factory = when {
calledFunction.isInline -> when {
valueParameter.isNoinline -> FirErrors.USAGE_IS_NOT_INLINABLE
valueParameter.isCrossinline && !valueParameterOfOriginalInlineFunction.isCrossinline
-> FirErrors.NON_LOCAL_RETURN_NOT_ALLOWED
else -> continue
}
else -> FirErrors.USAGE_IS_NOT_INLINABLE
}
reporter.reportOn(argument.source, factory, valueParameterOfOriginalInlineFunction.symbol, context)
}
}
}
private fun checkReceiver(
qualifiedAccessExpression: FirQualifiedAccessExpression,
receiverExpression: FirExpression,
targetSymbol: AbstractFirBasedSymbol<*>?,
context: CheckerContext
) {
val receiverSymbol = receiverExpression.toResolvedCallableSymbol() ?: return
if (receiverSymbol.fir in inlinableParameters) {
val valueParameter = receiverSymbol.fir as FirValueParameter
if (!isInvokeOrInlineExtension(targetSymbol)) {
reporter.reportOn(
qualifiedAccessExpression.source,
FirErrors.USAGE_IS_NOT_INLINABLE,
valueParameter.symbol,
context
)
}
}
}
private fun isInvokeOrInlineExtension(targetSymbol: AbstractFirBasedSymbol<*>?): Boolean {
if (targetSymbol !is FirNamedFunctionSymbol) return false
val function = targetSymbol.fir
if (function.isInline) return true
return function.name == OperatorNameConventions.INVOKE &&
function.dispatchReceiverType?.isBuiltinFunctionalType(session) == true
}
private fun checkQualifiedAccess(
qualifiedAccess: FirQualifiedAccess,
targetSymbol: AbstractFirBasedSymbol<*>?,
context: CheckerContext
) {
val source = qualifiedAccess.source ?: return
if (targetSymbol == null) return
val targetFir = targetSymbol.fir as? FirCallableMemberDeclaration<*>
if (targetSymbol.fir in inlinableParameters) {
if (!qualifiedAccess.partOfCall(context)) {
val valueParameter = targetSymbol.fir as FirValueParameter
reporter.reportOn(source, FirErrors.USAGE_IS_NOT_INLINABLE, valueParameter.symbol, context)
}
}
checkVisibilityAndAccess(qualifiedAccess, targetFir, source, context)
checkRecursion(targetSymbol, source, context)
}
private fun FirQualifiedAccess.partOfCall(context: CheckerContext): Boolean {
if (this !is FirExpression) return false
val containingQualifiedAccess = context.qualifiedAccesses.getOrNull(context.qualifiedAccesses.size - 2) ?: return false
if (this == containingQualifiedAccess.explicitReceiver) return true
val call = containingQualifiedAccess as? FirCall ?: return false
return call.arguments.any { it.unwrapArgument() == this }
}
private fun checkVisibilityAndAccess(
accessExpression: FirQualifiedAccess,
calledDeclaration: FirCallableMemberDeclaration<*>?,
source: FirSourceElement,
context: CheckerContext
) {
if (calledDeclaration == null) return
val recordedEffectiveVisibility = calledDeclaration.publishedApiEffectiveVisibility ?: calledDeclaration.effectiveVisibility
val calledFunEffectiveVisibility = recordedEffectiveVisibility.let {
if (it == EffectiveVisibility.Local) {
EffectiveVisibility.Public
} else {
it
}
}
val isCalledFunPublicOrPublishedApi = calledFunEffectiveVisibility.publicApi
val isInlineFunPublicOrPublishedApi = inlineFunEffectiveVisibility.publicApi
if (isInlineFunPublicOrPublishedApi &&
!isCalledFunPublicOrPublishedApi &&
calledDeclaration.visibility !== Visibilities.Local
) {
reporter.reportOn(
source,
FirErrors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE,
calledDeclaration.symbol,
inlineFunction.symbol,
context
)
} else {
checkPrivateClassMemberAccess(calledDeclaration, source, context)
if (isInlineFunPublicOrPublishedApi) {
checkSuperCalls(calledDeclaration, accessExpression, context)
}
}
val isConstructorCall = calledDeclaration is FirConstructor
if (
isInlineFunPublicOrPublishedApi &&
inlineFunEffectiveVisibility.toVisibility() !== Visibilities.Protected &&
calledFunEffectiveVisibility.toVisibility() === Visibilities.Protected
) {
val factory = when {
isConstructorCall -> FirErrors.PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE
prohibitProtectedCallFromInline -> FirErrors.PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR
else -> FirErrors.PROTECTED_CALL_FROM_PUBLIC_INLINE
}
reporter.reportOn(source, factory, calledDeclaration.symbol, inlineFunction.symbol, context)
}
}
private fun checkPrivateClassMemberAccess(
calledDeclaration: FirCallableMemberDeclaration<*>,
source: FirSourceElement,
context: CheckerContext
) {
if (!isEffectivelyPrivateApiFunction) {
if (calledDeclaration.isInsidePrivateClass()) {
reporter.reportOn(
source,
FirErrors.PRIVATE_CLASS_MEMBER_FROM_INLINE,
calledDeclaration.symbol,
inlineFunction.symbol,
context
)
}
}
}
private fun checkSuperCalls(
calledDeclaration: FirCallableMemberDeclaration<*>,
callExpression: FirQualifiedAccess,
context: CheckerContext
) {
val receiver = callExpression.dispatchReceiver as? FirQualifiedAccessExpression ?: return
if (receiver.calleeReference is FirSuperReference) {
val dispatchReceiverType = receiver.dispatchReceiver.typeRef.coneType
val classSymbol = dispatchReceiverType.toSymbol(session) ?: return
if (!classSymbol.isDefinedInInlineFunction()) {
reporter.reportOn(
callExpression.dispatchReceiver.source,
FirErrors.SUPER_CALL_FROM_PUBLIC_INLINE,
calledDeclaration.symbol,
context
)
}
}
}
private fun AbstractFirBasedSymbol<*>.isDefinedInInlineFunction(): Boolean {
return when (val fir = this.fir) {
is FirAnonymousFunction -> true
is FirMemberDeclaration -> fir.isLocalMember
is FirAnonymousObject -> true
is FirRegularClass -> fir.classId.isLocal
else -> error("Unknown callable declaration type: ${fir.render()}")
}
}
private fun checkRecursion(
targetSymbol: AbstractFirBasedSymbol<*>,
source: FirSourceElement,
context: CheckerContext
) {
if (targetSymbol == inlineFunction.symbol) {
reporter.reportOn(source, FirErrors.RECURSION_IN_INLINE, targetSymbol, context)
}
}
private fun FirCallableMemberDeclaration<*>.isInsidePrivateClass(): Boolean {
val containingClass = this.containingClass()?.toSymbol(session)?.fir ?: return false
val containingClassVisibility = when (containingClass) {
is FirAnonymousObject -> return false
is FirRegularClass -> containingClass.visibility
is FirTypeAlias -> containingClass.visibility
}
return containingClassVisibility == Visibilities.Private || containingClassVisibility == Visibilities.PrivateToThis
}
}
}

View File

@@ -63,11 +63,58 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
return false
}
fun FirIntersectionCallableSymbol.subjectToManyNotImplemented(): Boolean {
var nonAbstractCountInClass = 0
var nonAbstractCountInInterface = 0
var abstractCountInInterface = 0
for (intersectionSymbol in intersections) {
val intersection = intersectionSymbol.fir as FirCallableMemberDeclaration
val containingClass = intersection.getContainingClass(context) as? FirRegularClass
val hasInterfaceContainer = containingClass?.classKind == ClassKind.INTERFACE
if (intersection.modality != Modality.ABSTRACT) {
if (hasInterfaceContainer) {
nonAbstractCountInInterface++
} else {
nonAbstractCountInClass++
}
} else if (hasInterfaceContainer) {
abstractCountInInterface++
}
if (nonAbstractCountInClass + nonAbstractCountInInterface > 1) {
return true
}
if (nonAbstractCountInInterface > 0 && abstractCountInInterface > 0) {
return true
}
}
return false
}
fun FirIntersectionCallableSymbol.shouldBeImplemented(): Boolean {
// In Java 8, non-abstract intersection overrides having abstract symbol from base class
// still should be implemented in current class (even when they have default interface implementation)
if (intersections.none {
val fir = (it.fir as FirCallableMemberDeclaration).unwrapFakeOverrides()
fir.isAbstract && (fir.getContainingClass(context) as? FirRegularClass)?.classKind == ClassKind.CLASS
}
) return false
// Exception from the rule above: interface implementation via delegation
if (intersections.any {
val fir = (it.fir as FirCallableMemberDeclaration)
fir.origin == FirDeclarationOrigin.Delegated && !fir.isAbstract
}
) return false
return true
}
fun FirCallableMemberDeclaration<*>.shouldBeImplemented(): Boolean {
if (!isAbstract) return false
val containingClass = getContainingClass(context)
if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false
if (containingClass is FirRegularClass && containingClass.isExpect) return false
if (!isAbstract) {
val symbol = symbol as? FirIntersectionCallableSymbol ?: return false
return symbol.shouldBeImplemented()
}
if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false
return true
}
@@ -75,9 +122,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
classScope.processFunctionsByName(name) { namedFunctionSymbol ->
val simpleFunction = namedFunctionSymbol.fir
if (namedFunctionSymbol is FirIntersectionOverrideFunctionSymbol) {
if (namedFunctionSymbol.intersections.count {
(it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT
} > 1 && simpleFunction.getContainingClass(context) === declaration
if (simpleFunction.getContainingClass(context) === declaration &&
namedFunctionSymbol.subjectToManyNotImplemented()
) {
notImplementedIntersectionSymbols += namedFunctionSymbol
return@processFunctionsByName
@@ -99,9 +145,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
classScope.processPropertiesByName(name) { propertySymbol ->
val property = propertySymbol.fir as? FirProperty ?: return@processPropertiesByName
if (propertySymbol is FirIntersectionOverridePropertySymbol) {
if (propertySymbol.intersections.count {
(it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT
} > 1 && property.getContainingClass(context) === declaration
if (property.getContainingClass(context) === declaration &&
propertySymbol.subjectToManyNotImplemented()
) {
notImplementedIntersectionSymbols += propertySymbol
return@processPropertiesByName

View File

@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.SourceNavigator
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
@@ -25,10 +26,11 @@ import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
object FirPrimaryConstructorSuperTypeChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isInterface) {
for (superTypeRef in declaration.superTypeRefs) {
val source = superTypeRef.source ?: continue
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE) {
reporter.reportOn(source, FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE, context)
with(SourceNavigator.forElement(declaration)) {
for (superTypeRef in declaration.superTypeRefs) {
if (superTypeRef.isInConstructorCallee()) {
reporter.reportOn(superTypeRef.source, FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE, context)
}
}
}
return
@@ -97,10 +99,11 @@ object FirPrimaryConstructorSuperTypeChecker : FirRegularClassChecker() {
reporter: DiagnosticReporter,
context: CheckerContext
) {
for (superTypeRef in regularClass.superTypeRefs) {
val source = superTypeRef.source ?: continue
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE) {
reporter.reportOn(regularClass.source, FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, context)
with(SourceNavigator.forElement(regularClass)) {
for (superTypeRef in regularClass.superTypeRefs) {
if (superTypeRef.isInConstructorCallee()) {
reporter.reportOn(regularClass.source, FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, context)
}
}
}
}

View File

@@ -5,14 +5,12 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.getAncestors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.typeContext
@@ -43,7 +41,6 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
checkBoundUniqueness(declaration, context, reporter)
checkConflictingBounds(declaration, context, reporter)
checkTypeAliasBound(declaration, containingDeclaration, context, reporter)
checkBoundsPlacement(declaration, context, reporter)
checkDynamicBounds(declaration, context, reporter)
}
@@ -92,7 +89,9 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
// report the diagnostic on that bound
//take TypeConstraint bounds only to report on the same point as old FE
val constraintBounds = bounds.filter { it.isInTypeConstraint() }.toSet()
val constraintBounds = with(SourceNavigator.forElement(declaration)){
bounds.filter { it.isInTypeConstraint() }.toSet()
}
val reportOn =
if (bounds.size == 2) {
val boundDecl = otherBounds.firstOrNull() ?: boundWithParam.last()
@@ -105,14 +104,6 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
}
}
private fun FirTypeRef.isInTypeConstraint(): Boolean {
val source = source ?: return false
return source.treeStructure.getAncestors(source.lighterASTNode)
.find { it.tokenType == KtNodeTypes.TYPE_CONSTRAINT || it.tokenType == KtNodeTypes.TYPE_PARAMETER }
?.tokenType == KtNodeTypes.TYPE_CONSTRAINT
}
private fun checkBoundUniqueness(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
val seenClasses = mutableSetOf<FirRegularClass>()
val allNonErrorBounds = declaration.bounds.filter { it !is FirErrorTypeRef }
@@ -152,16 +143,6 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
}
}
//TODO should be moved to extended checkers (because this is basically a code-style warning)
private fun checkBoundsPlacement(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.bounds.size < 2) return
val (constraint, params) = declaration.bounds.partition { it.isInTypeConstraint() }
if (params.isNotEmpty() && constraint.isNotEmpty()) {
reporter.reportOn(declaration.source, FirErrors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS, context)
}
}
private fun checkDynamicBounds(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
declaration.bounds.forEach { bound ->
if (bound is FirDynamicTypeRef) {

View File

@@ -1,11 +1,10 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.ConstantArgumentKind
import org.jetbrains.kotlin.fir.analysis.checkers.checkConstantArguments
@@ -14,20 +13,17 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.psi.KtExpression
object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirAnnotationContainer) return
for (declarationOfAnnotation in declaration.annotations) {
for ((arg, _) in declarationOfAnnotation.argumentMapping ?: continue) {
val expression = (arg as? FirNamedArgumentExpression)?.expression ?: arg
object FirAnnotationArgumentChecker : FirAnnotationCallChecker() {
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
val argumentMapping = expression.argumentMapping ?: return
for ((arg, _) in argumentMapping) {
val argExpression = (arg as? FirNamedArgumentExpression)?.expression ?: arg
checkAnnotationArgumentWithSubElements(expression, context.session, reporter, context)
?.let { reporter.reportOn(expression.source, it, context) }
}
checkAnnotationArgumentWithSubElements(argExpression, context.session, reporter, context)
?.let { reporter.reportOn(argExpression.source, it, context) }
}
}

View File

@@ -20,22 +20,5 @@ object FirAnonymousFunctionChecker : FirAnonymousFunctionAsExpressionChecker() {
reporter.reportOn(source, FirErrors.USELESS_VARARG_ON_PARAMETER, context)
}
}
checkTypeParameters(expression, reporter, context)
}
private fun checkTypeParameters(
expression: FirAnonymousFunction,
reporter: DiagnosticReporter,
context: CheckerContext
) {
val source = expression.source ?: return
source.treeStructure.typeParametersList(source.lighterASTNode)?.let { _ ->
reporter.reportOn(
source,
FirErrors.TYPE_PARAMETERS_NOT_ALLOWED,
context
)
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.isAbstract
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.types.coneType
object FirConstructorCallChecker : FirFunctionCallChecker() {
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
val constructorSymbol =
(expression.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirConstructorSymbol ?: return
val declarationClass = constructorSymbol.fir.returnTypeRef.coneType.toRegularClass(context.session)
if (declarationClass != null && declarationClass.isAbstract && declarationClass.classKind == ClassKind.CLASS) {
reporter.reportOn(expression.source, FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, context)
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.isEnumClass
import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker.areCompatible
object FirEqualityCompatibilityChecker : FirEqualityOperatorCallChecker() {
override fun check(expression: FirEqualityOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) {
val arguments = expression.argumentList.arguments
if (arguments.size != 2) return
val lType = arguments[0].typeRef.coneType
val rType = arguments[1].typeRef.coneType
// If one of the type is already `Nothing?`, we skip reporting further comparison. This is to allow comparing with `null`, which has
// type `Nothing?`
if (lType.isNullableNothing || rType.isNullableNothing) return
val inferenceContext = context.session.inferenceComponents.ctx
val intersectionType = inferenceContext.intersectTypesOrNull(listOf(lType, rType)) as? ConeIntersectionType ?: return
val compatibility = intersectionType.intersectedTypes.areCompatible(inferenceContext)
if (compatibility != ConeTypeCompatibilityChecker.Compatibility.COMPATIBLE) {
when (expression.source?.kind) {
FirRealSourceElementKind -> {
// Note: FE1.0 reports INCOMPATIBLE_ENUM_COMPARISON_ERROR only when TypeIntersector.isIntersectionEmpty() thinks the
// given types are compatible. Exactly mimicking the behavior of FE1.0 is difficult and does not seem to provide any
// value. So instead, we deterministically output INCOMPATIBLE_ENUM_COMPARISON_ERROR if at least one of the value is an
// enum.
if (compatibility == ConeTypeCompatibilityChecker.Compatibility.HARD_INCOMPATIBLE &&
(lType.isEnumType(context) || rType.isEnumType(context))
) {
reporter.reportOn(
expression.source,
FirErrors.INCOMPATIBLE_ENUM_COMPARISON_ERROR,
lType,
rType,
context
)
} else {
reporter.reportOn(
expression.source,
if (compatibility == ConeTypeCompatibilityChecker.Compatibility.HARD_INCOMPATIBLE) {
FirErrors.EQUALITY_NOT_APPLICABLE
} else {
FirErrors.EQUALITY_NOT_APPLICABLE_WARNING
},
expression.operation.operator,
lType,
rType,
context
)
}
}
else -> reporter.reportOn(
expression.source,
if (compatibility == ConeTypeCompatibilityChecker.Compatibility.HARD_INCOMPATIBLE) {
FirErrors.INCOMPATIBLE_TYPES
} else {
FirErrors.INCOMPATIBLE_TYPES_WARNING
},
lType,
rType,
context
)
}
}
}
private fun ConeKotlinType.isEnumType(
context: CheckerContext
): Boolean {
if (isEnum) return true
val firRegularClass = (this as? ConeClassLikeType)?.lookupTag?.toFirRegularClass(context.session) ?: return false
return firRegularClass.isEnumClass
}
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import com.intellij.lang.LighterASTNode
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.stubs.elements.KtDotQualifiedExpressionElementType
import org.jetbrains.kotlin.psi.stubs.elements.KtNameReferenceExpressionElementType
object FirReservedUnderscoreExpressionChecker : FirBasicExpressionChecker() {
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
val source = expression.source
if (expression is FirFunctionCall) {
val calleeReferenceSource = expression.calleeReference.source
if (calleeReferenceSource is FirLightSourceElement && calleeReferenceSource.lighterASTNode.tokenType == KtNodeTypes.OPERATION_REFERENCE) {
return
}
reportIfUnderscore(
expression.calleeReference.source.text, expression.calleeReference.source, context, reporter,
isExpression = true
)
} else if (expression is FirQualifiedAccess) {
if (source is FirPsiSourceElement<*>) {
reportIfUnderscoreInQualifiedAccess(source, expression, context, reporter)
} else if (source is FirLightSourceElement) {
reportIfUnderscoreInQualifiedAccess(source, expression, context, reporter)
}
} else if (expression is FirGetClassCall) {
for (argument in expression.argumentList.arguments) {
reportIfUnderscore(argument.source.text, expression.source, context, reporter, isExpression = true)
}
} else if (expression is FirReturnExpression) {
var labelName: String? = null
if (source is FirPsiSourceElement<*>) {
labelName = (source.psi.parent as? KtLabeledExpression)?.getLabelName()
} else if (source is FirLightSourceElement) {
val parent = source.treeStructure.getParent(source.lighterASTNode)
if (parent != null && parent.tokenType == KtNodeTypes.LABELED_EXPRESSION) {
labelName = source.treeStructure.findDescendantByType(parent, KtNodeTypes.LABEL).toString()
labelName = labelName.substring(0, labelName.length - 1)
}
}
reportIfUnderscore(labelName, expression.source, context, reporter)
}
}
private fun reportIfUnderscoreInQualifiedAccess(
source: FirPsiSourceElement<*>,
expression: FirStatement,
context: CheckerContext,
reporter: DiagnosticReporter
) {
fun processQualifiedAccess(psi: PsiElement?) {
if (psi is KtNameReferenceExpression) {
reportIfUnderscore(psi.text, expression.source, context, reporter, isExpression = true)
} else if (psi is KtDotQualifiedExpression || psi is KtCallableReferenceExpression) {
processQualifiedAccess(psi.firstChild)
processQualifiedAccess(psi.lastChild)
}
}
val psi = source.psi
if (psi.parent !is KtDotQualifiedExpression && psi.parent !is KtCallableReferenceExpression) {
processQualifiedAccess(psi)
}
}
private fun reportIfUnderscoreInQualifiedAccess(
source: FirLightSourceElement,
expression: FirStatement,
context: CheckerContext,
reporter: DiagnosticReporter
) {
fun processQualifiedAccess(lightSourceElement: LighterASTNode?) {
val tokenType = lightSourceElement?.tokenType
if (tokenType is KtNameReferenceExpressionElementType) {
reportIfUnderscore(lightSourceElement.toString(), expression.source, context, reporter, isExpression = true)
} else if (lightSourceElement != null && (tokenType is KtDotQualifiedExpressionElementType || tokenType == KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION)) {
val children = lightSourceElement.getChildren(source.treeStructure)
processQualifiedAccess(children.first())
processQualifiedAccess(children.last())
}
}
val astNode = source.lighterASTNode
val parent = source.treeStructure.getParent(astNode)
if (parent?.tokenType !is KtDotQualifiedExpressionElementType && parent?.tokenType != KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION) {
processQualifiedAccess(astNode)
}
}
}
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (
declaration is FirClass<*> ||
declaration is FirFunction<*> ||
declaration is FirTypeParameter ||
declaration is FirProperty ||
declaration is FirTypeAlias
) {
reportIfUnderscore(declaration, context, reporter)
if (declaration is FirFunction<*>) {
for (parameter in declaration.valueParameters) {
reportIfUnderscore(
parameter,
context,
reporter,
isSingleUnderscoreAllowed = declaration is FirAnonymousFunction || declaration is FirPropertyAccessor
)
}
}
} else if (declaration is FirFile) {
for (import in declaration.imports) {
reportIfUnderscore(import.aliasName?.asString(), import.source, context, reporter)
}
}
}
}
private fun reportIfUnderscore(
declaration: FirDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter,
isSingleUnderscoreAllowed: Boolean = false
) {
val source = declaration.source
val rawIdentifier = when (source) {
is FirPsiSourceElement<*> ->
(source.psi as? PsiNameIdentifierOwner)?.nameIdentifier?.text
is FirLightSourceElement ->
source.treeStructure.nameIdentifier(source.lighterASTNode)?.toString()
else ->
null
}
reportIfUnderscore(rawIdentifier, source, context, reporter, isSingleUnderscoreAllowed)
val returnOrReceiverTypeRef = when (declaration) {
is FirValueParameter -> declaration.returnTypeRef.source
is FirFunction<*> -> declaration.receiverTypeRef?.source
else -> null
}
val isReportUnderscoreInReturnOrReceiverTypeRef = when (returnOrReceiverTypeRef) {
is FirPsiSourceElement<*> -> {
val psi = returnOrReceiverTypeRef.psi
psi is KtTypeReference && psi.anyDescendantOfType<LeafPsiElement> { isUnderscore(it.text) }
}
is FirLightSourceElement -> {
val lighterASTNode = returnOrReceiverTypeRef.lighterASTNode
lighterASTNode.tokenType == KtNodeTypes.TYPE_REFERENCE &&
source?.treeStructure?.findFirstDescendant(lighterASTNode)
{ it.tokenType == KtNodeTypes.REFERENCE_EXPRESSION && isUnderscore(it.toString()) } != null
}
else -> {
false
}
}
if (isReportUnderscoreInReturnOrReceiverTypeRef) {
reporter.reportOn(returnOrReceiverTypeRef, FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS, context)
}
}
private fun reportIfUnderscore(
text: CharSequence?,
source: FirSourceElement?,
context: CheckerContext,
reporter: DiagnosticReporter,
isSingleUnderscoreAllowed: Boolean = false,
isExpression: Boolean = false
) {
if (text == null || isSingleUnderscoreAllowed && text == "_") {
return
}
if (isUnderscore(text)) {
reporter.reportOn(
source,
if (isExpression) FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS else FirErrors.UNDERSCORE_IS_RESERVED,
context
)
}
}
private fun isUnderscore(text: CharSequence) = text.all { it == '_' }

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.isUnit
object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() {
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
val lastQualifiedAccess = context.qualifiedAccesses.lastOrNull()
if (lastQualifiedAccess?.explicitReceiver === expression) return
val lastGetClass = context.getClassCalls.lastOrNull()
if (lastGetClass?.argument === expression) return
// Note: if it's real Unit, it will be filtered by ClassKind.OBJECT check below
if (!expression.typeRef.isUnit) return
when (val symbol = expression.symbol) {
is FirRegularClassSymbol -> {
if (symbol.fir.classKind == ClassKind.OBJECT) return
reporter.reportOn(expression.source, FirErrors.NO_COMPANION_OBJECT, symbol, context)
}
null -> {
reporter.reportOn(expression.source, FirErrors.EXPRESSION_EXPECTED_PACKAGE_FOUND, context)
}
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.AbstractTypeChecker
// See .../types/CastDiagnosticsUtil.kt for counterparts, including isRefinementUseless, isExactTypeCast, isUpcast.
object FirUselessTypeOperationCallChecker : FirTypeOperatorCallChecker() {
override fun check(expression: FirTypeOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression.operation !in FirOperation.TYPES) return
val arg = expression.argument
val candidateType = arg.typeRef.coneType.upperBoundIfFlexible().fullyExpandedType(context.session)
if (candidateType is ConeKotlinErrorType) return
val targetType = expression.conversionTypeRef.coneType.fullyExpandedType(context.session)
if (targetType is ConeKotlinErrorType) return
// x as? Type <=> x as Type?
val refinedTargetType =
if (expression.operation == FirOperation.SAFE_AS) {
targetType.withNullability(ConeNullability.NULLABLE, context.session.typeContext)
} else {
targetType
}
if (isRefinementUseless(context, candidateType, refinedTargetType, shouldCheckForExactType(expression, context))) {
when (expression.operation) {
FirOperation.IS -> reporter.reportOn(expression.source, FirErrors.USELESS_IS_CHECK, true, context)
FirOperation.NOT_IS -> reporter.reportOn(expression.source, FirErrors.USELESS_IS_CHECK, false, context)
FirOperation.AS, FirOperation.SAFE_AS -> reporter.reportOn(expression.source, FirErrors.USELESS_CAST, context)
else -> throw AssertionError("Should not be here: ${expression.operation}")
}
}
}
@Suppress("UNUSED_PARAMETER")
private fun shouldCheckForExactType(expression: FirTypeOperatorCall, context: CheckerContext): Boolean {
return when (expression.operation) {
FirOperation.IS, FirOperation.NOT_IS -> false
// TODO: differentiate if this expression defines the enclosing thing's type
// e.g.,
// val c1 get() = 1 as Number
// val c2: Number get() = 1 <!USELESS_CAST!>as Number<!>
FirOperation.AS, FirOperation.SAFE_AS -> true
else -> throw AssertionError("Should not be here: ${expression.operation}")
}
}
private fun isRefinementUseless(
context: CheckerContext,
candidateType: ConeKotlinType,
targetType: ConeKotlinType,
shouldCheckForExactType: Boolean,
): Boolean {
return if (shouldCheckForExactType) {
isExactTypeCast(context, candidateType, targetType)
} else {
isUpcast(context, candidateType, targetType)
}
}
private fun isExactTypeCast(context: CheckerContext, candidateType: ConeKotlinType, targetType: ConeKotlinType): Boolean {
if (!AbstractTypeChecker.equalTypes(context.session.typeContext, candidateType, targetType, stubTypesEqualToAnything = false))
return false
// See comments at [isUpcast] why we need to check the existence of @ExtensionFunctionType
return candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType
}
private fun isUpcast(context: CheckerContext, candidateType: ConeKotlinType, targetType: ConeKotlinType): Boolean {
if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, candidateType, targetType, stubTypesEqualToAnything = false))
return false
// E.g., foo(p1: (X) -> Y), where p1 has a functional type whose receiver type is X and return type is Y.
// For bar(p2: X.() -> Y), p2 has the same functional type (with same receiver and return types).
// The only difference is the existence of type annotation, @ExtensionFunctionType,
// which indicates that the annotated type represents an extension function.
// If one casts p1 to p2 (or vice versa), it is _not_ up cast, i.e., not redundant, yet meaningful.
return candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType
}
}

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